norm.js 7.1 KB

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