<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Algebra lineare
Step1:  All'identificatore lista01 è associata una lista che contiene quattro elementi
Step2:  Per creare liste numeriche è utile la funzione range che restituisce, uno alla volta i numeri naturali
Step3:  Le liste si possono creare ultilizzando una sintassi molto sintetica detta "listcompreension". Ad esempio se volessi una lista che contiene tutti i numeri naturali minori di 5 potrei scrivere
Step4:  Se volessi una lista con i quadrati dei primi dieci naturali
Step5:  E se volessi una lista con i primi cinque naturali, i loro quadrati e i loro cubi
Step6:  Possiamo anche creare una lista di numeri interi casuali, per fare questo dobbiamo però caricare una particolare funzione dalla libreria "random"
Step7:  Una lista di stringhe può essere trasformata in una stringa concatenando tutti i suoi elementi
Step8:  Per eseguire le operazioni tra matrici, avremo bisogno anche di accoppiare elementi tratti da due liste diverse. L'iteratore "zip" fa esattamente questo. Se vogliamo ottenere una lista con le somme dei numeri contenuti in due altre liste, possiamo utilizzare la listcompreension con l'iteratore zip
Step9:  Ora che abbiamo preso un po' di confidenza con le lista Python, possiamo emulare la matrice usando una lista di sottoliste dove ogni sottolista rappresenta una riga della matrice
Step10:  Tenendo presente che in Python gli indici iniziano sempre da zero, si uò estrarre o modificare un elemento della matrice utilizzando gli indici. Ad esempio per estrarre il numero 7 dalla matrice precedente bisogna prendere dalla riga numero uno l'elemento numero due.
Step11:  Allo stesso modo, cioè sempre usando gli indici è anche possibile cambiare un elemento di una  matrice
Step12:  In Python possiamo realizzare delle matrici usando liste di liste, ma le matrici matematiche che vogliamo utilizzare devono avere qualcosa di più
Step17:  Il confronto funziona, ma la somma non ci va bene
Step19:  Dopo aver scritto le funzioni e averne controllato la correttezza,
siamo ora in grado di creare il nuovo tipo Matrix. 
Matrix è il nome associato alla classe che vogliamo realizzare
Classi
In Python è possibile definire un nuovo tipo di dati con tutti i suoi comportamenti, lo si fa definendo una nuova classe
Step20:  È possibile realizzare un oggetto matrice con il seguente comando
Step22:  L'oggetto matr02 viene creato, è di tipo matrice, 
ma questo oggetto non ha molte proprietà, 
anzi non ne abbiamo definite per niente.
Per dare delle proprietà alla nostra classe dobbiamo definire 
attributi che sono variabili legate all'oggetto e 
metodi che sono funzioni legate alla classe.
Aggiungiamo un attributo che contenga la matrice-lista, 
un attributo per il numero di righe e 
uno per il numero di colonne della matrice.
La classe Matrix avrà un primo metodo __init__ che viene eseguito 
quando viene costruito l'oggetto. Questo metodo ha due parametri
Step25:  Aggiungiamo anche un metodo che trasformi la matrice in una stringa 
separando gli elementi di ogni riga con un tabulatore e 
le righe con un acapo.
Step30:  Possiamo ora indicare a Python come sommare due oggetti Matrice. Il programma diventa
Step31:  E se le matrici che vogliamo addizionare non hanno le stesse dimensioni?
Step36:  Il risultato che otteniamo è sbagliato, 
 bisogna controllare le dimensioni, 
 eseguire l'addizione se è possibile farlo, altrimenti
 sollevare un'eccezione.
