Sei sulla pagina 1di 10

Metodi del Calcolo Scientico

Progetto 1: Librerie per lalgebra lineare


Federico Valentini, 726584
Sergio Cattaneo, 726786
Appello del 16 Giugno 2014
1 Consegna
Questa relazione ha lo scopo di simulare la ricerca di una libreria adabile
per risolvere sistemi lineari.
Si tratta di matrici sparse di grandezza via via crescente, di cui sono
memorizzati soltanto gli elementi diversi da zero.
La dimensione e molto grande, quindi non e possibile calcolarne la soluzione
con il semplice metodo di Gauss perche durante leliminazione di Gauss la
matrice si riempirebbe di non zeri e occuperebbe troppa memoria (l-in).
Bisogna quindi utilizzare un solutore per matrici sparse, che puo essere di-
retto o iterativo.
2 Teoria matematica
2.1 Sistemi Lineari
In algebra lineare, un sistema di equazioni lineari, anche detto sistema lin-
eare, un sistema di equazioni lineari che devono essere vericate tutte con-
temporaneamente.
Un sistema di equazioni lineari di m equazioni lineari in n incognite puo
essere scritto nel seguente modo:
1
_

_
a
11
x
1
+ a
12
x
2
+ + a
1n
x
n
= b
1
a
21
x
1
+ a
22
x
2
+ + a
2n
x
n
= b
2
.
.
.
a
m1
x
1
+ a
m2
x
2
+ + a
mn
x
n
= b
n
Oppure puo essere rappresentato tramite la forma matriciale equivalente:
A
m,n
=
_
_
_
_
_
a
1,1
a
1,2
a
1,n
a
2,1
a
2,2
a
2,n
.
.
.
.
.
.
.
.
.
.
.
.
a
m,1
a
m,2
a
m,n
_
_
_
_
_
_
_
_
_
_
x
1
x
2
.
.
.
x
n
_
_
_
_
_
=
_
_
_
_
_
b1
b2
.
.
.
b
n
_
_
_
_
_
Analizziamo ora i metodi di risoluzione dei sistemi lineari, che possiamo
suddividere in metodi diretti e metodi iterativi.
2.2 Metodi iterativi
Un metodo iterativo e un algoritmo di calcolo usato per ottenere lapprossimazione
di una soluzione di un problema matematico attraverso un numero nito di
passi.
Una dicolta prodotta dai metodi iterativi sta nel fatto che producono una
successione di vettori che converge alla soluzione e quindi bisogna decidere
un criterio di arresto, che non risulta sempre facile.
Fissato quindi il criterio di arresto, lalgoritmo terminera quando si scendera
al di sotto di un valore soglia ssato a priori, spesso partendo da x
(0)
= 0 e
fermandosi se:
||r
(k)
||
||b||
< soglia
dove r
(k)
e il residuo al passo k-esimo denito come:
r = b A x
e soglia una tolleranza pressata.
2
2.3 Metodi diretti
I metodi diretti si basano sullidea di trasformare il sistema attraverso un
numero nito di operazioni, dette mosse di Gauss, in un sistema equivalente
di cui sia calcolabile la soluzione basandosi sulla fattorizzazione della matrice
A di partenza.
Queste operazioni sono:
scambio di due righe
moltiplicazione di una riga per un numero diverso da zero
sommare una riga per il multiplo di unaltra
Per sistemi con matrici dense questi metodi sono in genere preferibili.
Tuttavia i metodi diretti diventano scomodi quando si ha a che fare con
matrici sparse di grandi dimensioni: in questi casi infatti per fattorizzare A
devo moltiplicare tra loro matrici sparse. Ma due matrici sparse moltiplicate
tra loro danno origine ad una matrice meno sparsa, e quindi ad una maggiore
occupazione di memoria, questo fenomeno e detto ll-in.
Tuttavia tramite la progettazione di algoritmi relativamente complessi e
possibile utilizzare questa tipologia di risoluzione nelle matrici sparse, grazie
ad una gestione eciente del ll-in.
3 Implementazione
3.1 Python
Python e un linguaggio multi-paradigma, che fa della dinamicita, semplicita
e essibilita i suoi principali obiettivi.
Oltre ad essere un linguaggio di programmazione concepito con eleganza
presenta numerose caratteristiche positive:
Object-oriented
Open-source
Potente
Facile da usare
Facile da imparare
3
Per completezza riportiamo anche il principale svantaggio di Python
rispetto agli altri linguaggi compilati, come C e C++ ovvero la velocita
di esecuzione.
Nellimplementazione standard di Python e prevista la compilazione del
codice sorgente in un formato intermedio (byte code) e la successiva inter-
pretazione. Infatti, siccome il codice Python non e compilato no a livello
di codice macchina binario, alcuni programmi verranno eseguiti pi u lenta-
mente se realizzati in Python piuttosto che in un linguaggio completamente
compilato come il C.
3.2 SciPy
SciPy[1] e una libreria open-source di algoritmi e strumenti matematici per
il linguaggio di programmazione Python.
Risulta essere la libreria per la computazione scientica in Python pi u larga-
mente utilizzata ed inoltre fa largo uso di NumPy, altra libreria fondamentale
del calcolo scientico in Python.
Il progetto e portato avanti da una comunita molto attiva ed e anche pre-
sente una documentazione molto dettagliata e ben strutturata.
3.3 NumPy
NumPy[2] e unestensione del linguaggio Python open source, che aggiunge
supporto per vettori e matrici multidimensionali e di grandi dimensioni e
con funzioni matematiche di alto livello con cui operare. Anche in questo
caso la libreria comprende una documentazione molto ben fatta e il codice
e costantemente aggiornato.
3.4 SuperLU
SuperLU[3] e una libreria open-source nativa in C, sviluppata a partire dal
1999 e con lultima versione risalente al 2011.
Questa libreria e in grado risolvere tramite metodo diretto sistemi lineari
di grandi dimensioni, sparsi e non simmetrici.
Questo perche prima della fattorizzazione vera e propria LU = A, include i
seguenti due passi aggiuntivi[4]:
1. Riordinamento di righe e colonne per ridurre il ll-in
2. Analisi per determinare la topologia degli elementi non-nulli e creazione
di strutture dati adeguate ad essa
4
Ciascuno di essi e implementato da numerosi algoritmi specializzati. In-
oltre il largo utilizzo di questa libreria in ambito accademico/scientico ha
portato allo sviluppo di porting verso altri linguaggi di sviluppo diversi da
C.
4 Sviluppo
4.1 Dettagli macchina
Per la realizzazioni di questi test ci siamo adati ad una macchina Lenovo
IdeaPad S510P con processore Intel Core i7-4500U (1.80 / 3.00 GHZ, 2 core,
4 MB CACHE L3) con 4 GB di RAM.
Il sistema operativo utilizzato e Manjaro 0.8.9 (una fork di ArchLinux).
4.2 Strutture dati utilizzate e funzione risolutiva
Il modulo scipy.sparse [5] contiene due strutture dati molto convenienti alla
scrittura in memoria delle matrici sparse: csc matrix e coo matrix.
La prima scansiona tutta la matrice leggendo per colonne, salvando
tutti i coecienti e comprimendo con codica run-length
La seconda contiene solo gli elementi non nulli salvati come tripla
(dato, riga, colonna)
Questultima struttura e stata utilizzata solo per leggere i dati dai le
.dat in input, infatti viene segnalato chiaramente nella documentazione che
e un formato poco conveniente per lesecuzione dei calcoli.
Quindi una volta letti i dati eettuiamo la conversione al primo formato,
pi u eciente nella computazione.
Le funzioni di Scipy che abbiamo utilizzato per la risoluzione dei sistemi
sono scipy.sparse.linalg.dsolve.splu che ritorna un oggetto da cui e possibile
chiamare un metodo solve che risolve il sistema lineare associato prendendo
in input solo il termine noto b.
5
5 Risultati ottenuti
I dati sui quali abbiamo testato la nostra applicazione Python erano orga-
nizzati in matrici simmetriche e non-simmetriche delle seguenti dimensioni:
1891 x 1891, 5781 x 5781, 10671 x 10671, 16561 x 16561, 23451 x 23451,
46902 x 46902.
Questa e la tabella che riassume i tempi
1
e gli errori
2
per tutti i casi di test
eseguiti:
Nome le Tempo (s) Errore
simmetrica-1891.dat 0.5769 3.348e
15
simmetrica-5781.dat 1.991 2.334e
14
simmetrica-10671.dat 4.604 1.029e
12
simmetrica-16561.dat 8.836 1.163e
10
simmetrica-23451.dat 15.04 1.183e
8
simmetrica-46902.dat 30.16 8.700e
9
non-simmetrica-1891.dat 0.3845 1.438e
15
non-simmetrica-5781.dat 2.080 8.900e
15
non-simmetrica-10671.dat 5.808 1.433e
12
non-simmetrica-16561.dat 12.58 1.226e
10
non-simmetrica-23451.dat 22.79 2.011e
8
non-simmetrica-46902.dat 47.12 1.145e
8
Lunico dubbio che ci resta dopo aver analizzato questi risultati e come
lerrore relativo aumenti esponenzialmente col crescere dellordine delle ma-
trici, pur restando sotto una soglia accettabile.
1
I tempi sono comprensivi di creazione delle strutture dati e della computazione vera
e propria, in particolare leettiva risoluzione ha impiegato dai 0.03s ai 2.6s
2
Er( x) =
|| xx||
||x||
6
A Appendice: codice sorgente applicazione
from scipy.sparse import coo_matrix, csc_matrix
from scipy.sparse.linalg import dsolve
from scipy.linalg import norm
import numpy as np
import time
def risolvi(__file__):
# Inizialmente gestiamo lheader del file.dat, dove estraiamo
# nelle seguente variabili:
# header[0] = dimensione matrice
# header[2] = tipologia matrice
(simmetrica/non-simmetrica)
t0 = time.time()
with open(__file__, r, newline=) as f:
header = f.readline()
header = header.split()
size = int(header[0])
flag = header[2]
t1 = time.time()
print("HEADER PROCESSATO:", t1 - t0, "secondi")
# Lettura dei dati da file (una colonna alla volta)
row = np.genfromtxt(__file__, dtype=int32,
skip_header=1, usecols=(0)).tolist()
col = np.genfromtxt(__file__, dtype=int32,
skip_header=1, usecols=(1)).tolist()
data = np.genfromtxt(__file__, skip_header=1,
usecols=(2)).tolist()
t2 = time.time()
print("CREAZIONE ARRAY:", t2 - t1, "secondi")
# Creazione della matrice sparsa A (simmetrica o
non-simmetrica
# in base al flag estratto in precedenza dal file.dat
#
# MATRICE SIMMETRICA
# Vengono lette le coordinate cosi come sono, istanziando
la matrice M.
7
# Vengono lette le coordinate invertite, istanziando la
matrice M.
# A = M + M - 0.5*diag(M)
#
# MATRICE NON-SIMMETRICA
# Vengono lette le coordinate cosi come sono, istanziando
la matrice A
j = len(row)
if flag == "half":
for i in range(0, j):
row[i] = row[i] - 1
col[i] = col[i] - 1
A = csc_matrix(csc_matrix(coo_matrix((np.array(data),
(np.array(row), np.array(col))),
shape=(size, size))) + csc_matrix(coo_matrix((np.array(data),
(np.array(col), np.array(row))), shape=(size, size))))
A.setdiag(A.diagonal() * 0.5)
t3 = time.time()
print("CREAZIONE MATRICE (half):", t3 - t2, "secondi")
else:
for i in range(0, j):
row[i] = row[i] - 1
col[i] = col[i] - 1
A = csc_matrix(coo_matrix((np.array(data), (np.array(row),
np.array(col))), shape=(size, size)))
t3 = time.time()
print("CREAZIONE MATRICE (full):", t3 - t2, "secondi")
# Creazione del vettore di soluzioni x_esatte dove
# x-esatte[i] = i
# e successiva creazione del vettore di termini noti b tale
per cui
# A*x_esatte = b
#
# Infine viene calcolata il vettore di x-approssimate
(x_approx)
# risolvendo il sistema lineare:
# x_approx = A / b
# tramite:
# - prima fattorizzazione LU della matrice dei
coefficienti
# - poi risoluzione con metodo diretto SuperLU 4.0
8
x_esatta = np.array(list(range(1, size + 1)), dtype=float64)
b = A.dot(x_esatta)
t4 = time.time()
print("CALCOLO b:", t4 - t3, "secondi")
lu = dsolve.splu(A)
x_approx = lu.solve(b)
t5 = time.time()
print("RISOLUZIONE SISTEMA:", t5 - t4, "secondi")
err = norm((x_esatta - x_approx)) / norm(x_esatta)
print(err)
print("RUNNING TIME:", time.time() - t0, "secondi")
out_file.write("MATRICE " + str(size) + " " + flag + "\nRunning
Time: ")
out_file.write(str(time.time() - t0) + " secondi\nErrore: " +
str(err))
out_file.write("\n\n")
out_file = open("test_prova.txt", "w")
risolvi(input/simmetrica-1891.dat)
risolvi(input/simmetrica-5781.dat)
risolvi(input/simmetrica-10671.dat)
risolvi(input/simmetrica-16561.dat)
risolvi(input/simmetrica-23451.dat)
risolvi(input/simmetrica-46902.dat)
risolvi(input/non-simmetrica-1891.dat)
risolvi(input/non-simmetrica-5781.dat)
risolvi(input/non-simmetrica-10671.dat)
risolvi(input/non-simmetrica-16561.dat)
risolvi(input/non-simmetrica-23451.dat)
risolvi(input/non-simmetrica-46902.dat)
out_file.close()
9
References
[1] SciPy: http://www.scipy.org/
[2] NumPy: http://www.numpy.org/
[3] SuperLU: http://crd-legacy.lbl.gov/ xiaoye/SuperLU/
[4] X. Li, Direct solvers for sparse matrices, July 2013.
[5] Sparse matrices: http://docs.scipy.org/doc/scipy/reference/sparse.html
10