lup.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.createLup = void 0;
  6. var _object = require("../../../utils/object.js");
  7. var _factory = require("../../../utils/factory.js");
  8. var name = 'lup';
  9. var dependencies = ['typed', 'matrix', 'abs', 'addScalar', 'divideScalar', 'multiplyScalar', 'subtract', 'larger', 'equalScalar', 'unaryMinus', 'DenseMatrix', 'SparseMatrix', 'Spa'];
  10. var createLup = /* #__PURE__ */(0, _factory.factory)(name, dependencies, function (_ref) {
  11. var typed = _ref.typed,
  12. matrix = _ref.matrix,
  13. abs = _ref.abs,
  14. addScalar = _ref.addScalar,
  15. divideScalar = _ref.divideScalar,
  16. multiplyScalar = _ref.multiplyScalar,
  17. subtract = _ref.subtract,
  18. larger = _ref.larger,
  19. equalScalar = _ref.equalScalar,
  20. unaryMinus = _ref.unaryMinus,
  21. DenseMatrix = _ref.DenseMatrix,
  22. SparseMatrix = _ref.SparseMatrix,
  23. Spa = _ref.Spa;
  24. /**
  25. * Calculate the Matrix LU decomposition with partial pivoting. Matrix `A` is decomposed in two matrices (`L`, `U`) and a
  26. * row permutation vector `p` where `A[p,:] = L * U`
  27. *
  28. * Syntax:
  29. *
  30. * math.lup(A)
  31. *
  32. * Example:
  33. *
  34. * const m = [[2, 1], [1, 4]]
  35. * const r = math.lup(m)
  36. * // r = {
  37. * // L: [[1, 0], [0.5, 1]],
  38. * // U: [[2, 1], [0, 3.5]],
  39. * // P: [0, 1]
  40. * // }
  41. *
  42. * See also:
  43. *
  44. * slu, lsolve, lusolve, usolve
  45. *
  46. * @param {Matrix | Array} A A two dimensional matrix or array for which to get the LUP decomposition.
  47. *
  48. * @return {{L: Array | Matrix, U: Array | Matrix, P: Array.<number>}} The lower triangular matrix, the upper triangular matrix and the permutation matrix.
  49. */
  50. return typed(name, {
  51. DenseMatrix: function DenseMatrix(m) {
  52. return _denseLUP(m);
  53. },
  54. SparseMatrix: function SparseMatrix(m) {
  55. return _sparseLUP(m);
  56. },
  57. Array: function Array(a) {
  58. // create dense matrix from array
  59. var m = matrix(a);
  60. // lup, use matrix implementation
  61. var r = _denseLUP(m);
  62. // result
  63. return {
  64. L: r.L.valueOf(),
  65. U: r.U.valueOf(),
  66. p: r.p
  67. };
  68. }
  69. });
  70. function _denseLUP(m) {
  71. // rows & columns
  72. var rows = m._size[0];
  73. var columns = m._size[1];
  74. // minimum rows and columns
  75. var n = Math.min(rows, columns);
  76. // matrix array, clone original data
  77. var data = (0, _object.clone)(m._data);
  78. // l matrix arrays
  79. var ldata = [];
  80. var lsize = [rows, n];
  81. // u matrix arrays
  82. var udata = [];
  83. var usize = [n, columns];
  84. // vars
  85. var i, j, k;
  86. // permutation vector
  87. var p = [];
  88. for (i = 0; i < rows; i++) {
  89. p[i] = i;
  90. }
  91. // loop columns
  92. for (j = 0; j < columns; j++) {
  93. // skip first column in upper triangular matrix
  94. if (j > 0) {
  95. // loop rows
  96. for (i = 0; i < rows; i++) {
  97. // min i,j
  98. var min = Math.min(i, j);
  99. // v[i, j]
  100. var s = 0;
  101. // loop up to min
  102. for (k = 0; k < min; k++) {
  103. // s = l[i, k] - data[k, j]
  104. s = addScalar(s, multiplyScalar(data[i][k], data[k][j]));
  105. }
  106. data[i][j] = subtract(data[i][j], s);
  107. }
  108. }
  109. // row with larger value in cvector, row >= j
  110. var pi = j;
  111. var pabsv = 0;
  112. var vjj = 0;
  113. // loop rows
  114. for (i = j; i < rows; i++) {
  115. // data @ i, j
  116. var v = data[i][j];
  117. // absolute value
  118. var absv = abs(v);
  119. // value is greater than pivote value
  120. if (larger(absv, pabsv)) {
  121. // store row
  122. pi = i;
  123. // update max value
  124. pabsv = absv;
  125. // value @ [j, j]
  126. vjj = v;
  127. }
  128. }
  129. // swap rows (j <-> pi)
  130. if (j !== pi) {
  131. // swap values j <-> pi in p
  132. p[j] = [p[pi], p[pi] = p[j]][0];
  133. // swap j <-> pi in data
  134. DenseMatrix._swapRows(j, pi, data);
  135. }
  136. // check column is in lower triangular matrix
  137. if (j < rows) {
  138. // loop rows (lower triangular matrix)
  139. for (i = j + 1; i < rows; i++) {
  140. // value @ i, j
  141. var vij = data[i][j];
  142. if (!equalScalar(vij, 0)) {
  143. // update data
  144. data[i][j] = divideScalar(data[i][j], vjj);
  145. }
  146. }
  147. }
  148. }
  149. // loop columns
  150. for (j = 0; j < columns; j++) {
  151. // loop rows
  152. for (i = 0; i < rows; i++) {
  153. // initialize row in arrays
  154. if (j === 0) {
  155. // check row exists in upper triangular matrix
  156. if (i < columns) {
  157. // U
  158. udata[i] = [];
  159. }
  160. // L
  161. ldata[i] = [];
  162. }
  163. // check we are in the upper triangular matrix
  164. if (i < j) {
  165. // check row exists in upper triangular matrix
  166. if (i < columns) {
  167. // U
  168. udata[i][j] = data[i][j];
  169. }
  170. // check column exists in lower triangular matrix
  171. if (j < rows) {
  172. // L
  173. ldata[i][j] = 0;
  174. }
  175. continue;
  176. }
  177. // diagonal value
  178. if (i === j) {
  179. // check row exists in upper triangular matrix
  180. if (i < columns) {
  181. // U
  182. udata[i][j] = data[i][j];
  183. }
  184. // check column exists in lower triangular matrix
  185. if (j < rows) {
  186. // L
  187. ldata[i][j] = 1;
  188. }
  189. continue;
  190. }
  191. // check row exists in upper triangular matrix
  192. if (i < columns) {
  193. // U
  194. udata[i][j] = 0;
  195. }
  196. // check column exists in lower triangular matrix
  197. if (j < rows) {
  198. // L
  199. ldata[i][j] = data[i][j];
  200. }
  201. }
  202. }
  203. // l matrix
  204. var l = new DenseMatrix({
  205. data: ldata,
  206. size: lsize
  207. });
  208. // u matrix
  209. var u = new DenseMatrix({
  210. data: udata,
  211. size: usize
  212. });
  213. // p vector
  214. var pv = [];
  215. for (i = 0, n = p.length; i < n; i++) {
  216. pv[p[i]] = i;
  217. }
  218. // return matrices
  219. return {
  220. L: l,
  221. U: u,
  222. p: pv,
  223. toString: function toString() {
  224. return 'L: ' + this.L.toString() + '\nU: ' + this.U.toString() + '\nP: ' + this.p;
  225. }
  226. };
  227. }
  228. function _sparseLUP(m) {
  229. // rows & columns
  230. var rows = m._size[0];
  231. var columns = m._size[1];
  232. // minimum rows and columns
  233. var n = Math.min(rows, columns);
  234. // matrix arrays (will not be modified, thanks to permutation vector)
  235. var values = m._values;
  236. var index = m._index;
  237. var ptr = m._ptr;
  238. // l matrix arrays
  239. var lvalues = [];
  240. var lindex = [];
  241. var lptr = [];
  242. var lsize = [rows, n];
  243. // u matrix arrays
  244. var uvalues = [];
  245. var uindex = [];
  246. var uptr = [];
  247. var usize = [n, columns];
  248. // vars
  249. var i, j, k;
  250. // permutation vectors, (current index -> original index) and (original index -> current index)
  251. var pvCo = [];
  252. var pvOc = [];
  253. for (i = 0; i < rows; i++) {
  254. pvCo[i] = i;
  255. pvOc[i] = i;
  256. }
  257. // swap indices in permutation vectors (condition x < y)!
  258. var swapIndeces = function swapIndeces(x, y) {
  259. // find pv indeces getting data from x and y
  260. var kx = pvOc[x];
  261. var ky = pvOc[y];
  262. // update permutation vector current -> original
  263. pvCo[kx] = y;
  264. pvCo[ky] = x;
  265. // update permutation vector original -> current
  266. pvOc[x] = ky;
  267. pvOc[y] = kx;
  268. };
  269. // loop columns
  270. var _loop = function _loop() {
  271. // sparse accumulator
  272. var spa = new Spa();
  273. // check lower triangular matrix has a value @ column j
  274. if (j < rows) {
  275. // update ptr
  276. lptr.push(lvalues.length);
  277. // first value in j column for lower triangular matrix
  278. lvalues.push(1);
  279. lindex.push(j);
  280. }
  281. // update ptr
  282. uptr.push(uvalues.length);
  283. // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1]
  284. var k0 = ptr[j];
  285. var k1 = ptr[j + 1];
  286. // copy column j into sparse accumulator
  287. for (k = k0; k < k1; k++) {
  288. // row
  289. i = index[k];
  290. // copy column values into sparse accumulator (use permutation vector)
  291. spa.set(pvCo[i], values[k]);
  292. }
  293. // skip first column in upper triangular matrix
  294. if (j > 0) {
  295. // loop rows in column j (above diagonal)
  296. spa.forEach(0, j - 1, function (k, vkj) {
  297. // loop rows in column k (L)
  298. SparseMatrix._forEachRow(k, lvalues, lindex, lptr, function (i, vik) {
  299. // check row is below k
  300. if (i > k) {
  301. // update spa value
  302. spa.accumulate(i, unaryMinus(multiplyScalar(vik, vkj)));
  303. }
  304. });
  305. });
  306. }
  307. // row with larger value in spa, row >= j
  308. var pi = j;
  309. var vjj = spa.get(j);
  310. var pabsv = abs(vjj);
  311. // loop values in spa (order by row, below diagonal)
  312. spa.forEach(j + 1, rows - 1, function (x, v) {
  313. // absolute value
  314. var absv = abs(v);
  315. // value is greater than pivote value
  316. if (larger(absv, pabsv)) {
  317. // store row
  318. pi = x;
  319. // update max value
  320. pabsv = absv;
  321. // value @ [j, j]
  322. vjj = v;
  323. }
  324. });
  325. // swap rows (j <-> pi)
  326. if (j !== pi) {
  327. // swap values j <-> pi in L
  328. SparseMatrix._swapRows(j, pi, lsize[1], lvalues, lindex, lptr);
  329. // swap values j <-> pi in U
  330. SparseMatrix._swapRows(j, pi, usize[1], uvalues, uindex, uptr);
  331. // swap values in spa
  332. spa.swap(j, pi);
  333. // update permutation vector (swap values @ j, pi)
  334. swapIndeces(j, pi);
  335. }
  336. // loop values in spa (order by row)
  337. spa.forEach(0, rows - 1, function (x, v) {
  338. // check we are above diagonal
  339. if (x <= j) {
  340. // update upper triangular matrix
  341. uvalues.push(v);
  342. uindex.push(x);
  343. } else {
  344. // update value
  345. v = divideScalar(v, vjj);
  346. // check value is non zero
  347. if (!equalScalar(v, 0)) {
  348. // update lower triangular matrix
  349. lvalues.push(v);
  350. lindex.push(x);
  351. }
  352. }
  353. });
  354. };
  355. for (j = 0; j < columns; j++) {
  356. _loop();
  357. }
  358. // update ptrs
  359. uptr.push(uvalues.length);
  360. lptr.push(lvalues.length);
  361. // return matrices
  362. return {
  363. L: new SparseMatrix({
  364. values: lvalues,
  365. index: lindex,
  366. ptr: lptr,
  367. size: lsize
  368. }),
  369. U: new SparseMatrix({
  370. values: uvalues,
  371. index: uindex,
  372. ptr: uptr,
  373. size: usize
  374. }),
  375. p: pvCo,
  376. toString: function toString() {
  377. return 'L: ' + this.L.toString() + '\nU: ' + this.U.toString() + '\nP: ' + this.p;
  378. }
  379. };
  380. }
  381. });
  382. exports.createLup = createLup;