Merge branch 'develop' into project-component
This commit is contained in:
		
						commit
						d619794cf6
					
				|  | @ -4,15 +4,15 @@ | ||||||
|   "license": "MIT", |   "license": "MIT", | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "@floating-ui/react-dom": "^1.0.0", |     "@floating-ui/react-dom": "^1.0.0", | ||||||
|     "@floating-ui/react-dom-interactions": "^0.9.3", |     "@floating-ui/react-dom-interactions": "^0.10.1", | ||||||
|     "@headlessui/react": "^1.6.6", |     "@headlessui/react": "^1.7.2", | ||||||
|     "@heroicons/react": "^1.0.6", |     "@heroicons/react": "^1.0.6", | ||||||
|     "@hookform/resolvers": "^2.9.8", |     "@hookform/resolvers": "^2.9.8", | ||||||
|     "@quri/squiggle-lang": "^0.4.2", |     "@quri/squiggle-lang": "^0.4.2", | ||||||
|     "@react-hook/size": "^2.1.2", |     "@react-hook/size": "^2.1.2", | ||||||
|     "@types/uuid": "^8.3.4", |     "@types/uuid": "^8.3.4", | ||||||
|     "clsx": "^1.2.1", |     "clsx": "^1.2.1", | ||||||
|     "framer-motion": "^7.3.2", |     "framer-motion": "^7.3.5", | ||||||
|     "lodash": "^4.17.21", |     "lodash": "^4.17.21", | ||||||
|     "react": "^18.1.0", |     "react": "^18.1.0", | ||||||
|     "react-ace": "^10.1.0", |     "react-ace": "^10.1.0", | ||||||
|  | @ -23,25 +23,25 @@ | ||||||
|     "vega": "^5.22.1", |     "vega": "^5.22.1", | ||||||
|     "vega-embed": "^6.21.0", |     "vega-embed": "^6.21.0", | ||||||
|     "vega-lite": "^5.5.0", |     "vega-lite": "^5.5.0", | ||||||
|     "vscode-uri": "^3.0.3", |     "vscode-uri": "^3.0.6", | ||||||
|     "yup": "^0.32.11" |     "yup": "^0.32.11" | ||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "@babel/plugin-proposal-private-property-in-object": "^7.18.6", |     "@babel/plugin-proposal-private-property-in-object": "^7.18.6", | ||||||
|     "@storybook/addon-actions": "^6.5.9", |     "@storybook/addon-actions": "^6.5.12", | ||||||
|     "@storybook/addon-essentials": "^6.5.10", |     "@storybook/addon-essentials": "^6.5.12", | ||||||
|     "@storybook/addon-links": "^6.5.10", |     "@storybook/addon-links": "^6.5.12", | ||||||
|     "@storybook/builder-webpack5": "^6.5.10", |     "@storybook/builder-webpack5": "^6.5.12", | ||||||
|     "@storybook/manager-webpack5": "^6.5.10", |     "@storybook/manager-webpack5": "^6.5.12", | ||||||
|     "@storybook/node-logger": "^6.5.9", |     "@storybook/node-logger": "^6.5.9", | ||||||
|     "@storybook/preset-create-react-app": "^4.1.2", |     "@storybook/preset-create-react-app": "^4.1.2", | ||||||
|     "@storybook/react": "^6.5.10", |     "@storybook/react": "^6.5.12", | ||||||
|     "@testing-library/jest-dom": "^5.16.5", |     "@testing-library/jest-dom": "^5.16.5", | ||||||
|     "@testing-library/react": "^13.4.0", |     "@testing-library/react": "^13.4.0", | ||||||
|     "@testing-library/user-event": "^14.4.3", |     "@testing-library/user-event": "^14.4.3", | ||||||
|     "@types/jest": "^27.5.0", |     "@types/jest": "^27.5.0", | ||||||
|     "@types/lodash": "^4.14.185", |     "@types/lodash": "^4.14.185", | ||||||
|     "@types/node": "^18.7.16", |     "@types/node": "^18.7.18", | ||||||
|     "@types/react": "^18.0.18", |     "@types/react": "^18.0.18", | ||||||
|     "@types/styled-components": "^5.1.26", |     "@types/styled-components": "^5.1.26", | ||||||
|     "@types/webpack": "^5.28.0", |     "@types/webpack": "^5.28.0", | ||||||
|  | @ -50,15 +50,15 @@ | ||||||
|     "postcss-cli": "^10.0.0", |     "postcss-cli": "^10.0.0", | ||||||
|     "postcss-import": "^15.0.0", |     "postcss-import": "^15.0.0", | ||||||
|     "postcss-loader": "^7.0.1", |     "postcss-loader": "^7.0.1", | ||||||
|     "postcss-nesting": "^10.1.10", |     "postcss-nesting": "^10.2.0", | ||||||
|     "react": "^18.1.0", |     "react": "^18.1.0", | ||||||
|     "react-scripts": "^5.0.1", |     "react-scripts": "^5.0.1", | ||||||
|     "style-loader": "^3.3.1", |     "style-loader": "^3.3.1", | ||||||
|     "tailwindcss": "^3.1.8", |     "tailwindcss": "^3.1.8", | ||||||
|     "ts-loader": "^9.3.0", |     "ts-loader": "^9.4.0", | ||||||
|     "tsconfig-paths-webpack-plugin": "^4.0.0", |     "tsconfig-paths-webpack-plugin": "^4.0.0", | ||||||
|     "typescript": "^4.8.3", |     "typescript": "^4.8.3", | ||||||
|     "web-vitals": "^3.0.1", |     "web-vitals": "^3.0.2", | ||||||
|     "webpack": "^5.74.0", |     "webpack": "^5.74.0", | ||||||
|     "webpack-cli": "^4.10.0", |     "webpack-cli": "^4.10.0", | ||||||
|     "webpack-dev-server": "^4.11.0" |     "webpack-dev-server": "^4.11.0" | ||||||
|  |  | ||||||
|  | @ -9,22 +9,28 @@ let prepareInputs = (ar, minWeight) => | ||||||
| describe("Continuous and discrete splits", () => { | describe("Continuous and discrete splits", () => { | ||||||
|   makeTest( |   makeTest( | ||||||
|     "is empty, with no common elements", |     "is empty, with no common elements", | ||||||
|     prepareInputs([1.432, 1.33455, 2.0], 2), |     prepareInputs([1.33455, 1.432, 2.0], 2), | ||||||
|     ([1.33455, 1.432, 2.0], []), |     ([1.33455, 1.432, 2.0], []), | ||||||
|   ) |   ) | ||||||
| 
 | 
 | ||||||
|   makeTest( |   makeTest( | ||||||
|     "only stores 3.5 as discrete when minWeight is 3", |     "only stores 3.5 as discrete when minWeight is 3", | ||||||
|     prepareInputs([1.432, 1.33455, 2.0, 2.0, 3.5, 3.5, 3.5], 3), |     prepareInputs([1.33455, 1.432, 2.0, 2.0, 3.5, 3.5, 3.5], 3), | ||||||
|     ([1.33455, 1.432, 2.0, 2.0], [(3.5, 3.0)]), |     ([1.33455, 1.432, 2.0, 2.0], [(3.5, 3.0)]), | ||||||
|   ) |   ) | ||||||
| 
 | 
 | ||||||
|   makeTest( |   makeTest( | ||||||
|     "doesn't store 3.5 as discrete when minWeight is 5", |     "doesn't store 3.5 as discrete when minWeight is 5", | ||||||
|     prepareInputs([1.432, 1.33455, 2.0, 2.0, 3.5, 3.5, 3.5], 5), |     prepareInputs([1.33455, 1.432, 2.0, 2.0, 3.5, 3.5, 3.5], 5), | ||||||
|     ([1.33455, 1.432, 2.0, 2.0, 3.5, 3.5, 3.5], []), |     ([1.33455, 1.432, 2.0, 2.0, 3.5, 3.5, 3.5], []), | ||||||
|   ) |   ) | ||||||
| 
 | 
 | ||||||
|  |   makeTest( | ||||||
|  |     "more general test", | ||||||
|  |     prepareInputs([10., 10., 11., 11., 11., 12., 13., 13., 13., 13., 13., 14.], 3), | ||||||
|  |     ([10., 10., 12., 14.], [(11., 3.), (13., 5.)]), | ||||||
|  |   ) | ||||||
|  | 
 | ||||||
|   let makeDuplicatedArray = count => { |   let makeDuplicatedArray = count => { | ||||||
|     let arr = Belt.Array.range(1, count) |> E.A.fmap(float_of_int) |     let arr = Belt.Array.range(1, count) |> E.A.fmap(float_of_int) | ||||||
|     let sorted = arr |> Belt.SortArray.stableSortBy(_, compare) |     let sorted = arr |> Belt.SortArray.stableSortBy(_, compare) | ||||||
|  |  | ||||||
|  | @ -45,7 +45,7 @@ | ||||||
|     "@stdlib/stats": "^0.0.13", |     "@stdlib/stats": "^0.0.13", | ||||||
|     "jstat": "^1.9.5", |     "jstat": "^1.9.5", | ||||||
|     "lodash": "^4.17.21", |     "lodash": "^4.17.21", | ||||||
|     "mathjs": "^11.2.0", |     "mathjs": "^11.2.1", | ||||||
|     "pdfast": "^0.2.0" |     "pdfast": "^0.2.0" | ||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|  | @ -67,7 +67,7 @@ | ||||||
|     "rescript": "^9.1.4", |     "rescript": "^9.1.4", | ||||||
|     "rescript-fast-check": "^1.1.1", |     "rescript-fast-check": "^1.1.1", | ||||||
|     "ts-jest": "^27.1.4", |     "ts-jest": "^27.1.4", | ||||||
|     "ts-loader": "^9.3.0", |     "ts-loader": "^9.4.0", | ||||||
|     "ts-node": "^10.9.1", |     "ts-node": "^10.9.1", | ||||||
|     "typescript": "^4.8.3", |     "typescript": "^4.8.3", | ||||||
|     "webpack": "^5.74.0", |     "webpack": "^5.74.0", | ||||||
|  |  | ||||||
|  | @ -1,15 +1,6 @@ | ||||||
| #!/usr/bin/env node
 | #!/usr/bin/env node
 | ||||||
| import { SqProject } from "@quri/squiggle-lang"; | import { SqProject } from "@quri/squiggle-lang"; | ||||||
| 
 | import { measure } from "./lib.mjs"; | ||||||
| const measure = (cb, times = 1) => { |  | ||||||
|   const t1 = new Date(); |  | ||||||
| 
 |  | ||||||
|   for (let i = 1; i <= times; i++) { |  | ||||||
|     cb(); |  | ||||||
|   } |  | ||||||
|   const t2 = new Date(); |  | ||||||
|   return (t2 - t1) / 1000; |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| const maxP = 5; | const maxP = 5; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,15 +1,6 @@ | ||||||
| #!/usr/bin/env node
 | #!/usr/bin/env node
 | ||||||
| import { SqProject } from "@quri/squiggle-lang"; | import { SqProject } from "@quri/squiggle-lang"; | ||||||
| 
 | import { measure } from "./lib.mjs"; | ||||||
| const measure = (cb, times = 1) => { |  | ||||||
|   const t1 = new Date(); |  | ||||||
| 
 |  | ||||||
|   for (let i = 1; i <= times; i++) { |  | ||||||
|     cb(); |  | ||||||
|   } |  | ||||||
|   const t2 = new Date(); |  | ||||||
|   return (t2 - t1) / 1000; |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| const maxP = 7; | const maxP = 7; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										34
									
								
								packages/squiggle-lang/scripts/bench-sampleset-to-pointset.mjs
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										34
									
								
								packages/squiggle-lang/scripts/bench-sampleset-to-pointset.mjs
									
									
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,34 @@ | ||||||
|  | #!/usr/bin/env node
 | ||||||
|  | import { SqProject } from "@quri/squiggle-lang"; | ||||||
|  | import { measure } from "./lib.mjs"; | ||||||
|  | 
 | ||||||
|  | const maxP = 3; | ||||||
|  | 
 | ||||||
|  | const sampleCount = process.env.SAMPLE_COUNT; | ||||||
|  | 
 | ||||||
|  | for (let p = 0; p <= maxP; p++) { | ||||||
|  |   const size = Math.pow(10, p); | ||||||
|  |   const project = SqProject.create(); | ||||||
|  |   if (sampleCount) { | ||||||
|  |     project.setEnvironment({ | ||||||
|  |       sampleCount: Number(sampleCount), | ||||||
|  |       xyPointLength: Number(sampleCount), | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |   project.setSource( | ||||||
|  |     "main", | ||||||
|  |     ` | ||||||
|  |     List.upTo(1, ${size}) -> map( | ||||||
|  |       { |x| normal(x,2) -> SampleSet.fromDist -> PointSet.fromDist } | ||||||
|  |     )->List.last | ||||||
|  |     ` | ||||||
|  |   ); | ||||||
|  |   const time = measure(() => { | ||||||
|  |     project.run("main"); | ||||||
|  |   }); | ||||||
|  |   const result = project.getResult("main"); | ||||||
|  |   if (result.tag != "Ok") { | ||||||
|  |     throw new Error("Code failed: " + result.value.toString()); | ||||||
|  |   } | ||||||
|  |   console.log(`1e${p}`, "\t", time); | ||||||
|  | } | ||||||
							
								
								
									
										41
									
								
								packages/squiggle-lang/scripts/lib.mjs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								packages/squiggle-lang/scripts/lib.mjs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,41 @@ | ||||||
|  | import { SqProject } from "@quri/squiggle-lang"; | ||||||
|  | 
 | ||||||
|  | export const measure = (cb, times = 1) => { | ||||||
|  |   const t1 = new Date(); | ||||||
|  | 
 | ||||||
|  |   for (let i = 1; i <= times; i++) { | ||||||
|  |     cb(); | ||||||
|  |   } | ||||||
|  |   const t2 = new Date(); | ||||||
|  |   return (t2 - t1) / 1000; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export const red = (str) => `\x1b[31m${str}\x1b[0m`; | ||||||
|  | export const green = (str) => `\x1b[32m${str}\x1b[0m`; | ||||||
|  | 
 | ||||||
|  | export const run = (src, { output, sampleCount }) => { | ||||||
|  |   const project = SqProject.create(); | ||||||
|  |   if (sampleCount) { | ||||||
|  |     project.setEnvironment({ | ||||||
|  |       sampleCount: Number(sampleCount), | ||||||
|  |       xyPointLength: Number(sampleCount), | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |   project.setSource("main", src); | ||||||
|  |   const time = measure(() => project.run("main")); | ||||||
|  | 
 | ||||||
|  |   const bindings = project.getBindings("main"); | ||||||
|  |   const result = project.getResult("main"); | ||||||
|  | 
 | ||||||
|  |   if (output) { | ||||||
|  |     console.log("Result:", result.tag, result.value.toString()); | ||||||
|  |     console.log("Bindings:", bindings.toString()); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   console.log( | ||||||
|  |     "Time:", | ||||||
|  |     String(time), | ||||||
|  |     result.tag === "Error" ? red(result.tag) : green(result.tag), | ||||||
|  |     result.tag === "Error" ? result.value.toString() : "" | ||||||
|  |   ); | ||||||
|  | }; | ||||||
|  | @ -1,21 +1,9 @@ | ||||||
| #!/usr/bin/env node
 | #!/usr/bin/env node
 | ||||||
| import { SqProject } from "@quri/squiggle-lang"; |  | ||||||
| import fs from "fs"; | import fs from "fs"; | ||||||
| 
 | 
 | ||||||
| import { Command } from "commander"; | import { Command } from "commander"; | ||||||
| 
 | 
 | ||||||
| const measure = (cb, times = 1) => { | import { run } from "./lib.mjs"; | ||||||
|   const t1 = new Date(); |  | ||||||
| 
 |  | ||||||
|   for (let i = 1; i <= times; i++) { |  | ||||||
|     cb(); |  | ||||||
|   } |  | ||||||
|   const t2 = new Date(); |  | ||||||
|   return (t2 - t1) / 1000; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| const red = (str) => `\x1b[31m${str}\x1b[0m`; |  | ||||||
| const green = (str) => `\x1b[32m${str}\x1b[0m`; |  | ||||||
| 
 | 
 | ||||||
| const program = new Command(); | const program = new Command(); | ||||||
| 
 | 
 | ||||||
|  | @ -24,34 +12,11 @@ program.arguments("<string>"); | ||||||
| 
 | 
 | ||||||
| const options = program.parse(process.argv); | const options = program.parse(process.argv); | ||||||
| 
 | 
 | ||||||
| const project = SqProject.create(); |  | ||||||
| const sampleCount = process.env.SAMPLE_COUNT; | const sampleCount = process.env.SAMPLE_COUNT; | ||||||
| if (sampleCount) { |  | ||||||
|   project.setEnvironment({ |  | ||||||
|     sampleCount: Number(sampleCount), |  | ||||||
|     xyPointLength: Number(sampleCount), |  | ||||||
|   }); |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| const src = fs.readFileSync(program.args[0], "utf-8"); | const src = fs.readFileSync(program.args[0], "utf-8"); | ||||||
| if (!src) { | if (!src) { | ||||||
|   throw new Error("Expected src"); |   throw new Error("Expected src"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| project.setSource("main", src); | run(src, { output: options.output, sampleCount }); | ||||||
| const time = measure(() => project.run("main")); |  | ||||||
| 
 |  | ||||||
| const bindings = project.getBindings("main"); |  | ||||||
| const result = project.getResult("main"); |  | ||||||
| 
 |  | ||||||
| if (options.output) { |  | ||||||
|   console.log("Result:", result.tag, result.value.toString()); |  | ||||||
|   console.log("Bindings:", bindings.toString()); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| console.log( |  | ||||||
|   "Time:", |  | ||||||
|   String(time), |  | ||||||
|   result.tag === "Error" ? red(result.tag) : green(result.tag), |  | ||||||
|   result.tag === "Error" ? result.value.toString() : "" |  | ||||||
| ); |  | ||||||
|  |  | ||||||
|  | @ -1,18 +1,10 @@ | ||||||
| #!/usr/bin/env node
 | #!/usr/bin/env node
 | ||||||
| import { SqProject } from "@quri/squiggle-lang"; | import { run } from "./lib.mjs"; | ||||||
| 
 |  | ||||||
| const project = SqProject.create(); |  | ||||||
| 
 | 
 | ||||||
| const src = process.argv[2]; | const src = process.argv[2]; | ||||||
| if (!src) { | if (!src) { | ||||||
|   throw new Error("Expected src"); |   throw new Error("Expected src"); | ||||||
| } | } | ||||||
| console.log(`Running ${src}`); | console.log(`Running ${src}`); | ||||||
| project.setSource("a", src); |  | ||||||
| project.run("a"); |  | ||||||
| 
 | 
 | ||||||
| const result = project.getResult("a"); | run(src); | ||||||
| console.log(result.tag, result.value.toString()); |  | ||||||
| 
 |  | ||||||
| const bindings = project.getBindings("a"); |  | ||||||
| console.log(bindings.asValue().toString()); |  | ||||||
|  |  | ||||||
|  | @ -33,19 +33,19 @@ module Internals = { | ||||||
| 
 | 
 | ||||||
|   module KDE = { |   module KDE = { | ||||||
|     let normalSampling = (samples, outputXYPoints, kernelWidth) => |     let normalSampling = (samples, outputXYPoints, kernelWidth) => | ||||||
|       samples |> JS.samplesToContinuousPdf(_, outputXYPoints, kernelWidth) |> JS.jsToDist |       samples->JS.samplesToContinuousPdf(outputXYPoints, kernelWidth)->JS.jsToDist | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   module T = { |   module T = { | ||||||
|     type t = array<float> |     type t = array<float> | ||||||
| 
 | 
 | ||||||
|     let xWidthToUnitWidth = (samples, outputXYPoints, xWidth) => { |     let xWidthToUnitWidth = (samples, outputXYPoints, xWidth) => { | ||||||
|       let xyPointRange = E.A.Sorted.range(samples) |> E.O.default(0.0) |       let xyPointRange = E.A.Sorted.range(samples)->E.O2.default(0.0) | ||||||
|       let xyPointWidth = xyPointRange /. float_of_int(outputXYPoints) |       let xyPointWidth = xyPointRange /. float_of_int(outputXYPoints) | ||||||
|       xWidth /. xyPointWidth |       xWidth /. xyPointWidth | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     let formatUnitWidth = w => Jstat.max([w, 1.0]) |> int_of_float |     let formatUnitWidth = w => Jstat.max([w, 1.0])->int_of_float | ||||||
| 
 | 
 | ||||||
|     let suggestedUnitWidth = (samples, outputXYPoints) => { |     let suggestedUnitWidth = (samples, outputXYPoints) => { | ||||||
|       let suggestedXWidth = SampleSetDist_Bandwidth.nrd0(samples) |       let suggestedXWidth = SampleSetDist_Bandwidth.nrd0(samples) | ||||||
|  | @ -62,23 +62,24 @@ let toPointSetDist = ( | ||||||
|   ~samplingInputs: SamplingInputs.samplingInputs, |   ~samplingInputs: SamplingInputs.samplingInputs, | ||||||
|   (), |   (), | ||||||
| ): Internals.Types.outputs => { | ): Internals.Types.outputs => { | ||||||
|   let samples = Js.Array2.copy(samples) |   let samples = samples->Js.Array2.copy->Js.Array2.sortInPlaceWith(compare) | ||||||
|   Array.fast_sort(compare, samples) | 
 | ||||||
|   let minDiscreteToKeep = MagicNumbers.ToPointSet.minDiscreteToKeep(samples) |   let minDiscreteToKeep = MagicNumbers.ToPointSet.minDiscreteToKeep(samples) | ||||||
|   let (continuousPart, discretePart) = E.A.Floats.Sorted.splitContinuousAndDiscreteForMinWeight( |   let (continuousPart, discretePart) = E.A.Floats.Sorted.splitContinuousAndDiscreteForMinWeight( | ||||||
|     samples, |     samples, | ||||||
|     ~minDiscreteWeight=minDiscreteToKeep, |     ~minDiscreteWeight=minDiscreteToKeep, | ||||||
|   ) |   ) | ||||||
|   let length = samples |> E.A.length |> float_of_int | 
 | ||||||
|  |   let length = samples->E.A.length->float_of_int | ||||||
|   let discrete: PointSetTypes.discreteShape = |   let discrete: PointSetTypes.discreteShape = | ||||||
|     discretePart |     discretePart | ||||||
|     |> E.FloatFloatMap.fmap(r => r /. length) |     ->E.FloatFloatMap.fmap(r => r /. length, _) | ||||||
|     |> E.FloatFloatMap.toArray |     ->E.FloatFloatMap.toArray | ||||||
|     |> XYShape.T.fromZippedArray |     ->XYShape.T.fromZippedArray | ||||||
|     |> Discrete.make |     ->Discrete.make | ||||||
| 
 | 
 | ||||||
|   let pdf = |   let pdf = | ||||||
|     continuousPart |> E.A.length > 5 |     continuousPart->E.A.length > 5 | ||||||
|       ? { |       ? { | ||||||
|           let _suggestedXWidth = SampleSetDist_Bandwidth.nrd0(continuousPart) |           let _suggestedXWidth = SampleSetDist_Bandwidth.nrd0(continuousPart) | ||||||
|           // todo: This does some recalculating from the last step. |           // todo: This does some recalculating from the last step. | ||||||
|  | @ -86,7 +87,7 @@ let toPointSetDist = ( | ||||||
|             continuousPart, |             continuousPart, | ||||||
|             samplingInputs.outputXYPoints, |             samplingInputs.outputXYPoints, | ||||||
|           ) |           ) | ||||||
|           let usedWidth = samplingInputs.kernelWidth |> E.O.default(_suggestedXWidth) |           let usedWidth = samplingInputs.kernelWidth->E.O2.default(_suggestedXWidth) | ||||||
|           let usedUnitWidth = Internals.T.xWidthToUnitWidth( |           let usedUnitWidth = Internals.T.xWidthToUnitWidth( | ||||||
|             samples, |             samples, | ||||||
|             samplingInputs.outputXYPoints, |             samplingInputs.outputXYPoints, | ||||||
|  | @ -101,18 +102,18 @@ let toPointSetDist = ( | ||||||
|             bandwidthUnitImplemented: usedUnitWidth, |             bandwidthUnitImplemented: usedUnitWidth, | ||||||
|           } |           } | ||||||
|           continuousPart |           continuousPart | ||||||
|           |> Internals.T.kde( |           ->Internals.T.kde( | ||||||
|             ~samples=_, |             ~samples=_, | ||||||
|             ~outputXYPoints=samplingInputs.outputXYPoints, |             ~outputXYPoints=samplingInputs.outputXYPoints, | ||||||
|             Internals.T.formatUnitWidth(usedUnitWidth), |             Internals.T.formatUnitWidth(usedUnitWidth), | ||||||
|           ) |           ) | ||||||
|           |> Continuous.make |           ->Continuous.make | ||||||
|           |> (r => Some((r, samplingStats))) |           ->(r => Some((r, samplingStats))) | ||||||
|         } |         } | ||||||
|       : None |       : None | ||||||
| 
 | 
 | ||||||
|   let pointSetDist = MixedShapeBuilder.buildSimple( |   let pointSetDist = MixedShapeBuilder.buildSimple( | ||||||
|     ~continuous=pdf |> E.O.fmap(fst), |     ~continuous=pdf->E.O2.fmap(fst), | ||||||
|     ~discrete=Some(discrete), |     ~discrete=Some(discrete), | ||||||
|   ) |   ) | ||||||
| 
 | 
 | ||||||
|  | @ -125,7 +126,7 @@ let toPointSetDist = ( | ||||||
|   let normalizedPointSet = pointSetDist->E.O2.fmap(PointSetDist.T.normalize) |   let normalizedPointSet = pointSetDist->E.O2.fmap(PointSetDist.T.normalize) | ||||||
| 
 | 
 | ||||||
|   let samplesParse: Internals.Types.outputs = { |   let samplesParse: Internals.Types.outputs = { | ||||||
|     continuousParseParams: pdf |> E.O.fmap(snd), |     continuousParseParams: pdf->E.O2.fmap(snd), | ||||||
|     pointSetDist: normalizedPointSet, |     pointSetDist: normalizedPointSet, | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -305,55 +305,50 @@ module Floats = { | ||||||
|     /* |     /* | ||||||
|       This function goes through a sorted array and divides it into two different clusters: |       This function goes through a sorted array and divides it into two different clusters: | ||||||
|       continuous samples and discrete samples. The discrete samples are stored in a mutable map. |       continuous samples and discrete samples. The discrete samples are stored in a mutable map. | ||||||
|       Samples are thought to be discrete if they have any duplicates. |       Samples are thought to be discrete if they have at least `minDiscreteWight` duplicates. | ||||||
|  */ |  | ||||||
|     let _splitContinuousAndDiscreteForDuplicates = (sortedArray: array<float>) => { |  | ||||||
|       let continuous: array<float> = [] |  | ||||||
|       let discrete = FloatFloatMap.empty() |  | ||||||
|       Belt.Array.forEachWithIndex(sortedArray, (index, element) => { |  | ||||||
|         let maxIndex = (sortedArray |> Array.length) - 1 |  | ||||||
|         let possiblySimilarElements = switch index { |  | ||||||
|         | 0 => [index + 1] |  | ||||||
|         | n if n == maxIndex => [index - 1] |  | ||||||
|         | _ => [index - 1, index + 1] |  | ||||||
|         } |> Belt.Array.map(_, r => sortedArray[r]) |  | ||||||
|         let hasSimilarElement = Belt.Array.some(possiblySimilarElements, r => r == element) |  | ||||||
|         hasSimilarElement |  | ||||||
|           ? FloatFloatMap.increment(element, discrete) |  | ||||||
|           : { |  | ||||||
|               let _ = Js.Array.push(element, continuous) |  | ||||||
|             } |  | ||||||
| 
 | 
 | ||||||
|         () |       If the min discrete weight is 4, that would mean that at least four elements needed from a specific | ||||||
|       }) |       value for that to be kept as discrete. This is important because in some cases, we can expect that | ||||||
|  |       some common elements will be generated by regular operations. The final continuous array will be sorted. | ||||||
| 
 | 
 | ||||||
|       (continuous, discrete) |       This function is performance-critical, don't change it significantly without benchmarking | ||||||
|     } |       SampleSet->PointSet conversion performance. | ||||||
| 
 |  | ||||||
|     /* |  | ||||||
|       This function works very similarly to splitContinuousAndDiscreteForDuplicates. The one major difference |  | ||||||
|       is that you can specify a minDiscreteWeight.  If the min discreet weight is 4, that would mean that |  | ||||||
|       at least four elements needed from a specific value for that to be kept as discrete. This is important |  | ||||||
|       because in some cases, we can expect that some common elements will be generated by regular operations. |  | ||||||
|       The final continous array will be sorted. |  | ||||||
|  */ |  */ | ||||||
|     let splitContinuousAndDiscreteForMinWeight = ( |     let splitContinuousAndDiscreteForMinWeight = ( | ||||||
|       sortedArray: array<float>, |       sortedArray: array<float>, | ||||||
|       ~minDiscreteWeight: int, |       ~minDiscreteWeight: int, | ||||||
|     ) => { |     ) => { | ||||||
|       let (continuous, discrete) = _splitContinuousAndDiscreteForDuplicates(sortedArray) |       let continuous: array<float> = [] | ||||||
|       let keepFn = v => Belt.Float.toInt(v) >= minDiscreteWeight |       let discrete = FloatFloatMap.empty() | ||||||
|       let (discreteToKeep, discreteToIntegrate) = FloatFloatMap.partition( | 
 | ||||||
|         ((_, v)) => keepFn(v), |       let addData = (count: int, value: float): unit => { | ||||||
|         discrete, |         if count >= minDiscreteWeight { | ||||||
|  |           FloatFloatMap.add(value, count->Belt.Int.toFloat, discrete) | ||||||
|  |         } else { | ||||||
|  |           for _ in 1 to count { | ||||||
|  |             continuous->Js.Array2.push(value)->ignore | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       let (finalCount, finalValue) = sortedArray->Belt.Array.reduce( | ||||||
|  |         // initial prev value doesn't matter; if it collides with the first element of the array, flush won't do anything | ||||||
|  |         (0, 0.), | ||||||
|  |         ((count, prev), element) => { | ||||||
|  |           if element == prev { | ||||||
|  |             (count + 1, prev) | ||||||
|  |           } else { | ||||||
|  |             // new value, process previous ones | ||||||
|  |             addData(count, prev) | ||||||
|  |             (1, element) | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|       ) |       ) | ||||||
|       let newContinousSamples = | 
 | ||||||
|         discreteToIntegrate->FloatFloatMap.toArray |       // flush final values | ||||||
|         |> fmap(((k, v)) => Belt.Array.makeBy(Belt.Float.toInt(v), _ => k)) |       addData(finalCount, finalValue) | ||||||
|         |> Belt.Array.concatMany | 
 | ||||||
|       let newContinuous = concat(continuous, newContinousSamples) |       (continuous, discrete) | ||||||
|       newContinuous |> Array.fast_sort(floatCompare) |  | ||||||
|       (newContinuous, discreteToKeep) |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -16,6 +16,14 @@ let increment = (el, t: t) => | ||||||
|     } |     } | ||||||
|   ) |   ) | ||||||
| 
 | 
 | ||||||
|  | let add = (el, amount: float, t: t) => | ||||||
|  |   Belt.MutableMap.update(t, el, x => | ||||||
|  |     switch x { | ||||||
|  |     | Some(n) => Some(n +. amount) | ||||||
|  |     | None => Some(amount) | ||||||
|  |     } | ||||||
|  |   ) | ||||||
|  | 
 | ||||||
| let get = (el, t: t) => Belt.MutableMap.get(t, el) | let get = (el, t: t) => Belt.MutableMap.get(t, el) | ||||||
| let fmap = (fn, t: t) => Belt.MutableMap.map(t, fn) | let fmap = (fn, t: t) => Belt.MutableMap.map(t, fn) | ||||||
| let partition = (fn, t: t) => { | let partition = (fn, t: t) => { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user