@mathigon/fermat
Version:
Powerful mathematics and statistics library for JavaScript.
1,168 lines (1,156 loc) • 35.7 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod2) => __copyProps(__defProp({}, "__esModule", { value: true }), mod2);
// src/index.ts
var index_exports = {};
__export(index_exports, {
Complex: () => Complex,
Matrix: () => matrix_exports,
Random: () => random_exports,
Regression: () => regression_exports,
Vector: () => Vector,
XNumber: () => XNumber,
binomial: () => binomial,
clamp: () => clamp,
correlation: () => correlation,
covariance: () => covariance,
cube: () => cube,
digits: () => digits,
eulerPhi: () => eulerPhi,
factorial: () => factorial,
gcd: () => gcd,
generatePrime: () => generatePrime,
goldbach: () => goldbach,
isBetween: () => isBetween,
isInteger: () => isInteger,
isPrime: () => isPrime,
lcm: () => lcm,
lerp: () => lerp,
listPrimes: () => listPrimes,
log: () => log,
mean: () => mean,
median: () => median,
mod: () => mod,
mode: () => mode,
nearlyEquals: () => nearlyEquals,
numberFormat: () => numberFormat,
parseNumber: () => parseNumber,
permutations: () => permutations,
polynomial: () => polynomial,
primeFactorisation: () => primeFactorisation,
primeFactors: () => primeFactors,
quadratic: () => quadratic,
quantile: () => quantile,
round: () => round,
roundTo: () => roundTo,
scientificFormat: () => scientificFormat,
sign: () => sign,
square: () => square,
stdDev: () => stdDev,
subsets: () => subsets,
toOrdinal: () => toOrdinal,
toWord: () => toWord,
variance: () => variance
});
module.exports = __toCommonJS(index_exports);
// src/arithmetic.ts
var PRECISION = 1e-6;
function nearlyEquals(a, b, t = PRECISION) {
if (isNaN(a) || isNaN(b)) return false;
return Math.abs(a - b) < t;
}
function isInteger(x, t = PRECISION) {
return nearlyEquals(x, Math.round(x), t);
}
function isBetween(value, a, b, t = PRECISION) {
if (a > b) [a, b] = [b, a];
return value > a + t && value < b - t;
}
function sign(value, t = PRECISION) {
return nearlyEquals(value, 0, t) ? 0 : value > 0 ? 1 : -1;
}
var NUM_REGEX = /(\d+)(\d{3})/;
var POWER_SUFFIX = ["", "k", "m", "b", "t", "q"];
function addThousandSeparators(x) {
let [n, dec] = x.split(".");
while (NUM_REGEX.test(n)) {
n = n.replace(NUM_REGEX, "$1,$2");
}
return n + (dec ? `.${dec}` : "");
}
function addPowerSuffix(n, places = 6) {
if (!places) return `${n}`;
const digits2 = `${Math.abs(Math.floor(n))}`.length;
const chars = digits2 + (n < 0 ? 1 : 0);
if (chars <= places) return `${round(n, places - chars)}`;
const x = Math.floor(Math.log10(Math.abs(n)) / 3);
const suffix = POWER_SUFFIX[x];
const decimalPlaces = places - (digits2 % 3 || 3) - (suffix ? 1 : 0) - (n < 0 ? 1 : 0);
return round(n / Math.pow(10, 3 * x), decimalPlaces) + suffix;
}
function numberFormat(n, places = 0, separators = true) {
const str = addPowerSuffix(n, places).replace("-", "\u2013");
return separators ? addThousandSeparators(str) : str;
}
function scientificFormat(value, places = 6) {
const abs = Math.abs(value);
if (isBetween(abs, Math.pow(10, -places), Math.pow(10, places))) {
return numberFormat(value, places);
}
if (abs > Number.MAX_VALUE) return `${Math.sign(value) < 0 ? "\u2013" : ""}\u221E`;
if (abs < Number.MIN_VALUE) return "0";
const [str, exponent] = value.toExponential().split("e");
const top = exponent.replace("+", "").replace("-", "\u2013");
const isNegative = top.startsWith("\u2013");
return `${str.slice(0, 5)} \xD7 10^${(isNegative ? "(" : "") + top + (isNegative ? ")" : "")}`;
}
var SPECIAL_DECIMAL = /^-?0,[0-9]+$/;
var POINT_DECIMAL = /^-?([0-9]+(,[0-9]{3})*)?\.?[0-9]*$/;
var COMMA_DECIMAL = /^-?[0-9]+(\.[0-9]{3})*,?[0-9]*$/;
function parseNumber(str) {
str = str.replace(/^–/, "-").trim();
if (!str || str.match(/[^0-9.,-]/)) return NaN;
if (SPECIAL_DECIMAL.test(str)) {
return parseFloat(str.replace(/,/, "."));
}
if (POINT_DECIMAL.test(str)) {
return parseFloat(str.replace(/,/g, ""));
}
if (COMMA_DECIMAL.test(str)) {
return parseFloat(str.replace(/\./g, "").replace(/,/, "."));
}
return NaN;
}
function toOrdinal(x) {
if (Math.abs(x) % 100 >= 11 && Math.abs(x) % 100 <= 13) {
return `${x}th`;
}
switch (x % 10) {
case 1:
return `${x}st`;
case 2:
return `${x}nd`;
case 3:
return `${x}rd`;
default:
return `${x}th`;
}
}
var ONES = [
"",
"one",
"two",
"three",
"four",
"five",
"six",
"seven",
"eight",
"nine",
"ten",
"eleven",
"twelve",
"thirteen",
"fourteen",
"fifteen",
"sixteen",
"seventeen",
"eighteen",
"nineteen"
];
var TENS = [
"",
"",
"twenty",
"thirty",
"forty",
"fifty",
"sixty",
"seventy",
"eighty",
"ninety"
];
var MULTIPLIERS = [
"",
" thousand",
" million",
" billion",
" trillion",
" quadrillion",
" quintillion",
" sextillion"
];
function toWordSingle(number) {
const [h, t, o] = number.split("");
const hundreds = h === "0" ? "" : ` ${ONES[+h]} hundred`;
if (t + o === "00") return hundreds;
if (+t < 2) return `${hundreds} ${ONES[+(t + o)]}`;
if (o === "0") return `${hundreds} ${TENS[+t]}`;
return `${hundreds} ${TENS[+t]}-${ONES[+o]}`;
}
function toWord(n) {
if (n === 0) return "zero";
const str = Math.round(Math.abs(n)).toString();
const chunks = Math.ceil(str.length / 3);
const padded = str.padStart(3 * chunks, "0");
let result = "";
for (let i = 0; i < chunks; i += 1) {
const chunk = padded.substr(i * 3, 3);
if (chunk === "000") continue;
result += toWordSingle(chunk) + MULTIPLIERS[chunks - 1 - i];
}
return result.trim();
}
function digits(n) {
const str = `${Math.abs(n)}`;
return str.split("").reverse().map((x) => +x);
}
function round(n, precision = 0) {
const factor = Math.pow(10, precision);
return Math.round(n * factor) / factor;
}
function roundTo(n, increment = 1) {
return Math.round(n / increment) * increment;
}
function clamp(x, min = -Infinity, max = Infinity) {
return Math.min(max, Math.max(min, x));
}
function lerp(a, b, t = 0.5) {
return a + (b - a) * t;
}
function square(x) {
return x * x;
}
function cube(x) {
return x * x * x;
}
function mod(a, m) {
return (a % m + m) % m;
}
function log(x, b) {
return b === void 0 ? Math.log(x) : Math.log(x) / Math.log(b);
}
function quadratic(a, b, c) {
if (nearlyEquals(a, 0) && nearlyEquals(b, 0)) return [];
if (nearlyEquals(a, 0)) return [-c / b];
const p = -b / 2 / a;
const q = Math.sqrt(b * b - 4 * a * c) / 2 / a;
return [p + q, p - q];
}
function polynomial(x, coefficients) {
let total4 = 0;
let xi = 1;
for (const c of coefficients) {
total4 += xi * c;
xi *= x;
}
return total4;
}
// src/combinatorics.ts
function factorial(x) {
if (x === 0) return 1;
if (x < 0) return NaN;
let n = 1;
for (let i = 2; i <= x; ++i) n *= i;
return n;
}
function binomial(n, k) {
if (k < 0 || k > n) return 0;
if (k === 0) return 1;
if (2 * k > n) return binomial(n, n - k);
let coeff = 1;
for (let i = 1; i <= k; ++i) coeff *= (n - i + 1) / i;
return Math.round(coeff);
}
function permutations(arr) {
const permArr = [];
const usedChars = [];
permuteHelper(arr, permArr, usedChars);
return permArr;
}
function permuteHelper(input, permArr, usedChars) {
for (let i = 0; i < input.length; i++) {
const term = input.splice(i, 1)[0];
usedChars.push(term);
if (input.length === 0) {
permArr.push(usedChars.slice());
}
permuteHelper(input, permArr, usedChars);
input.splice(i, 0, term);
usedChars.pop();
}
}
function subsets(array, length = 0) {
const copy = array.slice(0);
const results = subsetsHelper(copy);
return length ? results.filter((x) => x.length === length) : results;
}
function subsetsHelper(array) {
if (array.length === 1) return [[], array];
const last = array.pop();
const subsets2 = subsetsHelper(array);
const result = [];
for (const s of subsets2) {
result.push(s, [...s, last]);
}
return result;
}
// src/complex.ts
var absStr = (n, suffix) => {
const prefix = n < 0 ? "\u2013" : "";
if (Math.abs(n) === 1 && suffix) return prefix + suffix;
return prefix + Math.abs(n) + (suffix || "");
};
var Complex = class _Complex {
constructor(re = 0, im = 0) {
this.re = re;
this.im = im;
}
get modulus() {
return Math.sqrt(this.re * this.re + this.im * this.im);
}
get argument() {
return Math.atan2(this.im, this.re);
}
get conjugate() {
return new _Complex(this.re, -this.im);
}
/** Returns the ith nth-root of this complex number. */
root(n, i = 0) {
const r = Math.pow(this.modulus, 1 / n);
const th = (this.argument + i * 2 * Math.PI) / n;
return new _Complex(r * Math.cos(th), r * Math.sin(th));
}
toString(precision = 2) {
const re = round(this.re, precision);
const im = round(this.im, precision);
if (im === 0) return absStr(re);
if (re === 0) return absStr(im, "i");
return [absStr(re), im < 0 ? "\u2013" : "+", absStr(Math.abs(im), "i")].join(" ");
}
// ---------------------------------------------------------------------------
add(a) {
return _Complex.sum(this, a);
}
subtract(a) {
return _Complex.difference(this, a);
}
multiply(a) {
return _Complex.product(this, a);
}
divide(a) {
return _Complex.quotient(this, a);
}
/** Calculates the sum of two complex numbers c1 and c2. */
static sum(c1, c2) {
if (typeof c1 === "number") c1 = new _Complex(c1, 0);
if (typeof c2 === "number") c2 = new _Complex(c2, 0);
return new _Complex(c1.re + c2.re, c1.im + c2.im);
}
/** Calculates the difference of two complex numbers c1 and c2. */
static difference(c1, c2) {
if (typeof c1 === "number") c1 = new _Complex(c1, 0);
if (typeof c2 === "number") c2 = new _Complex(c2, 0);
return new _Complex(c1.re - c2.re, c1.im - c2.im);
}
/** Calculates the product of two complex numbers c1 and c2. */
static product(c1, c2) {
if (typeof c1 === "number") c1 = new _Complex(c1, 0);
if (typeof c2 === "number") c2 = new _Complex(c2, 0);
const re = c1.re * c2.re - c1.im * c2.im;
const im = c1.im * c2.re + c1.re * c2.im;
return new _Complex(re, im);
}
/** Calculates the quotient of two complex numbers c1 and c2. */
static quotient(c1, c2) {
if (typeof c1 === "number") c1 = new _Complex(c1, 0);
if (typeof c2 === "number") c2 = new _Complex(c2, 0);
if (Math.abs(c2.re) < Number.EPSILON || Math.abs(c2.im) < Number.EPSILON) {
return new _Complex(Infinity, Infinity);
}
const denominator = c2.re * c2.re + c2.im * c2.im;
const re = (c1.re * c2.re + c1.im * c2.im) / denominator;
const im = (c1.im * c2.re - c1.re * c2.im) / denominator;
return new _Complex(re, im);
}
/** Calculates e^c for a complex number c. */
static exp(c) {
if (typeof c === "number") c = new _Complex(c, 0);
const r = Math.exp(c.re);
return new _Complex(r * Math.cos(c.im), r * Math.sin(c.im));
}
};
// src/number-theory.ts
var import_core = require("@mathigon/core");
function gcd(...numbers) {
const [first, ...rest] = numbers;
if (rest.length > 1) return gcd(first, gcd(...rest));
let a = Math.abs(first);
let b = Math.abs(rest[0]);
while (b) [a, b] = [b, a % b];
return a;
}
function lcm(...numbers) {
const [first, ...rest] = numbers;
if (rest.length > 1) return lcm(first, lcm(...rest));
return Math.abs(first * rest[0]) / gcd(first, rest[0]);
}
function isPrime(n) {
if (n % 1 !== 0 || n < 2) return false;
if (n % 2 === 0) return n === 2;
if (n % 3 === 0) return n === 3;
const m = Math.sqrt(n);
for (let i = 5; i <= m; i += 6) {
if (n % i === 0) return false;
if (n % (i + 2) === 0) return false;
}
return true;
}
function primeFactorisation(n) {
if (n === 1) return [];
if (isPrime(n)) return [n];
const maxf = Math.sqrt(n);
for (let f = 2; f <= maxf; ++f) {
if (n % f === 0) {
return primeFactorisation(f).concat(primeFactorisation(n / f));
}
}
return [];
}
function primeFactors(n) {
return (0, import_core.unique)(primeFactorisation(n));
}
function listPrimes(n = 100) {
if (n < 2) return [];
const result = [2];
for (let i = 3; i <= n; i++) {
let notMultiple = false;
for (const r of result) {
notMultiple = notMultiple || 0 === i % r;
}
if (!notMultiple) result.push(i);
}
return result;
}
function generatePrime(d) {
if (d < 2 || d > 16) throw new Error("Invalid number of digits.");
const lastDigit = [1, 3, 7, 9];
const pow = Math.pow(10, d - 2);
while (true) {
const n = Math.floor(Math.random() * 9 * pow) + pow;
const x = 10 * n + lastDigit[Math.floor(4 * Math.random())];
if (isPrime(x)) return x;
}
}
function goldbach(x) {
if (x === 4) return [2, 2];
let a = x / 2;
let b = x / 2;
if (a % 2 === 0) {
a--;
b++;
}
while (a >= 3) {
if (isPrime(a) && isPrime(b)) return [a, b];
a -= 2;
b += 2;
}
return [-1, -1];
}
function eulerPhi(x) {
if (x <= 0) throw Error("Number should be greater than zero");
let n = x;
for (const p of primeFactors(x)) n *= (p - 1) / p;
return n;
}
// src/xnumber.ts
var FORMAT = /^([0-9\-.]*)([%πkmbtq]?)(\/([0-9\-.]+))?([%π]?)$/;
var tooBig = (x) => x >= Number.MAX_SAFE_INTEGER;
var XNumber = class _XNumber {
/** Only used for fractions and always ≥ 0. */
constructor(num, den, unit) {
this.unit = unit;
this.num = den !== void 0 && den < 0 ? -num : num;
if (den !== void 0 && Math.abs(den) !== 1 && num !== 0) this.den = Math.abs(den);
}
valueOf() {
return this.value;
}
toMixed() {
if (!this.den || this.unit) return this.toString();
const part = Math.abs(this.num) % this.den;
const whole = Math.abs(Math.trunc(this.value));
if (!whole) return this.toString();
return `${this.sign < 0 ? "\u2013" : ""}${whole} ${part}/${this.den}`;
}
toExpr(type, precision = 4) {
const v = this.value;
if (Math.abs(v) >= Number.MAX_VALUE) return "\u221E";
if (tooBig(this.num) || this.den && tooBig(this.den)) type = "decimal";
if (type === "scientific" || Math.abs(v) >= Number.MAX_SAFE_INTEGER) {
const [base, power2] = this.value.toExponential(precision - 1).split("e");
if (Math.abs(+power2) >= precision) {
const isNeg = power2.startsWith("-");
const exp = `${isNeg ? "(" : ""}${isNeg ? power2 : power2.slice(1)}${isNeg ? ")" : ""}`;
return `${base.replace(/\.?0+$/, "")} \xD7 10^${exp}${this.unit || ""}`;
}
}
if (!this.unit && !this.den || type === "decimal" || type === "scientific") {
const formatted = numberFormat(this.value, precision);
return formatted.match(/^[\d.]+$/g) ? formatted : `"${formatted}"`;
} else {
return type === "mixed" ? this.toMixed() : this.toString();
}
}
toString(precision = 4) {
const separators = !this.den && !this.unit;
let num = numberFormat(this.num, this.den ? 0 : precision, separators);
let unit = this.unit || "";
const den = this.den ? `/${numberFormat(this.den, 0, separators)}` : "";
if (num === "0") unit = "";
if (unit === "\u03C0" && !this.den && (num === "1" || num === "\u20131")) num = num.replace("1", "");
return `${num}${den}${unit}`;
}
toMathML() {
let str = `<mn>${this.num}</mn>`;
if (this.den !== void 0) str = `<mfrac>${str}<mn>${this.den}</mn></mfrac>`;
if (this.unit) str += this.unit === "\u03C0" ? `<mi>\u03C0</mi>` : `<mo>%</mo>`;
return str;
}
// ---------------------------------------------------------------------------
/**
* Returns the value of this number as a decimal. For example, 2/5 and 40%
* would both return 0.4.
*/
get value() {
const unit = this.unit === "%" ? 1 / 100 : this.unit === "\u03C0" ? Math.PI : 1;
return this.num * unit / (this.den || 1);
}
get sign() {
return Math.sign(this.num);
}
/** Simplifies fractions, e.g. 4/8 would become 1/2. */
get simplified() {
if (!this.den) return this;
const factor = gcd(Math.abs(this.num), this.den);
return new _XNumber(this.num / factor, this.den / factor, this.unit);
}
/** Returns 1/x of this number. */
get inverse() {
if (!this.den) return new _XNumber(this.den, this.num);
return new _XNumber(1 / this.num, void 0, this.unit);
}
/** Returns -x of this number. */
get negative() {
return new _XNumber(-this.num, this.den, this.unit);
}
get fraction() {
if (this.unit || !isInteger(this.num)) return;
return [this.num, this.den || 1];
}
// ---------------------------------------------------------------------------
/** Parses a number string, e.g. '1/2' or '20.7%'. */
static fromString(s) {
s = s.toLowerCase().replace(/[\s,"]/g, "").replace("\u2013", "-").replace("pi", "\u03C0");
const match = s.match(FORMAT);
if (!match) return;
let suffix = match[2] || match[5] || void 0;
let num = match[1] ? +match[1] : void 0;
const den = match[4] ? +match[4] : void 0;
if (suffix === "\u03C0" && (!match[1] || match[1] === "-")) num = match[1] ? -1 : 1;
if (num === void 0 || isNaN(num)) return;
const power2 = suffix ? "kmbtq".indexOf(suffix) : -1;
if (power2 >= 0) {
num *= 1e3 ** (power2 + 1);
suffix = void 0;
}
if (den === void 0) return new _XNumber(num, void 0, suffix);
if (isNaN(den) || nearlyEquals(den, 0)) return;
if (!isInteger(num) || !isInteger(den)) return new _XNumber(num / den, void 0, suffix);
return new _XNumber(num, den, suffix);
}
/** Converts a decimal into the closest fraction with a given maximum denominator. */
static fractionFromDecimal(x, maxDen = 1e3, precision = 1e-12) {
let n = [1, 0];
let d = [0, 1];
const absX = Math.abs(x);
let rem = absX;
while (Math.abs(n[0] / d[0] - absX) > precision) {
const a = Math.floor(rem);
n = [a * n[0] + n[1], n[0]];
d = [a * d[0] + d[1], d[0]];
if (d[0] > maxDen) return new _XNumber(x);
rem = 1 / (rem - a);
}
if (!nearlyEquals(n[0] / d[0], absX, precision)) return new _XNumber(x);
return new _XNumber(sign(x) * n[0], d[0] === 1 ? void 0 : d[0]);
}
// ---------------------------------------------------------------------------
clamp(min, max) {
const v = this.value;
if (min !== void 0 && v < min) return new _XNumber(min);
if (max !== void 0 && v > max) return new _XNumber(max);
return this;
}
add(a) {
return _XNumber.sum(this, a);
}
subtract(a) {
return _XNumber.difference(this, a);
}
multiply(a) {
return _XNumber.product(this, a);
}
divide(a) {
return _XNumber.quotient(this, a);
}
/** Calculates the sum of two fractions a and b. */
static sum(a, b) {
if (typeof b === "number") b = new _XNumber(b);
if (a.num === 0) return b;
if (a.unit !== b.unit) return new _XNumber(a.value + b.value);
if (!a.den && !b.den) return new _XNumber(a.num + b.num, void 0, a.unit);
if (!a.den) [a, b] = [b, a];
if (!isInteger(b.num)) return new _XNumber(a.value + b.value, void 0, a.unit);
const common = lcm(a.den, b.den || 1);
const fa = common / a.den;
const fb = common / (b.den || 1);
return new _XNumber(a.num * fa + b.num * fb, common, a.unit);
}
/** Calculates the difference of two numbers a and b. */
static difference(a, b) {
if (typeof b === "number") b = new _XNumber(b);
return _XNumber.sum(a, b.negative);
}
/** Calculates the product of two numbers a and b. */
static product(a, b) {
if (typeof b === "number") b = new _XNumber(b);
if (!a.unit && !a.den && isInteger(a.num)) return new _XNumber(a.num * b.num, b.den, b.unit);
if (!b.unit && !b.den && isInteger(b.num)) return new _XNumber(a.num * b.num, a.den, a.unit);
if (a.unit === "\u03C0" || b.unit === "\u03C0" || !isInteger(a.num) || !isInteger(b.num)) return new _XNumber(a.value * b.value);
const units = (a.unit === "%" ? 100 : 1) * (b.unit === "%" ? 100 : 1);
return new _XNumber(a.num * b.num, (a.den || 1) * (b.den || 1) * units);
}
/** Calculates the quotient of two fractions a and b. */
static quotient(a, b) {
if (typeof b === "number") b = new _XNumber(b);
return _XNumber.product(a, b.inverse);
}
};
// src/matrix.ts
var matrix_exports = {};
__export(matrix_exports, {
determinant: () => determinant,
fill: () => fill,
identity: () => identity,
inverse: () => inverse,
product: () => product,
reflection: () => reflection,
rotation: () => rotation,
scalarProduct: () => scalarProduct,
shear: () => shear,
sum: () => sum,
transpose: () => transpose
});
var import_core2 = require("@mathigon/core");
function fill(value, x, y) {
return (0, import_core2.repeat2D)(value, x, y);
}
function identity(n = 2) {
const x = fill(0, n, n);
for (let i = 0; i < n; ++i) x[i][i] = 1;
return x;
}
function rotation(angle) {
const sin = Math.sin(angle);
const cos = Math.cos(angle);
return [[cos, -sin], [sin, cos]];
}
function shear(lambda) {
return [[1, lambda], [0, 1]];
}
function reflection(angle) {
const sin = Math.sin(2 * angle);
const cos = Math.cos(2 * angle);
return [[cos, sin], [sin, -cos]];
}
function sum(...matrices) {
const [M1, ...rest] = matrices;
const M2 = rest.length > 1 ? sum(...rest) : rest[0];
if (M1.length !== M2.length || M1[0].length !== M2[0].length) {
throw new Error("Matrix sizes don\u2019t match");
}
const S = [];
for (let i = 0; i < M1.length; ++i) {
const row = [];
for (let j = 0; j < M1[i].length; ++j) {
row.push(M1[i][j] + M2[i][j]);
}
S.push(row);
}
return S;
}
function scalarProduct(M, v) {
return M.map((row) => row.map((x) => x * v));
}
function product(...matrices) {
const [M1, ...rest] = matrices;
const M2 = rest.length > 1 ? product(...rest) : rest[0];
if (M1[0].length !== M2.length) {
throw new Error("Matrix sizes don\u2019t match.");
}
const P2 = [];
for (let i = 0; i < M1.length; ++i) {
const row = [];
for (let j = 0; j < M2[0].length; ++j) {
let value = 0;
for (let k = 0; k < M2.length; ++k) {
value += M1[i][k] * M2[k][j];
}
row.push(value);
}
P2.push(row);
}
return P2;
}
function transpose(M) {
const T = [];
for (let j = 0; j < M[0].length; ++j) {
const row = [];
for (let i = 0; i < M.length; ++i) {
row.push(M[i][j]);
}
T.push(row);
}
return T;
}
function determinant(M) {
if (M.length !== M[0].length) throw new Error("Not a square matrix.");
const n = M.length;
if (n === 1) return M[0][0];
if (n === 2) return M[0][0] * M[1][1] - M[0][1] * M[1][0];
let det = 0;
for (let j = 0; j < n; ++j) {
let diagLeft = M[0][j];
let diagRight = M[0][j];
for (let i = 1; i < n; ++i) {
diagRight *= M[i][(j + i) % n];
diagLeft *= M[i][(j - i + n) % n];
}
det += diagRight - diagLeft;
}
return det;
}
function inverse(M) {
const n = M.length;
if (n !== M[0].length) throw new Error("Not a square matrix.");
const I = identity(n);
const C = (0, import_core2.tabulate2D)((x, y) => M[x][y], n, n);
for (let i = 0; i < n; ++i) {
let e = C[i][i];
if (nearlyEquals(e, 0)) {
for (let ii = i + 1; ii < n; ++ii) {
if (C[ii][i] !== 0) {
for (let j = 0; j < n; ++j) {
[C[ii][j], C[i][j]] = [C[i][j], C[ii][j]];
[I[ii][j], I[i][j]] = [I[i][j], I[ii][j]];
}
break;
}
}
e = C[i][i];
if (nearlyEquals(e, 0)) throw new Error("Matrix not invertible.");
}
for (let j = 0; j < n; ++j) {
C[i][j] = C[i][j] / e;
I[i][j] = I[i][j] / e;
}
for (let ii = 0; ii < n; ++ii) {
if (ii === i) continue;
const f = C[ii][i];
for (let j = 0; j < n; ++j) {
C[ii][j] -= f * C[i][j];
I[ii][j] -= f * I[i][j];
}
}
}
return I;
}
// src/random.ts
var random_exports = {};
__export(random_exports, {
bernoulli: () => bernoulli,
binomial: () => binomial2,
cauchy: () => cauchy,
chiCDF: () => chiCDF,
exponential: () => exponential,
find: () => find,
geometric: () => geometric,
integer: () => integer,
integrate: () => integrate,
normal: () => normal,
normalPDF: () => normalPDF,
poisson: () => poisson,
shuffle: () => shuffle,
smart: () => smart,
uniform: () => uniform,
weighted: () => weighted
});
var import_core3 = require("@mathigon/core");
function shuffle(a) {
a = a.slice(0);
for (let i = a.length - 1; i > 0; --i) {
const j = Math.floor(Math.random() * (i + 1));
[a[i], a[j]] = [a[j], a[i]];
}
return a;
}
function integer(a, b) {
const start = b === void 0 ? 0 : a;
const length = b === void 0 ? a : b - a + 1;
return start + Math.floor(length * Math.random());
}
function weighted(weights) {
const x = Math.random() * (0, import_core3.total)(weights);
let cum = 0;
return weights.findIndex((w) => (cum += w) >= x);
}
function find(items) {
return items[Math.floor(items.length * Math.random())];
}
var SMART_RANDOM_CACHE = /* @__PURE__ */ new Map();
function smart(n, id) {
if (!id) id = (0, import_core3.uid)();
if (!SMART_RANDOM_CACHE.has(id)) SMART_RANDOM_CACHE.set(id, (0, import_core3.repeat)(1, n));
const cache = SMART_RANDOM_CACHE.get(id);
const x = weighted(cache.map((x2) => x2 * x2));
cache[x] -= 1;
if (cache[x] <= 0) SMART_RANDOM_CACHE.set(id, cache.map((x2) => x2 + 1));
return x;
}
function bernoulli(p = 0.5) {
return Math.random() < p ? 1 : 0;
}
function binomial2(n = 1, p = 0.5) {
let t = 0;
for (let i = 0; i < n; ++i) t += bernoulli(p);
return t;
}
function poisson(l = 1) {
if (l <= 0) return 0;
const L = Math.exp(-l);
let p = 1;
let k = 0;
for (; p > L; ++k) p *= Math.random();
return k - 1;
}
function uniform(a = 0, b = 1) {
return a + (b - a) * Math.random();
}
function normal(m = 0, v = 1) {
const u1 = Math.random();
const u2 = Math.random();
const rand = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
return rand * Math.sqrt(v) + m;
}
function exponential(l = 1) {
return l <= 0 ? 0 : -Math.log(Math.random()) / l;
}
function geometric(p = 0.5) {
if (p <= 0 || p > 1) return void 0;
return Math.floor(Math.log(Math.random()) / Math.log(1 - p));
}
function cauchy() {
let rr;
let v1;
let v2;
do {
v1 = 2 * Math.random() - 1;
v2 = 2 * Math.random() - 1;
rr = v1 * v1 + v2 * v2;
} while (rr >= 1);
return v1 / v2;
}
function normalPDF(x, m = 1, v = 0) {
return Math.exp(-((x - m) ** 2) / (2 * v)) / Math.sqrt(2 * Math.PI * v);
}
var G = 7;
var P = [
0.9999999999998099,
676.5203681218851,
-1259.1392167224028,
771.3234287776531,
-176.6150291621406,
12.507343278686905,
-0.13857109526572012,
9984369578019572e-21,
15056327351493116e-23
];
function gamma(z) {
if (z < 0.5) return Math.PI / (Math.sin(Math.PI * z) * gamma(1 - z));
z -= 1;
let x = P[0];
for (let i = 1; i < G + 2; i++) x += P[i] / (z + i);
const t = z + G + 0.5;
return Math.sqrt(2 * Math.PI) * Math.pow(t, z + 0.5) * Math.exp(-t) * x;
}
function integrate(fn, xMin, xMax, dx = 1) {
let result = 0;
for (let x = xMin; x < xMax; x += dx) {
result += fn(x) * dx || 0;
}
return result;
}
function chiCDF(chi, deg) {
const int = integrate((t) => Math.pow(t, (deg - 2) / 2) * Math.exp(-t / 2), 0, chi);
return 1 - int / Math.pow(2, deg / 2) / gamma(deg / 2);
}
// src/regression.ts
var regression_exports = {};
__export(regression_exports, {
bestPolynomial: () => bestPolynomial,
coefficient: () => coefficient,
exponential: () => exponential2,
linear: () => linear,
logarithmic: () => logarithmic,
polynomial: () => polynomial2,
power: () => power
});
var import_core4 = require("@mathigon/core");
function evaluatePolynomial(regression, x) {
let xs = 1;
let t = regression[0];
for (let i = 1; i < regression.length; ++i) {
xs *= x;
t += xs * regression[i];
}
return t;
}
function linear(data, throughOrigin = false) {
let sX = 0;
let sY = 0;
let sXX = 0;
let sXY = 0;
const len = data.length;
for (let n = 0; n < len; n++) {
sX += data[n][0];
sY += data[n][1];
sXX += data[n][0] * data[n][0];
sXY += data[n][0] * data[n][1];
}
if (throughOrigin) {
const gradient2 = sXY / sXX;
return [0, gradient2];
}
const gradient = (len * sXY - sX * sY) / (len * sXX - sX * sX);
const intercept = sY / len - gradient * sX / len;
return [intercept, gradient];
}
function exponential2(data) {
const sum2 = [0, 0, 0, 0, 0, 0];
for (const d of data) {
sum2[0] += d[0];
sum2[1] += d[1];
sum2[2] += d[0] * d[0] * d[1];
sum2[3] += d[1] * Math.log(d[1]);
sum2[4] += d[0] * d[1] * Math.log(d[1]);
sum2[5] += d[0] * d[1];
}
const denominator = sum2[1] * sum2[2] - sum2[5] * sum2[5];
const a = Math.exp((sum2[2] * sum2[3] - sum2[5] * sum2[4]) / denominator);
const b = (sum2[1] * sum2[4] - sum2[5] * sum2[3]) / denominator;
return [a, b];
}
function logarithmic(data) {
const sum2 = [0, 0, 0, 0];
const len = data.length;
for (const d of data) {
sum2[0] += Math.log(d[0]);
sum2[1] += d[1] * Math.log(d[0]);
sum2[2] += d[1];
sum2[3] += Math.pow(Math.log(d[0]), 2);
}
const b = (len * sum2[1] - sum2[2] * sum2[0]) / (len * sum2[3] - sum2[0] * sum2[0]);
const a = (sum2[2] - b * sum2[0]) / len;
return [a, b];
}
function power(data) {
const sum2 = [0, 0, 0, 0];
const len = data.length;
for (const d of data) {
sum2[0] += Math.log(d[0]);
sum2[1] += Math.log(d[1]) * Math.log(d[0]);
sum2[2] += Math.log(d[1]);
sum2[3] += Math.pow(Math.log(d[0]), 2);
}
const b = (len * sum2[1] - sum2[2] * sum2[0]) / (len * sum2[3] - sum2[0] * sum2[0]);
const a = Math.exp((sum2[2] - b * sum2[0]) / len);
return [a, b];
}
function polynomial2(data, order = 2) {
const X = data.map((d) => (0, import_core4.list)(order + 1).map((p) => Math.pow(d[0], p)));
const XT = transpose(X);
const y = data.map((d) => [d[1]]);
const XTX = product(XT, X);
const inv = inverse(XTX);
const r = product(inv, XT, y);
return r.map((x) => x[0]);
}
function coefficient(data, fn) {
const total4 = data.reduce((sum2, d) => sum2 + d[1], 0);
const mean2 = total4 / data.length;
const ssyy = data.reduce((sum2, d) => sum2 + (d[1] - mean2) ** 2, 0);
const sse = data.reduce((sum2, d) => sum2 + (d[1] - fn(d[0])) ** 2, 0);
return 1 - sse / ssyy;
}
function bestPolynomial(data, threshold = 0.85, maxOrder = 8) {
if (data.length <= 1) return void 0;
for (let i = 1; i < maxOrder; ++i) {
const reg = polynomial2(data, i);
const fn = (x) => evaluatePolynomial(reg, x);
const coeff = coefficient(data, fn);
if (coeff >= threshold) return { order: i, coefficients: reg, fn };
}
return void 0;
}
// src/statistics.ts
var import_core5 = require("@mathigon/core");
function mean(values) {
return values.length ? (0, import_core5.total)(values) / values.length : 0;
}
function quantile(values, p, method = 1) {
const n = values.length;
if (!n) return 0;
const sorted = values.slice(0).sort((a, b) => a - b);
if (p === 0) return sorted[0];
if (p === 1) return sorted[n - 1];
if (![1, 2, 3].includes(method)) throw new RangeError("Invalid quantile method.");
const index = method === 1 ? n * p - 0.5 : (
// Matlab, Mathematica
method === 2 ? (n - 1) * p : (
// Excel, NumPy, Google Docs, R, Python (option)
(n + 1) * p - 1
)
);
if (Number.isInteger(index)) return sorted[index];
const floor = Math.floor(index);
return lerp(sorted[floor], sorted[floor + 1], index - floor);
}
function median(values, method = 1) {
return quantile(values, 0.5, method);
}
function mode(values) {
const counts = /* @__PURE__ */ new Map();
let maxCount = -1;
let result = void 0;
for (const v of values) {
if (!counts.has(v)) counts.set(v, 0);
const newCount = counts.get(v) + 1;
counts.set(v, newCount);
if (newCount === maxCount) {
result = void 0;
} else if (newCount > maxCount) {
maxCount = newCount;
result = v;
}
}
return result;
}
function variance(values) {
if (!values.length) return void 0;
const m = mean(values);
const sum2 = values.reduce((a, v) => a + (v - m) ** 2, 0);
return sum2 / (values.length - 1);
}
function stdDev(values) {
const v = variance(values);
return v ? Math.sqrt(v) : 0;
}
function covariance(aX, aY) {
if (aX.length !== aY.length) throw new Error("Array length mismatch.");
const sum2 = aX.reduce((a, v, i) => a + v * aY[i], 0);
return (sum2 - (0, import_core5.total)(aX) * (0, import_core5.total)(aY) / aX.length) / aX.length;
}
function correlation(aX, aY) {
if (aX.length !== aY.length) throw new Error("Array length mismatch.");
const covarXY = covariance(aX, aY);
const stdDevX = stdDev(aX);
const stdDevY = stdDev(aY);
return covarXY / (stdDevX * stdDevY);
}
// src/vector.ts
var import_core6 = require("@mathigon/core");
var Vector = class _Vector extends Array {
constructor(...args) {
super();
for (const i of args) this.push(i);
}
/** Returns the magnitude of the Vector */
get magnitude() {
let squares = 0;
for (let i = 0; i < this.length; ++i) squares += this[i] ** 2;
return Math.sqrt(squares);
}
/** Returns the unitVector of the Vector */
get unitVector() {
return this.scale(1 / this.magnitude);
}
/** Scales this vector by a factor q. */
scale(q) {
return this.map((x) => q * x);
}
// -------------------------------------------------------------------------
/** Calculates the sum of two vectors v1 and v2. */
static sum(v1, v2) {
if (v1.length !== v2.length) throw new Error("Mismatched vector sizes.");
return v1.map((v, i) => v + v2[i]);
}
/** Calculates the difference of two vectors v1 and v2. */
static difference(v1, v2) {
if (v1.length !== v2.length) throw new Error("Mismatched vector sizes.");
return v1.map((v, i) => v - v2[i]);
}
/** Calculates the element-wise product of two vectors v1 and v2. */
static product(v1, v2) {
if (v1.length !== v2.length) throw new Error("Mismatched vector sizes.");
return v1.map((v, i) => v * v2[i]);
}
/** Calculates the dot product of two vectors v1 and v2. */
static dot(v1, v2) {
return (0, import_core6.total)(_Vector.product(v1, v2));
}
/** Finds the cross product of two 3-dimensional vectors v1 and v2. */
static cross(v1, v2) {
if (v1.length !== 3 || v2.length !== 3) {
throw new Error("Cross product requires vectors of size 3.");
}
return new _Vector(
v1[1] * v2[2] - v1[2] * v2[1],
v1[2] * v2[0] - v1[0] * v2[2],
v1[0] * v2[1] - v1[1] * v2[0]
);
}
/** Checks if two vectors are equal. */
static equals(v1, v2) {
const n = v1.length;
if (n !== v2.length) return false;
for (let i = 0; i < n; ++i) if (!nearlyEquals(v1[i], v2[i])) return false;
return true;
}
};
//# sourceMappingURL=index.cjs.js.map