From b8159a88e07d4b81d43bece7cfdd7d909ddaa943 Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Mon, 28 Mar 2022 22:39:59 -0400 Subject: [PATCH 01/10] Figured out patchelf hack for nixos users --- CONTRIBUTING.md | 9 ++++++++ flake.nix | 1 + .../squiggle-lang/__tests__/Symbolic_test.res | 23 +++++++++++++++++++ packages/squiggle-lang/package.json | 3 ++- .../squiggle-lang/src/rescript/utility/E.res | 4 ++++ 5 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 packages/squiggle-lang/__tests__/Symbolic_test.res 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..cdb178cd --- /dev/null +++ b/packages/squiggle-lang/__tests__/Symbolic_test.res @@ -0,0 +1,23 @@ +open Jest +open Expect +open Js.Array +open SymbolicDist +open E.Sp + +let makeTest = (~only=false, str, item1, item2) => + only + ? Only.test(str, () => expect(item1) -> toEqual(item2)) + : test(str, () => expect(item1) -> toEqual(item2)) + +let normalParams1: SymbolicDistTypes.normal = {mean: 5.0, stdev: 2.0} +let normalParams2: SymbolicDistTypes.normal = {mean: 10.0, stdev: 2.0} +let normalParams3: SymbolicDistTypes.normal = {mean: 20.0, stdev: 2.0} +let range20 = [0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0,17.0,18.0,19.0,20.0] +let forSparkline = (thisPdf, inps) => map(thisPdf, inps) + +describe("normal combine", () => { + let pdf1 = x => Normal.pdf(x, normalParams1) + let forSparkline1 = forSparkline(pdf1, range20) + let x = forSparkline1 -> toString -> sparkly -> Js.Console.log + makeTest("Spark1", 1, 0) +}) diff --git a/packages/squiggle-lang/package.json b/packages/squiggle-lang/package.json index 6755d2d2..edb6803b 100644 --- a/packages/squiggle-lang/package.json +++ b/packages/squiggle-lang/package.json @@ -24,7 +24,8 @@ "mathjs": "10.4.1", "pdfast": "^0.2.0", "rationale": "0.2.0", - "rescript": "^9.1.4" + "rescript": "^9.1.4", + "sparkly": "6.0.0" }, "devDependencies": { "@glennsl/rescript-jest": "^0.9.0", diff --git a/packages/squiggle-lang/src/rescript/utility/E.res b/packages/squiggle-lang/src/rescript/utility/E.res index d17850fd..01c87a28 100644 --- a/packages/squiggle-lang/src/rescript/utility/E.res +++ b/packages/squiggle-lang/src/rescript/utility/E.res @@ -441,3 +441,7 @@ module JsArray = { |> Js.Array.map(Rationale.Option.toExn("Warning: This should not have happened")) let filter = Js.Array.filter } + +module Sp = { + @module("sparkly") @scope("sparkly") external sparkly: string => string = "sparkly" +} From 03318ee2e12937dcc1ba097e3ed4c6aa110a4002 Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Tue, 29 Mar 2022 02:13:52 -0400 Subject: [PATCH 02/10] translated sparkly to rescript, still debugging it tho --- .../squiggle-lang/__tests__/Symbolic_test.res | 3 +- packages/squiggle-lang/package.json | 3 +- .../squiggle-lang/src/rescript/utility/E.res | 4 -- .../src/rescript/utility/Sparklines.res | 51 +++++++++++++++++++ 4 files changed, 53 insertions(+), 8 deletions(-) create mode 100644 packages/squiggle-lang/src/rescript/utility/Sparklines.res diff --git a/packages/squiggle-lang/__tests__/Symbolic_test.res b/packages/squiggle-lang/__tests__/Symbolic_test.res index cdb178cd..8f9f88cd 100644 --- a/packages/squiggle-lang/__tests__/Symbolic_test.res +++ b/packages/squiggle-lang/__tests__/Symbolic_test.res @@ -2,7 +2,6 @@ open Jest open Expect open Js.Array open SymbolicDist -open E.Sp let makeTest = (~only=false, str, item1, item2) => only @@ -18,6 +17,6 @@ let forSparkline = (thisPdf, inps) => map(thisPdf, inps) describe("normal combine", () => { let pdf1 = x => Normal.pdf(x, normalParams1) let forSparkline1 = forSparkline(pdf1, range20) - let x = forSparkline1 -> toString -> sparkly -> Js.Console.log + let x = forSparkline1 -> toString -> Sparklines.sparkly -> Js.Console.log makeTest("Spark1", 1, 0) }) diff --git a/packages/squiggle-lang/package.json b/packages/squiggle-lang/package.json index edb6803b..6755d2d2 100644 --- a/packages/squiggle-lang/package.json +++ b/packages/squiggle-lang/package.json @@ -24,8 +24,7 @@ "mathjs": "10.4.1", "pdfast": "^0.2.0", "rationale": "0.2.0", - "rescript": "^9.1.4", - "sparkly": "6.0.0" + "rescript": "^9.1.4" }, "devDependencies": { "@glennsl/rescript-jest": "^0.9.0", diff --git a/packages/squiggle-lang/src/rescript/utility/E.res b/packages/squiggle-lang/src/rescript/utility/E.res index 01c87a28..d17850fd 100644 --- a/packages/squiggle-lang/src/rescript/utility/E.res +++ b/packages/squiggle-lang/src/rescript/utility/E.res @@ -441,7 +441,3 @@ module JsArray = { |> Js.Array.map(Rationale.Option.toExn("Warning: This should not have happened")) let filter = Js.Array.filter } - -module Sp = { - @module("sparkly") @scope("sparkly") external sparkly: string => string = "sparkly" -} 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..97b25127 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/utility/Sparklines.res @@ -0,0 +1,51 @@ +// Port of Sindre Sorhus' Sparkly to Rescript +// reference implementation: https://github.com/sindresorhus/sparkly +// Omitting rgb "fire" style, so no `chalk` dependency + +type sparklyConfig = { + minimum: option, + maximum: option +} + +let sparkly = ( + numbers: list, + ~options = {minimum: None, maximum: None} +) => { + // if not numbers is not an array, throw typeerror "Expected an array" + + // Unlike reference impl, we assume that all numbers are finite, i.e. no NaN. + let ticks = ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"] + let minimum = switch options.minimum { + | None => Js.Math.minimum(numbers) + | Some(x) => x + } + let maximum = switch options.maximum { + | None => Js.Math.maximum(numbers) + | Some(x) => x + } + + // Use a high tick if data is constant and max is not equal + let ticks = if minimum == maximum && maximum != 0.0 { + [ticks[4]] + } else { + ticks + } + + let toMapWith = number => { + let ret = if (! Js.Number.isFinite(number)) { + " " + } else { + let tickIndex = Js.Math.ceil((number / maximum) * ticks.length) - 1 + + let tickIndex = if maximum == 0.0 || tickIndex < 0 { + 0 + } else { + tickIndex + } + ticks[tickIndex] + } + ret + } + let ret = map(toMapWith, numbers) + Js.Array.joinWith("", ret) +} From 669fb95479a8eb76fa2e45f7377dd2f4eab6f965 Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Tue, 29 Mar 2022 10:04:08 -0400 Subject: [PATCH 03/10] debugged sparklines implementation --- .../squiggle-lang/__tests__/Symbolic_test.res | 4 ++-- .../src/rescript/utility/Sparklines.res | 19 +++++++++---------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Symbolic_test.res b/packages/squiggle-lang/__tests__/Symbolic_test.res index 8f9f88cd..f45e3374 100644 --- a/packages/squiggle-lang/__tests__/Symbolic_test.res +++ b/packages/squiggle-lang/__tests__/Symbolic_test.res @@ -14,9 +14,9 @@ let normalParams3: SymbolicDistTypes.normal = {mean: 20.0, stdev: 2.0} let range20 = [0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0,17.0,18.0,19.0,20.0] let forSparkline = (thisPdf, inps) => map(thisPdf, inps) -describe("normal combine", () => { +describe("Sparklines", () => { let pdf1 = x => Normal.pdf(x, normalParams1) let forSparkline1 = forSparkline(pdf1, range20) - let x = forSparkline1 -> toString -> Sparklines.sparkly -> Js.Console.log + Js.Console.log(Sparklines.sparkly(forSparkline1, ~options={minimum: None, maximum: None})) makeTest("Spark1", 1, 0) }) diff --git a/packages/squiggle-lang/src/rescript/utility/Sparklines.res b/packages/squiggle-lang/src/rescript/utility/Sparklines.res index 97b25127..9f2f780c 100644 --- a/packages/squiggle-lang/src/rescript/utility/Sparklines.res +++ b/packages/squiggle-lang/src/rescript/utility/Sparklines.res @@ -8,19 +8,19 @@ type sparklyConfig = { } let sparkly = ( - numbers: list, + numbers: array, ~options = {minimum: None, maximum: None} ) => { // if not numbers is not an array, throw typeerror "Expected an array" // Unlike reference impl, we assume that all numbers are finite, i.e. no NaN. - let ticks = ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"] + let ticks = ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"]// ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"] let minimum = switch options.minimum { - | None => Js.Math.minimum(numbers) + | None => Js.Math.minMany_float(numbers) | Some(x) => x } let maximum = switch options.maximum { - | None => Js.Math.maximum(numbers) + | None => Js.Math.maxMany_float(numbers) | Some(x) => x } @@ -31,11 +31,9 @@ let sparkly = ( ticks } - let toMapWith = number => { - let ret = if (! Js.Number.isFinite(number)) { - " " - } else { - let tickIndex = Js.Math.ceil((number / maximum) * ticks.length) - 1 + let toMapWith = (number: float) => { + let ret = { + let tickIndex = Js.Math.ceil_int((number /. maximum) *. Belt.Int.toFloat(Belt.Array.length(ticks))) - 1 let tickIndex = if maximum == 0.0 || tickIndex < 0 { 0 @@ -46,6 +44,7 @@ let sparkly = ( } ret } - let ret = map(toMapWith, numbers) + let ret = Belt.Array.map(numbers, toMapWith) + // Belt.Array.reduce(ret, "", (x, y) => x ++ y) Js.Array.joinWith("", ret) } From 49c091043a7559e305625e6b2bc19ef6bb149e0a Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Tue, 29 Mar 2022 10:40:38 -0400 Subject: [PATCH 04/10] second test case --- .../squiggle-lang/__tests__/Symbolic_test.res | 16 ++++++++++++---- .../src/rescript/utility/Sparklines.res | 5 +++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Symbolic_test.res b/packages/squiggle-lang/__tests__/Symbolic_test.res index f45e3374..98032804 100644 --- a/packages/squiggle-lang/__tests__/Symbolic_test.res +++ b/packages/squiggle-lang/__tests__/Symbolic_test.res @@ -9,14 +9,22 @@ let makeTest = (~only=false, str, item1, item2) => : test(str, () => expect(item1) -> toEqual(item2)) let normalParams1: SymbolicDistTypes.normal = {mean: 5.0, stdev: 2.0} -let normalParams2: SymbolicDistTypes.normal = {mean: 10.0, stdev: 2.0} +// let normalParams2: SymbolicDistTypes.normal = {mean: 10.0, stdev: 2.0} let normalParams3: SymbolicDistTypes.normal = {mean: 20.0, stdev: 2.0} let range20 = [0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0,17.0,18.0,19.0,20.0] let forSparkline = (thisPdf, inps) => map(thisPdf, inps) -describe("Sparklines", () => { +describe("Normal with Sparklines", () => { let pdf1 = x => Normal.pdf(x, normalParams1) let forSparkline1 = forSparkline(pdf1, range20) - Js.Console.log(Sparklines.sparkly(forSparkline1, ~options={minimum: None, maximum: None})) - makeTest("Spark1", 1, 0) + makeTest("mean=5", Sparklines.sparkly(forSparkline1, ~options={minimum: None, maximum: None}), `▁▂▃▅███▅▃▂▁▁▁▁▁▁▁▁▁▁▁`) + + let normal4 = Normal.add(normalParams1, normalParams3) + let normalParams4 = switch normal4 { + | #Normal(params) => params + | _ => {mean: 0.0, stdev: 1.0} + } + let pdf4 = x => Normal.pdf(x, normalParams4) + let forSparkline4 = forSparkline(pdf4, range20) + makeTest("mixture of two normals", Sparklines.sparkly(forSparkline4, ~options={minimum: None, maximum: None}), `▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▂▅█`) }) diff --git a/packages/squiggle-lang/src/rescript/utility/Sparklines.res b/packages/squiggle-lang/src/rescript/utility/Sparklines.res index 9f2f780c..35679918 100644 --- a/packages/squiggle-lang/src/rescript/utility/Sparklines.res +++ b/packages/squiggle-lang/src/rescript/utility/Sparklines.res @@ -14,16 +14,17 @@ let sparkly = ( // if not numbers is not an array, throw typeerror "Expected an array" // Unlike reference impl, we assume that all numbers are finite, i.e. no NaN. - let ticks = ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"]// ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"] + let ticks = [`▁`, `▂`, `▃`, `▄`, `▅`, `▆`, `▇`, `█`] let minimum = switch options.minimum { | None => Js.Math.minMany_float(numbers) | Some(x) => x } + // let minimum = E.O.default(Js.Math.minMany_float(numbers)) let maximum = switch options.maximum { | None => Js.Math.maxMany_float(numbers) | Some(x) => x } - + // let maximum = E.O.default(Js.Math.maxMany_float(numbers)) // Use a high tick if data is constant and max is not equal let ticks = if minimum == maximum && maximum != 0.0 { [ticks[4]] From 517a9128e2836fce30c73692a9dc44e0fcea3223 Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Tue, 29 Mar 2022 10:55:36 -0400 Subject: [PATCH 05/10] E.O.default pattern --- .../src/rescript/utility/Sparklines.res | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/utility/Sparklines.res b/packages/squiggle-lang/src/rescript/utility/Sparklines.res index 35679918..222364b7 100644 --- a/packages/squiggle-lang/src/rescript/utility/Sparklines.res +++ b/packages/squiggle-lang/src/rescript/utility/Sparklines.res @@ -15,16 +15,9 @@ let sparkly = ( // Unlike reference impl, we assume that all numbers are finite, i.e. no NaN. let ticks = [`▁`, `▂`, `▃`, `▄`, `▅`, `▆`, `▇`, `█`] - let minimum = switch options.minimum { - | None => Js.Math.minMany_float(numbers) - | Some(x) => x - } - // let minimum = E.O.default(Js.Math.minMany_float(numbers)) - let maximum = switch options.maximum { - | None => Js.Math.maxMany_float(numbers) - | Some(x) => x - } - // let maximum = E.O.default(Js.Math.maxMany_float(numbers)) + + let minimum = E.O.default(Js.Math.minMany_float(numbers), options.minimum) + let maximum = E.O.default(Js.Math.maxMany_float(numbers), options.maximum) // Use a high tick if data is constant and max is not equal let ticks = if minimum == maximum && maximum != 0.0 { [ticks[4]] From bcff646e54c6ae42b1064cfc9d4a7a5b8d2f6848 Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Tue, 29 Mar 2022 11:05:27 -0400 Subject: [PATCH 06/10] cleanup --- .../src/rescript/utility/Sparklines.res | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/utility/Sparklines.res b/packages/squiggle-lang/src/rescript/utility/Sparklines.res index 222364b7..2e5c9cf0 100644 --- a/packages/squiggle-lang/src/rescript/utility/Sparklines.res +++ b/packages/squiggle-lang/src/rescript/utility/Sparklines.res @@ -11,13 +11,13 @@ let sparkly = ( numbers: array, ~options = {minimum: None, maximum: None} ) => { - // if not numbers is not an array, throw typeerror "Expected an array" - // Unlike reference impl, we assume that all numbers are finite, i.e. no NaN. + let ticks = [`▁`, `▂`, `▃`, `▄`, `▅`, `▆`, `▇`, `█`] let minimum = E.O.default(Js.Math.minMany_float(numbers), options.minimum) let maximum = E.O.default(Js.Math.maxMany_float(numbers), options.maximum) + // Use a high tick if data is constant and max is not equal let ticks = if minimum == maximum && maximum != 0.0 { [ticks[4]] @@ -26,19 +26,15 @@ let sparkly = ( } let toMapWith = (number: float) => { - let ret = { - let tickIndex = Js.Math.ceil_int((number /. maximum) *. Belt.Int.toFloat(Belt.Array.length(ticks))) - 1 + let tickIndex = Js.Math.ceil_int((number /. maximum) *. Belt.Int.toFloat(Belt.Array.length(ticks))) - 1 - let tickIndex = if maximum == 0.0 || tickIndex < 0 { + let tickIndex = if maximum == 0.0 || tickIndex < 0 { 0 } else { tickIndex } - ticks[tickIndex] - } - ret + + ticks[tickIndex] } - let ret = Belt.Array.map(numbers, toMapWith) - // Belt.Array.reduce(ret, "", (x, y) => x ++ y) - Js.Array.joinWith("", ret) + Js.Array.joinWith("", Belt.Array.map(numbers, toMapWith)) } From 320b8da91af6aba68408a343ea4fd1e25f84ad59 Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Tue, 29 Mar 2022 15:10:20 -0400 Subject: [PATCH 07/10] most of the refactor based on @OAGr's comments --- .../squiggle-lang/__tests__/Symbolic_test.res | 38 ++++++++++--------- .../squiggle-lang/src/rescript/utility/E.res | 1 + .../src/rescript/utility/Sparklines.res | 33 ++++++++-------- 3 files changed, 37 insertions(+), 35 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Symbolic_test.res b/packages/squiggle-lang/__tests__/Symbolic_test.res index 98032804..7d2076ae 100644 --- a/packages/squiggle-lang/__tests__/Symbolic_test.res +++ b/packages/squiggle-lang/__tests__/Symbolic_test.res @@ -8,23 +8,27 @@ let makeTest = (~only=false, str, item1, item2) => ? Only.test(str, () => expect(item1) -> toEqual(item2)) : test(str, () => expect(item1) -> toEqual(item2)) -let normalParams1: SymbolicDistTypes.normal = {mean: 5.0, stdev: 2.0} -// let normalParams2: SymbolicDistTypes.normal = {mean: 10.0, stdev: 2.0} -let normalParams3: SymbolicDistTypes.normal = {mean: 20.0, stdev: 2.0} -let range20 = [0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0,17.0,18.0,19.0,20.0] -let forSparkline = (thisPdf, inps) => map(thisPdf, inps) +let pdfImage = (thePdf, inps) => map(thePdf, inps) -describe("Normal with Sparklines", () => { - let pdf1 = x => Normal.pdf(x, normalParams1) - let forSparkline1 = forSparkline(pdf1, range20) - makeTest("mean=5", Sparklines.sparkly(forSparkline1, ~options={minimum: None, maximum: None}), `▁▂▃▅███▅▃▂▁▁▁▁▁▁▁▁▁▁▁`) - - let normal4 = Normal.add(normalParams1, normalParams3) - let normalParams4 = switch normal4 { - | #Normal(params) => params - | _ => {mean: 0.0, stdev: 1.0} +let parameterWiseAdditionHelper = (n1: SymbolicDistTypes.normal, n2: SymbolicDistTypes.normal) => { + let normalDistAtSumMeanConstr = Normal.add(n1, n2) + let normalDistAtSumMean: SymbolicDistTypes.normal = switch normalDistAtSumMeanConstr { + | #Normal(params) => params } - let pdf4 = x => Normal.pdf(x, normalParams4) - let forSparkline4 = forSparkline(pdf4, range20) - makeTest("mixture of two normals", Sparklines.sparkly(forSparkline4, ~options={minimum: None, maximum: None}), `▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▂▅█`) + 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 = [0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0,17.0,18.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) + // let sparklineMean15 = pdfImage(pdfNormalDistAtMean15, 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..19febbad 100644 --- a/packages/squiggle-lang/src/rescript/utility/E.res +++ b/packages/squiggle-lang/src/rescript/utility/E.res @@ -323,6 +323,7 @@ module A = { } ) let filter = (o, e) => Js.Array.filter(o, e) + let joinWith = (fill, arr) => Js.Array.joinWith(fill, arr) module O = { let concatSomes = (optionals: array>): array<'a> => diff --git a/packages/squiggle-lang/src/rescript/utility/Sparklines.res b/packages/squiggle-lang/src/rescript/utility/Sparklines.res index 2e5c9cf0..627804ca 100644 --- a/packages/squiggle-lang/src/rescript/utility/Sparklines.res +++ b/packages/squiggle-lang/src/rescript/utility/Sparklines.res @@ -2,31 +2,28 @@ // reference implementation: https://github.com/sindresorhus/sparkly // Omitting rgb "fire" style, so no `chalk` dependency -type sparklyConfig = { - minimum: option, - maximum: option -} - -let sparkly = ( +let create = ( numbers: array, - ~options = {minimum: None, maximum: None} + ~minimum=?, + ~maximum=?, + () ) => { // Unlike reference impl, we assume that all numbers are finite, i.e. no NaN. let ticks = [`▁`, `▂`, `▃`, `▄`, `▅`, `▆`, `▇`, `█`] - let minimum = E.O.default(Js.Math.minMany_float(numbers), options.minimum) - let maximum = E.O.default(Js.Math.maxMany_float(numbers), options.maximum) + let minimum = E.O.default(Js.Math.minMany_float(numbers), minimum) + let maximum = E.O.default(Js.Math.maxMany_float(numbers), maximum) - // Use a high tick if data is constant and max is not equal - let ticks = if minimum == maximum && maximum != 0.0 { - [ticks[4]] - } else { - ticks - } +// // Use a high tick if data is constant and max is not equal to min or zero +// let ticks = if minimum == maximum && maximum != 0.0 { +// [ticks[4]] +// } else { +// ticks +// } - let toMapWith = (number: float) => { - let tickIndex = Js.Math.ceil_int((number /. maximum) *. Belt.Int.toFloat(Belt.Array.length(ticks))) - 1 + let toHeight = (number: float) => { + let tickIndex = Js.Math.ceil_int((number /. maximum) *. (ticks -> Belt.Array.length -> Belt.Int.toFloat)) - 1 let tickIndex = if maximum == 0.0 || tickIndex < 0 { 0 @@ -36,5 +33,5 @@ let sparkly = ( ticks[tickIndex] } - Js.Array.joinWith("", Belt.Array.map(numbers, toMapWith)) + toHeight -> E.A.fmap(numbers) -> (arr => E.A.joinWith("", arr)) } From 50f5256dc53a52c114c1d58bccefd00586191742 Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Tue, 29 Mar 2022 15:27:23 -0400 Subject: [PATCH 08/10] perhaps the final push of PR 124? --- packages/squiggle-lang/__tests__/Symbolic_test.res | 6 +++--- packages/squiggle-lang/src/rescript/utility/E.res | 1 + .../src/rescript/utility/Sparklines.res | 13 ++----------- 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Symbolic_test.res b/packages/squiggle-lang/__tests__/Symbolic_test.res index 7d2076ae..bac4d17b 100644 --- a/packages/squiggle-lang/__tests__/Symbolic_test.res +++ b/packages/squiggle-lang/__tests__/Symbolic_test.res @@ -22,13 +22,13 @@ 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 = [0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0,17.0,18.0,19.0,] + let range20Float = E.A.rangeFloat(0, 20) // [0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0,17.0,18.0,19.0,] let pdfNormalDistAtMean5 = x => Normal.pdf(x, normalDistAtMean5) let sparklineMean5 = pdfImage(pdfNormalDistAtMean5, range20Float) - makeTest("mean=5", Sparklines.create(sparklineMean5, ()), `▁▂▃▅███▅▃▂▁▁▁▁▁▁▁▁▁▁`) + makeTest("mean=5", Sparklines.create(sparklineMean5, ()), `▁▂▃▅███▅▃▂▁▁▁▁▁▁▁▁▁▁▁`) let sparklineMean15 = normalDistAtMean5 -> parameterWiseAdditionHelper(normalDistAtMean10) -> pdfImage(range20Float) // let sparklineMean15 = pdfImage(pdfNormalDistAtMean15, range20Float) - makeTest("parameter-wise addition of two normal distributions", Sparklines.create(sparklineMean15, ()), `▁▁▁▁▁▁▁▁▁▁▂▃▅▇███▇▅▃`) + 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 19febbad..eb366a6d 100644 --- a/packages/squiggle-lang/src/rescript/utility/E.res +++ b/packages/squiggle-lang/src/rescript/utility/E.res @@ -269,6 +269,7 @@ module A = { )) |> Rationale.Result.return } + let rangeFloat = (start, stop) => start -> Belt.Array.rangeBy(stop, ~step=1) -> (arr => fmap(Belt.Int.toFloat, arr)) // This zips while taking the longest elements of each array. let zipMaxLength = (array1, array2) => { diff --git a/packages/squiggle-lang/src/rescript/utility/Sparklines.res b/packages/squiggle-lang/src/rescript/utility/Sparklines.res index 627804ca..09e17e37 100644 --- a/packages/squiggle-lang/src/rescript/utility/Sparklines.res +++ b/packages/squiggle-lang/src/rescript/utility/Sparklines.res @@ -1,6 +1,7 @@ // 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 create = ( numbers: array, @@ -8,30 +9,20 @@ let create = ( ~maximum=?, () ) => { - // Unlike reference impl, we assume that all numbers are finite, i.e. no NaN. - let ticks = [`▁`, `▂`, `▃`, `▄`, `▅`, `▆`, `▇`, `█`] let minimum = E.O.default(Js.Math.minMany_float(numbers), minimum) let maximum = E.O.default(Js.Math.maxMany_float(numbers), maximum) -// // Use a high tick if data is constant and max is not equal to min or zero -// let ticks = if minimum == maximum && maximum != 0.0 { -// [ticks[4]] -// } else { -// ticks -// } - let toHeight = (number: float) => { let tickIndex = Js.Math.ceil_int((number /. maximum) *. (ticks -> Belt.Array.length -> Belt.Int.toFloat)) - 1 - let tickIndex = if maximum == 0.0 || tickIndex < 0 { 0 } else { tickIndex } - ticks[tickIndex] } + toHeight -> E.A.fmap(numbers) -> (arr => E.A.joinWith("", arr)) } From cd5680f2dc034d7bfcf4d7e40914778c29a99590 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Tue, 29 Mar 2022 16:31:08 -0400 Subject: [PATCH 09/10] Refactored Sparklines.res --- .../squiggle-lang/__tests__/Symbolic_test.res | 3 +- .../squiggle-lang/src/rescript/utility/E.res | 6 ++- .../src/rescript/utility/Sparklines.res | 38 +++++++++---------- 3 files changed, 23 insertions(+), 24 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Symbolic_test.res b/packages/squiggle-lang/__tests__/Symbolic_test.res index bac4d17b..8ec3be22 100644 --- a/packages/squiggle-lang/__tests__/Symbolic_test.res +++ b/packages/squiggle-lang/__tests__/Symbolic_test.res @@ -22,13 +22,12 @@ 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,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0,17.0,18.0,19.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) - // let sparklineMean15 = pdfImage(pdfNormalDistAtMean15, 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 eb366a6d..6d2a2ce2 100644 --- a/packages/squiggle-lang/src/rescript/utility/E.res +++ b/packages/squiggle-lang/src/rescript/utility/E.res @@ -269,7 +269,8 @@ module A = { )) |> Rationale.Result.return } - let rangeFloat = (start, stop) => start -> Belt.Array.rangeBy(stop, ~step=1) -> (arr => fmap(Belt.Int.toFloat, arr)) + 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) => { @@ -324,7 +325,7 @@ module A = { } ) let filter = (o, e) => Js.Array.filter(o, e) - let joinWith = (fill, arr) => Js.Array.joinWith(fill, arr) + let joinWith = Js.Array.joinWith module O = { let concatSomes = (optionals: array>): array<'a> => @@ -407,6 +408,7 @@ module A = { : { let _ = Js.Array.push(element, continuous) } + () }) diff --git a/packages/squiggle-lang/src/rescript/utility/Sparklines.res b/packages/squiggle-lang/src/rescript/utility/Sparklines.res index 09e17e37..cc07860f 100644 --- a/packages/squiggle-lang/src/rescript/utility/Sparklines.res +++ b/packages/squiggle-lang/src/rescript/utility/Sparklines.res @@ -3,26 +3,24 @@ // Omitting rgb "fire" style, so no `chalk` dependency // Omitting: NaN handling, special consideration for constant data. -let create = ( - numbers: array, - ~minimum=?, - ~maximum=?, - () -) => { - let ticks = [`▁`, `▂`, `▃`, `▄`, `▅`, `▆`, `▇`, `█`] +let ticks = [`▁`, `▂`, `▃`, `▄`, `▅`, `▆`, `▇`, `█`] - let minimum = E.O.default(Js.Math.minMany_float(numbers), minimum) - let maximum = E.O.default(Js.Math.maxMany_float(numbers), maximum) +let _ticksLength = E.A.length(ticks) - let toHeight = (number: float) => { - let tickIndex = Js.Math.ceil_int((number /. maximum) *. (ticks -> Belt.Array.length -> Belt.Int.toFloat)) - 1 - let tickIndex = if maximum == 0.0 || tickIndex < 0 { - 0 - } else { - tickIndex - } - ticks[tickIndex] - } - - toHeight -> E.A.fmap(numbers) -> (arr => E.A.joinWith("", arr)) +let _heightToTickIndex = (maximum: float, v: float) => { + let v = Js.Math.ceil_int(v /. maximum *. Belt.Int.toFloat(_ticksLength)) - 1 + min(v, 0) +} + +let create = (relativeHeights: array, ~maximum=?, ()) => { + if E.A.length(relativeHeights) === 0 { + "" + } else { + let maximum = maximum |> E.O.default(E.A.max(relativeHeights) |> E.O.toExn("")) + + relativeHeights + |> E.A.fmap(_heightToTickIndex(maximum)) + |> E.A.fmap(r => E.A.get(ticks, r) |> E.O.toExn("")) + |> E.A.joinWith("") + } } From 649f3e833adb6a74f219c7c48685e3f267532d55 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Tue, 29 Mar 2022 17:00:20 -0400 Subject: [PATCH 10/10] Changes as was requested in CR --- packages/squiggle-lang/src/rescript/utility/E.res | 13 +++++++++++-- .../src/rescript/utility/Sparklines.res | 12 ++++++------ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/utility/E.res b/packages/squiggle-lang/src/rescript/utility/E.res index 6d2a2ce2..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 @@ -324,7 +328,7 @@ 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 = { @@ -438,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 index cc07860f..12d509fa 100644 --- a/packages/squiggle-lang/src/rescript/utility/Sparklines.res +++ b/packages/squiggle-lang/src/rescript/utility/Sparklines.res @@ -8,19 +8,19 @@ let ticks = [`▁`, `▂`, `▃`, `▄`, `▅`, `▆`, `▇`, `█`] let _ticksLength = E.A.length(ticks) let _heightToTickIndex = (maximum: float, v: float) => { - let v = Js.Math.ceil_int(v /. maximum *. Belt.Int.toFloat(_ticksLength)) - 1 - min(v, 0) + 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.O.default(E.A.max(relativeHeights) |> E.O.toExn("")) + let maximum = maximum->E.O2.default(E.A.max(relativeHeights)->E.O2.toExn("")) relativeHeights - |> E.A.fmap(_heightToTickIndex(maximum)) - |> E.A.fmap(r => E.A.get(ticks, r) |> E.O.toExn("")) - |> E.A.joinWith("") + ->E.A2.fmap(_heightToTickIndex(maximum)) + ->E.A2.fmap(r => E.A.get(ticks, r)->E.O2.toExn("")) + ->E.A2.joinWith("") } }