1 | import { factory } from '../../utils/factory.js';
|
2 | var name = 'norm';
|
3 | var dependencies = ['typed', 'abs', 'add', 'pow', 'conj', 'sqrt', 'multiply', 'equalScalar', 'larger', 'smaller', 'matrix', 'ctranspose', 'eigs'];
|
4 | export var createNorm = /* #__PURE__ */factory(name, dependencies, (_ref) => {
|
5 | var {
|
6 | typed,
|
7 | abs,
|
8 | add,
|
9 | pow,
|
10 | conj,
|
11 | sqrt,
|
12 | multiply,
|
13 | equalScalar,
|
14 | larger,
|
15 | smaller,
|
16 | matrix,
|
17 | ctranspose,
|
18 | eigs
|
19 | } = _ref;
|
20 |
|
21 | /**
|
22 | * Calculate the norm of a number, vector or matrix.
|
23 | *
|
24 | * The second parameter p is optional. If not provided, it defaults to 2.
|
25 | *
|
26 | * Syntax:
|
27 | *
|
28 | * math.norm(x)
|
29 | * math.norm(x, p)
|
30 | *
|
31 | * Examples:
|
32 | *
|
33 | * math.abs(-3.5) // returns 3.5
|
34 | * math.norm(-3.5) // returns 3.5
|
35 | *
|
36 | * math.norm(math.complex(3, -4)) // returns 5
|
37 | *
|
38 | * math.norm([1, 2, -3], Infinity) // returns 3
|
39 | * math.norm([1, 2, -3], -Infinity) // returns 1
|
40 | *
|
41 | * math.norm([3, 4], 2) // returns 5
|
42 | *
|
43 | * math.norm([[1, 2], [3, 4]], 1) // returns 6
|
44 | * math.norm([[1, 2], [3, 4]], 'inf') // returns 7
|
45 | * math.norm([[1, 2], [3, 4]], 'fro') // returns 5.477225575051661
|
46 | *
|
47 | * See also:
|
48 | *
|
49 | * abs, hypot
|
50 | *
|
51 | * @param {number | BigNumber | Complex | Array | Matrix} x
|
52 | * Value for which to calculate the norm
|
53 | * @param {number | BigNumber | string} [p=2]
|
54 | * Vector space.
|
55 | * Supported numbers include Infinity and -Infinity.
|
56 | * Supported strings are: 'inf', '-inf', and 'fro' (The Frobenius norm)
|
57 | * @return {number | BigNumber} the p-norm
|
58 | */
|
59 | return typed(name, {
|
60 | number: Math.abs,
|
61 | Complex: function Complex(x) {
|
62 | return x.abs();
|
63 | },
|
64 | BigNumber: function BigNumber(x) {
|
65 | // norm(x) = abs(x)
|
66 | return x.abs();
|
67 | },
|
68 | boolean: function boolean(x) {
|
69 | // norm(x) = abs(x)
|
70 | return Math.abs(x);
|
71 | },
|
72 | Array: function Array(x) {
|
73 | return _norm(matrix(x), 2);
|
74 | },
|
75 | Matrix: function Matrix(x) {
|
76 | return _norm(x, 2);
|
77 | },
|
78 | 'number | Complex | BigNumber | boolean, number | BigNumber | string': function numberComplexBigNumberBooleanNumberBigNumberString(x) {
|
79 | // ignore second parameter, TODO: remove the option of second parameter for these types
|
80 | return this(x);
|
81 | },
|
82 | 'Array, number | BigNumber | string': function ArrayNumberBigNumberString(x, p) {
|
83 | return _norm(matrix(x), p);
|
84 | },
|
85 | 'Matrix, number | BigNumber | string': function MatrixNumberBigNumberString(x, p) {
|
86 | return _norm(x, p);
|
87 | }
|
88 | });
|
89 | /**
|
90 | * Calculate the plus infinity norm for a vector
|
91 | * @param {Matrix} x
|
92 | * @returns {number} Returns the norm
|
93 | * @private
|
94 | */
|
95 |
|
96 | function _vectorNormPlusInfinity(x) {
|
97 | // norm(x, Infinity) = max(abs(x))
|
98 | var pinf = 0; // skip zeros since abs(0) === 0
|
99 |
|
100 | x.forEach(function (value) {
|
101 | var v = abs(value);
|
102 |
|
103 | if (larger(v, pinf)) {
|
104 | pinf = v;
|
105 | }
|
106 | }, true);
|
107 | return pinf;
|
108 | }
|
109 | /**
|
110 | * Calculate the minus infinity norm for a vector
|
111 | * @param {Matrix} x
|
112 | * @returns {number} Returns the norm
|
113 | * @private
|
114 | */
|
115 |
|
116 |
|
117 | function _vectorNormMinusInfinity(x) {
|
118 | // norm(x, -Infinity) = min(abs(x))
|
119 | var ninf; // skip zeros since abs(0) === 0
|
120 |
|
121 | x.forEach(function (value) {
|
122 | var v = abs(value);
|
123 |
|
124 | if (!ninf || smaller(v, ninf)) {
|
125 | ninf = v;
|
126 | }
|
127 | }, true);
|
128 | return ninf || 0;
|
129 | }
|
130 | /**
|
131 | * Calculate the norm for a vector
|
132 | * @param {Matrix} x
|
133 | * @param {number | string} p
|
134 | * @returns {number} Returns the norm
|
135 | * @private
|
136 | */
|
137 |
|
138 |
|
139 | function _vectorNorm(x, p) {
|
140 | // check p
|
141 | if (p === Number.POSITIVE_INFINITY || p === 'inf') {
|
142 | return _vectorNormPlusInfinity(x);
|
143 | }
|
144 |
|
145 | if (p === Number.NEGATIVE_INFINITY || p === '-inf') {
|
146 | return _vectorNormMinusInfinity(x);
|
147 | }
|
148 |
|
149 | if (p === 'fro') {
|
150 | return _norm(x, 2);
|
151 | }
|
152 |
|
153 | if (typeof p === 'number' && !isNaN(p)) {
|
154 | // check p != 0
|
155 | if (!equalScalar(p, 0)) {
|
156 | // norm(x, p) = sum(abs(xi) ^ p) ^ 1/p
|
157 | var n = 0; // skip zeros since abs(0) === 0
|
158 |
|
159 | x.forEach(function (value) {
|
160 | n = add(pow(abs(value), p), n);
|
161 | }, true);
|
162 | return pow(n, 1 / p);
|
163 | }
|
164 |
|
165 | return Number.POSITIVE_INFINITY;
|
166 | } // invalid parameter value
|
167 |
|
168 |
|
169 | throw new Error('Unsupported parameter value');
|
170 | }
|
171 | /**
|
172 | * Calculate the Frobenius norm for a matrix
|
173 | * @param {Matrix} x
|
174 | * @returns {number} Returns the norm
|
175 | * @private
|
176 | */
|
177 |
|
178 |
|
179 | function _matrixNormFrobenius(x) {
|
180 | // norm(x) = sqrt(sum(diag(x'x)))
|
181 | var fro = 0;
|
182 | x.forEach(function (value, index) {
|
183 | fro = add(fro, multiply(value, conj(value)));
|
184 | });
|
185 | return abs(sqrt(fro));
|
186 | }
|
187 | /**
|
188 | * Calculate the norm L1 for a matrix
|
189 | * @param {Matrix} x
|
190 | * @returns {number} Returns the norm
|
191 | * @private
|
192 | */
|
193 |
|
194 |
|
195 | function _matrixNormOne(x) {
|
196 | // norm(x) = the largest column sum
|
197 | var c = []; // result
|
198 |
|
199 | var maxc = 0; // skip zeros since abs(0) == 0
|
200 |
|
201 | x.forEach(function (value, index) {
|
202 | var j = index[1];
|
203 | var cj = add(c[j] || 0, abs(value));
|
204 |
|
205 | if (larger(cj, maxc)) {
|
206 | maxc = cj;
|
207 | }
|
208 |
|
209 | c[j] = cj;
|
210 | }, true);
|
211 | return maxc;
|
212 | }
|
213 | /**
|
214 | * Calculate the norm L2 for a matrix
|
215 | * @param {Matrix} x
|
216 | * @returns {number} Returns the norm
|
217 | * @private
|
218 | */
|
219 |
|
220 |
|
221 | function _matrixNormTwo(x) {
|
222 | // norm(x) = sqrt( max eigenvalue of A*.A)
|
223 | var sizeX = x.size();
|
224 |
|
225 | if (sizeX[0] !== sizeX[1]) {
|
226 | throw new RangeError('Invalid matrix dimensions');
|
227 | }
|
228 |
|
229 | var tx = ctranspose(x);
|
230 | var squaredX = multiply(tx, x);
|
231 | var eigenVals = eigs(squaredX).values;
|
232 | var rho = eigenVals.get([eigenVals.size()[0] - 1]);
|
233 | return abs(sqrt(rho));
|
234 | }
|
235 | /**
|
236 | * Calculate the infinity norm for a matrix
|
237 | * @param {Matrix} x
|
238 | * @returns {number} Returns the norm
|
239 | * @private
|
240 | */
|
241 |
|
242 |
|
243 | function _matrixNormInfinity(x) {
|
244 | // norm(x) = the largest row sum
|
245 | var r = []; // result
|
246 |
|
247 | var maxr = 0; // skip zeros since abs(0) == 0
|
248 |
|
249 | x.forEach(function (value, index) {
|
250 | var i = index[0];
|
251 | var ri = add(r[i] || 0, abs(value));
|
252 |
|
253 | if (larger(ri, maxr)) {
|
254 | maxr = ri;
|
255 | }
|
256 |
|
257 | r[i] = ri;
|
258 | }, true);
|
259 | return maxr;
|
260 | }
|
261 | /**
|
262 | * Calculate the norm for a 2D Matrix (M*N)
|
263 | * @param {Matrix} x
|
264 | * @param {number | string} p
|
265 | * @returns {number} Returns the norm
|
266 | * @private
|
267 | */
|
268 |
|
269 |
|
270 | function _matrixNorm(x, p) {
|
271 | // check p
|
272 | if (p === 1) {
|
273 | return _matrixNormOne(x);
|
274 | }
|
275 |
|
276 | if (p === Number.POSITIVE_INFINITY || p === 'inf') {
|
277 | return _matrixNormInfinity(x);
|
278 | }
|
279 |
|
280 | if (p === 'fro') {
|
281 | return _matrixNormFrobenius(x);
|
282 | }
|
283 |
|
284 | if (p === 2) {
|
285 | return _matrixNormTwo(x);
|
286 | } // invalid parameter value
|
287 |
|
288 |
|
289 | throw new Error('Unsupported parameter value ' + p);
|
290 | }
|
291 | /**
|
292 | * Calculate the norm for an array
|
293 | * @param {Matrix} x
|
294 | * @param {number | string} p
|
295 | * @returns {number} Returns the norm
|
296 | * @private
|
297 | */
|
298 |
|
299 |
|
300 | function _norm(x, p) {
|
301 | // size
|
302 | var sizeX = x.size(); // check if it is a vector
|
303 |
|
304 | if (sizeX.length === 1) {
|
305 | return _vectorNorm(x, p);
|
306 | } // MxN matrix
|
307 |
|
308 |
|
309 | if (sizeX.length === 2) {
|
310 | if (sizeX[0] && sizeX[1]) {
|
311 | return _matrixNorm(x, p);
|
312 | } else {
|
313 | throw new RangeError('Invalid matrix dimensions');
|
314 | }
|
315 | }
|
316 | }
|
317 | }); |
\ | No newline at end of file |