Tarea 1


In [1]:
import numpy as np

Las listas no funcionan para construir matrices


In [2]:
x = [1 ,2, 3]
y = [4, 5, 6]
x + y


Out[2]:
[1, 2, 3, 4, 5, 6]

The numpy way


In [3]:
B = np.array([[1,2,3],[4,5,6]])

In [4]:
B


Out[4]:
array([[1, 2, 3],
       [4, 5, 6]])

In [5]:
B + 2*B


Out[5]:
array([[ 3,  6,  9],
       [12, 15, 18]])

Índices y slices


In [6]:
B[1,1]


Out[6]:
5

In [7]:
B[1,:]


Out[7]:
array([4, 5, 6])

In [8]:
B[:,2]


Out[8]:
array([3, 6])

In [9]:
B[0:2,0:2]


Out[9]:
array([[1, 2],
       [4, 5]])

In [10]:
B.shape


Out[10]:
(2, 3)

In [11]:
vec = np.array([1,2,3])
print(vec)


[1 2 3]

Empezando desde cero


In [12]:
class Array:
    "Una clase mínima para álgebra lineal"
    def __init__(self, list_of_rows):
        "Constructor"
        self.data = list_of_rows
        self.shape = (len(list_of_rows), len(list_of_rows[0]))

In [13]:
A = Array([[1,2,3],[4,5,6]])
A.__dict__


Out[13]:
{'data': [[1, 2, 3], [4, 5, 6]], 'shape': (2, 3)}

In [14]:
A.data


Out[14]:
[[1, 2, 3], [4, 5, 6]]

In [15]:
A.shape


Out[15]:
(2, 3)

Requerimientos

  1. Un método para imprimir una matriz de forma más agradable
  2. Validador
  3. Indexing
  4. Iniciar matriz vacía de ceros
  5. Transposición
  6. Suma
  7. Multiplicación escalar y matricial
  8. Vectores

1. Un método para imprimir mejor


In [16]:
Array([[1,2,3], [4,5,6]])


Out[16]:
<__main__.Array at 0x7fc962f42400>

In [17]:
print(Array([[1,2,3], [4,5,6]]))


<__main__.Array object at 0x7fc962f422b0>

In [18]:
np.array([[1,2,3],[4,5,6]])


Out[18]:
array([[1, 2, 3],
       [4, 5, 6]])

In [19]:
print(np.array([[1,2,3],[4,5,6]]))


[[1 2 3]
 [4 5 6]]

Ejercicio 1

repr y str


In [20]:
class Array:
    "Una clase mínima para álgebra lineal"
    def __init__(self, list_of_rows):
        "Constructor"
        self.data = list_of_rows
        self.shape = (len(list_of_rows), len(list_of_rows[0]))
    def __repr__(self):
        "Representar sin imprimir"
        return 'Array([%s])' % (', \n       '.join(str(x) for x in self.data))
    def __str__(self):
        "Imprimir"
        return '[%s]' % (' \n '.join(str(x) for x in self.data))

In [21]:
Array([[1,2,3], [4,5,6], [7,8,9]])


Out[21]:
Array([[1, 2, 3], 
       [4, 5, 6], 
       [7, 8, 9]])

In [22]:
x = Array([[1,2,3], [4,5,6], [7,8,9]]) # Pendiente: Necesitamos eliminar las comas de esta
print(x)


[[1, 2, 3] 
 [4, 5, 6] 
 [7, 8, 9]]

Ejercicio 2

Setitem


