|
1 /*! |
|
2 Direct products of the form $A \times B$. |
|
3 |
|
4 TODO: This could be easily much more generic if `derive_more` could derive arithmetic |
|
5 operations on references. |
|
6 */ |
|
7 |
|
8 use core::ops::{Mul,MulAssign,Div,DivAssign,Add,AddAssign,Sub,SubAssign,Neg}; |
|
9 use std::clone::Clone; |
|
10 use serde::{Serialize, Deserialize}; |
|
11 use crate::types::{Num, Float}; |
|
12 use crate::{maybe_lifetime, maybe_ref, impl_vectorspace_ops}; |
|
13 use crate::euclidean::{Dot, Euclidean}; |
|
14 |
|
15 #[derive(Debug,Clone,PartialEq,Eq,Serialize,Deserialize)] |
|
16 pub struct Pair<A, B> (pub A, pub B); |
|
17 |
|
18 impl<A, B> Pair<A,B> { |
|
19 pub fn new(a : A, b : B) -> Pair<A,B> { Pair{ 0 : a, 1 : b } } |
|
20 } |
|
21 |
|
22 impl<A, B> From<(A,B)> for Pair<A,B> { |
|
23 #[inline] |
|
24 fn from((a, b) : (A, B)) -> Pair<A,B> { Pair{ 0 : a, 1 : b } } |
|
25 } |
|
26 |
|
27 macro_rules! impl_binop { |
|
28 ($trait : ident, $fn : ident, $refl:ident, $refr:ident) => { |
|
29 impl_binop!(@doit: $trait, $fn; |
|
30 maybe_lifetime!($refl, &'l Pair<A,B>), |
|
31 (maybe_lifetime!($refl, &'l A), maybe_lifetime!($refl, &'l B)); |
|
32 maybe_lifetime!($refr, &'r Pair<Ai,Bi>), |
|
33 (maybe_lifetime!($refr, &'r Ai), maybe_lifetime!($refr, &'r Bi)); |
|
34 $refl, $refr); |
|
35 }; |
|
36 |
|
37 (@doit: $trait:ident, $fn:ident; |
|
38 $self:ty, ($aself:ty, $bself:ty); |
|
39 $in:ty, ($ain:ty, $bin:ty); |
|
40 $refl:ident, $refr:ident) => { |
|
41 impl<'l, 'r, A, B, Ai, Bi> $trait<$in> |
|
42 for $self |
|
43 where $aself: $trait<$ain>, |
|
44 $bself: $trait<$bin> { |
|
45 type Output = Pair<<$aself as $trait<$ain>>::Output, |
|
46 <$bself as $trait<$bin>>::Output>; |
|
47 |
|
48 #[inline] |
|
49 fn $fn(self, y : $in) -> Self::Output { |
|
50 Pair { 0 : maybe_ref!($refl, self.0).$fn(maybe_ref!($refr, y.0)), |
|
51 1 : maybe_ref!($refl, self.1).$fn(maybe_ref!($refr, y.1)) } |
|
52 } |
|
53 } |
|
54 }; |
|
55 } |
|
56 |
|
57 macro_rules! impl_assignop { |
|
58 ($trait : ident, $fn : ident, $refr:ident) => { |
|
59 impl_assignop!(@doit: $trait, $fn; |
|
60 maybe_lifetime!($refr, &'r Pair<Ai,Bi>), |
|
61 (maybe_lifetime!($refr, &'r Ai), maybe_lifetime!($refr, &'r Bi)); |
|
62 $refr); |
|
63 }; |
|
64 (@doit: $trait:ident, $fn:ident; |
|
65 $in:ty, ($ain:ty, $bin:ty); |
|
66 $refr:ident) => { |
|
67 impl<'r, A, B, Ai, Bi> $trait<$in> |
|
68 for Pair<A,B> |
|
69 where A: $trait<$ain>, |
|
70 B: $trait<$bin> { |
|
71 #[inline] |
|
72 fn $fn(&mut self, y : $in) -> () { |
|
73 self.0.$fn(maybe_ref!($refr, y.0)); |
|
74 self.1.$fn(maybe_ref!($refr, y.1)); |
|
75 } |
|
76 } |
|
77 } |
|
78 } |
|
79 |
|
80 macro_rules! impl_scalarop { |
|
81 ($trait : ident, $fn : ident, $refl:ident) => { |
|
82 impl_scalarop!(@doit: $trait, $fn; |
|
83 maybe_lifetime!($refl, &'l Pair<A,B>), |
|
84 (maybe_lifetime!($refl, &'l A), maybe_lifetime!($refl, &'l B)); |
|
85 $refl); |
|
86 }; |
|
87 (@doit: $trait:ident, $fn:ident; |
|
88 $self:ty, ($aself:ty, $bself:ty); |
|
89 $refl:ident) => { |
|
90 // Scalar as Rhs |
|
91 impl<'l, F : Num, A, B> $trait<F> |
|
92 for $self |
|
93 where $aself: $trait<F>, |
|
94 $bself: $trait<F> { |
|
95 type Output = Pair<<$aself as $trait<F>>::Output, |
|
96 <$bself as $trait<F>>::Output>; |
|
97 #[inline] |
|
98 fn $fn(self, a : F) -> Self::Output { |
|
99 Pair{ 0 : maybe_ref!($refl, self.0).$fn(a), |
|
100 1 : maybe_ref!($refl, self.1).$fn(a)} |
|
101 } |
|
102 } |
|
103 } |
|
104 } |
|
105 |
|
106 // Not used due to compiler overflow |
|
107 #[allow(unused_macros)] |
|
108 macro_rules! impl_scalarlhs_op { |
|
109 ($trait:ident, $fn:ident, $refr:ident, $field:ty) => { |
|
110 impl_scalarlhs_op!(@doit: $trait, $fn, |
|
111 maybe_lifetime!($refr, &'r Pair<Ai,Bi>), |
|
112 (maybe_lifetime!($refr, &'r Ai), maybe_lifetime!($refr, &'r Bi)); |
|
113 $refr, $field); |
|
114 }; |
|
115 (@doit: $trait:ident, $fn:ident, |
|
116 $in:ty, ($ain:ty, $bin:ty); |
|
117 $refr:ident, $field:ty) => { |
|
118 impl<'r, Ai, Bi> $trait<$in> |
|
119 for $field |
|
120 where $field : $trait<$ain> |
|
121 + $trait<$bin> { |
|
122 type Output = Pair<<$field as $trait<$ain>>::Output, |
|
123 <$field as $trait<$bin>>::Output>; |
|
124 #[inline] |
|
125 fn $fn(self, x : $in) -> Self::Output { |
|
126 Pair{ 0 : self.$fn(maybe_ref!($refr, x.0)), |
|
127 1 : self.$fn(maybe_ref!($refr, x.1))} |
|
128 } |
|
129 } |
|
130 }; |
|
131 } |
|
132 |
|
133 macro_rules! impl_scalar_assignop { |
|
134 ($trait : ident, $fn : ident) => { |
|
135 impl<'r, F : Num, A, B> $trait<F> |
|
136 for Pair<A,B> |
|
137 where A: $trait<F>, B: $trait<F> { |
|
138 #[inline] |
|
139 fn $fn(&mut self, a : F) -> () { |
|
140 self.0.$fn(a); |
|
141 self.1.$fn(a); |
|
142 } |
|
143 } |
|
144 } |
|
145 } |
|
146 |
|
147 macro_rules! impl_unaryop { |
|
148 ($trait:ident, $fn:ident, $refl:ident) => { |
|
149 impl_unaryop!(@doit: $trait, $fn; |
|
150 maybe_lifetime!($refl, &'l Pair<A,B>), |
|
151 (maybe_lifetime!($refl, &'l A), maybe_lifetime!($refl, &'l B)); |
|
152 $refl); |
|
153 }; |
|
154 (@doit: $trait:ident, $fn:ident; |
|
155 $self:ty, ($aself:ty, $bself:ty); |
|
156 $refl : ident) => { |
|
157 impl<'l, A, B> $trait |
|
158 for $self |
|
159 where $aself: $trait, |
|
160 $bself: $trait { |
|
161 type Output = Pair<<$aself as $trait>::Output, |
|
162 <$bself as $trait>::Output>; |
|
163 #[inline] |
|
164 fn $fn(self) -> Self::Output { |
|
165 Pair{ 0 : maybe_ref!($refl, self.0).$fn(), |
|
166 1 : maybe_ref!($refl, self.1).$fn()} |
|
167 } |
|
168 } |
|
169 } |
|
170 } |
|
171 |
|
172 |
|
173 impl_vectorspace_ops!(impl_binop, impl_assignop, impl_scalarop, impl_scalarlhs_op, |
|
174 impl_scalar_assignop, impl_unaryop); |
|
175 |
|
176 |
|
177 impl<A, B, U, V, F> Dot<Pair<U, V>, F> for Pair<A, B> |
|
178 where |
|
179 A : Dot<U, F>, |
|
180 B : Dot<V, F>, |
|
181 F : Num |
|
182 { |
|
183 |
|
184 fn dot(&self, Pair(ref u, ref v) : &Pair<U, V>) -> F { |
|
185 self.0.dot(u) + self.1.dot(v) |
|
186 } |
|
187 } |
|
188 |
|
189 impl<A, B, F> Euclidean<F> for Pair<A, B> |
|
190 where |
|
191 A : Euclidean<F>, |
|
192 B : Euclidean<F>, |
|
193 F : Float |
|
194 { |
|
195 type Output = Pair<<A as Euclidean<F>>::Output, <B as Euclidean<F>>::Output>; |
|
196 |
|
197 fn similar_origin(&self) -> <Self as Euclidean<F>>::Output { |
|
198 Pair(self.0.similar_origin(), self.1.similar_origin()) |
|
199 } |
|
200 |
|
201 fn dist2_squared(&self, Pair(ref u, ref v) : &Self) -> F { |
|
202 self.0.dist2_squared(u) + self.1.dist2_squared(v) |
|
203 } |
|
204 } |
|
205 |
|
206 use crate::linops::AXPY; |
|
207 |
|
208 impl<F, A, B, U, V> AXPY<F, Pair<U, V>> for Pair<A, B> |
|
209 where |
|
210 A : AXPY<F, U>, |
|
211 B : AXPY<F, V>, |
|
212 F : Num |
|
213 { |
|
214 fn axpy(&mut self, α : F, x : &Pair<U, V>, β : F) { |
|
215 self.0.axpy(α, &x.0, β); |
|
216 self.1.axpy(α, &x.1, β); |
|
217 } |
|
218 |
|
219 fn copy_from(&mut self, x : &Pair<U, V>,) { |
|
220 self.0.copy_from(&x.0); |
|
221 self.1.copy_from(&x.1); |
|
222 } |
|
223 |
|
224 fn scale_from(&mut self, α : F, x : &Pair<U, V>) { |
|
225 self.0.scale_from(α, &x.0); |
|
226 self.1.scale_from(α, &x.1); |
|
227 } |
|
228 } |