Discrete.js (7342B)
1 import * as Continuous from "./Continuous.js"; 2 import * as Result from "../utility/result.js"; 3 import * as MixedPoint from "./MixedPoint.js"; 4 import * as Common from "./Common.js"; 5 import { ContinuousShape } from "./Continuous.js"; 6 import * as XYShape from "../XYShape.js"; 7 import { convolutionOperationToFn, } from "./PointSet.js"; 8 import { epsilon_float } from "../magicNumbers.js"; 9 import { random_sample } from "../utility/math.js"; 10 import { MixedShape } from "./Mixed.js"; 11 export class DiscreteShape { 12 constructor(args) { 13 this.xyShape = args.xyShape; 14 this._integralSumCache = args.integralSumCache; 15 this._integralCache = args.integralCache; 16 } 17 get integralCache() { 18 return this._integralCache; 19 } 20 get integralSumCache() { 21 return this._integralSumCache; 22 } 23 withAdjustedIntegralSum(integralSumCache) { 24 return new DiscreteShape({ 25 xyShape: this.xyShape, 26 integralSumCache, 27 integralCache: this.integralCache, 28 }); 29 } 30 shapeMap(fn) { 31 return new DiscreteShape({ 32 xyShape: fn(this.xyShape), 33 integralSumCache: this.integralSumCache, 34 integralCache: this.integralCache, 35 }); 36 } 37 integral() { 38 if (!this._integralCache) { 39 if (XYShape.T.isEmpty(this.xyShape)) { 40 this._integralCache = emptyIntegral(); 41 } 42 else { 43 const ts = this.xyShape; 44 const firstX = XYShape.T.minX(ts); 45 const prependedZeroPoint = { 46 xs: [firstX - epsilon_float], 47 ys: [0], 48 }; 49 const integralShape = XYShape.T.accumulateYs(XYShape.T.concat(prependedZeroPoint, ts), (a, b) => a + b); 50 this._integralCache = Continuous.stepwiseToLinear(new ContinuousShape({ 51 xyShape: integralShape, 52 interpolation: "Stepwise", 53 })); 54 } 55 } 56 return this._integralCache; 57 } 58 integralSum() { 59 return (this._integralSumCache ??= this.integral().lastY()); 60 } 61 integralXtoY(f) { 62 return XYShape.XtoY.linear(this.integral().xyShape, f); 63 } 64 integralYtoX(f) { 65 return XYShape.YtoX.linear(this.integral().xyShape, f); 66 } 67 minX() { 68 return XYShape.T.minX(this.xyShape); 69 } 70 maxX() { 71 return XYShape.T.maxX(this.xyShape); 72 } 73 toDiscreteProbabilityMassFraction() { 74 return 1; 75 } 76 isEqual(t) { 77 return XYShape.T.isEqual(this.xyShape, t.xyShape); 78 } 79 mapY(fn, integralSumCacheFn, integralCacheFn) { 80 return new DiscreteShape({ 81 xyShape: XYShape.T.mapY(this.xyShape, fn), 82 integralSumCache: this.integralSumCache === undefined 83 ? undefined 84 : integralSumCacheFn?.(this.integralSumCache), 85 integralCache: this.integralCache === undefined 86 ? undefined 87 : integralCacheFn?.(this.integralCache), 88 }); 89 } 90 mapYResult(fn, integralSumCacheFn, integralCacheFn) { 91 const result = XYShape.T.mapYResult(this.xyShape, fn); 92 if (!result.ok) { 93 return result; 94 } 95 return Result.Ok(new DiscreteShape({ 96 xyShape: result.value, 97 integralSumCache: this.integralSumCache === undefined 98 ? undefined 99 : integralSumCacheFn?.(this.integralSumCache), 100 integralCache: this.integralCache === undefined 101 ? undefined 102 : integralCacheFn?.(this.integralCache), 103 })); 104 } 105 isEmpty() { 106 return this.xyShape.xs.length === 0; 107 } 108 toContinuous() { 109 return undefined; 110 } 111 toDiscrete() { 112 return this; 113 } 114 toMixed() { 115 return new MixedShape({ 116 continuous: Continuous.empty(), 117 discrete: this, 118 integralSumCache: this.integralSumCache, 119 integralCache: this.integralCache, 120 }); 121 } 122 scaleBy(scale) { 123 return this.mapY((r) => r * scale, (sum) => sum * scale, (cache) => cache.scaleBy(scale)); 124 } 125 normalize() { 126 return this.scaleBy(1 / this.integralSum()).withAdjustedIntegralSum(1); 127 } 128 downsample(i) { 129 const currentLength = XYShape.T.length(this.xyShape); 130 if (i < currentLength && i >= 1 && currentLength > 1) { 131 const sortedByY = XYShape.Zipped.sortByY(XYShape.T.zip(this.xyShape)); 132 const picked = [...sortedByY].reverse().slice(0, i); 133 return new DiscreteShape({ 134 xyShape: XYShape.T.fromZippedArray(XYShape.Zipped.sortByX(picked)), 135 }); 136 } 137 else { 138 return this; 139 } 140 } 141 truncate(leftCutoff, rightCutoff) { 142 return new DiscreteShape({ 143 xyShape: XYShape.T.fromZippedArray(XYShape.Zipped.filterByX(XYShape.T.zip(this.xyShape), (x) => x >= (leftCutoff ?? -Infinity) && x <= (rightCutoff ?? Infinity))), 144 }); 145 } 146 xToY(f) { 147 return MixedPoint.makeDiscrete(XYShape.XtoY.stepwiseIfAtX(this.xyShape, f) ?? 0); 148 } 149 mean() { 150 const s = this.xyShape; 151 return s.xs.reduce((acc, x, i) => acc + x * s.ys[i], 0); 152 } 153 variance() { 154 return XYShape.Analysis.getVarianceDangerously(this, (t) => t.mean(), (t) => t.shapeMap(XYShape.T.square).mean()); 155 } 156 } 157 const emptyIntegral = () => new ContinuousShape({ 158 xyShape: { xs: [-Infinity], ys: [0] }, 159 interpolation: "Stepwise", 160 integralSumCache: 0, 161 integralCache: undefined, 162 }); 163 export const empty = () => new DiscreteShape({ 164 xyShape: XYShape.T.empty, 165 integralSumCache: 0, 166 integralCache: emptyIntegral(), 167 }); 168 export const isFloat = (t) => { 169 if (t.xyShape.ys.length === 1 && t.xyShape.ys[0] === 1) { 170 return true; 171 } 172 return false; 173 }; 174 export const getShape = (t) => t.xyShape; 175 export const combinePointwise = (t1, t2, fn, integralSumCachesFn = () => undefined) => { 176 const combiner = XYShape.PointwiseCombination.combine; 177 return Result.fmap(combiner(XYShape.XtoY.discreteInterpolator, fn, t1.xyShape, t2.xyShape), (x) => new DiscreteShape({ xyShape: x })); 178 }; 179 export const combineAlgebraically = (op, t1, t2) => { 180 const t1s = t1.xyShape; 181 const t2s = t2.xyShape; 182 const t1n = XYShape.T.length(t1s); 183 const t2n = XYShape.T.length(t2s); 184 const combinedIntegralSum = Common.combineIntegralSums((s1, s2) => s1 * s2, t1.integralSumCache, t2.integralSumCache); 185 const fn = convolutionOperationToFn(op); 186 const xToYMap = new Map(); 187 for (let i = 0; i <= t1n - 1; i++) { 188 for (let j = 0; j <= t2n - 1; j++) { 189 const x = fn(t1s.xs[i], t2s.xs[j]); 190 const cv = xToYMap.get(x) ?? 0; 191 const my = t1s.ys[i] * t2s.ys[j]; 192 xToYMap.set(x, cv + my); 193 } 194 } 195 const rxys = XYShape.Zipped.sortByX([...xToYMap.entries()]); 196 const combinedShape = XYShape.T.fromZippedArray(rxys); 197 return new DiscreteShape({ 198 xyShape: combinedShape, 199 integralSumCache: combinedIntegralSum, 200 }); 201 }; 202 export const sampleN = (t, n) => { 203 const normalized = t.normalize().xyShape; 204 return random_sample(normalized.xs, { probs: normalized.ys, size: n }); 205 }; 206 //# sourceMappingURL=Discrete.js.map