UNPKG

5.9 kBJavaScriptView Raw
1import { isMatrix } from '../../utils/is';
2import { arraySize } from '../../utils/array';
3import { factory } from '../../utils/factory';
4import { format } from '../../utils/string';
5var name = 'inv';
6var dependencies = ['typed', 'matrix', 'divideScalar', 'addScalar', 'multiply', 'unaryMinus', 'det', 'identity', 'abs'];
7export var createInv = /* #__PURE__ */factory(name, dependencies, function (_ref) {
8 var typed = _ref.typed,
9 matrix = _ref.matrix,
10 divideScalar = _ref.divideScalar,
11 addScalar = _ref.addScalar,
12 multiply = _ref.multiply,
13 unaryMinus = _ref.unaryMinus,
14 det = _ref.det,
15 identity = _ref.identity,
16 abs = _ref.abs;
17
18 /**
19 * Calculate the inverse of a square matrix.
20 *
21 * Syntax:
22 *
23 * math.inv(x)
24 *
25 * Examples:
26 *
27 * math.inv([[1, 2], [3, 4]]) // returns [[-2, 1], [1.5, -0.5]]
28 * math.inv(4) // returns 0.25
29 * 1 / 4 // returns 0.25
30 *
31 * See also:
32 *
33 * det, transpose
34 *
35 * @param {number | Complex | Array | Matrix} x Matrix to be inversed
36 * @return {number | Complex | Array | Matrix} The inverse of `x`.
37 */
38 return typed(name, {
39 'Array | Matrix': function ArrayMatrix(x) {
40 var size = isMatrix(x) ? x.size() : arraySize(x);
41
42 switch (size.length) {
43 case 1:
44 // vector
45 if (size[0] === 1) {
46 if (isMatrix(x)) {
47 return matrix([divideScalar(1, x.valueOf()[0])]);
48 } else {
49 return [divideScalar(1, x[0])];
50 }
51 } else {
52 throw new RangeError('Matrix must be square ' + '(size: ' + format(size) + ')');
53 }
54
55 case 2:
56 // two dimensional array
57 {
58 var rows = size[0];
59 var cols = size[1];
60
61 if (rows === cols) {
62 if (isMatrix(x)) {
63 return matrix(_inv(x.valueOf(), rows, cols), x.storage());
64 } else {
65 // return an Array
66 return _inv(x, rows, cols);
67 }
68 } else {
69 throw new RangeError('Matrix must be square ' + '(size: ' + format(size) + ')');
70 }
71 }
72
73 default:
74 // multi dimensional array
75 throw new RangeError('Matrix must be two dimensional ' + '(size: ' + format(size) + ')');
76 }
77 },
78 any: function any(x) {
79 // scalar
80 return divideScalar(1, x); // FIXME: create a BigNumber one when configured for bignumbers
81 }
82 });
83 /**
84 * Calculate the inverse of a square matrix
85 * @param {Array[]} mat A square matrix
86 * @param {number} rows Number of rows
87 * @param {number} cols Number of columns, must equal rows
88 * @return {Array[]} inv Inverse matrix
89 * @private
90 */
91
92 function _inv(mat, rows, cols) {
93 var r, s, f, value, temp;
94
95 if (rows === 1) {
96 // this is a 1 x 1 matrix
97 value = mat[0][0];
98
99 if (value === 0) {
100 throw Error('Cannot calculate inverse, determinant is zero');
101 }
102
103 return [[divideScalar(1, value)]];
104 } else if (rows === 2) {
105 // this is a 2 x 2 matrix
106 var d = det(mat);
107
108 if (d === 0) {
109 throw Error('Cannot calculate inverse, determinant is zero');
110 }
111
112 return [[divideScalar(mat[1][1], d), divideScalar(unaryMinus(mat[0][1]), d)], [divideScalar(unaryMinus(mat[1][0]), d), divideScalar(mat[0][0], d)]];
113 } else {
114 // this is a matrix of 3 x 3 or larger
115 // calculate inverse using gauss-jordan elimination
116 // https://en.wikipedia.org/wiki/Gaussian_elimination
117 // http://mathworld.wolfram.com/MatrixInverse.html
118 // http://math.uww.edu/~mcfarlat/inverse.htm
119 // make a copy of the matrix (only the arrays, not of the elements)
120 var A = mat.concat();
121
122 for (r = 0; r < rows; r++) {
123 A[r] = A[r].concat();
124 } // create an identity matrix which in the end will contain the
125 // matrix inverse
126
127
128 var B = identity(rows).valueOf(); // loop over all columns, and perform row reductions
129
130 for (var c = 0; c < cols; c++) {
131 // Pivoting: Swap row c with row r, where row r contains the largest element A[r][c]
132 var ABig = abs(A[c][c]);
133 var rBig = c;
134 r = c + 1;
135
136 while (r < rows) {
137 if (abs(A[r][c]) > ABig) {
138 ABig = abs(A[r][c]);
139 rBig = r;
140 }
141
142 r++;
143 }
144
145 if (ABig === 0) {
146 throw Error('Cannot calculate inverse, determinant is zero');
147 }
148
149 r = rBig;
150
151 if (r !== c) {
152 temp = A[c];
153 A[c] = A[r];
154 A[r] = temp;
155 temp = B[c];
156 B[c] = B[r];
157 B[r] = temp;
158 } // eliminate non-zero values on the other rows at column c
159
160
161 var Ac = A[c];
162 var Bc = B[c];
163
164 for (r = 0; r < rows; r++) {
165 var Ar = A[r];
166 var Br = B[r];
167
168 if (r !== c) {
169 // eliminate value at column c and row r
170 if (Ar[c] !== 0) {
171 f = divideScalar(unaryMinus(Ar[c]), Ac[c]); // add (f * row c) to row r to eliminate the value
172 // at column c
173
174 for (s = c; s < cols; s++) {
175 Ar[s] = addScalar(Ar[s], multiply(f, Ac[s]));
176 }
177
178 for (s = 0; s < cols; s++) {
179 Br[s] = addScalar(Br[s], multiply(f, Bc[s]));
180 }
181 }
182 } else {
183 // normalize value at Acc to 1,
184 // divide each value on row r with the value at Acc
185 f = Ac[c];
186
187 for (s = c; s < cols; s++) {
188 Ar[s] = divideScalar(Ar[s], f);
189 }
190
191 for (s = 0; s < cols; s++) {
192 Br[s] = divideScalar(Br[s], f);
193 }
194 }
195 }
196 }
197
198 return B;
199 }
200 }
201});
\No newline at end of file