@davepagurek/flo-mat
Version:
Medial / Scale Axis Transform (MAT/SAT) Library.
89 lines (73 loc) • 3.14 kB
text/typescript
// TODO - import from `flo-poly` in the future
import { ddMultDouble2 } from "double-double";
import { ddAddDd } from "double-double";
import { γγ } from '../error-analysis/gamma.js';
// We *have* to do the below❗ The assignee is a getter❗ The assigned is a pure function❗ Otherwise code is too slow❗
const qmd = ddMultDouble2;
const qaq = ddAddDd;
const { abs } = Math;
const γγ3 = γγ(3);
/**
* Deflates the given polynomial *approximately* by removing a factor (x - t).
*
* @param p a polynomial with coefficients given densely as an array of
* double-double precision floating point numbers from highest to lowest power,
* e.g. `[[0,5],[0,-3],[0,0]]` represents the polynomial `5x^2 - 3x`
* @param pE the coefficient-wise absolute error of the input polynomial that
* still need to be multiplied by γγ3, i.e. it is `γγ3` times too big.
* @param t an evaluation point of the polynomial.
*
* @example
* ```typescript
* // The polynomial x^3 - 5x^2 + 8x - 4 has a root at 1 and a double root at 2
* ddDeflate([[0,1], [0,-5], [0,8], [0,-4]], [0,2]); //=> [[0,1], [0,-3], [0,2]]
* ddDeflate([[0,1], [0,-3], [0,2], [0,2]); //=> [[0,1], [0,-1]]
* ddDeflate([[0,1], [0,-1]], [0,1]); //=> [[0,1]]
* ```
*
* @doc
*/
function ddDeflateWithRunningError(
p: number[][],
pE: number[],
t: number): {
coeffs: number[][];
errBound: number[];
} {
//--------------------------------------------------------------------------
// `var` -> a variable
// `$var` -> the double precision approximation to `var`
// `_var` -> the absolute value of $var (a prefix underscore on a variable means absolute value)
// `var_` -> the error in var (a postfix underscore means error bound but should still be multiplied by 3*γ²)
// `_var_` -> means both absolute value and absolute error bound
// recall: `a*b`, where both `a` and `b` have errors |a| and |b| we get for the
// * error bound of (a*b) === a_|b| + |a|b_ + |a*b| (when either of a and b is double)
// * error bound of (a*b) === a_|b| + |a|b_ + 2|a*b| (when both a and b is double-double)
// * error bound of (a+b) === a_ + b_ + |a+b| (when a and/or b is double or double-double)
// * the returned errors need to be multiplied by 3γ² to get the true error
// * can use either `$var` or `var[var.length-1]` (the approx value) in error calculations
// due to multiplication by 3*γ² and not 3*u²
//--------------------------------------------------------------------------
const d = p.length - 1;
const bs = [p[0]]; // coefficients
let b_ = pE[0]; // running error
const bEs = [b_]; // coefficient-wise error bound
for (let i=1; i<d; i++) {
// p[i] + t*bs[i-1];
const a = bs[i-1];
const $m = t*a[1];
const _t = abs(t);
const m_ = _t*b_ + abs($m);
const pi = p[i];
const p_ = pE[i];
b_ = p_ + m_ + abs(pi[1] + $m);
const b = qaq(pi,qmd(t,a));
bs.push(b);
bEs.push(b_);
}
return {
coeffs: bs,
errBound: bEs.map(e => γγ3*e)
};
}
export { ddDeflateWithRunningError }