Step38:  Giustamente la seconda operazione prduce un errore.
Ora abbiamo tutti (quasi) gli elementi per scrivere una libreria
che supporti il calcolo con le matrici.
Libreria per il calcolo con le matrici
Capiti i concetti di base, possiamo scrivere una libreria che implementi il calcolo con le matrici.
Partiamo da un file vuoto e impostiamo il lavoro. Lo salviamo con il nome "matrix.py", scriviamo una breve intestazione con qualche informazione esseziale
Step40:  Ora definiamo le funzioni di supporto e il programma principale. Dato che quella che vogliamo scrivere è una libreria che verrà chiamata da altri programmi, il programma principale potrebbe anche essere vuoto, costituito dalla sola istruzione pass o mancare del tutto. Ma noi vogliamo scrive un programma seguendo un metodo ben preciso quindi nel programma principale carichiamo una  libreria e ne avviamo una funzione.
Step42:  Test Driven Development
Il TDD è lo sviluppo del software guidato dai test. 
L'idea di fondo è che prima di scrivere ogni singola funzione del programma, 
definisco il test che quella funzione dovrà passare.
Nel caso della funzione matr_zero, 
noi vogliamo poter creare una lista di liste che contengono tutti zeri e 
vogliamo poterla stampare. Queste condizioni che la funzione deve soddisfare
le inseriamo nella stringa di documentazione della funzione 
con anche il risultato atteso.
Step44:  Possiamo osservare che sono stati eseguiti due test, 
uno per ogni istruzione che inizia con &gt;&gt;&gt; e che non hanno dato errori.
Vediamo che doctest ci dice quali test sono passati 
e quali sono falliti, ma sebbene questo generalmente 
sia molto incoraggiante, noi siamo più interessati a 
sapere quali test falliscono e quindi nelle prossime 
esecuzioni mettiamo a False il parametro verbose.
Funzioni
Riprendiamo la scrittura della nostra libreria. 
Inseriamo le quattro funzioni sviluppate precedentemente
Step46:  Ovviamente il test fallisce. Osserviamo gli errori che segnala.
Il primo è dovuto al fatto che la funzione matr_random ha due 
parametri che abbiamo dimenticato.
Il secondo deriva dal fatto che non abbiamo definito la funzione, 
ma solo la sua docstring.
Scrivere il codice della funzione
che sarà molto simile a quello di matr_zero.
Step48:  La funzione è corretta, ma il test fallisce perché 
non riusciamo a prevedere quali numeri si inventerà 
la funzione randrange. 
Ma possiamo dire a doctest di considerare questo fatto
usando la direttiva
Step51:  Questa volta il test passa.
Scriviamo ora il test per le funzioni vect_add e vect_mul.
Step54:  Veniamo avvisati che due test non sono passati.
Ottimo!
Andiamo a completare le due funzioni in modo che superino i test.
Step57:  Benissimo, il nostro programma sta prendendo forma 
ed è già così robusto da superare i test.
La classe Matrix
È ora di realizzare la classe Matrix. 
Aggiungiamo l'intestazione della classe e il suo metodo __init__.
Step61:  Altro metodo utile da scrivere prima di passare alle operazioni
con le matrici è il metodo che viene chiamato quando si vuole 
tradurre la matrice in una stringa, magari per stamparla.
Il metodo ha un nome particolare __str__.
Step65:  Giusto, abbiamo detto a Python cose deve produrre __str__,
ora dobbiamo dire come ottenerlo.
Vogliamo realizzare una stringa concatenando gli elementi contenuti in ogni riga 
separandoli con un tabulatore e 
concatenare le righe separandole con un acapo.
Step69:  Accidenti, questa volta il test fallisce 
perché otteniamo un diverso numero di spazi. 
Ma gli spazi ci interessano relativamente, 
Possiamo farglielo sapere a doctest usando una direttiva.
Step75:  Due metodi utili nelle matrici sono quelli che ci permettono 
di estrarre una riga o una colonna dati i corrispondenti indici,
li chiameremo row e col.
Step81:  Bene, descritto cosa vogliamo ottenere, passiamo a scrivere il codice.
row sarà semplicissimo
Step99:  Ora abbiamo tutti gli elementi per completare la nostra libreria. 
Im metodo da seguire prevede alcuni sempli regole
<ASSISTANT_TASK:>
Python Code:
lista01 = ['pippo', 4, 5.7, ['lista', 'di', 'parole']]
Explanation: Algebra lineare: matrici
In matematica, una matrice è uno schieramento rettangolare di oggetti.
Sulle matrici sono definite alcune operazioni e le matrici vengono usate in diversi campi della matematica.
In questo lavoro vedremo come realizzare delle matrici in Python. 
Prima di immergerci nel nostro lavoro, esploriamo alcuni elementi 
di Python che saranno utili strumenti con i quali realizzare le matrici. 
Python
Liste
Python non ha un oggetto che corrisponda esattamente ad una matrice o ad un array a due dimensioni. Lo si può emulare con una lista di liste.
Una lista è una sequenza ordinata di oggetti, la si può creare ponendo tra parentesi quadre gli oggetti della lista separati da virgole:
End of explanation
print(lista01[0])
print(lista01[1])
print(lista01[2])
print(lista01[3])
print(lista01[3][0])
print(lista01[3][1])
print(lista01[3][2])
Explanation: All'identificatore lista01 è associata una lista che contiene quattro elementi:
una stringa;
un numero intero;
un numero in virgola mobile;
una lista di stringhe.
Le liste sono indicizzabili, teniamo presente che l'indice del primo elemento di una lista è sempre il numero zero.
End of explanation
for elemento in range(5):
    print(elemento)
