diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..faeb28c
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,7 @@
+# These owners will be the default owners for everything in
+# the repo. Unless a later match takes precedence,
+# Developers in this list will be requested for
+# review when someone opens a pull request.
+* @VolodymyrOrlov
+* @morenol
+* @Mec-iS
diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..1ac5dfa
--- /dev/null
+++ b/.github/CODE_OF_CONDUCT.md
@@ -0,0 +1,22 @@
+# Code of Conduct
+
+As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
+
+We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality.
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery
+* Personal attacks
+* Trolling or insulting/derogatory comments
+* Public or private harassment
+* Publishing other's private information, such as physical or electronic addresses, without explicit permission
+* Other unethical or unprofessional conduct.
+
+Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.
+
+This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
+
+This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/)
\ No newline at end of file
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
new file mode 100644
index 0000000..c09dfa7
--- /dev/null
+++ b/.github/CONTRIBUTING.md
@@ -0,0 +1,59 @@
+# **Contributing**
+
+When contributing to this repository, please first discuss the change you wish to make via issue,
+email, or any other method with the owners of this repository before making a change.
+
+Please note we have a [code of conduct](CODE_OF_CONDUCT.md), please follow it in all your interactions with the project.
+
+## Background
+
+We try to follow these principles:
+* follow as much as possible the sklearn API to give a frictionless user experience for practitioners already familiar with it
+* use only pure-Rust implementations for safety and future-proofing (with some low-level limited exceptions)
+* do not use macros in the library code to allow readability and transparent behavior
+* priority is not on "big data" dataset, try to be fast for small/average dataset with limited memory footprint.
+
+## Pull Request Process
+
+1. Open a PR following the template (erase the part of the template you don't need).
+2. Update the CHANGELOG.md with details of changes to the interface if they are breaking changes, this includes new environment variables, exposed ports useful file locations and container parameters.
+3. Pull Request can be merged in once you have the sign-off of one other developer, or if you do not have permission to do that you may request the reviewer to merge it for you.
+
+### generic guidelines
+Take a look to the conventions established by existing code:
+* Every module should come with some reference to scientific literature that allows relating the code to research. Use the `//!` comments at the top of the module to tell readers about the basics of the procedure you are implementing.
+* Every module should provide a Rust doctest, a brief test embedded with the documentation that explains how to use the procedure implemented.
+* Every module should provide comprehensive tests at the end, in its `mod tests {}` sub-module. These tests can be flagged or not with configuration flags to allow WebAssembly target.
+* Run `cargo doc --no-deps --open` and read the generated documentation in the browser to be sure that your changes reflects in the documentation and new code is documented.
+
+## Issue Report Process
+
+1. Go to the project's issues.
+2. Select the template that better fits your issue.
+3. Read carefully the instructions and write within the template guidelines.
+4. Submit it and wait for support.
+
+## Reviewing process
+
+1. After a PR is opened maintainers are notified
+2. Probably changes will be required to comply with the workflow, these commands are run automatically and all tests shall pass:
+ * **Coverage** (optional): `tarpaulin` is used with command `cargo tarpaulin --out Lcov --all-features -- --test-threads 1`
+ * **Formatting**: run `rustfmt src/*.rs` to apply automatic formatting
+ * **Linting**: `clippy` is used with command `cargo clippy --all-features -- -Drust-2018-idioms -Dwarnings`
+ * **Testing**: multiple test pipelines are run for different targets
+3. When everything is OK, code is merged.
+
+
+## Contribution Best Practices
+
+* Read this [how-to about Github workflow here](https://guides.github.com/introduction/flow/) if you are not familiar with.
+
+* Read all the texts related to [contributing for an OS community](https://github.com/HTTP-APIs/hydrus/tree/master/.github).
+
+* Read this [how-to about writing a PR](https://github.com/blog/1943-how-to-write-the-perfect-pull-request) and this [other how-to about writing a issue](https://wiredcraft.com/blog/how-we-write-our-github-issues/)
+
+* **read history**: search past open or closed issues for your problem before opening a new issue.
+
+* **PRs on develop**: any change should be PRed first in `development`
+
+* **testing**: everything should work and be tested as defined in the workflow. If any is failing for non-related reasons, annotate the test failure in the PR comment.
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 0000000..4fee515
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,24 @@
+### I'm submitting a
+- [ ] bug report.
+- [ ] feature request.
+
+### Current Behaviour:
+
+
+### Expected Behaviour:
+
+
+### Steps to reproduce:
+
+
+### Snapshot:
+
+
+### Environment:
+
+* rustc version
+* cargo version
+* OS details
+
+### Do you want to work on this issue?
+
\ No newline at end of file
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..600af94
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,29 @@
+
+
+
+
+Fixes #
+
+### Checklist
+- [ ] My branch is up-to-date with development branch.
+- [ ] Everything works and tested on latest stable Rust.
+- [ ] Coverage and Linting have been applied
+
+### Current behaviour
+
+
+### New expected behaviour
+
+
+### Change logs
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml
index 793e79d..09b53b6 100644
--- a/.github/workflows/coverage.yml
+++ b/.github/workflows/coverage.yml
@@ -39,6 +39,6 @@ jobs:
command: tarpaulin
args: --out Lcov --all-features -- --test-threads 1
- name: Upload to codecov.io
- uses: codecov/codecov-action@v1
+ uses: codecov/codecov-action@v2
with:
fail_ci_if_error: true
diff --git a/.gitignore b/.gitignore
index e4ee4c2..9c0651c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,3 +17,13 @@ smartcore.code-workspace
# OS
.DS_Store
+
+
+flamegraph.svg
+perf.data
+perf.data.old
+src.dot
+out.svg
+
+FlameGraph/
+out.stacks
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 79e77e4..a9dda10 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Added
- Seeds to multiple algorithims that depend on random number generation.
- Added feature `js` to use WASM in browser
+- Drop `nalgebra-bindings` feature
+- Complete refactoring with *extensive API changes* that includes:
+ * moving to a new traits system, less structs more traits
+ * adapting all the modules to the new traits system
+ * moving towards Rust 2021, in particular the use of `dyn` and `as_ref`
+ * reorganization of the code base, trying to eliminate duplicates
## BREAKING CHANGE
- Added a new parameter to `train_test_split` to define the seed.
diff --git a/Cargo.toml b/Cargo.toml
index 51b9887..d048eea 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,9 +2,9 @@
name = "smartcore"
description = "The most advanced machine learning library in rust."
homepage = "https://smartcorelib.org"
-version = "0.2.1"
+version = "0.4.0"
authors = ["SmartCore Developers"]
-edition = "2018"
+edition = "2021"
license = "Apache-2.0"
documentation = "https://docs.rs/smartcore"
repository = "https://github.com/smartcorelib/smartcore"
@@ -13,31 +13,27 @@ keywords = ["machine-learning", "statistical", "ai", "optimization", "linear-alg
categories = ["science"]
[features]
-default = ["datasets"]
+default = ["datasets", "serde"]
ndarray-bindings = ["ndarray"]
-nalgebra-bindings = ["nalgebra"]
datasets = ["rand_distr", "std"]
-fp_bench = ["itertools"]
std = ["rand/std", "rand/std_rng"]
# wasm32 only
js = ["getrandom/js"]
[dependencies]
+approx = "0.5.1"
+cfg-if = "1.0.0"
ndarray = { version = "0.15", optional = true }
-nalgebra = { version = "0.31", optional = true }
-num-traits = "0.2"
+num-traits = "0.2.12"
num = "0.4"
rand = { version = "0.8", default-features = false, features = ["small_rng"] }
rand_distr = { version = "0.4", optional = true }
serde = { version = "1", features = ["derive"], optional = true }
-itertools = { version = "0.10.3", optional = true }
-cfg-if = "1.0.0"
[target.'cfg(target_arch = "wasm32")'.dependencies]
getrandom = { version = "0.2", optional = true }
[dev-dependencies]
-smartcore = { path = ".", features = ["fp_bench"] }
criterion = { version = "0.4", default-features = false }
serde_json = "1.0"
bincode = "1.3.1"
@@ -45,16 +41,19 @@ bincode = "1.3.1"
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
wasm-bindgen-test = "0.3"
-[[bench]]
-name = "distance"
-harness = false
+[profile.bench]
+debug = true
-[[bench]]
-name = "naive_bayes"
-harness = false
-required-features = ["ndarray-bindings", "nalgebra-bindings"]
+resolver = "2"
-[[bench]]
-name = "fastpair"
-harness = false
-required-features = ["fp_bench"]
+[profile.test]
+debug = 1
+opt-level = 3
+split-debuginfo = "unpacked"
+
+[profile.release]
+strip = true
+debug = 1
+lto = true
+codegen-units = 1
+overflow-checks = true
\ No newline at end of file
diff --git a/README.md b/README.md
index e096131..3822f63 100644
--- a/README.md
+++ b/README.md
@@ -15,4 +15,46 @@
The Most Advanced Machine Learning Library In Rust.
------
\ No newline at end of file
+-----
+
+To start getting familiar with the new Smartcore v0.5 API, there is now available a [**Jupyter Notebook environment repository**](https://github.com/smartcorelib/smartcore-jupyter). Please see instructions there, your feedback is valuable for the future of the library.
+
+## Developers
+Contributions welcome, please start from [CONTRIBUTING and other relevant files](.github/CONTRIBUTING.md).
+
+### Walkthrough: traits system and basic structures
+
+#### numbers
+The library is founded on basic traits provided by `num-traits`. Basic traits are in `src/numbers`. These traits are used to define all the procedures in the library to make everything safer and provide constraints to what implementations can handle.
+
+#### linalg
+`numbers` are made at use in linear algebra structures in the **`src/linalg/basic`** module. These sub-modules define the traits used all over the code base.
+
+* *arrays*: In particular data structures like `Array`, `Array1` (1-dimensional), `Array2` (matrix, 2-D); plus their "views" traits. Views are used to provide no-footprint access to data, they have composed traits to allow writing (mutable traits: `MutArray`, `ArrayViewMut`, ...).
+* *matrix*: This provides the main entrypoint to matrices operations and currently the only structure provided in the shape of `struct DenseMatrix`. A matrix can be instantiated and automatically make available all the traits in "arrays" (sparse matrices implementation will be provided).
+* *vector*: Convenience traits are implemented for `std::Vec` to allow extensive reuse.
+
+These are all traits and by definition they do not allow instantiation. For instantiable structures see implementation like `DenseMatrix` with relative constructor.
+
+#### linalg/traits
+The traits in `src/linalg/traits` are closely linked to Linear Algebra's theoretical framework. These traits are used to specify characteristics and constraints for types accepted by various algorithms. For example these allow to define if a matrix is `QRDecomposable` and/or `SVDDecomposable`. See docstring for referencese to theoretical framework.
+
+As above these are all traits and by definition they do not allow instantiation. They are mostly used to provide constraints for implementations. For example, the implementation for Linear Regression requires the input data `X` to be in `smartcore`'s trait system `Array2 + QRDecomposable + SVDDecomposable`, a 2-D matrix that is both QR and SVD decomposable; that is what the provided strucure `linalg::arrays::matrix::DenseMatrix` happens to be: `impl QRDecomposable for DenseMatrix {};impl SVDDecomposable for DenseMatrix {}`.
+
+#### metrics
+Implementations for metrics (classification, regression, cluster, ...) and distance measure (Euclidean, Hamming, Manhattan, ...). For example: `Accuracy`, `F1`, `AUC`, `Precision`, `R2`. As everything else in the code base, these implementations reuse `numbers` and `linalg` traits and structures.
+
+These are collected in structures like `pub struct ClassificationMetrics {}` that implements `metrics::Metrics`, these are groups of functions (classification, regression, cluster, ...) that provide instantiation for the structures. Each of those instantiation can be passed around using the relative function, like `pub fn accuracy>(y_true: &V, y_pred: &V) -> T`. This provides a mechanism for metrics to be passed to higher interfaces like the `cross_validate`:
+```rust
+let results =
+ cross_validate(
+ BiasedEstimator::fit, // custom estimator
+ &x, &y, // input data
+ NoParameters {}, // extra parameters
+ cv, // type of cross validator
+ &accuracy // **metrics function** <--------
+ ).unwrap();
+```
+
+
+TODO: complete for all modules
diff --git a/benches/distance.rs b/benches/distance.rs
deleted file mode 100644
index b44e948..0000000
--- a/benches/distance.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-#[macro_use]
-extern crate criterion;
-extern crate smartcore;
-
-use criterion::black_box;
-use criterion::Criterion;
-use smartcore::math::distance::*;
-
-fn criterion_benchmark(c: &mut Criterion) {
- let a = vec![1., 2., 3.];
-
- c.bench_function("Euclidean Distance", move |b| {
- b.iter(|| Distances::euclidian().distance(black_box(&a), black_box(&a)))
- });
-}
-
-criterion_group!(benches, criterion_benchmark);
-criterion_main!(benches);
diff --git a/benches/fastpair.rs b/benches/fastpair.rs
deleted file mode 100644
index baa0e90..0000000
--- a/benches/fastpair.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
-
-// to run this bench you have to change the declaraion in mod.rs ---> pub mod fastpair;
-use smartcore::algorithm::neighbour::fastpair::FastPair;
-use smartcore::linalg::naive::dense_matrix::*;
-use std::time::Duration;
-
-fn closest_pair_bench(n: usize, m: usize) -> () {
- let x = DenseMatrix::::rand(n, m);
- let fastpair = FastPair::new(&x);
- let result = fastpair.unwrap();
-
- result.closest_pair();
-}
-
-fn closest_pair_brute_bench(n: usize, m: usize) -> () {
- let x = DenseMatrix::::rand(n, m);
- let fastpair = FastPair::new(&x);
- let result = fastpair.unwrap();
-
- result.closest_pair_brute();
-}
-
-fn bench_fastpair(c: &mut Criterion) {
- let mut group = c.benchmark_group("FastPair");
-
- // with full samples size (100) the test will take too long
- group.significance_level(0.1).sample_size(30);
- // increase from default 5.0 secs
- group.measurement_time(Duration::from_secs(60));
-
- for n_samples in [100_usize, 1000_usize].iter() {
- for n_features in [10_usize, 100_usize, 1000_usize].iter() {
- group.bench_with_input(
- BenchmarkId::from_parameter(format!(
- "fastpair --- n_samples: {}, n_features: {}",
- n_samples, n_features
- )),
- n_samples,
- |b, _| b.iter(|| closest_pair_bench(*n_samples, *n_features)),
- );
- group.bench_with_input(
- BenchmarkId::from_parameter(format!(
- "brute --- n_samples: {}, n_features: {}",
- n_samples, n_features
- )),
- n_samples,
- |b, _| b.iter(|| closest_pair_brute_bench(*n_samples, *n_features)),
- );
- }
- }
- group.finish();
-}
-
-criterion_group!(benches, bench_fastpair);
-criterion_main!(benches);
diff --git a/benches/naive_bayes.rs b/benches/naive_bayes.rs
deleted file mode 100644
index ba8cb6f..0000000
--- a/benches/naive_bayes.rs
+++ /dev/null
@@ -1,73 +0,0 @@
-use criterion::BenchmarkId;
-use criterion::{black_box, criterion_group, criterion_main, Criterion};
-
-use nalgebra::DMatrix;
-use ndarray::Array2;
-use smartcore::linalg::naive::dense_matrix::DenseMatrix;
-use smartcore::linalg::BaseMatrix;
-use smartcore::linalg::BaseVector;
-use smartcore::naive_bayes::gaussian::GaussianNB;
-
-pub fn gaussian_naive_bayes_fit_benchmark(c: &mut Criterion) {
- let mut group = c.benchmark_group("GaussianNB::fit");
-
- for n_samples in [100_usize, 1000_usize, 10000_usize].iter() {
- for n_features in [10_usize, 100_usize, 1000_usize].iter() {
- let x = DenseMatrix::::rand(*n_samples, *n_features);
- let y: Vec = (0..*n_samples)
- .map(|i| (i % *n_samples / 5_usize) as f64)
- .collect::>();
- group.bench_with_input(
- BenchmarkId::from_parameter(format!(
- "n_samples: {}, n_features: {}",
- n_samples, n_features
- )),
- n_samples,
- |b, _| {
- b.iter(|| {
- GaussianNB::fit(black_box(&x), black_box(&y), Default::default()).unwrap();
- })
- },
- );
- }
- }
- group.finish();
-}
-
-pub fn gaussian_naive_matrix_datastructure(c: &mut Criterion) {
- let mut group = c.benchmark_group("GaussianNB");
- let classes = (0..10000).map(|i| (i % 25) as f64).collect::>();
-
- group.bench_function("DenseMatrix", |b| {
- let x = DenseMatrix::::rand(10000, 500);
- let y = as BaseMatrix>::RowVector::from_array(&classes);
-
- b.iter(|| {
- GaussianNB::fit(black_box(&x), black_box(&y), Default::default()).unwrap();
- })
- });
-
- group.bench_function("ndarray", |b| {
- let x = Array2::::rand(10000, 500);
- let y = as BaseMatrix>::RowVector::from_array(&classes);
-
- b.iter(|| {
- GaussianNB::fit(black_box(&x), black_box(&y), Default::default()).unwrap();
- })
- });
-
- group.bench_function("ndalgebra", |b| {
- let x = DMatrix::::rand(10000, 500);
- let y = as BaseMatrix>::RowVector::from_array(&classes);
-
- b.iter(|| {
- GaussianNB::fit(black_box(&x), black_box(&y), Default::default()).unwrap();
- })
- });
-}
-criterion_group!(
- benches,
- gaussian_naive_bayes_fit_benchmark,
- gaussian_naive_matrix_datastructure
-);
-criterion_main!(benches);
diff --git a/src/algorithm/neighbour/bbd_tree.rs b/src/algorithm/neighbour/bbd_tree.rs
index 93ea050..e84f6de 100644
--- a/src/algorithm/neighbour/bbd_tree.rs
+++ b/src/algorithm/neighbour/bbd_tree.rs
@@ -1,45 +1,45 @@
use std::fmt::Debug;
-use crate::linalg::Matrix;
-use crate::math::distance::euclidian::*;
-use crate::math::num::RealNumber;
+use crate::linalg::basic::arrays::Array2;
+use crate::metrics::distance::euclidian::*;
+use crate::numbers::basenum::Number;
#[derive(Debug)]
-pub struct BBDTree {
- nodes: Vec>,
+pub struct BBDTree {
+ nodes: Vec,
index: Vec,
root: usize,
}
#[derive(Debug)]
-struct BBDTreeNode {
+struct BBDTreeNode {
count: usize,
index: usize,
- center: Vec,
- radius: Vec,
- sum: Vec,
- cost: T,
+ center: Vec,
+ radius: Vec,
+ sum: Vec,
+ cost: f64,
lower: Option,
upper: Option,
}
-impl BBDTreeNode {
- fn new(d: usize) -> BBDTreeNode {
+impl BBDTreeNode {
+ fn new(d: usize) -> BBDTreeNode {
BBDTreeNode {
count: 0,
index: 0,
- center: vec![T::zero(); d],
- radius: vec![T::zero(); d],
- sum: vec![T::zero(); d],
- cost: T::zero(),
+ center: vec![0f64; d],
+ radius: vec![0f64; d],
+ sum: vec![0f64; d],
+ cost: 0f64,
lower: Option::None,
upper: Option::None,
}
}
}
-impl BBDTree {
- pub fn new>(data: &M) -> BBDTree {
+impl BBDTree {
+ pub fn new>(data: &M) -> BBDTree {
let nodes = Vec::new();
let (n, _) = data.shape();
@@ -61,18 +61,18 @@ impl BBDTree {
pub(crate) fn clustering(
&self,
- centroids: &[Vec],
- sums: &mut Vec>,
+ centroids: &[Vec],
+ sums: &mut Vec>,
counts: &mut Vec,
membership: &mut Vec,
- ) -> T {
+ ) -> f64 {
let k = centroids.len();
counts.iter_mut().for_each(|v| *v = 0);
let mut candidates = vec![0; k];
for i in 0..k {
candidates[i] = i;
- sums[i].iter_mut().for_each(|v| *v = T::zero());
+ sums[i].iter_mut().for_each(|v| *v = 0f64);
}
self.filter(
@@ -89,13 +89,13 @@ impl BBDTree {
fn filter(
&self,
node: usize,
- centroids: &[Vec],
+ centroids: &[Vec],
candidates: &[usize],
k: usize,
- sums: &mut Vec>,
+ sums: &mut Vec>,
counts: &mut Vec,
membership: &mut Vec,
- ) -> T {
+ ) -> f64 {
let d = centroids[0].len();
let mut min_dist =
@@ -163,9 +163,9 @@ impl BBDTree {
}
fn prune(
- center: &[T],
- radius: &[T],
- centroids: &[Vec],
+ center: &[f64],
+ radius: &[f64],
+ centroids: &[Vec],
best_index: usize,
test_index: usize,
) -> bool {
@@ -177,22 +177,22 @@ impl BBDTree {
let best = ¢roids[best_index];
let test = ¢roids[test_index];
- let mut lhs = T::zero();
- let mut rhs = T::zero();
+ let mut lhs = 0f64;
+ let mut rhs = 0f64;
for i in 0..d {
let diff = test[i] - best[i];
lhs += diff * diff;
- if diff > T::zero() {
+ if diff > 0f64 {
rhs += (center[i] + radius[i] - best[i]) * diff;
} else {
rhs += (center[i] - radius[i] - best[i]) * diff;
}
}
- lhs >= T::two() * rhs
+ lhs >= 2f64 * rhs
}
- fn build_node>(&mut self, data: &M, begin: usize, end: usize) -> usize {
+ fn build_node>(&mut self, data: &M, begin: usize, end: usize) -> usize {
let (_, d) = data.shape();
let mut node = BBDTreeNode::new(d);
@@ -200,17 +200,17 @@ impl BBDTree {
node.count = end - begin;
node.index = begin;
- let mut lower_bound = vec![T::zero(); d];
- let mut upper_bound = vec![T::zero(); d];
+ let mut lower_bound = vec![0f64; d];
+ let mut upper_bound = vec![0f64; d];
for i in 0..d {
- lower_bound[i] = data.get(self.index[begin], i);
- upper_bound[i] = data.get(self.index[begin], i);
+ lower_bound[i] = data.get((self.index[begin], i)).to_f64().unwrap();
+ upper_bound[i] = data.get((self.index[begin], i)).to_f64().unwrap();
}
for i in begin..end {
for j in 0..d {
- let c = data.get(self.index[i], j);
+ let c = data.get((self.index[i], j)).to_f64().unwrap();
if lower_bound[j] > c {
lower_bound[j] = c;
}
@@ -220,32 +220,32 @@ impl BBDTree {
}
}
- let mut max_radius = T::from(-1.).unwrap();
+ let mut max_radius = -1f64;
let mut split_index = 0;
for i in 0..d {
- node.center[i] = (lower_bound[i] + upper_bound[i]) / T::two();
- node.radius[i] = (upper_bound[i] - lower_bound[i]) / T::two();
+ node.center[i] = (lower_bound[i] + upper_bound[i]) / 2f64;
+ node.radius[i] = (upper_bound[i] - lower_bound[i]) / 2f64;
if node.radius[i] > max_radius {
max_radius = node.radius[i];
split_index = i;
}
}
- if max_radius < T::from(1E-10).unwrap() {
+ if max_radius < 1E-10 {
node.lower = Option::None;
node.upper = Option::None;
for i in 0..d {
- node.sum[i] = data.get(self.index[begin], i);
+ node.sum[i] = data.get((self.index[begin], i)).to_f64().unwrap();
}
if end > begin + 1 {
let len = end - begin;
for i in 0..d {
- node.sum[i] *= T::from(len).unwrap();
+ node.sum[i] *= len as f64;
}
}
- node.cost = T::zero();
+ node.cost = 0f64;
return self.add_node(node);
}
@@ -254,8 +254,10 @@ impl BBDTree {
let mut i2 = end - 1;
let mut size = 0;
while i1 <= i2 {
- let mut i1_good = data.get(self.index[i1], split_index) < split_cutoff;
- let mut i2_good = data.get(self.index[i2], split_index) >= split_cutoff;
+ let mut i1_good =
+ data.get((self.index[i1], split_index)).to_f64().unwrap() < split_cutoff;
+ let mut i2_good =
+ data.get((self.index[i2], split_index)).to_f64().unwrap() >= split_cutoff;
if !i1_good && !i2_good {
self.index.swap(i1, i2);
@@ -281,9 +283,9 @@ impl BBDTree {
self.nodes[node.lower.unwrap()].sum[i] + self.nodes[node.upper.unwrap()].sum[i];
}
- let mut mean = vec![T::zero(); d];
+ let mut mean = vec![0f64; d];
for (i, mean_i) in mean.iter_mut().enumerate().take(d) {
- *mean_i = node.sum[i] / T::from(node.count).unwrap();
+ *mean_i = node.sum[i] / node.count as f64;
}
node.cost = BBDTree::node_cost(&self.nodes[node.lower.unwrap()], &mean)
@@ -292,17 +294,17 @@ impl BBDTree {
self.add_node(node)
}
- fn node_cost(node: &BBDTreeNode, center: &[T]) -> T {
+ fn node_cost(node: &BBDTreeNode, center: &[f64]) -> f64 {
let d = center.len();
- let mut scatter = T::zero();
+ let mut scatter = 0f64;
for (i, center_i) in center.iter().enumerate().take(d) {
- let x = (node.sum[i] / T::from(node.count).unwrap()) - *center_i;
+ let x = (node.sum[i] / node.count as f64) - *center_i;
scatter += x * x;
}
- node.cost + T::from(node.count).unwrap() * scatter
+ node.cost + node.count as f64 * scatter
}
- fn add_node(&mut self, new_node: BBDTreeNode) -> usize {
+ fn add_node(&mut self, new_node: BBDTreeNode) -> usize {
let idx = self.nodes.len();
self.nodes.push(new_node);
idx
@@ -312,7 +314,7 @@ impl BBDTree {
#[cfg(test)]
mod tests {
use super::*;
- use crate::linalg::naive::dense_matrix::DenseMatrix;
+ use crate::linalg::basic::matrix::DenseMatrix;
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
#[test]
diff --git a/src/algorithm/neighbour/cover_tree.rs b/src/algorithm/neighbour/cover_tree.rs
index 5664acc..85e0d22 100644
--- a/src/algorithm/neighbour/cover_tree.rs
+++ b/src/algorithm/neighbour/cover_tree.rs
@@ -4,12 +4,12 @@
//!
//! ```
//! use smartcore::algorithm::neighbour::cover_tree::*;
-//! use smartcore::math::distance::Distance;
+//! use smartcore::metrics::distance::Distance;
//!
//! #[derive(Clone)]
//! struct SimpleDistance {} // Our distance function
//!
-//! impl Distance for SimpleDistance {
+//! impl Distance for SimpleDistance {
//! fn distance(&self, a: &i32, b: &i32) -> f64 { // simple simmetrical scalar distance
//! (a - b).abs() as f64
//! }
@@ -29,28 +29,27 @@ use serde::{Deserialize, Serialize};
use crate::algorithm::sort::heap_select::HeapSelection;
use crate::error::{Failed, FailedError};
-use crate::math::distance::Distance;
-use crate::math::num::RealNumber;
+use crate::metrics::distance::Distance;
/// Implements Cover Tree algorithm
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug)]
-pub struct CoverTree> {
- base: F,
- inv_log_base: F,
+pub struct CoverTree> {
+ base: f64,
+ inv_log_base: f64,
distance: D,
- root: Node,
+ root: Node,
data: Vec,
identical_excluded: bool,
}
-impl> PartialEq for CoverTree {
+impl> PartialEq for CoverTree {
fn eq(&self, other: &Self) -> bool {
if self.data.len() != other.data.len() {
return false;
}
for i in 0..self.data.len() {
- if self.distance.distance(&self.data[i], &other.data[i]) != F::zero() {
+ if self.distance.distance(&self.data[i], &other.data[i]) != 0f64 {
return false;
}
}
@@ -60,36 +59,36 @@ impl> PartialEq for CoverTree {
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug)]
-struct Node {
+struct Node {
idx: usize,
- max_dist: F,
- parent_dist: F,
- children: Vec>,
- _scale: i64,
+ max_dist: f64,
+ parent_dist: f64,
+ children: Vec,
+ scale: i64,
}
#[derive(Debug)]
-struct DistanceSet {
+struct DistanceSet {
idx: usize,
- dist: Vec,
+ dist: Vec,
}
-impl> CoverTree {
+impl> CoverTree {
/// Construct a cover tree.
/// * `data` - vector of data points to search for.
/// * `distance` - distance metric to use for searching. This function should extend [`Distance`](../../../math/distance/index.html) interface.
- pub fn new(data: Vec, distance: D) -> Result, Failed> {
- let base = F::from_f64(1.3).unwrap();
+ pub fn new(data: Vec, distance: D) -> Result, Failed> {
+ let base = 1.3f64;
let root = Node {
idx: 0,
- max_dist: F::zero(),
- parent_dist: F::zero(),
+ max_dist: 0f64,
+ parent_dist: 0f64,
children: Vec::new(),
- _scale: 0,
+ scale: 0,
};
let mut tree = CoverTree {
base,
- inv_log_base: F::one() / base.ln(),
+ inv_log_base: 1f64 / base.ln(),
distance,
root,
data,
@@ -104,7 +103,7 @@ impl> CoverTree
/// Find k nearest neighbors of `p`
/// * `p` - look for k nearest points to `p`
/// * `k` - the number of nearest neighbors to return
- pub fn find(&self, p: &T, k: usize) -> Result, Failed> {
+ pub fn find(&self, p: &T, k: usize) -> Result, Failed> {
if k == 0 {
return Err(Failed::because(FailedError::FindFailed, "k should be > 0"));
}
@@ -119,13 +118,13 @@ impl> CoverTree
let e = self.get_data_value(self.root.idx);
let mut d = self.distance.distance(e, p);
- let mut current_cover_set: Vec<(F, &Node)> = Vec::new();
- let mut zero_set: Vec<(F, &Node)> = Vec::new();
+ let mut current_cover_set: Vec<(f64, &Node)> = Vec::new();
+ let mut zero_set: Vec<(f64, &Node)> = Vec::new();
current_cover_set.push((d, &self.root));
let mut heap = HeapSelection::with_capacity(k);
- heap.add(F::max_value());
+ heap.add(std::f64::MAX);
let mut empty_heap = true;
if !self.identical_excluded || self.get_data_value(self.root.idx) != p {
@@ -134,7 +133,7 @@ impl> CoverTree
}
while !current_cover_set.is_empty() {
- let mut next_cover_set: Vec<(F, &Node)> = Vec::new();
+ let mut next_cover_set: Vec<(f64, &Node)> = Vec::new();
for par in current_cover_set {
let parent = par.1;
for c in 0..parent.children.len() {
@@ -146,7 +145,7 @@ impl> CoverTree
}
let upper_bound = if empty_heap {
- F::infinity()
+ std::f64::INFINITY
} else {
*heap.peek()
};
@@ -169,7 +168,7 @@ impl> CoverTree
current_cover_set = next_cover_set;
}
- let mut neighbors: Vec<(usize, F, &T)> = Vec::new();
+ let mut neighbors: Vec<(usize, f64, &T)> = Vec::new();
let upper_bound = *heap.peek();
for ds in zero_set {
if ds.0 <= upper_bound {
@@ -189,25 +188,25 @@ impl> CoverTree
/// Find all nearest neighbors within radius `radius` from `p`
/// * `p` - look for k nearest points to `p`
/// * `radius` - radius of the search
- pub fn find_radius(&self, p: &T, radius: F) -> Result, Failed> {
- if radius <= F::zero() {
+ pub fn find_radius(&self, p: &T, radius: f64) -> Result, Failed> {
+ if radius <= 0f64 {
return Err(Failed::because(
FailedError::FindFailed,
"radius should be > 0",
));
}
- let mut neighbors: Vec<(usize, F, &T)> = Vec::new();
+ let mut neighbors: Vec<(usize, f64, &T)> = Vec::new();
- let mut current_cover_set: Vec<(F, &Node)> = Vec::new();
- let mut zero_set: Vec<(F, &Node)> = Vec::new();
+ let mut current_cover_set: Vec<(f64, &Node)> = Vec::new();
+ let mut zero_set: Vec<(f64, &Node)> = Vec::new();
let e = self.get_data_value(self.root.idx);
let mut d = self.distance.distance(e, p);
current_cover_set.push((d, &self.root));
while !current_cover_set.is_empty() {
- let mut next_cover_set: Vec<(F, &Node)> = Vec::new();
+ let mut next_cover_set: Vec<(f64, &Node)> = Vec::new();
for par in current_cover_set {
let parent = par.1;
for c in 0..parent.children.len() {
@@ -240,23 +239,23 @@ impl> CoverTree
Ok(neighbors)
}
- fn new_leaf(&self, idx: usize) -> Node {
+ fn new_leaf(&self, idx: usize) -> Node {
Node {
idx,
- max_dist: F::zero(),
- parent_dist: F::zero(),
+ max_dist: 0f64,
+ parent_dist: 0f64,
children: Vec::new(),
- _scale: 100,
+ scale: 100,
}
}
fn build_cover_tree(&mut self) {
- let mut point_set: Vec> = Vec::new();
- let mut consumed_set: Vec> = Vec::new();
+ let mut point_set: Vec = Vec::new();
+ let mut consumed_set: Vec = Vec::new();
let point = &self.data[0];
let idx = 0;
- let mut max_dist = -F::one();
+ let mut max_dist = -1f64;
for i in 1..self.data.len() {
let dist = self.distance.distance(point, &self.data[i]);
@@ -284,16 +283,16 @@ impl> CoverTree
p: usize,
max_scale: i64,
top_scale: i64,
- point_set: &mut Vec>,
- consumed_set: &mut Vec>,
- ) -> Node {
+ point_set: &mut Vec,
+ consumed_set: &mut Vec,
+ ) -> Node {
if point_set.is_empty() {
self.new_leaf(p)
} else {
let max_dist = self.max(point_set);
let next_scale = (max_scale - 1).min(self.get_scale(max_dist));
if next_scale == std::i64::MIN {
- let mut children: Vec> = Vec::new();
+ let mut children: Vec = Vec::new();
let mut leaf = self.new_leaf(p);
children.push(leaf);
while !point_set.is_empty() {
@@ -304,13 +303,13 @@ impl> CoverTree
}
Node {
idx: p,
- max_dist: F::zero(),
- parent_dist: F::zero(),
+ max_dist: 0f64,
+ parent_dist: 0f64,
children,
- _scale: 100,
+ scale: 100,
}
} else {
- let mut far: Vec> = Vec::new();
+ let mut far: Vec = Vec::new();
self.split(point_set, &mut far, max_scale);
let child = self.batch_insert(p, next_scale, top_scale, point_set, consumed_set);
@@ -319,14 +318,14 @@ impl> CoverTree
point_set.append(&mut far);
child
} else {
- let mut children: Vec> = vec![child];
- let mut new_point_set: Vec> = Vec::new();
- let mut new_consumed_set: Vec> = Vec::new();
+ let mut children: Vec = vec![child];
+ let mut new_point_set: Vec = Vec::new();
+ let mut new_consumed_set: Vec = Vec::new();
while !point_set.is_empty() {
- let set: DistanceSet = point_set.remove(point_set.len() - 1);
+ let set: DistanceSet = point_set.remove(point_set.len() - 1);
- let new_dist: F = set.dist[set.dist.len() - 1];
+ let new_dist = set.dist[set.dist.len() - 1];
self.dist_split(
point_set,
@@ -374,9 +373,9 @@ impl> CoverTree
Node {
idx: p,
max_dist: self.max(consumed_set),
- parent_dist: F::zero(),
+ parent_dist: 0f64,
children,
- _scale: (top_scale - max_scale),
+ scale: (top_scale - max_scale),
}
}
}
@@ -385,12 +384,12 @@ impl> CoverTree
fn split(
&self,
- point_set: &mut Vec>,
- far_set: &mut Vec>,
+ point_set: &mut Vec,
+ far_set: &mut Vec,
max_scale: i64,
) {
let fmax = self.get_cover_radius(max_scale);
- let mut new_set: Vec> = Vec::new();
+ let mut new_set: Vec = Vec::new();
for n in point_set.drain(0..) {
if n.dist[n.dist.len() - 1] <= fmax {
new_set.push(n);
@@ -404,13 +403,13 @@ impl> CoverTree
fn dist_split(
&self,
- point_set: &mut Vec>,
- new_point_set: &mut Vec>,
+ point_set: &mut Vec,
+ new_point_set: &mut Vec,
new_point: &T,
max_scale: i64,
) {
let fmax = self.get_cover_radius(max_scale);
- let mut new_set: Vec> = Vec::new();
+ let mut new_set: Vec = Vec::new();
for mut n in point_set.drain(0..) {
let new_dist = self
.distance
@@ -426,24 +425,24 @@ impl> CoverTree
point_set.append(&mut new_set);
}
- fn get_cover_radius(&self, s: i64) -> F {
- self.base.powf(F::from_i64(s).unwrap())
+ fn get_cover_radius(&self, s: i64) -> f64 {
+ self.base.powf(s as f64)
}
fn get_data_value(&self, idx: usize) -> &T {
&self.data[idx]
}
- fn get_scale(&self, d: F) -> i64 {
- if d == F::zero() {
+ fn get_scale(&self, d: f64) -> i64 {
+ if d == 0f64 {
std::i64::MIN
} else {
- (self.inv_log_base * d.ln()).ceil().to_i64().unwrap()
+ (self.inv_log_base * d.ln()).ceil() as i64
}
}
- fn max(&self, distance_set: &[DistanceSet]) -> F {
- let mut max = F::zero();
+ fn max(&self, distance_set: &[DistanceSet]) -> f64 {
+ let mut max = 0f64;
for n in distance_set {
if max < n.dist[n.dist.len() - 1] {
max = n.dist[n.dist.len() - 1];
@@ -457,13 +456,13 @@ impl> CoverTree
mod tests {
use super::*;
- use crate::math::distance::Distances;
+ use crate::metrics::distance::Distances;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone)]
struct SimpleDistance {}
- impl Distance for SimpleDistance {
+ impl Distance for SimpleDistance {
fn distance(&self, a: &i32, b: &i32) -> f64 {
(a - b).abs() as f64
}
@@ -513,7 +512,7 @@ mod tests {
let tree = CoverTree::new(data, SimpleDistance {}).unwrap();
- let deserialized_tree: CoverTree =
+ let deserialized_tree: CoverTree =
serde_json::from_str(&serde_json::to_string(&tree).unwrap()).unwrap();
assert_eq!(tree, deserialized_tree);
diff --git a/src/algorithm/neighbour/distances.rs b/src/algorithm/neighbour/distances.rs
index 56a7ed6..eee99ca 100644
--- a/src/algorithm/neighbour/distances.rs
+++ b/src/algorithm/neighbour/distances.rs
@@ -9,7 +9,7 @@ use std::cmp::{Eq, Ordering, PartialOrd};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
-use crate::math::num::RealNumber;
+use crate::numbers::realnum::RealNumber;
///
/// The edge of the subgraph is defined by `PairwiseDistance`.
diff --git a/src/algorithm/neighbour/fastpair.rs b/src/algorithm/neighbour/fastpair.rs
index bf3bca3..d676460 100644
--- a/src/algorithm/neighbour/fastpair.rs
+++ b/src/algorithm/neighbour/fastpair.rs
@@ -27,9 +27,10 @@ use std::collections::HashMap;
use crate::algorithm::neighbour::distances::PairwiseDistance;
use crate::error::{Failed, FailedError};
-use crate::linalg::Matrix;
-use crate::math::distance::euclidian::Euclidian;
-use crate::math::num::RealNumber;
+use crate::linalg::basic::arrays::Array2;
+use crate::metrics::distance::euclidian::Euclidian;
+use crate::numbers::realnum::RealNumber;
+use crate::numbers::floatnum::FloatNumber;
///
/// Inspired by Python implementation:
@@ -39,7 +40,7 @@ use crate::math::num::RealNumber;
/// affinity used is Euclidean so to allow linkage with single, ward, complete and average
///
#[derive(Debug, Clone)]
-pub struct FastPair<'a, T: RealNumber, M: Matrix> {
+pub struct FastPair<'a, T: RealNumber + FloatNumber, M: Array2> {
/// initial matrix
samples: &'a M,
/// closest pair hashmap (connectivity matrix for closest pairs)
@@ -48,7 +49,7 @@ pub struct FastPair<'a, T: RealNumber, M: Matrix> {
pub neighbours: Vec,
}
-impl<'a, T: RealNumber, M: Matrix> FastPair<'a, T, M> {
+impl<'a, T: RealNumber + FloatNumber, M: Array2> FastPair<'a, T, M> {
///
/// Constructor
/// Instantiate and inizialise the algorithm
@@ -72,7 +73,7 @@ impl<'a, T: RealNumber, M: Matrix> FastPair<'a, T, M> {
}
///
- /// Initialise `FastPair` by passing a `Matrix`.
+ /// Initialise `FastPair` by passing a `Array2`.
/// Build a FastPairs data-structure from a set of (new) points.
///
fn init(&mut self) {
@@ -96,8 +97,8 @@ impl<'a, T: RealNumber, M: Matrix> FastPair<'a, T, M> {
index_row_i,
PairwiseDistance {
node: index_row_i,
- neighbour: None,
- distance: Some(T::max_value()),
+ neighbour: Option::None,
+ distance: Some(T::MAX),
},
);
}
@@ -142,7 +143,7 @@ impl<'a, T: RealNumber, M: Matrix> FastPair<'a, T, M> {
// compute sparse matrix (connectivity matrix)
let mut sparse_matrix = M::zeros(len, len);
for (_, p) in distances.iter() {
- sparse_matrix.set(p.node, p.neighbour.unwrap(), p.distance.unwrap());
+ sparse_matrix.set((p.node, p.neighbour.unwrap()), p.distance.unwrap());
}
self.distances = distances;
@@ -180,7 +181,7 @@ impl<'a, T: RealNumber, M: Matrix> FastPair<'a, T, M> {
let mut closest_pair = PairwiseDistance {
node: 0,
- neighbour: None,
+ neighbour: Option::None,
distance: Some(T::max_value()),
};
for pair in (0..m).combinations(2) {
@@ -549,7 +550,7 @@ mod tests_fastpair {
let mut min_dissimilarity = PairwiseDistance {
node: 0,
- neighbour: None,
+ neighbour: Option::None,
distance: Some(f64::MAX),
};
for p in dissimilarities.iter() {
diff --git a/src/algorithm/neighbour/linear_search.rs b/src/algorithm/neighbour/linear_search.rs
index e2a1b6d..ccd5c10 100644
--- a/src/algorithm/neighbour/linear_search.rs
+++ b/src/algorithm/neighbour/linear_search.rs
@@ -3,12 +3,12 @@
//! see [KNN algorithms](../index.html)
//! ```
//! use smartcore::algorithm::neighbour::linear_search::*;
-//! use smartcore::math::distance::Distance;
+//! use smartcore::metrics::distance::Distance;
//!
//! #[derive(Clone)]
//! struct SimpleDistance {} // Our distance function
//!
-//! impl Distance for SimpleDistance {
+//! impl Distance for SimpleDistance {
//! fn distance(&self, a: &i32, b: &i32) -> f64 { // simple simmetrical scalar distance
//! (a - b).abs() as f64
//! }
@@ -25,38 +25,31 @@
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::cmp::{Ordering, PartialOrd};
-use std::marker::PhantomData;
use crate::algorithm::sort::heap_select::HeapSelection;
use crate::error::{Failed, FailedError};
-use crate::math::distance::Distance;
-use crate::math::num::RealNumber;
+use crate::metrics::distance::Distance;
/// Implements Linear Search algorithm, see [KNN algorithms](../index.html)
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug)]
-pub struct LinearKNNSearch> {
+pub struct LinearKNNSearch> {
distance: D,
data: Vec,
- f: PhantomData,
}
-impl> LinearKNNSearch {
+impl> LinearKNNSearch {
/// Initializes algorithm.
/// * `data` - vector of data points to search for.
/// * `distance` - distance metric to use for searching. This function should extend [`Distance`](../../../math/distance/index.html) interface.
- pub fn new(data: Vec, distance: D) -> Result, Failed> {
- Ok(LinearKNNSearch {
- data,
- distance,
- f: PhantomData,
- })
+ pub fn new(data: Vec, distance: D) -> Result, Failed> {
+ Ok(LinearKNNSearch { data, distance })
}
/// Find k nearest neighbors
/// * `from` - look for k nearest points to `from`
/// * `k` - the number of nearest neighbors to return
- pub fn find(&self, from: &T, k: usize) -> Result, Failed> {
+ pub fn find(&self, from: &T, k: usize) -> Result, Failed> {
if k < 1 || k > self.data.len() {
return Err(Failed::because(
FailedError::FindFailed,
@@ -64,11 +57,11 @@ impl> LinearKNNSearch {
));
}
- let mut heap = HeapSelection::>::with_capacity(k);
+ let mut heap = HeapSelection::::with_capacity(k);
for _ in 0..k {
heap.add(KNNPoint {
- distance: F::infinity(),
+ distance: std::f64::INFINITY,
index: None,
});
}
@@ -93,15 +86,15 @@ impl> LinearKNNSearch {
/// Find all nearest neighbors within radius `radius` from `p`
/// * `p` - look for k nearest points to `p`
/// * `radius` - radius of the search
- pub fn find_radius(&self, from: &T, radius: F) -> Result, Failed> {
- if radius <= F::zero() {
+ pub fn find_radius(&self, from: &T, radius: f64) -> Result, Failed> {
+ if radius <= 0f64 {
return Err(Failed::because(
FailedError::FindFailed,
"radius should be > 0",
));
}
- let mut neighbors: Vec<(usize, F, &T)> = Vec::new();
+ let mut neighbors: Vec<(usize, f64, &T)> = Vec::new();
for i in 0..self.data.len() {
let d = self.distance.distance(from, &self.data[i]);
@@ -116,35 +109,35 @@ impl> LinearKNNSearch {
}
#[derive(Debug)]
-struct KNNPoint {
- distance: F,
+struct KNNPoint {
+ distance: f64,
index: Option,
}
-impl PartialOrd for KNNPoint {
+impl PartialOrd for KNNPoint {
fn partial_cmp(&self, other: &Self) -> Option {
self.distance.partial_cmp(&other.distance)
}
}
-impl PartialEq for KNNPoint {
+impl PartialEq for KNNPoint {
fn eq(&self, other: &Self) -> bool {
self.distance == other.distance
}
}
-impl Eq for KNNPoint {}
+impl Eq for KNNPoint {}
#[cfg(test)]
mod tests {
use super::*;
- use crate::math::distance::Distances;
+ use crate::metrics::distance::Distances;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone)]
struct SimpleDistance {}
- impl Distance for SimpleDistance {
+ impl Distance for SimpleDistance {
fn distance(&self, a: &i32, b: &i32) -> f64 {
(a - b).abs() as f64
}
diff --git a/src/algorithm/neighbour/mod.rs b/src/algorithm/neighbour/mod.rs
index f59448a..fdfaeb7 100644
--- a/src/algorithm/neighbour/mod.rs
+++ b/src/algorithm/neighbour/mod.rs
@@ -33,8 +33,8 @@
use crate::algorithm::neighbour::cover_tree::CoverTree;
use crate::algorithm::neighbour::linear_search::LinearKNNSearch;
use crate::error::Failed;
-use crate::math::distance::Distance;
-use crate::math::num::RealNumber;
+use crate::metrics::distance::Distance;
+use crate::numbers::basenum::Number;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
@@ -44,7 +44,7 @@ pub mod cover_tree;
/// dissimilarities for vector-vector distance. Linkage algorithms used in fastpair
pub mod distances;
/// fastpair closest neighbour algorithm
-pub mod fastpair;
+// pub mod fastpair;
/// very simple algorithm that sequentially checks each element of the list until a match is found or the whole list has been searched.
pub mod linear_search;
@@ -67,13 +67,14 @@ impl Default for KNNAlgorithmName {
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug)]
-pub(crate) enum KNNAlgorithm, T>> {
- LinearSearch(LinearKNNSearch, T, D>),
- CoverTree(CoverTree, T, D>),
+pub(crate) enum KNNAlgorithm>> {
+ LinearSearch(LinearKNNSearch, D>),
+ CoverTree(CoverTree, D>),
}
+// TODO: missing documentation
impl KNNAlgorithmName {
- pub(crate) fn fit, T>>(
+ pub(crate) fn fit>>(
&self,
data: Vec>,
distance: D,
@@ -89,8 +90,8 @@ impl KNNAlgorithmName {
}
}
-impl, T>> KNNAlgorithm {
- pub fn find(&self, from: &Vec, k: usize) -> Result)>, Failed> {
+impl>> KNNAlgorithm {
+ pub fn find(&self, from: &Vec, k: usize) -> Result)>, Failed> {
match *self {
KNNAlgorithm::LinearSearch(ref linear) => linear.find(from, k),
KNNAlgorithm::CoverTree(ref cover) => cover.find(from, k),
@@ -100,8 +101,8 @@ impl