collection.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. import { isCollection, isMatrix } from './is.js';
  2. import { IndexError } from '../error/IndexError.js';
  3. import { arraySize } from './array.js';
  4. import { _switch } from './switch.js';
  5. /**
  6. * Test whether an array contains collections
  7. * @param {Array} array
  8. * @returns {boolean} Returns true when the array contains one or multiple
  9. * collections (Arrays or Matrices). Returns false otherwise.
  10. */
  11. export function containsCollections(array) {
  12. for (var i = 0; i < array.length; i++) {
  13. if (isCollection(array[i])) {
  14. return true;
  15. }
  16. }
  17. return false;
  18. }
  19. /**
  20. * Recursively loop over all elements in a given multi dimensional array
  21. * and invoke the callback on each of the elements.
  22. * @param {Array | Matrix} array
  23. * @param {Function} callback The callback method is invoked with one
  24. * parameter: the current element in the array
  25. */
  26. export function deepForEach(array, callback) {
  27. if (isMatrix(array)) {
  28. array = array.valueOf();
  29. }
  30. for (var i = 0, ii = array.length; i < ii; i++) {
  31. var value = array[i];
  32. if (Array.isArray(value)) {
  33. deepForEach(value, callback);
  34. } else {
  35. callback(value);
  36. }
  37. }
  38. }
  39. /**
  40. * Execute the callback function element wise for each element in array and any
  41. * nested array
  42. * Returns an array with the results
  43. * @param {Array | Matrix} array
  44. * @param {Function} callback The callback is called with two parameters:
  45. * value1 and value2, which contain the current
  46. * element of both arrays.
  47. * @param {boolean} [skipZeros] Invoke callback function for non-zero values only.
  48. *
  49. * @return {Array | Matrix} res
  50. */
  51. export function deepMap(array, callback, skipZeros) {
  52. if (array && typeof array.map === 'function') {
  53. // TODO: replace array.map with a for loop to improve performance
  54. return array.map(function (x) {
  55. return deepMap(x, callback, skipZeros);
  56. });
  57. } else {
  58. return callback(array);
  59. }
  60. }
  61. /**
  62. * Reduce a given matrix or array to a new matrix or
  63. * array with one less dimension, applying the given
  64. * callback in the selected dimension.
  65. * @param {Array | Matrix} mat
  66. * @param {number} dim
  67. * @param {Function} callback
  68. * @return {Array | Matrix} res
  69. */
  70. export function reduce(mat, dim, callback) {
  71. var size = Array.isArray(mat) ? arraySize(mat) : mat.size();
  72. if (dim < 0 || dim >= size.length) {
  73. // TODO: would be more clear when throwing a DimensionError here
  74. throw new IndexError(dim, size.length);
  75. }
  76. if (isMatrix(mat)) {
  77. return mat.create(_reduce(mat.valueOf(), dim, callback));
  78. } else {
  79. return _reduce(mat, dim, callback);
  80. }
  81. }
  82. /**
  83. * Recursively reduce a matrix
  84. * @param {Array} mat
  85. * @param {number} dim
  86. * @param {Function} callback
  87. * @returns {Array} ret
  88. * @private
  89. */
  90. function _reduce(mat, dim, callback) {
  91. var i, ret, val, tran;
  92. if (dim <= 0) {
  93. if (!Array.isArray(mat[0])) {
  94. val = mat[0];
  95. for (i = 1; i < mat.length; i++) {
  96. val = callback(val, mat[i]);
  97. }
  98. return val;
  99. } else {
  100. tran = _switch(mat);
  101. ret = [];
  102. for (i = 0; i < tran.length; i++) {
  103. ret[i] = _reduce(tran[i], dim - 1, callback);
  104. }
  105. return ret;
  106. }
  107. } else {
  108. ret = [];
  109. for (i = 0; i < mat.length; i++) {
  110. ret[i] = _reduce(mat[i], dim - 1, callback);
  111. }
  112. return ret;
  113. }
  114. }
  115. // TODO: document function scatter
  116. export function scatter(a, j, w, x, u, mark, cindex, f, inverse, update, value) {
  117. // a arrays
  118. var avalues = a._values;
  119. var aindex = a._index;
  120. var aptr = a._ptr;
  121. // vars
  122. var k, k0, k1, i;
  123. // check we need to process values (pattern matrix)
  124. if (x) {
  125. // values in j
  126. for (k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) {
  127. // row
  128. i = aindex[k];
  129. // check value exists in current j
  130. if (w[i] !== mark) {
  131. // i is new entry in j
  132. w[i] = mark;
  133. // add i to pattern of C
  134. cindex.push(i);
  135. // x(i) = A, check we need to call function this time
  136. if (update) {
  137. // copy value to workspace calling callback function
  138. x[i] = inverse ? f(avalues[k], value) : f(value, avalues[k]);
  139. // function was called on current row
  140. u[i] = mark;
  141. } else {
  142. // copy value to workspace
  143. x[i] = avalues[k];
  144. }
  145. } else {
  146. // i exists in C already
  147. x[i] = inverse ? f(avalues[k], x[i]) : f(x[i], avalues[k]);
  148. // function was called on current row
  149. u[i] = mark;
  150. }
  151. }
  152. } else {
  153. // values in j
  154. for (k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) {
  155. // row
  156. i = aindex[k];
  157. // check value exists in current j
  158. if (w[i] !== mark) {
  159. // i is new entry in j
  160. w[i] = mark;
  161. // add i to pattern of C
  162. cindex.push(i);
  163. } else {
  164. // indicate function was called on current row
  165. u[i] = mark;
  166. }
  167. }
  168. }
  169. }