-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patheigenvaluesJacobiMethod.js
147 lines (142 loc) · 3.81 KB
/
eigenvaluesJacobiMethod.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
// Jacobi Method for eigen values
// Reference to https://github.com/vuoriov4/jacobi-eigenvalue-algorithm-js/blob/master/src/index.js
import * as tf from "@tensorflow/tfjs";
const eigJacobi = (input, epsilon, iterations) => {
let n = input[0].length; // Size of the input matrix
const matrixReshape = tf.tensor(input);
const reshape = matrixReshape.reshape([n, n]);
input = reshape.arraySync();
let cloneInput = clone(input); // Clone of the input matrix as different variable
let eye = identity(n); // Create identity matrix from the size of input matrix
for (let i = 0; i < iterations; i++) {
let itr = iterate(eye, cloneInput, n);
eye = itr.eye;
cloneInput = itr.cloneInput;
if (iscloneInputiagonal(cloneInput, epsilon)) {
cloneInput = clean(cloneInput, epsilon);
eye = clean(eye, epsilon);
break;
}
}
return console.log("Eigen values are: ", [cloneInput]);
};
const iterate = (eye, cloneInput, n) => {
// find the indices of the largest off-diagonal element (in magnitude) from cloneInput
let di;
let dj;
for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {
if (i == j) continue;
if (
di === undefined ||
dj === undefined ||
Math.abs(cloneInput[i][j]) > Math.abs(cloneInput[di][dj])
) {
di = i;
dj = j;
}
}
}
// find the rotational angle
let angle;
if (cloneInput[di][di] === cloneInput[dj][dj]) {
if (cloneInput[di][dj] > 0) angle = Math.PI / 4;
else angle = -Math.PI / 4;
} else {
angle =
0.5 *
Math.atan(
(2 * cloneInput[di][dj]) / (cloneInput[di][di] - cloneInput[dj][dj])
);
}
// compute eye1
let eye1 = identity(n);
eye1[di][di] = Math.cos(angle);
eye1[dj][dj] = eye1[di][di];
eye1[di][dj] = -Math.sin(angle);
eye1[dj][di] = -eye1[di][dj];
// set new values
return {
eye: multiply(eye, eye1),
cloneInput: multiply(multiply(transpose(eye1), cloneInput), eye1),
};
};
const clean = (input, epsilon) => {
return tf.tidy(() => {
let n = input[0].length;
let result = clone(input);
for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {
if (tf.abs(tf.tensor(input[i][j])).arraySync() < epsilon)
result[i][j] = 0;
else result[i][j] = input[i][j];
}
}
return result;
});
};
const iscloneInputiagonal = (input, epsilon) => {
return tf.tidy(() => {
let n = input[0].length;
for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {
if (i == j) continue;
if (tf.abs(tf.tensor(input[i][j])).arraySync() > epsilon) return false;
}
}
return true;
});
};
const multiply = (A, B) => {
return tf.tidy(() => {
let n = A[0].length;
let result = identity(n);
for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {
let sum = 0;
for (let k = 0; k < n; k++) {
const a = tf.tensor(A[i][k]);
const b = tf.tensor(B[k][j]);
sum += tf.mul(a, b).arraySync();
}
result[i][j] = sum;
}
}
return result;
});
};
// Compute transpose of the input
const transpose = (input) => {
return tf.tidy(() => {
const c = tf.tensor(input);
let cln = c.transpose().arraySync();
return cln;
});
};
// Create a clone matrix of the input
const clone = (input) => {
return tf.tidy(() => {
const b = tf.tensor(input);
let result = b.clone().arraySync();
return result;
});
};
// Create identity matrix with the same size of the input matrix
const identity = (n) => {
return tf.tidy(() => {
let result = tf.eye(n, n).arraySync();
return result;
});
};
// eigJacobi(input, epsilon, iterations)
// Matrix should be symmetric
// Inputs should be array, number, number
eigJacobi(
[
[1, 4, 8],
[4, 1, 9],
[8, 9, 6],
],
0.000001,
100
);