| |
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}; |
| |
13 use crate::euclidean::Euclidean; |
| |
14 use crate::instance::{Instance, InstanceMut, Decomposition, DecompositionMut, MyCow}; |
| |
15 use crate::mapping::Space; |
| |
16 use crate::linops::AXPY; |
| |
17 use crate::loc::Loc; |
| |
18 use crate::norms::{Norm, PairNorm, NormExponent, Normed, HasDual, L2}; |
| |
19 |
| |
20 #[derive(Debug,Clone,Copy,PartialEq,Eq,Serialize,Deserialize)] |
| |
21 pub struct Pair<A, B> (pub A, pub B); |
| |
22 |
| |
23 impl<A, B> Pair<A,B> { |
| |
24 pub fn new(a : A, b : B) -> Pair<A,B> { Pair(a, b) } |
| |
25 } |
| |
26 |
| |
27 impl<A, B> From<(A,B)> for Pair<A,B> { |
| |
28 #[inline] |
| |
29 fn from((a, b) : (A, B)) -> Pair<A,B> { Pair(a, b) } |
| |
30 } |
| |
31 |
| |
32 impl<A, B> From<Pair<A,B>> for (A,B) { |
| |
33 #[inline] |
| |
34 fn from(Pair(a, b) : Pair<A, B>) -> (A,B) { (a, b) } |
| |
35 } |
| |
36 |
| |
37 macro_rules! impl_binop { |
| |
38 (($a : ty, $b : ty), $trait : ident, $fn : ident, $refl:ident, $refr:ident) => { |
| |
39 impl_binop!(@doit: $a, $b, $trait, $fn; |
| |
40 maybe_lifetime!($refl, &'l Pair<$a,$b>), |
| |
41 (maybe_lifetime!($refl, &'l $a), |
| |
42 maybe_lifetime!($refl, &'l $b)); |
| |
43 maybe_lifetime!($refr, &'r Pair<Ai,Bi>), |
| |
44 (maybe_lifetime!($refr, &'r Ai), |
| |
45 maybe_lifetime!($refr, &'r Bi)); |
| |
46 $refl, $refr); |
| |
47 }; |
| |
48 |
| |
49 (@doit: $a:ty, $b:ty, |
| |
50 $trait:ident, $fn:ident; |
| |
51 $self:ty, ($aself:ty, $bself:ty); |
| |
52 $in:ty, ($ain:ty, $bin:ty); |
| |
53 $refl:ident, $refr:ident) => { |
| |
54 impl<'l, 'r, Ai, Bi> $trait<$in> |
| |
55 for $self |
| |
56 where $aself: $trait<$ain>, |
| |
57 $bself: $trait<$bin> { |
| |
58 type Output = Pair<<$aself as $trait<$ain>>::Output, |
| |
59 <$bself as $trait<$bin>>::Output>; |
| |
60 |
| |
61 #[inline] |
| |
62 fn $fn(self, y : $in) -> Self::Output { |
| |
63 Pair(maybe_ref!($refl, self.0).$fn(maybe_ref!($refr, y.0)), |
| |
64 maybe_ref!($refl, self.1).$fn(maybe_ref!($refr, y.1))) |
| |
65 } |
| |
66 } |
| |
67 }; |
| |
68 } |
| |
69 |
| |
70 macro_rules! impl_assignop { |
| |
71 (($a : ty, $b : ty), $trait : ident, $fn : ident, $refr:ident) => { |
| |
72 impl_assignop!(@doit: $a, $b, |
| |
73 $trait, $fn; |
| |
74 maybe_lifetime!($refr, &'r Pair<Ai,Bi>), |
| |
75 (maybe_lifetime!($refr, &'r Ai), |
| |
76 maybe_lifetime!($refr, &'r Bi)); |
| |
77 $refr); |
| |
78 }; |
| |
79 (@doit: $a : ty, $b : ty, |
| |
80 $trait:ident, $fn:ident; |
| |
81 $in:ty, ($ain:ty, $bin:ty); |
| |
82 $refr:ident) => { |
| |
83 impl<'r, Ai, Bi> $trait<$in> |
| |
84 for Pair<$a,$b> |
| |
85 where $a: $trait<$ain>, |
| |
86 $b: $trait<$bin> { |
| |
87 #[inline] |
| |
88 fn $fn(&mut self, y : $in) -> () { |
| |
89 self.0.$fn(maybe_ref!($refr, y.0)); |
| |
90 self.1.$fn(maybe_ref!($refr, y.1)); |
| |
91 } |
| |
92 } |
| |
93 } |
| |
94 } |
| |
95 |
| |
96 macro_rules! impl_scalarop { |
| |
97 (($a : ty, $b : ty), $field : ty, $trait : ident, $fn : ident, $refl:ident) => { |
| |
98 impl_scalarop!(@doit: $field, |
| |
99 $trait, $fn; |
| |
100 maybe_lifetime!($refl, &'l Pair<$a,$b>), |
| |
101 (maybe_lifetime!($refl, &'l $a), |
| |
102 maybe_lifetime!($refl, &'l $b)); |
| |
103 $refl); |
| |
104 }; |
| |
105 (@doit: $field : ty, |
| |
106 $trait:ident, $fn:ident; |
| |
107 $self:ty, ($aself:ty, $bself:ty); |
| |
108 $refl:ident) => { |
| |
109 // Scalar as Rhs |
| |
110 impl<'l> $trait<$field> |
| |
111 for $self |
| |
112 where $aself: $trait<$field>, |
| |
113 $bself: $trait<$field> { |
| |
114 type Output = Pair<<$aself as $trait<$field>>::Output, |
| |
115 <$bself as $trait<$field>>::Output>; |
| |
116 #[inline] |
| |
117 fn $fn(self, a : $field) -> Self::Output { |
| |
118 Pair(maybe_ref!($refl, self.0).$fn(a), |
| |
119 maybe_ref!($refl, self.1).$fn(a)) |
| |
120 } |
| |
121 } |
| |
122 } |
| |
123 } |
| |
124 |
| |
125 // Not used due to compiler overflow |
| |
126 #[allow(unused_macros)] |
| |
127 macro_rules! impl_scalarlhs_op { |
| |
128 (($a : ty, $b : ty), $field : ty, $trait:ident, $fn:ident, $refr:ident) => { |
| |
129 impl_scalarlhs_op!(@doit: $trait, $fn, |
| |
130 maybe_lifetime!($refr, &'r Pair<$a,$b>), |
| |
131 (maybe_lifetime!($refr, &'r $a), |
| |
132 maybe_lifetime!($refr, &'r $b)); |
| |
133 $refr, $field); |
| |
134 }; |
| |
135 (@doit: $trait:ident, $fn:ident, |
| |
136 $in:ty, ($ain:ty, $bin:ty); |
| |
137 $refr:ident, $field:ty) => { |
| |
138 impl<'r> $trait<$in> |
| |
139 for $field |
| |
140 where $field : $trait<$ain> |
| |
141 + $trait<$bin> { |
| |
142 type Output = Pair<<$field as $trait<$ain>>::Output, |
| |
143 <$field as $trait<$bin>>::Output>; |
| |
144 #[inline] |
| |
145 fn $fn(self, x : $in) -> Self::Output { |
| |
146 Pair(self.$fn(maybe_ref!($refr, x.0)), |
| |
147 self.$fn(maybe_ref!($refr, x.1))) |
| |
148 } |
| |
149 } |
| |
150 }; |
| |
151 } |
| |
152 |
| |
153 macro_rules! impl_scalar_assignop { |
| |
154 (($a : ty, $b : ty), $field : ty, $trait : ident, $fn : ident) => { |
| |
155 impl<'r> $trait<$field> |
| |
156 for Pair<$a, $b> |
| |
157 where $a: $trait<$field>, $b: $trait<$field> { |
| |
158 #[inline] |
| |
159 fn $fn(&mut self, a : $field) -> () { |
| |
160 self.0.$fn(a); |
| |
161 self.1.$fn(a); |
| |
162 } |
| |
163 } |
| |
164 } |
| |
165 } |
| |
166 |
| |
167 macro_rules! impl_unaryop { |
| |
168 (($a : ty, $b : ty), $trait:ident, $fn:ident, $refl:ident) => { |
| |
169 impl_unaryop!(@doit: $trait, $fn; |
| |
170 maybe_lifetime!($refl, &'l Pair<$a,$b>), |
| |
171 (maybe_lifetime!($refl, &'l $a), |
| |
172 maybe_lifetime!($refl, &'l $b)); |
| |
173 $refl); |
| |
174 }; |
| |
175 (@doit: $trait:ident, $fn:ident; |
| |
176 $self:ty, ($aself:ty, $bself:ty); |
| |
177 $refl : ident) => { |
| |
178 impl<'l> $trait |
| |
179 for $self |
| |
180 where $aself: $trait, |
| |
181 $bself: $trait { |
| |
182 type Output = Pair<<$aself as $trait>::Output, |
| |
183 <$bself as $trait>::Output>; |
| |
184 #[inline] |
| |
185 fn $fn(self) -> Self::Output { |
| |
186 Pair(maybe_ref!($refl, self.0).$fn(), |
| |
187 maybe_ref!($refl, self.1).$fn()) |
| |
188 } |
| |
189 } |
| |
190 } |
| |
191 } |
| |
192 |
| |
193 #[macro_export] |
| |
194 macro_rules! impl_pair_vectorspace_ops { |
| |
195 (($a:ty, $b:ty), $field:ty) => { |
| |
196 impl_pair_vectorspace_ops!(@binary, ($a, $b), Add, add); |
| |
197 impl_pair_vectorspace_ops!(@binary, ($a, $b), Sub, sub); |
| |
198 impl_pair_vectorspace_ops!(@assign, ($a, $b), AddAssign, add_assign); |
| |
199 impl_pair_vectorspace_ops!(@assign, ($a, $b), SubAssign, sub_assign); |
| |
200 impl_pair_vectorspace_ops!(@scalar, ($a, $b), $field, Mul, mul); |
| |
201 impl_pair_vectorspace_ops!(@scalar, ($a, $b), $field, Div, div); |
| |
202 // Compiler overflow |
| |
203 // $( |
| |
204 // impl_pair_vectorspace_ops!(@scalar_lhs, ($a, $b), $field, $impl_scalarlhs_op, Mul, mul); |
| |
205 // )* |
| |
206 impl_pair_vectorspace_ops!(@scalar_assign, ($a, $b), $field, MulAssign, mul_assign); |
| |
207 impl_pair_vectorspace_ops!(@scalar_assign, ($a, $b), $field, DivAssign, div_assign); |
| |
208 impl_pair_vectorspace_ops!(@unary, ($a, $b), Neg, neg); |
| |
209 }; |
| |
210 (@binary, ($a : ty, $b : ty), $trait : ident, $fn : ident) => { |
| |
211 impl_binop!(($a, $b), $trait, $fn, ref, ref); |
| |
212 impl_binop!(($a, $b), $trait, $fn, ref, noref); |
| |
213 impl_binop!(($a, $b), $trait, $fn, noref, ref); |
| |
214 impl_binop!(($a, $b), $trait, $fn, noref, noref); |
| |
215 }; |
| |
216 (@assign, ($a : ty, $b : ty), $trait : ident, $fn :ident) => { |
| |
217 impl_assignop!(($a, $b), $trait, $fn, ref); |
| |
218 impl_assignop!(($a, $b), $trait, $fn, noref); |
| |
219 }; |
| |
220 (@scalar, ($a : ty, $b : ty), $field : ty, $trait : ident, $fn :ident) => { |
| |
221 impl_scalarop!(($a, $b), $field, $trait, $fn, ref); |
| |
222 impl_scalarop!(($a, $b), $field, $trait, $fn, noref); |
| |
223 }; |
| |
224 (@scalar_lhs, ($a : ty, $b : ty), $field : ty, $trait : ident, $fn : ident) => { |
| |
225 impl_scalarlhs_op!(($a, $b), $field, $trait, $fn, ref); |
| |
226 impl_scalarlhs_op!(($a, $b), $field, $trait, $fn, noref); |
| |
227 }; |
| |
228 (@scalar_assign, ($a : ty, $b : ty), $field : ty, $trait : ident, $fn : ident) => { |
| |
229 impl_scalar_assignop!(($a, $b), $field, $trait, $fn); |
| |
230 }; |
| |
231 (@unary, ($a : ty, $b : ty), $trait : ident, $fn : ident) => { |
| |
232 impl_unaryop!(($a, $b), $trait, $fn, ref); |
| |
233 impl_unaryop!(($a, $b), $trait, $fn, noref); |
| |
234 }; |
| |
235 } |
| |
236 |
| |
237 impl_pair_vectorspace_ops!((f32, f32), f32); |
| |
238 impl_pair_vectorspace_ops!((f64, f64), f64); |
| |
239 |
| |
240 type PairOutput<F, A, B> = Pair<<A as Euclidean<F>>::Output, <B as Euclidean<F>>::Output>; |
| |
241 |
| |
242 impl<A, B, F> Euclidean<F> for Pair<A, B> |
| |
243 where |
| |
244 A : Euclidean<F>, |
| |
245 B : Euclidean<F>, |
| |
246 F : Float, |
| |
247 PairOutput<F, A, B> : Euclidean<F>, |
| |
248 Self : Sized |
| |
249 + Mul<F, Output=PairOutput<F, A, B>> + MulAssign<F> |
| |
250 + Div<F, Output=PairOutput<F, A, B>> + DivAssign<F> |
| |
251 + Add<Self, Output=PairOutput<F, A, B>> |
| |
252 + Sub<Self, Output=PairOutput<F, A, B>> |
| |
253 + for<'b> Add<&'b Self, Output=PairOutput<F, A, B>> |
| |
254 + for<'b> Sub<&'b Self, Output=PairOutput<F, A, B>> |
| |
255 + AddAssign<Self> + for<'b> AddAssign<&'b Self> |
| |
256 + SubAssign<Self> + for<'b> SubAssign<&'b Self> |
| |
257 + Neg<Output=PairOutput<F, A, B>> |
| |
258 { |
| |
259 type Output = PairOutput<F, A, B>; |
| |
260 |
| |
261 fn dot<I : Instance<Self>>(&self, other : I) -> F { |
| |
262 let Pair(u, v) = other.decompose(); |
| |
263 self.0.dot(u) + self.1.dot(v) |
| |
264 } |
| |
265 |
| |
266 fn norm2_squared(&self) -> F { |
| |
267 self.0.norm2_squared() + self.1.norm2_squared() |
| |
268 } |
| |
269 |
| |
270 fn dist2_squared<I : Instance<Self>>(&self, other : I) -> F { |
| |
271 let Pair(u, v) = other.decompose(); |
| |
272 self.0.dist2_squared(u) + self.1.dist2_squared(v) |
| |
273 } |
| |
274 } |
| |
275 |
| |
276 impl<F, A, B, U, V> AXPY<F, Pair<U, V>> for Pair<A, B> |
| |
277 where |
| |
278 U : Space, |
| |
279 V : Space, |
| |
280 A : AXPY<F, U>, |
| |
281 B : AXPY<F, V>, |
| |
282 F : Num, |
| |
283 Self : MulAssign<F>, |
| |
284 Pair<A, B> : MulAssign<F>, |
| |
285 Pair<A::Owned, B::Owned> : AXPY<F, Pair<U, V>>, |
| |
286 { |
| |
287 |
| |
288 type Owned = Pair<A::Owned, B::Owned>; |
| |
289 |
| |
290 fn axpy<I : Instance<Pair<U,V>>>(&mut self, α : F, x : I, β : F) { |
| |
291 let Pair(u, v) = x.decompose(); |
| |
292 self.0.axpy(α, u, β); |
| |
293 self.1.axpy(α, v, β); |
| |
294 } |
| |
295 |
| |
296 fn copy_from<I : Instance<Pair<U,V>>>(&mut self, x : I) { |
| |
297 let Pair(u, v) = x.decompose(); |
| |
298 self.0.copy_from(u); |
| |
299 self.1.copy_from(v); |
| |
300 } |
| |
301 |
| |
302 fn scale_from<I : Instance<Pair<U,V>>>(&mut self, α : F, x : I) { |
| |
303 let Pair(u, v) = x.decompose(); |
| |
304 self.0.scale_from(α, u); |
| |
305 self.1.scale_from(α, v); |
| |
306 } |
| |
307 |
| |
308 /// Return a similar zero as `self`. |
| |
309 fn similar_origin(&self) -> Self::Owned { |
| |
310 Pair(self.0.similar_origin(), self.1.similar_origin()) |
| |
311 } |
| |
312 |
| |
313 /// Set self to zero. |
| |
314 fn set_zero(&mut self) { |
| |
315 self.0.set_zero(); |
| |
316 self.1.set_zero(); |
| |
317 } |
| |
318 } |
| |
319 |
| |
320 /// [`Decomposition`] for working with [`Pair`]s. |
| |
321 #[derive(Copy, Clone, Debug)] |
| |
322 pub struct PairDecomposition<D, Q>(D, Q); |
| |
323 |
| |
324 impl<A : Space, B : Space> Space for Pair<A, B> { |
| |
325 type Decomp = PairDecomposition<A::Decomp, B::Decomp>; |
| |
326 } |
| |
327 |
| |
328 impl<A, B, D, Q> Decomposition<Pair<A, B>> for PairDecomposition<D,Q> |
| |
329 where |
| |
330 A : Space, |
| |
331 B : Space, |
| |
332 D : Decomposition<A>, |
| |
333 Q : Decomposition<B>, |
| |
334 { |
| |
335 type Decomposition<'b> = Pair<D::Decomposition<'b>, Q::Decomposition<'b>> where Pair<A, B> : 'b; |
| |
336 type Reference<'b> = Pair<D::Reference<'b>, Q::Reference<'b>> where Pair<A, B> : 'b; |
| |
337 |
| |
338 #[inline] |
| |
339 fn lift<'b>(Pair(u, v) : Self::Reference<'b>) -> Self::Decomposition<'b> { |
| |
340 Pair(D::lift(u), Q::lift(v)) |
| |
341 } |
| |
342 } |
| |
343 |
| |
344 impl<A, B, U, V, D, Q> Instance<Pair<A, B>, PairDecomposition<D, Q>> for Pair<U, V> |
| |
345 where |
| |
346 A : Space, |
| |
347 B : Space, |
| |
348 D : Decomposition<A>, |
| |
349 Q : Decomposition<B>, |
| |
350 U : Instance<A, D>, |
| |
351 V : Instance<B, Q>, |
| |
352 { |
| |
353 #[inline] |
| |
354 fn decompose<'b>(self) |
| |
355 -> <PairDecomposition<D, Q> as Decomposition<Pair<A, B>>>::Decomposition<'b> |
| |
356 where Self : 'b, Pair<A, B> : 'b |
| |
357 { |
| |
358 Pair(self.0.decompose(), self.1.decompose()) |
| |
359 } |
| |
360 |
| |
361 #[inline] |
| |
362 fn ref_instance(&self) |
| |
363 -> <PairDecomposition<D, Q> as Decomposition<Pair<A, B>>>::Reference<'_> |
| |
364 { |
| |
365 Pair(self.0.ref_instance(), self.1.ref_instance()) |
| |
366 } |
| |
367 |
| |
368 #[inline] |
| |
369 fn cow<'b>(self) -> MyCow<'b, Pair<A, B>> where Self : 'b{ |
| |
370 MyCow::Owned(Pair(self.0.own(), self.1.own())) |
| |
371 } |
| |
372 |
| |
373 #[inline] |
| |
374 fn own(self) -> Pair<A, B> { |
| |
375 Pair(self.0.own(), self.1.own()) |
| |
376 } |
| |
377 } |
| |
378 |
| |
379 |
| |
380 impl<'a, A, B, U, V, D, Q> Instance<Pair<A, B>, PairDecomposition<D, Q>> for &'a Pair<U, V> |
| |
381 where |
| |
382 A : Space, |
| |
383 B : Space, |
| |
384 D : Decomposition<A>, |
| |
385 Q : Decomposition<B>, |
| |
386 U : Instance<A, D>, |
| |
387 V : Instance<B, Q>, |
| |
388 &'a U : Instance<A, D>, |
| |
389 &'a V : Instance<B, Q>, |
| |
390 { |
| |
391 #[inline] |
| |
392 fn decompose<'b>(self) |
| |
393 -> <PairDecomposition<D, Q> as Decomposition<Pair<A, B>>>::Decomposition<'b> |
| |
394 where Self : 'b, Pair<A, B> : 'b |
| |
395 { |
| |
396 Pair(D::lift(self.0.ref_instance()), Q::lift(self.1.ref_instance())) |
| |
397 } |
| |
398 |
| |
399 #[inline] |
| |
400 fn ref_instance(&self) |
| |
401 -> <PairDecomposition<D, Q> as Decomposition<Pair<A, B>>>::Reference<'_> |
| |
402 { |
| |
403 Pair(self.0.ref_instance(), self.1.ref_instance()) |
| |
404 } |
| |
405 |
| |
406 #[inline] |
| |
407 fn cow<'b>(self) -> MyCow<'b, Pair<A, B>> where Self : 'b { |
| |
408 MyCow::Owned(self.own()) |
| |
409 } |
| |
410 |
| |
411 #[inline] |
| |
412 fn own(self) -> Pair<A, B> { |
| |
413 let Pair(ref u, ref v) = self; |
| |
414 Pair(u.own(), v.own()) |
| |
415 } |
| |
416 |
| |
417 } |
| |
418 |
| |
419 impl<A, B, D, Q> DecompositionMut<Pair<A, B>> for PairDecomposition<D,Q> |
| |
420 where |
| |
421 A : Space, |
| |
422 B : Space, |
| |
423 D : DecompositionMut<A>, |
| |
424 Q : DecompositionMut<B>, |
| |
425 { |
| |
426 type ReferenceMut<'b> = Pair<D::ReferenceMut<'b>, Q::ReferenceMut<'b>> where Pair<A, B> : 'b; |
| |
427 } |
| |
428 |
| |
429 impl<A, B, U, V, D, Q> InstanceMut<Pair<A, B>, PairDecomposition<D, Q>> for Pair<U, V> |
| |
430 where |
| |
431 A : Space, |
| |
432 B : Space, |
| |
433 D : DecompositionMut<A>, |
| |
434 Q : DecompositionMut<B>, |
| |
435 U : InstanceMut<A, D>, |
| |
436 V : InstanceMut<B, Q>, |
| |
437 { |
| |
438 #[inline] |
| |
439 fn ref_instance_mut(&mut self) |
| |
440 -> <PairDecomposition<D, Q> as DecompositionMut<Pair<A, B>>>::ReferenceMut<'_> |
| |
441 { |
| |
442 Pair(self.0.ref_instance_mut(), self.1.ref_instance_mut()) |
| |
443 } |
| |
444 } |
| |
445 |
| |
446 impl<'a, A, B, U, V, D, Q> InstanceMut<Pair<A, B>, PairDecomposition<D, Q>> for &'a mut Pair<U, V> |
| |
447 where |
| |
448 A : Space, |
| |
449 B : Space, |
| |
450 D : DecompositionMut<A>, |
| |
451 Q : DecompositionMut<B>, |
| |
452 U : InstanceMut<A, D>, |
| |
453 V : InstanceMut<B, Q>, |
| |
454 { |
| |
455 #[inline] |
| |
456 fn ref_instance_mut(&mut self) |
| |
457 -> <PairDecomposition<D, Q> as DecompositionMut<Pair<A, B>>>::ReferenceMut<'_> |
| |
458 { |
| |
459 Pair(self.0.ref_instance_mut(), self.1.ref_instance_mut()) |
| |
460 } |
| |
461 } |
| |
462 |
| |
463 |
| |
464 impl<F, A, B, ExpA, ExpB, ExpJ> Norm<F, PairNorm<ExpA, ExpB, ExpJ>> |
| |
465 for Pair<A,B> |
| |
466 where |
| |
467 F : Num, |
| |
468 ExpA : NormExponent, |
| |
469 ExpB : NormExponent, |
| |
470 ExpJ : NormExponent, |
| |
471 A : Norm<F, ExpA>, |
| |
472 B : Norm<F, ExpB>, |
| |
473 Loc<F, 2> : Norm<F, ExpJ>, |
| |
474 { |
| |
475 fn norm(&self, PairNorm(expa, expb, expj) : PairNorm<ExpA, ExpB, ExpJ>) -> F { |
| |
476 Loc([self.0.norm(expa), self.1.norm(expb)]).norm(expj) |
| |
477 } |
| |
478 } |
| |
479 |
| |
480 |
| |
481 impl<F : Float, A, B> Normed<F> for Pair<A,B> |
| |
482 where |
| |
483 A : Normed<F>, |
| |
484 B : Normed<F>, |
| |
485 { |
| |
486 type NormExp = PairNorm<A::NormExp, B::NormExp, L2>; |
| |
487 |
| |
488 #[inline] |
| |
489 fn norm_exponent(&self) -> Self::NormExp { |
| |
490 PairNorm(self.0.norm_exponent(), self.1.norm_exponent(), L2) |
| |
491 } |
| |
492 |
| |
493 #[inline] |
| |
494 fn is_zero(&self) -> bool { |
| |
495 self.0.is_zero() && self.1.is_zero() |
| |
496 } |
| |
497 } |
| |
498 |
| |
499 impl<F : Float, A, B> HasDual<F> for Pair<A,B> |
| |
500 where |
| |
501 A : HasDual<F>, |
| |
502 B : HasDual<F>, |
| |
503 |
| |
504 { |
| |
505 type DualSpace = Pair<A::DualSpace, B::DualSpace>; |
| |
506 } |