Initial commit
This commit is contained in:
@@ -8,3 +8,11 @@ Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
# IDE
|
||||
.idea
|
||||
.project
|
||||
.vscode
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "smartcore"
|
||||
version = "0.1.0"
|
||||
authors = ["Vlad Orlov"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
ndarray = "0.12.1"
|
||||
ndarray-linalg = "0.10"
|
||||
num-traits = "0.2"
|
||||
|
||||
[dev-dependencies]
|
||||
ndarray = "0.12.1"
|
||||
criterion = "0.2"
|
||||
|
||||
[[bench]]
|
||||
name = "distance"
|
||||
harness = false
|
||||
@@ -0,0 +1,19 @@
|
||||
#[macro_use]
|
||||
extern crate criterion;
|
||||
extern crate smartcore;
|
||||
extern crate ndarray;
|
||||
use ndarray::Array;
|
||||
use smartcore::math::distance::euclidian::EuclidianDistance;
|
||||
use smartcore::math::distance::Distance;
|
||||
|
||||
use criterion::Criterion;
|
||||
use criterion::black_box;
|
||||
|
||||
fn criterion_benchmark(c: &mut Criterion) {
|
||||
let a = Array::from_vec(vec![1., 2., 3.]);
|
||||
|
||||
c.bench_function("Euclidean Distance", move |b| b.iter(|| EuclidianDistance::distance(black_box(&a), black_box(&a))));
|
||||
}
|
||||
|
||||
criterion_group!(benches, criterion_benchmark);
|
||||
criterion_main!(benches);
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -0,0 +1 @@
|
||||
pub mod sort;
|
||||
@@ -0,0 +1,64 @@
|
||||
use std::cmp::Ordering;
|
||||
|
||||
pub struct HeapSelect<T: std::cmp::Ord> {
|
||||
|
||||
k: usize,
|
||||
n: usize,
|
||||
sorted: bool,
|
||||
heap: Vec<T>
|
||||
|
||||
|
||||
}
|
||||
|
||||
impl<T: std::cmp::Ord> HeapSelect<T> {
|
||||
|
||||
pub fn from_vec(vec: Vec<T>) -> HeapSelect<T> {
|
||||
HeapSelect{
|
||||
k: vec.len(),
|
||||
n: 0,
|
||||
sorted: false,
|
||||
heap: vec
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(&mut self, element: T) {
|
||||
self.sorted = false;
|
||||
if self.n < self.k {
|
||||
self.heap[self.n] = element;
|
||||
self.n += 1;
|
||||
if self.n == self.k {
|
||||
self.heapify();
|
||||
}
|
||||
} else {
|
||||
self.n += 1;
|
||||
if element.cmp(&self.heap[0]) == Ordering::Less {
|
||||
self.heap[0] = element;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn heapify(&mut self){
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_from_vec() {
|
||||
let heap = HeapSelect::from_vec(vec!(1, 2, 3));
|
||||
assert_eq!(3, heap.k);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_add() {
|
||||
let mut heap = HeapSelect::from_vec(Vec::<i32>::new());
|
||||
heap.add(1);
|
||||
heap.add(2);
|
||||
heap.add(3);
|
||||
assert_eq!(3, heap.n);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod heap_select;
|
||||
@@ -0,0 +1,76 @@
|
||||
use super::Classifier;
|
||||
use super::super::math::distance::Distance;
|
||||
use super::super::math::distance::euclidian::EuclidianDistance;
|
||||
use ndarray::prelude::*;
|
||||
use num_traits::Signed;
|
||||
use num_traits::Float;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub struct KNNClassifier<E> {
|
||||
y: Option<Array1<E>>
|
||||
}
|
||||
|
||||
pub trait KNNAlgorithm<T>{
|
||||
fn find(&self, from: &T, k: i32) -> &Vec<T>;
|
||||
}
|
||||
|
||||
pub struct SimpleKNNAlgorithm<T, A, D>
|
||||
where
|
||||
A: Float,
|
||||
D: Distance<T, A>
|
||||
{
|
||||
data: Vec<T>,
|
||||
distance: D,
|
||||
__phantom: PhantomData<A>
|
||||
}
|
||||
|
||||
impl<T, A, D> KNNAlgorithm<T> for SimpleKNNAlgorithm<T, A, D>
|
||||
where
|
||||
A: Float,
|
||||
D: Distance<T, A>
|
||||
{
|
||||
fn find(&self, from: &T, k: i32) -> &Vec<T> {
|
||||
&self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl<A1, A2> Classifier<A1, A2> for KNNClassifier<A2>
|
||||
where
|
||||
A2: Signed + Clone,
|
||||
{
|
||||
fn fit(&mut self, x: &Array2<A1>, y: &Array1<A2>){
|
||||
self.y = Some(Array1::<A2>::zeros(ArrayBase::len(y)));
|
||||
}
|
||||
|
||||
fn predict(&self, x: &Array2<A1>) -> Array1<A2>{
|
||||
let array = Array1::<A2>::zeros(ArrayBase::len(self.y.as_ref().unwrap()));
|
||||
array
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn knn_fit_predict() {
|
||||
let mut knn = KNNClassifier{y: None};
|
||||
let x = arr2(&[[1, 2, 3],[4, 5, 6]]);
|
||||
let y = arr1(&[1, 2]);
|
||||
knn.fit(&x, &y);
|
||||
let r = knn.predict(&x);
|
||||
assert_eq!(2, ArrayBase::len(&r));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn knn_find() {
|
||||
let sKnn = SimpleKNNAlgorithm{
|
||||
data: vec!(arr1(&[1., 2.]), arr1(&[1., 2.]), arr1(&[1., 2.])),
|
||||
distance: EuclidianDistance{},
|
||||
__phantom: PhantomData
|
||||
};
|
||||
|
||||
assert_eq!(&vec!(arr1(&[1., 2.]), arr1(&[1., 2.]), arr1(&[1., 2.])), sKnn.find(&arr1(&[1., 2.]), 3));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
use ndarray::prelude::*;
|
||||
use ndarray::{arr1, arr2};
|
||||
use ndarray::FixedInitializer;
|
||||
|
||||
pub mod knn;
|
||||
|
||||
pub trait Classifier<E1, E2>
|
||||
{
|
||||
|
||||
fn fit(&mut self, x: &Array2<E1>, y: &Array1<E2>);
|
||||
|
||||
fn predict(&self, x: &Array2<E1>) -> Array1<E2>;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IllegalArgumentError {
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
impl fmt::Display for IllegalArgumentError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.message)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
pub mod classification;
|
||||
pub mod math;
|
||||
pub mod error;
|
||||
pub mod algorithm;
|
||||
@@ -0,0 +1,48 @@
|
||||
use super::Distance;
|
||||
use ndarray::{ArrayBase, Data, Dimension};
|
||||
use num_traits::Float;
|
||||
|
||||
pub struct EuclidianDistance{}
|
||||
|
||||
impl<A, S, D> Distance<ArrayBase<S, D>, A> for EuclidianDistance
|
||||
where
|
||||
A: Float,
|
||||
S: Data<Elem = A>,
|
||||
D: Dimension
|
||||
{
|
||||
|
||||
fn distance(a: &ArrayBase<S, D>, b: &ArrayBase<S, D>) -> A {
|
||||
if a.len() != b.len() {
|
||||
panic!("vectors a and b have different length");
|
||||
} else {
|
||||
((a - b)*(a - b)).sum().sqrt()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use ndarray::{arr1, Array};
|
||||
|
||||
#[test]
|
||||
fn measure_simple_euclidian_distance() {
|
||||
let a = Array::from_vec(vec![1., 2., 3.]);
|
||||
let b = Array::from_vec(vec![4., 5., 6.]);
|
||||
|
||||
let d = EuclidianDistance::distance(&a, &b);
|
||||
|
||||
assert!((d - 5.19615242).abs() < 1e-8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn measure_simple_euclidian_distance_static() {
|
||||
let a = arr1(&[-2.1968219, -0.9559913, -0.0431738, 1.0567679, 0.3853515]);
|
||||
let b = arr1(&[-1.7781325, -0.6659839, 0.9526148, -0.9460919, -0.3925300]);
|
||||
|
||||
let d = EuclidianDistance::distance(&a, &b);
|
||||
|
||||
assert!((d - 2.422302).abs() < 1e-6);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
pub mod euclidian;
|
||||
|
||||
use num_traits::Float;
|
||||
|
||||
pub trait Distance<T, A>
|
||||
where
|
||||
A: Float
|
||||
{
|
||||
fn distance(a: &T, b: &T) -> A;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod distance;
|
||||
Reference in New Issue
Block a user