realSymetric.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. import { clone } from '../../../utils/object.js';
  2. export function createRealSymmetric(_ref) {
  3. var {
  4. config,
  5. addScalar,
  6. subtract,
  7. abs,
  8. atan,
  9. cos,
  10. sin,
  11. multiplyScalar,
  12. inv,
  13. bignumber,
  14. multiply,
  15. add
  16. } = _ref;
  17. /**
  18. * @param {number[] | BigNumber[]} arr
  19. * @param {number} N
  20. * @param {number} prec
  21. * @param {'number' | 'BigNumber'} type
  22. */
  23. function main(arr, N) {
  24. var prec = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : config.epsilon;
  25. var type = arguments.length > 3 ? arguments[3] : undefined;
  26. if (type === 'number') {
  27. return diag(arr, prec);
  28. }
  29. if (type === 'BigNumber') {
  30. return diagBig(arr, prec);
  31. }
  32. throw TypeError('Unsupported data type: ' + type);
  33. }
  34. // diagonalization implementation for number (efficient)
  35. function diag(x, precision) {
  36. var N = x.length;
  37. var e0 = Math.abs(precision / N);
  38. var psi;
  39. var Sij = new Array(N);
  40. // Sij is Identity Matrix
  41. for (var i = 0; i < N; i++) {
  42. Sij[i] = createArray(N, 0);
  43. Sij[i][i] = 1.0;
  44. }
  45. // initial error
  46. var Vab = getAij(x);
  47. while (Math.abs(Vab[1]) >= Math.abs(e0)) {
  48. var _i = Vab[0][0];
  49. var j = Vab[0][1];
  50. psi = getTheta(x[_i][_i], x[j][j], x[_i][j]);
  51. x = x1(x, psi, _i, j);
  52. Sij = Sij1(Sij, psi, _i, j);
  53. Vab = getAij(x);
  54. }
  55. var Ei = createArray(N, 0); // eigenvalues
  56. for (var _i2 = 0; _i2 < N; _i2++) {
  57. Ei[_i2] = x[_i2][_i2];
  58. }
  59. return sorting(clone(Ei), clone(Sij));
  60. }
  61. // diagonalization implementation for bigNumber
  62. function diagBig(x, precision) {
  63. var N = x.length;
  64. var e0 = abs(precision / N);
  65. var psi;
  66. var Sij = new Array(N);
  67. // Sij is Identity Matrix
  68. for (var i = 0; i < N; i++) {
  69. Sij[i] = createArray(N, 0);
  70. Sij[i][i] = 1.0;
  71. }
  72. // initial error
  73. var Vab = getAijBig(x);
  74. while (abs(Vab[1]) >= abs(e0)) {
  75. var _i3 = Vab[0][0];
  76. var j = Vab[0][1];
  77. psi = getThetaBig(x[_i3][_i3], x[j][j], x[_i3][j]);
  78. x = x1Big(x, psi, _i3, j);
  79. Sij = Sij1Big(Sij, psi, _i3, j);
  80. Vab = getAijBig(x);
  81. }
  82. var Ei = createArray(N, 0); // eigenvalues
  83. for (var _i4 = 0; _i4 < N; _i4++) {
  84. Ei[_i4] = x[_i4][_i4];
  85. }
  86. // return [clone(Ei), clone(Sij)]
  87. return sorting(clone(Ei), clone(Sij));
  88. }
  89. // get angle
  90. function getTheta(aii, ajj, aij) {
  91. var denom = ajj - aii;
  92. if (Math.abs(denom) <= config.epsilon) {
  93. return Math.PI / 4.0;
  94. } else {
  95. return 0.5 * Math.atan(2.0 * aij / (ajj - aii));
  96. }
  97. }
  98. // get angle
  99. function getThetaBig(aii, ajj, aij) {
  100. var denom = subtract(ajj, aii);
  101. if (abs(denom) <= config.epsilon) {
  102. return bignumber(-1).acos().div(4);
  103. } else {
  104. return multiplyScalar(0.5, atan(multiply(2.0, aij, inv(denom))));
  105. }
  106. }
  107. // update eigvec
  108. function Sij1(Sij, theta, i, j) {
  109. var N = Sij.length;
  110. var c = Math.cos(theta);
  111. var s = Math.sin(theta);
  112. var Ski = createArray(N, 0);
  113. var Skj = createArray(N, 0);
  114. for (var k = 0; k < N; k++) {
  115. Ski[k] = c * Sij[k][i] - s * Sij[k][j];
  116. Skj[k] = s * Sij[k][i] + c * Sij[k][j];
  117. }
  118. for (var _k = 0; _k < N; _k++) {
  119. Sij[_k][i] = Ski[_k];
  120. Sij[_k][j] = Skj[_k];
  121. }
  122. return Sij;
  123. }
  124. // update eigvec for overlap
  125. function Sij1Big(Sij, theta, i, j) {
  126. var N = Sij.length;
  127. var c = cos(theta);
  128. var s = sin(theta);
  129. var Ski = createArray(N, bignumber(0));
  130. var Skj = createArray(N, bignumber(0));
  131. for (var k = 0; k < N; k++) {
  132. Ski[k] = subtract(multiplyScalar(c, Sij[k][i]), multiplyScalar(s, Sij[k][j]));
  133. Skj[k] = addScalar(multiplyScalar(s, Sij[k][i]), multiplyScalar(c, Sij[k][j]));
  134. }
  135. for (var _k2 = 0; _k2 < N; _k2++) {
  136. Sij[_k2][i] = Ski[_k2];
  137. Sij[_k2][j] = Skj[_k2];
  138. }
  139. return Sij;
  140. }
  141. // update matrix
  142. function x1Big(Hij, theta, i, j) {
  143. var N = Hij.length;
  144. var c = bignumber(cos(theta));
  145. var s = bignumber(sin(theta));
  146. var c2 = multiplyScalar(c, c);
  147. var s2 = multiplyScalar(s, s);
  148. var Aki = createArray(N, bignumber(0));
  149. var Akj = createArray(N, bignumber(0));
  150. // 2cs Hij
  151. var csHij = multiply(bignumber(2), c, s, Hij[i][j]);
  152. // Aii
  153. var Aii = addScalar(subtract(multiplyScalar(c2, Hij[i][i]), csHij), multiplyScalar(s2, Hij[j][j]));
  154. var Ajj = add(multiplyScalar(s2, Hij[i][i]), csHij, multiplyScalar(c2, Hij[j][j]));
  155. // 0 to i
  156. for (var k = 0; k < N; k++) {
  157. Aki[k] = subtract(multiplyScalar(c, Hij[i][k]), multiplyScalar(s, Hij[j][k]));
  158. Akj[k] = addScalar(multiplyScalar(s, Hij[i][k]), multiplyScalar(c, Hij[j][k]));
  159. }
  160. // Modify Hij
  161. Hij[i][i] = Aii;
  162. Hij[j][j] = Ajj;
  163. Hij[i][j] = bignumber(0);
  164. Hij[j][i] = bignumber(0);
  165. // 0 to i
  166. for (var _k3 = 0; _k3 < N; _k3++) {
  167. if (_k3 !== i && _k3 !== j) {
  168. Hij[i][_k3] = Aki[_k3];
  169. Hij[_k3][i] = Aki[_k3];
  170. Hij[j][_k3] = Akj[_k3];
  171. Hij[_k3][j] = Akj[_k3];
  172. }
  173. }
  174. return Hij;
  175. }
  176. // update matrix
  177. function x1(Hij, theta, i, j) {
  178. var N = Hij.length;
  179. var c = Math.cos(theta);
  180. var s = Math.sin(theta);
  181. var c2 = c * c;
  182. var s2 = s * s;
  183. var Aki = createArray(N, 0);
  184. var Akj = createArray(N, 0);
  185. // Aii
  186. var Aii = c2 * Hij[i][i] - 2 * c * s * Hij[i][j] + s2 * Hij[j][j];
  187. var Ajj = s2 * Hij[i][i] + 2 * c * s * Hij[i][j] + c2 * Hij[j][j];
  188. // 0 to i
  189. for (var k = 0; k < N; k++) {
  190. Aki[k] = c * Hij[i][k] - s * Hij[j][k];
  191. Akj[k] = s * Hij[i][k] + c * Hij[j][k];
  192. }
  193. // Modify Hij
  194. Hij[i][i] = Aii;
  195. Hij[j][j] = Ajj;
  196. Hij[i][j] = 0;
  197. Hij[j][i] = 0;
  198. // 0 to i
  199. for (var _k4 = 0; _k4 < N; _k4++) {
  200. if (_k4 !== i && _k4 !== j) {
  201. Hij[i][_k4] = Aki[_k4];
  202. Hij[_k4][i] = Aki[_k4];
  203. Hij[j][_k4] = Akj[_k4];
  204. Hij[_k4][j] = Akj[_k4];
  205. }
  206. }
  207. return Hij;
  208. }
  209. // get max off-diagonal value from Upper Diagonal
  210. function getAij(Mij) {
  211. var N = Mij.length;
  212. var maxMij = 0;
  213. var maxIJ = [0, 1];
  214. for (var i = 0; i < N; i++) {
  215. for (var j = i + 1; j < N; j++) {
  216. if (Math.abs(maxMij) < Math.abs(Mij[i][j])) {
  217. maxMij = Math.abs(Mij[i][j]);
  218. maxIJ = [i, j];
  219. }
  220. }
  221. }
  222. return [maxIJ, maxMij];
  223. }
  224. // get max off-diagonal value from Upper Diagonal
  225. function getAijBig(Mij) {
  226. var N = Mij.length;
  227. var maxMij = 0;
  228. var maxIJ = [0, 1];
  229. for (var i = 0; i < N; i++) {
  230. for (var j = i + 1; j < N; j++) {
  231. if (abs(maxMij) < abs(Mij[i][j])) {
  232. maxMij = abs(Mij[i][j]);
  233. maxIJ = [i, j];
  234. }
  235. }
  236. }
  237. return [maxIJ, maxMij];
  238. }
  239. // sort results
  240. function sorting(E, S) {
  241. var N = E.length;
  242. var values = Array(N);
  243. var vectors = Array(N);
  244. for (var k = 0; k < N; k++) {
  245. vectors[k] = Array(N);
  246. }
  247. for (var i = 0; i < N; i++) {
  248. var minID = 0;
  249. var minE = E[0];
  250. for (var j = 0; j < E.length; j++) {
  251. if (abs(E[j]) < abs(minE)) {
  252. minID = j;
  253. minE = E[minID];
  254. }
  255. }
  256. values[i] = E.splice(minID, 1)[0];
  257. for (var _k5 = 0; _k5 < N; _k5++) {
  258. vectors[_k5][i] = S[_k5][minID];
  259. S[_k5].splice(minID, 1);
  260. }
  261. }
  262. return {
  263. values,
  264. vectors
  265. };
  266. }
  267. /**
  268. * Create an array of a certain size and fill all items with an initial value
  269. * @param {number} size
  270. * @param {number} value
  271. * @return {number[]}
  272. */
  273. function createArray(size, value) {
  274. // TODO: as soon as all browsers support Array.fill, use that instead (IE doesn't support it)
  275. var array = new Array(size);
  276. for (var i = 0; i < size; i++) {
  277. array[i] = value;
  278. }
  279. return array;
  280. }
  281. return main;
  282. }