@mathigon/fermat
Version:
Powerful mathematics and statistics library for JavaScript.
1,151 lines (1,140 loc) • 34.1 kB
JavaScript
var __defProp = Object.defineProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
// 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
import { unique } from "@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 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
});
import { repeat2D, tabulate2D } from "@mathigon/core";
function fill(value, x, y) {
return 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 = 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
});
import { repeat, total, uid } from "@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() * 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 = uid();
if (!SMART_RANDOM_CACHE.has(id)) SMART_RANDOM_CACHE.set(id, 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
});
import { list } from "@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) => 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
import { total as total2 } from "@mathigon/core";
function mean(values) {
return values.length ? total2(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 - total2(aX) * total2(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
import { total as total3 } from "@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 total3(_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;
}
};
export {
Complex,
matrix_exports as Matrix,
random_exports as Random,
regression_exports as Regression,
Vector,
XNumber,
binomial,
clamp,
correlation,
covariance,
cube,
digits,
eulerPhi,
factorial,
gcd,
generatePrime,
goldbach,
isBetween,
isInteger,
isPrime,
lcm,
lerp,
listPrimes,
log,
mean,
median,
mod,
mode,
nearlyEquals,
numberFormat,
parseNumber,
permutations,
polynomial,
primeFactorisation,
primeFactors,
quadratic,
quantile,
round,
roundTo,
scientificFormat,
sign,
square,
stdDev,
subsets,
toOrdinal,
toWord,
variance
};
//# sourceMappingURL=index.esm.js.map