Skip to main content

num_dual/
macros.rs

1#[macro_export]
2macro_rules! impl_from_f {
3    ($struct:ident, [$($im:ident),*]$(, [$($dim:tt),*]$(, [$($ddim:tt),*])*)?) => {
4        impl<T: DualNum<F>, F$($(, $dim: Dim)*)?> From<F> for $struct<T, F$($(, $dim)*)?>
5        where
6            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
7        {
8            #[inline]
9            fn from(float: F) -> Self {
10                Self::from_re(T::from(float))
11            }
12        }
13    };
14}
15
16#[macro_export]
17macro_rules! impl_zero_one {
18    ($struct:ident$(, [$($dim:tt),*]$(, [$($ddim:tt),*])*)?) => {
19        impl<T: DualNum<F>, F: Float$($(, $dim: Dim)*)?> Zero for $struct<T, F$($(, $dim)*)?>
20        where
21            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
22        {
23            #[inline]
24            fn zero() -> Self {
25                Self::from_re(T::zero())
26            }
27
28            #[inline]
29            fn is_zero(&self) -> bool {
30                self.re.is_zero()
31            }
32        }
33
34        impl<T: DualNum<F>, F: Float$($(, $dim: Dim)*)?> One for $struct<T, F$($(, $dim)*)?>
35        where
36            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
37        {
38            #[inline]
39            fn one() -> Self {
40                Self::from_re(T::one())
41            }
42
43            #[inline]
44            fn is_one(&self) -> bool {
45                self.re.is_one()
46            }
47        }
48    };
49}
50
51#[macro_export]
52macro_rules! impl_add_sub_rem {
53    ($struct:ident, [$($im:ident),*]$(, [$($dim:tt),*]$(, [$($ddim:tt),*])*)?) => {
54        impl<'a, 'b, T: DualNum<F>, F: Float$($(, $dim: Dim)*)?> Add<&'a $struct<T, F$($(, $dim)*)?>>
55            for &'b $struct<T, F$($(, $dim)*)?>
56        where
57            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
58        {
59            type Output = $struct<T, F$($(, $dim)*)?>;
60            #[inline]
61            fn add(self, other: &$struct<T, F$($(, $dim)*)?>) -> $struct<T, F$($(, $dim)*)?> {
62                Self::Output::new(self.re.clone() + &other.re, $(self.$im.clone() + &other.$im,)*)
63            }
64        }
65
66        impl<'a, 'b, T: DualNum<F>, F: Float$($(, $dim: Dim)*)?> Sub<&'a $struct<T, F$($(, $dim)*)?>>
67            for &'b $struct<T, F$($(, $dim)*)?>
68        where
69            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
70        {
71            type Output = $struct<T, F$($(, $dim)*)?>;
72            #[inline]
73            fn sub(self, other: &$struct<T, F$($(, $dim)*)?>) -> $struct<T, F$($(, $dim)*)?> {
74                Self::Output::new(self.re.clone() - &other.re, $(self.$im.clone() - &other.$im,)*)
75            }
76        }
77
78        impl<'a, 'b, T: DualNum<F>, F$($(, $dim: Dim)*)?> Rem<&'a $struct<T, F$($(, $dim)*)?>> for &'b $struct<T, F$($(, $dim)*)?>
79        where
80            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
81        {
82            type Output = $struct<T, F$($(, $dim)*)?>;
83            #[inline]
84            fn rem(self, _other: &$struct<T, F$($(, $dim)*)?>) -> $struct<T, F$($(, $dim)*)?> {
85                unimplemented!()
86            }
87        }
88    };
89}
90
91#[macro_export]
92macro_rules! forward_binop {
93    ($struct:ident, $trt:ident, $operator:tt, $mth:ident$(, [$($dim:tt),*]$(, [$($ddim:tt),*])*)?) => {
94        impl<T: DualNum<F>, F: Float$($(, $dim: Dim)*)?> $trt<$struct<T, F$($(, $dim)*)?>> for &$struct<T, F$($(, $dim)*)?>
95        where
96            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
97        {
98            type Output = $struct<T, F$($(, $dim)*)?>;
99            #[inline]
100            fn $mth(self, rhs: $struct<T, F$($(, $dim)*)?>) -> Self::Output {
101                self $operator &rhs
102            }
103        }
104
105        impl<T: DualNum<F>, F: Float$($(, $dim: Dim)*)?> $trt<&$struct<T, F$($(, $dim)*)?>> for $struct<T, F$($(, $dim)*)?>
106        where
107            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
108        {
109            type Output = $struct<T, F$($(, $dim)*)?>;
110            #[inline]
111            fn $mth(self, rhs: &$struct<T, F$($(, $dim)*)?>) -> Self::Output {
112                &self $operator rhs
113            }
114        }
115
116        impl<T: DualNum<F>, F: Float$($(, $dim: Dim)*)?> $trt for $struct<T, F$($(, $dim)*)?>
117        where
118            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
119        {
120            type Output = $struct<T, F$($(, $dim)*)?>;
121            #[inline]
122            fn $mth(self, rhs: $struct<T, F$($(, $dim)*)?>) -> Self::Output {
123                &self $operator &rhs
124            }
125        }
126    };
127}
128
129#[macro_export]
130macro_rules! impl_neg {
131    ($struct:ident, [$($im:ident),*]$(, [$($dim:tt),*]$(, [$($ddim:tt),*])*)?) => {
132        impl<T: DualNum<F>, F: Float$($(, $dim: Dim)*)?> Neg for $struct<T, F$($(, $dim)*)?>
133        where
134            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
135        {
136            type Output = Self;
137            #[inline]
138            fn neg(self) -> Self {
139                -&self
140            }
141        }
142
143        impl<T: DualNum<F>, F: Float$($(, $dim: Dim)*)?> Neg for &$struct<T, F$($(, $dim)*)?>
144        where
145            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
146        {
147            type Output = $struct<T, F$($(, $dim)*)?>;
148            #[inline]
149            fn neg(self) -> Self::Output {
150                <$struct<T, F$($(, $dim)*)?>>::new(-self.re.clone(), $(-self.$im.clone()),*)
151            }
152        }
153    };
154}
155
156#[macro_export]
157macro_rules! impl_assign_ops {
158    ($struct:ident, [$($im:ident),*]$(, [$($dim:tt),*]$(, [$($ddim:tt),*])*)?) => {
159        impl<T: DualNum<F>, F: Float$($(, $dim: Dim)*)?> MulAssign for $struct<T, F$($(, $dim)*)?>
160        where
161            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
162        {
163            #[inline]
164            fn mul_assign(&mut self, other: Self) {
165                *self = self.clone() * other;
166            }
167        }
168
169        impl<T: DualNum<F>, F: Float$($(, $dim: Dim)*)?> DivAssign for $struct<T, F$($(, $dim)*)?>
170        where
171            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
172        {
173            #[inline]
174            fn div_assign(&mut self, other: Self) {
175                *self = self.clone() / other;
176            }
177        }
178
179        impl<T: DualNum<F>, F$($(, $dim: Dim)*)?> AddAssign for $struct<T, F$($(, $dim)*)?>
180        where
181            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
182        {
183            #[inline]
184            fn add_assign(&mut self, other: Self) {
185                self.re += other.re;
186                $(self.$im += other.$im;)*
187            }
188        }
189
190        impl<T: DualNum<F>, F$($(, $dim: Dim)*)?> SubAssign for $struct<T, F$($(, $dim)*)?>
191        where
192            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
193        {
194            #[inline]
195            fn sub_assign(&mut self, other: Self) {
196                self.re -= other.re;
197                $(self.$im -= other.$im;)*
198            }
199        }
200
201        impl<T: DualNum<F>, F$($(, $dim: Dim)*)?> RemAssign for $struct<T, F$($(, $dim)*)?>
202        where
203            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
204        {
205            #[inline]
206            fn rem_assign(&mut self, _other: Self) {
207                unimplemented!()
208            }
209        }
210    };
211}
212
213#[macro_export]
214macro_rules! impl_scalar_op {
215    ($struct:ident, [$($im:ident),*]$(, [$($dim:tt),*]$(, [$($ddim:tt),*])*)?) => {
216        impl<T: DualNum<F>, F: DualNumFloat$($(, $dim: Dim)*)?> Mul<F> for $struct<T, F$($(, $dim)*)?>
217        where
218            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
219        {
220            type Output = Self;
221            #[inline]
222            fn mul(mut self, other: F) -> Self {
223                self *= other;
224                self
225            }
226        }
227
228        impl<T: DualNum<F>, F: DualNumFloat$($(, $dim: Dim)*)?> MulAssign<F> for $struct<T, F$($(, $dim)*)?>
229        where
230            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
231        {
232            #[inline]
233            fn mul_assign(&mut self, other: F) {
234                self.re *= other;
235                $(self.$im *= T::from(other);)*
236            }
237        }
238
239        impl<T: DualNum<F>, F: DualNumFloat$($(, $dim: Dim)*)?> Div<F> for $struct<T, F$($(, $dim)*)?>
240        where
241            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
242        {
243            type Output = Self;
244            #[inline]
245            fn div(mut self, other: F) -> Self {
246                self /= other;
247                self
248            }
249        }
250
251        impl<T: DualNum<F>, F: DualNumFloat$($(, $dim: Dim)*)?> DivAssign<F> for $struct<T, F$($(, $dim)*)?>
252        where
253            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
254        {
255            #[inline]
256            fn div_assign(&mut self, other: F) {
257                self.re /= other;
258                $(self.$im /= T::from(other);)*
259            }
260        }
261
262        impl<T: DualNum<F>, F$($(, $dim: Dim)*)?> Add<F> for $struct<T, F$($(, $dim)*)?>
263        where
264            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
265        {
266            type Output = Self;
267            #[inline]
268            fn add(mut self, other: F) -> Self {
269                self.re += other;
270                self
271            }
272        }
273
274        impl<T: DualNum<F>, F$($(, $dim: Dim)*)?> AddAssign<F> for $struct<T, F$($(, $dim)*)?>
275        where
276            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
277        {
278            #[inline]
279            fn add_assign(&mut self, other: F)  {
280                self.re += other;
281            }
282        }
283
284        impl<T: DualNum<F>, F$($(, $dim: Dim)*)?> Sub<F> for $struct<T, F$($(, $dim)*)?>
285        where
286            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
287        {
288            type Output = Self;
289            #[inline]
290            fn sub(mut self, other: F) -> Self {
291                self.re -= other;
292                self
293            }
294        }
295
296        impl<T: DualNum<F>, F$($(, $dim: Dim)*)?> SubAssign<F> for $struct<T, F$($(, $dim)*)?>
297        where
298            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
299        {
300            #[inline]
301            fn sub_assign(&mut self, other: F)  {
302                self.re -= other;
303            }
304        }
305
306        impl<T: DualNum<F>, F$($(, $dim: Dim)*)?> Rem<F> for $struct<T, F$($(, $dim)*)?>
307        where
308            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
309        {
310            type Output = Self;
311            #[inline]
312            fn rem(self, _other: F) -> Self {
313                unimplemented!()
314            }
315        }
316
317        impl<T: DualNum<F>, F$($(, $dim: Dim)*)?> RemAssign<F> for $struct<T, F$($(, $dim)*)?>
318        where
319            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
320        {
321            #[inline]
322            fn rem_assign(&mut self, _other: F) {
323                unimplemented!()
324            }
325        }
326    };
327}
328
329#[macro_export]
330macro_rules! impl_inv {
331    ($struct:ident$(, [$($dim:tt),*]$(, [$($ddim:tt),*])*)?) => {
332        impl<T: DualNum<F>, F: DualNumFloat$($(, $dim: Dim)*)?> Inv for $struct<T, F$($(, $dim)*)?>
333        where
334            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
335        {
336            type Output = Self;
337            #[inline]
338            fn inv(self) -> Self {
339                self.recip()
340            }
341        }
342    };
343}
344
345#[macro_export]
346macro_rules! impl_iterator {
347    ($struct:ident$(, [$($dim:tt),*]$(, [$($ddim:tt),*])*)?) => {
348        impl<T: DualNum<F>, F: Float$($(, $dim: Dim)*)?> Sum for $struct<T, F$($(, $dim)*)?>
349        where
350            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
351        {
352            #[inline]
353            fn sum<I>(iter: I) -> Self
354            where
355                I: Iterator<Item = Self>,
356            {
357                iter.fold(Self::zero(), |acc, c| acc + c)
358            }
359        }
360
361        impl<'a, T: DualNum<F>, F: Float$($(, $dim: Dim)*)?> Sum<&'a $struct<T, F$($(, $dim)*)?>>
362            for $struct<T, F$($(, $dim)*)?>
363        where
364            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
365        {
366            #[inline]
367            fn sum<I>(iter: I) -> Self
368            where
369                I: Iterator<Item = &'a $struct<T, F$($(, $dim)*)?>>,
370            {
371                iter.fold(Self::zero(), |acc, c| acc + c)
372            }
373        }
374        impl<T: DualNum<F>, F: Float$($(, $dim: Dim)*)?> Product for $struct<T, F$($(, $dim)*)?>
375        where
376            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
377        {
378            #[inline]
379            fn product<I>(iter: I) -> Self
380            where
381                I: Iterator<Item = Self>,
382            {
383                iter.fold(Self::one(), |acc, c| acc * c)
384            }
385        }
386        impl<'a, T: DualNum<F>, F: Float$($(, $dim: Dim)*)?> Product<&'a $struct<T, F$($(, $dim)*)?>>
387            for $struct<T, F$($(, $dim)*)?>
388        where
389            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
390        {
391            #[inline]
392            fn product<I>(iter: I) -> Self
393            where
394                I: Iterator<Item = &'a $struct<T, F$($(, $dim)*)?>>,
395            {
396                iter.fold(Self::one(), |acc, c| acc * c)
397            }
398        }
399    };
400}
401
402#[macro_export]
403macro_rules! impl_from_primitive {
404    ($struct:ident$(, [$($dim:tt),*]$(, [$($ddim:tt),*])*)?) => {
405        impl<T: DualNum<F>, F: Float + FromPrimitive$($(, $dim: Dim)*)?> FromPrimitive for $struct<T, F$($(, $dim)*)?>
406        where
407            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
408        {
409            #[inline]
410            fn from_isize(n: isize) -> Option<Self> {
411                F::from_isize(n).map(|f| f.into())
412            }
413
414            #[inline]
415            fn from_i8(n: i8) -> Option<Self> {
416                F::from_i8(n).map(|f| f.into())
417            }
418
419            #[inline]
420            fn from_i16(n: i16) -> Option<Self> {
421                F::from_i16(n).map(|f| f.into())
422            }
423
424            #[inline]
425            fn from_i32(n: i32) -> Option<Self> {
426                F::from_i32(n).map(|f| f.into())
427            }
428
429            #[inline]
430            fn from_i64(n: i64) -> Option<Self> {
431                F::from_i64(n).map(|f| f.into())
432            }
433
434            #[inline]
435            fn from_i128(n: i128) -> Option<Self> {
436                F::from_i128(n).map(|f| f.into())
437            }
438
439            #[inline]
440            fn from_usize(n: usize) -> Option<Self> {
441                F::from_usize(n).map(|f| f.into())
442            }
443
444            #[inline]
445            fn from_u8(n: u8) -> Option<Self> {
446                F::from_u8(n).map(|f| f.into())
447            }
448
449            #[inline]
450            fn from_u16(n: u16) -> Option<Self> {
451                F::from_u16(n).map(|f| f.into())
452            }
453
454            #[inline]
455            fn from_u32(n: u32) -> Option<Self> {
456                F::from_u32(n).map(|f| f.into())
457            }
458
459            #[inline]
460            fn from_u64(n: u64) -> Option<Self> {
461                F::from_u64(n).map(|f| f.into())
462            }
463
464            #[inline]
465            fn from_u128(n: u128) -> Option<Self> {
466                F::from_u128(n).map(|f| f.into())
467            }
468
469            #[inline]
470            fn from_f32(n: f32) -> Option<Self> {
471                F::from_f32(n).map(|f| f.into())
472            }
473
474            #[inline]
475            fn from_f64(n: f64) -> Option<Self> {
476                F::from_f64(n).map(|f| f.into())
477            }
478        }
479    };
480}
481
482#[macro_export]
483macro_rules! impl_signed {
484    ($struct:ident$(, [$($dim:tt),*]$(, [$($ddim:tt),*])*)?) => {
485        impl<T: DualNum<F>, F: DualNumFloat$($(, $dim: Dim)*)?> Signed for $struct<T, F$($(, $dim)*)?>
486        where
487            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
488        {
489            #[inline]
490            fn abs(&self) -> Self {
491                if self.is_positive() {
492                    self.clone()
493                } else {
494                    -self
495                }
496            }
497
498            #[inline]
499            fn abs_sub(&self, other: &Self) -> Self {
500                if self.re() > other.re() {
501                    self - other
502                } else {
503                    Self::zero()
504                }
505            }
506
507            #[inline]
508            fn signum(&self) -> Self {
509                if self.is_positive() {
510                    Self::one()
511                } else if self.is_zero() {
512                    Self::zero()
513                } else {
514                    -Self::one()
515                }
516            }
517
518            #[inline]
519            fn is_positive(&self) -> bool {
520                self.re.is_positive()
521            }
522
523            #[inline]
524            fn is_negative(&self) -> bool {
525                self.re.is_negative()
526            }
527        }
528    };
529}
530
531#[macro_export]
532macro_rules! impl_float_const {
533    ($struct:ident$(, [$($dim:tt),*]$(, [$($ddim:tt),*])*)?) => {
534        impl<T: DualNum<F>, F: Float + FloatConst$($(, $dim: Dim)*)?> FloatConst for $struct<T, F$($(, $dim)*)?>
535        where
536            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
537        {
538            fn E() -> Self {
539                Self::from(F::E())
540            }
541
542            fn FRAC_1_PI() -> Self {
543                Self::from(F::FRAC_1_PI())
544            }
545
546            fn FRAC_1_SQRT_2() -> Self {
547                Self::from(F::FRAC_1_SQRT_2())
548            }
549
550            fn FRAC_2_PI() -> Self {
551                Self::from(F::FRAC_2_PI())
552            }
553
554            fn FRAC_2_SQRT_PI() -> Self {
555                Self::from(F::FRAC_2_SQRT_PI())
556            }
557
558            fn FRAC_PI_2() -> Self {
559                Self::from(F::FRAC_PI_2())
560            }
561
562            fn FRAC_PI_3() -> Self {
563                Self::from(F::FRAC_PI_3())
564            }
565
566            fn FRAC_PI_4() -> Self {
567                Self::from(F::FRAC_PI_4())
568            }
569
570            fn FRAC_PI_6() -> Self {
571                Self::from(F::FRAC_PI_6())
572            }
573
574            fn FRAC_PI_8() -> Self {
575                Self::from(F::FRAC_PI_8())
576            }
577
578            fn LN_10() -> Self {
579                Self::from(F::LN_10())
580            }
581
582            fn LN_2() -> Self {
583                Self::from(F::LN_2())
584            }
585
586            fn LOG10_E() -> Self {
587                Self::from(F::LOG10_E())
588            }
589
590            fn LOG2_E() -> Self {
591                Self::from(F::LOG2_E())
592            }
593
594            fn PI() -> Self {
595                Self::from(F::PI())
596            }
597
598            fn SQRT_2() -> Self {
599                Self::from(F::SQRT_2())
600            }
601        }
602    };
603}
604
605#[macro_export]
606macro_rules! impl_num {
607    ($struct:ident$(, [$($dim:tt),*]$(, [$($ddim:tt),*])*)?) => {
608        impl<T: DualNum<F> + Signed, F: Float$($(, $dim: Dim)*)?> Num for $struct<T, F$($(, $dim)*)?>
609        where
610            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
611        {
612            type FromStrRadixErr = F::FromStrRadixErr;
613            #[inline]
614            fn from_str_radix(_str: &str, _radix: u32) -> Result<Self, Self::FromStrRadixErr> {
615                unimplemented!()
616            }
617        }
618    };
619}
620
621#[macro_export]
622macro_rules! impl_dual_struct {
623    ($struct:ident$(, [$($dim:tt),*]$(, [$($ddim:tt),*])*)?) => {
624        impl<T: DualNum<F>, F$($(, $dim: Dim)*)?> $crate::DualStruct<Self,F> for $struct<T, F$($(, $dim)*)?>
625        where
626            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
627        {
628            type Real = F;
629            type Inner = T;
630            #[inline]
631            fn re(&self) -> Self::Real {
632                self.re.re()
633            }
634            #[inline]
635            fn from_inner(inner: &Self::Inner) -> Self {
636                Self::from_re(inner.clone())
637            }
638        }
639
640        impl<T: DualNum<F>, F$($(, $dim: Dim)*)?> $crate::Mappable<Self> for $struct<T, F$($(, $dim)*)?>
641        where
642            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
643        {
644            type Output<O> = O;
645            #[inline]
646            fn map_dual<G: Fn(Self) -> O, O>(self, g: G) -> O {
647                g(self)
648            }
649        }
650    };
651}
652
653#[macro_export]
654macro_rules! impl_comparisons {
655    ($struct:ident$(, [$($dim:tt),*]$(, [$($ddim:tt),*])*)?) => {
656        /// Comparisons are only made based on the real part. This allows the code to follow the
657        /// same execution path as real-valued code would.
658        impl<T: DualNum<F>, F$($(, $dim: Dim)*)?> PartialEq for $struct<T, F$($(, $dim)*)?>
659        where
660            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
661        {
662            #[inline]
663            fn eq(&self, other: &Self) -> bool {
664                self.re.eq(&other.re)
665            }
666        }
667        impl<T: DualNum<F>, F$($(, $dim: Dim)*)?> PartialEq<F> for $struct<T, F$($(, $dim)*)?>
668        where
669            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
670        {
671            #[inline]
672            fn eq(&self, other: &F) -> bool {
673                self.re.eq(other)
674            }
675        }
676
677        /// Like PartialEq, comparisons are only made based on the real part. This allows the code to follow the
678        /// same execution path as real-valued code would.
679        impl<T: DualNum<F>, F$($(, $dim: Dim)*)?> PartialOrd for $struct<T, F$($(, $dim)*)?>
680        where
681            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
682        {
683            #[inline]
684            fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
685                self.re.partial_cmp(&other.re)
686            }
687        }
688        impl<T: DualNum<F>, F$($(, $dim: Dim)*)?> PartialOrd<F> for $struct<T, F$($(, $dim)*)?>
689        where
690            $($(DefaultAllocator: Allocator<$($ddim,)*>),*)?
691        {
692            #[inline]
693            fn partial_cmp(&self, other: &F) -> Option<std::cmp::Ordering> {
694                self.re.partial_cmp(other)
695            }
696        }
697    };
698}
699
700#[macro_export]
701macro_rules! impl_dual {
702    ($struct:ident, [$($im:ident),*]$(, [$($dim:tt),*]$(, [$($ddim:tt),*])*)?) => {
703        impl_from_f!($struct, [$($im),*]$(, [$($dim),*]$(, [$($ddim),*])*)?);
704        impl_zero_one!($struct$(, [$($dim),*]$(, [$($ddim),*])*)?);
705        impl_add_sub_rem!($struct, [$($im),*]$(, [$($dim),*]$(, [$($ddim),*])*)?);
706        forward_binop!($struct, Add, +, add$(, [$($dim),*]$(, [$($ddim),*])*)?);
707        forward_binop!($struct, Sub, -, sub$(, [$($dim),*]$(, [$($ddim),*])*)?);
708        forward_binop!($struct, Mul, *, mul$(, [$($dim),*]$(, [$($ddim),*])*)?);
709        forward_binop!($struct, Div, /, div$(, [$($dim),*]$(, [$($ddim),*])*)?);
710        forward_binop!($struct, Rem, %, rem$(, [$($dim),*]$(, [$($ddim),*])*)?);
711        impl_neg!($struct, [$($im),*]$(, [$($dim),*]$(, [$($ddim),*])*)?);
712        impl_assign_ops!($struct, [$($im),*]$(, [$($dim),*]$(, [$($ddim),*])*)?);
713        impl_scalar_op!($struct, [$($im),*]$(, [$($dim),*]$(, [$($ddim),*])*)?);
714        impl_inv!($struct$(, [$($dim),*]$(, [$($ddim),*])*)?);
715        impl_iterator!($struct$(, [$($dim),*]$(, [$($ddim),*])*)?);
716        impl_from_primitive!($struct$(, [$($dim),*]$(, [$($ddim),*])*)?);
717        impl_signed!($struct$(, [$($dim),*]$(, [$($ddim),*])*)?);
718        impl_num!($struct$(, [$($dim),*]$(, [$($ddim),*])*)?);
719        impl_float_const!($struct$(, [$($dim),*]$(, [$($ddim),*])*)?);
720        impl_dual_struct!($struct$(, [$($dim),*]$(, [$($ddim),*])*)?);
721        impl_comparisons!($struct$(, [$($dim),*]$(, [$($ddim),*])*)?);
722    };
723}