In [23]:
class Array:
    "Una clase mínima para álgebra lineal"
    def __init__(self, list_of_rows):
        "Constructor y validador"
        # obtener dimensiones
        self.data = list_of_rows
        nrow = len(list_of_rows)
        #  ___caso vector: redimensionar correctamente
        if not isinstance(list_of_rows[0], list):
            nrow = 1
            self.data = [[x] for x in list_of_rows]
        # ahora las columnas deben estar bien aunque sea un vector
        ncol = len(self.data[0])
        self.shape = (nrow, ncol)
        # validar tamano correcto de filas
        if any([len(r) != ncol for r in self.data]):
            raise Exception("Las filas deben ser del mismo tamano")
    
    def __getitem__(self, idx):
        return self.data[idx[0]][idx[1]]
    def __repr__(self):
        "Representar sin imprimir"
        return 'Array([%s])' % (', \n       '.join(str(x) for x in self.data))
    def __str__(self):
        "Imprimir"
        return '[%s]' % (' \n '.join(str(x) for x in self.data))
    def __setitem__(self, idx, new_value):
        "Cambiar valor"
        self.data[idx[0]][idx[1]] = new_value

In [24]:
A = Array([[1,2,3],[4,5,6]])
A[1,1]


Out[24]:
5

In [25]:
A[1,2] = 10
A


Out[25]:
Array([[1, 2, 3], 
       [4, 5, 10]])

Ejercicio 3


In [26]:
y=10
x=4

In [27]:
a = [0. for z in range(x)]
print(a)
b = [a for z in range (y)]
print(b)
Array([a for z in range (y)])


[0.0, 0.0, 0.0, 0.0]
[[0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0]]
Out[27]:
Array([[0.0, 0.0, 0.0, 0.0], 
       [0.0, 0.0, 0.0, 0.0], 
       [0.0, 0.0, 0.0, 0.0], 
       [0.0, 0.0, 0.0, 0.0], 
       [0.0, 0.0, 0.0, 0.0], 
       [0.0, 0.0, 0.0, 0.0], 
       [0.0, 0.0, 0.0, 0.0], 
       [0.0, 0.0, 0.0, 0.0], 
       [0.0, 0.0, 0.0, 0.0], 
       [0.0, 0.0, 0.0, 0.0]])

1) Array de ceros


In [143]:
def zeros(shapex, shapey):
    "Esta función crea un array de ceros"
    a = [0. for z in range(shapey)]
    return [a for z in range(shapex)]

In [144]:
A = Array(zeros(3,5))
print(A)


[[0.0, 0.0, 0.0, 0.0, 0.0] 
 [0.0, 0.0, 0.0, 0.0, 0.0] 
 [0.0, 0.0, 0.0, 0.0, 0.0]]

2) Matriz identidad


In [145]:
def eye(n):
    "Esta función crea una matriz identidad de tamaño n"
    x = [[0 if x is not y else 1 for x in range(n) ] for y in range(n)]
    return x

In [146]:
A = Array(eye(5))
print(A)


[[1, 0, 0, 0, 0] 
 [0, 1, 0, 0, 0] 
 [0, 0, 1, 0, 0] 
 [0, 0, 0, 1, 0] 
 [0, 0, 0, 0, 1]]

Ejercicio 4

Transponer


In [147]:
class Array:
    "Una clase mínima para álgebra lineal"
    def __init__(self, list_of_rows):
        "Constructor y validador"
        # obtener dimensiones
        self.data = list_of_rows
        nrow = len(list_of_rows)
        #  ___caso vector: redimensionar correctamente
        if not isinstance(list_of_rows[0], list):
            nrow = 1
            self.data = [[x] for x in list_of_rows]
        # ahora las columnas deben estar bien aunque sea un vector
        ncol = len(self.data[0])
        self.shape = (nrow, ncol)
        # validar tamano correcto de filas
        if any([len(r) != ncol for r in self.data]):
            raise Exception("Las filas deben ser del mismo tamano")
    
    def __getitem__(self, idx):
        return self.data[idx[0]][idx[1]]
    def __repr__(self):
        "Representar sin imprimir"
        return 'Array([%s])' % (', \n       '.join(str(x) for x in self.data))
    def __str__(self):
        "Imprimir"
        return '[%s]' % (' \n '.join(str(x) for x in self.data))
    def __setitem__(self, idx, new_value):
        "Cambiar valor"
        self.data[idx[0]][idx[1]] = new_value
    def transponer(self):
        "Esta función transpone una matriz A mxn en una matriz B nxm"
        n = len(self.data[0])
        B = [[j[i] for j in self.data] for i in range(n)]  
        return B

