1pub mod calculus;
2pub mod complex;
3pub mod consts;
4pub mod linear;
5pub mod stats;
6pub mod units;
7pub mod algebra;
8
9#[cfg(test)]
10mod tests {
11 use super::*;
12 use crate::complex::Complex;
13 use crate::consts::Const;
14 use crate::linear::{Matrix, Vector};
15 use crate::stats::Stats;
16 use crate::units::*;
17 use std::f64::consts::PI;
18
19 #[test]
21 fn test_mathematical_constants() {
22 assert_eq!(Const::pi(Some(7)), 3.1415927);
23 assert_eq!(Const::e(Some(7)), 2.7182818);
24 assert_eq!(Const::golden_ratio(Some(8)), 1.61803399);
25
26 assert!((Const::PI - std::f64::consts::PI).abs() < 1e-10);
27 assert!((Const::E - std::f64::consts::E).abs() < 1e-10);
28 assert!((Const::GOLDEN_RATIO - 1.618033988749895).abs() < 1e-10);
29 }
30
31 #[test]
32 fn test_physical_constants() {
33 assert!((Const::GRAVITATIONAL_CONSTANT - 6.67430e-11).abs() < 1e-15);
34 assert!(
35 (Const::REDUCED_PLANCK_CONSTANT - Const::PLANCK_CONSTANT / (2.0 * Const::PI)).abs()
36 < 1e-40
37 );
38 assert!((Const::BOLTZMANN_CONSTANT - 1.380649e-23).abs() < 1e-28);
39 assert!((Const::PROTON_MASS - 1.67262192369e-27).abs() < 1e-35);
40 assert!((Const::AVOGADRO_CONSTANT - 6.02214076e23).abs() < 1e15);
41 }
42
43 #[test]
44 fn test_precision_handling() {
45 assert_eq!(Const::pi(Some(2)), 3.14);
46 assert_eq!(Const::pi(Some(4)), 3.1416);
47 assert_eq!(Const::e(Some(2)), 2.72);
48 assert_eq!(Const::e(Some(4)), 2.7183);
49 assert_eq!(Const::golden_ratio(Some(2)), 1.62);
50 assert_eq!(Const::golden_ratio(Some(4)), 1.6180);
51 }
52
53 #[test]
54 fn test_constant_unit_conversions() {
55 let g_in_nm3_kg_s2 = Const::gravitational_constant(Force::Newton);
56 assert!(g_in_nm3_kg_s2.to_newtons() > 0.0);
57
58 let h_in_joule_sec = Const::planck_constant(Energy::Joule);
59 assert!(h_in_joule_sec.to_joules() > 0.0);
60
61 let kb_in_joule_per_k = Const::boltzmann_constant(Energy::Joule);
62 assert!(kb_in_joule_per_k.to_joules() > 0.0);
63
64 let me_in_atomic_units = Const::electron_mass(Mass::Atomic);
65 assert!(me_in_atomic_units.to_kg() > 0.0);
66
67 let mp_in_atomic_units = Const::proton_mass(Mass::Atomic);
68 assert!(mp_in_atomic_units.to_kg() > 0.0);
69
70 let na_in_hz = Const::avogadro_constant(Frequency::Hertz);
71 assert!(na_in_hz.to_hertz() > 0.0);
72 }
73
74 #[test]
75 fn test_derived_constants() {
76 let fine_structure = Const::ELEMENTARY_CHARGE.powi(2)
77 / (4.0
78 * Const::PI
79 * 8.854187812813e-12
80 * Const::REDUCED_PLANCK_CONSTANT
81 * Const::SPEED_OF_LIGHT);
82 assert!((fine_structure - 0.0072973525693).abs() < 1e-10);
83 }
84
85 #[test]
86 fn test_constant_relationships() {
87 let thermal_energy_at_room_temp = Const::BOLTZMANN_CONSTANT * 300.0;
88 assert!(thermal_energy_at_room_temp > 0.0);
89
90 let electron_rest_energy = Const::ELECTRON_MASS * Const::SPEED_OF_LIGHT.powi(2);
91 assert!(electron_rest_energy > 0.0);
92
93 let proton_electron_mass_ratio = Const::PROTON_MASS / Const::ELECTRON_MASS;
94 assert!((proton_electron_mass_ratio - 1836.15267343).abs() < 1e-6);
95 }
96
97 #[test]
98 fn test_constant_conversions() {
99 let c_in_kmh = Const::speed_of_light(Speed::KmH);
100 let e_in_ev = Const::elementary_charge(ElectricCharge::ElementaryCharge);
101 let m_in_kg = Const::electron_mass(Mass::Kg);
102 assert!(c_in_kmh.to_mps() > 0.0);
103 assert!(e_in_ev.to_coulombs() > 0.0);
104 assert!(m_in_kg.to_kg() > 0.0);
105 }
106
107 #[test]
109 fn test_mass_conversions() {
110 let kg = Mass::Kg;
111 assert!((kg.clone().convert_to(Mass::Pound).to_kg() - 1.0).abs() < 1e-10);
112 assert!((kg.convert_to(Mass::Gram).to_kg() - 1.0).abs() < 1e-10);
113
114 let ton_in_kg = Mass::Ton.to_kg();
115 assert!((ton_in_kg - 1000.0).abs() < 1e-10);
116
117 assert!((Mass::Pound.convert_to(Mass::Ounce).to_kg() - 0.45359237).abs() < 1e-8);
118 }
119
120 #[test]
121 fn test_length_conversions() {
122 let meter = Length::Meter;
123 assert!((meter.convert_to(Length::Foot).to_meters() - 1.0).abs() < 1e-10);
124 assert!((Length::Mile.convert_to(Length::Kilometer).to_meters() - 1609.344).abs() < 1e-10);
125 assert!((Length::Inch.convert_to(Length::Centimeter).to_meters() - 0.0254).abs() < 1e-10);
126
127 let nautical_mile = Length::NauticalMile;
128 let meters = nautical_mile.to_meters();
129 assert!((meters - 1852.0).abs() < 1e-10);
130 }
131
132 #[test]
133 fn test_temperature_conversions() {
134 let celsius = Temperature::Celsius;
135 assert!((celsius.to_kelvin(0.0) - 273.15).abs() < 1e-10);
136 assert!((celsius.to_fahrenheit(100.0) - 212.0).abs() < 1e-10);
137 assert!((Temperature::Fahrenheit.to_celsius(32.0) - 0.0).abs() < 1e-10);
138 assert!((Temperature::Kelvin.to_celsius(273.15) - 0.0).abs() < 1e-10);
139 }
140
141 #[test]
142 fn test_time_conversions() {
143 let second = Time::Second;
144 assert!((second.convert_to(Time::Millisecond).to_seconds() - 1.0).abs() < 1e-10);
145 assert!((Time::Hour.convert_to(Time::Minute).to_seconds() - 3600.0).abs() < 1e-10);
146 assert!((Time::Day.convert_to(Time::Hour).to_seconds() - 86400.0).abs() < 1e-10);
147
148 assert!((Time::JulianYear.convert_to(Time::Day).to_seconds() - 31557600.0).abs() < 1e-10);
149 assert!((Time::SiderealDay.convert_to(Time::Hour).to_seconds() - 86164.0905).abs() < 1e-6);
150 assert!(
151 (Time::SiderealYear.convert_to(Time::Day).to_seconds() - 31558149.504).abs() < 1e-6
152 );
153 }
154
155 #[test]
156 fn test_length_astronomical() {
157 let light_year = Length::LightYear;
158 assert!((light_year.convert_to(Length::Parsec).to_meters() - 9.461e15).abs() < 1e12);
159 assert!(
160 (Length::AstroUnit.convert_to(Length::Kilometer).to_meters() - 149597870700.0).abs()
161 < 1e5
162 );
163 assert!((Length::Parsec.convert_to(Length::LightYear).to_meters() - 3.086e16).abs() < 1e13);
164 }
165
166 #[test]
167 fn test_length_microscopic() {
168 assert!((Length::Angstrom.convert_to(Length::Nanometer).to_meters() - 1e-10).abs() < 1e-15);
169 assert!((Length::Fermi.convert_to(Length::Angstrom).to_meters() - 1e-15).abs() < 1e-20);
170 assert!((Length::Micron.convert_to(Length::Millimeter).to_meters() - 1e-6).abs() < 1e-10);
171 }
172
173 #[test]
174 fn test_area_conversions() {
175 let hectare = Area::Hectare;
176 assert!((hectare.to_square_meters() - 10000.0).abs() < 1e-10);
177 assert!((Area::Acre.to_square_meters() - 4046.8564224).abs() < 1e-6);
178 assert!((Area::SquareMile.to_hectares() - 258.9988110336).abs() < 1e-6);
179 }
180
181 #[test]
182 fn test_volume_conversions() {
183 assert!((Volume::Liter.to_cubic_meters() - 0.001).abs() < 1e-10);
184 assert!((Volume::Gallon.to_liters() - 3.785411784).abs() < 1e-6);
185 assert!((Volume::CubicFoot.to_cubic_meters() - 0.028316846592).abs() < 1e-10);
186
187 let custom_volume = Length::Meter.cubed();
188 assert!((custom_volume.to_liters() - 1000.0).abs() < 1e-6);
189 }
190
191 #[test]
192 fn test_speed_conversions() {
193 assert!((Speed::C.to_mps() - 299792458.0).abs() < 1e-6);
194 assert!((Speed::Mach.to_kmh() - 1234.8).abs() < 1e-1);
195 assert!((Speed::Knot.to_mps() - 0.514444).abs() < 1e-6);
196 }
197
198 #[test]
199 fn test_force_and_energy() {
200 let newton = Force::Newton;
201 assert!((newton.to_pounds() - 0.224809).abs() < 1e-6);
202 assert!((Force::Kg.to_newtons() - 9.80665).abs() < 1e-6);
203
204 let joule = Energy::Joule;
205 assert!((joule.to_calories() - 0.239006).abs() < 1e-6);
206 assert!((Energy::Ev.to_joules() - 1.602176634e-19).abs() < 1e-25);
207 }
208
209 #[test]
210 fn test_pressure_conversions() {
211 assert!((Pressure::Bar.to_pascal() - 100000.0).abs() < 1e-6);
212 assert!((Pressure::Atmospheric.to_pascal() - 101325.0).abs() < 1e-6);
213 assert!((Pressure::Psi.to_pascal() - 6894.757293168361).abs() < 1e-6);
214 assert!((Pressure::Torr.to_pascal() - 133.322).abs() < 1e-3);
215 }
216
217 #[test]
218 fn test_electrical_units() {
219 let coulomb = ElectricCharge::Coulomb;
220 assert!((coulomb.to_elementary_charges() - 6.241509074e18).abs() < 1e12);
221
222 let ampere = Current::Ampere;
223 assert!((ampere.to_milliamperes() - 1000.0).abs() < 1e-10);
224 }
225
226 #[test]
227 fn test_frequency_and_acceleration() {
228 let hz = Frequency::Hertz;
229 assert!((hz.to_kilohertz() - 0.001).abs() < 1e-10);
230 assert!((Frequency::Gigahertz.to_hertz() - 1e9).abs() < 1e-6);
231
232 let g = Acceleration::G;
233 assert!((g.to_mps2() - 9.80665).abs() < 1e-6);
234 assert!((Acceleration::MetersPerSecondSquared.to_g() - 0.101972).abs() < 1e-6);
235 }
236
237 #[test]
238 fn test_compound_unit_conversions() {
239 let work = Energy::Custom(Force::Newton, Length::Meter);
240 assert!((work.to_joules() - 1.0).abs() < 1e-10);
241
242 let power = Energy::Joule.per_time(Time::Second);
243 assert!((power.to_watts() - 1.0).abs() < 1e-10);
244
245 let accel = Length::Meter.per_time_squared(Time::Second, Time::Second);
246 assert!((accel.to_mps2() - 1.0).abs() < 1e-10);
247
248 let freq = Time::Second.frequency();
249 assert!((freq.to_hertz() - 1.0).abs() < 1e-10);
250 }
251
252 #[test]
254 fn test_vector_operations() {
255 let v1 = Vector::new(vec![1.0, 2.0, 3.0]);
256 let v2 = Vector::new(vec![4.0, 5.0, 6.0]);
257 let v3 = Vector::new(vec![2.0, 1.0, -1.0]);
258
259 let cross = v1.cross(&v2).unwrap();
260 assert!((cross[0] + 3.0).abs() < 1e-10);
261 assert!((cross[1] - 6.0).abs() < 1e-10);
262 assert!((cross[2] - (-3.0)).abs() < 1e-10);
263
264 let v4 = Vector::new(vec![1.0, 2.0]);
265 assert!(v1.dot(&v4).is_err());
266 assert!(v1.cross(&v4).is_err());
267
268 let normalized = v3.normalize();
269 assert!((normalized.magnitude() - 1.0).abs() < 1e-10);
270
271 let sum = (&v1 + &v2).unwrap();
272 assert!((sum[0] - 5.0).abs() < 1e-10);
273 assert!((sum[1] - 7.0).abs() < 1e-10);
274 assert!((sum[2] - 9.0).abs() < 1e-10);
275 }
276
277 #[test]
278 fn test_matrix_operations() {
279 let m = Matrix::new(vec![
280 vec![4.0, -2.0, 1.0],
281 vec![-2.0, 4.0, -2.0],
282 vec![1.0, -2.0, 4.0],
283 ])
284 .unwrap();
285
286 let (l, u) = m.lu_decomposition().unwrap();
287 let lu_product = (l * u).unwrap();
288 for i in 0..3 {
289 for j in 0..3 {
290 assert!((m[(i, j)] - lu_product[(i, j)]).abs() < 1e-10);
291 }
292 }
293
294 let (q, r) = m.qr_decomposition().unwrap();
295 let qr_product = (q * r).unwrap();
296 for i in 0..3 {
297 for j in 0..3 {
298 assert!((m[(i, j)] - qr_product[(i, j)]).abs() < 1e-10);
299 }
300 }
301
302 assert!(m.is_symmetric());
303 assert!(m.is_positive_definite());
304 assert!((m.trace().unwrap() - 12.0).abs() < 1e-10);
305
306 let l = m.cholesky().unwrap();
307 let l_transpose = l.transpose();
308 let ll_product = (l * l_transpose).unwrap();
309 for i in 0..3 {
310 for j in 0..3 {
311 assert!((m[(i, j)] - ll_product[(i, j)]).abs() < 1e-10);
312 }
313 }
314 }
315
316 #[test]
317 fn test_matrix_transformations() {
318 let m = Matrix::new(vec![vec![1.0, 2.0], vec![3.0, 4.0]]).unwrap();
319
320 let v = Vector::new(vec![1.0, 2.0]);
322 let mv = (&m * &v).unwrap();
323 assert!((mv[0] - 5.0).abs() < 1e-10);
324 assert!((mv[1] - 11.0).abs() < 1e-10);
325
326 let inv = m.inverse().unwrap();
328 let identity = (m.clone() * inv.clone()).unwrap();
329 assert!((identity[(0, 0)] - 1.0).abs() < 1e-10);
330 assert!((identity[(1, 1)] - 1.0).abs() < 1e-10);
331 assert!(identity[(0, 1)].abs() < 1e-10);
332 assert!(identity[(1, 0)].abs() < 1e-10);
333
334 assert_eq!(m.rank().unwrap(), 2);
336
337 let singular_matrix = Matrix::new(vec![vec![1.0, 2.0], vec![2.0, 4.0]]).unwrap();
338 assert_eq!(singular_matrix.rank().unwrap(), 1);
339 }
340
341 #[test]
342 fn test_matrix_special_cases() {
343 assert!(Matrix::new(vec![]).is_err());
344
345 let rect_matrix = Matrix::new(vec![vec![1.0, 2.0, 3.0], vec![4.0, 5.0, 6.0]]).unwrap();
346 assert!(rect_matrix.determinant().is_err());
347 assert!(rect_matrix.inverse().is_err());
348 assert!(rect_matrix.lu_decomposition().is_err());
349
350 let singular = Matrix::new(vec![vec![1.0, 1.0], vec![1.0, 1.0]]).unwrap();
351 assert!(singular.inverse().is_err());
352
353 let non_pd = Matrix::new(vec![vec![1.0, 2.0], vec![2.0, 1.0]]).unwrap();
354 assert!(!non_pd.is_positive_definite());
355 }
356
357 #[test]
358 fn test_matrix_decompositions() {
359 let m = Matrix::new(vec![vec![4.0, 2.0], vec![2.0, 4.0]]).unwrap();
360
361 let (l, u) = m.lu_decomposition().unwrap();
362 assert!((l[(1, 0)] * u[(0, 1)] + l[(1, 1)] * u[(1, 1)] - m[(1, 1)]).abs() < 1e-10);
363
364 let inverse = m.inverse().unwrap();
365 assert!((inverse[(0, 0)] * m[(0, 0)] + inverse[(0, 1)] * m[(1, 0)] - 1.0).abs() < 1e-10);
366 }
367
368 #[test]
370 fn test_central_tendency() {
371 let data = vec![1.0, 2.0, 3.0, 4.0, 5.0];
372
373 assert!((Stats::mean(&data).unwrap() - 3.0).abs() < 1e-10);
374 assert!((Stats::median(&data).unwrap() - 3.0).abs() < 1e-10);
375
376 let data_with_mode = vec![1.0, 2.0, 2.0, 3.0, 4.0];
377 let mode = Stats::mode(&data_with_mode).unwrap();
378 assert_eq!(mode, vec![2.0]);
379 }
380
381 #[test]
382 fn test_dispersion() {
383 let data = vec![2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0];
384
385 assert!((Stats::variance(&data).unwrap() - 4.571428571428571).abs() < 1e-10);
386 assert!((Stats::std_dev(&data).unwrap() - 2.138089935299395).abs() < 1e-10);
387 assert!((Stats::range(&data).unwrap() - 7.0).abs() < 1e-10);
388 }
389
390 #[test]
391 fn test_distribution_characteristics() {
392 let data = vec![1.0, 2.0, 2.0, 3.0, 3.0, 3.0, 4.0, 4.0, 5.0];
393
394 let quartiles = Stats::quartiles(&data).unwrap();
395 assert!((quartiles.0 - 2.0).abs() < 1e-10); assert!((quartiles.1 - 3.0).abs() < 1e-10); assert!((quartiles.2 - 4.0).abs() < 1e-10); }
399
400 #[test]
401 fn test_effect_size() {
402 let data1 = vec![1.0, 2.0, 3.0, 4.0, 5.0];
403 let data2 = vec![2.0, 3.0, 4.0, 5.0, 6.0];
404
405 let d = Stats::cohens_d(&data1, &data2).unwrap();
406 assert!(d < 0.0); }
408
409 #[test]
410 fn test_regression() {
411 let x = vec![1.0, 2.0, 3.0, 4.0, 5.0];
412 let y = vec![2.0, 4.0, 6.0, 8.0, 10.0];
413
414 let (slope, intercept) = Stats::linear_regression(&x, &y).unwrap();
415 assert!((slope - 2.0).abs() < 1e-10);
416 assert!(intercept.abs() < 1e-10);
417 }
418
419 #[test]
420 fn test_time_series() {
421 let data = vec![1.0, 2.0, 1.0, 2.0, 1.0];
422 let ac1 = Stats::autocorrelation(&data, 1).unwrap();
423 assert!(ac1 < 0.0);
424
425 let ac2 = Stats::autocorrelation(&data, 2).unwrap();
426 assert!(ac2 > 0.0);
427 }
428
429 #[test]
431 fn test_complex_arithmetic() {
432 let z1 = Complex::new(1.0, 2.0);
433 let z2 = Complex::new(3.0, 4.0);
434
435 let sum = z1 + z2;
436 assert!((sum.re() as f32 - 4.0).abs() < 1e-10);
437 assert!((sum.im() as f32 - 6.0).abs() < 1e-10);
438
439 let product = z1 * z2;
440 assert!((product.re() as f32 - (-5.0)).abs() < 1e-10);
441 assert!((product.im() as f32 - 10.0).abs() < 1e-10);
442 }
443
444 #[test]
445 fn test_complex_properties() {
446 let z = Complex::new(3.0, 4.0);
447
448 assert!((z.modulus() - 5.0).abs() < 1e-10);
449 assert!((z.argument() - (4.0_f64).atan2(3.0)).abs() < 1e-10);
450
451 let conjugate = z.conjugate();
452 assert!((conjugate.re() - 3.0).abs() < 1e-10);
453 assert!((conjugate.im() + 4.0).abs() < 1e-10);
454 }
455
456 #[test]
457 fn test_complex_functions() {
458 let z = Complex::new(0.0, PI);
459
460 let exp_z = z.exp();
461 assert!((exp_z.re() + 1.0).abs() < 1e-10);
462 assert!(exp_z.im().abs() < 1e-10);
463
464 let z1 = Complex::new(1.0, 1.0);
465 let ln_z = z1.ln();
466
467 let expected_re = (2.0_f64).sqrt().ln();
468 let expected_im = PI / 4.0;
469
470 assert!((ln_z.re() - expected_re).abs() < 1e-10);
471 assert!((ln_z.im() - expected_im).abs() < 1e-10);
472
473 let z2 = Complex::new(1.0, 0.0);
474 let ln_z2 = z2.ln();
475 assert!(ln_z2.re().abs() < 1e-10);
476 assert!(ln_z2.im().abs() < 1e-10);
477 }
478
479 #[test]
481 fn test_derivatives() {
482 let f = |x: f64| x * x;
483 assert!((calculus::Calculus::derivative(&f, 2.0, 1e-6) - 4.0).abs() < 1e-4);
484 assert!((calculus::Calculus::derivative(&f, -2.0, 1e-6) + 4.0).abs() < 1e-4);
485 assert!((calculus::Calculus::second_derivative(&f, 0.0, 1e-6) - 2.0).abs() < 1e-4);
486 }
487
488 #[test]
489 fn test_integrals() {
490 let f = |x: f64| x * x;
491
492 let simpson = calculus::Calculus::integrate_simpson(&f, 0.0, 1.0, 1000);
493 assert!((simpson - 1.0 / 3.0).abs() < 1e-4);
494
495 let trapezoid = calculus::Calculus::integrate_trapezoid(&f, 0.0, 1.0, 1000);
496 assert!((trapezoid - 1.0 / 3.0).abs() < 1e-3);
497
498 let rectangle = calculus::Calculus::integrate_rectangle(&f, 0.0, 1.0, 1000);
499 assert!((rectangle - 1.0 / 3.0).abs() < 1e-3);
500 }
501
502 #[test]
503 fn test_differential_equations() {
504 let f = |_x: f64, y: f64| y;
505
506 let euler = calculus::Calculus::euler(&f, 0.0, 1.0, 0.01, 100);
507 assert!((euler.last().unwrap().1 - f64::exp(1.0)).abs() < 0.1);
508
509 let rk4 = calculus::Calculus::runge_kutta4(&f, 0.0, 1.0, 0.01, 100);
510 assert!((rk4.last().unwrap().1 - f64::exp(1.0)).abs() < 0.01);
511 }
512}