Something like an end to end proof of concept

This commit is contained in:
Quinn Dougherty 2022-08-17 04:18:09 -07:00
parent 94d57491bd
commit 8c38c3955f
24 changed files with 214 additions and 599 deletions

View File

@ -16,12 +16,18 @@ jobs:
name: Precheck for skipping redundant jobs
runs-on: ubuntu-latest
outputs:
should_skip_mc: ${{ steps.skip_lang_check.outputs.should_skip }}
should_skip_lang: ${{ steps.skip_lang_check.outputs.should_skip }}
should_skip_components: ${{ steps.skip_components_check.outputs.should_skip }}
should_skip_website: ${{ steps.skip_website_check.outputs.should_skip }}
should_skip_vscodeext: ${{ steps.skip_vscodeext_check.outputs.should_skip }}
should_skip_cli: ${{ steps.skip_cli_check.outputs.should_skip }}
steps:
- id: skip_mc_check
name: Check if the changes are about mc files
uses: fkirc/skip-duplicate-actions@v4.0.0
with:
paths: '["packages/mc/**"]'
- id: skip_lang_check
name: Check if the changes are about squiggle-lang src files
uses: fkirc/skip-duplicate-actions@v4.0.0
@ -48,6 +54,29 @@ jobs:
with:
paths: '["packages/cli/**"]'
mc-build:
name: MC build
runs-on: ubuntu-latest
needs: pre_check
if: ${{ needs.pre_check.outputs.should_skip_mc != 'true' }}
defaults:
run:
shell: bash
working-directory: packages/mc
steps:
- name: Run yarn at monorepo level
run: cd ../../ && yarn
- name: Download wasm-bindgen
uses: jetli/wasm-bindgen-action@v0.1.0
with:
version: 'latest'
- name: Download wasm-pack
uses: jetli/wasm-pack-action@v0.3.0
with:
version: 'latest'
- name: Build
run: wasm-pack build --target nodejs
lang-lint:
name: Language lint
runs-on: ubuntu-latest
@ -84,7 +113,17 @@ jobs:
fetch-depth: 2
- name: Install dependencies from monorepo level
run: cd ../../ && yarn
- name: Build rescript codebase
- name: Download wasm-bindgen
uses: jetli/wasm-bindgen-action@v0.1.0
with:
version: 'latest'
- name: Download wasm-pack
uses: jetli/wasm-pack-action@v0.3.0
with:
version: 'latest'
- name: Build
run: wasm-pack build --target nodejs
- name: Build rescript codebase and typescript interface
run: yarn build
- name: Run rescript tests
run: yarn test:rescript
@ -127,7 +166,17 @@ jobs:
- uses: actions/checkout@v3
- name: Install dependencies from monorepo level
run: cd ../../ && yarn
- name: Build rescript codebase in squiggle-lang
- name: Download wasm-bindgen
uses: jetli/wasm-bindgen-action@v0.1.0
with:
version: 'latest'
- name: Download wasm-pack
uses: jetli/wasm-pack-action@v0.3.0
with:
version: 'latest'
- name: Build
run: wasm-pack build --target nodejs
- name: Build rescript codebase and typescript interface in squiggle-lang
run: cd ../squiggle-lang && yarn build
- name: Run webpack
run: yarn bundle
@ -164,7 +213,17 @@ jobs:
- uses: actions/checkout@v3
- name: Install dependencies from monorepo level
run: cd ../../ && yarn
- name: Build rescript in squiggle-lang
- name: Download wasm-bindgen
uses: jetli/wasm-bindgen-action@v0.1.0
with:
version: 'latest'
- name: Download wasm-pack
uses: jetli/wasm-pack-action@v0.3.0
with:
version: 'latest'
- name: Build
run: wasm-pack build --target nodejs
- name: Build rescript and typescript in squiggle-lang
run: cd ../squiggle-lang && yarn build
- name: Build components
run: cd ../components && yarn build

