diff --git a/.github/workflows/checking.yml b/.github/workflows/checking.yml index 7e807b084..3c3e7dfde 100644 --- a/.github/workflows/checking.yml +++ b/.github/workflows/checking.yml @@ -40,3 +40,24 @@ jobs: - name: Run cargo check (with serde) run: cargo check --workspace --all-targets --features "linfa-clustering/serde linfa-ica/serde linfa-kernel/serde linfa-reduction/serde linfa-svm/serde linfa-elasticnet/serde linfa-pls/serde linfa-trees/serde linfa-nn/serde linfa-linear/serde linfa-preprocessing/serde linfa-bayes/serde linfa-logistic/serde linfa-ftrl/serde" + + check-wasm-browser: + name: check-wasm-browser + runs-on: ubuntu-latest + + steps: + - name: Checkout sources + uses: actions/checkout@master + + - name: Install toolchain + uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + targets: wasm32-unknown-unknown + + - name: Run browser WASM checks + run: | + cargo check -p linfa --lib --target wasm32-unknown-unknown --features wasm-bindgen + cargo check -p linfa-linear --lib --target wasm32-unknown-unknown --features wasm-bindgen + cargo check -p linfa-logistic --lib --target wasm32-unknown-unknown --features wasm-bindgen + cargo check -p linfa-ftrl --lib --target wasm32-unknown-unknown --features wasm-bindgen diff --git a/Cargo.toml b/Cargo.toml index 8f11fc550..da67ab4a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,11 +34,13 @@ intel-mkl-system = ["blas", "ndarray-linalg/intel-mkl-system"] blas = ["ndarray/blas"] serde = ["serde_crate", "ndarray/serde"] +wasm-bindgen = ["dep:getrandom"] [dependencies] num-traits = "0.2" rand = { version = "0.8", features = ["small_rng"] } approx = "0.5" +getrandom = { version = "0.2", optional = true, features = ["js"] } ndarray = { version = "0.16", features = ["approx"] } ndarray-linalg = { version = "0.17", optional = true } @@ -75,6 +77,7 @@ pprof = { version = "0.15", features = [ [workspace] members = ["algorithms/*", "datasets"] +resolver = "2" [profile.release] opt-level = 3 diff --git a/README.md b/README.md index 37884454c..10ad4f8db 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,10 @@ We believe that only a significant community effort can nurture, build, and sust If this strikes a chord with you, please take a look at the [roadmap](https://github.com/rust-ml/linfa/issues/7) and get involved! +## Browser WASM + +For browser-style WASM on `wasm32-unknown-unknown`, enable `linfa`'s `wasm-bindgen` feature. + ## BLAS/Lapack backend Some algorithm crates need to use an external library for linear algebra routines. By default, we use a pure-Rust implementation. However, you can also choose an external BLAS/LAPACK backend library instead, by enabling the `blas` feature and a feature corresponding to your BLAS backend. Currently you can choose between the following BLAS/LAPACK backends: `openblas`, `netblas` or `intel-mkl`. diff --git a/algorithms/linfa-clustering/src/dbscan/algorithm.rs b/algorithms/linfa-clustering/src/dbscan/algorithm.rs index b5baaebe8..ab16bc741 100644 --- a/algorithms/linfa-clustering/src/dbscan/algorithm.rs +++ b/algorithms/linfa-clustering/src/dbscan/algorithm.rs @@ -131,7 +131,7 @@ impl, DF: Distance, N: NearestNeighbour> continue; } neighbors.iter().for_each(|&n| search_found[n] = true); - search_queue.extend(neighbors.into_iter()); + search_queue.extend(neighbors); // Now go over the neighbours adding them to the cluster cluster_memberships[i] = Some(current_cluster_id); diff --git a/algorithms/linfa-clustering/src/optics/algorithm.rs b/algorithms/linfa-clustering/src/optics/algorithm.rs index 14bfec00a..70ed48070 100644 --- a/algorithms/linfa-clustering/src/optics/algorithm.rs +++ b/algorithms/linfa-clustering/src/optics/algorithm.rs @@ -198,15 +198,15 @@ impl, N: NearestNeighbour> index += 1; continue; } - let mut expected = if processed.is_empty() { 0 } else { index }; let mut points_index = index; // Look for next point to process starting from lowest possible unprocessed index - for index in processed.range(index..) { + for (expected, index) in + (if processed.is_empty() { 0 } else { index }..).zip(processed.range(index..)) + { if expected != *index { points_index = expected; break; } - expected += 1; } index += 1; let neighbors = self.find_neighbors(&*nn, observations.row(points_index)); diff --git a/algorithms/linfa-ftrl/Cargo.toml b/algorithms/linfa-ftrl/Cargo.toml index 0cb430857..8c2f52abf 100644 --- a/algorithms/linfa-ftrl/Cargo.toml +++ b/algorithms/linfa-ftrl/Cargo.toml @@ -15,7 +15,7 @@ categories = ["algorithms", "mathematics", "science"] [features] serde = ["serde_crate", "linfa/serde", "ndarray/serde", "argmin/serde1"] -wasm-bindgen = ["argmin/wasm-bindgen"] +wasm-bindgen = ["argmin/wasm-bindgen", "linfa/wasm-bindgen"] [dependencies.serde_crate] package = "serde" diff --git a/algorithms/linfa-hierarchical/examples/irisflower.rs b/algorithms/linfa-hierarchical/examples/irisflower.rs index f61511d08..f49a09dce 100644 --- a/algorithms/linfa-hierarchical/examples/irisflower.rs +++ b/algorithms/linfa-hierarchical/examples/irisflower.rs @@ -16,7 +16,7 @@ fn main() -> Result<(), Box> { .num_clusters(3) .transform(kernel)?; - for (id, target) in kernel.targets().iter().zip(dataset.targets().into_iter()) { + for (id, target) in kernel.targets().iter().zip(dataset.targets()) { let name = match *target { 0 => "setosa", 1 => "versicolor", diff --git a/algorithms/linfa-hierarchical/src/lib.rs b/algorithms/linfa-hierarchical/src/lib.rs index eae797956..24623c385 100644 --- a/algorithms/linfa-hierarchical/src/lib.rs +++ b/algorithms/linfa-hierarchical/src/lib.rs @@ -141,10 +141,7 @@ impl Transformer, DatasetBase, Vec>> .map(|x| (x, vec![x])) .collect::>(); - // counter for new clusters, which are formed as unions of previous ones - let mut ct = num_observations; - - for step in res.steps() { + for (ct, step) in (num_observations..).zip(res.steps().iter()) { let should_stop = match self.stopping { Criterion::NumClusters(max_clusters) => clusters.len() <= max_clusters, Criterion::Distance(dis) => step.dissimilarity >= dis, @@ -164,7 +161,6 @@ impl Transformer, DatasetBase, Vec>> // insert into hashmap and increase counter clusters.insert(ct, ids); - ct += 1; } // flatten resulting clusters and reverse index diff --git a/algorithms/linfa-linear/Cargo.toml b/algorithms/linfa-linear/Cargo.toml index 2075592ef..99eeb5e50 100644 --- a/algorithms/linfa-linear/Cargo.toml +++ b/algorithms/linfa-linear/Cargo.toml @@ -19,7 +19,7 @@ categories = ["algorithms", "mathematics", "science"] [features] blas = ["ndarray-linalg", "linfa/ndarray-linalg"] serde = ["serde_crate", "linfa/serde", "ndarray/serde", "argmin/serde1"] -wasm-bindgen = ["argmin/wasm-bindgen"] +wasm-bindgen = ["argmin/wasm-bindgen", "linfa/wasm-bindgen"] [dependencies.serde_crate] package = "serde" diff --git a/algorithms/linfa-logistic/Cargo.toml b/algorithms/linfa-logistic/Cargo.toml index da36d3786..c771385ac 100644 --- a/algorithms/linfa-logistic/Cargo.toml +++ b/algorithms/linfa-logistic/Cargo.toml @@ -15,7 +15,7 @@ categories = ["algorithms", "mathematics", "science"] [features] serde = ["serde_crate", "linfa/serde", "ndarray/serde", "argmin/serde1"] -wasm-bindgen = ["argmin/wasm-bindgen"] +wasm-bindgen = ["argmin/wasm-bindgen", "linfa/wasm-bindgen"] [dependencies.serde_crate] package = "serde" diff --git a/datasets/src/dataset.rs b/datasets/src/dataset.rs index 4b68f9c2a..05606d6fe 100644 --- a/datasets/src/dataset.rs +++ b/datasets/src/dataset.rs @@ -2,6 +2,12 @@ use std::io::Read; use csv::ReaderBuilder; use flate2::read::GzDecoder; +#[cfg(any( + feature = "iris", + feature = "diabetes", + feature = "winequality", + feature = "linnerud" +))] use linfa::Dataset; use ndarray::prelude::*; use ndarray_csv::{Array2Reader, ReadError}; diff --git a/src/composing/multi_class_model.rs b/src/composing/multi_class_model.rs index e36e461a5..3a336ff82 100644 --- a/src/composing/multi_class_model.rs +++ b/src/composing/multi_class_model.rs @@ -46,7 +46,7 @@ impl> PredictInplace, // if probability is higher res = res .into_iter() - .zip(pairs.into_iter()) + .zip(pairs) .map(|(c, d)| if d.1 > c.1 { d } else { c }) .collect(); }