1 | 'use strict'
|
2 |
|
3 | const util = require('../../utils/index')
|
4 |
|
5 | function factory (type, config, load, typed) {
|
6 | const matrix = load(require('../../type/matrix/function/matrix'))
|
7 | const divideScalar = load(require('../arithmetic/divideScalar'))
|
8 | const addScalar = load(require('../arithmetic/addScalar'))
|
9 | const multiply = load(require('../arithmetic/multiply'))
|
10 | const unaryMinus = load(require('../arithmetic/unaryMinus'))
|
11 | const det = load(require('../matrix/det'))
|
12 | const identity = load(require('./identity'))
|
13 | const abs = load(require('../arithmetic/abs'))
|
14 |
|
15 | |
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 | const inv = typed('inv', {
|
36 | 'Array | Matrix': function (x) {
|
37 | const size = type.isMatrix(x) ? x.size() : util.array.size(x)
|
38 | switch (size.length) {
|
39 | case 1:
|
40 |
|
41 | if (size[0] === 1) {
|
42 | if (type.isMatrix(x)) {
|
43 | return matrix([
|
44 | divideScalar(1, x.valueOf()[0])
|
45 | ])
|
46 | } else {
|
47 | return [
|
48 | divideScalar(1, x[0])
|
49 | ]
|
50 | }
|
51 | } else {
|
52 | throw new RangeError('Matrix must be square ' +
|
53 | '(size: ' + util.string.format(size) + ')')
|
54 | }
|
55 |
|
56 | case 2:
|
57 |
|
58 | const rows = size[0]
|
59 | const cols = size[1]
|
60 | if (rows === cols) {
|
61 | if (type.isMatrix(x)) {
|
62 | return matrix(
|
63 | _inv(x.valueOf(), rows, cols),
|
64 | x.storage()
|
65 | )
|
66 | } else {
|
67 |
|
68 | return _inv(x, rows, cols)
|
69 | }
|
70 | } else {
|
71 | throw new RangeError('Matrix must be square ' +
|
72 | '(size: ' + util.string.format(size) + ')')
|
73 | }
|
74 |
|
75 | default:
|
76 |
|
77 | throw new RangeError('Matrix must be two dimensional ' +
|
78 | '(size: ' + util.string.format(size) + ')')
|
79 | }
|
80 | },
|
81 |
|
82 | 'any': function (x) {
|
83 |
|
84 | return divideScalar(1, x)
|
85 | }
|
86 | })
|
87 |
|
88 | |
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 | function _inv (mat, rows, cols) {
|
97 | let r, s, f, value, temp
|
98 |
|
99 | if (rows === 1) {
|
100 |
|
101 | value = mat[0][0]
|
102 | if (value === 0) {
|
103 | throw Error('Cannot calculate inverse, determinant is zero')
|
104 | }
|
105 | return [[
|
106 | divideScalar(1, value)
|
107 | ]]
|
108 | } else if (rows === 2) {
|
109 |
|
110 | const d = det(mat)
|
111 | if (d === 0) {
|
112 | throw Error('Cannot calculate inverse, determinant is zero')
|
113 | }
|
114 | return [
|
115 | [
|
116 | divideScalar(mat[1][1], d),
|
117 | divideScalar(unaryMinus(mat[0][1]), d)
|
118 | ],
|
119 | [
|
120 | divideScalar(unaryMinus(mat[1][0]), d),
|
121 | divideScalar(mat[0][0], d)
|
122 | ]
|
123 | ]
|
124 | } else {
|
125 |
|
126 |
|
127 |
|
128 |
|
129 |
|
130 |
|
131 |
|
132 | const A = mat.concat()
|
133 | for (r = 0; r < rows; r++) {
|
134 | A[r] = A[r].concat()
|
135 | }
|
136 |
|
137 |
|
138 |
|
139 | const B = identity(rows).valueOf()
|
140 |
|
141 |
|
142 | for (let c = 0; c < cols; c++) {
|
143 |
|
144 | let ABig = abs(A[c][c])
|
145 | let rBig = c
|
146 | r = c + 1
|
147 | while (r < rows) {
|
148 | if (abs(A[r][c]) > ABig) {
|
149 | ABig = abs(A[r][c])
|
150 | rBig = r
|
151 | }
|
152 | r++
|
153 | }
|
154 | if (ABig === 0) {
|
155 | throw Error('Cannot calculate inverse, determinant is zero')
|
156 | }
|
157 | r = rBig
|
158 | if (r !== c) {
|
159 | temp = A[c]; A[c] = A[r]; A[r] = temp
|
160 | temp = B[c]; B[c] = B[r]; B[r] = temp
|
161 | }
|
162 |
|
163 |
|
164 | const Ac = A[c]
|
165 | const Bc = B[c]
|
166 | for (r = 0; r < rows; r++) {
|
167 | const Ar = A[r]
|
168 | const Br = B[r]
|
169 | if (r !== c) {
|
170 |
|
171 | if (Ar[c] !== 0) {
|
172 | f = divideScalar(unaryMinus(Ar[c]), Ac[c])
|
173 |
|
174 |
|
175 |
|
176 | for (s = c; s < cols; s++) {
|
177 | Ar[s] = addScalar(Ar[s], multiply(f, Ac[s]))
|
178 | }
|
179 | for (s = 0; s < cols; s++) {
|
180 | Br[s] = addScalar(Br[s], multiply(f, Bc[s]))
|
181 | }
|
182 | }
|
183 | } else {
|
184 |
|
185 |
|
186 | f = Ac[c]
|
187 | for (s = c; s < cols; s++) {
|
188 | Ar[s] = divideScalar(Ar[s], f)
|
189 | }
|
190 | for (s = 0; s < cols; s++) {
|
191 | Br[s] = divideScalar(Br[s], f)
|
192 | }
|
193 | }
|
194 | }
|
195 | }
|
196 | return B
|
197 | }
|
198 | }
|
199 |
|
200 | inv.toTex = { 1: `\\left(\${args[0]}\\right)^{-1}` }
|
201 |
|
202 | return inv
|
203 | }
|
204 |
|
205 | exports.name = 'inv'
|
206 | exports.factory = factory
|