unitforge/
impl_macros.rs

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