Explanation: Per creare liste numeriche è utile la funzione range che restituisce, uno alla volta i numeri naturali:
End of explanation
[elemento for elemento in range(5)]
Explanation: Le liste si possono creare ultilizzando una sintassi molto sintetica detta "listcompreension". Ad esempio se volessi una lista che contiene tutti i numeri naturali minori di 5 potrei scrivere:
End of explanation
[elemento**2 for elemento in range(5)]
Explanation: Se volessi una lista con i quadrati dei primi dieci naturali:
End of explanation
[[elemento, elemento**2, elemento**3] for elemento in range(5)]
Explanation: E se volessi una lista con i primi cinque naturali, i loro quadrati e i loro cubi:
End of explanation
import random
lista05 = [random.randrange(10) for _ in range(20)]
print(lista05)
Explanation: Possiamo anche creare una lista di numeri interi casuali, per fare questo dobbiamo però caricare una particolare funzione dalla libreria "random":
End of explanation
lista06 = ['Et', 'telefono', 'casa']
' '.join(lista06)
Explanation: Una lista di stringhe può essere trasformata in una stringa concatenando tutti i suoi elementi:
End of explanation
lista07 = [random.randrange(10, 50) for _ in range(10)]
lista08 = [random.randrange(10, 50) for _ in range(10)]
somma = [a + b for a, b in zip(lista07, lista08)]
print(lista07)
print(lista08)
print(somma)
Explanation: Per eseguire le operazioni tra matrici, avremo bisogno anche di accoppiare elementi tratti da due liste diverse. L'iteratore "zip" fa esattamente questo. Se vogliamo ottenere una lista con le somme dei numeri contenuti in due altre liste, possiamo utilizzare la listcompreension con l'iteratore zip:
End of explanation
matr01 = [[1, 4, 6], [2, 3, 7]]
print(matr01)
matr02 = [[random.randrange(10) for _ in range(3)], [random.randrange(10) for _ in range(3)]]
print(matr02)
matr02 = [[random.randrange(10) for _ in range(3)] for _ in range(2)]
print(matr02)
Explanation: Ora che abbiamo preso un po' di confidenza con le lista Python, possiamo emulare la matrice usando una lista di sottoliste dove ogni sottolista rappresenta una riga della matrice:
End of explanation
matr01[1][2]
Explanation: Tenendo presente che in Python gli indici iniziano sempre da zero, si uò estrarre o modificare un elemento della matrice utilizzando gli indici. Ad esempio per estrarre il numero 7 dalla matrice precedente bisogna prendere dalla riga numero uno l'elemento numero due.
End of explanation
matr01[1][2] = 9
print(matr01)
Explanation: Allo stesso modo, cioè sempre usando gli indici è anche possibile cambiare un elemento di una  matrice:
End of explanation
matr03 = [[1, 4, 6], [2, 3, 9]]
print(matr03)
print(matr01 == matr03)
print(matr01 + matr03)
Explanation: In Python possiamo realizzare delle matrici usando liste di liste, ma le matrici matematiche che vogliamo utilizzare devono avere qualcosa di più: con le nostre matrici vogliamo anche poter eseguire alcune operazioni. Vogliamo poter confrontarle, addizionarle, moltiplicarle, ...
End of explanation
def matr_zero(rows, cols):
    Return a bidimensional matrix of zeros.
    pass
    
def matr_random(rows, cols, mi, ma):
    Return a bidimensional matrix of random integers.
    pass
def vect_add(matr1, matr2):
    Return vectors sum.
    pass
def vect_scalar_product(matr1, matr2):
    Return vectors scalar product.
    pass
print(matr_zero(4, 5))
print(matr_random(4, 5, 10, 10))
print(vect_add([3, 4, 5], [4, 3, 2]))
print(vect_scalar_product([3, 4, 5], [4, 3, 2]))
Explanation: Il confronto funziona, ma la somma non ci va bene: estende la matrice invece che addizionare gli elementi.
Dobbiamo quindi creare noi un nuovo oggetto ch si comporti come una matrice.
Funzioni
Prima di creare una matrice creiamo alcune funzioni che ci saranno utili:
* una funzione che crea una matrice zero;
* una funzione che crea una matrice, di date dimensioni, composta da numeri casuali;
* una funzione che sommi due vettori;
* una funzione che calcoli il prodotto scalare di due vettori.
Scriviamo le seguenti funzioni e controlliamo che i risultati forniti siano corretti.
End of explanation
class Matrix():
    Classe che implementa le matrici.
