Skip to content

Commit

Permalink
Migrated the remaining parts of math module.
Browse files Browse the repository at this point in the history
We now have `slice`, `rng` and `func` modules in the codebase. This commit does not include unit tests and documentation, whose progress can be tracked on issues #23 and #22 respectively. Added `lazy_static` as a dependency.
  • Loading branch information
sammorrell committed Jan 10, 2022
1 parent f36ffc6 commit 9e02998
Show file tree
Hide file tree
Showing 10 changed files with 749 additions and 2 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ ndarray = { version = "0.15.*", features = ["rayon", "serde-1"] }
ndarray-stats = "0.5.*"
ndarray-parallel = "0.9.*"
indicatif = "0.16.*"
lazy_static = "1.4.*"

# Formats for the File I/O Library.
json5 = "0.4.*"
Expand Down
209 changes: 209 additions & 0 deletions src/math/func/formula.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
//! Formula implementation.

use crate::math::is_ascending;
use ndarray::Array1;
use std::fmt::{Display, Error, Formatter};

/// Mathematical formulae accepting a single scalar argument.
#[derive(Debug, Clone)]
pub enum Formula {
/// Constant value. = c
Constant {
/// Constant.
c: f64,
},
/// Line formula. = mx + c
Line {
/// Offset.
c: f64,
/// Gradient.
m: f64,
},
/// Bifurcation formula. = if x < t { under } else { over }.
Bifurcation {
/// Threshold value.
t: f64,
/// Under value.
under: f64,
/// Over value.
over: f64,
},
/// Constant value spline.
ConstantSpline {
/// X change points.
xs: Array1<f64>,
/// Y values.
ys: Array1<f64>,
},
/// Linear spline.
LinearSpline {
/// X change points.
xs: Array1<f64>,
/// Y values.
ys: Array1<f64>,
/// Gradient between points.
grads: Array1<f64>,
},
/// Quadratic spline.
QuadraticSpline {
/// X change points.
xs: Array1<f64>,
/// Y values.
ys: Array1<f64>,
/// Gradient between points.
grads: Array1<f64>,
/// Second order term between points.
quads: Array1<f64>,
},
}

impl Formula {
/// Construct a constant spline instance.
#[inline]
#[must_use]
pub fn new_constant_spline(xs: Array1<f64>, ys: Array1<f64>) -> Self {
debug_assert!(xs.len() >= 2);
debug_assert!(is_ascending(xs.as_slice().unwrap()));
debug_assert!(ys.len() == xs.len());

Self::ConstantSpline { xs, ys }
}

/// Construct a linear spline instance.
#[inline]
#[must_use]
pub fn new_linear_spline(xs: Array1<f64>, ys: Array1<f64>, grads: Array1<f64>) -> Self {
debug_assert!(xs.len() >= 2);
debug_assert!(is_ascending(xs.as_slice().unwrap()));
debug_assert!(ys.len() == xs.len());
debug_assert!((grads.len() + 1) == xs.len());

Self::LinearSpline { xs, ys, grads }
}

/// Construct a linear spline instance.
#[inline]
#[must_use]
pub fn new_linear_spline_auto(xs: Array1<f64>, ys: Array1<f64>) -> Self {
debug_assert!(xs.len() >= 2);
debug_assert!(is_ascending(xs.as_slice().unwrap()));
debug_assert!(ys.len() == xs.len());

let mut grads = Vec::with_capacity(xs.len() - 1);
for ((x_curr, x_next), (y_curr, y_next)) in xs
.iter()
.zip(xs.iter().skip(1))
.zip(ys.iter().zip(ys.iter().skip(1)))
{
grads.push((y_next - y_curr) / (x_next - x_curr));
}

Self::new_linear_spline(xs, ys, Array1::from(grads))
}

/// Construct a quadratic spline instance.
#[inline]
#[must_use]
pub fn new_quadratic_spline(
xs: Array1<f64>,
ys: Array1<f64>,
grads: Array1<f64>,
quads: Array1<f64>,
) -> Self {
debug_assert!(xs.len() >= 2);
debug_assert!(is_ascending(xs.as_slice().unwrap()));
debug_assert!(ys.len() == xs.len());
debug_assert!((grads.len() + 1) == xs.len());
debug_assert!((quads.len() + 1) == xs.len());

Self::QuadraticSpline {
xs,
ys,
grads,
quads,
}
}

/// Determine the corresponding output value for the given input.
#[inline]
#[must_use]
pub fn y(&self, x: f64) -> f64 {
match *self {
Self::Constant { ref c } => *c,
Self::Line { c, m } => x.mul_add(m, c),
Self::Bifurcation {
ref t,
ref under,
ref over,
} => {
if x < *t {
*under
} else {
*over
}
}
Self::ConstantSpline { ref xs, ref ys } => {
debug_assert!(x >= xs[0]);
debug_assert!(x <= xs[xs.len() - 1]);

for (index, xn) in xs.iter().enumerate() {
if *xn > x {
return ys[index - 1];
}
}
ys[ys.len() - 1]
}
Self::LinearSpline {
ref xs,
ref ys,
ref grads,
} => {
debug_assert!(x >= xs[0]);
debug_assert!(x <= xs[xs.len() - 1]);

for (index, xn) in xs.iter().enumerate() {
if *xn > x {
let dx = x - xs[index - 1];
return grads[index - 1].mul_add(dx, ys[index - 1]);
}
}
ys[ys.len() - 1]
}
Self::QuadraticSpline {
ref xs,
ref ys,
ref grads,
ref quads,
} => {
debug_assert!(x >= xs[0]);
debug_assert!(x <= xs[xs.len() - 1]);

for (index, xn) in xs.iter().enumerate() {
if *xn > x {
let dx = x - xs[index - 1];
let y = ys[index - 1];
let g = grads[index - 1];
let q = quads[index - 1];
return q.mul_add(dx * dx, g.mul_add(dx, y));
}
}
ys[ys.len() - 1]
}
}
}
}

