measures/
define_units_relationship.rs

1#[macro_export]
2macro_rules! define_units_relationship {
3    { $exact:tt $with_approx:tt $with_correlation:tt, $unit1:ident 1 == $unit2:ident 1 * __ 1 } => {
4        measures::expand_1_1_same! { $exact $with_approx $with_correlation, $unit2 $unit1 }
5    };
6    { $exact:tt $with_approx:tt $with_correlation:tt, $unit1:ident 1 == $unit2:ident 1 * $unit3:ident 1 } => {
7        measures::expand_1_1! { $exact $with_approx $with_correlation, $unit2 $unit3 $unit1 }
8    };
9    { $exact:tt $with_approx:tt $with_correlation:tt, $unit1:ident 2 == $unit2:ident 1 * $unit3:ident 2 } => {
10        measures::expand_1_2! { $exact $with_approx $with_correlation, $unit2 $unit3 $unit1 }
11    };
12    { $exact:tt $with_approx:tt $with_correlation:tt, $unit1:ident 2 == $unit2:ident 2 * $unit3:ident 1 } => {
13        measures::expand_1_2! { $exact $with_approx $with_correlation, $unit3 $unit2 $unit1 }
14    };
15    { $exact:tt $with_approx:tt $with_correlation:tt, $unit1:ident 3 == $unit2:ident 1 * $unit3:ident 3 } => {
16        measures::expand_1_3! { $exact $with_approx $with_correlation, $unit2 $unit3 $unit1 }
17    };
18    { $exact:tt $with_approx:tt $with_correlation:tt, $unit1:ident 3 == $unit2:ident 3 * $unit3:ident 1 } => {
19        measures::expand_1_3! { $exact $with_approx $with_correlation, $unit3 $unit2 $unit1 }
20    };
21    { $exact:tt $with_approx:tt $with_correlation:tt, $unit1:ident 1 == $unit2:ident 2 * __ 2 } => {
22        measures::expand_2_2_same! { $exact $with_approx $with_correlation, $unit2 $unit1 }
23    };
24    { $exact:tt $with_approx:tt $with_correlation:tt, $unit1:ident 1 == $unit2:ident 2 * $unit3:ident 2 } => {
25        measures::expand_2_2! { $exact $with_approx $with_correlation, $unit2 $unit3 $unit1 }
26    };
27    { $exact:tt $with_approx:tt $with_correlation:tt, $unit1:ident 1 == $unit2:ident 3 * __ 3 } => {
28        measures::expand_3_3_same! { $exact $with_approx $with_correlation, $unit2 $unit1 }
29    };
30    { $exact:tt $with_approx:tt $with_correlation:tt, $unit1:ident 1 == $unit2:ident 3 * $unit3:ident 3 } => {
31        measures::expand_3_3! { $exact $with_approx $with_correlation, $unit2 $unit3 $unit1 }
32    };
33    { $exact:tt $with_approx:tt $with_correlation:tt, $unit1:ident 1 == $unit2:ident 2 X __ 2 } => {
34        measures::expand_cross_2_same! { $exact $with_approx $with_correlation, $unit2 $unit1 }
35    };
36    { $exact:tt $with_approx:tt $with_correlation:tt, $unit1:ident 1 == $unit2:ident 2 X $unit3:ident 2 } => {
37        measures::expand_cross_2! { $exact $with_approx $with_correlation, $unit2 $unit3 $unit1 }
38    };
39    { $exact:tt $with_approx:tt $with_correlation:tt, $unit1:ident 3 == $unit2:ident 3 X __ 3 } => {
40        measures::expand_cross_3_same! { $exact $with_approx $with_correlation, $unit2 $unit1 }
41    };
42    { $exact:tt $with_approx:tt $with_correlation:tt, $unit1:ident 3 == $unit2:ident 3 X $unit3:ident 3 } => {
43        measures::expand_cross_3! { $exact $with_approx $with_correlation, $unit2 $unit3 $unit1 }
44    };
45}
46
47// Generates the operator overloads to multiply and divide two 1-D measures having different units.
48#[macro_export]
49macro_rules! expand_1_1 {
50    {
51        $exact:ident $with_approx:ident $with_correlation:ident,
52        $unit1:ident $unit2:ident $unit3:ident
53    } => {
54        // Operations for exact measures.
55        measures::if_all_true! { { $exact }
56            // Measure<U1> * Measure<U2> -> Measure<U3>
57            impl<Number: ArithmeticOps> Mul<Measure<$unit2, Number>> for Measure<$unit1, Number> {
58                type Output = Measure<$unit3, Number>;
59                fn mul(self, other: Measure<$unit2, Number>) -> Self::Output {
60                    Self::Output::new(self.value * other.value)
61                }
62            }
63
64            // Measure<U2> * Measure<U1> -> Measure<U3>
65            impl<Number: ArithmeticOps> Mul<Measure<$unit1, Number>> for Measure<$unit2, Number> {
66                type Output = Measure<$unit3, Number>;
67                fn mul(self, other: Measure<$unit1, Number>) -> Self::Output {
68                    Self::Output::new(self.value * other.value)
69                }
70            }
71
72            // Measure<U3> / Measure<U1> -> Measure<U2>
73            impl<Number: ArithmeticOps> Div<Measure<$unit1, Number>> for Measure<$unit3, Number> {
74                type Output = Measure<$unit2, Number>;
75                fn div(self, other: Measure<$unit1, Number>) -> Self::Output {
76                    Self::Output::new(self.value / other.value)
77                }
78            }
79
80            // Measure<U3> / Measure<U2> -> Measure<U1>
81            impl<Number: ArithmeticOps> Div<Measure<$unit2, Number>> for Measure<$unit3, Number> {
82                type Output = Measure<$unit1, Number>;
83                fn div(self, other: Measure<$unit2, Number>) -> Self::Output {
84                    Self::Output::new(self.value / other.value)
85                }
86            }
87        }
88
89        // Operations for measures with a variance.
90        measures::if_all_true! { { $with_approx }
91            // ApproxMeasure<U1> * ApproxMeasure<U2> -> ApproxMeasure<U3>
92            impl<Number: ArithmeticOps> Mul<ApproxMeasure<$unit2, Number>> for ApproxMeasure<$unit1, Number> {
93                type Output = ApproxMeasure<$unit3, Number>;
94                fn mul(self, other: ApproxMeasure<$unit2, Number>) -> Self::Output {
95                    Self::Output::with_variance(
96                        self.value * other.value,
97                        other.value * other.value * self.variance + self.value * self.value * other.variance
98                    )
99                }
100            }
101
102            // ApproxMeasure<U2> * ApproxMeasure<U1> -> ApproxMeasure<U3>
103            impl<Number: ArithmeticOps> Mul<ApproxMeasure<$unit1, Number>> for ApproxMeasure<$unit2, Number> {
104                type Output = ApproxMeasure<$unit3, Number>;
105                fn mul(self, other: ApproxMeasure<$unit1, Number>) -> Self::Output {
106                    let value_product = self.value * other.value;
107                    Self::Output::with_variance(
108                        value_product,
109                        value_product *
110                            (other.value * self.variance / self.value +
111                            self.value * other.variance / other.value),
112                    )
113                }
114            }
115
116            // ApproxMeasure<U3> / ApproxMeasure<U1> -> ApproxMeasure<U2>
117            impl<Number: ArithmeticOps> Div<ApproxMeasure<$unit1, Number>> for ApproxMeasure<$unit3, Number> {
118                type Output = ApproxMeasure<$unit2, Number>;
119                fn div(self, other: ApproxMeasure<$unit1, Number>) -> Self::Output {
120                    let self_ratio = self.variance / (self.value * self.value);
121                    let other_ratio = other.variance / (other.value * other.value);
122                    let value_ratio = self.value / other.value;
123                    Self::Output::with_variance(
124                        value_ratio,
125                        value_ratio * value_ratio * (self_ratio + other_ratio),
126                    )
127                }
128            }
129
130            // ApproxMeasure<U3> / ApproxMeasure<U2> -> ApproxMeasure<U1>
131            impl<Number: ArithmeticOps> Div<ApproxMeasure<$unit2, Number>> for ApproxMeasure<$unit3, Number> {
132                type Output = ApproxMeasure<$unit1, Number>;
133                fn div(self, other: ApproxMeasure<$unit2, Number>) -> Self::Output {
134                    let self_ratio = self.variance / (self.value * self.value);
135                    let other_ratio = other.variance / (other.value * other.value);
136                    let value_ratio = self.value / other.value;
137                    Self::Output::with_variance(
138                        value_ratio,
139                        value_ratio * value_ratio * (self_ratio + other_ratio),
140                    )
141                }
142            }
143        }
144
145        // Operations with correlation, for measures with a variance.
146        measures::if_all_true! { { $with_correlation }
147            // ApproxMeasure<U1>.multiply_with_correlation(ApproxMeasure<U2>, Number) -> ApproxMeasure<U3>
148            impl<Number: ArithmeticOps> ApproxMeasure<$unit1, Number> {
149                fn multiply_with_correlation(self, other: ApproxMeasure<$unit2, Number>, correlation: Number) -> ApproxMeasure<$unit3, Number> {
150                    ApproxMeasure::<$unit3, Number>::with_variance(
151                        self.value * other.value,
152                        other.value * other.value * self.variance + self.value * self.value * other.variance + (Number::ONE + Number::ONE) * self.value * other.value * correlation * self.variance.sqrt() * other.variance.sqrt(),
153                    )
154                }
155            }
156
157            // ApproxMeasure<U2>.multiply_with_correlation(ApproxMeasure<U1>, Number) -> ApproxMeasure<U3>
158            impl<Number: ArithmeticOps> ApproxMeasure<$unit1, Number> {
159                fn multiply_with_correlation(self, other: ApproxMeasure<$unit2, Number>, correlation: Number) -> ApproxMeasure<$unit3, Number> {
160                    other.multiply_with_correlation(self, correlation)
161                }
162            }
163
164            // ApproxMeasure<U3>.divide_with_correlation(ApproxMeasure<U1>, Number) -> ApproxMeasure<U2>
165            impl<Number: ArithmeticOps> ApproxMeasure<$unit1, Number> {
166                fn divide_with_correlation(self, other: ApproxMeasure<$unit2, Number>, correlation: Number) -> ApproxMeasure<$unit3, Number> {
167                    //TODO: Verify this formula.
168                    let value_product = self.value * other.value;
169                    ApproxMeasure::<$unit3, Number>::with_variance(
170                        value_product,
171                        other.value * other.value * self.variance + self.value * self.value * other.variance + (Number::ONE + Number::ONE) * self.value * other.value * correlation * self.variance.sqrt() * other.variance.sqrt(),
172                    )
173                }
174            }
175
176            // ApproxMeasure<U3>.divide_with_correlation(ApproxMeasure<U2>, Number) -> ApproxMeasure<U1>
177            impl<Number: ArithmeticOps> ApproxMeasure<$unit1, Number> {
178                fn divide_with_correlation(self, other: ApproxMeasure<$unit2, Number>, correlation: Number) -> ApproxMeasure<$unit3, Number> {
179                    //TODO: Verify this formula.
180                    let value_product = self.value * other.value;
181                    ApproxMeasure::<$unit3, Number>::with_variance(
182                        value_product,
183                        other.value * other.value * self.variance + self.value * self.value * other.variance + (Number::ONE + Number::ONE) * self.value * other.value * correlation * self.variance.sqrt() * other.variance.sqrt(),
184                    )
185                }
186            }
187        }
188    };
189}
190
191// Generates the operator overloads to multiply and divide two 1-D measures having the same unit.
192#[macro_export]
193macro_rules! expand_1_1_same {
194    {
195        $exact:ident $with_approx:ident $with_correlation:ident,
196        $unit1:ident $unit3:ident
197    } => {
198        measures::if_all_true! { { $exact }
199            // Measure<U1> * Measure<U1> -> Measure<U3>
200            impl<Number: ArithmeticOps> Mul<Measure<$unit1, Number>> for Measure<$unit1, Number> {
201                type Output = Measure<$unit3, Number>;
202                fn mul(self, other: Measure<$unit1, Number>) -> Self::Output {
203                    Self::Output::new(self.value * other.value)
204                }
205            }
206
207            // Measure<U3> / Measure<U1> -> Measure<U1>
208            impl<Number: ArithmeticOps> Div<Measure<$unit1, Number>> for Measure<$unit3, Number> {
209                type Output = Measure<$unit1, Number>;
210                fn div(self, other: Measure<$unit1, Number>) -> Self::Output {
211                    Self::Output::new(self.value / other.value)
212                }
213            }
214
215            // Measure<U1>.squared() -> Measure<U3>
216            impl<Number: ArithmeticOps> Measure<$unit1, Number> {
217                pub fn squared(self) -> Measure<$unit3, Number> {
218                    Measure::<$unit3, Number>::new(self.value * self.value)
219                }
220            }
221
222            // Measure<U3>.sqrt() -> Measure<U1>
223            // A generic implementation caused a slowdown in some cases,
224            // and so it was replaced by the following implementations, specific,
225            // respectively, for f64 and f32.
226            impl Sqrt for Measure<$unit3, f64> {
227                type Output = Measure<$unit1, f64>;
228                fn sqrt(self) -> Self::Output {
229                    Self::Output::new(self.value.sqrt())
230                }
231            }
232            impl Sqrt for Measure<$unit3, f32> {
233                type Output = Measure<$unit1, f32>;
234                fn sqrt(self) -> Self::Output {
235                    Self::Output::new(self.value.sqrt())
236                }
237            }
238        }
239
240        measures::if_all_true! { { $with_approx }
241            // ApproxMeasure<U1> * ApproxMeasure<U1> -> ApproxMeasure<U3>
242            impl<Number: ArithmeticOps> Mul<ApproxMeasure<$unit1, Number>> for ApproxMeasure<$unit1, Number> {
243                type Output = ApproxMeasure<$unit3, Number>;
244                fn mul(self, other: ApproxMeasure<$unit1, Number>) -> Self::Output {
245                    let value_product = self.value * other.value;
246                    Self::Output::with_variance(
247                        value_product,
248                        value_product *
249                            (other.value * self.variance / self.value +
250                            self.value * other.variance / other.value),
251                    )
252                }
253            }
254
255            // ApproxMeasure<U3> / ApproxMeasure<U1> -> ApproxMeasure<U1>
256            impl<Number: ArithmeticOps> Div<ApproxMeasure<$unit1, Number>> for ApproxMeasure<$unit3, Number> {
257                type Output = ApproxMeasure<$unit1, Number>;
258                fn div(self, other: ApproxMeasure<$unit1, Number>) -> Self::Output {
259                    let self_ratio = self.variance / (self.value * self.value);
260                    let other_ratio = other.variance / (other.value * other.value);
261                    let value_ratio = self.value / other.value;
262                    Self::Output::with_variance(
263                        value_ratio,
264                        value_ratio * value_ratio * (self_ratio + other_ratio),
265                    )
266                }
267            }
268
269            // ApproxMeasure<U1>.squared() -> ApproxMeasure<U3>
270            impl<Number: ArithmeticOps> ApproxMeasure<$unit1, Number> {
271                fn squared(self) -> ApproxMeasure<$unit3, Number> {
272                    let value_product = self.value * self.value;
273                    ApproxMeasure::<$unit3, Number>::with_variance(
274                        value_product,
275                        value_product * ((self.variance + self.variance) + (self.variance + self.variance)),
276                    )
277                }
278            }
279
280            // ApproxMeasure<U3>.sqrt() -> ApproxMeasure<U1>
281            impl<Number: ArithmeticOps> Sqrt for ApproxMeasure<$unit3, Number> {
282                type Output = ApproxMeasure<$unit1, Number>;
283                fn sqrt(self) -> Self::Output {
284                    Self::Output::with_variance(
285                        self.value.sqrt(),
286                        self.variance / self.value / ((Number::ONE + Number::ONE) + (Number::ONE + Number::ONE)),
287                    )
288                }
289            }
290        }
291    };
292}
293
294// Generates the operator overloads to multiply and divide a 1-D measure and a 2-D measure.
295#[macro_export]
296macro_rules! expand_1_2 {
297    {
298        $exact:ident $with_approx:ident $with_correlation:ident,
299        $unit1:ident $unit2:ident $unit3:ident
300    } => {
301        // Measure<U1> * Measure2d<U2> -> Measure2d<U3>
302        impl<Number: ArithmeticOps> Mul<Measure2d<$unit2, Number>> for Measure<$unit1, Number> {
303            type Output = Measure2d<$unit3, Number>;
304            fn mul(self, other: Measure2d<$unit2, Number>) -> Self::Output {
305                Self::Output::new([self.value * other.values[0], self.value * other.values[1]])
306            }
307        }
308
309        // Measure2d<U2> * Measure<U1> -> Measure2d<U3>
310        impl<Number: ArithmeticOps> Mul<Measure<$unit1, Number>> for Measure2d<$unit2, Number> {
311            type Output = Measure2d<$unit3, Number>;
312            fn mul(self, other: Measure<$unit1, Number>) -> Self::Output {
313                Self::Output::new([self.values[0] * other.value, self.values[1] * other.value])
314            }
315        }
316
317        // Measure2d<U3> / Measure<U1> -> Measure2d<U2>
318        impl<Number: ArithmeticOps> Div<Measure<$unit1, Number>> for Measure2d<$unit3, Number> {
319            type Output = Measure2d<$unit2, Number>;
320            fn div(self, other: Measure<$unit1, Number>) -> Self::Output {
321                Self::Output::new([self.values[0] / other.value, self.values[1] / other.value])
322            }
323        }
324    };
325}
326
327// Generates the operator overloads to multiply and divide a 1-D measure and a 3-D measure.
328#[macro_export]
329macro_rules! expand_1_3 {
330    {
331        $exact:ident $with_approx:ident $with_correlation:ident,
332        $unit1:ident $unit2:ident $unit3:ident
333    } => {
334        // Measure<U1> * Measure3d<U2> -> Measure3d<U3>
335        impl<Number: ArithmeticOps> Mul<Measure3d<$unit2, Number>> for Measure<$unit1, Number> {
336            type Output = Measure3d<$unit3, Number>;
337            fn mul(self, other: Measure3d<$unit2, Number>) -> Self::Output {
338                Self::Output::new([
339                    self.value * other.values[0],
340                    self.value * other.values[1],
341                    self.value * other.values[2],
342                ])
343            }
344        }
345
346        // Measure3d<U2> * Measure<U1> -> Measure3d<U3>
347        impl<Number: ArithmeticOps> Mul<Measure<$unit1, Number>> for Measure3d<$unit2, Number> {
348            type Output = Measure3d<$unit3, Number>;
349            fn mul(self, other: Measure<$unit1, Number>) -> Self::Output {
350                other * self
351            }
352        }
353
354        // Measure3d<U3> / Measure<U1> -> Measure3d<U2>
355        impl<Number: ArithmeticOps> Div<Measure<$unit1, Number>> for Measure3d<$unit3, Number> {
356            type Output = Measure3d<$unit2, Number>;
357            fn div(self, other: Measure<$unit1, Number>) -> Self::Output {
358                Self::Output::new([
359                    self.values[0] / other.value,
360                    self.values[1] / other.value,
361                    self.values[2] / other.value,
362                ])
363            }
364        }
365
366        measures::if_all_true! { { $with_approx }
367            // ApproxMeasure<U1> * ApproxMeasure3d<U2> -> ApproxMeasure3d<U3>
368            impl<Number: ArithmeticOps> Mul<ApproxMeasure3d<$unit2, Number>> for ApproxMeasure<$unit1, Number> {
369                type Output = ApproxMeasure3d<$unit3, Number>;
370                fn mul(self, other: ApproxMeasure3d<$unit2, Number>) -> Self::Output {
371                    let value_product_x = self.value * other.values[0];
372                    let value_product_y = self.value * other.values[1];
373                    let value_product_z = self.value * other.values[2];
374                    Self::Output::with_covariances(
375                        [
376                            value_product_x,
377                            value_product_y,
378                            value_product_z,
379                        ],
380                        other.covariances,
381                    )
382                }
383            }
384
385            // ApproxMeasure3d<U2> * ApproxMeasure<U1> -> ApproxMeasure3d<U3>
386            impl<Number: ArithmeticOps> Mul<ApproxMeasure<$unit1, Number>> for ApproxMeasure3d<$unit2, Number> {
387                type Output = ApproxMeasure3d<$unit3, Number>;
388                fn mul(self, other: ApproxMeasure<$unit1, Number>) -> Self::Output {
389                    other * self
390                }
391            }
392
393            // ApproxMeasure3d<U3> / ApproxMeasure<U1> -> ApproxMeasure3d<U2>
394            impl<Number: ArithmeticOps> Div<ApproxMeasure<$unit1, Number>> for ApproxMeasure3d<$unit3, Number> {
395                type Output = ApproxMeasure3d<$unit2, Number>;
396                fn div(self, other: ApproxMeasure<$unit1, Number>) -> Self::Output {
397                    let value_ratio_x = self.values[0] / other.value;
398                    let value_ratio_y = self.values[1] / other.value;
399                    let value_ratio_z = self.values[2] / other.value;
400                    Self::Output::with_covariances(
401                        [
402                            value_ratio_x,
403                            value_ratio_y,
404                            value_ratio_z,
405                        ],
406                        self.covariances,
407                    )
408                }
409            }
410        }
411    };
412}
413
414// Generates the operator overloads to compute the dot product (`*`) of two 2-D measures having different units.
415#[macro_export]
416macro_rules! expand_2_2 {
417    {
418        $exact:ident $with_approx:ident $with_correlation:ident,
419        $unit1:ident $unit2:ident $unit3:ident
420    } => {
421        // Measure2d<U1> * Measure2d<U2> -> Measure<U3>
422        impl<Number: ArithmeticOps> Mul<Measure2d<$unit2, Number>> for Measure2d<$unit1, Number> {
423            type Output = Measure<$unit3, Number>;
424            fn mul(self, other: Measure2d<$unit2, Number>) -> Self::Output {
425                Self::Output::new(self.values[0] * other.values[0] + self.values[1] * other.values[1])
426            }
427        }
428
429        // Measure2d<U2> * Measure2d<U1> -> Measure<U3>
430        impl<Number: ArithmeticOps> Mul<Measure2d<$unit1, Number>> for Measure2d<$unit2, Number> {
431            type Output = Measure<$unit3, Number>;
432            fn mul(self, other: Measure2d<$unit1, Number>) -> Self::Output {
433                Self::Output::new(self.values[0] * other.values[0] + self.values[1] * other.values[1])
434            }
435        }
436
437        measures::if_all_true! { { $with_approx }
438        }
439    };
440}
441
442// Generates the operator overloads to compute the dot product (`*`) of two 2-D measures having the same unit.
443#[macro_export]
444macro_rules! expand_2_2_same {
445    {
446        $exact:ident $with_approx:ident $with_correlation:ident,
447        $unit1:ident $unit2:ident
448    } => {
449        // Measure2d<U1> * Measure2d<U1> -> Measure<U3>
450        impl<Number: ArithmeticOps> Mul<Measure2d<$unit1, Number>> for Measure2d<$unit1, Number> {
451            type Output = Measure<$unit2, Number>;
452            fn mul(self, other: Measure2d<$unit1, Number>) -> Self::Output {
453                Self::Output::new(self.values[0] * other.values[0] + self.values[1] * other.values[1])
454            }
455        }
456
457        // Measure2d<U1>.squared() -> Measure<U3>
458        impl<Number: ArithmeticOps> Measure2d<$unit1, Number> {
459            pub fn squared(self) -> Measure<$unit2, Number> {
460                Measure::<$unit2, Number>::new(self.values[0] * self.values[0] + self.values[1] * self.values[1])
461            }
462        }
463
464        measures::if_all_true! { { $with_approx }
465        }
466    };
467}
468
469// Generates the operator overloads to compute the dot product (`*`) of two 3-D measures having the same unit.
470#[macro_export]
471macro_rules! expand_3_3_same {
472    {
473        $exact:ident $with_approx:ident $with_correlation:ident,
474        $unit1:ident $unit2:ident
475    } => {
476        // Measure3d<U1> * Measure3d<U1> -> Measure<U3>
477        impl<Number: ArithmeticOps> Mul<Measure3d<$unit1, Number>> for Measure3d<$unit1, Number> {
478            type Output = Measure<$unit2, Number>;
479            fn mul(self, other: Measure3d<$unit1, Number>) -> Self::Output {
480                Self::Output::new(self.values[0] * other.values[0] + self.values[1] * other.values[1] + self.values[2] * other.values[2])
481            }
482        }
483
484        // Measure3d<U1>.squared() -> Measure<U3>
485        impl<Number: ArithmeticOps> Measure3d<$unit1, Number> {
486            pub fn squared(self) -> Measure<$unit2, Number> {
487                Measure::<$unit2, Number>::new(self.values[0] * self.values[0] + self.values[1] * self.values[1] + self.values[2] * self.values[2])
488            }
489        }
490
491        measures::if_all_true! { { $with_approx }
492            // ApproxMeasure3d<U1> * ApproxMeasure3d<U1> -> ApproxMeasure<U3>
493            impl<Number: ArithmeticOps> Mul<ApproxMeasure3d<$unit1, Number>> for ApproxMeasure3d<$unit1, Number> {
494                type Output = ApproxMeasure<$unit2, Number>;
495                fn mul(self, other: ApproxMeasure3d<$unit1, Number>) -> Self::Output {
496                    let value_product_x = self.values[0] * other.values[0];
497                    let value_product_y = self.values[1] * other.values[1];
498                    let value_product_z = self.values[2] * other.values[2];
499                    Self::Output::with_variance(
500                        value_product_x +
501                        value_product_y +
502                        value_product_z,
503                        self.covariances[0][0],
504                    )
505                }
506            }
507
508            // ApproxMeasure3d<U1>.squared() -> ApproxMeasure<U3>
509            impl<Number: ArithmeticOps> ApproxMeasure3d<$unit1, Number> {
510                fn squared(self) -> ApproxMeasure<$unit2, Number> {
511                    let value = self.values[0] * self.values[0] + self.values[1] * self.values[1] + self.values[2] * self.values[2];
512                    ApproxMeasure::<$unit2, Number>::with_variance(
513                        value,
514                        value * (self.covariances[0][0] + self.covariances[0][0]),
515                    )
516                }
517            }
518        }
519    };
520}
521
522// Generates the operator overloads to compute the dot product (`*`) of two 3-D measures having different units.
523#[macro_export]
524macro_rules! expand_3_3 {
525    {
526        $exact:ident $with_approx:ident $with_correlation:ident,
527        $unit1:ident $unit2:ident $unit3:ident
528    } => {
529        // Measure3d<U1> * Measure3d<U2> -> Measure<U3>
530        impl<Number: ArithmeticOps> Mul<Measure3d<$unit2, Number>> for Measure3d<$unit1, Number> {
531            type Output = Measure<$unit3, Number>;
532            fn mul(self, other: Measure3d<$unit2, Number>) -> Self::Output {
533                Self::Output::new(self.values[0] * other.values[0] + self.values[1] * other.values[1] + self.values[2] * other.values[2])
534            }
535        }
536
537        // Measure3d<U2> * Measure3d<U1> -> Measure<U3>
538        impl<Number: ArithmeticOps> Mul<Measure3d<$unit1, Number>> for Measure3d<$unit2, Number> {
539            type Output = Measure<$unit3, Number>;
540            fn mul(self, other: Measure3d<$unit1, Number>) -> Self::Output {
541                Self::Output::new(self.values[0] * other.values[0] + self.values[1] * other.values[1] + self.values[2] * other.values[2])
542            }
543        }
544
545        measures::if_all_true! { { $with_approx }
546            // Measure3d<U1> * Measure3d<U2> -> Measure<U3>
547            impl<Number: ArithmeticOps> Mul<ApproxMeasure3d<$unit2, Number>> for ApproxMeasure3d<$unit1, Number> {
548                type Output = ApproxMeasure<$unit3, Number>;
549                fn mul(self, other: ApproxMeasure3d<$unit2, Number>) -> Self::Output {
550                    let value_product_x = self.values[0] * other.values[0];
551                    let value_product_y = self.values[1] * other.values[1];
552                    let value_product_z = self.values[2] * other.values[2];
553                    Self::Output::with_variance(
554                        value_product_x + value_product_y + value_product_z,
555                        self.covariances[0][0],
556                    )
557                }
558            }
559
560            // Measure3d<U2> * Measure3d<U1> -> Measure<U3>
561            impl<Number: ArithmeticOps> Mul<ApproxMeasure3d<$unit1, Number>> for ApproxMeasure3d<$unit2, Number> {
562                type Output = ApproxMeasure<$unit3, Number>;
563                fn mul(self, other: ApproxMeasure3d<$unit1, Number>) -> Self::Output {
564                    let value_product_x = self.values[0] * other.values[0];
565                    let value_product_y = self.values[1] * other.values[1];
566                    let value_product_z = self.values[2] * other.values[2];
567                    Self::Output::with_variance(
568                        value_product_x + value_product_y + value_product_z,
569                        self.covariances[0][0],
570                    )
571                }
572            }
573        }
574    };
575}
576
577// Generates the function to compute the cross product of two 2-D measures having the same unit.
578#[macro_export]
579macro_rules! expand_cross_2_same {
580    {
581        $exact:ident $with_approx:ident $with_correlation:ident,
582        $unit1:ident $unit2:ident
583    } => {
584        // Measure2d<U1>.cross_product(Measure2d<U1>) -> Measure<U3>
585        impl<Number: ArithmeticOps> measures::traits::CrossProduct<Measure2d<$unit1, Number>> for Measure2d<$unit1, Number> {
586            type Output = Measure<$unit2, Number>;
587            fn cross_product(self, other: Measure2d<$unit1, Number>) -> Self::Output {
588                Self::Output::new(self.values[0] * other.values[1] - self.values[1] * other.values[0])
589            }
590        }
591
592        measures::if_all_true! { { $with_approx }
593        }
594    };
595}
596
597// Generates the functions to compute the cross product of two 2-D measures having different units.
598#[macro_export]
599macro_rules! expand_cross_2 {
600    {
601        $exact:ident $with_approx:ident $with_correlation:ident,
602        $unit1:ident $unit2:ident $unit3:ident
603    } => {
604        // Measure2d<U1>.cross_product(Measure2d<U2>) -> Measure<U3>
605        impl<Number: ArithmeticOps> measures::traits::CrossProduct<Measure2d<$unit2, Number>> for Measure2d<$unit1, Number> {
606            type Output = Measure<$unit3, Number>;
607            fn cross_product(self, other: Measure2d<$unit2, Number>) -> Self::Output {
608                Self::Output::new(self.values[0] * other.values[1] - self.values[1] * other.values[0])
609            }
610        }
611
612        // Measure2d<U2>.cross_product(Measure2d<U1>) -> Measure<U3>
613        impl<Number: ArithmeticOps> measures::traits::CrossProduct<Measure2d<$unit1, Number>> for Measure2d<$unit2, Number> {
614            type Output = Measure<$unit3, Number>;
615            fn cross_product(self, other: Measure2d<$unit1, Number>) -> Self::Output {
616                Self::Output::new(self.values[0] * other.values[1] - self.values[1] * other.values[0])
617            }
618        }
619
620        measures::if_all_true! { { $with_approx }
621        }
622    };
623}
624
625// Generates the function to compute the cross product of two 3-D measures having the same unit.
626#[macro_export]
627macro_rules! expand_cross_3_same {
628    {
629        $exact:ident $with_approx:ident $with_correlation:ident,
630        $unit1:ident $unit2:ident
631    } => {
632        // Measure3d<U1>.cross_product(Measure3d<U1>) -> Measure<U3>
633        impl<Number: ArithmeticOps> measures::traits::CrossProduct<Measure3d<$unit1, Number>> for Measure3d<$unit1, Number> {
634            type Output = Measure3d<$unit2, Number>;
635            fn cross_product(self, other: Measure3d<$unit1, Number>) -> Self::Output {
636                Self::Output::new(
637                    [
638                        self.values[1] * other.values[2] - self.values[2] * other.values[1],
639                        self.values[2] * other.values[0] - self.values[0] * other.values[2],
640                        self.values[0] * other.values[1] - self.values[1] * other.values[0],
641                    ]
642                )
643            }
644        }
645
646        measures::if_all_true! { { $with_approx }
647        }
648    };
649}
650
651// Generates the functions to compute the cross product of two 3-D measures having different units.
652#[macro_export]
653macro_rules! expand_cross_3 {
654    {
655        $exact:ident $with_approx:ident $with_correlation:ident,
656        $unit1:ident $unit2:ident $unit3:ident
657    } => {
658        // Measure3d<U1>.cross_product(Measure3d<U2>) -> Measure<U4>
659        impl<Number: ArithmeticOps> measures::traits::CrossProduct<Measure3d<$unit2, Number>> for Measure3d<$unit1, Number> {
660            type Output = Measure3d<$unit3, Number>;
661            fn cross_product(self, other: Measure3d<$unit2, Number>) -> Self::Output {
662                Self::Output::new([
663                    self.values[1] * other.values[2] - self.values[2] * other.values[1],
664                    self.values[2] * other.values[0] - self.values[0] * other.values[2],
665                    self.values[0] * other.values[1] - self.values[1] * other.values[0],
666                ])
667            }
668        }
669
670        // Measure3d<U2>.cross_product(Measure3d<U1>) -> Measure<U4>
671        impl<Number: ArithmeticOps> measures::traits::CrossProduct<Measure3d<$unit1, Number>> for Measure3d<$unit2, Number> {
672            type Output = Measure3d<$unit3, Number>;
673            fn cross_product(self, other: Measure3d<$unit1, Number>) -> Self::Output {
674                Self::Output::new([
675                    self.values[1] * other.values[2] - self.values[2] * other.values[1],
676                    self.values[2] * other.values[0] - self.values[0] * other.values[2],
677                    self.values[0] * other.values[1] - self.values[1] * other.values[0],
678                ])
679            }
680        }
681
682        measures::if_all_true! { { $with_approx }
683        }
684    };
685}