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}