Matrices Dispersas Un ejemplo de aplicación de POO en Python. Introducción a la Computación Clase 24 Patricia Borensztejn Diccionarios y Tuplas • Refrescamos diccionarios porque los vamos a usar para representar matrices dispersas. Tupla • La tupla es una secuencia heterogénea de elementos, accesible a través de un índice. • Las tuplas se diferencian de las listas porque las tuplas no son objetos dinámicos, por lo tanto son INMUTABLES, como las cadenas y como los escalares. • Se declaran usando como separador una coma Tuplas y Listas • Las tuplas se acceden mediante un índice. • Pero: >>> t = ("a", "b", "mpilgrim", "z", "example") >>> t ('a', 'b', 'mpilgrim', 'z', 'example') >>> t[0] 'a' >>> t[-1] 'example' >>> t[1:3] ('b', 'mpilgrim') – No se pueden modificar – No existen métodos o funciones para trabajar con ellas – Entonces… para que sirven? Diccionarios • También llamados matrices asociativas, relacionan una clave y un valor. • Por ejemplo: d = {“Nueve Reinas “: “Fabián Bielinsky”, “Kill Bill”: “Tarantino”, “Amélie”: “Jean-Pierre Jeunet”} • El primer valor es la clave, y el segundo es el valor. • Como clave podemos utilizar cualquier valor inmutable: números, cadenas, booleanos, tuplas (para eso sirven!) Diccionarios • El acceso a los valores almacenados no se realiza a través de un índice como en el caso de las listas o las tuplas, sino por medio de su clave. • Asi: d [“Nueve Reinas “] # devuelve “Fabián Bielinsky”, • Se pueden asignar valores a los valores. • NO se pueden obtener claves usando los valores. Algunos métodos del tipo Diccionario dict.clear() elimina todos los elementos del diccionario dict dict.get(clave,[default]) devuelve el valor de la clave o lo que definamos por defecto si la clave no se encuentra en el diccionario dict.has_key(clave) devuelve 1 si la clave se encuentra en el diccionario. En cualquier otro caso devuelve 0. dict.items() devuelve una lista de pares de tuplas clave-valor. dict.keys() devuelve una lista de claves dict.values() devuelve la lista de valores dict.update(dict2) añade los pares clave-valor del diccionario dict2 al diccionario dict Matriz Dispersa • Podemos almacenarla con un diccionario cuya clave sea una tupla=(i,j) valores clave: tuplas Matriz Dispersa • Problema: si accedemos a un elemento nulo, como no existe la clave, tenemos un error. >>> matriz = {(0,3):1,(2,1):1,(4,3):3} >>> matriz[0,3] 1 >>> matriz[0,0] Traceback (most recent call last): File "<pyshell#2>", line 1 matriz[0,0] KeyError: (0, 0) >>> Matriz Dispersa • Cuidarnos de no acceder elementos nulos…. Clase MatrizDispersa • Queremos implementar una clase que herede todos los métodos del tipo diccionario. • Entonces definimos así: class sparse(dict): """ Formato del Diccionario: { (i,j): value, ... } donde (i,j) son los índices de la matriz """ pass • No tiene __init__. La usamos. >>> A=sparse() >>> A={(0,0):1,(2,4):7} >>> print A {(0, 0): 1, (2, 4): 7} Clase Matriz Dispersa • Agregamos un método para imprimir la matriz dispersa class sparse(dict): def out(self): print '# (i, j) -- value' for k in self.keys(): print k, self[k] Imprimir • Fíjense que como la implementación es con diccionario, no hay orden. a = sparse({(0,0):2.0, (0,1):1.0, (1,0):1.0, (1,1):2.0, (1,2):1.0, (2,1):1.0, (2,2):2.0}) print "a=", a a.out() >>> a= {(0, 1): 1.0, (1, 2): 1.0, (0, 0): 2.0, (2, 2): 2.0, (1, 0): 1.0, (1, 1): 2.0, (2, 1): 1.0} # (i, j) -- value (0, 1) 1.0 (1, 2) 1.0 (0, 0) 2.0 (2, 2) 2.0 (1, 0) 1.0 (1, 1) 2.0 (2, 1) 1.0 Imprimir en orden • Agregamos un método para imprimir la matriz dispersa, pero manteniendo el orden class sparse(dict): def out(self): print '# (i, j) -- value' for k in self.keys(): print k, self[k] def out2(self): print '# (i, j) -- value' indice=self.keys() indice.sort() for k in indice: print k, self[k] Imprimir en orden a = sparse({(0,0):2.0, (0,1):1.0, (1,0):1.0, (1,1):2.0, (1,2):1.0, (2,1):1.0, (2,2):2.0}) print "a=", a a.out2() a= {(0, 1): 1.0, (1, 2): 1.0, (0, 0): 2.0, (2, 2): 2.0, (1, 0): 1.0, (1, 1): 2.0, (2, 1): 1.0} # (i, j) -- value (0, 0) 2.0 (0, 1) 1.0 (1, 0) 1.0 (1, 1) 2.0 (1, 2) 1.0 (2, 1) 1.0 (2, 2) 2.0 Imprimir • Ahora me interesa imprimir la matriz completa. class sparse(dict): def size(self): " returns # of rows and columns " nrow = 0 ncol = 0 for key in self.keys(): nrow = max([nrow, key[0]+1]) ncol = max([ncol, key[1]+1]) return (nrow, ncol) def imprime_completa(self): nrow,ncol=self.size() for i in range (0,nrow): for j in range (0,ncol): print str(self.get((i,j),0.0)), print "\n" Imprimir Matriz Dispersa a= {(0, 1): 1.0, (1, 2): 1.0, (0, 0): 2.0, (2, 2): 2.0, (1, 0): 1.0, (1, 1): 2.0, (2, 1): 1.0} # (i, j) -- value (0, 0) 2.0 (0, 1) 1.0 (1, 0) 1.0 (1, 1) 2.0 (1, 2) 1.0 (2, 1) 1.0 (2, 2) 2.0 2.0 1.0 0.0 1.0 2.0 1.0 0.0 1.0 2.0 Vamos a sumar y restar matrices dispersas def __add__(self, other): res = sparse(self.copy()) for ij in other: res[ij] = self.get(ij,0.) + other[ij] return res def __sub__(self, other): res = sparse(self.copy()) for ij in other: res[ij] = self.get(ij,0.) - other[ij] return res Ejercicio • Multiplicar matrices dispersas. • Para multiplicar dos matrices dispersas, a y b, el número de filas de a debe ser igual al número de columnas de b. Esa condición debe comprobarse, y en caso de que no se cumpla, se debe generar un mensaje de error.