| |
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 } |