time-to-botec

Benchmark sampling in different programming languages
Log | Files | Refs | README

Continuous.js (11055B)


      1 import { epsilon_float } from "../magicNumbers.js";
      2 import * as XYShape from "../XYShape.js";
      3 import * as MixedPoint from "./MixedPoint.js";
      4 import * as Result from "../utility/result.js";
      5 import { MixedShape } from "./Mixed.js";
      6 import * as AlgebraicShapeCombination from "./AlgebraicShapeCombination.js";
      7 import * as Common from "./Common.js";
      8 import * as Discrete from "./Discrete.js";
      9 export class ContinuousShape {
     10     constructor(args) {
     11         this.xyShape = args.xyShape;
     12         this.interpolation = args.interpolation ?? "Linear";
     13         this._integralSumCache = args.integralSumCache;
     14         this._integralCache = args.integralCache;
     15     }
     16     get integralCache() {
     17         return this._integralCache;
     18     }
     19     get integralSumCache() {
     20         return this._integralSumCache;
     21     }
     22     withAdjustedIntegralSum(integralSumCache) {
     23         return new ContinuousShape({
     24             xyShape: this.xyShape,
     25             interpolation: this.interpolation,
     26             integralSumCache,
     27             integralCache: this.integralCache,
     28         });
     29     }
     30     lastY() {
     31         return XYShape.T.lastY(this.xyShape);
     32     }
     33     minX() {
     34         return XYShape.T.minX(this.xyShape);
     35     }
     36     maxX() {
     37         return XYShape.T.maxX(this.xyShape);
     38     }
     39     isEqual(t) {
     40         return (XYShape.T.isEqual(this.xyShape, t.xyShape) &&
     41             this.interpolation === t.interpolation);
     42     }
     43     mapY(fn, integralSumCacheFn, integralCacheFn) {
     44         return new ContinuousShape({
     45             xyShape: XYShape.T.mapY(this.xyShape, fn),
     46             interpolation: this.interpolation,
     47             integralSumCache: this.integralSumCache === undefined
     48                 ? undefined
     49                 : integralSumCacheFn?.(this.integralSumCache),
     50             integralCache: this.integralCache === undefined
     51                 ? undefined
     52                 : integralCacheFn?.(this.integralCache),
     53         });
     54     }
     55     mapYResult(fn, integralSumCacheFn, integralCacheFn) {
     56         const result = XYShape.T.mapYResult(this.xyShape, fn);
     57         if (!result.ok) {
     58             return result;
     59         }
     60         return Result.Ok(new ContinuousShape({
     61             xyShape: result.value,
     62             interpolation: this.interpolation,
     63             integralSumCache: this.integralSumCache === undefined
     64                 ? undefined
     65                 : integralSumCacheFn?.(this.integralSumCache),
     66             integralCache: this.integralCache === undefined
     67                 ? undefined
     68                 : integralCacheFn?.(this.integralCache),
     69         }));
     70     }
     71     toDiscreteProbabilityMassFraction() {
     72         return 0;
     73     }
     74     xToY(f) {
     75         switch (this.interpolation) {
     76             case "Stepwise":
     77                 return MixedPoint.makeContinuous(XYShape.XtoY.stepwiseIncremental(this.xyShape, f) ?? 0);
     78             case "Linear":
     79                 return MixedPoint.makeContinuous(XYShape.XtoY.linear(this.xyShape, f));
     80         }
     81     }
     82     truncate(leftCutoff, rightCutoff) {
     83         const lc = leftCutoff ?? -Infinity;
     84         const rc = rightCutoff ?? Infinity;
     85         const truncatedZippedPairs = XYShape.Zipped.filterByX(XYShape.T.zip(this.xyShape), (x) => x >= lc && x <= rc);
     86         const leftNewPoint = leftCutoff === undefined ? [] : [[lc - epsilon_float, 0]];
     87         const rightNewPoint = rightCutoff === undefined ? [] : [[rc + epsilon_float, 0]];
     88         const truncatedZippedPairsWithNewPoints = [
     89             ...leftNewPoint,
     90             ...truncatedZippedPairs,
     91             ...rightNewPoint,
     92         ];
     93         const truncatedShape = XYShape.T.fromZippedArray(truncatedZippedPairsWithNewPoints);
     94         return new ContinuousShape({ xyShape: truncatedShape });
     95     }
     96     integral() {
     97         if (!this._integralCache) {
     98             if (XYShape.T.isEmpty(this.xyShape)) {
     99                 this._integralCache = emptyIntegral();
    100             }
    101             else {
    102                 this._integralCache = new ContinuousShape({
    103                     xyShape: XYShape.Range.integrateWithTriangles(this.xyShape),
    104                 });
    105             }
    106         }
    107         return this._integralCache;
    108     }
    109     integralSum() {
    110         return (this._integralSumCache ??= this.integral().lastY());
    111     }
    112     integralXtoY(f) {
    113         return XYShape.XtoY.linear(this.integral().xyShape, f);
    114     }
    115     integralYtoX(f) {
    116         return XYShape.YtoX.linear(this.integral().xyShape, f);
    117     }
    118     shapeMap(fn) {
    119         return new ContinuousShape({
    120             xyShape: fn(this.xyShape),
    121             interpolation: this.interpolation,
    122             integralSumCache: this.integralSumCache,
    123             integralCache: this.integralCache,
    124         });
    125     }
    126     downsample(length) {
    127         return this.shapeMap((shape) => XYShape.XsConversion.proportionByProbabilityMass(shape, length, this.integral().xyShape));
    128     }
    129     isEmpty() {
    130         return this.xyShape.xs.length === 0;
    131     }
    132     toContinuous() {
    133         return this;
    134     }
    135     toDiscrete() {
    136         return undefined;
    137     }
    138     toMixed() {
    139         return new MixedShape({
    140             continuous: this,
    141             discrete: Discrete.empty(),
    142             integralSumCache: this.integralSumCache,
    143             integralCache: this.integralCache,
    144         });
    145     }
    146     scaleBy(scale) {
    147         return this.mapY((r) => r * scale, (sum) => sum * scale, (cache) => cache.scaleBy(scale));
    148     }
    149     normalize() {
    150         return this.scaleBy(1 / this.integralSum()).withAdjustedIntegralSum(1);
    151     }
    152     mean() {
    153         const indefiniteIntegralStepwise = (p, h1) => (h1 * p ** 2) / 2;
    154         const indefiniteIntegralLinear = (p, a, b) => (a * p ** 2) / 2 + (b * p ** 3) / 3;
    155         return this.integrate(indefiniteIntegralStepwise, indefiniteIntegralLinear);
    156     }
    157     integrate(indefiniteIntegralStepwise = (p, h1) => h1 * p, indefiniteIntegralLinear = (p, a, b) => a * p + (b * p ** 2) / 2) {
    158         const xs = this.xyShape.xs;
    159         const ys = this.xyShape.ys;
    160         let areaUnderIntegral = 0;
    161         for (let i = 1; i < xs.length; i++) {
    162             if (this.interpolation === "Stepwise") {
    163                 areaUnderIntegral +=
    164                     indefiniteIntegralStepwise(xs[i], ys[i - 1]) -
    165                         indefiniteIntegralStepwise(xs[i - 1], ys[i - 1]);
    166             }
    167             else if (this.interpolation === "Linear") {
    168                 const x1 = xs[i - 1];
    169                 const x2 = xs[i];
    170                 if (x1 !== x2) {
    171                     const h1 = ys[i - 1];
    172                     const h2 = ys[i];
    173                     const b = (h1 - h2) / (x1 - x2);
    174                     const a = h1 - b * x1;
    175                     areaUnderIntegral +=
    176                         indefiniteIntegralLinear(x2, a, b) -
    177                             indefiniteIntegralLinear(x1, a, b);
    178                 }
    179             }
    180             else {
    181                 throw new Error(`Unknown interpolation strategy ${this.interpolation}`);
    182             }
    183         }
    184         return areaUnderIntegral;
    185     }
    186     getMeanOfSquares() {
    187         const indefiniteIntegralLinear = (p, a, b) => (a * p ** 3) / 3 + (b * p ** 4) / 4;
    188         const indefiniteIntegralStepwise = (p, h1) => (h1 * p ** 3) / 3;
    189         return this.integrate(indefiniteIntegralStepwise, indefiniteIntegralLinear);
    190     }
    191     variance() {
    192         return XYShape.Analysis.getVarianceDangerously(this, (t) => t.mean(), (t) => t.getMeanOfSquares());
    193     }
    194     downsampleEquallyOverX(length) {
    195         return this.shapeMap((shape) => XYShape.XsConversion.proportionEquallyOverX(shape, length));
    196     }
    197 }
    198 export const Analysis = {};
    199 const emptyIntegral = () => new ContinuousShape({
    200     xyShape: {
    201         xs: [-Infinity],
    202         ys: [0.0],
    203     },
    204     interpolation: "Linear",
    205     integralSumCache: 0,
    206     integralCache: undefined,
    207 });
    208 export const empty = () => new ContinuousShape({
    209     xyShape: XYShape.T.empty,
    210     interpolation: "Linear",
    211     integralSumCache: 0,
    212     integralCache: emptyIntegral(),
    213 });
    214 export const stepwiseToLinear = (t) => {
    215     return new ContinuousShape({
    216         xyShape: XYShape.Range.stepwiseToLinear(t.xyShape),
    217         interpolation: "Linear",
    218         integralSumCache: t.integralSumCache,
    219         integralCache: t.integralCache,
    220     });
    221 };
    222 export const combinePointwise = (t1, t2, fn, distributionType = "PDF", integralSumCachesFn = () => undefined) => {
    223     const combiner = XYShape.PointwiseCombination.combine;
    224     const combinedIntegralSum = Common.combineIntegralSums(integralSumCachesFn, t1.integralSumCache, t2.integralSumCache);
    225     if (t1.interpolation === "Stepwise" && t2.interpolation === "Linear") {
    226         t1 = stepwiseToLinear(t1);
    227     }
    228     else if (t1.interpolation === "Linear" && t2.interpolation === "Stepwise") {
    229         t2 = stepwiseToLinear(t2);
    230     }
    231     const extrapolation = {
    232         PDF: "UseZero",
    233         CDF: "UseOutermostPoints",
    234     }[distributionType];
    235     const interpolator = XYShape.XtoY.continuousInterpolator(t1.interpolation, extrapolation);
    236     return Result.fmap(combiner(interpolator, fn, t1.xyShape, t2.xyShape), (x) => new ContinuousShape({
    237         xyShape: x,
    238         interpolation: "Linear",
    239         integralSumCache: combinedIntegralSum,
    240     }));
    241 };
    242 export const getShape = (t) => t.xyShape;
    243 export const sum = (continuousShapes) => {
    244     return continuousShapes.reduce((x, y) => {
    245         const result = combinePointwise(x, y, (a, b) => Result.Ok(a + b));
    246         if (!result.ok) {
    247             throw new Error("Addition should never fail");
    248         }
    249         return result.value;
    250     }, empty());
    251 };
    252 export const combineAlgebraicallyWithDiscrete = (op, t1, t2, discretePosition) => {
    253     const t1s = t1.xyShape;
    254     const t2s = t2.xyShape;
    255     if (XYShape.T.isEmpty(t1s) || XYShape.T.isEmpty(t2s)) {
    256         return empty();
    257     }
    258     else {
    259         const continuousAsLinear = {
    260             Linear: t1,
    261             Stepwise: stepwiseToLinear(t1),
    262         }[t1.interpolation];
    263         const combinedShape = AlgebraicShapeCombination.combineShapesContinuousDiscrete(op, continuousAsLinear.xyShape, t2s, { discretePosition });
    264         const combinedIntegralSum = op === "Multiply"
    265             ? Common.combineIntegralSums((a, b) => a * b, t1.integralSumCache, t2.integralSumCache)
    266             : undefined;
    267         return new ContinuousShape({
    268             xyShape: combinedShape,
    269             interpolation: t1.interpolation,
    270             integralSumCache: combinedIntegralSum,
    271         });
    272     }
    273 };
    274 export const combineAlgebraically = (op, t1, t2) => {
    275     const s1 = t1.xyShape;
    276     const s2 = t2.xyShape;
    277     const t1n = XYShape.T.length(s1);
    278     const t2n = XYShape.T.length(s2);
    279     if (t1n === 0 || t2n === 0) {
    280         return empty();
    281     }
    282     else {
    283         const combinedShape = AlgebraicShapeCombination.combineShapesContinuousContinuous(op, s1, s2);
    284         const combinedIntegralSum = Common.combineIntegralSums((a, b) => a * b, t1.integralSumCache, t2.integralSumCache);
    285         return new ContinuousShape({
    286             xyShape: combinedShape,
    287             interpolation: "Linear",
    288             integralSumCache: combinedIntegralSum,
    289         });
    290     }
    291 };
    292 //# sourceMappingURL=Continuous.js.map