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