Explanation: Dopo aver scritto le funzioni e averne controllato la correttezza,
siamo ora in grado di creare il nuovo tipo Matrix. 
Matrix è il nome associato alla classe che vogliamo realizzare
Classi
In Python è possibile definire un nuovo tipo di dati con tutti i suoi comportamenti, lo si fa definendo una nuova classe:
End of explanation
matr02 = Matrix()
print(matr02)
Explanation: È possibile realizzare un oggetto matrice con il seguente comando:
End of explanation
class Matrix():
    Matrix class.
    def __init__(self, matr):      # Metodo che inizializza l'oggetto.
        self.matr = matr           # Attributo che contiene la matrice.
        self.rows = len(matr)      # numero di righe
        self.cols = len(matr[0])   # numero di colonne
        
matr02 = Matrix([[1, 2], [2, 3], [3, 4], [4, 5]])
print('righe:', matr02.rows, 'colonne:', matr02.cols)
Explanation: L'oggetto matr02 viene creato, è di tipo matrice, 
ma questo oggetto non ha molte proprietà, 
anzi non ne abbiamo definite per niente.
Per dare delle proprietà alla nostra classe dobbiamo definire 
attributi che sono variabili legate all'oggetto e 
metodi che sono funzioni legate alla classe.
Aggiungiamo un attributo che contenga la matrice-lista, 
un attributo per il numero di righe e 
uno per il numero di colonne della matrice.
La classe Matrix avrà un primo metodo __init__ che viene eseguito 
quando viene costruito l'oggetto. Questo metodo ha due parametri:
* self è un riferimento all'oggetto;
* matr contiene la matrice sotto forma di lista.
Il metodo __init__ lega all'attributo matr
dell'oggetto che si sta creando, la lista matr 
passata come argomento e agli attributi rows e cols
rispettivamente il numero di righe e di colonne della matrice.
End of explanation
class Matrix():
    Matrix class.
    def __init__(self, matr):      # Metodo che inizializza l'oggetto.
        self.matr = matr           # Attributo che contiene la matrice.
        self.rows = len(matr)      # numero di righe
        self.cols = len(matr[0])   # numero di colonne
        
    def __str__(self):
        Matrix to string.
        return "\n".join(["\t".join(map(str, r)) for r in self.matr])
m_0 = Matrix([[1, 2], [2, 3], [3, 4], [4, 5]])
print(m_0)
Explanation: Aggiungiamo anche un metodo che trasformi la matrice in una stringa 
separando gli elementi di ogni riga con un tabulatore e 
le righe con un acapo.
End of explanation
def vect_add(v0, v1):
    Return vectors sum.
    return [a+b for a, b in zip(v0, v1)]
class Matrix():
    Matrix class.
    def __init__(self, matr):      # Metodo che inizializza l'oggetto.
        self.matr = matr           # Attributo che contiene la matrice.
        self.rows = len(matr)      # numero di righe
        self.cols = len(matr[0])   # numero di colonne
        
    def __str__(self):
        Matrix to string.
        return "\n".join(["\t".join(map(str, r)) for r in self.matr])
    
    def __add__(self, other):
        Matrix sum.
        return Matrix([vect_add(a, b) for a, b in zip(self.matr, other.matr)])
m_a = Matrix([[2, 3, 4], [0, 2, 3]])
m_b = Matrix([[1, 2, 3], [4, 5, 6]])
print(m_a + m_b)
Explanation: Possiamo ora indicare a Python come sommare due oggetti Matrice. Il programma diventa:
End of explanation
m_a = Matrix([[2, 3, 4, 6], [0, 2, 3, 4]])
m_b = Matrix([[1, 2, 3], [4, 5, 6]])
print(m_a + m_b)
Explanation: E se le matrici che vogliamo addizionare non hanno le stesse dimensioni?
End of explanation
def vect_add(v0, v1):
    Return vectors sum.
    return [a+b for a, b in zip(v0, v1)]
class Matrix():
    Matrix class.
    def __init__(self, matr):      # Metodo che inizializza l'oggetto.
        self.matr = matr           # Attributo che contiene la matrice.
        self.rows = len(matr)      # numero di righe
        self.cols = len(matr[0])   # numero di colonne
        
    def __str__(self):
        Matrix to string.
        return "\n".join(["\t".join(map(str, r)) for r in self.matr])
    
    def __add__(self, other):
        Matrix sum.
        if self.rows == other.rows and self.cols == other.cols:
            return Matrix([vect_add(a, b) for a, b in zip(self.matr, other.matr)])
        else:           # raises an exception if the matrixes are not the same size.
            raise Exception("Matrixes can't be added.")
