#![deny(missing_docs)]
use Io::*;
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum AbstractIo {
Constant,
Variable,
Bin(Box<(AbstractIo, AbstractIo)>),
Vector(u64, Box<AbstractIo>),
Tup(Vec<AbstractIo>),
}
#[derive(Clone, PartialEq)]
pub enum Io {
AvatarCore,
Avogadro,
Boltzmann,
Const(f64),
Gravity,
LuminousEfficacy,
Planck,
SpeedOfLight,
Acceleration,
AmountOfSubstance,
Charge,
ElectricCurrent,
Length,
LuminousIntensity,
Mass,
Speed,
ThermodynamicTemperature,
Time,
Volume,
Neg(Box<Io>),
Sqrt(Box<Io>),
Add(Box<(Io, Io)>),
Sub(Box<(Io, Io)>),
Mul(Box<(Io, Io)>),
Div(Box<(Io, Io)>),
Vector(u64, Box<Io>),
Tup(Vec<Io>),
Comp(u64, Box<Io>),
}
impl AbstractIo {
pub fn dim(&self) -> [u64; 2] {
use AbstractIo::*;
match self {
Constant => [1, 0],
Variable => [1, 1],
Bin(ab) => {
let a_dim = ab.0.dim();
let b_dim = ab.1.dim();
[a_dim[0] * b_dim[0], a_dim[1] + b_dim[1]]
}
Vector(n, a) => {
let a_dim = a.dim();
[n * a_dim[0], n * a_dim[1]]
}
Tup(items) => {
let mut sum = [0, 0];
for it in items {
let dim = it.dim();
sum = [sum[0] + dim[0], sum[1] + dim[1]];
}
sum
}
}
}
}
impl Io {
pub fn same(&self, other: &Io) -> bool {
self == other
}
pub fn norm(&self) -> Option<Io> {
if let Vector(n, a) = self {Some(norm(*n, (**a).clone()))} else {None}
}
}
impl Io {
pub fn to_abstract(&self) -> AbstractIo {
match self {
AvatarCore |
Avogadro |
Boltzmann |
Charge |
Const(_) |
Gravity |
LuminousEfficacy |
Planck |
SpeedOfLight => AbstractIo::Constant,
Acceleration |
AmountOfSubstance |
ElectricCurrent |
Length |
LuminousIntensity |
Mass |
Speed |
ThermodynamicTemperature |
Time |
Volume => AbstractIo::Variable,
Neg(a) |
Sqrt(a) => a.to_abstract(),
Add(ab) | Sub(ab) | Mul(ab) | Div(ab) => {
if ab.0.same(&ab.1) {return ab.0.to_abstract()};
AbstractIo::Bin(Box::new((ab.0.to_abstract(), ab.1.to_abstract())))
}
Vector(n, a) => AbstractIo::Vector(*n, Box::new(a.to_abstract())),
Tup(items) => AbstractIo::Tup(items.iter().map(|n| n.to_abstract()).collect()),
Comp(_, a) => a.to_abstract(),
}
}
}
impl Io {
pub fn dim(&self) -> [u64; 2] {self.to_abstract().dim()}
}
pub fn neg(a: Io) -> Io {Neg(Box::new(a))}
pub fn sqrt(a: Io) -> Io {Sqrt(Box::new(a))}
pub fn add(a: Io, b: Io) -> Io {Add(Box::new((a, b)))}
pub fn sub(a: Io, b: Io) -> Io {Sub(Box::new((a, b)))}
pub fn mul(a: Io, b: Io) -> Io {Mul(Box::new((a, b)))}
pub fn div(a: Io, b: Io) -> Io {Div(Box::new((a, b)))}
pub fn square(a: Io) -> Io {mul(a.clone(), a)}
pub fn vec3(a: Io) -> Io {Vector(3, Box::new(a))}
pub fn tup2(a: Io, b: Io) -> Io {Tup(vec![a, b])}
pub fn tup3(a: Io, b: Io, c: Io) -> Io {Tup(vec![a, b, c])}
pub fn sum(n: u64, a: Io) -> Io {
let mut res = AvatarCore;
for i in 0..n {
res = add(res, Comp(i, Box::new(a.clone())));
}
res
}
pub fn prod(n: u64, a: Io) -> Io {
let mut res = AvatarCore;
for i in 0..n {
res = mul(res, Comp(i, Box::new(a.clone())));
}
res
}
pub fn bin(a: AbstractIo, b: AbstractIo) -> AbstractIo {
AbstractIo::Bin(Box::new((a, b)))
}
pub fn fold(n: u64, a: AbstractIo) -> AbstractIo {
let mut res = AbstractIo::Constant;
for _ in 0..n {
res = bin(res, a.clone());
}
res
}
pub fn norm_squared(n: u64, a: Io) -> Io {sum(n, square(a))}
pub fn norm(n: u64, a: Io) -> Io {sqrt(norm_squared(n, a))}
pub fn avg(n: u64, a: Io) -> Io {div(sum(n, a), Const(n as f64))}
pub fn c() -> Io {SpeedOfLight}
pub fn density() -> Io {mul(Mass, Volume)}
pub fn rest_mass_energy() -> Io {mul(Mass, square(c()))}
pub fn position() -> Io {vec3(Length)}
pub fn velocity() -> Io {vec3(Speed)}
pub fn acceleration_vector() -> Io {vec3(Acceleration)}
pub fn force() -> Io {mul(Mass, acceleration_vector())}
pub fn energy() -> Io {mul(mul(Mass, Acceleration), Length)}
pub fn gravity_potential_energy() -> Io {mul(Gravity, mul(Mass, Length))}
pub fn kinetic_energy() -> Io {mul(Const(0.5), mul(Mass, square(Speed)))}
pub fn measure_speed() -> Io {div(Length, Time)}
pub fn measure_speed_between_lengths() -> Io {div(sub(Length, Length), Time)}
pub fn measure_velocity() -> Io {vec3(measure_speed())}
pub fn measure_acceleration() -> Io {div(Length, square(Time))}
pub fn measure_acceleration_vector() -> Io {vec3(measure_acceleration())}
pub fn measure_force() -> Io {mul(Mass, measure_acceleration_vector())}
pub fn measure_energy() -> Io {mul(mul(Mass, measure_acceleration()), Length)}
pub fn measure_gravity_potential_energy() -> Io {gravity_potential_energy()}
pub fn measure_kinetic_energy() -> Io {kinetic_energy()}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_density() {
let a = density();
assert_eq!(a.dim(), [1, 2]);
}
#[test]
fn test_square() {
let a = square(Mass);
assert_eq!(a.dim(), [1, 1]);
}
#[test]
fn test_commute() {
let a = mul(c(), mul(Mass, c()));
let b = rest_mass_energy();
assert_eq!(b.dim(), [1, 1]);
assert_eq!(a.dim(), b.dim());
}
#[test]
fn test_speed() {
let a = measure_speed();
assert_eq!(a.dim(), [1, 2]);
let b = measure_speed_between_lengths();
assert_eq!(b.dim(), [1, 2]);
assert_eq!(a.dim(), b.dim());
}
#[test]
fn test_velocity() {
let a = velocity();
assert_eq!(a.dim(), [3, 3]);
let a = measure_velocity();
assert_eq!(a.dim(), [3, 6]);
}
#[test]
fn test_acceleration() {
let a = measure_acceleration();
assert_eq!(a.dim(), [1, 2]);
let a = acceleration_vector();
assert_eq!(a.dim(), [3, 3]);
let a = measure_acceleration_vector();
assert_eq!(a.dim(), [3, 6]);
}
#[test]
fn test_force() {
let a = force();
assert_eq!(a.dim(), [3, 4]);
let a = measure_force();
assert_eq!(a.dim(), [3, 7]);
}
#[test]
fn test_energy() {
let a = energy();
assert_eq!(a.dim(), [1, 3]);
let a = measure_energy();
assert_eq!(a.dim(), [1, 4]);
}
#[test]
fn test_tup() {
let a = tup2(measure_force(), measure_energy());
assert_eq!(a.dim(), [4, 11]);
}
#[test]
fn test_gravity_potential_energy() {
let a = gravity_potential_energy();
assert_eq!(a.dim(), [1, 2]);
let a = measure_gravity_potential_energy();
assert_eq!(a.dim(), [1, 2]);
}
#[test]
fn test_kinetic_energy() {
let a = kinetic_energy();
assert_eq!(a.dim(), [1, 2]);
let a = measure_kinetic_energy();
assert_eq!(a.dim(), [1, 2]);
}
#[test]
fn test_sub() {
let a = sub(Length, Time);
let b = add(Length, neg(Time));
assert_eq!(a.dim(), b.dim());
}
#[test]
fn test_norm() {
let a = norm(3, measure_speed());
assert_eq!(a.dim(), [1, 6]);
let b = measure_velocity();
assert_eq!(b.dim(), [3, 6]);
assert!(a.dim() != b.dim());
let c = measure_velocity().norm().unwrap();
assert_eq!(c.dim(), [1, 6]);
assert_eq!(a.dim(), c.dim());
}
#[test]
fn test_fold() {
let n = 10;
let a = sum(n, Length);
let b = fold(n, Length.to_abstract());
assert_eq!(a.dim(), b.dim());
let a = sum(n, measure_speed());
let b = fold(n, measure_speed().to_abstract());
assert_eq!(a.dim(), b.dim());
}
}