diff --git a/__tests__/Distributions__Test.re b/__tests__/Distributions__Test.re index a0be6861..8d7dd906 100644 --- a/__tests__/Distributions__Test.re +++ b/__tests__/Distributions__Test.re @@ -16,8 +16,8 @@ describe("Shape", () => { describe("Continuous", () => { open Distributions.Continuous; let continuous = make(shape, `Linear); - makeTest("minX", T.minX(continuous), Some(1.0)); - makeTest("maxX", T.maxX(continuous), Some(8.0)); + makeTest("minX", T.minX(continuous), 1.0); + makeTest("maxX", T.maxX(continuous), 8.0); makeTest( "mapY", T.mapY(r => r *. 2.0, continuous) |> getShape |> (r => r.ys), @@ -127,8 +127,8 @@ describe("Shape", () => { ys: [|0.3, 0.5, 0.2|], }; let discrete = shape; - makeTest("minX", T.minX(discrete), Some(1.0)); - makeTest("maxX", T.maxX(discrete), Some(8.0)); + makeTest("minX", T.minX(discrete), 1.0); + makeTest("maxX", T.maxX(discrete), 8.0); makeTest( "mapY", T.mapY(r => r *. 2.0, discrete) |> (r => r.ys), @@ -210,8 +210,8 @@ describe("Shape", () => { }, ) |> E.O.toExn(""); - makeTest("minX", T.minX(mixed), Some(1.0)); - makeTest("maxX", T.maxX(mixed), Some(14.0)); + makeTest("minX", T.minX(mixed), 1.0); + makeTest("maxX", T.maxX(mixed), 14.0); makeTest( "mapY", T.mapY(r => r *. 2.0, mixed), @@ -320,8 +320,8 @@ describe("Shape", () => { ~guesstimatorString=None, (), ); - makeTest("minX", T.minX(distPlus), Some(1.0)); - makeTest("maxX", T.maxX(distPlus), Some(14.0)); + makeTest("minX", T.minX(distPlus), 1.0); + makeTest("maxX", T.maxX(distPlus), 14.0); makeTest( "xToY at 4.0", T.xToY(4., distPlus), diff --git a/src/components/charts/DistPlusPlot.re b/src/components/charts/DistPlusPlot.re index 79d64e3b..b828eeb6 100644 --- a/src/components/charts/DistPlusPlot.re +++ b/src/components/charts/DistPlusPlot.re @@ -267,11 +267,7 @@ module IntegralChart = { |> Distributions.Continuous.toLinear |> E.O.fmap(Distributions.Continuous.getShape); let range = T.xTotalRange(distPlus); - let minX = - switch (T.minX(distPlus), range) { - | (Some(min), Some(range)) => Some(min -. range *. 0.001) - | _ => None - }; + let minX = T.minX(distPlus) -. range *. 0.001; let maxX = integral |> Distributions.Continuous.T.maxX; let timeScale = distPlus.unit |> DistTypes.DistributionUnit.toJson; option(float); - let maxX: t => option(float); + let minX: t => float; + let maxX: t => float; let mapY: (float => float, t) => t; let xToY: (float, t) => DistTypes.mixedPoint; let toShape: t => DistTypes.shape; @@ -24,11 +24,7 @@ module Dist = (T: dist) => { type integral = T.integral; let minX = T.minX; let maxX = T.maxX; - let xTotalRange = (t: t) => - switch (minX(t), maxX(t)) { - | (Some(min), Some(max)) => Some(max -. min) - | _ => None - }; + let xTotalRange = (t: t) => maxX(t) -. minX(t); let mapY = T.mapY; let xToY = T.xToY; let truncate = T.truncate; @@ -60,7 +56,6 @@ module Dist = (T: dist) => { module Continuous = { type t = DistTypes.continuousShape; - let xyShape = (t: t) => t.xyShape; let getShape = (t: t) => t.xyShape; let interpolation = (t: t) => t.interpolation; let make = (xyShape, interpolation): t => {xyShape, interpolation}; @@ -69,8 +64,7 @@ module Continuous = { xyShape: fn(xyShape), interpolation, }; - let lastY = (t: t) => - t |> xyShape |> XYShape.Pairs.unsafeLast |> (((_, y)) => y); + let lastY = (t: t) => t |> getShape |> XYShape.T.lastY; let oShapeMap = (fn, {xyShape, interpolation}: t): option(DistTypes.continuousShape) => fn(xyShape) |> E.O.fmap(make(_, interpolation)); @@ -84,17 +78,17 @@ module Continuous = { | {interpolation: `Linear, _} => Some(t) }; }; - let shapeFn = (fn, t: t) => t |> xyShape |> fn; + let shapeFn = (fn, t: t) => t |> getShape |> fn; module T = Dist({ type t = DistTypes.continuousShape; type integral = DistTypes.continuousShape; - let minX = shapeFn(XYShape.T.minX); - let maxX = shapeFn(XYShape.T.maxX); + let minX = shapeFn(r => r |> XYShape.T.minX); + let maxX = shapeFn(r => r |> XYShape.T.maxX); let toDiscreteProbabilityMass = _ => 0.0; let mapY = (fn, t: t) => - t |> xyShape |> XYShape.T.mapY(fn) |> fromShape; + t |> getShape |> XYShape.T.mapY(fn) |> fromShape; let toShape = (t: t): DistTypes.shape => Continuous(t); let xToY = (f, {interpolation, xyShape}: t) => switch (interpolation) { @@ -121,7 +115,7 @@ module Continuous = { | Some(cache) => cache | None => t - |> xyShape + |> getShape |> XYShape.Range.integrateWithTriangles |> E.O.toExt("This should not have happened") |> fromShape diff --git a/src/distributions/MixedShapeBuilder.re b/src/distribution/MixedShapeBuilder.re similarity index 100% rename from src/distributions/MixedShapeBuilder.re rename to src/distribution/MixedShapeBuilder.re diff --git a/src/distributions/TimeTypes.re b/src/distribution/TimeTypes.re similarity index 100% rename from src/distributions/TimeTypes.re rename to src/distribution/TimeTypes.re diff --git a/src/distributions/XYShape.re b/src/distribution/XYShape.re similarity index 83% rename from src/distributions/XYShape.re rename to src/distribution/XYShape.re index c9228fd3..3a6676e0 100644 --- a/src/distributions/XYShape.re +++ b/src/distribution/XYShape.re @@ -8,16 +8,19 @@ let interpolate = yMin *. minProportion +. yMax *. maxProportion; }; +// TODO: Make sure that shapes cannot be empty. +let extImp = E.O.toExt("Should not be possible"); + module T = { type t = xyShape; type ts = array(xyShape); let xs = (t: t) => t.xs; let ys = (t: t) => t.ys; - let minX = (t: t) => t |> xs |> E.A.Sorted.min; - let maxX = (t: t) => t |> xs |> E.A.Sorted.max; - let minY = (t: t) => t |> ys |> E.A.Sorted.min; - let maxY = (t: t) => t |> ys |> E.A.Sorted.max; - let xTotalRange = (t: t) => t |> xs |> E.A.Sorted.range; + let minX = (t: t) => t |> xs |> E.A.Sorted.min |> extImp; + let maxX = (t: t) => t |> xs |> E.A.Sorted.max |> extImp; + let firstY = (t: t) => t |> ys |> E.A.first |> extImp; + let lastY = (t: t) => t |> ys |> E.A.last |> extImp; + let xTotalRange = (t: t) => maxX(t) -. minX(t); let mapX = (fn, t: t): t => {xs: E.A.fmap(fn, t.xs), ys: t.ys}; let mapY = (fn, t: t): t => {xs: t.xs, ys: E.A.fmap(fn, t.ys)}; let zip = ({xs, ys}: t) => Belt.Array.zip(xs, ys); @@ -29,11 +32,7 @@ module T = { let fromZippedArray = (pairs: array((float, float))): t => pairs |> Belt.Array.unzip |> fromArray; let equallyDividedXs = (t: t, newLength) => { - E.A.Floats.range( - minX(t) |> E.O.toExt("Unsafe"), - maxX(t) |> E.O.toExt("Unsafe"), - newLength, - ); + E.A.Floats.range(minX(t), maxX(t), newLength); }; let toJs = (t: t) => { {"xs": t.xs, "ys": t.ys}; @@ -42,18 +41,8 @@ module T = { module Ts = { type t = T.ts; - let minX = (t: t) => - t - |> E.A.fmap(T.minX) - |> E.A.O.concatSomes - |> E.A.min - |> E.O.toExt("Unsafe"); - let maxX = (t: t) => - t - |> E.A.fmap(T.maxX) - |> E.A.O.concatSomes - |> E.A.max - |> E.O.toExt("Unsafe"); + let minX = (t: t) => t |> E.A.fmap(T.minX) |> E.A.min |> extImp; + let maxX = (t: t) => t |> E.A.fmap(T.maxX) |> E.A.max |> extImp; let equallyDividedXs = (t: t, newLength) => { E.A.Floats.range(minX(t), maxX(t), newLength); }; @@ -63,19 +52,8 @@ module Ts = { module Pairs = { let x = fst; let y = snd; - let first = (t: T.t) => - switch (T.minX(t), T.minY(t)) { - | (Some(x), Some(y)) => Some((x, y)) - | _ => None - }; - let last = (t: T.t) => - switch (T.maxX(t), T.maxY(t)) { - | (Some(x), Some(y)) => Some((x, y)) - | _ => None - }; - - let unsafeFirst = (t: T.t) => first(t) |> E.O.toExn("Unsafe operation"); - let unsafeLast = (t: T.t) => last(t) |> E.O.toExn("Unsafe operation"); + let first = (t: T.t) => (T.minX(t), T.firstY(t)); + let last = (t: T.t) => (T.maxX(t), T.lastY(t)); let getBy = (t: T.t, fn) => t |> T.zip |> E.A.getBy(_, fn); @@ -99,8 +77,8 @@ module YtoX = { E.A.Sorted.binarySearchFirstElementGreaterIndex(T.ys(t), y); let foundX = switch (firstHigherIndex) { - | `overMax => T.maxX(t) |> E.O.default(0.0) - | `underMin => T.minX(t) |> E.O.default(0.0) + | `overMax => T.maxX(t) + | `underMin => T.minX(t) | `firstHigher(firstHigherIndex) => let lowerOrEqualIndex = firstHigherIndex - 1 < 0 ? 0 : firstHigherIndex - 1; @@ -135,8 +113,8 @@ module XtoY = { E.A.Sorted.binarySearchFirstElementGreaterIndex(T.xs(t), x); let n = switch (firstHigherIndex) { - | `overMax => T.maxY(t) |> E.O.default(0.0) - | `underMin => T.minY(t) |> E.O.default(0.0) + | `overMax => T.lastY(t) + | `underMin => T.firstY(t) | `firstHigher(firstHigherIndex) => let lowerOrEqualIndex = firstHigherIndex - 1 < 0 ? 0 : firstHigherIndex - 1; @@ -180,10 +158,10 @@ module XsConversion = { module Zipped = { type zipped = array((float, float)); - let sortByY = (t: zipped) => - t |> E.A.stableSortBy(_, ((_, y1), (_, y2)) => y1 > y2 ? 1 : 0); - let sortByX = (t: zipped) => - t |> E.A.stableSortBy(_, ((x1, _), (x2, _)) => x1 > x2 ? 1 : 0); + let compareYs = ((_, y1), (_, y2)) => y1 > y2 ? 1 : 0; + let compareXs = ((x1, _), (x2, _)) => x1 > x2 ? 1 : 0; + let sortByY = (t: zipped) => t |> E.A.stableSortBy(_, compareYs); + let sortByX = (t: zipped) => t |> E.A.stableSortBy(_, compareXs); }; module Combine = { @@ -282,10 +260,10 @@ module Range = { // TODO: It would be nicer if this the diff didn't change the first element, and also maybe if there were a more elegant way of doing this. let stepsToContinuous = t => { - let diff = T.xTotalRange(t) |> E.O.fmap(r => r *. 0.00001); + let diff = T.xTotalRange(t) |> (r => r *. 0.00001); let items = - switch (diff, E.A.toRanges(Belt.Array.zip(t.xs, t.ys))) { - | (Some(diff), Ok(items)) => + switch (E.A.toRanges(Belt.Array.zip(t.xs, t.ys))) { + | Ok(items) => Some( items |> Belt.Array.map(_, rangePointAssumingSteps) @@ -321,5 +299,5 @@ let logScorePoint = (sampleCount, t1, t2) => ) |> Range.integrateWithTriangles |> E.O.fmap(T.accumulateYs((+.))) - |> E.O.bind(_, Pairs.last) + |> E.O.fmap(Pairs.last) |> E.O.fmap(Pairs.y); \ No newline at end of file diff --git a/src/utility/E.re b/src/utility/E.re index b245342f..45531457 100644 --- a/src/utility/E.re +++ b/src/utility/E.re @@ -215,7 +215,6 @@ module L = { let toArray = Array.of_list; let fmapi = List.mapi; let concat = List.concat; - let append = List.append; let drop = Rationale.RList.drop; let remove = Rationale.RList.remove; let find = List.find; diff --git a/src/utility/lib/Functions.re b/src/utility/lib/Functions.re deleted file mode 100644 index 5c6317eb..00000000 --- a/src/utility/lib/Functions.re +++ /dev/null @@ -1,7 +0,0 @@ -let interpolate = - (xMin: float, xMax: float, yMin: float, yMax: float, xIntended: float) - : float => { - let minProportion = (xMax -. xIntended) /. (xMax -. xMin); - let maxProportion = (xIntended -. xMin) /. (xMax -. xMin); - yMin *. minProportion +. yMax *. maxProportion; -}; \ No newline at end of file