m_a = Matrix([[2, 3, 4], [0, 2, 3]])
m_b = Matrix([[1, 2, 3], [4, 5, 6]])
print(m_a + m_b)
m_a = Matrix([[2, 3, 4, 6], [0, 2, 3, 4]])
m_b = Matrix([[1, 2, 3], [4, 5, 6]])
print(m_a + m_b)
Explanation: Il risultato che otteniamo è sbagliato, 
 bisogna controllare le dimensioni, 
 eseguire l'addizione se è possibile farlo, altrimenti
 sollevare un'eccezione.
End of explanation
# 30 marzo 2015
# Daniele
# Matrici
# GPL 3
class Matrix with operations.
from __future__ import division, print_function   # for compatibility with 2.x
import random
Explanation: Giustamente la seconda operazione prduce un errore.
Ora abbiamo tutti (quasi) gli elementi per scrivere una libreria
che supporti il calcolo con le matrici.
Libreria per il calcolo con le matrici
Capiti i concetti di base, possiamo scrivere una libreria che implementi il calcolo con le matrici.
Partiamo da un file vuoto e impostiamo il lavoro. Lo salviamo con il nome "matrix.py", scriviamo una breve intestazione con qualche informazione esseziale: data, titolo, autore, licenza, ...
Scriviamo un breve testo che illustri lo scopo della libreria.
E importiamo qualche libreria che ci tornerà utile.
End of explanation
def matr_zero(rows, cols):
    Return a bidimensional matrix of zeros.
    return [[0 for i in range(cols)] for r in range(rows)]
if __name__=='__main__':
    import doctest
    doctest.testmod(verbose=True)
Explanation: Ora definiamo le funzioni di supporto e il programma principale. Dato che quella che vogliamo scrivere è una libreria che verrà chiamata da altri programmi, il programma principale potrebbe anche essere vuoto, costituito dalla sola istruzione pass o mancare del tutto. Ma noi vogliamo scrive un programma seguendo un metodo ben preciso quindi nel programma principale carichiamo una  libreria e ne avviamo una funzione.
End of explanation
def matr_zero(rows, cols):
    Return a bidimensional matrix of zeros.
>>> m_0 = matr_zero(3, 4)
>>> print(m_0)
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
    
    return [[0 for i in range(cols)] for r in range(rows)]
if __name__=='__main__':
    import doctest
    doctest.testmod(verbose=True)
Explanation: Test Driven Development
Il TDD è lo sviluppo del software guidato dai test. 
L'idea di fondo è che prima di scrivere ogni singola funzione del programma, 
definisco il test che quella funzione dovrà passare.
Nel caso della funzione matr_zero, 
noi vogliamo poter creare una lista di liste che contengono tutti zeri e 
vogliamo poterla stampare. Queste condizioni che la funzione deve soddisfare
le inseriamo nella stringa di documentazione della funzione 
con anche il risultato atteso.
End of explanation
def matr_random(rows, cols, mi, ma):
    Return a bidimensional matrix of random numbers.
>>> m_0 = matr_random(3, 4)
>>> print(m_0)
[[3, 6, 4, 9], [1, 5, 8, 6], [3, 7, 0, 9]]
    
if __name__=='__main__':
    import doctest
    doctest.testmod(verbose=False)
Explanation: Possiamo osservare che sono stati eseguiti due test, 
uno per ogni istruzione che inizia con &gt;&gt;&gt; e che non hanno dato errori.
Vediamo che doctest ci dice quali test sono passati 
e quali sono falliti, ma sebbene questo generalmente 
sia molto incoraggiante, noi siamo più interessati a 
sapere quali test falliscono e quindi nelle prossime 
esecuzioni mettiamo a False il parametro verbose.
Funzioni
Riprendiamo la scrittura della nostra libreria. 
Inseriamo le quattro funzioni sviluppate precedentemente:
matr_zero(rows, cols):
matr_random(rows, cols, mi, ma):
vect_add(matr1, matr2):
vect_scalar_product(matr1, matr2):
Questa volta, come abbiamo fatto per matr_zero,
aggiungiamo per ognuna una doc string che contenga 
almeno un test.
Procediamo con la funzione che crea una lista di liste 
di numei casuali specificando 
le dimensioni della matrice e il range di numeri.
Come sempre scriviamo l'intestazione della funzione, 
la stringa di documentazione (docstring) e il test.
End of explanation
def matr_random(rows, cols, mi, ma):
    Return a bidimensional matrix of random numbers.
