From fff473b27c38f65346642eb3da4353447fda2f1d Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Mon, 16 Mar 2020 20:20:39 +0000 Subject: [PATCH] Small changes to hopefully improve CDF.re --- src/distributions/Distributions.re | 3 +- src/distributions/XYShape.re | 78 ++++++++++++++++++++++-------- src/utility/E.re | 13 ++++- src/utility/Guesstimator.re | 2 +- src/utility/lib/CDF.re | 18 ++++--- 5 files changed, 83 insertions(+), 31 deletions(-) diff --git a/src/distributions/Distributions.re b/src/distributions/Distributions.re index 1b4c421f..1af451d9 100644 --- a/src/distributions/Distributions.re +++ b/src/distributions/Distributions.re @@ -112,8 +112,7 @@ module Continuous = { let toDiscreteProbabilityMass = _ => 0.0; let pointwiseFmap = (fn, t: t) => t |> xyShape |> XYShape.T.pointwiseMap(fn) |> fromShape; - let truncate = i => - shapeMap(CdfLibrary.Distribution.convertToNewLength(i)); + let truncate = i => shapeMap(XYShape.T.convertToNewLength(i)); let toShape = (t: t): DistTypes.shape => Continuous(t); let xToY = (f, {interpolation, xyShape}: t) => switch (interpolation) { diff --git a/src/distributions/XYShape.re b/src/distributions/XYShape.re index dddd912d..67226d35 100644 --- a/src/distributions/XYShape.re +++ b/src/distributions/XYShape.re @@ -50,7 +50,33 @@ module T = { let findY = (x: float, t: t): float => { // todo: change getIndexBy to realize it's sorted - // Belt.SortArray.binarySearchBy + let firstHigherIndex = + E.A.Sorted.binarySearchFirstElementGreaterIndex(xs(t), x); + let n = + switch (firstHigherIndex) { + | `overMax => maxY(t) |> E.O.default(0.0) + | `underMin => minY(t) |> E.O.default(0.0) + | `firstHigher(firstHigherIndex) => + let lowerOrEqualIndex = + firstHigherIndex - 1 < 0 ? 0 : firstHigherIndex - 1; + let needsInterpolation = xs(t)[lowerOrEqualIndex] != x; + if (needsInterpolation) { + Functions.interpolate( + xs(t)[lowerOrEqualIndex], + xs(t)[firstHigherIndex], + ys(t)[lowerOrEqualIndex], + ys(t)[firstHigherIndex], + x, + ); + } else { + ys(t)[lowerOrEqualIndex]; + }; + }; + n; + }; + + let findYA = (x: float, t: t): float => { + // todo: change getIndexBy to realize it's sorted let firstHigherIndex = Belt.Array.getIndexBy(xs(t), e => e >= x); switch (firstHigherIndex) { | None => maxY(t) |> E.O.default(0.0) @@ -75,25 +101,39 @@ module T = { let findX = (y: float, t: t): float => { let firstHigherIndex = Belt.Array.getIndexBy(ys(t), e => e >= y); - switch (firstHigherIndex) { - | None => maxX(t) |> E.O.default(0.0) - | Some(0) => minX(t) |> E.O.default(0.0) - | Some(firstHigherIndex) => - let lowerOrEqualIndex = - firstHigherIndex - 1 < 0 ? 0 : firstHigherIndex - 1; - let needsInterpolation = ys(t)[lowerOrEqualIndex] != y; - if (needsInterpolation) { - Functions.interpolate( - ys(t)[lowerOrEqualIndex], - ys(t)[firstHigherIndex], - ys(t)[lowerOrEqualIndex], - ys(t)[firstHigherIndex], - y, - ); - } else { - xs(t)[lowerOrEqualIndex]; + let f: float = + switch (firstHigherIndex) { + | None => maxX(t) |> E.O.default(0.0) + | Some(0) => minX(t) |> E.O.default(0.0) + | Some(firstHigherIndex) => + let lowerOrEqualIndex = + firstHigherIndex - 1 < 0 ? 0 : firstHigherIndex - 1; + let needsInterpolation = ys(t)[lowerOrEqualIndex] != y; + if (needsInterpolation) { + Functions.interpolate( + ys(t)[lowerOrEqualIndex], + ys(t)[firstHigherIndex], + ys(t)[lowerOrEqualIndex], + ys(t)[firstHigherIndex], + y, + ); + } else { + xs(t)[lowerOrEqualIndex]; + }; }; - }; + f; + }; + + let convertWithAlternativeXs = (newXs: array(float), t: t): t => { + let newYs = Belt.Array.map(newXs, f => findY(f, t)); + {xs: newXs, ys: newYs}; + }; + + let convertToNewLength = (newLength: int, t: t): DistTypes.xyShape => { + Functions.( + range(min(xs(t)), max(xs(t)), newLength) + |> convertWithAlternativeXs(_, t) + ); }; module XtoY = { diff --git a/src/utility/E.re b/src/utility/E.re index d311844a..4d4845bb 100644 --- a/src/utility/E.re +++ b/src/utility/E.re @@ -138,7 +138,6 @@ module J = { let fromNumber = Js.Json.number; module O = { - let fromString = (str: string) => switch (str) { | "" => None @@ -287,6 +286,18 @@ module A = { bringErrorUp |> Belt.Result.map(_, forceOpen); }; }; + + module Sorted = { + let binarySearchFirstElementGreaterIndex = (ar: array('a), el: 'a) => { + let el = Belt.SortArray.binarySearchBy(ar, el, compare); + let el = el < 0 ? el * (-1) - 1 : el; + switch (el) { + | e when e >= length(ar) => `overMax + | e when e == 0 => `underMin + | e => `firstHigher(e) + }; + }; + }; }; module JsArray = { diff --git a/src/utility/Guesstimator.re b/src/utility/Guesstimator.re index b9d85d0c..a4dce3da 100644 --- a/src/utility/Guesstimator.re +++ b/src/utility/Guesstimator.re @@ -131,7 +131,7 @@ let toMixed = ~cuttoff=0.995, (), ) => { - let truncateTo = None; + // let truncateTo = None; let start = Js.Date.now(); let timeMessage = message => Js.log2(message, Js.Date.now() -. start); timeMessage("Starting"); diff --git a/src/utility/lib/CDF.re b/src/utility/lib/CDF.re index e0e5f114..900952e0 100644 --- a/src/utility/lib/CDF.re +++ b/src/utility/lib/CDF.re @@ -35,11 +35,12 @@ module Make = (Config: Config) => { let minY = () => get(ys, 0); let maxY = () => get(ys, len(ys) - 1); let findY = (x: float): float => { - let firstHigherIndex = Belt.Array.getIndexBy(xs, e => e >= x); + let firstHigherIndex = + E.A.Sorted.binarySearchFirstElementGreaterIndex(xs, x); switch (firstHigherIndex) { - | None => maxY() - | Some(0) => minY() - | Some(firstHigherIndex) => + | `overMax => maxY() + | `underMin => minY() + | `firstHigher(firstHigherIndex) => let lowerOrEqualIndex = firstHigherIndex - 1 < 0 ? 0 : firstHigherIndex - 1; let needsInterpolation = get(xs, lowerOrEqualIndex) != x; @@ -57,11 +58,12 @@ module Make = (Config: Config) => { }; }; let findX = (y: float): float => { - let firstHigherIndex = Belt.Array.getIndexBy(ys, e => e >= y); + let firstHigherIndex = + E.A.Sorted.binarySearchFirstElementGreaterIndex(ys, y); switch (firstHigherIndex) { - | None => maxX() - | Some(0) => minX() - | Some(firstHigherIndex) => + | `overMax => maxX() + | `underMin => minX() + | `firstHigher(firstHigherIndex) => let lowerOrEqualIndex = firstHigherIndex - 1 < 0 ? 0 : firstHigherIndex - 1; let needsInterpolation = get(ys, lowerOrEqualIndex) != y;