flo-poly
Version:
A practical, root-focused JavaScript polynomial utility library.
276 lines (238 loc) • 8.93 kB
text/typescript
import { fromRoots } from '../../roots/from-roots/double/from-roots.js';
/**
* Arbitrary seed value for the simple random number generator.
*
* @internal
*/
const SEED = 123456789;
/**
* The range for the simple random number generator, i.e. the generated
* numbers will be in [0,RANGE].
*
* @internal
*/
const RANGE = 4294967296;
/**
* Creates a function from the given function with parameters similar
* to flatRoots but with an extra parameter in the beginning indicating
* the length of the array generated by the original function.
*
* @param f
*
* @internal
*/
function createArrFunction(
f: (d: number, a?: number, b?: number, seed?: number, odds?: number) => { p: number[], seed: number }):
(n: number, d: number, a?: number, b?: number, seed?: number, odds?: number) => number[][] {
return function(
n: number,
d: number,
a?: number,
b?: number,
seed = SEED,
odds = 0) {
const res: number[][] = [];
for (let i=0; i<n; i++) {
const v = f(d, a, b, seed, odds);
const p = v.p;
seed = v.seed;
res.push(p);
}
return res;
}
}
/**
* Generates and returns an array of polynomials with random **roots** (with coefficients
* given densely as an array of double floating point numbers from highest to
* lowest power, e.g. `[5,-3,0]` represents the polynomial `5x^2 - 3x`).
*
* * all roots will approximate real values so is not at all representative of
* a natural random root distribution
*
* * the exact same polynomials will be created on each call to this function
* if the same seed is used; this is by design to improve testing.
*
* @param n the number of polynomials to generate.
* @param d the degree of the polynomials
* @param a defaults to 0; the lower bound of the coefficients
* @param b defaults to 1; the upper bound of the coefficients
* @param seed defaults to 123456789; a seed value in [0,4294967296]
* @param odds defaults to 0; the odds that a root will be doubled (applied
* recursively so that some roots could be tripled, etc.
*
* @example
* ```typescript
* flatRootsArr(2,3,0,10); //=> [[1, -17.27247918024659, 97.33487287168995, -179.34094494147305], [1, -14.934967160224915, 57.624514485645406, -14.513933300587215]]
* flatRootsArr(2,3,0,10); //=> [[1, -17.27247918024659, 97.33487287168995, -179.34094494147305], [1, -14.934967160224915, 57.624514485645406, -14.513933300587215]]
* ```
*
* @doc
*/
const flatRootsArr = createArrFunction(flatRoots);
/**
* Generates and returns an array of polynomials with random **coefficients** (with coefficients
* given densely as an array of double floating point numbers from highest to
* lowest power, e.g. `[5,-3,0]` represents the polynomial `5x^2 - 3x`).
*
* * the exact same polynomials will be created on each call to this function
* if the same seed is used; this is by design to improve testing.
*
* @param n the number of polynomials to generate.
* @param d the length of the polynomial coefficients array
* @param a defaults to 0; the lower bound of the coefficients
* @param b defaults to 1; the upper bound of the coefficients
* @param seed defaults to 123456789; a seed value in [0,4294967296]
* @param odds defaults to 0; the odds that a root will be doubled (applied
* recursively so that some roots could be tripled, etc.
*
* @example
* ```typescript
* flatCoefficientsArr(2,3,-2,2); //=> [[0.1749166026711464, -0.20349335670471191, 0.9375684261322021], [1.0617692470550537, -1.8918039798736572, 0.8040215969085693]]
* flatCoefficientsArr(2,3,-2,2); //=> [[0.1749166026711464, -0.20349335670471191, 0.9375684261322021], [1.0617692470550537, -1.8918039798736572, 0.8040215969085693]]
* ```
*
* @doc
*/
const flatCoefficientsArr = createArrFunction(flatCoefficients);
/**
* Returns a quasi-random number to be used as the next input to this function.
*
* * see [stackoverflow](https://stackoverflow.com/questions/3062746/special-simple-random-number-generator)
*
* @param seed
*
* @internal
*/
function predictiveRandom(seed: number): number {
const a = 134775813;
return (a * seed + 1) % RANGE;
}
/**
* Generates a random array of numbers picked from a bounded flat
* distribution (i.e. a rectangular distribution) with specified odds of
* duplication of consecutive values.
*
* @param n the number of values to generate
* @param a defaults to 0; the lower bound of the distribution
* @param b defaults to 1; the upper bound of the distribution
* @param seed defaults to 123456789; a seed
* @param odds defaults to 0; the odds that a number will be doubled (applied
* recursively so that some numbers will be tripled, etc.
*
* @internal
*/
function randomArray(
n: number,
a: number,
b: number,
seed: number,
odds = 0): { vs: number[], seed: number } {
let vs: number[] = [];
for (let i=0; i<n; i++) {
seed = predictiveRandom(seed);
const v = ((seed/RANGE) * (b-a)) + a;
seed = push(seed, vs, v, odds);
}
vs = vs.slice(0,n);
return { vs, seed };
}
/**
* Helper function that will add more numbers to the passed array - modifies the
* values parameter.
*
* @param seed
* @param values an existing array of values - will be modified!
* @param x the number that will be added (possibly multiple times)
* @param odds the odds that the number will be added again (recursively).
*
* @internal
*/
function push(seed: number, values: number[], x: number, odds: number): number {
seed = predictiveRandom(seed);
values.push(x);
if ((seed/RANGE) < odds) {
seed = push(seed, values, x, odds);
}
return seed;
}
/**
* Generates and returns an array of polynomials with random **roots** (with coefficients
* given densely as an array of double floating point numbers from highest to
* lowest power, e.g. `[5,-3,0]` represents the polynomial `5x^2 - 3x`).
*
* * also returns a new seed value that can be used as the input to the next
* call to a predictive random function
*
* * all roots will approximate real values so is not at all representative of
* a natural random root distribution
*
* * the exact same polynomial will be created on each call to this function
* if the same seed is used; this is by design to improve testing.
*
* @param d the degree of the polynomials
* @param a defaults to 0; the lower bound of the coefficients
* @param b defaults to 1; the upper bound of the coefficients
* @param seed defaults to 123456789; a seed value in [0,4294967296]
* @param odds defaults to 0; the odds that a root will be doubled (applied
* recursively so that some roots could be tripled, etc.
*
* @example
* ```typescript
* flatRoots(3,0,10); //=> { p: [1, -17.27247918024659, 97.33487287168995, -179.34094494147305], seed: 939629312 }
* ```
*
* @doc
*/
function flatRoots(
d: number,
a = 0,
b = 1,
seed = SEED,
odds = 0): { p: number[], seed: number } {
const randArr = randomArray(d, a, b, seed, odds);
seed = randArr.seed;
const p = fromRoots(randArr.vs);
return { p, seed };
}
/**
* Generates and returns an array of polynomials with random **coefficients** (with coefficients
* given densely as an array of double floating point numbers from highest to
* lowest power, e.g. `[5,-3,0]` represents the polynomial `5x^2 - 3x`).
*
* * also returns a new seed value that can be used as the input to the next
* call to a predictive random function
*
* * the exact same polynomial will be created on each call to this function
* if the same seed is used; this is by design to improve testing.
*
* @param d the length of the polynomial coefficients array
* @param a defaults to 0; the lower bound of the coefficients
* @param b defaults to 1; the upper bound of the coefficients
* @param seed defaults to 123456789; a seed value in [0,4294967296]
* @param odds defaults to 0; the odds that a root will be doubled (applied
* recursively so that some roots could be tripled, etc.
*
* @example
* ```typescript
* flatCoefficients(3,-5,5); //=> { p: [0.437291506677866, -0.5087333917617798, 2.3439210653305054], seed: 939629312 }
* ```
*
* @doc
*/
function flatCoefficients(
d: number,
a = -1,
b = +1,
seed = SEED): { p: number[], seed: number } {
const randArr = randomArray(d, a, b, seed);
seed = randArr.seed;
const p = randArr.vs;
return { p, seed };
}
export {
flatRoots,
flatRootsArr,
flatCoefficients,
flatCoefficientsArr,
predictiveRandom
}