>>> m_0 = matr_random(3, 4, 0, 10)
>>> print(m_0)
[[3, 6, 4, 9], [1, 5, 8, 6], [3, 7, 0, 9]]
    
    return [[random.randrange(mi, ma) for i in range(cols)] for r in range(rows)]
if __name__=='__main__':
    import doctest
    doctest.testmod(verbose=False)
Explanation: Ovviamente il test fallisce. Osserviamo gli errori che segnala.
Il primo è dovuto al fatto che la funzione matr_random ha due 
parametri che abbiamo dimenticato.
Il secondo deriva dal fatto che non abbiamo definito la funzione, 
ma solo la sua docstring.
Scrivere il codice della funzione
che sarà molto simile a quello di matr_zero.
End of explanation
def matr_random(rows, cols, mi, ma):
    Return a bidimensional matrix of random numbers.
>>> m_0 = matr_random(3, 4, 0, 10)
>>> print(m_0)                      # doctest: +ELLIPSIS
[[..., ..., ..., ...], [..., ..., ..., ...], [..., ..., ..., ...]]
    
    return [[random.randrange(mi, ma) for i in range(cols)] for r in range(rows)]
if __name__=='__main__':
    import doctest
    doctest.testmod(verbose=False)
Explanation: La funzione è corretta, ma il test fallisce perché 
non riusciamo a prevedere quali numeri si inventerà 
la funzione randrange. 
Ma possiamo dire a doctest di considerare questo fatto
usando la direttiva: +ELLIPSIS 
e i tre puntini per i numeri che possono variare.
End of explanation
def vect_add(v0, v1):
    Return vectors sum.
>>> print(vect_add([2, 4, 6], [3, 5, 0]))
[5, 9, 6]
    
def vect_mul(v0, v1):
    Return vectors scalar product.
>>> print(vect_mul([2, 4, 6], [3, 5, 0]))
26
    
if __name__=='__main__':
    import doctest
    doctest.testmod(verbose=False)
Explanation: Questa volta il test passa.
Scriviamo ora il test per le funzioni vect_add e vect_mul.
End of explanation
def vect_add(v0, v1):
    Return vectors sum.
>>> print(vect_add([2, 4, 6], [3, 5, 0]))
[5, 9, 6]
    
    return [a+b for a, b in zip(v0, v1)]
def vect_mul(v0, v1):
    Return vectors scalar product.
>>> print(vect_mul([2, 4, 6], [3, 5, 0]))
26
    
    return sum([a*b for a, b in zip(v0, v1)])
if __name__=='__main__':
    import doctest
    doctest.testmod(verbose=False)
Explanation: Veniamo avvisati che due test non sono passati.
Ottimo!
Andiamo a completare le due funzioni in modo che superino i test.
End of explanation
class Matrix():
    Matrix class.
    def __init__(self, matr):
        Matrix init.
>>> m_0 = Matrix(matr_zero(4, 3))
>>> print(m_0.rows, m_0.cols)
4 3
>>> print(m_0.matr)
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
        
        self.matr = matr           # Attributo che contiene la matrice.
        self.rows = len(matr)      # numero di righe
        self.cols = len(matr[0])   # numero di colonne
        
if __name__ == '__main__':
    import doctest
    doctest.testmod(verbose=False)
Explanation: Benissimo, il nostro programma sta prendendo forma 
ed è già così robusto da superare i test.
La classe Matrix
È ora di realizzare la classe Matrix. 
Aggiungiamo l'intestazione della classe e il suo metodo __init__.
End of explanation
class Matrix():
    Matrix class.
    def __init__(self, matr):
        Matrix init.
>>> m_0 = Matrix(matr_zero(4, 3))
>>> print(m_0.rows, m_0.cols)
4 3
>>> print(m_0.matr)
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
        
        self.matr = matr           # Attributo che contiene la matrice.
        self.rows = len(matr)      # numero di righe
        self.cols = len(matr[0])   # numero di colonne
        
    def __str__(self):
        Matrix to string.
>>> m_0 = Matrix(matr_zero(2, 3))
>>> print(m_0)
0  0  0
0  0  0
        
if __name__=='__main__':
    import doctest
    doctest.testmod(verbose=False)
Explanation: Altro metodo utile da scrivere prima di passare alle operazioni
con le matrici è il metodo che viene chiamato quando si vuole 
tradurre la matrice in una stringa, magari per stamparla.
Il metodo ha un nome particolare __str__.
End of explanation
class Matrix():
    Matrix class.
    def __init__(self, matr):
        Matrix init.