impl Display for Formula {
#[inline]
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
let kind = match *self {
Self::Constant { .. } => "Constant",
Self::Line { .. } => "Line",
Self::Bifurcation { .. } => "Bifurcation",
Self::ConstantSpline { .. } => "Constant Spline",
Self::LinearSpline { .. } => "Linear Spline",
Self::QuadraticSpline { .. } => "Quadrati Spline",
};
write!(fmt, "{}", kind)
}
}
71 changes: 71 additions & 0 deletions src/math/func/formula_builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
//! Formula form implementation.

use crate::ord::Build;
use arctk_attr::file;
use ndarray::Array1;
use std::fmt::{Display, Formatter};

/// Mathematical formulae accepting a single scalar argument.
#[file]
pub enum FormulaBuilder {
/// Constant value. = c
Constant(f64),
/// Line formula. = (x * m) + c
Line(f64, f64),
/// Bifurcation formula. = x < y ? a : b.
Bifurcation(f64, f64, f64),
/// Constant value spline.
ConstantSpline(Vec<f64>, Vec<f64>),
/// Linear spline between points.
LinearSpline(Vec<f64>, Vec<f64>, Vec<f64>),
/// Connected linear spline between points.
LinearSplineAuto(Vec<f64>, Vec<f64>),
/// Quadratic spline between points.
QuadraticSpline(Vec<f64>, Vec<f64>, Vec<f64>, Vec<f64>),
}

impl Build for FormulaBuilder {
type Inst = crate::math::Formula;

#[inline]
fn build(self) -> Self::Inst {
match self {
Self::Constant(c) => Self::Inst::Constant { c },
Self::Line(c, m) => Self::Inst::Line { c, m },
Self::Bifurcation(t, under, over) => Self::Inst::Bifurcation { t, under, over },
Self::ConstantSpline(xs, ys) => {
Self::Inst::new_constant_spline(Array1::from(xs), Array1::from(ys))
}
Self::LinearSpline(xs, ys, grads) => Self::Inst::new_linear_spline(
Array1::from(xs),
Array1::from(ys),
Array1::from(grads),
),
Self::LinearSplineAuto(xs, ys) => {
Self::Inst::new_linear_spline_auto(Array1::from(xs), Array1::from(ys))
}
Self::QuadraticSpline(xs, ys, grads, quads) => Self::Inst::new_quadratic_spline(
Array1::from(xs),
Array1::from(ys),
Array1::from(grads),
Array1::from(quads),
),
}
}
}

impl Display for FormulaBuilder {
#[inline]
fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
let kind = match *self {
Self::Constant { .. } => "Constant",
Self::Line { .. } => "Line",
Self::Bifurcation { .. } => "Bifurcation",
Self::ConstantSpline { .. } => "Constant Spline",
Self::LinearSpline { .. } => "Linear Spline",
Self::LinearSplineAuto { .. } => "Linear Spline [auto]",
Self::QuadraticSpline { .. } => "Quadratic Spline",
};
write!(fmt, "{}", kind)
}
}
6 changes: 6 additions & 0 deletions src/math/func/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//! Mathematical function module.

pub mod formula;
pub mod formula_builder;

pub use self::{formula::*, formula_builder::*};
21 changes: 21 additions & 0 deletions src/math/linalg/rot/rot3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@ impl Mul<Dir3> for Rot3 {
}
}

impl Mul<&Dir3> for Rot3 {
type Output = Dir3;

#[inline]
#[must_use]
fn mul(self, rhs: &Dir3) -> Self::Output {
Self::Output::from(self.data * rhs.data())
}
}

impl Mul<Vec3> for Rot3 {
type Output = Vec3;

Expand All @@ -67,3 +77,14 @@ impl Mul<Vec3> for Rot3 {
Self::Output::from(self.data * rhs.data())
}
}


impl Mul<&Vec3> for Rot3 {
type Output = Vec3;

#[inline]
#[must_use]
fn mul(self, rhs: &Vec3) -> Self::Output {
Self::Output::from(self.data * rhs.data())
}
}
6 changes: 4 additions & 2 deletions src/math/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
//! Mathematics module.

pub mod alias;
pub mod func;
pub mod linalg;

pub mod rng;
pub mod slice;
pub mod trans3_builder;

pub use self::{alias::*, linalg::*, trans3_builder::*};
pub use self::{alias::*, func::*, linalg::*, rng::*, slice::*, trans3_builder::*};
Loading

0 comments on commit 9e02998

Please sign in to comment.