ifstream f[17];Allo stesso modo si possono definire delle matrici multidimensionali di qualunque tipo di oggetto:
TH1F istogramma[5][5];Siccome un vettore od una matrice sono strutture molto generali, il C++ non puo' prevedere su esse delle funzioni matematiche specifiche.
Tuttavia nei problemi di fisica spesso abbiamo a che fare con vettori e matrici con elementi numerici che operano secondo le regole dell'algebra lineare. In questi casi abbiamo a che fare con oggetti appartenenti ad una struttura matematica particolarmente ricca, contenente diverse operazioni, ad esempio il prodotto scalare di vettori o la moltiplicazione riga per colonna tipica delle matrici.
Per questo ha senso definire degli oggetti piu` complicati dei semplici vettori forniti dal C++: dei vettori numerici dotati della possibilita` di effettuare le operazioni matematiche che ci interessano. Nel nostro caso ROOT ci fornisce le classi:
Notate che la classe TMatrixD e' una classe derivata dalla classe TMatrixDBase, per cui puo` usare i metodi di tale classe. Ad esempio, il metodo UnitMatrix(), che inizializza la matrice ad essere una matrice diagonale unitaria, e' tra i metodi di TMatrixDBase e non di TMatrixD.
Per dichiarare un vettore si puo` usare un costruttore che ha come unico argomento un intero indicante la dimensione del vettore:
TVectorD x(3); // x e' un TVectorD di dimensione 3Si noti che il costruttore e' una funzione, che viene chiamata al momento dell'esecuzione del programma, e quindi ěl suo argomento puo` avere una dimensione variabile.
Ad esempio, il seguente frammento di codice si comporta come ci si aspetta:
int N; cout << "Inserisci la dimenzione del vettore" << endl; cin >> N; TVectorD vettore(N); // OK, il vettore e' dimensionato correttamentementre il seguente codice e' sbagliato, anche se un compilatore tollerante a volte lo permetta:
int N; cout << "Inserisci la dimenzione del vettore" << endl; cin >> N; double vettore[N]; // NO! Non si sa a cosa il vettore e' stato dimensionato
Per accedere alle componenti del vettore, si utilizza l'operatore () (parentesi tonde). Funziona anche l'operatore [] (parentesi quadre), ma per similitudine con le matrici che verranno dopo, e' meglio utilizzare le parentesi tonde. Un vettore puo` quindi venire inizializzato ad esempio con:
TVectorD x(3); x(0)=1.; x(1)=0.; x(2)=-1.;
Al momento della creazione, un vettore puo` anche essere inizializzato direttamente al valore di un altro vettore, sia usando un costruttore, che un'inizializzazione esplicita. I seguenti costrutti che inizializzano il nuovo vettore z ad avere lo stesso contenuto del vettore x definito in precedenza, sono del tutto equivalenti:
TVectorD z(x); TVectorD z=x;
Ora segue l'elenco di alcuni metodi utili:
int dim;
cout << "Inserisci la dimensione del triangolo da calcolare:" << endl;
cin >> dim;
TMatrixD triang(dim,dim); // matrice quadrata con lato pari a dim
triang(0,0)=1. // costruiamo la prima riga
for (int i=1; i<dim; i++) { // esemplificando l'accesso
triang[0][i]=0.; // agli elementi di matrice usando
} // sia l'operatore () che l'operatore []
for (int j=1; j<dim; j++) {
triang(j,0)=1.;
for (int i=1 ; i<=j ; i++) triang(j,i)=triang(j-1,i-1)+triang(j-1,i);
for (int i=j+1; i<dim; i++) triang(j,i)=0;
}
Infine, per verificare la struttura di una matrice sono a disposizione
i seguenti metodi:
Anche per le matrici si puo` effettuare l'inizializzazione come copia di un'altra matrice nel costruttore:
TMatrixD M(triang);e
TMatrixD M=triang;sono inizializzazioni equivalenti. I seguenti metodi invece alterano il contenuto della matrice, sostituendola con quella trasformata:
Come esempio di verifica del funzionamento delle operazioni di cui sopra, potete provare ad eseguire la seguente catena di operazioni e verificare che dia il risultato atteso:
TMatrixD A(3,3); A.UnitMatrix() A.Print() A(1,0)=0.5; A(2,2)=0.5; A.Print(); double det; A.Invert(&det); A.Print() cout << det << endl; A.T(); A.Print();
Supponiamo di aver definito le seguenti variabili:
TVector x(N), y(N); TMatrix A(M,N), B(I,M); double a;Allora:
Un esempio classico e' quello dell'oscillatore armonico smorzato, la cui
equazione:
puo` essere resa in forma matriciale come:
Se al sistema aggiungiamo una forzante esterna:
e lo mettiamo in forma matriciale:
possiamo identificarlo con l'equazione generale precedente
Un altro esempio e' il moto di una particella in un campo elettromagnetico
costante:
che puo` venire espressa nella forma:
Se la matrice A non fosse invertibile, questo significherebbe che il moto presenta una deriva (si considerino ad esempio le matrici corrispondenti al moto rettilineo uniforme o uniformement accelerato, ma anche quella della particella in campo elettromagnetico uniforme).
Il seguente frammento di codice effettua l'integrazione dell'equazione
dell'oscillatore armonico smorzato, per un tempo di 10 secondi e valori di
dt di 0.01 s e stampa un grafico della traiettoria nello spazio delle
fasi (x,v):
double a, w, F;
cout << "inserisci il valore di omega: ";
cin >> w;
cout << "inserisci il valore dello smorzamento: ";
cin >> a;
cout << "inserisci il valore della forzante: ";
cin >> F;
TMatrixD A(2,2);
A.Zero(); // Azzera la matrice
A(0,1)=1.; // inizializza la matrice A
A(1,0)=-w*w;
A(1,1)=-a;
TVectorD b(2);
b(0)=0.; // inizializza il vettore b
b(1)=F;
TVectorD x(2); // condizioni iniziali:
x(0)=1.; // il punto e` a distanza 1 dall'origine
x(1)=0.; // ed a velocita` nulla
TGraph traiettoria; // grafico dove mettere la traiettoria
traiettoria.SetPoint(0,x(0),x(1)); // primo punto: condizioni iniziali
double dt=0.001, tmax=10.;
int nstep=tmax/dt;
for (int i=1; i<=nstep; i++) {
TVectorD h(x);
h*=A; // h=Ax
h+=b; // h=Ax+b
h*=dt; // h=(Ax+b)*dt
x+=h; // x(t+dt)=x(t)+(Ax+b)*dt
traiettoria.SetPoint(i,x(0),x(1));
}
traiettoria.Draw("ALX");
Il problema grosso del metodo di Eulero e' che l'approssimazione al primo
ordine non e' molto buona e bisogna trovare un buon compromesso tra la
precisione ottenibile ed il passo di integrazione.
Negli esercizio che seguono, provate ad aumentare il tempo di integrazione
su di una soluzione nota per provare a vedere quanto varia con il tempo
l'errore di integrazione.
In particolare, provate tracciare le traiettorie nel piano (x,y) in alcuni casi particolari: