Initial commit

This commit is contained in:
Volodymyr Orlov
2019-05-28 17:46:03 -07:00
parent f0275e2fc4
commit f4d3a80490
14 changed files with 285 additions and 0 deletions
+8
View File
@@ -8,3 +8,11 @@ Cargo.lock
# These are backup files generated by rustfmt # These are backup files generated by rustfmt
**/*.rs.bk **/*.rs.bk
# IDE
.idea
.project
.vscode
# OS
.DS_Store
+18
View File
@@ -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
+19
View File
@@ -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);
+9
View File
@@ -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>
+1
View File
@@ -0,0 +1 @@
pub mod sort;
+64
View File
@@ -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);
}
}
+1
View File
@@ -0,0 +1 @@
pub mod heap_select;
+76
View File
@@ -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));
}
}
+14
View File
@@ -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>;
}
+12
View File
@@ -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)
}
}
+4
View File
@@ -0,0 +1,4 @@
pub mod classification;
pub mod math;
pub mod error;
pub mod algorithm;
+48
View File
@@ -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);
}
}
+10
View File
@@ -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;
}
+1
View File
@@ -0,0 +1 @@
pub mod distance;