diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3694f142..a6b645f8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -36,6 +36,15 @@ You need `yarn`. TODO: fill this out based on all the different packages scripts once they cool down. +## If you're on NixOS + +You'll need to run a command like this in order to get `yarn build` to run, especially in `packages/squiggle-lang`. +```sh +patchelf --set-interpreter $(patchelf --print-interpreter $(which mkdir)) ./node_modules/gentype/gentype.exe +``` + +See [here](https://github.com/NixOS/nixpkgs/issues/107375) + # Pull request protocol Please work against `staging` branch. **Do not** work against `master`. Please do not merge without approval from some subset of Quinn, Sam, and Ozzie; they will be auto-pinged. diff --git a/flake.nix b/flake.nix index fc4595b8..d39ba79a 100644 --- a/flake.nix +++ b/flake.nix @@ -44,6 +44,7 @@ yarn2nix nodePackages.npm nodejs + patchelf (pkgs.vscode-with-extensions.override { vscode = pkgs.vscodium; vscodeExtensions = pkgs.vscode-utils.extensionsFromVscodeMarketplace [ diff --git a/packages/squiggle-lang/__tests__/Symbolic_test.res b/packages/squiggle-lang/__tests__/Symbolic_test.res new file mode 100644 index 00000000..8ec3be22 --- /dev/null +++ b/packages/squiggle-lang/__tests__/Symbolic_test.res @@ -0,0 +1,33 @@ +open Jest +open Expect +open Js.Array +open SymbolicDist + +let makeTest = (~only=false, str, item1, item2) => + only + ? Only.test(str, () => expect(item1) -> toEqual(item2)) + : test(str, () => expect(item1) -> toEqual(item2)) + +let pdfImage = (thePdf, inps) => map(thePdf, inps) + +let parameterWiseAdditionHelper = (n1: SymbolicDistTypes.normal, n2: SymbolicDistTypes.normal) => { + let normalDistAtSumMeanConstr = Normal.add(n1, n2) + let normalDistAtSumMean: SymbolicDistTypes.normal = switch normalDistAtSumMeanConstr { + | #Normal(params) => params + } + x => Normal.pdf(x, normalDistAtSumMean) +} + +describe("Normal distribution with sparklines", () => { + + let normalDistAtMean5: SymbolicDistTypes.normal = {mean: 5.0, stdev: 2.0} + let normalDistAtMean10: SymbolicDistTypes.normal = {mean: 10.0, stdev: 2.0} + let range20Float = E.A.rangeFloat(0, 20) // [0.0,1.0,2.0,3.0,4.0,...19.0,] + + let pdfNormalDistAtMean5 = x => Normal.pdf(x, normalDistAtMean5) + let sparklineMean5 = pdfImage(pdfNormalDistAtMean5, range20Float) + makeTest("mean=5", Sparklines.create(sparklineMean5, ()), `▁▂▃▅███▅▃▂▁▁▁▁▁▁▁▁▁▁▁`) + + let sparklineMean15 = normalDistAtMean5 -> parameterWiseAdditionHelper(normalDistAtMean10) -> pdfImage(range20Float) + makeTest("parameter-wise addition of two normal distributions", Sparklines.create(sparklineMean15, ()), `▁▁▁▁▁▁▁▁▁▁▂▃▅▇███▇▅▃▂`) +}) diff --git a/packages/squiggle-lang/src/rescript/utility/E.res b/packages/squiggle-lang/src/rescript/utility/E.res index d17850fd..71c4c1e4 100644 --- a/packages/squiggle-lang/src/rescript/utility/E.res +++ b/packages/squiggle-lang/src/rescript/utility/E.res @@ -1,5 +1,4 @@ open Rationale.Function.Infix - module FloatFloatMap = { module Id = Belt.Id.MakeComparable({ type t = float @@ -87,6 +86,11 @@ module O = { let max = compare(\">") } +module O2 = { + let default = (a, b) => O.default(b, a) + let toExn = (a, b) => O.toExn(b, a) +} + /* Functions */ module F = { let apply = (a, e) => a |> e @@ -269,6 +273,8 @@ module A = { )) |> Rationale.Result.return } + let rangeFloat = (~step=1, start, stop) => + Belt.Array.rangeBy(start, stop, ~step) |> fmap(Belt.Int.toFloat) // This zips while taking the longest elements of each array. let zipMaxLength = (array1, array2) => { @@ -322,7 +328,8 @@ module A = { | r => Some(r) } ) - let filter = (o, e) => Js.Array.filter(o, e) + let filter = Js.Array.filter + let joinWith = Js.Array.joinWith module O = { let concatSomes = (optionals: array>): array<'a> => @@ -405,6 +412,7 @@ module A = { : { let _ = Js.Array.push(element, continuous) } + () }) @@ -434,6 +442,11 @@ module A = { } } +module A2 = { + let fmap = (a, b) => Array.map(b, a) + let joinWith = (a, b) => A.joinWith(b, a) +} + module JsArray = { let concatSomes = (optionals: Js.Array.t>): Js.Array.t<'a> => optionals diff --git a/packages/squiggle-lang/src/rescript/utility/Sparklines.res b/packages/squiggle-lang/src/rescript/utility/Sparklines.res new file mode 100644 index 00000000..12d509fa --- /dev/null +++ b/packages/squiggle-lang/src/rescript/utility/Sparklines.res @@ -0,0 +1,26 @@ +// Port of Sindre Sorhus' Sparkly to Rescript +// reference implementation: https://github.com/sindresorhus/sparkly +// Omitting rgb "fire" style, so no `chalk` dependency +// Omitting: NaN handling, special consideration for constant data. + +let ticks = [`▁`, `▂`, `▃`, `▄`, `▅`, `▆`, `▇`, `█`] + +let _ticksLength = E.A.length(ticks) + +let _heightToTickIndex = (maximum: float, v: float) => { + let suggestedTickIndex = Js.Math.ceil_int(v /. maximum *. Belt.Int.toFloat(_ticksLength)) - 1 + max(suggestedTickIndex, 0) +} + +let create = (relativeHeights: array, ~maximum=?, ()) => { + if E.A.length(relativeHeights) === 0 { + "" + } else { + let maximum = maximum->E.O2.default(E.A.max(relativeHeights)->E.O2.toExn("")) + + relativeHeights + ->E.A2.fmap(_heightToTickIndex(maximum)) + ->E.A2.fmap(r => E.A.get(ticks, r)->E.O2.toExn("")) + ->E.A2.joinWith("") + } +}