In [148]:
A = [[1,2,3],[99,5,6],[4,99,6],[4,5,6],[4,5,6],[4,5,6],[4,5,6],[4,5,6]] 
Z = [[1,2,3,4,5,6,7,8,9,10],[1,2,3,4,5,6,7,8,9,10]]

In [149]:
B = Array(A).transponer()
print(B)
W = Array(Z).transponer()
print(W)


[[1, 99, 4, 4, 4, 4, 4, 4], [2, 5, 99, 5, 5, 5, 5, 5], [3, 6, 6, 6, 6, 6, 6, 6]]
[[1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6], [7, 7], [8, 8], [9, 9], [10, 10]]

Ejercicio 5

1) Suma por la derecha


In [150]:
class Array:
    "Una clase mínima para álgebra lineal"
    def __init__(self, list_of_rows):
        "Constructor y validador"
        # obtener dimensiones
        self.data = list_of_rows
        nrow = len(list_of_rows)
        #  ___caso vector: redimensionar correctamente
        if not isinstance(list_of_rows[0], list):
            nrow = 1
            self.data = [[x] for x in list_of_rows]
        # ahora las columnas deben estar bien aunque sea un vector
        ncol = len(self.data[0])
        self.shape = (nrow, ncol)
        # validar tamano correcto de filas
        if any([len(r) != ncol for r in self.data]):
            raise Exception("Las filas deben ser del mismo tamano")
    
    def __getitem__(self, idx):
        return self.data[idx[0]][idx[1]]
    def __repr__(self):
        "Representar sin imprimir"
        return 'Array([%s])' % (', \n       '.join(str(x) for x in self.data))
    def __str__(self):
        "Imprimir"
        return '[%s]' % (' \n '.join(str(x) for x in self.data))
    def __setitem__(self, idx, new_value):
        "Cambiar valor"
        self.data[idx[0]][idx[1]] = new_value
    def transponer(self):
        "Esta función transpone una matriz A mxn en una matriz B nxm"
        n = len(self.data[0])
        B = [[j[i] for j in self.data] for i in range(n)]  
        return B
    
    def __add__(self, other):
        "Hora de sumar"
        if isinstance(other, Array):
            if self.shape != other.shape:
                raise Exception("Las dimensiones son distintas!")
            rows, cols = self.shape
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] + other.data[r][c]
            return newArray
        elif isinstance(2, (int, float, complex)): # en caso de que el lado derecho sea solo un numero
            rows, cols = self.shape
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] + other
            return newArray
        else:
            return NotImplemented # es un tipo de error particular usado en estos metodos

    def __radd__(self, other):
        "Hora de sumar por la derecha"
        if isinstance(2, (int, float, complex)): # en caso de que el lado izquierdo sea solo un numero
            rows, cols = self.shape
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] + other
            return newArray
        else:
            return NotImplemented # es un tipo de error particular usado en estos metodos

In [151]:
A = Array([[1,2], [3,4]])
B = Array([[5,6], [7,8]])
C = A + B
C.data


Out[151]:
[[6, 8], [10, 12]]

In [152]:
D = A + 10
D.data


Out[152]:
[[11, 12], [13, 14]]

In [153]:
D = 15 + A
D.data


Out[153]:
[[16, 17], [18, 19]]

In [154]:
1 + Array([[1,2], [3,4]])


Out[154]:
Array([[2, 3], 
       [4, 5]])

2) Resta


