Skip to main content

unitforge/
impl_macros.rs

1#[macro_export]
2macro_rules! impl_quantity {
3    ($type:ident, $unit:ident, $display_units:expr) => {
4        #[cfg(feature = "pyo3")]
5        use pyo3::{
6            basic::CompareOp, exceptions::PyValueError, pymethods, types::PyType, Bound,
7            IntoPyObject, Py, PyAny, PyRef, PyResult,
8        };
9
10        #[cfg(feature = "strum")]
11        use strum::IntoEnumIterator;
12        use $crate::small_linalg::{Matrix3, Vector3};
13        #[cfg(feature = "pyo3")]
14        use $crate::Quantity;
15
16        #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
17        #[cfg(feature = "pyo3")]
18        #[pyclass(module = "unitforge")]
19        #[derive(Copy, Clone)]
20        pub struct $type {
21            pub(crate) multiplier: f64,
22            pub(crate) power: i32,
23        }
24        #[cfg(not(feature = "pyo3"))]
25        #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
26        #[derive(Copy, Clone)]
27        pub struct $type {
28            pub(crate) multiplier: f64,
29            pub(crate) power: i32,
30        }
31
32        impl PhysicsQuantity for $type {
33            fn as_f64(&self) -> f64 {
34                self.multiplier * 10_f64.powi(self.power)
35            }
36
37            type Unit = $unit;
38
39            fn new(value: f64, unit: Self::Unit) -> $type {
40                if value.is_infinite() {
41                    if value.is_sign_negative() {
42                        return Self::NEG_INFINITY;
43                    } else {
44                        return Self::INFINITY;
45                    }
46                }
47                if value.is_zero() {
48                    return $type {
49                        multiplier: 0.0,
50                        power: 0,
51                    };
52                }
53                let (unit_multiplier, unit_power) = unit.base_per_x();
54                let (multiplier, power) = Self::split_value(value);
55                let r = $type {
56                    multiplier: multiplier * unit_multiplier,
57                    power: power + unit_power,
58                };
59                r
60            }
61
62            fn split_value(v: f64) -> (f64, i32) {
63                if v.is_zero() {
64                    (0.0, 0)
65                } else if v.is_infinite() {
66                    if v > 0.0 {
67                        (f64::INFINITY, 0)
68                    } else {
69                        (f64::NEG_INFINITY, 0)
70                    }
71                } else {
72                    let power = v.abs().log10().floor() as i32;
73                    let multiplier = v / 10f64.powi(power);
74                    (multiplier, power)
75                }
76            }
77
78            fn get_value(&self) -> f64 {
79                self.multiplier * 10_f64.powi(self.power)
80            }
81
82            fn get_power(&self) -> i32 {
83                self.power
84            }
85
86            fn get_multiplier(&self) -> f64 {
87                self.multiplier
88            }
89
90            fn get_tuple(&self) -> (f64, i32) {
91                (self.multiplier, self.power)
92            }
93
94            fn to(&self, unit: Self::Unit) -> f64 {
95                let (unit_multiplier, unit_power) = unit.base_per_x();
96                self.multiplier / unit_multiplier * 10_f64.powi(self.power - unit_power)
97            }
98
99            fn abs(self) -> Self {
100                Self {
101                    multiplier: self.multiplier.abs(),
102                    power: self.power,
103                }
104            }
105
106            fn is_nan(&self) -> bool {
107                self.multiplier.is_nan()
108            }
109
110            fn from_raw(value: f64) -> Self {
111                if value.is_infinite() {
112                    if value.is_sign_negative() {
113                        return Self::NEG_INFINITY;
114                    } else {
115                        return Self::INFINITY;
116                    }
117                }
118                let (multiplier, power) = Self::split_value(value);
119                Self { multiplier, power }
120            }
121
122            fn nan() -> Self {
123                Self {
124                    multiplier: <f64 as Float>::nan(),
125                    power: 0,
126                }
127            }
128
129            fn from_exponential(multiplier: f64, power: i32) -> Self {
130                Self { multiplier, power }
131            }
132
133            fn min(self, other: Self) -> Self {
134                if self < other {
135                    self
136                } else {
137                    other
138                }
139            }
140
141            fn max(self, other: Self) -> Self {
142                if self > other {
143                    self
144                } else {
145                    other
146                }
147            }
148
149            fn is_close(&self, other: &Self, tolerance: &Self) -> bool {
150                (self.as_f64() - other.as_f64()).abs() <= tolerance.as_f64().abs()
151            }
152
153            fn optimize(&mut self) {
154                if self.multiplier.abs() < f64::EPSILON {
155                    return;
156                }
157                let power_on_multiplier = self.multiplier.abs().log10().round() as i32;
158                self.multiplier /= 10_f64.powi(power_on_multiplier);
159                self.power += power_on_multiplier;
160            }
161
162            const INFINITY: Self = Self {
163                multiplier: f64::INFINITY,
164                power: 0,
165            };
166
167            const NEG_INFINITY: Self = Self {
168                multiplier: f64::NEG_INFINITY,
169                power: 0,
170            };
171        }
172
173        impl $crate::UnitforgeQuantity for $type {}
174
175        impl From<f64> for $type {
176            fn from(value: f64) -> Self {
177                if value.is_infinite() {
178                    if value.is_sign_negative() {
179                        return Self::NEG_INFINITY;
180                    } else {
181                        return Self::INFINITY;
182                    }
183                }
184                let (multiplier, power) = Self::split_value(value);
185                Self { multiplier, power }
186            }
187        }
188
189        #[cfg(feature = "pyo3")]
190        #[pymethods]
191        impl $type {
192            fn __mul__(lhs: PyRef<Self>, rhs: Py<PyAny>) -> PyResult<Py<PyAny>> {
193                let py = lhs.py();
194                let rhs_ref = rhs.bind(py);
195                let lhs_ref = lhs.into_pyobject(py)?;
196                let rhs_quantity = Quantity::from_py_any(rhs_ref)
197                    .map_err(|e| PyValueError::new_err(e.to_string()))?;
198                let lhs_quantity = Quantity::from_py_any(&lhs_ref)
199                    .map_err(|e| PyValueError::new_err(e.to_string()))?;
200                match lhs_quantity * rhs_quantity {
201                    Ok(value) => Ok(value.to_pyobject(py)?),
202                    Err(_) => Err(PyValueError::new_err(
203                        "Multiplication of given objects is not possible.",
204                    )),
205                }
206            }
207
208            fn __truediv__(lhs: PyRef<Self>, rhs: Py<PyAny>) -> PyResult<Py<PyAny>> {
209                let py = lhs.py();
210                let rhs_ref = rhs.bind(py);
211                let lhs_ref = lhs.into_pyobject(py)?;
212                let rhs_quantity = Quantity::from_py_any(rhs_ref)
213                    .map_err(|e| PyValueError::new_err(e.to_string()))?;
214                let lhs_quantity = Quantity::from_py_any(&lhs_ref)
215                    .map_err(|e| PyValueError::new_err(e.to_string()))?;
216                match lhs_quantity / rhs_quantity {
217                    Ok(value) => Ok(value.to_pyobject(py)?),
218                    Err(_) => Err(PyValueError::new_err(
219                        "Division of given objects is not possible.",
220                    )),
221                }
222            }
223
224            fn __rmul__(&self, rhs: f64) -> PyResult<Self> {
225                Ok(*self * rhs)
226            }
227        }
228
229        impl fmt::Display for $type {
230            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
231                use std::collections::HashMap;
232                let mut groups: HashMap<String, Vec<String>> = HashMap::new();
233
234                for base_unit in $display_units {
235                    let value = self.to(base_unit);
236                    let rounded = if value.is_zero() {
237                        value
238                    } else {
239                        let digits = value.abs().log10().ceil() as i32;
240                        let rounding_multiplier = 10_f64.powi(3 - digits);
241                        (value * rounding_multiplier).round() / rounding_multiplier
242                    };
243
244                    let value = format!("{}", rounded);
245                    groups
246                        .entry(value)
247                        .or_default()
248                        .push(base_unit.name().to_string());
249                }
250
251                let mut parts = Vec::new();
252                for (value, units) in groups {
253                    let joined_units = units.join(", ");
254                    parts.push(format!(
255                        "{}{}{}",
256                        value,
257                        if joined_units.starts_with('°') {
258                            ""
259                        } else {
260                            " "
261                        },
262                        joined_units
263                    ));
264                }
265
266                write!(f, "{}", parts.join(", "))
267            }
268        }
269
270        impl Neg for $type {
271            type Output = Self;
272
273            fn neg(self) -> Self::Output {
274                Self {
275                    multiplier: -self.multiplier,
276                    power: self.power,
277                }
278            }
279        }
280
281        impl PartialEq<Self> for $type
282        where
283            $type: PhysicsQuantity,
284        {
285            fn eq(&self, other: &Self) -> bool {
286                self.is_close(
287                    other,
288                    &Self {
289                        multiplier: self.multiplier,
290                        power: self.power.clone() - 9,
291                    },
292                )
293            }
294        }
295
296        impl PartialOrd for $type
297        where
298            $type: PhysicsQuantity,
299        {
300            fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
301                self.as_f64().partial_cmp(&other.as_f64())
302            }
303        }
304
305        impl FromPrimitive for $type {
306            fn from_i64(n: i64) -> Option<Self> {
307                Some(Self::from_raw(n as f64))
308            }
309
310            fn from_u64(n: u64) -> Option<Self> {
311                Some(Self::from_raw(n as f64))
312            }
313
314            fn from_f64(n: f64) -> Option<Self> {
315                Some(Self::from_raw(n))
316            }
317        }
318
319        impl Add for $type {
320            type Output = Self;
321
322            fn add(self, other: Self) -> Self {
323                let common_power = self.power.max(other.power);
324                let multiplier = self.multiplier * 10_f64.powi(self.power - common_power)
325                    + other.multiplier * 10_f64.powi(other.power - common_power);
326                let mut res = Self {
327                    multiplier,
328                    power: common_power,
329                };
330                res.optimize();
331                res
332            }
333        }
334
335        impl Sub for $type {
336            type Output = Self;
337
338            fn sub(self, other: Self) -> Self {
339                let common_power = (self.power + other.power) / 2;
340                let multiplier = self.multiplier * 10_f64.powi(self.power - common_power)
341                    - other.multiplier * 10_f64.powi(other.power - common_power);
342
343                let mut res = Self {
344                    multiplier,
345                    power: common_power,
346                };
347                res.optimize();
348                res
349            }
350        }
351
352        impl Div<f64> for $type {
353            type Output = Self;
354
355            fn div(self, rhs: f64) -> Self::Output {
356                let (rhs_multiplier, rhs_power) = Self::split_value(rhs);
357                Self {
358                    multiplier: self.multiplier / rhs_multiplier,
359                    power: self.power - rhs_power,
360                }
361            }
362        }
363
364        impl Mul<f64> for $type {
365            type Output = Self;
366
367            fn mul(self, rhs: f64) -> Self::Output {
368                let (rhs_multiplier, rhs_power) = Self::split_value(rhs);
369                Self {
370                    multiplier: self.multiplier * rhs_multiplier,
371                    power: self.power + rhs_power,
372                }
373            }
374        }
375
376        impl Mul<$type> for f64 {
377            type Output = $type;
378
379            fn mul(self, rhs: $type) -> Self::Output {
380                rhs * self
381            }
382        }
383
384        impl AddAssign for $type {
385            fn add_assign(&mut self, other: Self) {
386                let common_power = (self.power + other.power) / 2;
387                self.multiplier = self.multiplier * 10_f64.powi(self.power - common_power)
388                    + other.multiplier * 10_f64.powi(other.power - common_power);
389                self.power = common_power;
390                self.optimize();
391            }
392        }
393
394        impl SubAssign for $type {
395            fn sub_assign(&mut self, other: Self) {
396                let common_power = (self.power + other.power) / 2;
397                self.multiplier = self.multiplier * 10_f64.powi(self.power - common_power)
398                    - other.multiplier * 10_f64.powi(other.power - common_power);
399                self.power = common_power;
400                self.optimize();
401            }
402        }
403
404        impl MulAssign<f64> for $type {
405            fn mul_assign(&mut self, rhs: f64) {
406                let (rhs_multiplier, rhs_power) = Self::split_value(rhs);
407                self.multiplier *= rhs_multiplier;
408                self.power += rhs_power;
409            }
410        }
411
412        impl DivAssign<f64> for $type {
413            fn div_assign(&mut self, rhs: f64) {
414                let (rhs_multiplier, rhs_power) = Self::split_value(rhs);
415                self.multiplier /= rhs_multiplier;
416                self.power -= rhs_power;
417            }
418        }
419
420        impl Mul<Vector3<f64>> for $type {
421            type Output = Vector3<$type>;
422
423            fn mul(self, rhs: Vector3<f64>) -> Self::Output {
424                Vector3::new([self * rhs[0], self * rhs[1], self * rhs[2]])
425            }
426        }
427
428        impl Mul<Matrix3<f64>> for $type {
429            type Output = Matrix3<$type>;
430
431            fn mul(self, rhs: Matrix3<f64>) -> Self::Output {
432                Matrix3::new([
433                    [self * rhs[(0, 0)], self * rhs[(0, 1)], self * rhs[(0, 2)]],
434                    [self * rhs[(1, 0)], self * rhs[(1, 1)], self * rhs[(1, 2)]],
435                    [self * rhs[(2, 0)], self * rhs[(2, 1)], self * rhs[(2, 2)]],
436                ])
437            }
438        }
439
440        impl Zero for $type {
441            fn zero() -> Self {
442                Self {
443                    multiplier: 0.0,
444                    power: 0,
445                }
446            }
447
448            fn is_zero(&self) -> bool {
449                self.multiplier == 0.0
450            }
451        }
452
453        impl fmt::Debug for $type {
454            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
455                fmt::Display::fmt(self, f)
456            }
457        }
458
459        impl QuantityArray2<$unit> for Array2<$type> {
460            fn from_raw(raw: ArrayView2<f64>, unit: $unit) -> Self {
461                let mut res = Array2::zeros(raw.dim());
462                for i in 0..raw.dim().0 {
463                    for j in 0..raw.dim().1 {
464                        res[[i, j]] = <$type>::new(raw[[i, j]], unit);
465                    }
466                }
467                res
468            }
469
470            fn to_raw(&self) -> Array2<f64> {
471                let mut res = Array2::zeros(self.dim());
472                for i in 0..self.dim().0 {
473                    for j in 0..self.dim().1 {
474                        res[[i, j]] = self[[i, j]].as_f64();
475                    }
476                }
477                res
478            }
479
480            fn to(&self, unit: $unit) -> Array2<f64> {
481                let mut res = Array2::zeros(self.dim());
482                for i in 0..self.dim().0 {
483                    for j in 0..self.dim().1 {
484                        res[[i, j]] = self[[i, j]].to(unit);
485                    }
486                }
487                res
488            }
489        }
490
491        impl QuantityArray1<$unit> for Array1<$type> {
492            fn from_raw(raw: ArrayView1<f64>, unit: $unit) -> Self {
493                let mut res = Array1::zeros(raw.dim());
494                for i in 0..raw.dim() {
495                    res[i] = <$type>::new(raw[i], unit);
496                }
497                res
498            }
499
500            fn to_raw(&self) -> Array1<f64> {
501                let mut res = Array1::zeros(self.dim());
502                for i in 0..self.dim() {
503                    res[i] = self[i].as_f64();
504                }
505                res
506            }
507
508            fn to(&self, unit: $unit) -> Array1<f64> {
509                let mut res = Array1::zeros(self.dim());
510                for i in 0..self.dim() {
511                    res[i] = self[i].to(unit);
512                }
513                res
514            }
515        }
516
517        #[cfg(feature = "pyo3")]
518        #[pymethods]
519        impl $type {
520            #[classmethod]
521            #[pyo3(name = "zero")]
522            fn zero_py(_cls: &Bound<'_, PyType>) -> Self {
523                Self::zero()
524            }
525
526            #[new]
527            fn new_py(value: f64, unit: $unit) -> PyResult<Self> {
528                Ok(Self::new(value, unit))
529            }
530
531            fn close_abs(&self, other: PyRef<Self>, threshold: Self) -> bool {
532                (self.clone() - other.clone()).abs() <= threshold
533            }
534
535            fn close_rel(&self, other: PyRef<Self>, threshold: f64) -> bool {
536                let mean = (self.clone() + other.clone()) / 2.;
537                (self.clone() - other.clone()).abs() <= mean * threshold
538            }
539
540            fn __richcmp__(&self, other: PyRef<Self>, op: CompareOp) -> bool {
541                match op {
542                    CompareOp::Lt => self.clone() < other.clone(),
543                    CompareOp::Le => self.clone() <= other.clone(),
544                    CompareOp::Eq => self.clone() == other.clone(),
545                    CompareOp::Ne => self.clone() != other.clone(),
546                    CompareOp::Gt => self.clone() > other.clone(),
547                    CompareOp::Ge => self.clone() >= other.clone(),
548                }
549            }
550
551            fn __repr__(&self) -> PyResult<String> {
552                Ok(format!("{:?}", self))
553            }
554
555            fn __str__(&self) -> PyResult<String> {
556                Ok(format!("{:?}", self))
557            }
558
559            fn __add__(lhs: PyRef<Self>, rhs: PyRef<Self>) -> PyResult<Self> {
560                Ok(lhs.clone() + rhs.clone())
561            }
562
563            fn __neg__(lhs: PyRef<Self>) -> PyResult<Self> {
564                Ok(-lhs.clone())
565            }
566
567            fn __sub__(lhs: PyRef<Self>, rhs: PyRef<Self>) -> PyResult<Self> {
568                Ok(lhs.clone() - rhs.clone())
569            }
570
571            fn __abs__(&self) -> Self {
572                self.abs()
573            }
574
575            #[allow(clippy::wrong_self_convention)]
576            #[pyo3(name = "to")]
577            fn to_py(&self, unit: $unit) -> f64 {
578                self.to(unit)
579            }
580        }
581
582        #[cfg(feature = "strum")]
583        impl $type {
584            pub fn optimal_unit(&self) -> Option<$unit> {
585                let mut min_value = f64::INFINITY;
586                let mut best_unit = None;
587                for unit in $unit::iter() {
588                    let deviation = (self.to(unit).abs() - 1.).abs();
589                    if deviation < min_value {
590                        min_value = deviation;
591                        best_unit = Some(unit);
592                    }
593                }
594                best_unit
595            }
596        }
597    };
598}
599
600#[macro_export]
601macro_rules! make_alias {
602    ($base_quantity:ty, $base_unit:ty, $alias_quantity:ident, $alias_unit:ident) => {
603        pub type $alias_unit = $base_unit;
604        pub type $alias_quantity = $base_quantity;
605    };
606}
607
608#[macro_export]
609macro_rules! impl_const {
610    ($type:ident, $name:ident, $multiplier:expr, $power:expr) => {
611        #[cfg(feature = "pyo3")]
612        #[pymethods]
613        impl $type {
614            #[staticmethod]
615            pub fn $name() -> Self {
616                Self {
617                    multiplier: $multiplier,
618                    power: $power,
619                }
620            }
621        }
622        #[cfg(not(feature = "pyo3"))]
623        impl $type {
624            pub fn $name() -> Self {
625                Self {
626                    multiplier: $multiplier,
627                    power: $power,
628                }
629            }
630        }
631    };
632}
633
634#[macro_export]
635macro_rules! impl_div_with_self_to_f64 {
636    ($lhs:ty) => {
637        impl Div<$lhs> for $lhs {
638            type Output = f64;
639
640            fn div(self, rhs: Self) -> Self::Output {
641                (self.multiplier / rhs.multiplier) * 10_f64.powi(self.power - rhs.power)
642            }
643        }
644    };
645}
646
647#[macro_export]
648macro_rules! impl_mul {
649    ($lhs:ty, $rhs:ty, $result:ty) => {
650        impl std::ops::Mul<$rhs> for $lhs {
651            type Output = $result;
652
653            fn mul(self, rhs: $rhs) -> Self::Output {
654                <$result>::from_exponential(
655                    self.multiplier * rhs.multiplier,
656                    self.power + rhs.power,
657                )
658            }
659        }
660
661        impl std::ops::Mul<$lhs> for $rhs {
662            type Output = $result;
663
664            fn mul(self, rhs: $lhs) -> Self::Output {
665                <$result>::from_exponential(
666                    self.multiplier * rhs.multiplier,
667                    self.power + rhs.power,
668                )
669            }
670        }
671
672        impl MulArray1<$rhs> for Array1<$lhs> {
673            type Output = Array1<$result>;
674
675            fn mul_array1(self, rhs: Array1<$rhs>) -> Array1<$result> {
676                self.into_iter()
677                    .zip(rhs.into_iter())
678                    .map(|(force, distance)| force * distance)
679                    .collect()
680            }
681        }
682
683        impl MulArray2<$rhs> for Array2<$lhs> {
684            type Output = Array2<$result>;
685
686            fn mul_array2(self, rhs: Array2<$rhs>) -> Result<Array2<$result>, String> {
687                let mut results = Vec::new();
688
689                for (lhs_row, rhs_row) in self.outer_iter().zip(rhs.outer_iter()) {
690                    let result_row: Array1<$result> = lhs_row
691                        .iter()
692                        .zip(rhs_row.iter())
693                        .map(|(&lhs, &rhs)| lhs * rhs)
694                        .collect();
695                    results.push(result_row);
696                }
697
698                let nrows = results.len();
699                let ncols = if nrows > 0 { results[0].len() } else { 0 };
700                let data: Vec<$result> = results
701                    .into_iter()
702                    .flat_map(|r| {
703                        let (raw_vec, _) = r.into_raw_vec_and_offset();
704                        raw_vec
705                    })
706                    .collect();
707
708                Array2::from_shape_vec((nrows, ncols), data)
709                    .map_err(|_| "Shape mismatch".to_string())
710            }
711        }
712
713        impl MulArray1<$lhs> for Array1<$rhs> {
714            type Output = Array1<$result>;
715
716            fn mul_array1(self, rhs: Array1<$lhs>) -> Array1<$result> {
717                self.into_iter()
718                    .zip(rhs.into_iter())
719                    .map(|(force, distance)| force * distance)
720                    .collect()
721            }
722        }
723
724        impl MulArray2<$lhs> for Array2<$rhs> {
725            type Output = Array2<$result>;
726
727            fn mul_array2(self, rhs: Array2<$lhs>) -> Result<Array2<$result>, String> {
728                let mut results = Vec::new();
729
730                for (force_row, distance_row) in self.outer_iter().zip(rhs.outer_iter()) {
731                    let result_row: Array1<$result> = force_row
732                        .iter()
733                        .zip(distance_row.iter())
734                        .map(|(&force, &distance)| force * distance)
735                        .collect();
736                    results.push(result_row);
737                }
738
739                let nrows = results.len();
740                let ncols = if nrows > 0 { results[0].len() } else { 0 };
741                let data: Vec<$result> = results
742                    .into_iter()
743                    .flat_map(|r| {
744                        let (raw_vec, _) = r.into_raw_vec_and_offset();
745                        raw_vec
746                    })
747                    .collect();
748
749                Array2::from_shape_vec((nrows, ncols), data)
750                    .map_err(|_| "Shape mismatch".to_string())
751            }
752        }
753    };
754}
755
756#[macro_export]
757macro_rules! impl_mul_with_self {
758    ($lhs:ty,$result:ty) => {
759        impl std::ops::Mul<$lhs> for $lhs {
760            type Output = $result;
761
762            fn mul(self, rhs: $lhs) -> Self::Output {
763                <$result>::from_exponential(
764                    self.multiplier * rhs.multiplier,
765                    self.power + rhs.power,
766                )
767            }
768        }
769
770        impl MulArray1<$lhs> for Array1<$lhs> {
771            type Output = Array1<$result>;
772
773            fn mul_array1(self, rhs: Array1<$lhs>) -> Array1<$result> {
774                self.into_iter()
775                    .zip(rhs.into_iter())
776                    .map(|(force, distance)| force * distance)
777                    .collect()
778            }
779        }
780
781        impl MulArray2<$lhs> for Array2<$lhs> {
782            type Output = Array2<$result>;
783
784            fn mul_array2(self, rhs: Array2<$lhs>) -> Result<Array2<$result>, String> {
785                let mut results = Vec::new();
786
787                for (force_row, distance_row) in self.outer_iter().zip(rhs.outer_iter()) {
788                    let result_row: Array1<$result> = force_row
789                        .iter()
790                        .zip(distance_row.iter())
791                        .map(|(&force, &distance)| force * distance)
792                        .collect();
793                    results.push(result_row);
794                }
795
796                let nrows = results.len();
797                let ncols = if nrows > 0 { results[0].len() } else { 0 };
798                let data: Vec<$result> = results
799                    .into_iter()
800                    .flat_map(|r| {
801                        let (raw_vec, _) = r.into_raw_vec_and_offset();
802                        raw_vec
803                    })
804                    .collect();
805
806                Array2::from_shape_vec((nrows, ncols), data)
807                    .map_err(|_| "Shape mismatch".to_string())
808            }
809        }
810    };
811}
812
813#[macro_export]
814macro_rules! impl_div {
815    ($lhs:ty, $rhs:ty, $result:ty) => {
816        impl std::ops::Div<$rhs> for $lhs {
817            type Output = $result;
818
819            fn div(self, rhs: $rhs) -> Self::Output {
820                <$result>::from_exponential(
821                    self.multiplier / rhs.multiplier,
822                    self.power - rhs.power,
823                )
824            }
825        }
826
827        impl DivArray1<$rhs> for Array1<$lhs> {
828            type Output = Array1<$result>;
829
830            fn div_array1(self, rhs: Array1<$rhs>) -> Array1<$result> {
831                self.into_iter()
832                    .zip(rhs.into_iter())
833                    .map(|(force, distance)| force / distance)
834                    .collect()
835            }
836        }
837
838        impl DivArray2<$rhs> for Array2<$lhs> {
839            type Output = Array2<$result>;
840
841            fn div_array2(self, rhs: Array2<$rhs>) -> Result<Array2<$result>, String> {
842                let mut results = Vec::new();
843
844                for (force_row, distance_row) in self.outer_iter().zip(rhs.outer_iter()) {
845                    let result_row: Array1<$result> = force_row
846                        .iter()
847                        .zip(distance_row.iter())
848                        .map(|(&force, &distance)| force / distance)
849                        .collect();
850                    results.push(result_row);
851                }
852
853                let nrows = results.len();
854                let ncols = if nrows > 0 { results[0].len() } else { 0 };
855                let data: Vec<$result> = results
856                    .into_iter()
857                    .flat_map(|r| {
858                        let (raw_vec, _) = r.into_raw_vec_and_offset();
859                        raw_vec
860                    })
861                    .collect();
862
863                Array2::from_shape_vec((nrows, ncols), data)
864                    .map_err(|_| "Shape mismatch".to_string())
865            }
866        }
867    };
868}
869
870#[macro_export]
871macro_rules! impl_sqrt {
872    ($lhs:ty, $res:ty) => {
873        impl Sqrt<$res> for $lhs {
874            fn sqrt(self) -> $res {
875                if self.power % 2 == 0 {
876                    <$res>::from_exponential(self.multiplier.sqrt(), self.power / 2)
877                } else {
878                    <$res>::from_exponential(
879                        self.multiplier.sqrt() * 10_f64.sqrt(),
880                        (self.power - 1) / 2,
881                    )
882                }
883            }
884        }
885        #[cfg(feature = "pyo3")]
886        #[pymethods]
887        impl $lhs {
888            #[pyo3(name = "sqrt")]
889            fn sqrt_py(&self) -> $res {
890                self.sqrt()
891            }
892        }
893    };
894}
895
896#[macro_export]
897macro_rules! impl_mul_relation_with_self {
898    ($lhs:ty, $res:ty) => {
899        impl_mul_with_self!($lhs, $res);
900        impl_sqrt!($res, $lhs);
901        impl_div!($res, $lhs, $lhs);
902    };
903}
904
905#[macro_export]
906macro_rules! impl_mul_relation_with_other {
907    ($lhs:ty, $rhs:ty, $res:ty) => {
908        impl_mul!($lhs, $rhs, $res);
909        impl_div!($res, $lhs, $rhs);
910        impl_div!($res, $rhs, $lhs);
911    };
912}
913
914pub mod macros {
915    pub use crate::impl_const;
916    pub use crate::impl_div;
917    pub use crate::impl_div_with_self_to_f64;
918    pub use crate::impl_mul;
919    pub use crate::impl_mul_relation_with_other;
920    pub use crate::impl_mul_relation_with_self;
921    pub use crate::impl_mul_with_self;
922    pub use crate::impl_quantity;
923    pub use crate::impl_sqrt;
924    pub use crate::make_alias;
925}