unitforge/
impl_macros.rs

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