In [155]:
class Array:
    "Una clase mínima para álgebra lineal"
    def __init__(self, list_of_rows):
        "Constructor y validador"
        # obtener dimensiones
        self.data = list_of_rows
        nrow = len(list_of_rows)
        #  ___caso vector: redimensionar correctamente
        if not isinstance(list_of_rows[0], list):
            nrow = 1
            self.data = [[x] for x in list_of_rows]
        # ahora las columnas deben estar bien aunque sea un vector
        ncol = len(self.data[0])
        self.shape = (nrow, ncol)
        # validar tamano correcto de filas
        if any([len(r) != ncol for r in self.data]):
            raise Exception("Las filas deben ser del mismo tamano")
    
    def __getitem__(self, idx):
        return self.data[idx[0]][idx[1]]
    def __repr__(self):
        "Representar sin imprimir"
        return 'Array([%s])' % (', \n       '.join(str(x) for x in self.data))
    def __str__(self):
        "Imprimir"
        return '[%s]' % (' \n '.join(str(x) for x in self.data))
    def __setitem__(self, idx, new_value):
        "Cambiar valor"
        self.data[idx[0]][idx[1]] = new_value
    def transponer(self):
        "Esta función transpone una matriz A mxn en una matriz B nxm"
        n = len(self.data[0])
        B = [[j[i] for j in self.data] for i in range(n)]  
        return B
    
    def __add__(self, other):
        "Hora de sumar"
        if isinstance(other, Array):
            if self.shape != other.shape:
                raise Exception("Las dimensiones son distintas!")
            rows, cols = self.shape
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] + other.data[r][c]
            return newArray
        elif isinstance(2, (int, float, complex)): # en caso de que el lado derecho sea solo un numero
            rows, cols = self.shape
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] + other
            return newArray
        else:
            return NotImplemented # es un tipo de error particular usado en estos metodos

    def __radd__(self, other):
        "Hora de sumar por la derecha"
        if isinstance(2, (int, float, complex)): # en caso de que el lado izquierdo sea solo un numero
            rows, cols = self.shape
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] + other
            return newArray
        else:
            return NotImplemented # es un tipo de error particular usado en estos metodos

    def __sub__(self, other):
        "Hora de restar"
        if isinstance(other, Array):
            if self.shape != other.shape:
                raise Exception("Las dimensiones son distintas!")
            rows, cols = self.shape
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] - other.data[r][c]
            return newArray
        elif isinstance(2, (int, float, complex)): # en caso de que el lado derecho sea solo un numero
            rows, cols = self.shape
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] - other
            return newArray
        else:
            return NotImplemented # es un tipo de error particular usado en estos metodos
        
    def __rsub__(self, other):
        "Hora de sumar por la derecha"
        if isinstance(2, (int, float, complex)): # en caso de que el lado izquierdo sea solo un numero
            rows, cols = self.shape
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] - other
            return newArray
        else:
            return NotImplemented # es un tipo de error particular usado en estos metodos

In [156]:
A = Array([[1,2], [3,4]])
B = Array([[5,6], [7,8]])
C = A - B
C.data


Out[156]:
[[-4, -4], [-4, -4]]

In [157]:
D = A - 10
D.data


Out[157]:
[[-9, -8], [-7, -6]]

In [158]:
D = 15 - A
D.data


Out[158]:
[[-14, -13], [-12, -11]]

Ejercicio 6