>>> m_0 = Matrix(matr_zero(4, 3))
>>> print(m_0.rows, m_0.cols)
4 3
>>> print(m_0.matr)
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
        
        self.matr = matr           # Attributo che contiene la matrice.
        self.rows = len(matr)      # numero di righe
        self.cols = len(matr[0])   # numero di colonne
        
    def __str__(self):
        Matrix to string.
>>> m_0 = Matrix(matr_zero(2, 3))
>>> print(m_0)
0  0  0
0  0  0
        
        return "\n".join(["\t".join(map(str, r)) for r in self.matr])
if __name__=='__main__':
    import doctest
    doctest.testmod(verbose=False)
Explanation: Giusto, abbiamo detto a Python cose deve produrre __str__,
ora dobbiamo dire come ottenerlo.
Vogliamo realizzare una stringa concatenando gli elementi contenuti in ogni riga 
separandoli con un tabulatore e 
concatenare le righe separandole con un acapo.
End of explanation
class Matrix():
    Matrix class.
    def __init__(self, matr):
        Matrix init.
>>> m_0 = Matrix(matr_zero(4, 3))
>>> print(m_0.rows, m_0.cols)
4 3
>>> print(m_0.matr)
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
        
        self.matr = matr           # Attributo che contiene la matrice.
        self.rows = len(matr)      # numero di righe
        self.cols = len(matr[0])   # numero di colonne
        
    def __str__(self):
        Matrix to string.
>>> m_0 = Matrix(matr_zero(2, 3))
>>> print(m_0)                     # doctest: +NORMALIZE_WHITESPACE
0  0  0
0  0  0
        
        return "\n".join(["\t".join(map(str, r)) for r in self.matr])
if __name__=='__main__':
    import doctest
    doctest.testmod(verbose=False)
Explanation: Accidenti, questa volta il test fallisce 
perché otteniamo un diverso numero di spazi. 
Ma gli spazi ci interessano relativamente, 
Possiamo farglielo sapere a doctest usando una direttiva.
End of explanation
class Matrix():
    Matrix class.
    def __init__(self, matr):
        Matrix init.
>>> m_0 = Matrix(matr_zero(4, 3))
>>> print(m_0.rows, m_0.cols)
4 3
>>> print(m_0.matr)
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
        
        self.matr = matr           # Attributo che contiene la matrice.
        self.rows = len(matr)      # numero di righe
        self.cols = len(matr[0])   # numero di colonne
        
    def __str__(self):
        Matrix to string.
>>> m_0 = Matrix(matr_zero(2, 3))
>>> print(m_0)                     # doctest: +NORMALIZE_WHITESPACE
0  0  0
0  0  0
        
        return "\n".join(["\t".join(map(str, r)) for r in self.matr])
    def row(self, index):
        Return a Matrix row.
>>> m_0 = Matrix([[0, 1, 2], [1, 5, 9], [2, 7, 1], [3, 0, 4]])
>>> print(m_0.row(2))
[2, 7, 1]
        
    def col(self, index):
        Return a Matrix col.
>>> m_0 = Matrix([[0, 1, 2], [1, 5, 9], [2, 7, 1], [3, 0, 4]])
>>> print(m_0.row(2))
[2, 9, 1, 4]
        
        
if __name__=='__main__':
    import doctest
    doctest.testmod(verbose=False)
Explanation: Due metodi utili nelle matrici sono quelli che ci permettono 
di estrarre una riga o una colonna dati i corrispondenti indici,
li chiameremo row e col.
End of explanation
class Matrix():
    Matrix class.
    def __init__(self, matr):
        Matrix init.
>>> m_0 = Matrix(matr_zero(4, 3))
>>> print(m_0.rows, m_0.cols)
4 3
>>> print(m_0.matr)
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
        
        self.matr = matr           # Attributo che contiene la matrice.
        self.rows = len(matr)      # numero di righe
        self.cols = len(matr[0])   # numero di colonne
        
    def __str__(self):
        Matrix to string.
>>> m_0 = Matrix(matr_zero(2, 3))
>>> print(m_0)                     # doctest: +NORMALIZE_WHITESPACE
0  0  0
0  0  0
        
        return "\n".join(["\t".join(map(str, r)) for r in self.matr])
    def row(self, index):
        Return a Matrix row.
>>> m_0 = Matrix([[0, 1, 2], [1, 5, 9], [2, 7, 1], [3, 0, 4]])
>>> print(m_0.row(2))
[2, 7, 1]
        
        return self.matr[index]
    def col(self, index):
        Return a Matrix col.
