diff.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. import { factory } from '../../utils/factory.js';
  2. import { isInteger } from '../../utils/number.js';
  3. import { isMatrix } from '../../utils/is.js';
  4. var name = 'diff';
  5. var dependencies = ['typed', 'matrix', 'subtract', 'number'];
  6. export var createDiff = /* #__PURE__ */factory(name, dependencies, _ref => {
  7. var {
  8. typed,
  9. matrix,
  10. subtract,
  11. number
  12. } = _ref;
  13. /**
  14. * Create a new matrix or array of the difference between elements of the given array
  15. * The optional dim parameter lets you specify the dimension to evaluate the difference of
  16. * If no dimension parameter is passed it is assumed as dimension 0
  17. *
  18. * Dimension is zero-based in javascript and one-based in the parser and can be a number or bignumber
  19. * Arrays must be 'rectangular' meaning arrays like [1, 2]
  20. * If something is passed as a matrix it will be returned as a matrix but other than that all matrices are converted to arrays
  21. *
  22. * Syntax:
  23. *
  24. * math.diff(arr)
  25. * math.diff(arr, dim)
  26. *
  27. * Examples:
  28. *
  29. * const arr = [1, 2, 4, 7, 0]
  30. * math.diff(arr) // returns [1, 2, 3, -7] (no dimension passed so 0 is assumed)
  31. * math.diff(math.matrix(arr)) // returns Matrix [1, 2, 3, -7]
  32. *
  33. * const arr = [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [9, 8, 7, 6, 4]]
  34. * math.diff(arr) // returns [[0, 0, 0, 0, 0], [8, 6, 4, 2, -1]]
  35. * math.diff(arr, 0) // returns [[0, 0, 0, 0, 0], [8, 6, 4, 2, -1]]
  36. * math.diff(arr, 1) // returns [[1, 1, 1, 1], [1, 1, 1, 1], [-1, -1, -1, -2]]
  37. * math.diff(arr, math.bignumber(1)) // returns [[1, 1, 1, 1], [1, 1, 1, 1], [-1, -1, -1, -2]]
  38. *
  39. * math.diff(arr, 2) // throws RangeError as arr is 2 dimensional not 3
  40. * math.diff(arr, -1) // throws RangeError as negative dimensions are not allowed
  41. *
  42. * // These will all produce the same result
  43. * math.diff([[1, 2], [3, 4]])
  44. * math.diff([math.matrix([1, 2]), math.matrix([3, 4])])
  45. * math.diff([[1, 2], math.matrix([3, 4])])
  46. * math.diff([math.matrix([1, 2]), [3, 4]])
  47. * // They do not produce the same result as math.diff(math.matrix([[1, 2], [3, 4]])) as this returns a matrix
  48. *
  49. * See Also:
  50. *
  51. * sum
  52. * subtract
  53. * partitionSelect
  54. *
  55. * @param {Array | Matrix} arr An array or matrix
  56. * @param {number} dim Dimension
  57. * @return {Array | Matrix} Difference between array elements in given dimension
  58. */
  59. return typed(name, {
  60. 'Array | Matrix': function ArrayMatrix(arr) {
  61. // No dimension specified => assume dimension 0
  62. if (isMatrix(arr)) {
  63. return matrix(_diff(arr.toArray()));
  64. } else {
  65. return _diff(arr);
  66. }
  67. },
  68. 'Array | Matrix, number': function ArrayMatrixNumber(arr, dim) {
  69. if (!isInteger(dim)) throw new RangeError('Dimension must be a whole number');
  70. if (isMatrix(arr)) {
  71. return matrix(_recursive(arr.toArray(), dim));
  72. } else {
  73. return _recursive(arr, dim);
  74. }
  75. },
  76. 'Array, BigNumber': typed.referTo('Array,number', selfAn => (arr, dim) => selfAn(arr, number(dim))),
  77. 'Matrix, BigNumber': typed.referTo('Matrix,number', selfMn => (arr, dim) => selfMn(arr, number(dim)))
  78. });
  79. /**
  80. * Recursively find the correct dimension in the array/matrix
  81. * Then Apply _diff to that dimension
  82. *
  83. * @param {Array} arr The array
  84. * @param {number} dim Dimension
  85. * @return {Array} resulting array
  86. */
  87. function _recursive(arr, dim) {
  88. if (isMatrix(arr)) {
  89. arr = arr.toArray(); // Makes sure arrays like [ matrix([0, 1]), matrix([1, 0]) ] are processed properly
  90. }
  91. if (!Array.isArray(arr)) {
  92. throw RangeError('Array/Matrix does not have that many dimensions');
  93. }
  94. if (dim > 0) {
  95. var result = [];
  96. arr.forEach(element => {
  97. result.push(_recursive(element, dim - 1));
  98. });
  99. return result;
  100. } else if (dim === 0) {
  101. return _diff(arr);
  102. } else {
  103. throw RangeError('Cannot have negative dimension');
  104. }
  105. }
  106. /**
  107. * Difference between elements in the array
  108. *
  109. * @param {Array} arr An array
  110. * @return {Array} resulting array
  111. */
  112. function _diff(arr) {
  113. var result = [];
  114. var size = arr.length;
  115. for (var i = 1; i < size; i++) {
  116. result.push(_ElementDiff(arr[i - 1], arr[i]));
  117. }
  118. return result;
  119. }
  120. /**
  121. * Difference between 2 objects
  122. *
  123. * @param {Object} obj1 First object
  124. * @param {Object} obj2 Second object
  125. * @return {Array} resulting array
  126. */
  127. function _ElementDiff(obj1, obj2) {
  128. // Convert matrices to arrays
  129. if (isMatrix(obj1)) obj1 = obj1.toArray();
  130. if (isMatrix(obj2)) obj2 = obj2.toArray();
  131. var obj1IsArray = Array.isArray(obj1);
  132. var obj2IsArray = Array.isArray(obj2);
  133. if (obj1IsArray && obj2IsArray) {
  134. return _ArrayDiff(obj1, obj2);
  135. }
  136. if (!obj1IsArray && !obj2IsArray) {
  137. return subtract(obj2, obj1); // Difference is (second - first) NOT (first - second)
  138. }
  139. throw TypeError('Cannot calculate difference between 1 array and 1 non-array');
  140. }
  141. /**
  142. * Difference of elements in 2 arrays
  143. *
  144. * @param {Array} arr1 Array 1
  145. * @param {Array} arr2 Array 2
  146. * @return {Array} resulting array
  147. */
  148. function _ArrayDiff(arr1, arr2) {
  149. if (arr1.length !== arr2.length) {
  150. throw RangeError('Not all sub-arrays have the same length');
  151. }
  152. var result = [];
  153. var size = arr1.length;
  154. for (var i = 0; i < size; i++) {
  155. result.push(_ElementDiff(arr1[i], arr2[i]));
  156. }
  157. return result;
  158. }
  159. });