-
Notifications
You must be signed in to change notification settings - Fork 0
/
jacobi.js
159 lines (153 loc) · 3.78 KB
/
jacobi.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// Rotation Matrix
var Rot = function(theta){
var Mat = [[Math.cos(theta),Math.sin(theta)],[-Math.sin(theta),Math.cos(theta)]];
return Mat
}
// Givens Matrix
var Rij = function(k,l,theta,N){
var Mat = Array(N)
for (var i = 0; i<N;i++){
Mat[i] = Array(N)
}
// Identity Matrix
for (var i = 0; i<N;i++){
for (var j = 0; j<N;j++){
Mat[i][j] = (i===j)*1.0;
}
}
var Rotij = Rot(theta);
// Put Rotation part in i, j
Mat[k][k] = Rotij[0][0] // 11
Mat[l][l] = Rotij[1][1] // 22
Mat[k][l] = Rotij[0][1] // 12
Mat[l][k] = Rotij[1][0] // 21
return Mat
}
// get angle
var getTheta = function(aii,ajj,aij){
var th = 0.0
var denom = (ajj - aii);
if (Math.abs(denom) <= 1E-12){
th = Math.PI/4.0
}
else {
th = 0.5 * Math.atan(2.0 * aij / (ajj - aii) )
}
return th
}
// get max off-diagonal value from Upper Diagonal
var getAij = function(Mij){
var N = Mij.length;
var maxMij = 0.0 ;
var maxIJ = [0,1];
for (var i = 0; i<N;i++){
for (var j = i+1; j<N;j++){
if (Math.abs(maxMij) <= Math.abs(Mij[i][j])){
maxMij = Math.abs(Mij[i][j]);
maxIJ = [i,j];
}
}
}
return [maxIJ,maxMij]
}
// Unitary Rotation UT x H x U
var unitary = function(U,H){
var N = U.length;
// empty NxN matrix
var Mat = Array(N)
for (var i = 0; i<N;i++){
Mat[i] = Array(N)
}
// compute element
for (var i = 0; i<N;i++){
for (var j = 0; j<N;j++){
Mat[i][j] = 0
for (var k = 0; k<N;k++){
for (var l = 0; l<N;l++){
Mat[i][j] = Mat[i][j] + U[k][i] * H[k][l] * U[l][j];
}
}
}
}
return Mat;
}
// Matrix Multiplication
var AxB = function(A,B){
var N = A.length;
// empty NxN matrix
var Mat = Array(N)
for (var i = 0; i<N;i++){
Mat[i] = Array(N)
}
for (var i = 0; i<N;i++){
for (var j = 0; j<N;j++){
Mat[i][j] = 0
for (var k = 0; k<N;k++){
Mat[i][j] = Mat[i][j] + A[i][k] * B[k][j] ;
}
}
}
return Mat;
}
var diag = function(Hij, convergence = 1E-7){
var N = Hij.length;
var Ei = Array(N);
var e0 = Math.abs(convergence / N)
// initial vector
var Sij = Array(N);
for (var i = 0; i<N;i++){
Sij[i] = Array(N)
}
// Sij is Identity Matrix
for (var i = 0; i<N;i++){
for (var j = 0; j<N;j++){
Sij[i][j] = (i===j)*1.0;
}
}
// initial error
var Vab = getAij(Hij);
// jacobi iterations
while (Math.abs(Vab[1]) >= Math.abs(e0)){
// block index to be rotated
var i = Vab[0][0];
var j = Vab[0][1];
// get theta
var psi = getTheta(Hij[i][i], Hij[j][j], Hij[i][j]);
// Givens matrix
var Gij = Rij(i,j,psi,N);
// rotate Hamiltonian using Givens
Hij = unitary(Gij,Hij);
// Update vectors
Sij = AxB(Sij,Gij);
// update error
Vab = getAij(Hij);
}
for (var i = 0; i<N;i++){
Ei[i] = Hij[i][i];
}
return sorting(Ei , Sij)
}
var sorting = function(E, S){
var N = E.length ;
var Ef = Array(N);
var Sf = Array(N);
for (var k = 0; k<N;k++){
Sf[k] = Array(N);
}
for (var i = 0; i<N;i++){
var minID = 0;
var minE = E[0];
for (var j = 0; j<E.length;j++){
if (E[j] < minE){
minID = j ;
minE = E[minID];
}
}
Ef[i] = E.splice(minID,1);
for (var k = 0; k<N;k++){
Sf[k][i] = S[k][minID];
S[k].splice(minID,1);
}
}
return [Ef,Sf]
}