norm.js (7488B)
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.toArray(); 232 var rho = eigenVals[eigenVals.length - 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 });