simple-squiggle

A restricted subset of Squiggle
Log | Files | Refs | README

realSymetric.js (7832B)


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