┌ │ │ │ │ │ │ │ │ │ │ │ │ │ └ |
V6/f8 | V7/f8 | V8/f8 | V1/f8 | V2/f8 | V3/f8 | V4/f8 | V5/f8 | ┐ │ │ │ │ │ │ │ │ │ │ │ │ │ ┘ |
0 | 0 | 0 | V1/f1 | q1/q2 | 0 | 0 | 0 | ||
0 | 0 | 0 | V1/f2 | V2/f2 | q2/q3 | 0 | 0 | ||
0 | 0 | 0 | V1/f3 | V2/f3 | V3/f3 | q3/q4 | 0 | ||
0 | 0 | 0 | V1/f4 | V2/f4 | V3/f4 | V4/f4 | q4/q5 | ||
q5/q6 | 0 | 0 | V1/f5 | V2/f5 | V3/f5 | V4/f5 | V5/f5 | ||
V6/f6 | q6/q7 | 0 | V1/f6 | V2/f6 | V3/f6 | V4/f6 | V5/f6 | ||
V6/f7 | V7/f7 | q7/q8 | V1/f7 | V2/f7 | V3/f7 | V4/f7 | V5/f7 |
Questa funzione calcola sia la matrice ortogonale sia i dati necessari per fare il prodotto della matrice ortogonale per un vettore qualsiasi in modo veloce ossia non facendo tante moltiplicazioni quanto il quadrato dell'ordine della matrice ma solo il triplo dell'ordine.
var fuma=function(Vt){ var j,k,kn=0,uma=[[0]],uni=[[0]]; var Q=[0],Qb=[0],Vq=0,Yn=-1; var uso=[[0],[0],[0]],V=[],nord=Vt.length; for(j=0;nord>j;j++){V[0]=Math.abs(Vt[j]); if(V[0]>Yn){kn=j;Yn=V[0]}} for(j=kn;nord>j;j++)V[j-kn]=Vt[j]; for(j=0;kn>j;j++)V[nord-kn+j]=Vt[j]; for(j=0;nord>j;j++){Vq+=V[j]*V[j]; Q[j]=Math.sqrt(Vq); uma[j]=[0]; for(k=0;nord>k;k++)uma[j][k]=0; uso[0][j]=V[j];} Yn=1/Q[nord-1]; uso[1][0]=Yn; uso[2][0]=kn; for(k=0;nord>k;k++)uma[0][k]=Yn*V[k]; for(j=1;nord>j;j++){uma[j][j]=Q[j-1]/Q[j]; uso[2][j]=uma[j][j]; Yn=-V[j]/(Q[j-1]*Q[j]); uso[1][j]=Yn; for(k=0;j>k;k++)uma[j][k]=Yn*V[k];} for(k=0;nord>k;k++){uni[k]=[]; for(j=0;kn>j;j++)uni[k][j]=uma[k][nord-kn+j]; for(j=kn;nord>j;j++)uni[k][j]=uma[k][j-kn];} return [uni,uso]; }In pratica basta calcolare solo i dati da usare per fare velocemente il prodotto della matrice ortogonale con un qualsiasi vettore. Qui calcola solo i dati necessari ( un triplice vettore ).
var fuso=function(Vt){ var j,kn=0,Q=[0],Vm,Vq=0,Yn=-1; var uso=[[0],[0],[0]],nord=Vt.length; for(j=0;nord>j;j++){uso[0][j]=0; Vm=Math.abs(Vt[j]); if(Vm>Yn){kn=j;Yn=Vm}} for(j=kn;nord>j;j++)uso[0][j-kn]=Vt[j]; for(j=0;kn>j;j++)uso[0][nord-kn+j]=Vt[j]; for(j=0;nord>j;j++){Vq+=uso[0][j]*uso[0][j]; Q[j]=Math.sqrt(Vq);} uso[1][0]=1/Q[nord-1]; uso[2][0]=kn; for(j=1;nord>j;j++){ uso[2][j]=Q[j-1]/Q[j]; uso[1][j]=-uso[0][j]/(Q[j-1]*Q[j]);} return uso; }Qui invece usa i dati precalcolati per fare velocemente il prodotto della matrice ortogonale per un qualsiasi vettore.
var fusa=function(uso,Vt){ var j,kn,S=0,R=[0],V=[0],n=Vt.length; kn=uso[2][0]; for(j=kn;n>j;j++)V[j-kn]=Vt[j]; for(j=0;kn>j;j++)V[n-kn+j]=Vt[j]; S=uso[0][0]*V[0] for(j=1;n>j;j++){ R[j]=S*uso[1][j]+V[j]*uso[2][j]; S+=uso[0][j]*V[j]} R[0]=S*uso[1][0]; return R;}Ecco l'applicazione pratica della matrice ortogonale : Fattorizza la generica matrice mat con le matrici unitarie producendo come risultato una triangolare superiore mn e l'insieme delle matrice unitarie da usare ossia uso.
var risol=function(mat){ var j,k,v,uso=[],mn=[[]],n=mat.length; var fus=function(Vt){ var j,kn=0,Q=[0],Vm,Vq=0,Yn=-1; var uso=[[0],[0],[0]],nord=Vt.length; for(j=0;nord>j;j++){uso[0][j]=0; Vm=Math.abs(Vt[j]); if(Vm>Yn){kn=j;Yn=Vm}} for(j=kn;nord>j;j++)uso[0][j-kn]=Vt[j]; for(j=0;kn>j;j++)uso[0][nord-kn+j]=Vt[j]; for(j=0;nord>j;j++){Vq+=uso[0][j]*uso[0][j]; Q[j]=Math.sqrt(Vq);} uso[1][0]=1/Q[nord-1]; uso[2][0]=kn; for(j=1;nord>j;j++){ uso[2][j]=Q[j-1]/Q[j]; uso[1][j]=-uso[0][j]/(Q[j-1]*Q[j]);} return uso;}; var fua=function(uso,Vt){ var j,kn,S=0,R=[0],V=[0],n=Vt.length; kn=uso[2][0]; for(j=kn;n>j;j++)V[j-kn]=Vt[j]; for(j=0;kn>j;j++)V[n-kn+j]=Vt[j]; S=uso[0][0]*V[0] for(j=1;n>j;j++){ R[j]=S*uso[1][j]+V[j]*uso[2][j]; S+=uso[0][j]*V[j]} R[0]=S*uso[1][0]; return R;}; for(j=0;n>j;j++){ mn[j]=[mat[j][0]]; for(k=1;n>k;k++)mn[j][k]=mat[j][k];} for(j=0;n>j;j++){ v=[]; for(k=j;n>k;k++)v[k-j]=mn[k][j]; uso[j]=fus(v); for(h=j;n>h;h++){ v=[]; for(k=j;n>k;k++)v[k-j]=mn[k][h]; vu=fua(uso[j],v); for(k=j;n>k;k++)mn[k][h]=vu[k-j];} } return [mn,uso];}Fattorizzata, con la precedente funzione risol, la matrice mat che ora chiamo mfa, la si può usare per trovare la soluzione del sistema lineare, usando il termine noto vt.
var usolu=function(mfa,vt){ var j,k,tn,x,v,vu,vs=[0],n=vt.length; var sup=function(mup,vt){ var j,k,tn,x,vs=[0],n=mup.length; for(j=0;n>j;j++)vs[j]=vt[j]; for(j=n-1;j>=0;j+=-1){ tn=vs[j]; x=tn/mup[j][j]; for(k=0;j>k;k++)vs[k]+=-x*mup[k][j]; vs[j]=x;} return vs;}; var fua=function(uso,Vt){ var j,kn,S=0,R=[0],V=[0],n=Vt.length; kn=uso[2][0]; for(j=kn;n>j;j++)V[j-kn]=Vt[j]; for(j=0;kn>j;j++)V[n-kn+j]=Vt[j]; S=uso[0][0]*V[0] for(j=1;n>j;j++){ R[j]=S*uso[1][j]+V[j]*uso[2][j]; S+=uso[0][j]*V[j]} R[0]=S*uso[1][0]; return R;}; for(j=0;n>j;j++)vs[j]=vt[j]; for(j=0;n>j;j++){ v=[]; for(k=j;n>k;k++)v[k-j]=vs[k]; vu=fua(mfa[1][j],v); for(k=j;n>k;k++)vs[k]=vu[k-j]; } v=sup(mfa[0],vs); return v; }Trascrivo qui anche alcune funzioni di servizio usabili per fare varie cose, come stampare bene una matrice o fare la matrice trasposta, il prodotto matrice per vettore e il prodotto matrice per matrice etc...
var stamat=function(mat){ var j,k,sp,ss="[",xbr="\u003cbr/\u003e"; for(j=0;mat.length>j;j++){ ss+=xbr+"["; for(k=0;mat.length>k;k++){ if(1e-8>Math.abs(mat[j][k])){sp=" 0.0";} else{sp=" "+mat[j][k];} if(sp.length>10)sp=sp.substr(0,10); if(mat.length-1>k)ss+=sp+"," else{ss+=sp}} ss+="]"; } return ss+"]"; } // var trasp=function(mat){ var j,k,mtr=[[0]]; for(j=0;mat.length>j;j++){ mtr[j]=[mat[0][j]]; for(k=1;mat.length>k;k++)mtr[j][k]=mat[k][j]; } return mtr; } // var matvet=function(ma,vet){ var j,h,to,vr=[0]; for(j=0;ma.length>j;j++){ to=0; for(h=0;ma.length>h;h++)to+=ma[j][h]*vet[h]; vr[j]=to; } return vr; } // var matmul=function(ma,mb){ var j,k,h,to,mr=[[0]]; for(j=0;ma.length>j;j++){ mr[j]=[0]; for(k=0;ma.length>k;k++){ to=0; for(h=0;ma.length>h;h++)to+=ma[j][h]*mb[h][k]; mr[j][k]=to; } } return mr; } // var diffev=function(va,vb){ var j,vr=[0],n=va.length; for(j=0;n>j;j++)vr[j]=va[j]-vb[j]; return vr; } // var diffu=function(ua,ub){ var j,dd=0,n=ua.length; if(ub.length!=n)alert("Errore! dimensioni diverse "+n); for(j=0;n>j;j++){ dd+=Math.abs(ua[0][j]-ub[0][j])+ Math.abs(ua[1][j]-ub[1][j])+ Math.abs(ua[2][j]-ub[2][j]); } return dd; }
...Attivare Javascript per vedere i calcoli!...
- Una precedente libreria: http://www.elegio.it/doc/tridia/sorgenti/alin-20130106.html
- http://www.elegio.it/omnia/ht/
- http://www.elegio.it/doc/tn/
- http://www.elegio.it/doc/tn/inversione-non-solo-con-la-lu.html dove LU significa decomposizione Lower-Upper : https://it.wikipedia.org/wiki/Decomposizione_LU
Anche se già l'ho messa in rete trascrivo qui questa agile, breve funzione che fa l'inversa in modo molto numericamente costoso ma questa funzione mi sembra utile per trovare la matrice inversa di una matrice di ordine piccolo...
Inversione fatta da una unica funzione // Calcolo della matrice inversa della matrice mat. // Come si vede e' un algoritmo molto compatto anche // se il numero delle operazioni da fare cresce molto // al crescere dell'ordine della matrice mat. // var fainv=function(mat){ var minore,xmino=function(mat,r,c){ var j,jn=0,k,kn,id=[],ord=mat.length; for(j=0;ord>j;j++){ if(j!=r){ kn=0; id[id.length]=[]; for(k=0;ord>k;k++){ if(k!=c){ id[jn][kn]=mat[j][k]; kn++;} } jn++;} }; return id; } var xdet=function(mat){ var j,ord=mat.length,pm=1,dd=0; if(ord==1){ dd=mat[0][0]; return dd;}; for(j=0;ord>j;j++){ mm=xmino(mat,0,j); dd+=pm*mat[0][j]*xdet(mm); pm=-pm;} return dd; } var j,k,m,d,id=[],ord=mat.length; d=1/xdet(mat); for(j=0;ord>j;j++){ m=d*(1-2*(j%2)); id[id.length]=[]; for(k=0;ord>k;k++){ minore=xmino(mat,k,j); id[j][k]=m*xdet(minore); m=-m;} } return id; }☺ Costosa ma elegante questa function, NO ??? ☺