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}