use symplex::units::*;
use symplex::prelude::*;
#[test]
fn dim_mass_times_acceleration_is_force() {
let ctx = Context::new();
let m = Mass::symbol(&ctx, "m");
let a = Acceleration::symbol(&ctx, "a");
let f: Force = symplex::dim!(ctx, Force: m * a);
assert_eq!(format!("{}", f.inner()), "a*m");
}
#[test]
fn dim_force_times_length_is_energy() {
let ctx = Context::new();
let f = Force::symbol(&ctx, "F");
let d = Length::symbol(&ctx, "d");
let e: Energy = symplex::dim!(ctx, Energy: f * d);
assert_eq!(format!("{}", e.inner()), "F*d");
}
#[test]
fn dim_mass_times_gravity_times_height() {
let ctx = Context::new();
let m = Mass::symbol(&ctx, "m");
let g = Acceleration::symbol(&ctx, "g");
let h = Length::symbol(&ctx, "h");
let pe: Energy = symplex::dim!(ctx, Energy: m * g * h);
let inner = format!("{}", pe.inner());
assert!(inner.contains("m"));
assert!(inner.contains("g"));
assert!(inner.contains("h"));
}
#[test]
fn dim_length_div_time_is_velocity() {
let ctx = Context::new();
let l = Length::symbol(&ctx, "L");
let t = Time::symbol(&ctx, "t");
let v: Velocity = symplex::dim!(ctx, Velocity: l / t);
assert_eq!(format!("{}", v.inner()), "L/t");
}
#[test]
fn dim_energy_div_time_is_power() {
let ctx = Context::new();
let e = Energy::symbol(&ctx, "E_val");
let t = Time::symbol(&ctx, "t");
let p: Power = symplex::dim!(ctx, Power: e / t);
assert_eq!(format!("{}", p.inner()), "E_val/t");
}
#[test]
fn dim_force_div_area_is_pressure() {
let ctx = Context::new();
let f = Force::symbol(&ctx, "F");
let a = Area::symbol(&ctx, "A");
let p: Pressure = symplex::dim!(ctx, Pressure: f / a);
assert_eq!(format!("{}", p.inner()), "F/A");
}
#[test]
fn dim_add_same_type() {
let ctx = Context::new();
let f1 = Force::symbol(&ctx, "F1");
let f2 = Force::symbol(&ctx, "F2");
let total: Force = symplex::dim!(ctx, Force: f1 + f2);
assert_eq!(format!("{}", total.inner()), "F1 + F2");
}
#[test]
fn dim_sub_same_type() {
let ctx = Context::new();
let e1 = Energy::symbol(&ctx, "KE");
let e2 = Energy::symbol(&ctx, "PE");
let diff: Energy = symplex::dim!(ctx, Energy: e1 - e2);
assert_eq!(format!("{}", diff.inner()), "KE - PE");
}
#[test]
fn dim_negation() {
let ctx = Context::new();
let f = Force::symbol(&ctx, "F");
let neg_f: Force = symplex::dim!(ctx, Force: -f);
assert_eq!(format!("{}", neg_f.inner()), "-F");
}
#[test]
fn dim_scalar_multiply_by_integer() {
let ctx = Context::new();
let f = Force::symbol(&ctx, "F");
let doubled: Force = symplex::dim!(ctx, Force: 2 * f);
assert_eq!(format!("{}", doubled.inner()), "2*F");
}
#[test]
fn dim_rational_constant() {
let ctx = Context::new();
let v = Velocity::symbol(&ctx, "v");
let half_v: Velocity = symplex::dim!(ctx, Velocity: 1/2 * v);
assert_eq!(format!("{}", half_v.inner()), "1/2*v");
}
#[test]
fn dim_integer_is_dimensionless() {
let ctx = Context::new();
let d: Dimensionless = symplex::dim!(ctx, Dimensionless: 42);
assert_eq!(format!("{}", d.inner()), "42");
}
#[test]
fn dim_length_squared_is_area() {
let ctx = Context::new();
let l = Length::symbol(&ctx, "r");
let a: Area = symplex::dim!(ctx, Area: l^2);
assert_eq!(format!("{}", a.inner()), "r^2");
}
#[test]
fn dim_length_cubed_is_volume() {
let ctx = Context::new();
let l = Length::symbol(&ctx, "r");
let vol: Volume = symplex::dim!(ctx, Volume: l^3);
assert_eq!(format!("{}", vol.inner()), "r^3");
}
#[test]
fn dim_power_zero_is_dimensionless() {
let ctx = Context::new();
let _m = Mass::symbol(&ctx, "m");
let one: Dimensionless = symplex::dim!(ctx, Dimensionless: _m^0);
assert_eq!(format!("{}", one.inner()), "1");
}
#[test]
fn dim_power_one_identity() {
let ctx = Context::new();
let l = Length::symbol(&ctx, "x");
let same: Length = symplex::dim!(ctx, Length: l^1);
assert_eq!(format!("{}", same.inner()), "x");
}
#[test]
fn dim_kinetic_energy() {
let ctx = Context::new();
let m = Mass::symbol(&ctx, "m");
let v = Velocity::symbol(&ctx, "v");
let ke: Energy = symplex::dim!(ctx, Energy: 1/2 * m * v^2);
let inner = format!("{}", ke.inner());
assert!(inner.contains("m"));
assert!(inner.contains("v"));
}
#[test]
fn dim_spring_potential_energy() {
let ctx = Context::new();
let k = Stiffness::symbol(&ctx, "k");
let x = Length::symbol(&ctx, "x");
let pe: Energy = symplex::dim!(ctx, Energy: 1/2 * k * x^2);
let inner = format!("{}", pe.inner());
assert!(inner.contains("k"));
assert!(inner.contains("x"));
}
#[test]
fn dim_momentum_equals_mass_times_velocity() {
let ctx = Context::new();
let m = Mass::symbol(&ctx, "m");
let v = Velocity::symbol(&ctx, "v");
let p: Momentum = symplex::dim!(ctx, Momentum: m * v);
let inner = format!("{}", p.inner());
assert!(inner.contains("m"));
assert!(inner.contains("v"));
}
#[test]
fn dim_ohms_law() {
let ctx = Context::new();
let i = Current::symbol(&ctx, "I_val");
let r = Resistance::symbol(&ctx, "R");
let v: Voltage = symplex::dim!(ctx, Voltage: i * r);
let inner = format!("{}", v.inner());
assert!(inner.contains("I_val"));
assert!(inner.contains("R"));
}
#[test]
fn dim_power_electrical() {
let ctx = Context::new();
let v = Voltage::symbol(&ctx, "V_val");
let i = Current::symbol(&ctx, "I_val");
let p: Power = symplex::dim!(ctx, Power: v * i);
let inner = format!("{}", p.inner());
assert!(inner.contains("V_val"));
assert!(inner.contains("I_val"));
}
#[test]
fn dim_pi_is_dimensionless() {
let ctx = Context::new();
let d: Dimensionless = symplex::dim!(ctx, Dimensionless: pi);
assert_eq!(format!("{}", d.inner()), "pi");
}
#[test]
fn dim_pi_times_length_squared_is_area() {
let ctx = Context::new();
let r = Length::symbol(&ctx, "r");
let circle_area: Area = symplex::dim!(ctx, Area: pi * r^2);
let inner = format!("{}", circle_area.inner());
assert!(inner.contains("pi"));
assert!(inner.contains("r"));
}
#[test]
fn dim_euler_number_is_dimensionless() {
let ctx = Context::new();
let d: Dimensionless = symplex::dim!(ctx, Dimensionless: E);
assert_eq!(format!("{}", d.inner()), "E");
}
#[test]
fn dim_sin_returns_dimensionless() {
let ctx = Context::new();
let theta = Dimensionless::symbol(&ctx, "theta");
let s: Dimensionless = symplex::dim!(ctx, Dimensionless: sin(theta));
assert_eq!(format!("{}", s.inner()), "sin(theta)");
}
#[test]
fn dim_cos_returns_dimensionless() {
let ctx = Context::new();
let theta = Dimensionless::symbol(&ctx, "theta");
let c: Dimensionless = symplex::dim!(ctx, Dimensionless: cos(theta));
assert_eq!(format!("{}", c.inner()), "cos(theta)");
}
#[test]
fn dim_exp_returns_dimensionless() {
let ctx = Context::new();
let x = Dimensionless::symbol(&ctx, "x");
let e: Dimensionless = symplex::dim!(ctx, Dimensionless: exp(x));
assert_eq!(format!("{}", e.inner()), "exp(x)");
}
#[test]
fn dim_ln_returns_dimensionless() {
let ctx = Context::new();
let x = Dimensionless::symbol(&ctx, "x");
let l: Dimensionless = symplex::dim!(ctx, Dimensionless: ln(x));
assert_eq!(format!("{}", l.inner()), "ln(x)");
}
#[test]
fn dim_function_result_scaled_by_quantity() {
let ctx = Context::new();
let m = Mass::symbol(&ctx, "m");
let g = Acceleration::symbol(&ctx, "g");
let theta = Dimensionless::symbol(&ctx, "theta");
let f: Force = symplex::dim!(ctx, Force: m * g * sin(theta));
let inner = format!("{}", f.inner());
assert!(inner.contains("m"));
assert!(inner.contains("g"));
assert!(inner.contains("sin"));
}
#[test]
fn dim_uses_variables_by_cloning() {
let ctx = Context::new();
let m = Mass::symbol(&ctx, "m");
let g = Acceleration::symbol(&ctx, "g");
let h = Length::symbol(&ctx, "h");
let _e: Energy = symplex::dim!(ctx, Energy: m * g * h);
let m2 = Mass::symbol(&ctx, "m");
let g2 = Acceleration::symbol(&ctx, "g");
let h2 = Length::symbol(&ctx, "h");
let _e2: Energy = symplex::dim!(ctx, Energy: m2 * g2 * h2);
}
#[test]
fn dim_gravitational_potential_energy() {
let ctx = Context::new();
let m = Mass::symbol(&ctx, "m");
let g = Acceleration::symbol(&ctx, "g");
let h = Length::symbol(&ctx, "h");
let u: Energy = symplex::dim!(ctx, Energy: m * g * h);
let inner = format!("{}", u.inner());
assert!(inner.contains("m"));
assert!(inner.contains("g"));
assert!(inner.contains("h"));
}
#[test]
fn dim_damped_force() {
let ctx = Context::new();
let b = Damping::symbol(&ctx, "b");
let v = Velocity::symbol(&ctx, "v");
let k = Stiffness::symbol(&ctx, "k");
let x = Length::symbol(&ctx, "x");
let f: Force = symplex::dim!(ctx, Force: -b * v - k * x);
let inner = format!("{}", f.inner());
assert!(inner.contains("b"));
assert!(inner.contains("v"));
assert!(inner.contains("k"));
assert!(inner.contains("x"));
}
#[test]
fn dim_moment_of_inertia_rod() {
let ctx = Context::new();
let m = Mass::symbol(&ctx, "m");
let big_l = Length::symbol(&ctx, "L");
let moi: MomentOfInertia = symplex::dim!(ctx, MomentOfInertia: 1/12 * m * big_l^2);
let inner = format!("{}", moi.inner());
assert!(inner.contains("m"));
assert!(inner.contains("L"));
}
#[test]
fn dim_charge_is_current_times_time() {
let ctx = Context::new();
let i = Current::symbol(&ctx, "I_val");
let t = Time::symbol(&ctx, "t");
let q: Charge = symplex::dim!(ctx, Charge: i * t);
let inner = format!("{}", q.inner());
assert!(inner.contains("I_val"));
assert!(inner.contains("t"));
}
#[test]
fn dim_voltage_from_inductance_and_current_rate() {
let ctx = Context::new();
let l = Inductance::symbol(&ctx, "L_ind");
let di = Current::symbol(&ctx, "dI");
let dt = Time::symbol(&ctx, "dt");
let v: Voltage = symplex::dim!(ctx, Voltage: l * di / dt);
let inner = format!("{}", v.inner());
assert!(inner.contains("L_ind"));
assert!(inner.contains("dI"));
assert!(inner.contains("dt"));
}
#[test]
fn dim_parenthesised_addition_then_multiply() {
let ctx = Context::new();
let m = Mass::symbol(&ctx, "m");
let a1 = Acceleration::symbol(&ctx, "a1");
let a2 = Acceleration::symbol(&ctx, "a2");
let f: Force = symplex::dim!(ctx, Force: m * (a1 + a2));
let inner = format!("{}", f.inner());
assert!(inner.contains("m"));
assert!(inner.contains("a1"));
assert!(inner.contains("a2"));
}
#[test]
fn dim_numerical_eval() {
let ctx = Context::new();
let m = Mass::from_ex(ctx.int(10));
let a = Acceleration::from_ex(ctx.rational(98, 10));
let f: Force = symplex::dim!(ctx, Force: m * a);
let val = f.eval_f64().unwrap();
assert!((val - 98.0).abs() < 1e-10);
}
#[test]
fn dim_circle_area_numerical() {
let ctx = Context::new();
let r = Length::from_ex(ctx.int(5));
let a: Area = symplex::dim!(ctx, Area: pi * r^2);
let val = a.eval().eval_f64().unwrap();
let expected = std::f64::consts::PI * 25.0;
assert!((val - expected).abs() < 1e-10);
}