UNPKG

7.49 kBJavaScriptView Raw
1import { factory } from '../../utils/factory.js';
2var name = 'norm';
3var dependencies = ['typed', 'abs', 'add', 'pow', 'conj', 'sqrt', 'multiply', 'equalScalar', 'larger', 'smaller', 'matrix', 'ctranspose', 'eigs'];
4export 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