>>> m_0 = Matrix([[0, 1, 2], [1, 5, 9], [2, 7, 1], [3, 0, 4]])
>>> print(m_0.col(2))
[2, 9, 1, 4]
        
        return [row[index] for row in self.matr]
        
if __name__=='__main__':
    import doctest
    doctest.testmod(verbose=False)
Explanation: Bene, descritto cosa vogliamo ottenere, passiamo a scrivere il codice.
row sarà semplicissimo: restituisci l'iesimo elemento della matrice.
col risulterà più complicato: deve costruire una lista che ha come 
elementi gli iesimi elementi di ogni riga.
End of explanation
# 30 marzo 2015
# Daniele
# Matrici
# GPL 3
class Matrix with operations.
from __future__ import division, print_function   # for compatibility with 2.x
import random
def matr_zero(rows, cols):
    Return a bidimensional matrix of zeros.
>>> m_0 = matr_zero(3, 4)
>>> print(m_0)
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
    
    return [[0 for i in range(cols)] for r in range(rows)]
def matr_random(rows, cols, mi, ma):
    Return a bidimensional matrix of random numbers.
>>> m_0 = matr_random(3, 4, 0, 10)
>>> print(m_0)                      # doctest: +ELLIPSIS
[[..., ..., ..., ...], [..., ..., ..., ...], [..., ..., ..., ...]]
    
    return [[random.randrange(mi, ma) for i in range(cols)] for r in range(rows)]
def vect_add(v0, v1):
    Return vectors sum.
>>> print(vect_add([2, 4, 6], [3, 5, 0]))
[5, 9, 6]
    
    return [a+b for a, b in zip(v0, v1)]
def vect_mul(v0, v1):
    Return vectors scalar product.
>>> print(vect_mul([2, 4, 6], [3, 5, 0]))
26
    
    return sum([a*b for a, b in zip(v0, v1)])
class Matrix():
    Matrix class.
    def __init__(self, matr):
        Matrix init.
>>> m_0 = Matrix(matr_zero(4, 3))
>>> print(m_0.rows, m_0.cols)
4 3
>>> print(m_0.matr)
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
        
        self.matr = matr           # Attributo che contiene la matrice.
        self.rows = len(matr)      # numero di righe
        self.cols = len(matr[0])   # numero di colonne
        
    def __str__(self):
        Matrix to string.
>>> m_0 = Matrix(matr_zero(2, 3))
>>> print(m_0)                     # doctest: +NORMALIZE_WHITESPACE
0  0  0
0  0  0
        
        return "\n".join(["\t".join(map(str, r)) for r in self.matr])
    def row(self, index):
        Return a Matrix row.
>>> m_0 = Matrix([[0, 1, 2], [1, 5, 9], [2, 7, 1], [3, 0, 4]])
>>> print(m_0.row(2))
[2, 7, 1]
        
        return self.matr[index]
    def col(self, index):
        Return a Matrix col.
>>> m_0 = Matrix([[0, 1, 2], [1, 5, 9], [2, 7, 1], [3, 0, 4]])
>>> print(m_0.col(2))
[2, 9, 1, 4]
        
        return [row[index] for row in self.matr]
    def transpose(self):
        Return transposed Matrix.
>>> 
        
    def __add__(self, other):
        return [[i*r for i in range(self.matr)] for r in range(self.matr)]
      
    def __neg__(self):
        Return -Matrix.
>>> 
        
      
    def __sub__(self, other):
        Return difference for two matrix
>>> 
        
    
    def __mul__(self, other):
        Return Matrix product.
>>> 
        
    __rmul__ = __mul__
    def determinant(self):
        Return inverse of Matrix.
>>> 
        
    def inverse(self):
        Return inverse of Matrix.
>>> 
        
    def __div__(self, other):
        Return Matrix quotient.
>>> 
        
if __name__=='__main__':
    import doctest
    doctest.testmod(verbose=False)
    
m = Matrix([[0, 3, 2], [1, 5, 9], [2, 7, 1], [3, 0, 4]])
print(m)
A = m+m
print(A)
Explanation: Ora abbiamo tutti gli elementi per completare la nostra libreria. 
Im metodo da seguire prevede alcuni sempli regole:
aggiungere una funzione alla volta;
scrivere la docstring con il test della funzione;
scrivere il codice della funzione correggendolo finché
il test non passa.
Seguendo queste indicazionicompletate la sguente libreria.
End of explanation
<END_TASK>