In [1]:
class Array:
"Una clase minima para algebra lineal"
def __init__(self, list_of_rows):
# 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 tamaño correcto de filas
if any([len(r) != ncol for r in self.data]):
raise Exception("Las filas deben ser del mismo tamano")
# validar que los elementos sean numéricos
for i in range(nrow):
for j in range(ncol):
if not isinstance(self.data[i][j], (int, float, complex)):
raise Exception("'" + str(self.data[i][j]) + "'" + " no es numérico")
# Ejercicio 1
def __repr__(self):
if((len(self.data)) == 1):
return ("Array(" + str(self.data[0]) + ")")
else:
cadena = "Array("
for i in range(len(self.data)):
if(i==0):
cadena = cadena + str(self.data[i]) + ",\n"
elif(i>0 and i<(len(self.data)-1)):
cadena = cadena + " " + str(self.data[i]) + ",\n"
elif(i == (len(self.data)-1)):
cadena = cadena + " " + str(self.data[i])
return (cadena + ")")
def __str__(self):
cadena = ""
for i in range(len(self.data)):
cadena = cadena + str(self.data[i]) + "\n"
return cadena
# Ejercicio 2
def __getitem__(self, idx):
return self.data[idx[0]][idx[1]]
def __setitem__(self, idx, new_value):
self.data[idx[0]][idx[1]] = new_value
# Ejercicio 3
def zeros(x, y):
zeroarray = Array([[0 for c in range(y)] for r in range(x)])
return zeroarray
def eye(x):
eyearray = Array([[0 for c in range(x)] for r in range(x)])
for i in range(x):
for j in range(x):
if i == j:
eyearray[i,j] = 1
return eyearray
# Ejercicio 4
def transpose(self):
#Obtener dimensiones
nrow = len(self.data)
ncol = len(self.data[0])
#Crear matriz receptora
transpuesta = Array([[0 for c in range(nrow)] for r in range(ncol)])
#Transponer
for i in range(nrow):
for j in range(ncol):
transpuesta[j,i] = self.data[i][j]
return transpuesta
# Ejercicio 5
def __add__(self, other):
#Matriz, matriz
if isinstance(other, Array):
#Validar las dimensiones
if self.shape != other.shape:
raise Exception("Las dimensiones son distintas!")
#Obtener dimensiones
rows, cols = self.shape
#Crear matriz receptora
newArray = Array([[0. for c in range(cols)] for r in range(rows)])
#Sumar
for r in range(rows):
for c in range(cols):
newArray.data[r][c] = self.data[r][c] + other.data[r][c]
return newArray
#Matriz, entero
elif isinstance(other, (int, float, complex)):
#Obterner dimensiones
rows, cols = self.shape
#Crear matriz receptora
newArray = Array([[0. for c in range(cols)] for r in range(rows)])
#Sumar
for r in range(rows):
for c in range(cols):
newArray.data[r][c] = self.data[r][c] + other
return newArray
else:
return NotImplemented
__radd__ = __add__
def __sub__(self, other):
#Matriz, matriz
if isinstance(other, Array):
#Validar las dimensiones
if self.shape != other.shape:
raise Exception("Las dimensiones son distintas!")
#Obtener las dimensiones
rows, cols = self.shape
#Crear matriz receptora
newArray = Array([[0. for c in range(cols)] for r in range(rows)])
#Restar
for r in range(rows):
for c in range(cols):
newArray.data[r][c] = self.data[r][c] - other.data[r][c]
return newArray
#Matriz, entero
elif isinstance(other, (int, float, complex)):
#Obtener las dimensiones
rows, cols = self.shape
#Crear matriz receptora
newArray = Array([[0. for c in range(cols)] for r in range(rows)])
#Restar
for r in range(rows):
for c in range(cols):
newArray.data[r][c] = self.data[r][c] - other
return newArray
else:
return NotImplemented
# Ejercicio 6
def __mul__(self, other):
#Matriz, matriz
if isinstance(other, Array):
#Validar las dimensiones
if self.shape[1] != other.shape[0]:
raise Exception("Las matrices no son compatibles!")
#Obtener las dimensiones
rowsA = self.shape[0]
rowsB = other.shape[0]
colsB = other.shape[1]
#Crear matriz receptora
newArray = Array([[0 for c in range(colsB)] for r in range(rowsA)])
#Multiplicar
for i in range(rowsA):
for j in range(colsB):
for k in range(rowsB):
newArray[i,j] = newArray[i,j] + self.data[i][k] * other.data[k][j]
return newArray
#Matriz, entero
elif isinstance(other, (int, float, complex)):
#Obtener las dimensiones
rows, cols = self.shape
#Crear matriz receptora
newArray = Array([[0 for c in range(cols)] for r in range(rows)])
#Multiplicar
for r in range(rows):
for c in range(cols):
newArray.data[r][c] = self.data[r][c] * other
return newArray
else:
return NotImplemented
def __rmul__(self, other):
if isinstance(other, (int, float, complex)):
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
# Ejericio 7
def foward_sub(self, y):
#Validar que la matriz sea cuadrada
if isinstance(self , Array):
if self.shape[0] != self.shape[1]:
raise Exception("La matriz no es cuadrada!")
#Validar que la matriz sea L
nrow = len(self.data)
ncol = len(self.data[0])
for i in range(nrow):
for j in range(ncol):
if(i<j and self.data[i][j] != 0):
raise Exception("La matriz no es L!")
#Validar que no existan ceros en la diagonal
for i in range(nrow):
for j in range(ncol):
if(i==j and self.data[i][j] == 0):
raise Exception("Existen 0's en la diagonal!")
#Validar que el segundo argumento sea un vector
if isinstance(y, Array):
#if not(((y.shape[1]) != 1) or ((y.shape[0]!=1))):
#raise Exception("El segundo argumento debe ser un vector")
#Validar que b sea un array columna
if (y.shape[1] != 1):
raise Exception("'Ax = b' b tiene que ser un array columna")
#Validar que b y A tengan el mismo numero de filas
if (self.shape[0] != y.shape[0]):
raise Exception("'Ax = b' Las filas del array columna no coinciden con las filas de la matriz")
#Enderezar vector de ser necesario
#b = y.shape[1]
#if ((y.shape[1]) == 1 ):
y = Array.transpose(y)
#Foward Substitution
solution = Array([[0 for n in range(nrow)]])
for i in range(len(y.data[0])):
solution[0,i] = y[0,i]
for j in range(i):
solution[0,i] = solution[0,i] - (self[i,j])*(solution[0,j])
solution[0,i] = ((solution[0,i])/(self[i,i]))
#Ajustar vector para que salga igual que como entro
#if (b != 0 ):
solution = Array.transpose(solution)
return (solution)
else:
return NotImplemented
# Ejercicio 8
def backward_sub(self, y):
#Validar que la matriz sea cuadrada
if isinstance(self , Array):
if self.shape[0] != self.shape[1]:
raise Exception("La matriz no es cuadrada!")
#Validar que la matriz sea U
nrow = len(self.data)
ncol = len(self.data[0])
for i in range(nrow):
for j in range(ncol):
if(i>j and self.data[i][j] != 0):
raise Exception("La matriz no es U!")
#Validar que no existan ceros en la diagonal
for i in range(nrow):
for j in range(ncol):
if(i==j and self.data[i][j] == 0):
raise Exception("Existen 0's en la diagonal!")
#Validar que el segundo argumento sea un vector
if isinstance(y, Array):
#if not((y.shape[1] == 1) or (y.shape[0]==1)):
#raise Exception("El segundo argumento debe ser un vector")
#Validar que b sea un array columna
if (y.shape[1] != 1):
raise Exception("'Ax = b' b tiene que ser un array columna")
#Validar que b y A tengan el mismo numero de filas
if (self.shape[0] != y.shape[0]):
raise Exception("'Ax = b' Las filas del array columna no coinciden con las filas de la matriz")
#Enderezar vector de ser necesario
b = y.shape[1]
if ((y.shape[1]) == 1 ):
y = Array.transpose(y)
#Backward Substitution
solution = Array([[0 for n in range(nrow)]])
h = len(y.data[0]) - 1
m = 0
for i in range((len(y.data[0])-1),-1,-1):
solution[0,i] = y[0,i]
h = len(y.data[0]) - 1
for j in range(m):
solution[0,i] = solution[0,i] - (self[i,h])*(solution[0,h])
h-=1
m += 1
solution[0,i] = ((solution[0,i])/(self[i,i]))
#Ajustar vector para que salga igual que como entro
if (b != 0 ):
solution = Array.transpose(solution)
return (solution)
else:
return NotImplemented
# Ejercicio 9
def lu_decomposition(self):
#Validar que la matriz sea cuadrada
if isinstance(self , Array):
if self.shape[0] != self.shape[1]:
raise Exception("La matriz no es cuadrada!")
#Crear matrices receptroas
n = self.shape[1]
L = Array.eye(n)
U = Array.zeros(n,n)
P = Array.eye(n)
# Crear matriz de permutación, con filas en el orden correcto
for o in range(n):
row = max(range(o, n), key=lambda i: abs(self.data[i][o]))
if o != row:
P.data[o], P.data[row] = P.data[row], P.data[o]
#Obtener matriz P*A
PA = P*self
# Descomposición LU
for j in range(n):
for i in range(j+1):
s1 = sum(U.data[k][j] * L.data[i][k] for k in range(i))
U.data[i][j] = PA.data[i][j] - s1
for i in range(j, n):
s2 = sum(U.data[k][j] * L.data[i][k] for k in range(j))
L.data[i][j] = (PA.data[i][j] - s2) / U.data[j][j]
return (P, L, U)
# Ejercicio 10
def lu_linsolve(self, b):
r = self
e = b
#Validar que b sea un array columna
if (e.shape[1] != 1):
raise Exception("'Ax = b' b tiene que ser un array columna")
#Validar que b y A tengan el mismo numero de filas
if (r.shape[0] != e.shape[0]):
raise Exception("'Ax = b' Las filas del array columna no coinciden con las filas de la matriz")
P,L,U = Array.lu_decomposition(self)
if(b.shape[0]==1):
b = Array.transpose(b)
b1 = P*b
y = Array.foward_sub(L,b1)
x = Array.backward_sub(U,y)
return(x)
In [2]:
A =Array([[1,2,3],[4,5,6],[7,8,9]])
In [3]:
A
Out[3]:
In [4]:
print(A)
In [5]:
A[0,0] = 3
In [6]:
A
Out[6]:
In [7]:
A[0,0] = 1
In [8]:
A
Out[8]:
In [9]:
Array.zeros(2,2)
Out[9]:
In [10]:
Array.zeros(5,6)
Out[10]:
In [11]:
Array.eye(3)
Out[11]:
In [12]:
Array.eye(5)
Out[12]:
In [13]:
A.transpose()
Out[13]:
In [14]:
Q = Array([[1,2,3],[5,6,7]])
In [15]:
print(Q)
In [16]:
print(Q.transpose())
In [17]:
B = Array([[9,8,7],[6,5,4],[3,2,1]])
In [18]:
B
Out[18]:
In [19]:
A
Out[19]:
In [20]:
C = A+B
In [21]:
C
Out[21]:
In [22]:
C+1
Out[22]:
In [23]:
1+C
Out[23]:
In [24]:
A-B
Out[24]:
In [25]:
B-A
Out[25]:
In [26]:
C-1
Out[26]:
In [27]:
A*B
Out[27]:
In [28]:
B*A
Out[28]:
In [29]:
a= Array([[1,2],[3,4]])
In [30]:
A*a
In [31]:
b= Array([[1,2,3],[4,5,6]])
In [32]:
print(a*b)
In [33]:
c = a*b
In [34]:
print(c)
In [35]:
print(c*2)
In [36]:
print(2*c)
In [37]:
F = Array([[3,0,0,0],[-1,1,0,0],[3,-2,-1,0],[1,-2,6,2]])
In [38]:
f = Array([[20],[-7],[4],[3]])
In [39]:
sf=Array.foward_sub(F,f)
In [40]:
print(sf)
In [41]:
F*sf
Out[41]:
In [42]:
F[0,1] = 1
In [43]:
sf=Array.foward_sub(F,f)
In [44]:
B = Array([[4,-1,2,3],[0,-2,7,-4],[0,0,6,5],[0,0,0,3]])
In [45]:
b = Array([[20],[-7],[4],[6]])
In [46]:
sb=Array.backward_sub(B,b)
In [47]:
print(sb)
In [48]:
B*sb
Out[48]:
In [49]:
A = Array([[0,-2,3,1],[0,4,-3,2],[1,2,-3,2],[-2,-4,5,-10]])
In [50]:
P,L,U = Array.lu_decomposition(A)
In [51]:
P
Out[51]:
In [52]:
L
Out[52]:
In [53]:
U
Out[53]:
In [54]:
P*A
Out[54]:
In [55]:
L*U
Out[55]:
In [56]:
y = Array([[6],[1],[0],[5]])
In [57]:
A
Out[57]:
In [58]:
x = Array.lu_linsolve(A,y)
In [59]:
print(x)
In [60]:
print(A*x)
In [ ]:
In [ ]: