UNPKG

ts-scikit

Version:

A scientific toolkit written in Typescript

556 lines 15.3 kB
"use strict"; /** * Utilities for arrays plus math methods * @packageDocumentation */ Object.defineProperty(exports, "__esModule", { value: true }); exports.binarySearch = exports.quickPartialSort = exports.ramp = exports.fill = exports.zero = exports.czero = exports.ccopy = exports.copy = exports.almostEqual = exports.isMonotonic = exports.isDecreasing = exports.isIncreasing = exports.toDegrees = exports.toRadians = exports.cosFromSin = exports.arrayDimensions = void 0; /////////////////////////////////////////////////////////////////////////// // math methods /** @internal */ const N_SMALL_SORT = 7; /** @internal */ const N_LARGE_SORT = 40; /** * Returns the number of dimensions for the provided array. * @param array the array. * @param dim the starting dimension. * @returns the number of dimensions. */ function arrayDimensions(array, dim = 0) { return (array instanceof Array) ? arrayDimensions(array[0], dim + 1) : dim; } exports.arrayDimensions = arrayDimensions; /** * Takes the cosine of a number by using the sine and an additional angle. * @param sin the sine of an angle. * @param angle the angle. * @returns the resulting cosine. */ function cosFromSin(sin, angle) { // sin(x)^2 + cos(x)^2 = 1 const cos = Math.sqrt(1.0 - sin * sin); const a = angle + (Math.PI / 2); let b = a - Math.floor(a / (2 * Math.PI)) * (2 * Math.PI); if (b < 0) { b += (2 * Math.PI); } return (b >= Math.PI) ? -cos : cos; } exports.cosFromSin = cosFromSin; /** * Converts degrees to radians. * @param degrees the angle in degrees * @returns the angle in radians. */ function toRadians(degrees) { return (degrees * Math.PI / 180.0); } exports.toRadians = toRadians; /** * Converts radians to degrees. * @param radians the angle in radians. * @returns the angle in degrees. */ function toDegrees(radians) { return (radians * 180.0 / Math.PI); } exports.toDegrees = toDegrees; /** * Determines whether the specified array is increasing. * The array is increasing if its elements a[i] increase with array index i, * with no equal values. * @param a the array. * @returns true, if increasing (or a.length &lt; 2); false, otherwise. */ function isIncreasing(a) { const n = a.length; if (n > 1) { for (let i = 1; i < n; ++i) { if (a[i - 1] > a[i]) { return false; } } } return true; } exports.isIncreasing = isIncreasing; /** * Determines whether the specified array is decreasing. * The array is decreasing if its elements a[i] decrease with array index i, * with no equal values. * @param a the array. * @returns true, if decreasing (or a.length &lt; 2); false, otherwise. */ function isDecreasing(a) { const n = a.length; if (n > 1) { for (let i = 1; i < n; ++i) { if (a[i - 1] < a[i]) { return false; } } } return true; } exports.isDecreasing = isDecreasing; /** * Determines whether the specified array is monotonic. * The array is monotonic if its elements[i] either increase or * decrease (but not both) with array index i, with no equal values. * @param a the array. * @returns true, if monotonic (or a.length &lt; 2); false, otherwise. */ function isMonotonic(a) { return isIncreasing(a) || isDecreasing(a); } exports.isMonotonic = isMonotonic; /** * Determines if two values are almost equal given a provided tolerance. * @param v1 a value. * @param v2 a value. * @param tiny the tolerance. * @returns true, if almost equal; false, otherwise. */ function almostEqual(v1, v2, tiny) { const diff = v2 - v1; return (diff < 0.0) ? -diff < tiny : diff < tiny; } exports.almostEqual = almostEqual; function copy(rx, p1, p2, p3, p4, p5, p6, p7, p8, p9) { switch (arrayDimensions(rx)) { case 1: return _copy1d(rx, p1, p2, p3); case 2: return _copy2d(rx, p1, p2, p3, p4, p5, p6); default: return _copy3d(rx, p1, p2, p3, p4, p5, p6, p7, p8, p9); } } exports.copy = copy; function ccopy(cx, n1, p2, p3, p4, p5, p6, p7, p8, p9) { if (!n1) { n1 = cx.length; } switch (arrayDimensions(cx)) { case 1: return _copy1d(cx, n1 * 2, p2, p3, true); case 2: return _copy2d(cx, n1 * 2, p2, p3, p4, p5, p6, true); default: return _copy3d(cx, n1 * 2, p2, p3, p4, p5, p6, p7, p8, p9, true); } } exports.ccopy = ccopy; function czero(cxn1, n2, n3) { switch (arrayDimensions(cxn1)) { case 1: _fill1D(cxn1, 0); return; case 2: _fill2D(cxn1, 0); return; case 3: _fill3D(cxn1, 0); return; } if (n3) { const rx = new Array(n3); for (let i3 = 0; i3 < n3; ++i3) { rx[i3] = new Array(n2); for (let i2 = 0; i2 < n2; ++i2) { rx[i3][i2] = Array.from({ length: 2 * cxn1 }, () => 0); } } return rx; } else if (n2) { const rx = new Array(n2); for (let i2 = 0; i2 < n2; ++i2) { rx[i2] = Array.from({ length: 2 * cxn1 }, () => 0); } return rx; } else { return Array.from({ length: 2 * cxn1 }, () => 0); } } exports.czero = czero; function zero(rxn1, n2, n3) { switch (arrayDimensions(rxn1)) { case 1: _fill1D(rxn1, 0); return; case 2: _fill2D(rxn1, 0); return; case 3: _fill3D(rxn1, 0); return; } if (n3) { const rx = new Array(n3); for (let i3 = 0; i3 < n3; ++i3) { rx[i3] = new Array(n2); for (let i2 = 0; i2 < n2; ++i2) { rx[i3][i2] = Array.from({ length: rxn1 }, () => 0); } } return rx; } else if (n2) { const rx = new Array(n2); for (let i2 = 0; i2 < n2; ++i2) { rx[i2] = Array.from({ length: rxn1 }, () => 0); } return rx; } else { return Array.from({ length: rxn1 }, () => 0); } } exports.zero = zero; function fill(p1, p2, p3, p4) { switch (arrayDimensions(p1)) { case 1: _fill1D(p1, p2); return; case 2: _fill2D(p1, p2); return; case 3: _fill3D(p1, p2); return; } if (p4) { const rx = new Array(p4); for (let i3 = 0; i3 < p4; ++i3) { rx[i3] = new Array(p3); for (let i2 = 0; i2 < p3; ++i2) { rx[i3][i2] = Array.from({ length: p2 }, () => p1); } } return rx; } else if (p3) { const rx = new Array(p3); for (let i2 = 0; i2 < p3; ++i2) { rx[i2] = Array.from({ length: p2 }, () => p1); } return rx; } else { return Array.from({ length: p2 }, () => p1); } } exports.fill = fill; /** @internal */ function _fill1D(rx, fill) { const n1 = rx.length; for (let i1 = 0; i1 < n1; ++i1) { rx[i1] = fill; } } /** @internal */ function _fill2D(rx, fill) { const n2 = rx.length; for (let i2 = 0; i2 < n2; ++i2) { _fill1D(rx[i2], fill); } } /** @internal */ function _fill3D(rx, fill) { const n3 = rx.length; for (let i3 = 0; i3 < n3; ++i3) { _fill2D(rx[i3], fill); } } function ramp(rxa, p1, p2, p3, p4, p5, p6) { // If passing in an array, return reference switch (arrayDimensions(rxa)) { case 1: _ramp1d(rxa, p1, p2); return; case 2: _ramp2d(rxa, p1, p2, p3); return; case 3: _ramp3d(rxa, p1, p2, p3, p4); return; } // Otherwise, create new and return if (p6) { const rx = zero(p4, p5, p6); _ramp3d(rx, rxa, p1, p2, p3); return rx; } else if (p4) { const rx = zero(p3, p4); _ramp2d(rx, rxa, p1, p2); return rx; } else { const rx = zero(p2); _ramp1d(rx, rxa, p1); return rx; } } exports.ramp = ramp; /** @internal */ function _ramp1d(rx, ra, rb1) { const n1 = rx.length; for (let i1 = 0; i1 < n1; ++i1) { rx[i1] = ra + rb1 * i1; } } /** @internal */ function _ramp2d(rx, ra, rb1, rb2) { const n2 = rx.length; for (let i2 = 0; i2 < n2; ++i2) { _ramp1d(rx[i2], ra + rb2 * i2, rb1); } } /** @internal */ function _ramp3d(rx, ra, rb1, rb2, rb3) { const n3 = rx.length; for (let i3 = 0; i3 < n3; ++i3) { _ramp2d(rx[i3], ra + rb3 * i3, rb1, rb2); } } /////////////////////////////////////////////////////////////////////////// // real-to-complex /////////////////////////////////////////////////////////////////////////// /** @internal */ class RealToComplex { apply(rx, ry, cz) { const cdim = arrayDimensions(cz); const rdim = arrayDimensions(rx); switch (arrayDimensions(rx)) { case 1: case 2: default: } } } /////////////////////////////////////////////////////////////////////////// // misc algorithms /////////////////////////////////////////////////////////////////////////// /** * Performs a quick partial sort. * @param k * @param arr */ function quickPartialSort(k, arr) { const n = arr.length; let p = 0; let q = n - 1; const m = (n > N_SMALL_SORT) ? new Array(2) : null; while (q - p >= N_SMALL_SORT) { m[0] = p; m[1] = q; quickPartition(arr, m); if (k < m[0]) { q = m[0] - 1; } else if (k > m[1]) { p = m[1] + 1; } else { return; } } insertionSort(arr, p, q); } exports.quickPartialSort = quickPartialSort; /** * Performs a binary search in a monotonic array of values. * <p> * Values are assumed to increase or decrease monotonically, with no equal * values. * <p> * Warning: this method does not ensure that the specified array is * monotonic; that check would be more costly than this search. * @param a the array of values, assumed to be monotonic. * @param x the value for which to search. * @param i the index at which to begin the search. If negative, this * method interprets this index as if returned from a * previous call. * @returns the index at which the specified value is found, or, if not * found, -(i + 1), where i equals the index at which the * specified value would be located if it was inserted into * the monotonic array. */ function binarySearch(a, x, i) { if (!i) { i = a.length; } const n = a.length; const nm1 = n - 1; let low = 0; let high = nm1; const increasing = n < 2 || a[0] < a[1]; if (i < n) { high = (0 <= i) ? i : -(i + 1); low = high - 1; let step = 1; if (increasing) { for (; 0 < low && x < a[low]; low -= step, step += step) { high = low; } for (; high < nm1 && a[high] < x; high += step, step += step) { low = high; } } else { for (; 0 < low && x > a[low]; low -= step, step += step) { high = low; } for (; high < nm1 && a[high] > x; high += step, step += step) { low = high; } } if (low < 0) { low = 0; } if (high > nm1) { high = nm1; } } if (increasing) { while (low <= high) { const mid = (low + high) >> 1; const amid = a[mid]; if (amid < x) { low = mid + 1; } else if (amid > x) { high = mid - 1; } else { return mid; } } } else { while (low <= high) { const mid = (low + high) >> 1; const amid = a[mid]; if (amid > x) { low = mid + 1; } else if (amid < x) { high = mid - 1; } else { return mid; } } } return -(low + 1); } exports.binarySearch = binarySearch; /** @internal */ function med3(a, i, j, k) { return a[i] < a[j] ? (a[j] < a[k] ? j : a[i] < a[k] ? k : i) : (a[j] > a[k] ? j : a[i] > a[k] ? k : i); } /** @internal */ function swap(a, i, j, n = 1) { while (n > 0) { const ai = a[i]; a[i++] = a[j]; a[j++] = ai; --n; } } /** @internal */ function insertionSort(a, p, q) { for (let i = p; i <= q; ++i) { for (let j = i; j > p && a[j - 1] > a[j]; --j) { swap(a, j, j - 1); } } } /** @internal */ function quickPartition(x, m) { const p = m[0]; const q = m[1]; const n = q - p + 1; let k = (p + q) / 2; if (n > N_SMALL_SORT) { let j = q; let l = q; if (n > N_LARGE_SORT) { const s = n / 8; j = med3(x, j, j + s, j + 2 * s); k = med3(x, k - s, k, k + s); l = med3(x, l - 2 * s, l - s, l); } k = med3(x, j, k, l); } const y = x[k]; let a = p, b = p; let c = q, d = q; while (true) { while (b <= c && x[b] <= y) { if (x[b] === y) { swap(x, a++, b); } ++b; } while (c >= b && x[c] >= y) { if (x[c] === y) { swap(x, c, d--); } --c; } if (b > c) { break; } swap(x, b, c); ++b; --c; } const r = Math.min(a - p, b - a); const s = Math.min(d - c, q - d); const t = q + 1; swap(x, p, b - r, r); swap(x, b, t - s, s); m[0] = p + (b - a); // p --- m[0]-1 | m[0] --- m[1] | m[1]+1 --- q m[1] = q - (d - c); // x<y x=y x>y } /** @internal */ function _copy1d(x, n1, j1 = 0, k1 = 1, complex = false) { const m = (complex) ? 2.0 : 1.0; const c = (complex) ? 1.0 : 0.0; const k1xm = k1 * m; const k1ym = (complex) ? 2.0 : 1.0; const xdm = x.length / m; n1 = (!n1) ? xdm : Math.min(xdm, Math.max(0, n1 / m)); const y = new Array(n1); for (let i1 = 0, ix = m * j1, iy = 0; i1 < n1; ++i1, ix += k1xm, iy += k1ym) { y[iy] = x[ix]; y[iy + c] = x[ix + c]; } return y; } /** @internal */ function _copy2d(x, n1, n2, j1 = 0, j2 = 0, k1 = 1, k2 = 1, complex = false) { n2 = (!n2) ? x.length : Math.min(x.length, Math.max(0, n2)); const y = new Array(n2); for (let i2 = 0; i2 < n2; ++i2) { y[i2] = _copy1d(x[j2 + i2 * k2], n1, j1, k1, complex); } return y; } /** @internal */ function _copy3d(x, n1, n2, n3, j1 = 0, j2 = 0, j3 = 0, k1 = 1, k2 = 1, k3 = 1, complex = false) { n3 = (!n3) ? x.length : Math.min(x.length, Math.max(0, n3)); const y = new Array(n3); for (let i3 = 0; i3 < n3; ++i3) { y[i3] = _copy2d(x[j3 + i3 * k3], n1, n2, j1, j2, k1, k2, complex); } return y; } //# sourceMappingURL=array-math.js.map