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