In [193]:
class Array:
    "Una clase mínima para álgebra lineal"
    def __init__(self, list_of_rows):
        "Constructor y validador"
        # obtener dimensiones
        self.data = list_of_rows
        nrow = len(list_of_rows)
        #  ___caso vector: redimensionar correctamente
        if not isinstance(list_of_rows[0], list):
            nrow = 1
            self.data = [[x] for x in list_of_rows]
        # ahora las columnas deben estar bien aunque sea un vector
        ncol = len(self.data[0])
        self.shape = (nrow, ncol)
        # validar tamano correcto de filas
        if any([len(r) != ncol for r in self.data]):
            raise Exception("Las filas deben ser del mismo tamano")
    
    def __getitem__(self, idx):
        return self.data[idx[0]][idx[1]]
    def __repr__(self):
        "Representar sin imprimir"
        return 'Array([%s])' % (', \n       '.join(str(x) for x in self.data))
    def __str__(self):
        "Imprimir"
        return '[%s]' % (' \n '.join(str(x) for x in self.data))
    def __setitem__(self, idx, new_value):
        "Cambiar valor"
        self.data[idx[0]][idx[1]] = new_value
    def transponer(self):
        "Esta función transpone una matriz A mxn en una matriz B nxm"
        n = len(self.data[0])
        B = [[j[i] for j in self.data] for i in range(n)]  
        return B
    
    def cuadrada(self):
        if self.shape[0] == self.shape[1]:
            resultado = "Sí"
        else:
            resultado = "No"
        return [resultado,self.shape[0]]
    
    def __add__(self, other):
        "Hora de sumar"
        if isinstance(other, Array):
            if self.shape != other.shape:
                raise Exception("Las dimensiones son distintas!")
            rows, cols = self.shape
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] + other.data[r][c]
            return newArray
        elif isinstance(2, (int, float, complex)): # en caso de que el lado derecho sea solo un numero
            rows, cols = self.shape
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] + other
            return newArray
        else:
            return NotImplemented # es un tipo de error particular usado en estos metodos

    def __radd__(self, other):
        "Hora de sumar por la derecha"
        if isinstance(2, (int, float, complex)): # en caso de que el lado izquierdo sea solo un numero
            rows, cols = self.shape
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] + other
            return newArray
        else:
            return NotImplemented # es un tipo de error particular usado en estos metodos

    def __sub__(self, other):
        "Hora de restar"
        if isinstance(other, Array):
            if self.shape != other.shape:
                raise Exception("Las dimensiones son distintas!")
            rows, cols = self.shape
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] - other.data[r][c]
            return newArray
        elif isinstance(2, (int, float, complex)): # en caso de que el lado derecho sea solo un numero
            rows, cols = self.shape
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] - other
            return newArray
        else:
            return NotImplemented # es un tipo de error particular usado en estos metodos
        
    def __rsub__(self, other):
        "Hora de sumar por la derecha"
        if isinstance(2, (int, float, complex)): # en caso de que el lado izquierdo sea solo un numero
            rows, cols = self.shape
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] - other
            return newArray
        else:
            return NotImplemented # es un tipo de error particular usado en estos metodos
    
    def __mul__(self,other):
        "Hora de multiplicar"
        if isinstance(other, Array) and isinstance(self, Array):
            if self.shape[1] != other.shape[0]:
                raise Exception("Las dimensiones son distintas!")
            rows = self.shape[0]
            cols = other.shape[1]
            p = self.shape[1]
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = [newArray.data[r][c] + self.data[r][x] * other.data[x][c] for x in range(p)]
                    newArray.data[r][c] = sum(newArray.data[r][c])
            return newArray
        
        elif isinstance(2, (int, float, complex)): # en caso de que el lado derecho sea solo un numero
            rows, cols = self.shape
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] * other
            return newArray
        else:
            return NotImplemented # es un tipo de error particular usado en estos metodos

    def __rmul__(self,other):
        "Hora de multiplicar por la derecha"
        if isinstance(2, (int, float, complex)): # en caso de que el lado izquierdo sea solo un numero
            rows, cols = self.shape
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] * other
            return newArray
        else:
            return NotImplemented # es un tipo de error particular usado en estos metodos

In [194]:
A = Array([[1,2,3], [4,5,6]])
B = Array([[1,2], [3,4], [5,6]])
C = A*B
C.data
print(C)


[[22.0, 28.0] 
 [49.0, 64.0]]

In [161]:
B = Array([[1,2,3], [4,5,6]])
A = Array([[1,2], [3,4], [5,6]])
C = A*B
C.data
print(C)


[[9.0, 12.0, 15.0] 
 [19.0, 26.0, 33.0] 
 [29.0, 40.0, 51.0]]

In [162]:
a = [[1,2,3], [4,5,6]]
b = eye(3)
A = Array(a)
B = Array(b)



