In [1]:
# import numpy as np # Importo librería NumPy como np
In [2]:
import copy as cp
class Array:
#----------[ Metodo constructor y validador:
def __init__(self, list_of_rows):
""" Metodo Constructor y Validador
2. Un validador
Parámetros:
.- list_of_rows: lista de arrays que asigna al atributo DATA
y ademas en SHAPE define la dimensión del mismo.
Ejemplo:
A = Array([[1,2,3],[4,5,6],[7,8,9]])
"""
# 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")
#---------- Metodo constructor y validador ].
#----------[ Metodo para imprimir sin función Print:
def __repr__(self):
""" 1. Un metodo para imprimir mejor...
Metodo para imprimir un Array sin utilizar print
"""
nrow, ncol = self.shape
data_out = "array(["
data_line = "["
espacio = max(max([[len(str(self.data[i][j])) for i in range(nrow)] for j in range(ncol)]))
for i in range(nrow):
data_line = "[" + str(", ".join(map(lambda i: ('{:.0f}'.format(i)).rjust(espacio), self.data[i]))) + "]"
if i < (nrow - 1):
data_out += data_line + ",\n "
else:
data_out += data_line + "])"
return (data_out)
#---------- Metodo para imprimir sin función Print ].
#----------[ Metodo para imprimir con función Print:
def __str__(self):
""" 1. Un metodo para imprimir mejor...
Metodo para imprimir un Array utilizando print
"""
nrow, ncol = self.shape
data_out = "["
data_line = "["
espacio = max(max([[len(str(self.data[i][j])) for i in range(nrow)] for j in range(ncol)]))
for i in range(nrow):
data_line = "[" + str(" ".join(map(lambda i: ('{:.0f}'.format(i)).rjust(espacio), self.data[i]))) + "]"
if i < (nrow - 1):
data_out += data_line + "\n "
else:
data_out += data_line + "]"
return (data_out)
#---------- Metodo para imprimir con función Print ].
#----------[ Metodo para obtener un item:
def __getitem__(self, idx, ini=0):
""" 3.1. Indexing and Item assignment
Retorna un item
"""
if ("slice" not in str(idx[0])) & ("slice" not in str(idx[1])) :
nrow, ncol = self.shape
if idx[0] <= nrow | idx[1] <= ncol:
if ini == 0:
return self.data[idx[0]][idx[1]]
else:
return self.data[(idx[0] - 1)][(idx[1] -1) ]
else:
raise Exception("La dimensión no corresponde con la del Array!")
else:
return NotImplemented
#---------- Metodo para obtener un item ].
#----------[ Metodo para modificar un item:
def __setitem__(self, idx, new_value, ini=0):
""" 3.2. Indexing and Item assignment
Modifica el valor de un item particular:
"""
nrow, ncol = self.shape
if idx[0] <= nrow | idx[1] <= ncol:
if ini == 0:
self.data[idx[0]][idx[1]] = new_value
else:
self.data[(idx[0] - 1)][(idx[1] -1)] = new_value
print("Item modificado.")
else:
raise Exception("La dimensión no corresponde con la del Array!")
#---------- Metodo para modificar un item ].
#----------[ Función para crear Matriz de Ceros:
def zeros(shape):
""" 4.1. Iniciar una matriz en Ceros
Genera un Array de Ceros de la dimensión indicada
Parametros
----------
shape: (n,m) -> n filas x m columnas
"""
if isinstance(shape, tuple):
nrow, ncol = shape
elif isinstance(shape, int):
nrow = ncol = shape
else:
raise Exception("Parámetro no definido.")
newArray = Array([[0 for i in range(ncol)] for j in range(nrow)])
return newArray
#---------- Función para crear Matriz de Ceros ].
#----------[ Función para crear Matriz Identidad:
def eye(n,m=0,k=0):
""" 4.2. Iniciar una matriz con Unos en la diagonal
Parametros
----------
n: Número de filas
m: Número de columnas (opcional)
Por defecto m = n
k: Desplaza la diagonal (opcional)
k = 0: Daigonal principal (valor por defect)
k > 0: Diagonal superior
k < 0: Diagonal inferior
"""
if m == 0: m = idxy = n
elif n > m: idxy = n
else: idxy = m
idx = 0
idy = 0
newArray = Array.zeros((n,m))
for i in range(idxy):
idx = idy = i
if k == 0:
if (idx < n) & (idy < m):
# Asigno 1 a la diagonal
newArray.data[idx][idy] = 1.0
elif k > 0:
idy += k
if (idx < n) & (idy < m):
# Asigno 1 a la diagonal
newArray.data[idx][idy] = 1.0
else:
idx += k
if (idx < n) & (idy < m) & (idx >= 0):
# Asigno 1 a la diagonal
newArray.data[idx][idy] = 1.0
return newArray
#---------- Función para crear Matriz Identidad ].
#----------[ Metodo para generar la matriz transpuesta:
def transpose(self):
""" 5. Transposicion
Calcula la Transpuesta de una matriz
"""
nrow, ncol = self.shape
return Array([[self.data[j][i] for j in range(nrow)] for i in range(ncol)])
#---------- Metodo para generar la matriz transpuesta ].
#----------[ Metodo para sumar arrays:
def __add__(self, other):
""" 6.1. Suma
Suma Arrays
"""
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
#---------- Metodo para sumar arrays ].
#----------[ Metodo para sumar arrays:
def __radd__(self, other):
""" 6.2. Suma
Suma Arrays
"""
return self.__add__(other)
#---------- Metodo para sumar arrays ].
#----------[ Metodo para restar arrays:
def __sub__(self, other):
""" 6.3. Resta
Resta Arrays
"""
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
#---------- Metodo para restar arrays ].
#----------[ Metodo para sumar arrays:
def __rsub__(self, other):
""" 6.3. Resta
Resta Arrays
"""
return self.__sub__(other)
#---------- Metodo para sumar arrays ].
#----------[ Metodo para Multiplicar arrays:
def __mul__(self, other):
""" 7. Multiplicacion Matricial
Multiplica Arrays:
"""
if isinstance(other, Array):
other_t = other.transpose() # Obtengo transpuestas
idx = 0
idy = 0
list_of_rows = []
list_of_calc = [0 for x in range(self.shape[0])] # Creo lista de long. n con Ceros
for x in range(self.shape[0] * other.shape[1]): # Itero n x m
# Calculo la suma de multiplicar Fila Nx por Columna My
# list_of_calc[idx] = (sum(i*j for i,j in zip(self.data[idy], other_t.data[idx])))
list_of_calc[idx] = (sum(i*j for i,j in zip(other_t.data[idy], self.data[idx])))
if idx == (self.shape[0] - 1):
idx = 0
idy += 1
list_of_rows.append(cp.copy(list_of_calc))
else:
idx += 1
if "Vector" not in str(type(other)):
return Array(list_of_rows)
else:
return Vector(list_of_calc)
elif isinstance(other, int):
if "Vector" not in str(type(self)):
nrow, ncol = self.shape
return Array([[self.data[i][j] * other for j in range(nrow)] for i in range(ncol)])
else:
return NotImplemented
else:
return NotImplemented
#---------- Metodo para Multiplicar arrays: ].
#----------[ Metodo para sumar arrays:
def __rmul__(self, other):
""" 7. Multiplicacion Matricial
Multiplica Arrays:
"""
return self.__mul__(other)
#---------- Metodo para sumar arrays ].
#-------------------------------------------------------------------------------------------------------------#
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])
def __sub__(self, other):
new_arr = Array.__sub__(self, other)
return Vector([x[0] for x in new_arr.data])
#----------[ Metodo para Multiplicar arrays:
def __mul__(self, other):
""" 8. Multiplicacion de Vectores
Multiplica Arrays:
"""
print(NotImplemented)
return NotImplemented
#---------- Metodo para Multiplicar arrays: ].
#-------------------------------------------------------------------------------------------------------------#
In [3]:
A = Array([[1,2,3], [4,5,6],[7,8,9]])
A.__dict__ # el campo escondido __dict__ permite acceder a las propiedades de clase de un objeto
Out[3]:
In [4]:
A.data, A.shape
Out[4]:
In [5]:
print(A) # Muestro el contenido de A utilizando la función print
In [6]:
A # Muestro el contenido de A sin utilizar la función print
Out[6]:
In [7]:
A[0,0] # Accedo al valor de una posición
Out[7]:
In [8]:
A[0,0] = -3 # Modifico el valor de una posición
A
Out[8]:
In [9]:
Z = Array.zeros((3,3)) # Genero matriz de m x n de Ceros
Z
Out[9]:
In [10]:
E = Array.eye(3,3) # Genero matriz de m x n con 1s en la diagonal
E
Out[10]:
In [11]:
T = A.transpose() # Obtengo la transpuesta de A
T
Out[11]:
In [12]:
S1 = A + T # Sumo Matrices
S1
Out[12]:
In [13]:
S2 = A + 10 # Sumo Matriz + Escalar
S2
Out[13]:
In [14]:
M1 = A * T # Multiplico Matrices
M1
Out[14]:
In [15]:
M2 = A * 5 # Multiplico Matriz por un Escalar
M2
Out[15]:
In [16]:
Vector([1,2,3]).__dict__
Out[16]:
In [17]:
vec = Vector([1,2,3])
vec
Out[17]:
In [18]:
Vector([1,2,3]) + Vector([5,-2,0])
Out[18]:
In [19]:
(vec + 10) - 5
Out[19]:
In [20]:
MV = A * vec
MV
Out[20]: