Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Facoltà di Ingegneria
Corso di Laurea Specialistica in Ingegneria Civile
Dipartimento di Modellistica per l’Ingegneria
Relatore Candidato
Alessandro DE ROSIS
Prof.Ing. Giovanni GARCEA
matr. 117811
............................ ............................
Corelatore
Ing. Giuseppe ZAGARI
............................
1
Indice
Introduzione 5
2
2.3.6 MTL4 Dense . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.3.7 MTL4 Sparse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.3.8 Confronti tra le durate delle analisi . . . . . . . . . . . . . . . . . . . 28
3
5.6 L’iterazione inversa Householder-QR . . . . . . . . . . . . . . . . . . . . . . 69
5.6.1 La riduzione di Householder . . . . . . . . . . . . . . . . . . . . . . . 69
5.6.2 L’iterazione QR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
5.6.3 Calcolo degli autovettori . . . . . . . . . . . . . . . . . . . . . . . . . 71
5.7 Il metodo di Lanczos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
8 Conclusioni 93
4
Introduzione
5
possibile migliorare le performance di codici FEM migliorando ed ottimizzando l’utilizzo
di tali librerie. La necessità è sentita sia nel caso di analisi lineare, vista le notevoli
dimensioni che può assumere il problema, ma ancor di più in contesti di analisi nonlineare,
che solitamente richiedono al soluzione in successione di diversi sotto-problemi lineari.
In quest’ottica si inserisce questo lavoro di tesi che è volto a passare in rassegna al-
cuni tra i più efficaci strumenti computazionali a disposizione e a mettere in luce quanto
alcuni più di altri influenzino fortemente le prestazioni computazionali. In quest’ottica
un punto basilare che bisogna affrontare è quello che riguarda la tecnologia dei moderni
microprocessori utilizzati dai calcolatori e come essi interagiscono con il software numerico
che implementa le librerie di analisi numerica.
In effetti fino a qualche hanno fa l’architettura dell’hardware, a parità di risorse di cal-
colo, aveva poca importanza nella performance del codice [20]. La ricerca è stata pertanto
essenzialmente indirizzata a come sviluppare delle tecniche numeriche efficienti capaci di
tener conto della particolare struttura del problema e di avvantaggiarsene nella soluzione.
Se pensiamo sempre all’esempio della soluzione dei sistemi lineari, che hanno cosı̀ tanta
importanza nelle formulazione FEM, si sono create una serie di routines capace di sfrut-
tare al meglio ad esempio le caratteristiche della matrice che governa il sistema lineare,
sviluppando procedure ad hoc per matrici definite positive, simmetriche, bandate o sparse.
Oltre a questa ottimizzazione oggi è necessario però soffermarsi anche sull’ottimizzazio-
ne di altri aspetti legati a come i dati e le operazioni vengono eseguite all’interno del
microprocessore E’ necessario cioè sfruttare al massimo anche glia accessi alle risorse di
memoria Cache e allocare in queste zone di accesso superveloce le quantità utilizzate, evi-
tando di effettuare operazioni che comportano l’accesso a quantità allocate in aree a lento
accesso, tipicamente la aree di memoria RAM. Cosı̀ per esemplificare anche se si utilizza
un efficiente metodo numerico che effettua la decomposizione di una matrice simmetrica
di dimensione n e banda m esattamente in bn2 /2 operazioni elementari, cioè il minimo
teorico, se la programmazione non cura l’aspetto hardware il metodo stesso può risultare
molto meno efficiente di una differente implementazioni anche meno sofisticata dal punto
di vista delle tecniche di analisi numerica, ma che però sfrutta al meglio l’hardware del
microprocessore.
Ad oggi esistono una serie di librerie di algebra numerica ad uso gratuito e facilmen-
te disponibili su internet. La tesi propone una serie di test sulle librerie più importanti
disponibili in rete a partire sai test delle più banali operazioni matriciali e vettoriali alle
soluzione di sistemi lineari in vari contesti ed alla soluzione di problemi agli autovalori
utilizzando sia matrici e vettori forniti in [4], ma anche sistemi algebrici derivanti da pro-
blemi di meccanica delle strutture. Infine le procedure sono state implementate all’interno
di codici FEM per l’analisi lineare e nonlineare di strutture a pannelli sottili o travi 3D.
Anche in questo caso sono stati riportati una serie di test numerici per verificare l’efficienza
computazionale dell’implementazione proposta.
La tesi è cosı̀ organizzata: nel primo capitolo verrà esposta l’architettura dei moderni
sistemi, soffermandosi in particolar modo sull’aspetto del memory management e sulle
strategie per migliorare l’accesso ai dati; il secondo capitolo si propone di utilizzare alcune
librerie di algebra lineare per eseguire operazioni tra vettori e matrici e di misurare la pre-
stazionalità di queste in relazione al tempo impiegato; il terzo capitolo espone gli aspetti
6
teorici che stanno alla base della risoluzione di un sistema lineare di equazioni, quali il
metodo di eliminazione di Gauss, la fattorizzazione LU e quella alla Cholesky; il quarto
capitolo si preoccupa di passare in rassegna i vari strumenti utilizzabili e di stimarne le
performance; il quinto capitolo discute della teoria del calcolo di autovalori e autovettori,
tanto nel caso che siano richieste tutte le autosoluzioni (algoritmo QR), quanto che ne
siano desiderate solo alcune (metodo di Lanczos); il sesto capitolo espone i risultati della
campagna di sperimentazione relativa alla risoluzione di un problema generalizzato agli
autovalori; il settimo capitolo dimostra come tutti gli strumenti finora discussi siano facil-
mente utilizzabili in contesti tipici della meccanica computazionale e che la loro adozione
non può che portare benefici all’intero processo di analisi; segue quindi l’ottavo capitolo
dove vengono messi in luce tutti gli aspetti riguardanti la campagna di sperimentazione.
7
Capitolo 1
1.1 Introduzione
Si supponga di dover svolgere il prodotto scalare di due vettori di dimensione n: la com-
plessità del problema, intesa come numero di operazioni elementari da svolgere, è pari a
2n. Si sarebbe portati a pensare che su una stessa macchina questa operazione svolta da
librerie diverse impieghi durate dell’analisi del tutto uguali, ma ciò non è vero. Le librerie
a disposizione, a differenza di un’implementazione a mano delle operazioni, sono in grado
di sfruttare la tecnologia del calcolatore e quindi traggono risorse (in termini di risparmio
sulla durata dell’analisi) dalla particolare architettura del calcolatore [12], [13].
Si rende pertanto necessario discutere al riguardo della tecnologia dei moderni micro-
processori che equipaggiano i calcolatori [17].
8
erano formate da un’unità polifunzionale che svolgeva in rigida sequenza tutti e cinque
i passaggi legati all’elaborazione delle istruzioni. Una CPU classica (1.1) richiede quindi
almeno cinque cicli di clock per eseguire una singola istruzione.
La prima istruzione deve prelevare i numeri contenuti nelle variabili A e B, sommarli e porli
nella variabile C. La seconda istruzione deve prelevare il valore contenuto nella variabile
9
C, sottrarlo di uno e salvare il risultato in D. Ma la seconda istruzione non potrà essere
elaborata (EX) fino a quando il dato della prima operazione non sarà disponibile in memo-
ria (MEM) e quindi la seconda operazione dovrà bloccarsi per attendere il completamento
della prima e quindi questo ridurrà il throughput complessivo.
Il secondo problema consiste nei salti condizionati. I programmi contengono delle istru-
zioni condizionate che se una specifica condizione è verificata provvedono a interrompere
il flusso abituale del programma e a mandare in esecuzione un altro pezzo di programma
indicato dall’istruzione di salto. Ogni volta che questo accade il microprocessore si trova a
dover eseguire un nuovo flusso di operazioni e quindi deve svuotare la pipeline del prece-
dente flusso e caricare il nuovo flusso. Ovviamente queste operazioni fanno sprecare cicli di
clock e quindi deprimono il throughput. Per ridurre questo problema le CPU adottano del-
le unità chiamate unità di predizione delle diramazioni (in inglese Branch Prediction Unit)
che fanno delle previsioni sul flusso del programma. Queste unità riducono notevolmente
i cicli persi per i salti.
10
forniti i dati di cui necessita. Tutto ciò non solo ha un impatto negativo sulla performance
globale, ma in aggiunta impedisce all’applicazione di sfruttare l’elevata velocità della CPU.
Un modo per aggirare questo problema è quello di inserire una piccola memoria ad alta
velocità tra il processore e la memoria principale (1.4); questa memoria buffer è nota
come cache. L’applicazione trae vantaggio dal caricamento dei dati dalla cache anzichè
dalla memoria principale; infatti, essendo il tempo di accesso alla cache molto ridotto, le
performance subiscono un miglioramento.
Si supponga di dover eseguire una certa applicazione. Dapprima il sistema copia i dati
di cui necessita la CPU dalla memoria alla cache e poi da questa in un registro della CPU.
Qualora l’applicazione dovesse aver di nuovo bisogno di questi dati, il tempo di accesso a
questi si riduce notevolmente se essi sono ancora contenuti nella cache. Per ammortizzare
il costo di questo trasferimento di memoria, viene caricato nella cache più di un elemento.
L’unita di trasferimento si chiama cache block o cache line; l’accesso a un singolo dato
porta un’intera linea nella cache. A ciò fa riferimento il concetto di sub-blocking. Con il
sub-blocking la cache alloca una linea/blocco con una lunghezza che è multipla della cache
line. Gli slot interni al blocco più grande sono poi riempiti con le singole cache line (o
sub-block). Tale modo di fare funziona bene se l’accesso alle line è consecutivo.
Quando il processore vuole leggere o scrivere in una data collocazione in memoria
principale, inizialmente controlla se il contenuto di questa posizione è caricato in cache.
Questa operazione viene effettuata confrontando l’indirizzo della posizione di memoria
con tutte le etichette nella cache che potrebbero contenere quell’indirizzo. Se il processore
trova che la posizione di memoria è in cache, si parla di cache hit (accesso avvenuto con
successo), altrimenti di cache miss (fallimento d’accesso). Nel caso di un cache hit, il
processore legge o scrive immediatamente il dato sulla linea di cache. Il rapporto tra
cache hit e accessi totali è chiamato anche hit rate ed è una misura dell’efficacia della
cache stessa.
Nel caso di un cache miss, la maggior parte delle cache crea una nuova entità, che
comprende l’etichetta appena richiesta dal processore ed una copia del dato dalla memoria.
Un fallimento del genere è relativamente lento, in quanto richiede il trasferimento del dato
dalla memoria principale, il cui tempo di risposta è molto maggiore di quello della memoria
cache.
Per poter fare spazio a nuovi dati nel caso di un cache miss, la cache generalmente deve
11
eliminare il contenuto di una delle linee. L’euristica che utilizza per scegliere quale dato
eliminare è chiamata politica di rimpiazzamento. Il problema fondamentale di ogni politica
di rimpiazzamento è quello di dover predire il dato della cache che verrà richiesto nel futuro
con minor probabilità. Predire il futuro è difficile, soprattutto per le cache hardware che
devono sfruttare regole facilmente implementabili in circuiteria, perciò esistono una serie
di politiche di rimpiazzamento e nessuna di esse può essere ritenuta perfetta. Una delle
più popolari, la LRU (dall’inglese Least Recently Used, cioè usato meno recentemente),
rimpiazza, appunto, il dato al quale si è fatto accesso meno recentemente.
Quando un dato è scritto nella cache, dopo un po’ di tempo deve comunque essere
scritto in memoria principale. La decisione del momento in cui questa scrittura deve aver
luogo è controllata dalla politica di scrittura. In una cache write-through, ogni scrittura
sulla cache comporta una scrittura contemporanea nella memoria principale. In alternati-
va, una cache write-back non esegue immediatamente questa azione: al contrario, la cache
tiene traccia delle linee che contegono dati da aggiornare settando opportunamente quello
che viene chiamato il dirty bit. Il dato viene effettivamente scritto in memoria solo quando
esso deve essere eliminato dalla cache per far spazio a nuove informazioni. Per questa ra-
gione, una ricerca fallita in una cache write-back spesso genera due accessi alla memoria:
uno per leggere il nuovo dato, l’altro per scrivere la vecchia informazione (se indicato dal
dirty bit).Sia il write-back che il write-through servono a mantenere la coerenza tra i livelli
di memoria.
Esistono anche alcune politiche intermedie. La cache potrebbe essere ad esempio write-
through, ma le scritture potrebbero essere temporaneamente inserite in una coda, cosı̀ da
processare insieme scritture multiple, ottimizzando l’accesso al bus.
I dati in memoria principale, dei quali esiste una copia nella cache, potrebbero essere
modificati da altre cause (evento non improbabile, ad esempio, in un sistema multiproces-
sore), perciò i dati nella cache potrebbero diventare obsoleti. I protocolli di comunicazione
tra i sistemi di gestione delle cache che conservano la consistenza dei dati sono chiamati
protocolli di coerenza.
Il tempo impiegato per leggere un dato dalla memoria (latenza di lettura) è importante,
perché spesso una CPU potrebbe completare la propria coda di operazioni mentre aspetta
l’arrivo del dato richiesto. Quando un microprocessore raggiunge questo stato, si parla
di stallo della CPU. Con l’aumento della velocità dei microprocessori, l’andare in stallo
per cache miss spreca molta potenza di calcolo; le CPU moderne, infatti, possono eseguire
centinaia di istruzioni nello stesso tempo necessario per caricare un singolo dato dalla
memoria.
12
programma in indirizzi fisici nella memoria principale. La porzione del processore che fa
questa traduzione è conosciuta come la memory management unit (MMU ). La MMU può
accedere velocemente alla tabella di traduzioni attraverso il Translation Lookaside Buffer
(TLB), che è una cache di mappature per la page table del sistema operativo.
La traduzione degli indirizzi ha tre caratteristiche importanti:
• Latenza: generalmente, la MMU rende disponibile l’indirizzo fisico pochi cicli dopo
che l’indirizzo virtuale è computato dal generatore di indirizzi;
• Aliasing: più indirizzi virtuali possono riferirsi ad uno stesso indirizzo fisico. La
maggior parte dei processori garantisce che tutti gli aggiornamenti al singolo indirizzo
fisico vengano eseguiti in ordine. Per permettere ciò, il processore deve assicurarsi
che, in ogni istante, esista in cache una sola copia di ogni indirizzo fisico;
L’esistenza di indirizzi fisici e virtuali pone la questione su quali di essi utilizzare per
le etichette e gli indici della cache. La motivazione di usare indirizzi virtuali è la velocità:
una cache di dati con indici ed etichette virtuali esclude la MMU dalle operazioni di
caricamento ed uso dei dati dalla memoria. Il ritardo provocato dal caricamento dei dati
dalla memoria RAM (load latency) è cruciale per le prestazioni della CPU: per questo
motivo, la maggior parte delle cache di livello 1 sono indicizzate con indirizzi virtuali,
permettendo alla MMU di ricercare nella TLB in parallelo con il recupero dei dati dalla
cache della RAM.
L’indirizzamento virtuale non è sempre la scelta migliore: introduce, ad esempio, il
problema degli alias virtuali, cioè la cache potrebbe immagazzinare in più locazioni il
valore di uno stesso indirizzo fisico. Il costo per la gestione degli alias virtuali cresce con
la dimensione della cache e, come risultato, la maggior parte delle cache di livello 2 e
superiori sono indicizzate con indirizzi fisici.
Nei microprocessori moderni è possibile trovare alcuni tipi di cache che differiscono tra
di loro non solo per la dimensione e le funzioni, ma anche per la particolare organizzazione
interna. Trasformare un indirizzo virtuale di un dato in uno fisico è un operazione piuttosto
costosa. La TLB è una cache che memorizza questi indirizzi trasformati. Ogni elemento
della TLB fa riferimento a una memoria virtuale. La CPU può solo operare su dati
e istruzioni che hanno il riferimento nella TLB; qualora questo non dovesse esserci, il
sistema deve crearlo di nuovo e ciò comporta un certo costo.
13
Figura 1.5: La memoria virtuale
14
attendendo che i dati arrivino nei registri. Con questa tecnica i dati sono spostati più
prossimi all’utilizzo da parte della CPU.
Un’altra tecnica che si può utilizzare per l’incremento delle prestazioni è nota come
loop-unrolling. Essa si traduce nello srotolamento del ciclo consistente nel modificare il
controllo del ciclo e nel replicare opportunamente le istruzioni all’interno dello stesso. I
vantaggi di questa tecnica sono:
L’overhead del programma e il numero di trasferimenti di dati dai livelli più bassi di
memoria ai registri si riducono di un fattore proporzionale alla nuova lunghezza del ciclo
(profondità dell’unrolling). Questa tecnica ha però anche degli svantaggi:
Il nuovo programma non deve fare più 100 loop, bensı̀ 20. D’altro canto sono state
inserite delle righe di codice in più e il compilatore deve allocare più registri per memoriz-
zare le variabili nell’iterazione del loop allargato. In aggiunta a quanto appena esposto,
sono disponibili anche altre tecniche per l’ottimizzazione delle prestazioni. Esse vengono
eseguite lanciando il compilatore con delle particolari opzioni [19]; in particolare l’opzione
più interessante è -O3 che oltre al prefetch e al loop-unrolling utilizza altre tecniche inte-
ressanti come la common subexpression elimination che ottimizza un ciclo for quando in
esso appaiono delle quantità costanti. Ma ne esistono anche molte altre che ottimizzano i
riferimenti a strutture dati, riducono la dimensione di queste, pianificano il flusso di dati
e allineano gli stessi.
15
Alla luce di tutto ciò lo scopo di questa tesi è quella di dimostrare come, a parità di
algoritmo, le routines che riescono a sfruttare meglio proprietà quale l’organizzazione della
cache risultano essere le più performanti.
Per la la campagna di test numerici, condotta nei capitoli successivi è stata utilizzata
una macchina dotata di processore Intel(R) Pentium(R) 4 Dual Core CPU 3.20GHz, L2
cache 1024 KB, RAM 2GB, equipaggiata con sistema operativo Ubuntu Jaunty Jackalope
9.04.
16
Capitolo 2
In questo capitolo verranno passati in rassegna alcuni strumenti messi a disposizione per
compiere operazioni tra vettori e matrici. Questi strumenti sono delle librerie di algebra
lineare utilizzate per condurre delle analisi organizzate in livelli cosı̀ classificabili:
Per ogni livello di analisi sono stati implementati dei codici di calcolo sfruttando le
seguenti librerie:
• AMD Core Math Library (nel seguito ACML), costituite da subroutines di al-
gebra lineare (BLAS) ottimizzate per fornire elevate prestazioni sui processori AMD
e da una suite completa di algebra lineare (LAPACK [5]);
• Intel Math Kernel Library (nel seguito MKL), costituita dalle stesse librerie
della suite precedente, ma ottimizzata per i processori Intel;
• The Matrix Template Library 4 [14] (nel seguito MTL 4), una libreria che
associa alla velocità delle operazioni una sintassi molto semplice e intuitiva;
• Eigen 2 [1], una libreria ottimizzata per fornire elevate prestazioni con il compilatore
GCC.
Sono state inoltre implementate delle routines che svolgono le operazioni manualmente,
cioè senza l’ausilio di librerie addizionali.
17
Nel seguito verranno passati in rassegna tutti i livelli dell’analisi e verranno illustrati i
codici sviluppati ad hoc per l’utilizzo di ogni libreria. Lo scopo di queste analisi sarà quello
di fornire una classificazione delle prestazioni delle librerie sopra elencate in funzione del
tempo impiegato per l’analisi e del numero di operazioni effettuate nell’unità di tempo
(flops).
2.1.1 ACML
L’utilizzo della libreria ACML richiede l’inclusione del header file acml.h e si concretizza
nell’ istruzione
double ddot(int n, double *a, int inca, double *b, int incb)
dove n è la dimensione dei vettori a e b, inca e incb sono rispettivamente gli incrementi
con i quali devono essere scanditi i vettori a e b. Il vettore a di dimensione M ∗ N è stato
ricavato a partire dall’input di una matrice A la quale è stata poi per colonne disposta in
un unico vettore.
2.1.2 BLITZ++
La BLITZ++ Numerical Library richiede l’header file blitz/array.h. La sintassi con la
quale si dichiara un generico vettore è:
Array<type,dimension> name(length)
dove type è la tipologia degli elementi che costiuiscono il vettore (double, int, float, com-
plex), dimension è l’ordine dello stesso (1=vettore, 2=matrice), name è il nome che gli si
intende dare e length è il numero di elementi che lo costituiscono.
E’ interessante notare come la sintassi della funzione che calcola il prodotto scalare sia
molto semplice e intuitiva:
c = sum(a(i) * b(i))
2.1.3 EIGEN 2
La dichiarazione di un vettore passa attraverso l’istruzione
VectorXd name(length,1);
18
dove la lettera d indica che si tratta di un array di double. Questa libreria consente
anche con una semplice istruzione di inizializzare a 0 o a 1 tutti i termini di un vettore:
a = VectorXd::Zero(M*N);
b = VectorXd::Ones(M*N);
L’istruzione dalla sintassi molto semplice che consente di calcolare il prodotto scalare
è:
double c = a.dot(b);
2.1.4 HAND
Questa routine calcola il prodotto scalare tra due vettori manualemente, cioè un ciclo f or
innesta il prodotto tra componenti con lo stesso indice e incrementa di questo risultato
una certa variabile inizializzata precedentemente a zero. Quando la routine esce dal ciclo,
la variabile assume il valore del prodotto scalare.
double c = 0.0;
for(int i=0; i<M*N; i++)
c += a[i]*b[i];
2.1.5 MKL
L’utilizzo della libreria MKL richiede l’inclusione del header file mkl.h e si concretizza nella
stessa istruzione usata con le librerie ACML.
2.1.6 MTL4
La libreria Matrix Template Library 4 richiede l’header file boost/numeric/mtl/mtl.hpp.
La dichiarazione di un vettore è fatta nella forma:
dense_vector<type> name(length)
dove type è la tipologia degli elementi che costiuiscono il vettore (double, int, float, com-
plex), name è il nome che gli si intende dare e length è il numero di elementi che lo
costituiscono. L’operazione di prodotto scalare si concretizza nell’espressione:
c = dot(a,b)
19
2.1.7 Confronti tra le durate delle analisi
Vengono adesso proposti dei confronti tra le durate delle analisi con le metodologie espo-
ste nei paragrafi precedenti. Tutte le routines ricevono in input una matrice quadrata
simmetrica generata random tramite l’ausilio di Matlab.
0.1
0.08
0.06
0.04
0.02
0
0 2e+06 4e+06 6e+06 8e+06 1e+07 1.2e+07 1.4e+07 1.6e+07
Dimensione
Figura 2.1: Confronti tra i tempi dell’analisi del prodotto scalare tra due vettori
1
GFlops [log]
0.1
0.01
100 1000 10000 100000 1e+06 1e+07 1e+08
Dimensione [log]
Figura 2.2: Confronti tra i GFlops dell’analisi del prodotto scalare tra due vettori
20
sqrt(dim) ACML BLITZ EIGEN2 HAND MKL MTL4
10 0.0 0.0 0.0 0.0 0.0 0.0
20 0.0 0.0 0.0 0.0 0.0 0.0
30 0.0 0.0 0.0 0.0 0.0 0.0
40 0.0 0.0 0.0 0.0 0.0 0.0
50 0.0 0.0 0.0 0.0 0.0 0.0
60 0.0 0.0 0.0 0.0 0.0 0.0
70 0.0 0.0 0.0 0.0 0.0 0.0
80 0.0 0.0 0.0 0.0 0.0 0.0
90 0.0 0.0 0.0 0.0 0.0 0.0
100 0.00003 0.00007 0.00008 0.00004 0.00008 0.00005
200 0.0001 0.0003 0.00033 0.00016 0.00014 0.00024
300 0.00047 0.0007 0.00074 0.0004 0.00035 0.0005
400 0.001 0.00144 0.0014 0.0009 0.0009 0.0011
500 0.0018 0.0023 0.0022 0.00178 0.00176 0.00188
600 0.0027 0.00336 0.0033 0.00276 0.00265 0.00274
700 0.0036 0.00458 0.00451 0.0037 0.00364 0.00377
800 0.00477 0.00589 0.0059 0.0049 0.00476 0.00488
900 0.006 0.00757 0.00746 0.0062 0.006 0.00618
1000 0.006 0.0089 0.009 0.007 0.007 0.0075
1200 0.008 0.01296 0.013 0.011 0.0108 0.0107
1500 0.013 0.0204 0.0204 0.017 0.0168 0.01717
1700 0.016 0.0263 0.027 0.022 0.022 0.02223
2000 0.022 0.036 0.0363 0.0306 0.0304 0.03081
2200 0.03 0.044 0.044 0.03656 0.0369 0.03739
2500 0.044 0.0571 0.0567 0.0478 0.0473 0.04795
2700 0.052 0.0667 0.0664 0.0559 0.0551 0.05569
3000 0.061 0.0823 0.0818 0.0692 0.0679 0.0688
3200 0.0749 0.0939 0.0936 0.0786 0.078 0.0783
3500 0.0875 0.1128 0.1118 0.0932 0.0918 0.0937
3700 0.0977 0.1260 0.1257 0.1044 0.1006 0.1047
4000 0.1174 0.1466 0.1472 0.1215 0.1154 0.122
Tabella 2.1: Durate delle analisi del prodotto tra due vettori
21
2.2 Livello 2: operazioni tra matrici e vettori
In questo paragrafo le librerie vengono utilizzate per compiere l’operazione di prodotto tra
una matrice e un vettore. La matrice viene fornita come input tramite un file di testo,
mentre il vettore è assegnato di default come unitario.
2.2.1 ACML
Le routines ACML sono sritte in Fortran e leggono una matrice A a partire da un vettore a
che contiene tutte le colonne della matrice in fila. Il cuore di questa routine è la chiamata
alla funzione che calcola il prodotto tra una matrice e un vettore:
dove transa specifica se si desidera la trasposta della matrice (’t’) oppure meno (’n’),
m e n sono le dimensioni di A, α è uno scalare che moltiplica A, a è il vettore che contiene
la successione delle colonne di A, lda è il numero di righe di A, b è il vettore che moltiplica
A, incb è l’incremento dei termini di b, β è uno scalare che moltiplica il vettore c, c è un
vettore che in output contiene la soluzione, incc è l’incremento dei termini di c.
2.2.2 BLITZ++
Anche in questo caso, grazie a una sintassi molto semplice
firstIndex i;
secondIndex j;
y = sum(A(i,j) * b(j), j);
è possibile effettuare la chiamata alla routine che calcola il prodotto tra la matrice A e il
vettore b e lo restituisce nel vettore y.
2.2.3 EIGEN 2
La sintassi tramite la quale di dichiara una matrice è del tipo:
Matrixd name(nrows,ncols);
name = MatrixXd::Zero(nrows,ncols);
C = A * b;
22
2.2.4 HAND
Il vettore prodotto viene generato tramite due cicli f or
2.2.5 MKL
Essendo la sintassi utilizzata estremamente simili a quella della libreria ACMl sopra
esposta, si evita di dilungarsi sulla descrizione della stessa.
dense2D<type> name(M, N)
Una sintassi molto intuitiva, tra l’altro identica a quella di MATLAB, rende di immediata
stesura la routine che calcola il prodotto tra una matrice e un vettore grazie alle librerie
MTL4.
23
2.2.8 Confronti tra le durate delle analisi
Vengono adesso proposti dei confronti tra le durate delle analisi con le metodologie esposte
nel paragrafo precedente.
0.1
0.08
0.06
0.04
0.02
0
0 500 1000 1500 2000 2500 3000 3500 4000
Dimensione
Figura 2.3: Confronti tra i tempi dell’analisi del prodotto tra una matrice e un vettore
10
GFlops [log]
0.1
0.01
10 100 1000 10000
Dimensione [log]
Figura 2.4: Confronti tra i GFlops dell’analisi del prodotto tra una matrice e un vettore
24
dim ACML BLITZ EIGEN2 HAND MKL MTL4 D MTL4 S
10 0.0 0.0 0.0 0.0 0.0 0.0 0.0
20 0.0 0.0 0.0 0.0 0.0 0.0 0.0
30 0.0 0.0 0.0 0.0 0.0 0.0 0.0
40 0.0 0.0 0.0 0.0 0.0 0.0 0.0
50 0.0 0.0 0.0 0.0 0.0 0.0 0.0
60 0.0 0.0 0.0 0.0 0.0 0.0 0.0
70 0.0 0.0 0.0 0.0 0.0 0.0 0.0
80 0.0 0.0 0.0 0.0 0.0 0.0 0.0
90 0.0 0.0 0.0 0.0 0.0 0.0 0.0
100 0.00002 0.00006 0.00004 0.00004 0.00003 0.00005 0.00001
200 0.00009 0.00022 0.00012 0.00016 0.00012 0.00032 0.00001
300 0.00029 0.00048 0.00026 0.00036 0.00023 0.00079 0.00002
400 0.00056 0.00085 0.0005 0.00066 0.00047 0.00149 0.00002
500 0.00095 0.00138 0.00077 0.0011 0.00073 0.00230 0.00003
600 0.00146 0.0021 0.0013 0.00172 0.00129 0.00336 0.00004
700 0.00212 0.00291 0.00185 0.00242 0.00186 0.00459 0.00005
800 0.00285 0.00383 0.00259 0.0032 0.00259 0.00599 0.00005
900 0.00368 0.00484 0.00322 0.00406 0.00322 0.00759 0.00006
1000 0.0035 0.00598 0.00391 0.00502 0.00391 0.00775 0.00007
1200 0.00508 0.00859 0.00596 0.00723 0.00593 0.00834 0.00008
1500 0.00771 0.01345 0.00892 0.01127 0.00885 0.01309 0.00009
1700 0.00994 0.01727 0.01141 0.01452 0.01168 0.01956 0.00011
2000 0.01381 0.02415 0.01693 0.02017 0.01688 0.03090 0.00013
2200 0.01737 0.0302 0.02034 0.02522 0.02033 0.04018 0.00014
2500 0.02488 0.04015 0.02514 0.0335 0.0255 0.05451 0.00016
2700 0.0308 0.0469 0.02976 0.03911 0.02973 0.06494 0.00018
3000 0.03819 0.05806 0.03758 0.04829 0.0376 0.08150 0.0002
3200 0.04519 0.06616 0.04418 0.05483 0.04356 0.09428 0.00022
3500 0.05416 0.07872 0.05011 0.06556 0.04989 0.11371 0.00023
3700 0.06234 0.08792 0.05528 0.07321 0.05595 0.12720 0.00025
4000 0.07639 0.10297 0.06916 0.08553 0.06832 0.14902 0.00026
Tabella 2.2: Durate delle analisi del prodotto tra una matrice e un vettore
25
2.3 Livello 3: operazioni tra matrici
Questo paragrafo affronterà il problema della prodotto tra due matrici esprimibile nella
forma classica C = A ∗ B utilizzando le metodologie precedentemente elencate. Tutte le
routines ricevono in input un file di testo dal quale ricavano la matrice A; viene assegnato
di default una matrice B posta avere tutti i termini unitari e tramite una o più istruzioni
viene di volta in volta calcolato la matrice prodotto C.
2.3.1 ACML
Questa routine calcola il prodotto tra le matrici A e B e lo restituisce nella matrice C. Le
matrici sono tutte scritte in forma di vettore. La chiamata che effettua l’operazione del
prodotto è
dgemm(transa, transb, int m, int n, int k, double alpha, double *a,
int lda, double *b, int ldb, double beta, double *c, int ldc);
dove transa e transb ci consentono di inserire le matrici A e B trasposte o meno, m e
n sono le dimensioni di A, n e k sono le dimensioni di B, α è uno scalare che moltiplica
A, a, b e c sono le matrici A, B e C scritte in forma di vettore, lda, ldb e ldc sono
rispettivamente il numero di righe delle matrici, β è uno scalare che moltiplica il vettore
c. Questo vettore contiene la soluzione.
2.3.2 BLITZ++
Evitando discussioni sulla dichiarazione della matrici, risulta interessante la funzione che
ne calcola il prodotto:
firstIndex i;
secondIndex j;
thirdIndex k;
y = sum(A(i,j) * B(j,k), j);
2.3.3 EIGEN 2
Anche in questo caso la sintassi per dichiarare la matrice prodotto è molto semplice. E’
interessante notare come non sia necessario dichiarare a priori la dimensione della matrice
prodotto, ma come essa venga gestita dinamicamente, cioè viene allocata run-time e non
compile-time.
2.3.4 HAND
In questo caso sono necessari tre cicli f or:
for (int i=0; i<M; i++)
for (int k=0; k<N; k++)
for (int j=0; j<M; j++)
C[i][j]+= A[i][k] * B[k][j];
26
2.3.5 MKL
Si evita di discutere circa la sintassi poichè banalmente deducibile da quella delle librerie
ACML.
C = A * B;
27
2.3.8 Confronti tra le durate delle analisi
Vengono adesso proposti dei confronti tra le durate delle analisi con le metodologie esposte
nei paragrafi precedenti.
1.2
0.8
0.6
0.4
0.2
0
0 100 200 300 400 500 600 700 800 900
Dimensione
Figura 2.5: Confronti tra i tempi dell’analisi del prodotto tra due matrici
0.1
0.01
10 100 1000
Dimensione [log]
Figura 2.6: Confronti tra i GFlops dell’analisi del prodotto tra due matrici
28
dim ACML BLITZ EIGEN2 HAND MKL MTL4 D MTL4 S
10 0.00002 0.0 0.00001 0.00001 0.00001 0.00001 0.00001
20 0.00003 0.00004 0.00003 0.00004 0.00002 0.00005 0.00002
30 0.00008 0.00018 0.00009 0.0001 0.00007 0.00012 0.00004
40 0.00021 0.00046 0.00019 0.00024 0.00016 0.00025 0.00006
50 0.00039 0.00089 0.00038 0.00044 0.00031 0.00048 0.00010
60 0.00054 0.00152 0.00063 0.00078 0.00054 0.00081 0.00014
70 0.00092 0.00248 0.00103 0.00112 0.00086 0.00141 0.00020
80 0.00135 0.00376 0.00148 0.00148 0.00128 0.00204 0.00024
90 0.00173 0.00528 0.00203 0.00173 0.00184 0.00286 0.00030
100 0.00183 0.00396 0.00286 0.002 0.00153 0.00401 0.00038
200 0.01570 0.03139 0.02139 0.01955 0.01183 0.03209 0.00145
300 0.05672 0.19803 0.07131 0.08275 0.05277 0.10333 0.00331
400 0.13930 0.69930 0.16674 0.21775 0.15169 0.24717 0.00593
500 0.26786 1.65613 0.32238 0.50052 0.30302 0.47375 0.01001
600 0.47248 NaN 0.55876 0.97139 0.52770 0.82997 0.01364
700 0.75553 NaN 0.87678 1.67441 0.82313 1.28785 0.01873
800 1.11161 NaN 1.31649 NaN 1.23904 1.93624 0.02401
900 1.56742 NaN 1.85368 NaN 1.77554 NaN 0.03074
Tabella 2.3: Durate delle analisi del prodotto tra due matrici
29
Capitolo 3
3.1 Introduzione
Questo capitolo tratterà gli aspetti prettamente teorici che riguardano le metodologie
cosiddette dirette per la soluzione dei sistemi lineare [16], [6], [9]. Un sistema di m equazioni
lineari in n incognite è un insieme di relazioni algebriche esprimibile nella forma:
n
X
Aij xj = bi , i = 1, ..., m (3.1)
j=1
dove xj sono le incognite, Aij sono i coefficienti del sistema e bi sono le componenti
del vettore dei termini noti. Il sistema (3.1) può essere espresso in notazione matriciale
compatta:
Ax = b (3.2)
dove sono stati indicati con A = (Aij ) ∈ Cmxn i coefficienti della matrice, con b =
(bi ) ∈ Cm il vettore dei termini noti e con x = (xj ) ∈ Cn il vettore delle incognite. Si
definisce soluzione di (3.2) qualsiasi n-upla di valori di xj che soddisfi (3.1). Questo capitolo
focalizzerà l’attenzione sui sistemi di equazioni reali con matrici di coefficienti quadrate
di ordine n. In questo caso l’esistenza e l’unicità della soluzione di (3.1) è garantita se è
rispettata una delle seguenti condizioni:
• A è invertibile;
• rank(A) = n;
∆j
xj = , j = 1, ...n, (3.3)
det(A)
30
dove ∆j è il determinante di quella matrice ottenuta sostituendo la j-esima colonna di A
con il vettore b. L’applicazione di questa formula implica un numero elevato di operazioni.
Sono stati allora proposti dei metodi alternativi, detti metodi diretti, che consentono di
ricavare la soluzione in un numero finito di passi.
x1 = b1 /L11
x2 = (b2 − L21 x1 )/L22 (3.5)
x3 = (b3 − L31 x1 − L32 x2 )/L22
Questo algoritmo può essere esteso ai sistemi n x n ed è detto forward substitution. Nel
caso in esame, cioè di sistema esprimibile nella forma Lx = b, con L matrice triangolare
inferiore non singolare di ordine n (con n ≥ 2), il metodo può cosı̀ essere espresso:
b1
x1 = L11 ,
P
xi = 1
Lii bi − i−1
j=1 L ij xj , i = 2, ..., n (3.6)
Si possono trarre conclusioni simili dal sistema lineare Ux = b, con U matrice triango-
lare superiore non singolare di ordine n (con n ≥ 2). In questo caso si utilizza un metodo
detto backward substitution:
bn
xn = Unn ,
P
xi = 1
Uii bi − nj=i+1 Uij xj , i = n − 1, ..., 1 (3.7)
31
3.3 Il Metodo di Eliminazione di Gauss (GEM)
Il Metodo di Eliminazione di Gauss (GEM) ha lo scopo di ridurre il sistema Ax=b in
b dove U è una matrice triangolare superiore e b
un altro equivalente Ux = b, b è un vettore
dei termini noti aggiornato. Quest’ultimo sistema può essere risolto tramite backward
substitution.
Una qualsiasi matrice A può essere trasformata in una matrice a gradini per righe
operando una sequenza di operazioni (operazioni elementari sulle righe) di uno dei seguenti
tipi:
• si scambiano tra di loro due righe;
32
Definita matrice elementare E una matrice quadrata che si ottiene operando una
singola operazione elementare sulle righe della matrice identità I, è possibile affermare
che eseguire una operazione elementare sulle righe di una matrice A (mxm) equivale a
fare il prodotto EA, dove E è la matrice elementare mxm ottenuta eseguendo la stessa
operazione elementare sulle righe della matrice identità Im .
Si supponga di applicare a una matrice A una sequenza di k operazioni elementari sul-
le righe (come descritto nell’algoritmo di Gauss) per ottenere una matrice U triangolare
superiore; la prima di queste operazioni elementari la si realizza effettuando il prodotto
E1 A, essendo E1 la matrice elementare corrispondente a tale operazione elementare; poi
bisogna effettuare una seconda operazione sulle righe, a cui corrisponde la matrice elemen-
tare E2 e quindi si effettua il prodotto E2 (E1 A). L’algoritmo di Gauss descrive quindi
questa sequenza di passi:
cioè
U = PA (3.14)
dove
P = Ek ...E2 E1 (3.15)
Ciò vuol dire che la matrice P si ottiene operando sulla matrice identità la stessa
sequenza di operazioni elementari utilizzate per passare dalla matrice A alla matrice U.
33
3.4 La fattorizzazione LU
Nel paragrafo precedente è stato visto come una matrice A possa essere trasformata me-
diante operazioni elementari sulle righe in una matrice U triangolare superiore. Se non si
pretende di avere U nella forma ridotta, allora la riduzione si può operare aggiungendo
a righe successive multipli delle righe precedenti, ed eventualmente scambiando righe, ma
mai aggiungendo a una riga precedente multipli di una riga successiva; in questo modo le
matrici Ei o corrispondono a scambi di righe oppure sono triangolari inferiori. La matrice
A viene detta inferiormente ridotta se può essere ridotta nella forma a gradini senza utiliz-
zare scambi di righe. In tal caso la matrice P = Ek ...E2 E1 è prodotto di matrici triangolari
inferiori e quindi è a sua volta triangolare inferiore; anche L = P−1 è triangolare inferiore
e la matrice A si può scrivere nella forma:
A = LU (3.16)
Esempio
Trovare la fattorizzazione LU per la seguente matrice
0 2 −6 −2 4
A = 0 −1 3 3 2 (3.17)
0 −1 3 7 10
Soluzione
0 2 −6 −2 4
A = 0 −1 3 3 2 (3.18)
0 −1 3 7 10
0 1 −3 −1 2
7→ 0 0 0 2 4 (3.19)
0 0 0 12 6
0 1 −3 −1 2
7→ 0 0 0 1 2 =U (3.20)
0 0 0 0 0
Risulta A = LU, dove
2 0 0
L = −1 2 0 (3.21)
−1 6 1
è la matrice ottenuta dalla matrice identità sostituendo nei posti corrispondenti le
componenti marcate nel processo di riduzione.
34
La fattorizzazione LU risulta essere molto utile. Si supponga infatti di dover risolvere
il sistema Ax = b. Se A = LU, allora
LUx = b (3.22)
35
3.5 La fattorizzazione di Cholesky
La decomposizione di Cholesky è la fattorizzazione di una matrice hermitiana e definita
positiva in una matrice triangolare inferiore e nella sua trasposta coniugata. Essa si può
considerare come un caso speciale della più generale decomposizione LU.
Sia A una matrice quadrata, hermitiana e definita positiva ; tale A può essere decom-
posta come
A = LL+ (A ∈ Km×m ) (3.23)
con L matrice triangolare inferiore con elementi diagonali positivi e L+ la matrice coniu-
gata trasposta di L.
Se la matriceA è reale e simmetrica, la coniugata trasposta di L coincide con la
trasposta e la decomposizione si semplifica
A(1) = A (3.25)
(i) Ai,i b∗i
A = (3.26)
bi B(i)
!
√1 0
Ai,i
Li = (3.27)
− A1i,i bi I
!
1 0
A(i) = L−1 (L−1
i )
∗
(3.28)
i 0 B(i) − A1i,i bi b∗i
in modo che
(i) 1 0
A = L−1
i (i+1) (L−1
i )
∗
(3.30)
0 A
Il ciclo termina dopo n passi dove A(n) = 1. Si nota che la matrice triangolare inferiore
L è calcolata come
L = L1 L2 . . . Ln (3.31)
L’algoritmo di Cholesky-Crout fornisce un procedimento per calcolare i termini della
matrice triangolare inferiore L. Esso inizia formando l’angolo superiore sinistro della
matrice L e procede a calcolare la matrice colonna per colonna.
36
v
u i−1
u X
Li,i = tAi,i − L2i,k . peri = 1, ..., m (3.32)
k=1
i−1
!
1 X
Lj,i = Aj,i − Lj,ι Li,ι perj = i + 1, ..., m (3.33)
Li,i ι=1
37
Capitolo 4
4.1 Introduzione
In precedenza è stato affermato che i problemi della meccanica delle strutture possono
essere affidati a un calcolatore che si occupa della soluzione di un sistema di equazioni.
Questo capitolo si occuperà del problema dei solutori algebrici, cioè verranno implementate
delle routines allo scopo di risolvere un sistema di equazioni esprimibile nella classica forma
A ∗ x = b, dove x è il vettore delle incognite, b è il vettore dei termini noti e A è la matrice
dei coefficienti.
Sono stati implementati dei solutori che operano su matrici generiche:
• solutore genericoACML,
• solutore genericoMKL.
e altri che lavorano con matrici simmetriche:
• solutore triangolare ACML,
• solutore MKL,
• solutore BANDEC/BANDSOL.
Infine sono stati implementati dei solutori per matrici sparse:
38
• solutore CHOLMOD SuiteSparse [7],
Allora pi (1) fornisce la frazione di esempi per la quale il solutore i è più efficace (in
base al parametro sij , pi (2) fornisce la frazione per la quale esso è all’interno di un fattore
2 del migliore. Il parametro utilizzato per costruire i benchmark è la cpu time impiegata
per svolgere il processo di fattorizzazione.
39
4.3 Solutori per matrici generiche
Vengono di seguito esposte le routines necessarie per effettuare la risoluzione di un sistema
lineare quando la matrice dei coefficienti si presenta in forma generica.
4.3.1 ACML
La funzione che opera la fattorizzazione è:
dove T RAN S indica la forma del sistema di equazioni, N è la dimensione della matrice,
N RHS il numero di colonne del vettore dei termini noti, A è la matrice dei coefficienti,
LDA ne è la dimensione principale, B è il vettore dei termini noti, LDB è la lunghezza
dello stesso, IN F O è un parametro indicatore della riuscita della soluzione.
4.3.2 MKL
Non si ci sofferma su questa routine poichè estremamente simile a quella precedentemente
esposta.
40
4.4 Solutori per matrici simmetriche
Vengono adesso presentati i solutori implementati per risolvere sistemi di equazioni quando
la matrice si presenta in forma simmetrica. In questo caso è necessario fornire in input
solo la parte triangolare inferiore della matrice stessa.
4.4.1 ACML
La funzione che opera la fattorizzazione della matrice simmetrica è
dove N RHS è il numero di colonne del vettore dei termini noti e LDB è la lunghezza
dello stesso.
4.4.2 MKL
La fattorizzazione avviene tramite la routine
4.4.3 MTL 4
Fornita in input la matrice simmetrica A, ne viene isolato il triangolo inferiore tramite la
funzione
AA = lower(A);
x = lower_trisolve(AA,b);
41
4.5 Solutori per matrici bandate
In questo paragrafo vengono esposti i solutori per matrici bandate che sono stati imple-
mentati.
4.5.1 ACML
La chiamata alla procedura che fattorizza è
dove nrhs è il numero di colonne di b, b è il vettore dei termini noti, ldb è il numero
delle righe di b, inf o è un indicatore dell’esito del processo di soluzione.
4.5.2 MKL
La sintassi delle chiamate per fattorizzare e risolvere è uguale a quella del caso precedente.
4.5.3 BANDEC/BANDSOL
//---------------------------------------------------------------------------------------------------
int ldlfact(int neq, int band, double** e)
{
int j, k, n, m, i;
short nlab=0;
double Zero = 1e-15;
for (n=0; n<neq; n++)
{
if ( fabs(e[0][n])> Zero )
for (m=1; (m<band)&&((i=n+m)<neq); m++)
{
double d = e[m][n]/e[0][n];
for (j=0, k=m; k<band; k++, j++)
e[j][i]-=d*e[k][n];
e[m][n]=d;
}
else nlab++;
42
}
return nlab;
}
//---------------------------------------------------------------------------------------------------
double ldlsolve(int neq, int band, double** e, double* v)
{
int n, m;
double d, dot=0.0;
double Zero= 1e-15;
for (n=0; n<neq; n++)
if ( fabs(e[0][n])>Zero)
for (m=1; (m<band)&&(n+m<neq); m++)
v[n+m] -= e[m][n]*v[n];
43
4.5.4 Confronti tra le durate delle analisi
I solutori sopra esposti sono stati messi a paragone confrontando le durate delle analisi.
Sono state fornite in input delle matrici tutte caratterizzate dall’essere reali, simmetriche,
bandate e definite positive [4].
44
file Dimensione Nonzeri Banda Banda/Dim [%]
bcsstk14 1806 63454 162 8.97
bcsstk15 3948 117816 438 11.09
bcsstk16 4884 290378 141 2.89
bcsstk17 10974 428650 522 4.76
bcsstk18 11948 149090 1244 10.41
bcsstk24 3562 159910 3334 93.60
Tabella 4.3: Durate delle analisi dei solutori bandati normalizzati rispetto a quella del
solutore MKL
45
Benchmark solutori bandati
1
0.9
0.8
0.7
0.6
Performance profile
0.5
0.4
0.3
acml
0.2
mkl
bandec
0.1
0
0 2 4 6 8 10 12 14
α
46
4.6 Solutori per matrici sparse
In questo paragrafo vengono presentati dei solutori da utilizzare quando la matrice dei
coefficienti si presenta in forma sparsa. La matrice in input è contenuta in un file di
testo dove sulla prima riga compaiono il numero di righe, quello di colonne e il numero di
nonzeri nella sola parte triangolare nel caso di CHOLMOD, PARDISO e SPOOLES, di
tutta la matrice nel caso di UMFPACK; ciò è dovuto al fatto che l’ultimo è un solutore per
matrici non simmetriche. Dalla seconda riga in poi compaiono tre colonne che contengono
rispettivamente l’indice di riga, quello di colonna e il valore degli elementi nonzeri. Questa
forma di scrivere una matrice si chiama triplet form.
cholmod_triplet *T;
T = cholmod_read_triplet(f,&c);
cholmod_sparse *A ;
A = cholmod_triplet_to_sparse(T, T->nzmax, &c);
47
4.6.2 UMFPACK SuiteSparse
La matrice in input in triplet form viene convertita in column compressed form
dove M è l’ordine della matrice e nz il numero di nonzeri dell’intera matrice (si presti
attenzione al fatto che bisogna passare tutta la matrice alla routine e non solo un triangolo
anche qualora essa dovesse essere simmetrica!). Gli indici di riga degli elementi della
colonna j sono memorizzati in Ai[Ap[j]...Ap[j + 1] − 1]. Il corrispondente valore numerico
è memorizzato in Ax[Ap[j]...Ap[j + 1] − 1]. Non sono presenti indici duplicati ed essi sono
forniti per ogni colonna in ordine ascendente. Il termine Ap[0] deve essere nullo. Il numero
complessivo di nonzeri della matrice è nz = Ap[n].
La matrice subisce quindi un processo di fattorizzazione simbolica
48
4.6.3 SPOOLES
La matrice dei coefficienti viene costruita tramite alcune istruzioni:
InpMtx *mtxA;
InpMtx_init(mtxA, INPMTX_BY_ROWS, type, nent, neqns);
InpMtx_inputRealEntry(mtxA, I[i], J[i], val[i]);
InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS);
frontmtx = FrontMtx_new();
mtxmanager = SubMtxManager_new();
SubMtxManager_init(mtxmanager, NO_LOCK, 0);
FrontMtx_init(frontmtx, frontETree, symbfacIVL, type,
symmetryflag, FRONTMTX_DENSE_FRONTS, pivotingflag, NO_LOCK,
0, NULL, mtxmanager, msg1v1, msgFile);
mtxY = DenseMtx_new();
DenseMtx_init(mtxY, type, 0, 0, neqns, 1, 1, neqns);
DenseMtx_zero(mtxY);
for(int irow = 0; irow<M; irow++)
DenseMtx_setRealEntry(mtxY, irow, 0, 1.0);
mtxX = DenseMtx_new();
DenseMtx_init(mtxX, type, 0, 0, neqns, nrhs, 1, neqns);
DenseMtx_zero(mtxX);
FrontMtx_solve(frontmtx, mtxX, mtxY, mtxmanager, cpus, msg1v1, msgFile);
49
4.6.4 PARDISO MKL
La matrice di input in triplet form viene convertita in columns compressed form
phase = 11;
PARDISO (pt, &maxfct, &mnum, &mtype, &phase,
&M, val, ia, I, &idum, &nrhs,
iparm, &msglvl, &ddum, &ddum, &error);
phase = 22;
PARDISO (pt, &maxfct, &mnum, &mtype, &phase,
&M, val, ia, I, &idum, &nrhs,
iparm, &msglvl, &ddum, &ddum, &error);
Inizializzato unitario il vettore dei termini noti, avviene infine la soluzione del sistema
phase = 33;
iparm[7] = 2; /* Max numbers of iterative refinement steps. */
/* Set right hand side to one. */
for (int i = 0; i<M; i++)
b[i] = 1.0;
PARDISO (pt, &maxfct, &mnum, &mtype, &phase,
&M, val, ia, I, &idum, &nrhs,
iparm, &msglvl, b, x, &error);
50
4.6.5 Confronti tra le analisi
I solutori sopra esposti sono stati messi a paragone confrontando le durate delle analisi.
Sono state fornite in input delle matrici tutte caratterizzate dall’essere reali, simmetriche
e definite positive [4].
51
Figura 4.17: bcsstk07 Figura 4.18: bcsstk08 Figura 4.19: bcsstk09
52
Figura 4.29: bcsstm05 Figura 4.30: bcsstm06 Figura 4.31: bcsstm08
53
Figura 4.41: pwtk Figura 4.42: s1rmq4m1 Figura 4.43: s1rmt3m1
54
file Dimensione Nonzeri
1138bus 1138 4054
494bus 494 1666
662bus 662 2474
685bus 685 3249
Dubcova2 65025 1030225
bcsstk03 112 376
bcsstk04 132 1890
bcsstk05 153 1288
bcsstk06 420 4140
bcsstk07 420 4140
bcsstk08 1074 12960
bcsstk09 1083 18437
bcsstk10 1086 22070
bcsstk11 1473 34241
bcsstk13 2003 83883
bcsstk14 1806 63454
bcsstk15 3948 117816
bcsstk16 4884 290378
bcsstk17 10974 219812
bcsstk18 11948 149090
bcsstk25 15439 252241
bcsstm05 153 153
bcsstm06 420 420
bcsstm07 420 3836
bcsstm09 1083 1083
bcsstm10 1086 11589
bundle1 10581 770811
ct20stif 52329 2600295
cvxbqp1 50000 349968
finan512 74752 596992
gyrok 17361 1021159
minsurfo 40806 203622
nos5 468 5172
pwtk 217918 11524432
s1rmq4m1 5489 143300
s1rmt3m1 5489 21765
s2rmq4m1 5489 263351
s2rmt3m1 5489 217681
s3rmq4m1 5489 143300
s3rmt3m1 5489 112505
s3rmt3m3 5357 207123
smt 25710 3749582
t3dle 20360 20360
wathen100 55
30401 471601
0.9
0.8
0.7
0.6
Performance profile
0.5
0.4
0.3
0.2
cholmod
0.1
pardiso
spooles
umfpack
0
0 2 4 6 8 10 12 14 16
α
56
file Cholmod Pardiso Spooles UMF
1138bus 0.0 0.0 0.0 0.0
494bus 0.00 0.00 0.0 0.0
662bus 0.00 0.00 0.0 0.0
685bus 0.00 0.00 0.0 0.0
Dubcova2 0.71 0.39 1.04 1.73
bcsstk03 0.0 0.0 0.0 0.01
bcsstk04 0.0 0.0 0.0 0.01
bcsstk05 0.0 0.0 0.0 0.01
bcsstk06 0.0 0.0 0.0 0.01
bcsstk07 0.0 0.0 0.0 0.01
bcsstk08 0.0 0.0 0.01 0.02
bcsstk09 0.01 0.0 0.01 0.03
bcsstk10 0.01 0.0 0.0 0.02
bcsstk11 0.01 0.0 0.0 0.02
bcsstk13 0.07 0.04 0.07 0.14
bcsstk14 0.02 0.01 0.02 0.06
bcsstk15 0.13 0.08 0.19 0.29
bcsstk16 0.17 0.11 0.16 0.37
bcsstk17 0.20 0.16 0.21 0.49
bcsstk18 0.16 0.10 0.20 0.39
bcsstk24 0.05 0.05 0.06 0.14
bcsstk25 0.30 0.27 0.43 0.69
bcsstm05 0.0 0.0 0.0 0.0
bcsstm06 0.0 0.0 0.0 0.0
bcsstm07 0.0 0.0 0.0 0.0
bcsstm09 0.0 0.0 0.0 0.0
bcsstm10 0.0 0.0 0.0 0.01
bundle1 0.20 0.07 0.47 3.44
ct20stif 3.17 2.37 7.63 7.03
cvxbqp1 1.62 0.43 3.92 3.46
finan512 0.77 0.35 NaN 2.13
gyrok 0.27 0.22 0.18 0.72
minsurfo 0.25 0.17 0.37 0.61
nos5 0.0 0.0 0.01 0.01
pwtk 16.84 10.81 53.99 40.76
s1rmq4m1 0.11 0.08 0.12 0.38
s1rmt3m1 0.09 0.09 0.09 0.22
s2rmq4m1 0.12 0.11 0.12 0.43
s2rmt3m1 0.09 0.09 0.09 0.23
s3rmq4m1 0.12 0.11 0.12 0.39
s3rmt3m1 0.10 0.09 0.09 0.28
s3rmt3m3 0.08 0.07 0.06 0.25
smt 4.87 3.46 17.24 11.27
t3dle 0.0 57 0.0 0.08 0.01
wathen100 0.30 0.22 0.41 0.70
Tabella 4.6: Durate delle analisi dei solutori bandati e dei solutori sparsi
0.9
0.8
0.7
0.6
Performance profile
0.5
0.4
0.3
0.2 acml
mkl
bandec
cholmod
0.1 pardiso
spooles
umfpack
0
0 2 4 6 8 10 12
α
58
4.7 L’impatto del calcolo high performance sulla risoluzione
dei sistemi lineari
Come già più volte affermato, ciò che incide di più sulle prestazioni di un’applicazione che
gira sui moderni microprocessori è la lentezza nell’accesso ai dati. Molte macchine usano
una cache che trasferisce i dati alla cpu molto velocemente, ma il carico di dati che può
immagazzinare solitamente è molto ridotto. Ciò significa che se si vogliono ottenere elevate
prestazioni è necessario riutilizzare i dati nella cache il più possibile per ammortizzare il
costo del loro trasferimento dalla memoria principale. I più adatti e più largamente usato
strumenti per fare ciò sono le routines Level 3 BLAS O(n3) coinvolgono le matrici di
ordine n [11]. Le due routines più importanti usate nella fattorizzazione LU sono la
routine che opera il prodotto tra due matrici dgemm e quella che opera la soluzione di
un sistema traingolare DTRSM. Se intendiamo la fattorizzazione LU in una maniera a
blocchi o partizionata, diventa relativamente semplice mostrare come le Level 3 BLAS
possano essere utilizzate. La figura (4.54) mostra una schematizzazzione a blocchi della
fattorizzazione LU. Le operazioni di fattorizzazione sono svolte nelle regioni tratteggiate
ed è richiesto l’accesso alle regioni ombreggiate.
59
Capitolo 5
Approssimazione di autovalori e
autovettori
5.1 Introduzione
Lo scopo di questo capitolo è quello di descrivere le varie tecniche utilizzabili per il calcolo
di autovalori e autovettori [16]. Prima di passare agli algoritmi, però, si ritiene necessario
introdurre delle considerazioni preliminari sulla risoluzione di tali problematiche.
Il più semplice è il cosiddetto problema standard agli autovalori esprimibile in forma:
KΦ = λΦ (5.1)
0 ≤ λ1 ≤ λ2 · · · ≤ λn−1 ≤ λn (5.2)
KΦ = ΦΛ (5.3)
dove Φ è una matrice n × p le cui colonne sono gli autovettori del problema, mentre Λ è
una matrice p × p i cui termini diagonali sono gli autovalori. Se K è definita positiva allora
λi > 0, mentre se è semidefinita positiva λi ≥ 0 e il numero di autovalori nulli corrisponde
ai moti rigidi.
Il problema (5.1) viene risolto ad esempio quando bisogna valutare la matrice di
rigidezza di un elemento.
Un secondo tipo di problema, che si incontra ad esempio nelle applicazioni, è il cosid-
detto problema generalizzato agli autovalori:
KΦ = λMΦ (5.4)
60
dove K e M sono delle matrice di dimensioni n × n. Applicazioni del problema 5.4 sono
ad esempio legate alla dinamica quando si studia il problema con le tecniche dell’analisi
modale. In questo caso le due matrici sono rispettivamente le matrice delle rigidizze e
delle masse del problema. In tal caso gli autovalori λi e i corrispondenti autovettori φi
sono rispettivamente i quadrati delle pulsazioni ωi 2 e le forme modali.
In analogia a quanto fatto nella (5.3) è possibile riscrivere il problema come:
KΦ = MΦΛ (5.5)
dove le colonne di Φ sono gli autovettori, mentre la matrice diagonale Λ contiene gli
autovalori.
Il problema generalizzato (5.4) sarebbe riconducibile a quello standard (5.1) qualora la
matrice M fosse unitaria. In analogia alla soluzione di (5.1), gli autovalori di(5.4) λi > 0,
dove gli autovalori nulli corrispondono ai moti rigidi del sistema.
Un secondo tipo di problema generalizzato si incontra nell’analisi a buckling:
Kt φ = λKt−∆t φ (5.6)
dove Kt−∆t e Kt sono le matrici di rigidezza corrispondenti agli istanti (cioè ai livelli di
carico) t − ∆t e t.
Nel capitolo dedicato alla soluzione di sistemi lineari è stata già messa in luce l’im-
portanza di usare procedure di calcolo efficaci. Ciò viene avvertito in maniera ancor più
significativa nel caso dei problemi agli autovalori poichè la risoluzione di tale problema
comporta un onere computazionale superiore a quello della risoluzione dei sistemi di equa-
zioni. Sono presenti in letteratura molte metodologie per la risoluzione dei problemi agli
autovalori, ma in meccanica delle strutture l’attenzione si focalizza su quei metodi che
sfruttano le particolari proprietà delle matrici (simmetriche, definite positive, bandate e
cosı̀ via). Alcuni algoritmi traggono vantaggio da queste proprietà allo scopo di ridurre il
costo computazionale dell’operazione.
61
autocoppia (λi , φi ) soddisfa la (5.4) e si ha:
Questa equazione dice che se si individua un vettore λi Mφi e lo si usa come vettore
dei carichi R nell’equazione KU = R, allora U = φi . Ciò suggerisce di usare gli algoritmi
mostrati nel capitolo sulla risoluzione dei sistemi lineari.
L’equazione (5.7) mostra anche che un autovettore è definito come multiplo di se stesso,
cioè:
K(αi φi ) = λi M(αi φi ) (5.8)
dove αi è una costante non nulla. L’autovettore che ci interessa è quello che soddisfa la
proprietà di ortonormalità rispetto a M:
La soluzione della (5.4) per p autovalori desiderati è stabilita nella (5.5). Le relazioni
(5.9) e (5.10) permettono di scrivere:
ΦT KΦ = Λ (5.11)
ΦT M Φ = I (5.12)
E’ molto importante notare che le (5.11) e (5.12) sono condizioni che gli autovettori
devono soddisfare, ma se l’ortonormaltà rispetto a M e l’ortogonalità rispetto a K sono
soddisfatte i p vettori non sono necessariamente autovettori a meno che non sia p = n.
In altre parole si assuma che X contenga p vettori, con p ≤ n, e che sia XT KX = D e
XT MX = I; allora i vettori contenuti in X e gli elementi diagonali di D possono essere o
meno rispettivamente autovettori e autovalori di (5.4). Se p = n allora X = Φ e D = Λ
poichè solo gli autovalori sono la base dell’intero spazio n-dimensionale e diagonalizzano
le matrici K e M.
5.2.2 Lo shifting
Una procedura sovente utilizzata per la risoluzione dei problemi agli autovalori è quella
dello shifting il cui scopo è quello di velocizzare il processo di soluzione. Nella soluzione
di Kφ = λMφ si dà uno shift ρ a K e si calcola:
K̂ = K − ρM (5.13)
e si considera il problema
K̂ψ = µMψ (5.14)
62
Per capire come gli autovalori di Kφ = λMφ siano K̂ψ = µMψ si riscrive la (5.14)
come
Kψ = γMψ (5.15)
con γ = ρ + µ. La (5.15) è il problema Kφ = λMφ dove
λi = ρ + µ i ; φi = ψi (5.16)
In altre parole gli autovettori di K̂ψ = µMψ sono gli stessi di Kφ = λMφ, mentre gli
autovalori vanno diminuiti di ρ. Una frequenta applicazione della tecnica dello shifting si
ha quando è richiesto il calcolo dei moti rigidi e l’algoritmo utilizzato non è stato ideato
esplicitamente per la determinazione degli autovalori nulli. Da quanto appena esposto è
possibile affermare che se sono presenti dei moti rigidi è sempre possibile lavorare su una
matrice di rigidezza shiftata che presenta tutti gli autovalori positivi.
M = SST (5.17)
dove S è una matrice non singolare. Se la (5.17) viene sostituita nella (5.4) si ha
Kφ = λSST φ (5.18)
φ̃ = ST φ (5.19)
63
E’ possibile utilizzare due decomposizioni di M: la fattorizzazione alla Cholesky e la
decomposizione spettrale. Se si usa la fattorizzazione alla Cholesky si ha
S = L˜M . (5.22)
M = RD2 RT (5.23)
essendo
S = RD2 (5.24)
E’ da notare che quando M è diagonale le espressioni (5.22) e (5.24) di S coincidono,
mentre sono diverse quando M è bandata.
Confrontando le due decomposizioni, è possibile affermare che la fattorizzazione alla
Cholesky è computazionalmente più vantaggiosa a causa del basso numero di operazioni
richieste; d’altro canto la decomposizione spettrale può portare a una maggiore accuratezza
nella risoluzione del problema Kφ = λMφ.
Se M è mal condizionata, si può optare per decomporre K al suo posto. Il problema
generalizzato KΦ = λMΦ viene scritto come Mφ = (1/λ)Kφ e si può ottenere il problema
standard
1
M̃φ̃ = φ̃ (5.25)
λ
dove
M̃ = S−1 MS−T (5.26)
M = SST (5.27)
φ̃ = ST φ (5.28)
ed S si può ottenere come fattorizzazione alla Cholesky o decomposizione spettrale di K.
64
Essendo φ̄ 2
= 1 facendo la norma si ha
−1
1 ≤ (Λ − λ̄I) krk2 (5.32)
2
ed essendo
−1 1
(Λ − λ̄I) = max (5.33)
2 i λi − λ̄
si ha
1
min ≤ krk2 (5.34)
i λi − λ̄
L’espressione (5.34) fornisce una misura dell’accuratezza dell’approssimazione effettua-
ta sull’autovalore.
Se λ̄ è un’approssimazione dell’autovalore λi , il corrispondente vettore φ̄ è un’appros-
simazione di φi :
krk2
φ̄ − αφi 2 ≤ ; min λi − λ̄ (5.35)
s
Se si usa il metodo dell’iterazione inversa è facile trovare una stima dell’errore. Sia
Si ha ( ! )1/2
φ̂T Mφ̂ 2
min λi − ρ(φ̄) ≤ − ρ(φ̄) (5.37)
i φ̄T Mφ̄
e ( )1/2
2
λi − ρ(φ̄) ρ(φ̄)
min ≤ 1− (5.38)
i λi φ̂T M φ̂/φ̄T M φ̄
dove ρ(φ̄) è il quoziente di Rayleigh
φ̄T Kφ̄
ρ(φ̄) = (5.39)
φ̄T Mφ̄
E’ interessante considerare la stima dell’errore
Kφ̄ − λMφ̄ 2
ǫ= (5.40)
Kφ̄ 2
65
5.3 L’iterazione inversa
La tecnica dell’iterazione inversa è molto efficace per quel che concerne il calcolo di un
autovettore e del corrispondente autovalore. Si assuma che K sia definita positiva e M sia
diagonale. Si assume un vettore di iterazione x1 e al passo k = 1, 2 . . . n si ha un’iterazione
del tipo:
Kx̄k+1 = Mxk (5.41)
e
x̄k1
xk+1 = T
(5.42)
(x̄k Mx̄k+1 )1/2
da cui si ha
xk+1 = φ1 per k→∞ (5.43)
Il punto fondamentale è la risoluzione della (5.41), mentre la (5.42) esprime solo la
condizione di ortonormalità rispetto a M.
Sebbene le relazioni (5.41) e (5.42) siano i passi dell’algoritmo, è più efficiente imple-
mentare l’iterazione inversa come segue:
Kx̄k+1 = yk (5.44)
x̄T yk
ρ(x̄k+1 ) = Tk+1 (5.46)
x̄k+1 ȳk+1
ȳk+1
yk+1 = T
(5.47)
(x̄k+1 ȳk+1 )1/2
da cui
yk+1 → Mφ1 e ρ(x̄k+1 ) → λ1 per k→∞ (5.48)
(k+1)
Se si indica con λ1 (=ρ(x̄k+1 )) l’approssimazione a λ1 , si misura la convergenza
con
(k+1) (k)
λ1 − λ1
(k+1)
≤ tol (5.49)
λ1
dove tol deve essere 10−2s o inferiore quando per il calcolo dell’autovalore λ1 è richiesta
una precisione 2s − digit.
Se si indica con l l’ultima iterazione
λ1 ∼
= ρ(x̄l+1 ) (5.50)
e
x̄l+1
φ1 ∼
= T
(5.51)
(x̄l+1 ȳl+1 )1/2
66
5.4 L’iterazione diretta
Il metodo dell’iterazione diretta è complementare a quello dell’interazione inversa. Esso
infatti permette di calcolare l’autovettore corrispondente all’autovalore massimo. Scelto
un vettore di iterazione iniziale x1 , nelle successive iterazioni si valuta per k = 1, 2, . . . , n:
Mx̄k+1 = yk (5.55)
x̄T
k+1 yk+1
ρ(x̄k+1 ) = (5.57)
x̄T
k+1 ȳk
ȳk+1
yk+1 = T
(5.58)
(x̄k+1 ȳk )1/2
da cui
yk+1 → Mφn e ρ(x̄k+1 ) → λn per k→∞ (5.59)
Se si indica con l l’ultima iterazione
λn ∼
= ρ(x̄l+1 ) (5.60)
e
x̄l+1
φn ∼
= T
(5.61)
(x̄l+1 ȳ)1/2
67
Se si indacano c = cos θ e s = sin θ, la procedura che calcola A(k) partendo da A(k−1)
può essere cosı̀ scritta
T
App (k) Apq (k) c s App (k−1) Apq (k−1) c s
= (5.63)
Apq (k) Aqq (k) −s c Apq (k−1) Aqq (k−1) −s c
La relazione (5.67) suggerisce a ogni passo k che la scelta migliore degli indici p e q è
quella che corrisponde al termine di A(k−1)
68
5.6 L’iterazione inversa Householder-QR
Il metodo dell’iterazione inversa Huseholder-QR (HQRI) è una procedura per la risoluzione
dei problemi standard. Se allora viene considerato un problema generalizzato, affinchè esso
possa essere risolto è necessario prima trasformarlo in uno standard. Verrà considerato il
problema Kφ = λφ con K che può avere autovalori nulli. Il metodo HQRI si articola in
tre passi:
• calcolo degli autovettori della matrice tridiagonale richiesti tramite iterazione inver-
sa.
Una differenza fondamentale con il metodo di Jacobi è che la matrice è prima trasfor-
mata senza iterazione in forma tridiagonale. Questa matrice può essere usata efficacemente
da questo metodo nel quale tutti gli autovalori sono calcolati. Nel seguito vengono esposti
i tre step di questo metodo.
Kk+1 = PT
k KPk ; k = 1, 2, . . . , n − 2 (5.70)
69
dove e1 è il versore di dimensione n − 1. Dalla relazione precedente si ottiene
w̄1 = k1 + sign(k21 ) kk1 k2 e1 (5.76)
dove k21 è l’elemento (2,1) di K1 .
Noto w̄1 , è possibile innescare l’algoritmo che riduce K in forma tridiagonale.
5.6.2 L’iterazione QR
L’iterazione QR è applicata alla matrice tridiagonale ottenuta dalla trasformazione di
Householder di K. In ogni caso l’iterazione QR sarebbe applicabile anche a K scritta
in forma originaria, ma il passaggio attraverso una sua riscrittura in forma tridiagonale
incrementa l’efficienza del processo di soluzione.
Il nome iterazione QR deriva dalla notazione usata nell’algoritmo. Il punto fondamen-
tale di questa tecnica è la fattorizzazione di K come
K = QR (5.77)
dove Q è una matrice ortogonale e R è una matrice triangolare superiore. Quindi si crea
RQ = QT KQ (5.78)
Una buona scelta è quella di ridurre K in una matrice triangolare superiore R usando
la matrice di rotazione di Jacobi, cioè valutando:
PT T T
n,n−1 . . . P3,1 P2,1 K = R (5.79)
dove la matrice di rotazione PT j,1 è scelta in modo da azzerare l’elemento (j,i). Usare
la(5.79) corrisponde a impiegare la (5.78):
Q = P2,1 P3,1 . . . Pn,n−1 (5.80)
L’algoritmo di iterazione QR si ottiene ripetendo le (5.77) e (5.78). Utilizzando la
notazione K1 = K, si scrive
Kk = Qk Rk (5.81)
e poi
Kk+1 = Rk Qk (5.82)
dove, trascurando il fatto che autovalori e autovettori possono non trovarsi nel solito
ordine,
Kk+1 → Λ e Q1 . . . Qk+1 Qk → Φ con k→∞ (5.83)
Questa pocedura può essere usata anche con lo shifting scrivendo:
Kk − µk I = Qk Rk (5.84)
Kk+1 = Rk Qk + µk I (5.85)
e anche ora come prima
Kk+1 → Λ e Q1 . . . Qk+1 Qk → Φ con k→∞ (5.86)
70
5.6.3 Calcolo degli autovettori
Una volta calcolati tutti gli autovalori in maniera accurata,si calcolano solo gli autovettori
desiderati della matrice Kn−1 (5.70) per semplice interazione inversa con shift pari al valore
del corrispondente autovalore. Sono di solito sufficienti due step dell’iterazione inversa
partendo da un vettore unitario. Gli autovettori di Kn−1 devono poi essere trasformati
con le trasformazioni di Householder usate per ottenere gli autovettori di K; indicando
con ψi l’i-esimo autovettore di Kn−1 e usando le matrici di trasformazione Pk si ha:
φi = P1 P2 . . . Pn−2 ψi (5.87)
αi−1 = x̄T
i Mxi−1 (5.90)
x̃i = x̄i − αi−1 xi−1 − βi−1 xi−2 (5.91)
1/2
βi = (x̃T
i Mx̃i ) (5.92)
xi = x̃i /βi (5.93)
La sequenza di vettori xi con i = 1, . . . , q generata utilizzando le relazioni precedenti
fornisce dei vettori che sono ortonormali a M e la matrice X = [x1 , . . . , xq ] soddisfa la
relazione:
XT (MK−1 M)X = Tq (5.94)
dove Tq è una matrice tridiagonale di ordine q:
α1 β2
β2 α2 β3
..
.
..
Tq = . (5.95)
..
.
αq−1 βq
βq αq
71
Usando la (5.94) è possibile mettere in relazione gli autovalori e autovettori di Tq quando
q = n con quelli del problema generalizzato Kφ = λMφ che può anche essere scritto come
1
Mφ = MK−1 Mφ (5.96)
λ
Usando la trasformazione
φ = Xφ̃ (5.97)
e la (5.94) s ottiene dalla (5.96)
1
Tn φ̃ = φ̃ (5.98)
λ
Gli autovalori di Tn sono i reciproci degli autovalori di Kφ = λMφ, mentre gli
autovettori sono messi in relazione dalla (5.97).
72
Capitolo 6
Approssimazione di autovalori e
autovettori - Applicazioni
Ax = λBx (6.1)
In questo capitolo verrà focalizzata l’attenzione prima sulla determinazione degli auto-
vettori e degli autovalori di una matrice e poi su quelli del problema generalizzato agli
autovalori.
73
6.1.1 ACML
E’ possibile individuare una chiamata che permette il calcolo di tutti gli autovalori e/o
autovettori:
dsbev(char jobz, char uplo, int n, int ndiag, double *a,
int lda, double *w, double *z, int ldz, int *info);
dove
• se jobz =′ N ′ viene effettuato solo il calcolo degli autovalori, mentre se jobz =′ V ′
anche quello degli autovettori;
• se uplo =′ U ′ vuol dire che si sta passando il triangolo superiore della matrice; se
uplo =′ L′ quello inferiore;
• n è la dimensione della matrice di input;
• ndiag è il numero di sovradiagonali (se uplo = ’U’) o di sottodiagonali (se uplo =
’L’);
• a è il vettore che contiene la matrice di input scritta in una forma particolare;
• lda è la dimensione di a;
• w è il vettore le cui componenti sono gli autovalori della matrice;
• z è il vettore che per colonne contiene gli autovettori della matrice;
• ldz è la dimensione di z;
• inf o è un indicatore della riuscita dell’analisi.
Molto più interessante risulta essere l’altra funzione, che permette di effettuare una
selezione sul calcolo di autovalori e autovettori.
dsbevx(char jobz, char range, char uplo, int n, int ndiag,
double *a, int lda, double *q, int ldq, double vl, double vu,
int il, int iu, double abstol, int *nfound, double *w, double *z,
int ldz, int *ifail, int *info);
dove
• se range =′ A′ vengono restituiti tutti gli autovalori, se range =′ V ′ vengono resti-
tuiti solo quelli il cui valore è compreso tra vl e vu, se range =′ I ′ vengono restituiti
glia autovalori tra l’indice il el’indice iu disposti in ordine ascendente;
• q è il vettore che contiene per colonne una matrice di dimensioni [ldq,n] usata (se
jobz=’V’) per la riduzione in forma triangolare;
• abstol è la tolleranza sull’errore nel calcolo degli autovalori;
• if ail se jobz=’V’ e info=0 i primi M elementi di ifail sono nulli; se inf o ≥ 0, ifail
contiene gli indici di quegli autovettori la cui convergenza è fallita.
74
6.1.2 MKL
Anche in questo caso è possibile scegliere una funzione che permette il calcolo di tutti gli
autovalori e/o autovettori:
75
6.2 Problema generalizzato agli autovalori
Questo paragrafo illustra le routines che sono state implementate per i seguenti scopi:
• ACML,
• MKL,
• ARPACK.
6.2.1 ACML
Parallelamente a quanto esposto per la determinazione di autovalori e autovettori di una
matrice, anche in questo caso è possibile individuare due importanti funzioni. La prima
istruzione calcola autovalori e/o autovettori:
dsbgv(char jobz, char uplo, int n, int ka, int kb, double *ab,
int ldab, double *bb, int ldbb, double *w, double *z, int ldz, int *info);
dove
• se uplo =′ U ′ vuol dire che si sta passando il triangolo superiore della matrice; se
uplo =′ L′ quello inferiore;
76
• ka è il numero di sovradiagonali (se uplo = ’U’) o di sottodiagonali (se uplo = ’L’)
di a;
• ldz è la dimensione di z;
dsbgvx(char jobz, char range, char uplo, int n, int ka, int kb,
double *ab, int ldab, double *bb, int ldbb, double *q, int ldq,
double vl, double vu, int il, int iu, double abstol, int *m,
double *w, double *z, int ldz, int *ifail, int *info);
6.2.2 MKL
Questa routine lavora in maniera del tutto analoga a quella precedentemente esposta.
6.2.3 ARPACK
Questa routine risolvere un problema agli autovalori generalizzato per matrici simmetriche.
Le matrici A e B vengono create tramite i costruttori
previa memorizzazione dei dati di input secondo la stessa procedura di storage usata dalle
routines ACML/MKL.
Tramite la chiamata
77
è possibile determinare i primi nev autovalori prossimi al valore 2.0.
E’ possibile anche trovare gli autovettori associati a tali autovettori:
dprob.FindEigenVectors();
Solution(A, B, dprob);
78
6.2.4 Confronti tra le durate delle analisi
Verranno di seguito confrontate le routines per matrici bandate che calcolano autovalori e
autovettori di un problema generalizzato. In particolare si effettueranno tre test:
Verranno fornite in input delle matrici disponibili presso [4] e le cui caratteristiche
principali sono elencate in tabella 6.1.
La tabella 6.2 mostra i risultati dell’analisi, mentre la figura (6.13) fornisce un’analisi
della prestazionalità complessiva delle tre routines utilizzate.
79
Figura 6.1: bcsstk03 Figura 6.2: bcsstk04 Figura 6.3: bcsstk05
80
Determinazione di tutti gli autovalori
1
0.9
0.8
0.7
0.6
Performance profile
0.5
0.4
0.3 acml
mkl
0.2 arpack
0.1
0
0 0.5 1 1.5 2 2.5 3 3.5
0.9
0.8
0.7
0.6
Performance profile
0.5
0.4
0.3 acml
mkl
0.2 arpack
0.1
0
0 0.2 0.4 0.6 0.8 1 1.2
81
Determinazione delle prime 5 autosoluzioni
1
0.9
0.8
0.7
0.6
Performance profile
0.5
0.4
0.3
0.2
acml
0.1
mkl
arpack
0
0 2 4 6 8 10 12 14 16 18
0.9
0.8
0.7
0.6
Performance profil
0.5
0.4
0.3
0.2
acml
0.1
mkl
arpack
0
0 5 10 15 20 25 30 35 40
82
Capitolo 7
7.1 Introduzione
Come già discusso in precedenza, in meccanica delle strutture frequente dover affrontare
due tipi di problemi:
In questo capitolo saranno esposte una serie di applicazioni meccaniche delle routines
esposte nei capitoli precedenti.
83
7.2.1 Test 1 - Cbeam
Si faccia riferimento alla Figura 7.1.
La tabella 7.1 mostra le durate dei processi di fattorizzazione dei vari solutori impie-
gati, mentre la figura (7.8) fornisce una misura della prestazionalità dei solutori in questa
situazione.
84
Mesh Chol Pard Spool UMF Acml Mkl Bandec Skyd N band/N [%]
100-15 0.72 1.02 0.82 1.26 1.67 2.56 16.52 1.93 14600 2.06
40-25 0.45 0.48 0.44 0.86 3.62 3.61 35.72 3.14 9560 5.03
40-30 0.62 0.48 0.55 1.20 6.00 5.87 62.57 5.59 11390 5.01
40-40 0.93 0.75 0.87 1.80 13.64 12.80 152.80 16.72 15050 4.99
20-30 0.22 0.20 0.17 0.38 2.81 2.89 26.46 2.84 5790 9.86
20-40 0.31 0.25 0.25 0.57 6.50 6.27 74.60 7.67 7650 9.81
0.9
0.8
cholmod
0.7
pardiso
spooles
umfpack
acml
0.6
mkl
Performance profile
bandec
skydec
0.5
0.4
0.3
0.2
0.1
0
0 1 2 3 4 5 6 7 8 9
α
85
Per una più immediata comprensione di questi risultati gli stessi vergono normalizzati
rispetto al più veloce, cioè Pardiso, ed espressi come multipli di questo nella tabella 7.2.
Tabella 7.2: Durate del processo di fattorizzazione per CBeam normalizzati rispetto a
Pardiso
86
7.2.2 Test 2 - Ibeam
Si faccia riferimento alla Figura 7.9.
Come già visto nel caso precedente, anche qui la struttura ha subito diverse discretiz-
zazioni e per ognuna di queste è stata condotta l’analisi lineare.
La tabella 7.3 mostra le durate dei processi di fattorizzazione dei vari solutori impiegati,
mentre la figura (7.14) fornisce informazioni sulle performance dei solutori.
Mesh Chol Pard Spool UMF Acml Mkl Bandec Skyd N band/N [%]
40-25 0.71 0.65 0.72 1.28 21.85 21.11 260.13 22.88 15826 5.95
40-30 0.95 0.78 0.90 1.84 37.81 34.98 1262.85 43.15 18876 5.95
40-40 1.41 1.20 1.39 6 2.78 89.60 77.59 NaN 97.40 24976 5.94
20-30 0.27 0.31 0.29 0.48 12.79 15.88 230.57 17.08 9596 11.70
20-40 0.40 0.39 0.40 0.66 37.51 37.22 549.23 44.98 12696 11.68
87
Figura 7.10: 40-30 Figura 7.11: 40-40 Figura 7.12: 20-30
0.9
0.8
0.7
0.6
Performance profile
0.5
0.4
0.3
cholmod
0.2
pardiso
spooles
umfpack
acml
0.1
mkl
bandec
skydec
0
0 2 4 6 8 10
α
88
Per una più immediata comprensione di questi risultati gli stessi vengono normalizzati
rispetto al più veloce, cioè Pardiso, ed espressi come multipli di questo nella tabella 7.4.
Tabella 7.4: Durate del processo di fattorizzazione per IBeam normalizzati rispetto a
Pardiso
La figura (7.15) mostra la misura della performance complessiva dei solutori sui due
test effettuati.
Benchmark KASP
1
0.9
0.8
0.7
0.6
0.5
0.4
cholmod
pardiso
0.3 spooles
umfpack
acml
0.2 mkl
bandec
skydec
0.1
0
0 2 4 6 8 10
89
7.3 Problema agli autovalori
Le procedure di calcolo agli autovalori sono state implementate nell’ambito di un codice di
calcolo per l’analisi elastica nonlineare alla Koiter di telai 3D. L’attenzione stata focalizzata
principalmente sulla ricerca del punto di biforcazione.
Gli spostamenti u[λ] sono considerati talmente piccoli che si può far riferimento alla
configurazione iniziale indeformata della struttura e il legame tensioni-deformazioni può
essere ritenuto lineare. Grazie a questa ipotesi la matrice di rigidezza tangente Kt [λ]
definita dall’equivalenza energetica
K0 v + λKg v = 0. (7.3)
90
7.3.1 Test 1 - Cupola
E’ stato utilizzato una struttura che presenta 2912 variabili che ha generato le matrici
in figura (7.16) e (7.17). Nella figura (7.18) sono riportate le durate dell’analisi volta a
ricercare le prime k autosoluzioni con le librerie ARPACK.
900
800
700
Durata dell’analisi [s]
600
500
400
300
200
100
0
0 200 400 600 800 1000 1200 1400 1600
Numero di autosoluzioni richieste
91
7.3.2 Test 2 - Traliccio
Stavolta è stato utilizzato una struttura che presenta 5910 variabili che ha generato le
matrici in figura (7.19) e (7.20). Nella figura (7.18) sono riportate le durate dell’analisi
volta a ricercare le prime k autosoluzioni con le librerie ARPACK.
1800
1600
1400
Durata dell’analisi
1200
1000
800
600
400
200
0
0 200 400 600 800 1000 1200 1400 1600 1800 2000
Numero di autosoluzioni richieste
92
Capitolo 8
Conclusioni
L’obiettivo di questa tesi è stato mettere in luce come le librerie numeriche di nuova gene-
razione, che la tecnologia mette a disposizione, riescano ad incrementare le prestazioni di
calcolo in maniera sensibile rispetto a strumenti che non sfruttano appieno l’architettura
del calcolatore. In alcuni casi l’incremento di prestazioni ottenuto in termini di tempo di
calcolo è stato di ordini di grandezza superiore a parità di algoritmo utilizzato. Questa
differenza enorme nelle prestazioni è dovuta essenzialmente alla maniera con cui, trami-
te opportuna implementazione del software, la CPU accede ai dati di cui ha prioritaria
necessita e ciò si traduce in:
• riduzione dell’attività di ricerca dei dati sulla rom e sulla ram da parte della CPU;
93
computazionale e di analisi agli elementi finiti in generale. Solitamente in problemi strut-
turali la matrice K è simmetrica bandata e definita positiva. Pertanto, passate in rassegna
le varie soluzioni proposte per matrici generiche e simmetriche indefinite, è stata focaliz-
zata l’attenzione sui solutori bandati. In particolare è stato dimostrato come procedure
sofisticate dal punto di vista della programmazione, ma basate su metodi tradizionali di
progettazione del software e quindi prive di risorse extra in termini di gestione dell’ac-
cesso ai dati, forniscano risultati decisamente peggiori rispetto ai solutori bandati ACML
e MKL che si appoggiano al pacchetto BLAS/LAPACK. La migliore prestazione del so-
lutore bandato MKL è da ricercare nel fatto che la libreria è ottimizzata per processori
Intel, quale quello che equipaggia la macchina usata per la campagna di sperimentazione.
è ragionevole presumere che se tale campagna fosse stata condotta su una macchina con
processore AMD il solutore ACML sarebbe stato più performante.
Si è quindi passati a studiare i solutori sparsi sempre nell’ambito di problemi governa-
ti da matrici simmetriche e definite positive. La campagna di sperimentazione condotta
su 44 matrici ha messo in luce come il solutore UMFPACK SuiteSparse sia quello me-
no performante. Ciò è dovuto alla natura dello stesso poichè progettato per matrici non
simmetriche. La stessa SuiteSparse implementa il solutore CHOLMOD per matrici sim-
metriche e definite positive che si ha fornito prestazioni di tutto rispetto essendo inferiore,
nelle performance, solo al solutore sparso PARDISO MKL, la cui elevata prestazionalità
è figlia in maniera particolare dell’utilizzo delle librerie MKL su una macchina Intel. Il
solutore SPOOLES ha dimostrato delle prestazioni accettabili.
La curiosità ha poi indotto ad estendere la campagna di sperimentazione dei solutori
sparsi anche alle matrici utilizzate per i solutori bandati ed è stato dimostrato come anche
nel caso di matrici di coefficienti bandate i solutori sparsi siano sempre più performanti
almeno nella vasta casistica di test numerici condotti che solo in maniera sintetica è stata
riportata nella tesi. Alla luce di queste considerazioni è possibile affermare che l’adozione
di un solutore sparso come PARDISO MKL, possa essere presa in considerazione anche
nei casi in cui la struttura della matrice del problema è bandata avendo mostrato delle
performance sempre paragonabili o superiori a quelle dei solutori bandati.
Un altro problema frequente in meccanica computazionale è quello della soluzione di
un problema agli autovalori generalizzato. La sperimentazione ha riguardato una routine
ACML, una MKL e una ARPACK ed ha messo in luce come le routines ACML e MKL
siano in vantaggio rispetto a quella ARPACK quando si tratta di calcolare l’intero set di
autovalori e/o autovettori. La situazione si ribalta quando la ricerca è finalizzata a un
numero di autosoluzioni decisamente piccolo rispetto alla dimensione delle matrici. Ciò è
ovviamente intimamente legato al diverso algoritmo che il pacchetto Arpack implementa
rispetto al pacchetto Blas/Lapack. Il primo, infatti, riconduce il calcolo delle autosoluzioni
all’utilizzo di una variante del metodo di Lanczos, mentre il secondo a una variante dell’al-
goritmo QR (si faccia riferimento al capitolo sugli aspetti teorici del calcolo di autovalori
e autovettori).
Si è quindi passati all’implementazione ed alla sperimentazione numerica su pacchetti
agli elementi finiti riguardanti problemi prettamente strutturali. In particolare sono state
inserite le routine per l’analisi lineare e per l’analisi agli autovalori nel codice KASP (Koiter
Analysis of Slender Panels) che effettua l’analisi asintototica di strutture a pannelli e di un
94
codice per l’analisi nonlineare di strutture costituite da travi 3D. Anche in questo contesto,
i test condotti su una serie di benchmark hanno mostrato lo stesso tipo di performance
ottenute nel caso di matrici generiche e non ottenute da formulazioni FEM, sia per quel che
riguarda i solutori di sistemi lineari, sia per il problema agli autovalori generalizzato. Si
può concludere quindi che questi strumenti possono, se correttamente utilizzati, fortemente
ottimizzare le prestazioni di codici FEM esistenti.
Si può concludere affermando che la moderna programmazione in ambito strutturale
non può prescindere da una più accurata conoscenza del calcolatore che si concretizza
nell’adozione di strumenti efficaci per la risoluzione di un dato problema.
95
Appendice A
L’utilizzo dell’analisi agli elementi finiti è basato sull’impiego dell’algebra dei vettori e
delle matrici poichè la rappresentazione matriciale permette di poter esprimere il processo
di soluzione in una notazione tanto compatta quanto elegante.
Da un punto di vista pratico l’algebra lineare può quindi essere considerata come uno
strumento efficace per manipolare in maniera pratica un gran numero di dati.
96
dove A è la matrice (mxn) dei coefficienti, x è il vettore delle n incognite e b è il vettore
degli m termini noti.
97
cui Ia dev’essere di lunghezza m + 1. Il terzo array, Ja, contiene l’indice della colonna di
ciascun elemento di A, quindi Ja è lungo N N Z.
Ad esempio, la matrice
1 2 0 0
0 3 9 0 (A.4)
0 1 4 0
è una matrice (3x4) con sei elementi diversi da zero, per cui
A= 1 2 3 9 1 4 (A.5)
Ia = 1 3 5 7 (A.6)
Ja = 1 2 2 3 2 3 (A.7)
Una matrice bandata è una matrice sparsa i cui elementi diversi da zero sono tutti
posti in una banda diagonale che comprende la diagonale principale e, opzionalmente, una
o più diagonali alla sua destra od alla sua sinistra.
Formalmente una matrice (n × n) A = (ai,j ) è una matrice a banda se tutti gli elementi
dalla matrice all’esterno di una striscia diagonale la cui ampiezza è determinata dalle
costanti k1 e k2 :
98
Per esempio, si consideri una matrice tridiagonale con banda pari a 3. La matrice 6x6:
B11 B12 0 ··· ··· 0
..
B21 B22 B23 . . . . . . .
..
0 B32 B33 B34 . . . .
(A.9)
.. . .
. . B43 B44 B45 0
.. .. ..
. . . B B 54 B 55 56
0 ··· ··· 0 B65 B66
99
Figura A.2: Matrice skyline
2
X
(A × B)12 = a1r br2 = a11 b12 + a12 b22 (A.15)
r=1
100
Una matrice con una sola riga, cioè di dimensione 1 × n, è un vettore riga. Analoga-
mente, una matrice con una sola colonna, cioè di dimensione m × 1 è un vettore colonna.
Nell’operazione di moltiplicazione questi due oggetti si comportano in modo differente.
Generalmente, per prodotto di una matrice per un vettore si intende il prodotto di
matrici Av, dove A è una matrice m × n e v è un vettore colonna n × 1. Il risultato di
questa operazione è un altro vettore colonna di dimensione m × 1.
101
Bibliografia
[6] Klaus-Jurgen Bathe. Finite Element Procedures. Klaus-Jurgen Bathe, February 2007.
[7] T. Davis. User Guide for CHOLMOD: a sparse Cholesky factorization and
modification package, 2008.
[9] Timothy A. Davis. Direct Methods for Sparse Linear Systems (Fundamentals of Al-
gorithms). Society for Industrial and Applied Mathematic, illustrated edition edition,
September 2006.
[10] Elizabeth D. Dolan and Jorge J. Moré. Benchmarking optimization software with
performance profiles. Mathematical Programming, 91(2):201–213, January 2002.
[11] I. Duff. The impact of high-performance computing in the solution of linear systems:
trends and problems. Journal of Computational and Applied Mathematics, 123(1-
2):515–530, November 2000.
[13] Kris Kaspersky. Code Optimization: Effective Memory Usage. A-List Publishing,
September 2003.
102
[14] Lie-Quan Lee and Andrew Lumsdaine. Generic programming for high-performance
scientific applications. Concurrency and Computation: Practice and Experience, 17(7-
8):941–965, 2005.
[15] Richard B. Lehoucq, Danny C. Sorensen, and C. Yang. Arpack User’s Guide: Solu-
tion of Large-Scale Eigenvalue Problems With Implicityly Restorted Arnoldi Methods
(Software, Environments, Tools). Soc for Industrial & Applied Math.
[16] Alfio Quarteroni, Riccardo Sacco, and Fausto Saleri. Numerical Mathematics (Texts
in Applied Mathematics). Springer, 2nd edition, November 2006.
[19] William von Hagen. The Definitive Guide to GCC, Second Edition. Apress, 2 edition,
August 2006.
[20] A. Willembohm. On the performance of pure and impure parallel functional programs.
Parallel Computing, 25(13-14):1723–1740, December 1999.
[21] Ralph Wiloughby. Lanczos Algorithms for Large Symmetric Eigenvalue Computations
Volume 1: Theory (Classics in Applied Mathematics). SIAM: Society for Industrial
and Applied Mathematics, 1st edition, September 2002.
103