C = A*B
C.data
print(C)


[[1.0, 2.0, 3.0] 
 [4.0, 5.0, 6.0]]

In [165]:
a = [[1,2,3], [4,5,6]]
b = zeros(3,10)
A = Array(a)
B = Array(b)

C = A*B
C.data
print(C)


[[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] 
 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]]

In [164]:
D = A * .5
D.data


Out[164]:
[[0.5, 1.0, 1.5], [2.0, 2.5, 3.0]]

In [124]:
D = .5 * A
D.data


Out[124]:
[[0.5, 1.0, 1.5], [2.0, 2.5, 3.0]]

In [125]:
A = Array([[1,2],[3,4]])
B = Array([[1,2],[3,4]])
C = A*B
C.data
print(C)


[[7.0, 10.0] 
 [15.0, 22.0]]

Ejercicio 7


In [166]:
class Vector(Array): # declara que Vector es un tipo de Array
    def __init__(self, list_of_numbers):
        self.vdata = list_of_numbers
        list_of_rows = [[x] for x in list_of_numbers]
        return Array.__init__(self, list_of_rows)
    def __repr__(self):
        return "Vector(" + str(self.vdata) + ")"
    def __str__(self):
        return str(self.vdata)
    def __add__(self, other):
        new_arr = Array.__add__(self, other)
        return Vector([x[0] for x in new_arr.data])

Algoritmo de forward substitution


In [460]:
class Array:
    "Una clase mínima para álgebra lineal"
    def __init__(self, list_of_rows):
        "Constructor y validador"
        # obtener dimensiones
        self.data = list_of_rows
        nrow = len(list_of_rows)
        #  ___caso vector: redimensionar correctamente
        if not isinstance(list_of_rows[0], list):
            nrow = 1
            self.data = [[x] for x in list_of_rows]
        # ahora las columnas deben estar bien aunque sea un vector
        ncol = len(self.data[0])
        self.shape = (nrow, ncol)
        # validar tamano correcto de filas
        if any([len(r) != ncol for r in self.data]):
            raise Exception("Las filas deben ser del mismo tamano")
    
    def __getitem__(self, idx):
        return self.data[idx[0]][idx[1]]
    def __repr__(self):
        "Representar sin imprimir"
        return 'Array([%s])' % (', \n       '.join(str(x) for x in self.data))
    def __str__(self):
        "Imprimir"
        return '[%s]' % (' \n '.join(str(x) for x in self.data))
    def __setitem__(self, idx, new_value):
        "Cambiar valor"
        self.data[idx[0]][idx[1]] = new_value
    def transponer(self):
        "Esta función transpone una matriz A mxn en una matriz B nxm"
        n = len(self.data[0])
        B = [[j[i] for j in self.data] for i in range(n)]  
        return B
    
    def cuadrada(self):
        if self.shape[0] == self.shape[1]:
            resultado = "Sí"
        else:
            resultado = "No"
        return [resultado,self.shape[0]]
    
    def __add__(self, other):
        "Hora de sumar"
        if isinstance(other, Array):
            if self.shape != other.shape:
                raise Exception("Las dimensiones son distintas!")
            rows, cols = self.shape
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] + other.data[r][c]
            return newArray
        elif isinstance(2, (int, float, complex)): # en caso de que el lado derecho sea solo un numero
            rows, cols = self.shape
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] + other
            return newArray
        else:
            return NotImplemented # es un tipo de error particular usado en estos metodos

    def __radd__(self, other):
        "Hora de sumar por la derecha"
        if isinstance(2, (int, float, complex)): # en caso de que el lado izquierdo sea solo un numero
            rows, cols = self.shape
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] + other
            return newArray
        else:
            return NotImplemented # es un tipo de error particular usado en estos metodos

    def __sub__(self, other):
        "Hora de restar"
        if isinstance(other, Array):
            if self.shape != other.shape:
                raise Exception("Las dimensiones son distintas!")
            rows, cols = self.shape
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] - other.data[r][c]
            return newArray
        elif isinstance(2, (int, float, complex)): # en caso de que el lado derecho sea solo un numero
            rows, cols = self.shape
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] - other
            return newArray
        else:
            return NotImplemented # es un tipo de error particular usado en estos metodos
        
    def __rsub__(self, other):
        "Hora de sumar por la derecha"
        if isinstance(2, (int, float, complex)): # en caso de que el lado izquierdo sea solo un numero
            rows, cols = self.shape
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] - other
            return newArray
        else:
            return NotImplemented # es un tipo de error particular usado en estos metodos
    
    def __mul__(self,other):
        "Hora de multiplicar"
        if isinstance(other, Array) and isinstance(self, Array):
            if self.shape[1] != other.shape[0]:
                raise Exception("Las dimensiones son distintas!")
            rows = self.shape[0]
            cols = other.shape[1]
            p = self.shape[1]
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = [newArray.data[r][c] + self.data[r][x] * other.data[x][c] for x in range(p)]
                    newArray.data[r][c] = sum(newArray.data[r][c])
            return newArray
        
        elif isinstance(2, (int, float, complex)): # en caso de que el lado derecho sea solo un numero
            rows, cols = self.shape
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] * other
            return newArray
        else:
            return NotImplemented # es un tipo de error particular usado en estos metodos

    def __rmul__(self,other):
        "Hora de multiplicar por la derecha"
        if isinstance(2, (int, float, complex)): # en caso de que el lado izquierdo sea solo un numero
            rows, cols = self.shape
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] * other
            return newArray
        else:
            return NotImplemented # es un tipo de error particular usado en estos metodos
    
    def shape(self):
        self.shape
        

    def forwards_subs(self, vector):
