## ~axect/Peroxide

ref: 2e9b2744bcac8348cc8f4103c4a3f8de1bf0a5d9 Peroxide/README.md -rw-r--r-- 9.8 KiB
2e9b2744axect Sourcehut badges (True markdown embedded) 9 months ago

## Peroxide

Pure Rust numeric library contains linear algebra, numerical analysis, statistics and machine learning tools with R, MATLAB, Python like macros.

### Latest README version

Corresponding to `0.12.3`.

### Pre-requisite

• Python module : `matplotlib` for plotting

### Install

• Add next line to your `cargo.toml` ```toml peroxide = "0.12" ```

### Example

#### Basic Runge-Kutta 4th order with inline-python

```#![feature(proc_macro_hygiene)]
extern crate peroxide;
extern crate inline_python;
use peroxide::*;
use inline_python::python;

fn main() {
// Initial condition
let init_state = State::<f64>::new(0f64, c!(1), c!(0));

let mut ode_solver = ExplicitODE::new(test_fn);

ode_solver
.set_method(ExMethod::RK4)
.set_initial_condition(init_state)
.set_step_size(0.01)
.set_times(1000);

let result = ode_solver.integrate();

let x = result.col(0);
let y = result.col(1);

// Plot (Thanks to inline-python)
python! {
import pylab as plt
plt.plot('x, 'y)
plt.show()
}
}

// dy/dx = (5x^2 - y) / e^(x+y)
fn test_fn(st: &mut State<f64>) {
let x = st.param;
let y = &st.value;
let dy = &mut st.deriv;
dy[0] = (5f64 * x.powi(2) - y[0]) / (x + y[0]).exp();
}
```

#### Basic Runge-Kutta 4th order with advanced plotting

```extern crate peroxide;
use peroxide::*;

fn main() {
let init_state = State::<f64>::new(0f64, c!(1), c!(0));

let mut ode_solver = ExplicitODE::new(test_fn);

ode_solver
.set_method(ExMethod::RK4)
.set_initial_condition(init_state)
.set_step_size(0.01)
.set_times(1000);

let result = ode_solver.integrate();

let x = result.col(0);
let y = result.col(1);

// Plot (using python matplotlib)
let mut plt = Plot2D::new();
plt.set_domain(x)
.insert_image(y)
.set_title("Test Figure")
.set_fig_size((10, 6))
.set_dpi(300)
.set_legends(vec!["RK4"])
.set_path("example_data/test_plot.png");

plt.savefig();
}

fn test_fn(st: &mut State<f64>) {
let x = st.param;
let y = &st.value;
let dy = &mut st.deriv;
dy[0] = (5f64 * x.powi(2) - y[0]) / (x + y[0]).exp();
}
```

#### Basic Runge-Kutta 4th order with Stop condition

```extern crate peroxide;
use peroxide::*;

fn main() {
let init_state = State::<f64>::new(0f64, c!(1), c!(0));

let mut ode_solver = ExplicitODE::new(test_fn);

ode_solver
.set_method(ExMethod::RK4)
.set_initial_condition(init_state)
.set_step_size(0.01)
.set_stop_condition(stop)        // Add stop condition
.set_times(1000);

let result = ode_solver.integrate();

let x = result.col(0);
let y = result.col(1);

let mut plt = Plot2D::new();
plt.set_domain(x)
.insert_image(y)
.set_title("Test Figure")
.set_fig_size((10, 6))
.set_dpi(300)
.set_legends(vec!["RK4"])
.set_path("example_data/test_plot.png");

plt.savefig();
}

fn test_fn(st: &mut State<f64>) {
let x = st.param;
let y = &st.value;
let dy = &mut st.deriv;
dy[0] = (5f64 * x.powi(2) - y[0]) / (x + y[0]).exp();
}

fn stop(st: &ExplicitODE) -> bool {
let y = &st.get_state().value[0];
(*y - 2.4).abs() < 0.01
}
```

#### Multi-Layer Perceptron (from scratch)

```extern crate peroxide;
use peroxide::*;

// x : n x L
// xb: n x (L+1)
// v : (L+1) x M
// a : n x M
// ab: n x (M+1)
// w : (M+1) x n
// wb: M x N
// y : n x N
// t : n x N
// dh: n x M
// do: n x N

fn main() {
let v = weights_init(3, 2);
let w = weights_init(3, 1);

let x = ml_matrix("0 0; 0 1; 1 0; 1 1");
let t = ml_matrix("0;1;1;0");

let y = train(v, w, x, t, 0.25, 5000);
y.print();
}

fn weights_init(m: usize, n: usize) -> Matrix {
rand(m, n) * 2f64 - 1f64
}

fn sigmoid(x: f64) -> f64 {
1f64 / (1f64 + (-x).exp())
}

fn forward(weights: Matrix, input_bias: Matrix) -> Matrix {
let s = input_bias * weights;
s.fmap(|x| sigmoid(x))
}

fn add_bias(input: Matrix, bias: f64) -> Matrix {
let b = matrix(vec![bias; input.row], input.row, 1, Col);
cbind(b, input)
}

fn hide_bias(weight: Matrix) -> Matrix {
weight.skip(1, Row)
}

fn train(
weights1: Matrix,
weights2: Matrix,
input: Matrix,
eta: f64,
times: usize,
) -> Matrix {
let x = input;
let mut v = weights1;
let mut w = weights2;
let t = answer;
let xb = add_bias(x.clone(), -1f64);

for _i in 0..times {
let a = forward(v.clone(), xb.clone());
let ab = add_bias(a.clone(), -1f64);
let y = forward(w.clone(), ab.clone());
//        let err = (y.clone() - t.clone()).t() * (y.clone() - t.clone());
let wb = hide_bias(w.clone());
let delta_o = (y.clone() - t.clone()) * y.clone() * (1f64 - y.clone());
let delta_h = (delta_o.clone() * wb.t()) * a.clone() * (1f64 - a.clone());

w = w.clone() - eta * (ab.t() * delta_o);
v = v.clone() - eta * (xb.t() * delta_h);
}

let a = forward(v, xb);
let ab = add_bias(a, -1f64);
let y = forward(w, ab);

y
}
```

#### Levenberg-Marquardt Algorithm (refer to lm.pdf)

```extern crate peroxide;
use peroxide::*;

fn main() {
let noise = Normal(0., 0.5);
let p_true: Vec<Number> = NumberVector::from_f64_vec(vec![20f64, 10f64, 1f64, 50f64]);
let p_init = vec![5f64, 2f64, 0.2f64, 10f64];
let domain = seq(0, 99, 1);
let real = f(&domain, p_true.clone()).to_f64_vec();
let y = zip_with(|x, y| x + y, &real, &noise.sample(100));
let data = hstack!(domain.clone(), y.clone());

let mut opt = Optimizer::new(data, f);
let p = opt
.set_init_param(p_init)
.set_max_iter(100)
.set_method(LevenbergMarquardt)
.optimize();
p.print();
opt.get_error().print();
}

fn f(domain: &Vec<f64>, p: Vec<Number>) -> Vec<Number> {
domain.clone().into_iter()
.map(|t| Number::from_f64(t))
.map(|t| p[0] * (-t / p[1]).exp() + p[2] * t * (-t / p[3]).exp())
.collect()
}
```

### Version Info

To see RELEASES.md

To see TODO.md