View File

@ -38,7 +38,7 @@
cargo2nix.overlays.default
(final: prev: {
# set the node version here
nodejs = prev.nodejs-18_x;
nodejs = prev.nodejs-16_x;
# The override is the only way to get it into mkYarnModules
})
];

View File

@ -7,12 +7,15 @@ with pkgs; {
cargo
yarn
nodejs
nodePackages.ts-node
rustup
pkg-config
libressl
nixfmt
rustfmt
cargo2nix.outputs.packages.${pkgs.system}.default
wasmtime
binaryen
];
};
}

View File

@ -29,6 +29,7 @@ rec {
THE_LD=$(patchelf --print-interpreter $(which mkdir))
patchelf --set-interpreter $THE_LD bin/linux/ppx
patchelf --set-interpreter $THE_LD bin/linux/bisect-ppx-report
cp bin/linux/ppx ppx
'';
};
gentype = {

View File

@ -449,7 +449,7 @@ dependencies = [
]
[[package]]
name = "quri-squiggle-mc"
name = "quri_squiggle_mc"
version = "0.0.1"
dependencies = [
"cached",

View File

@ -1,6 +1,6 @@
# You must change these to your own details.
[package]
name = "quri-squiggle-mc"
name = "quri_squiggle_mc"
description = "Cached and parallel Monte Carlo simulations in WebAssembly"
version = "0.0.1"
authors = ["Quinn <quinn@quantifieduncertainty.org>"]
@ -11,11 +11,11 @@ readme = "README.md"
edition = "2018"
[package.metadata.wasm-pack.profile.dev]
wasm-opt = false
wasm-opt = true
[package.metadata.wasm-pack.profile.profiling]
wasm-opt = false
wasm-opt = true
[package.metadata.wasm-pack.profile.release]
wasm-opt = false
wasm-opt = true
[lib]
crate-type = ["cdylib"]
@ -33,7 +33,7 @@ default = ["wee_alloc"]
[dependencies]
# The `wasm-bindgen` crate provides the bare minimum functionality needed
# to interact with JavaScript.
wasm-bindgen = "0.2.45"
wasm-bindgen = "0.2.82"
# The `web-sys` crate allows you to interact with the various browser APIs,
# like the DOM.

View File

@ -6,6 +6,8 @@ Please run `yarn` at the monorepo level.
In this subrepo, please run `./cargo-refresh-nix.sh` every time `Cargo.toml`/`Cargo.lock` is modified, it requires nix with flakes.
Please view `/.github/workflows/ci.yml` for the most accurate story about how to build in concert with the rest of the packages in the monorepo.
## How to run in debug mode
```sh

View File

@ -1 +0,0 @@
import("../pkg/index.js").catch(console.error);

View File

@ -4,15 +4,20 @@
"version": "0.0.1",
"scripts": {
"build": "rimraf dist pkg && webpack",
"start": "rimraf dist pkg && webpack-dev-server --open -d",
"build:node": "wasm-pack build --target nodejs",
"watch": "rimraf dist pkg && webpack --watch",
"start": "rimraf dist pkg && webpack-dev-server --open",
"test": "cargo test && wasm-pack test --headless"
},
"devDependencies": {
"@wasm-tool/wasm-pack-plugin": "^1.1.0",
"copy-webpack-plugin": "^5.0.3",
"webpack": "^4.42.0",
"webpack-cli": "^3.3.3",
"webpack-dev-server": "^3.7.1",
"rimraf": "^3.0.0"
}
"@wasm-tool/wasm-pack-plugin": "^1.6.0",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0",
"webpack-dev-server": "^4.10.0",
"rimraf": "^3.0.0",
"ts-loader": "^9.3.1",
"typescript": "^4.7.4"
},
"main": "./pkg/index.js",
"types": "./pkg/index.d.ts"
}

View File

@ -1,9 +1,10 @@
/** The math here was taken from https://github.com/jasondavies/science.js/blob/master/src/stats/SampleSetDist_Bandwidth.js
*/
use statistics::variance;
// mod magic_numbers;
// use kernel_density::ecdf::percentile;
use crate::distribution::BandwidthParameters;
use crate::distribution::e::a::floats::{lenf, min, percentile};
mod e;
use e::a::floats::{lenf, min, percentile};
fn iqr_percentile() -> f64 {
return BandwidthParameters::default().iqr_percentile;

View File

@ -1,10 +1,7 @@
pub mod e;
pub mod bandwidth;
pub mod magic_numbers;
pub mod monte_carlo;
pub use e::*;
// pub use bandwidth;
pub use magic_numbers::bandwidth::Parameters as BandwidthParameters;
pub use magic_numbers::environment::Parameters as EnvironmentParameters;
pub use monte_carlo::my_string;
pub use monte_carlo::sampleN;

View File

@ -1,8 +1,36 @@
use rand;
use rand_distr::{Distribution, Normal};
extern crate kernel_density;
pub fn my_string() -> String {
let normal = Normal::new(2.0, 3.0).unwrap();
let v = normal.sample(&mut rand::thread_rng());
return format!("{} is from an N(2,3) distribution", v);
use rand::Rng;
use rand::thread_rng;
// use kernel_density::kde;
// use crate::distribution::bandwidth::{nrd0, nrd};
// TODO: impl a constructor such that xs.len() == ys.len().
pub struct PdfCurve {
xs: Vec<f64>,
ys: Vec<f64>,
}
// pub fn samples_to_continuous_pdf(samples: Vec<f64>, bandwidth: f64) -> PdfCurve {
// let pdf = kde::normal(&samples, bandwidth);
// return PdfCurve {
// xs: samples,
// ys: samples.map(|x| pdf.density(x)),
// };
// }
// pub fn getCurve(xs: Vec<f64>, n: u64) -> Vec<f64> {
// let bandwidth = nrd(xs);
// let curve = samples_to_continuous_pdf(samples, bandwidth);
// return curve.ys;
// }
pub fn sampleN(xs: Vec<f32>, n: i32) -> Vec<f32> {
let m = xs.len();
let mut output = vec![];
for _ in 0..n {
output.push(xs[thread_rng().gen_range(0..m)])
}
return output;
}

View File

@ -11,20 +11,11 @@ use distribution::{monte_carlo, bandwidth};
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
// This is like the `main` function, except for JavaScript.
#[wasm_bindgen(start)]
pub fn main_js() -> Result<(), JsValue> {
// This provides better error messages in debug mode.
// It's disabled in release mode so it doesn't bloat up the file size.
#[wasm_bindgen]
pub fn sample_n(samples: Box<[f32]>, num_samples: i32) -> Vec<f32> {
#[cfg(debug_assertions)]
console_error_panic_hook::set_once();
let samples_vec = Vec::from(samples);
console::log_1(&JsValue::from_str(&format!(
"nrd(1,2,5): {}",
bandwidth::nrd([1.0, 2.0, 5.0].to_vec())
)));
// Your code goes here!
console::log_1(&JsValue::from_str(&monte_carlo::my_string()));
Ok(())
monte_carlo::sampleN(samples_vec, num_samples)
}

View File

@ -2,9 +2,10 @@
<html>
<head>
<meta charset="UTF-8">
<title>My Rust + Webpack project!</title>
<title>For developing squiggle-mc</title>
</head>
<body>
<script src="index.js"></script>
<h1>Testing the squiggle monte carlo module</h1>
<script src="main.js"></script>
</body>
</html>

2
packages/mc/ts/index.ts Normal file
View File

@ -0,0 +1,2 @@
import * as mc_rust_wasm from "../pkg";
// console.log(mc_rust_wasm.sample_n([1,2,3,4,4,5,5,3,3,4,4,32,4,24,4,5,2,2], 1000))

11
packages/mc/tsconfig.json Normal file
View File

@ -0,0 +1,11 @@
{
"compilerOptions": {
"outDir": "./dist/",
"noImplicitAny": true,
"module": "es6",
"target": "es5",
"jsx": "react",
"allowJs": true,
"moduleResolution": "node"
}
}

View File

@ -3,26 +3,39 @@ const CopyPlugin = require("copy-webpack-plugin");
const WasmPackPlugin = require("@wasm-tool/wasm-pack-plugin");
const dist = path.resolve(__dirname, "dist");
const static = path.resolve(__dirname, "static");
module.exports = {
mode: "production",
entry: {
index: "./js/index.js"
mode: "development",
entry: "./ts/index.ts",
module: {
rules: [
{
test: /\.tsx?$/,
use: "ts-loader",
exclude: /node_modules/,
},
],
},
output: {
path: dist,
filename: "[name].js"
},
devServer: {
contentBase: dist,
filename: "[name].js",
},
plugins: [
new CopyPlugin([
path.resolve(__dirname, "static")
]),
new WasmPackPlugin({
crateDirectory: __dirname,
}),
]
],
resolve: {
extensions: [".tsx", ".ts", ".js"]
},
experiments: {
asyncWebAssembly: true,
},
devServer: {
static: {
directory: static,
watch: true,
},
},
};

View File

@ -37,6 +37,6 @@
"number": "+A-42-48-9-30-4"
},
"ppx-flags": [
["../../node_modules/bisect_ppx/bin/linux/ppx", "--exclude-files", ".*_test\\.res$$"]
["../../node_modules/bisect_ppx/ppx", "--exclude-files", ".*_test\\.res$$"]
]
}

View File

@ -11,4 +11,7 @@ module.exports = {
".*Helpers.bs.js",
".*Helpers.ts",
],
moduleNameMapper: {
"@quri/squiggle-mc": "<rootDir>/../mc/pkg",
},
};

View File

@ -5,9 +5,9 @@
"license": "MIT",
"scripts": {
"peggy": "peggy --cache",
"build:mc-cached": "cd ../squiggle-mc-cached && yarn build and cd ../squiggle-lang",
"build:mc": "cd ../mc && yarn build and cd ../squiggle-lang",
"rescript": "rescript",
"build": "yarn build:mc-cached && yarn build:peggy && yarn build:rescript && yarn build:typescript",
"build": "yarn build:peggy && yarn build:rescript && yarn build:typescript",
"build:peggy:helpers": "tsc --module commonjs --outDir src/rescript/Reducer/Reducer_Peggy/ src/rescript/Reducer/Reducer_Peggy/helpers.ts",
"build:peggy": "yarn build:peggy:helpers && find . -type f -name *.peggy -exec yarn peggy {} \\;",
"build:rescript": "rescript build -with-deps",

View File

@ -87,7 +87,7 @@ The former helps in cases where multiple distributions are correlated.
However, if n > length(t), then there's no clear right answer, so we just randomly
sample everything.
*/
let sampleN = (t: t, n) => {
let sampleN' = (t: t, n) => {
if n <= E.A.length(get(t)) {
E.A.slice(get(t), ~offset=0, ~len=n)
} else {
@ -95,6 +95,8 @@ let sampleN = (t: t, n) => {
}
}
let sampleN = WasmInterface.sampleN
let _fromSampleResultArray = (samples: array<result<float, QuriSquiggleLang.Operation.Error.t>>) =>
E.A.R.firstErrorOrOpen(samples)->E.R2.errMap(Error.fromOperationError) |> E.R2.bind(make)

View File

@ -0,0 +1,2 @@
@module external sampleN: (array<float>, int) => array<float> = "@quri/squiggle-mc/sample_n"
let sampleN = sampleN

569
yarn.lock

File diff suppressed because it is too large Load Diff