#        if self.shape[0] == self.shape[1]:
#            n_var = self.cuadrada()[1]
#            a = [0 for x in range(n_var)]
           
#            while 
            
            
#            return a
#        else:
#            return "No es matriz cuadrada"
        pass

In [463]:
A = Array([[5,0,0,0],[4,5,0,0],[7,8,9,0],[7,8,9,10]])
V = Array([[2],[3],[4],[13]])

x = zeros(4,1)
print(A.shape[0])


4

In [466]:
def solve(m, y):
    v = [0 for i in range(A.shape[0])]
    for i in range(A.shape[0]):
        v[i] = (y[i] - v.dotProduct(m[i]))/float(m[i][i])

    return v

In [468]:
a = [[5,0,0,0],[4,5,0,0],[7,8,9,0],[7,8,9,10]]
v = [[2],[3],[4],[13]]
solve(A,V)


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-468-70e694ef8fae> in <module>()
      1 a = [[5,0,0,0],[4,5,0,0],[7,8,9,0],[7,8,9,10]]
      2 v = [[2],[3],[4],[13]]
----> 3 solve(A,V)

<ipython-input-466-990247490d7d> in solve(m, y)
      2     v = [0 for i in range(A.shape[0])]
      3     for i in range(A.shape[0]):
----> 4         v[i] = (y[i] - v.dotProduct(m[i]))/float(m[i][i])
      5 
      6     return v

<ipython-input-460-edd7f42ed4c3> in __getitem__(self, idx)
     18 
     19     def __getitem__(self, idx):
---> 20         return self.data[idx[0]][idx[1]]
     21     def __repr__(self):
     22         "Representar sin imprimir"

TypeError: 'int' object is not subscriptable

In [412]:
A = [[5,2,3],[4,5,6],[7,8,9]]
C = Array(A).cuadrada()

B = Array(A)
D = B.cuadrada()

D


Out[412]:
['Sí', 3]

In [222]:
a = Array(zeros(B.cuadrada()[1],1))
a


Out[222]:
Array([[0.0], 
       [0.0], 
       [0.0]])

In [223]:
b = Array([[1],[2],[3]]) 
print(b)


[[1] 
 [2] 
 [3]]

Con esto concluimos.