src/convex.rs

changeset 198
3868555d135c
parent 168
93daa824c04a
equal deleted inserted replaced
94:1f19c6bbf07b 198:3868555d135c
1 /*! 1 /*!
2 Some convex analysis basics 2 Some convex analysis basics
3 */ 3 */
4 4
5 use crate::error::DynResult;
6 use crate::euclidean::Euclidean;
7 use crate::instance::{ClosedSpace, DecompositionMut, Instance};
8 use crate::linops::{IdOp, Scaled, SimpleZeroOp, AXPY};
9 use crate::mapping::{DifferentiableImpl, LipschitzDifferentiableImpl, Mapping, Space};
10 use crate::norms::*;
11 use crate::operator_arithmetic::{Constant, Weighted};
12 use crate::types::*;
13 use serde::{Deserialize, Serialize};
5 use std::marker::PhantomData; 14 use std::marker::PhantomData;
6 use crate::types::*;
7 use crate::mapping::{Mapping, Space};
8 use crate::linops::IdOp;
9 use crate::instance::{Instance, InstanceMut, DecompositionMut};
10 use crate::operator_arithmetic::{Constant, Weighted};
11 use crate::norms::*;
12 15
13 /// Trait for convex mappings. Has no features, just serves as a constraint 16 /// Trait for convex mappings. Has no features, just serves as a constraint
14 /// 17 ///
15 /// TODO: should constrain `Mapping::Codomain` to implement a partial order, 18 /// TODO: should constrain `Mapping::Codomain` to implement a partial order,
16 /// but this makes everything complicated with little benefit. 19 /// but this makes everything complicated with little benefit.
17 pub trait ConvexMapping<Domain : Space, F : Num = f64> : Mapping<Domain, Codomain = F> 20 pub trait ConvexMapping<Domain: Space, F: Num = f64>: Mapping<Domain, Codomain = F> {
18 {} 21 /// Returns (a lower estimate of) the factor of strong convexity in the norm of `Domain`.
22 fn factor_of_strong_convexity(&self) -> F {
23 F::ZERO
24 }
25 }
19 26
20 /// Trait for mappings with a Fenchel conjugate 27 /// Trait for mappings with a Fenchel conjugate
21 /// 28 ///
22 /// The conjugate type has to implement [`ConvexMapping`], but a `Conjugable` mapping need 29 /// The conjugate type has to implement [`ConvexMapping`], but a `Conjugable` mapping need
23 /// not be convex. 30 /// not be convex.
24 pub trait Conjugable<Domain : HasDual<F>, F : Num = f64> : Mapping<Domain> { 31 pub trait Conjugable<Domain: HasDual<F>, F: Num = f64>: Mapping<Domain, Codomain = F> {
25 type Conjugate<'a> : ConvexMapping<Domain::DualSpace, F> where Self : 'a; 32 type Conjugate<'a>: ConvexMapping<Domain::DualSpace, F>
33 where
34 Self: 'a;
26 35
27 fn conjugate(&self) -> Self::Conjugate<'_>; 36 fn conjugate(&self) -> Self::Conjugate<'_>;
28 } 37 }
29 38
30 /// Trait for mappings with a Fenchel preconjugate 39 /// Trait for mappings with a Fenchel preconjugate
31 /// 40 ///
32 /// In contrast to [`Conjugable`], the preconjugate need not implement [`ConvexMapping`], 41 /// In contrast to [`Conjugable`], the preconjugate need not implement [`ConvexMapping`],
33 /// but a `Preconjugable` mapping has to be convex. 42 /// but a `Preconjugable` mapping has to be convex.
34 pub trait Preconjugable<Domain, Predual, F : Num = f64> : ConvexMapping<Domain, F> 43 pub trait Preconjugable<Domain, Predual, F: Num = f64>: ConvexMapping<Domain, F>
35 where 44 where
36 Domain : Space, 45 Domain: Space,
37 Predual : HasDual<F> 46 Predual: HasDual<F>,
38 { 47 {
39 type Preconjugate<'a> : Mapping<Predual> where Self : 'a; 48 type Preconjugate<'a>: Mapping<Predual, Codomain = F>
49 where
50 Self: 'a;
40 51
41 fn preconjugate(&self) -> Self::Preconjugate<'_>; 52 fn preconjugate(&self) -> Self::Preconjugate<'_>;
42 } 53 }
43 54
44 /// Trait for mappings with a proximap map 55 /// Trait for mappings with a proximap map
45 /// 56 ///
46 /// The conjugate type has to implement [`ConvexMapping`], but a `Conjugable` mapping need 57 /// The conjugate type has to implement [`ConvexMapping`], but a `Conjugable` mapping need
47 /// not be convex. 58 /// not be convex.
48 pub trait Prox<Domain : Space> : Mapping<Domain> { 59 pub trait Prox<Domain: Space>: Mapping<Domain> {
49 type Prox<'a> : Mapping<Domain, Codomain=Domain> where Self : 'a; 60 type Prox<'a>: Mapping<Domain, Codomain = Domain::Principal>
61 where
62 Self: 'a;
50 63
51 /// Returns a proximal mapping with weight τ 64 /// Returns a proximal mapping with weight τ
52 fn prox_mapping(&self, τ : Self::Codomain) -> Self::Prox<'_>; 65 fn prox_mapping(&self, τ: Self::Codomain) -> Self::Prox<'_>;
53 66
54 /// Calculate the proximal mapping with weight τ 67 /// Calculate the proximal mapping with weight τ
55 fn prox<I : Instance<Domain>>(&self, τ : Self::Codomain, z : I) -> Domain { 68 fn prox<I: Instance<Domain>>(&self, τ: Self::Codomain, z: I) -> Domain::Principal {
56 self.prox_mapping(τ).apply(z) 69 self.prox_mapping(τ).apply(z)
57 } 70 }
58 71
59 /// Calculate the proximal mapping with weight τ in-place 72 /// Calculate the proximal mapping with weight τ in-place
60 fn prox_mut<'b>(&self, τ : Self::Codomain, y : &'b mut Domain) 73 fn prox_mut<'b>(&self, τ: Self::Codomain, y: &'b mut Domain::Principal)
61 where 74 where
62 &'b mut Domain : InstanceMut<Domain>, 75 Domain::Decomp: DecompositionMut<Domain>,
63 Domain:: Decomp : DecompositionMut<Domain>, 76 for<'a> &'a Domain::Principal: Instance<Domain>,
64 for<'a> &'a Domain : Instance<Domain>,
65 { 77 {
66 *y = self.prox(τ, &*y); 78 *y = self.prox(τ, &*y);
67 } 79 }
68 } 80 }
69 81
70
71 /// Constraint to the unit ball of the norm described by `E`. 82 /// Constraint to the unit ball of the norm described by `E`.
72 pub struct NormConstraint<F : Float, E : NormExponent> { 83 #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
73 radius : F, 84 pub struct NormConstraint<F: Float, E: NormExponent> {
74 norm : NormMapping<F, E>, 85 radius: F,
86 norm: NormMapping<F, E>,
75 } 87 }
76 88
77 impl<Domain, E, F> ConvexMapping<Domain, F> for NormMapping<F, E> 89 impl<Domain, E, F> ConvexMapping<Domain, F> for NormMapping<F, E>
78 where 90 where
79 Domain : Space, 91 Domain: Space,
80 E : NormExponent, 92 E: NormExponent,
81 F : Float, 93 F: Float,
82 Self : Mapping<Domain, Codomain=F> 94 Self: Mapping<Domain, Codomain = F>,
83 {} 95 {
84 96 }
85 97
86 impl<F, E, Domain> Mapping<Domain> for NormConstraint<F, E> 98 impl<F, E, Domain> Mapping<Domain> for NormConstraint<F, E>
87 where 99 where
88 Domain : Space + Norm<F, E>, 100 Domain: Space,
89 F : Float, 101 Domain::Principal: Norm<E, F>,
90 E : NormExponent, 102 F: Float,
103 E: NormExponent,
91 { 104 {
92 type Codomain = F; 105 type Codomain = F;
93 106
94 fn apply<I : Instance<Domain>>(&self, d : I) -> F { 107 fn apply<I: Instance<Domain>>(&self, d: I) -> F {
95 if d.eval(|x| x.norm(self.norm.exponent)) <= self.radius { 108 if d.eval(|x| x.norm(self.norm.exponent)) <= self.radius {
96 F::ZERO 109 F::ZERO
97 } else { 110 } else {
98 F::INFINITY 111 F::INFINITY
99 } 112 }
100 } 113 }
101 } 114 }
102 115
103 impl<Domain, E, F> ConvexMapping<Domain, F> for NormConstraint<F, E> 116 impl<Domain, E, F> ConvexMapping<Domain, F> for NormConstraint<F, E>
104 where 117 where
105 Domain : Space, 118 Domain: Space,
106 E : NormExponent, 119 E: NormExponent,
107 F : Float, 120 F: Float,
108 Self : Mapping<Domain, Codomain=F> 121 Self: Mapping<Domain, Codomain = F>,
109 {} 122 {
110 123 }
111 124
112 impl<E, F, Domain> Conjugable<Domain, F> for NormMapping<F, E> 125 impl<E, F, Domain> Conjugable<Domain, F> for NormMapping<F, E>
113 where 126 where
114 E : HasDualExponent, 127 E: HasDualExponent,
115 F : Float, 128 F: Float,
116 Domain : HasDual<F> + Norm<F, E> + Space, 129 Domain: HasDual<F>,
117 <Domain as HasDual<F>>::DualSpace : Norm<F, E::DualExp> 130 Domain::Principal: Norm<E, F>,
118 { 131 <Domain as HasDual<F>>::DualSpace: Norm<E::DualExp, F>,
119 type Conjugate<'a> = NormConstraint<F, E::DualExp> where Self : 'a; 132 {
133 type Conjugate<'a>
134 = NormConstraint<F, E::DualExp>
135 where
136 Self: 'a;
137
138 fn conjugate(&self) -> Self::Conjugate<'_> {
139 NormConstraint { radius: F::ONE, norm: self.exponent.dual_exponent().as_mapping() }
140 }
141 }
142
143 impl<C, E, F, Domain> Conjugable<Domain, F> for Weighted<NormMapping<F, E>, C>
144 where
145 C: Constant<Type = F>,
146 E: HasDualExponent,
147 F: Float,
148 Domain: HasDual<F>,
149 Domain::Principal: Norm<E, F>,
150 <Domain as HasDual<F>>::DualSpace: Norm<E::DualExp, F>,
151 {
152 type Conjugate<'a>
153 = NormConstraint<F, E::DualExp>
154 where
155 Self: 'a;
120 156
121 fn conjugate(&self) -> Self::Conjugate<'_> { 157 fn conjugate(&self) -> Self::Conjugate<'_> {
122 NormConstraint { 158 NormConstraint {
123 radius : F::ONE, 159 radius: self.weight.value(),
124 norm : self.exponent.dual_exponent().as_mapping() 160 norm: self.base_fn.exponent.dual_exponent().as_mapping(),
125 } 161 }
126 } 162 }
127 } 163 }
128 164
129 impl<C, E, F, Domain> Conjugable<Domain, F> for Weighted<NormMapping<F, E>, C>
130 where
131 C : Constant<Type = F>,
132 E : HasDualExponent,
133 F : Float,
134 Domain : HasDual<F> + Norm<F, E> + Space,
135 <Domain as HasDual<F>>::DualSpace : Norm<F, E::DualExp>
136 {
137 type Conjugate<'a> = NormConstraint<F, E::DualExp> where Self : 'a;
138
139 fn conjugate(&self) -> Self::Conjugate<'_> {
140 NormConstraint {
141 radius : self.weight.value(),
142 norm : self.base_fn.exponent.dual_exponent().as_mapping()
143 }
144 }
145 }
146
147 impl<Domain, E, F> Prox<Domain> for NormConstraint<F, E> 165 impl<Domain, E, F> Prox<Domain> for NormConstraint<F, E>
148 where 166 where
149 Domain : Space + Norm<F, E>, 167 Domain: Space,
150 E : NormExponent, 168 Domain::Principal: Norm<E, F>,
151 F : Float, 169 E: NormExponent,
152 NormProjection<F, E> : Mapping<Domain, Codomain=Domain>, 170 F: Float,
153 { 171 NormProjection<F, E>: Mapping<Domain, Codomain = Domain::Principal>,
154 type Prox<'a> = NormProjection<F, E> where Self : 'a; 172 {
155 173 type Prox<'a>
156 #[inline] 174 = NormProjection<F, E>
157 fn prox_mapping(&self, _τ : Self::Codomain) -> Self::Prox<'_> { 175 where
176 Self: 'a;
177
178 #[inline]
179 fn prox_mapping(&self, _τ: Self::Codomain) -> Self::Prox<'_> {
158 assert!(self.radius >= F::ZERO); 180 assert!(self.radius >= F::ZERO);
159 NormProjection{ radius : self.radius, exponent : self.norm.exponent } 181 NormProjection { radius: self.radius, exponent: self.norm.exponent }
160 } 182 }
161 } 183 }
162 184
163 /// Projection to the unit ball of the norm described by `E`. 185 /// Projection to the unit ball of the norm described by `E`.
164 pub struct NormProjection<F : Float, E : NormExponent> { 186 #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
165 radius : F, 187 pub struct NormProjection<F: Float, E: NormExponent> {
166 exponent : E, 188 radius: F,
189 exponent: E,
167 } 190 }
168 191
169 /* 192 /*
170 impl<F, Domain> Mapping<Domain> for NormProjection<F, L2> 193 impl<F, Domain> Mapping<Domain> for NormProjection<F, L2>
171 where 194 where
180 } 203 }
181 */ 204 */
182 205
183 impl<F, E, Domain> Mapping<Domain> for NormProjection<F, E> 206 impl<F, E, Domain> Mapping<Domain> for NormProjection<F, E>
184 where 207 where
185 Domain : Space + Projection<F, E>, 208 Domain: Space,
186 F : Float, 209 Domain::Principal: ClosedSpace + Projection<F, E>,
187 E : NormExponent, 210 F: Float,
188 { 211 E: NormExponent,
189 type Codomain = Domain; 212 {
190 213 type Codomain = Domain::Principal;
191 fn apply<I : Instance<Domain>>(&self, d : I) -> Domain { 214
215 fn apply<I: Instance<Domain>>(&self, d: I) -> Self::Codomain {
192 d.own().proj_ball(self.radius, self.exponent) 216 d.own().proj_ball(self.radius, self.exponent)
193 } 217 }
194 } 218 }
195 219
196
197 /// The zero mapping 220 /// The zero mapping
198 pub struct Zero<Domain : Space, F : Num>(PhantomData<(Domain, F)>); 221 #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
199 222 pub struct Zero<Domain: Space, F: Num>(PhantomData<(Domain, F)>);
200 impl<Domain : Space, F : Num> Zero<Domain, F> { 223
224 impl<Domain: Space, F: Num> Zero<Domain, F> {
201 pub fn new() -> Self { 225 pub fn new() -> Self {
202 Zero(PhantomData) 226 Zero(PhantomData)
203 } 227 }
204 } 228 }
205 229
206 impl<Domain : Space, F : Num> Mapping<Domain> for Zero<Domain, F> { 230 impl<Domain: Space, F: Num> Mapping<Domain> for Zero<Domain, F> {
207 type Codomain = F; 231 type Codomain = F;
208 232
209 /// Compute the value of `self` at `x`. 233 /// Compute the value of `self` at `x`.
210 fn apply<I : Instance<Domain>>(&self, _x : I) -> Self::Codomain { 234 fn apply<I: Instance<Domain>>(&self, _x: I) -> Self::Codomain {
211 F::ZERO 235 F::ZERO
212 } 236 }
213 } 237 }
214 238
215 impl<Domain : Space, F : Num> ConvexMapping<Domain, F> for Zero<Domain, F> { } 239 impl<Domain: Space, F: Float> ConvexMapping<Domain, F> for Zero<Domain, F> {}
216 240
217 241 impl<Domain: HasDual<F>, F: Float> Conjugable<Domain, F> for Zero<Domain, F> {
218 impl<Domain : HasDual<F>, F : Float> Conjugable<Domain, F> for Zero<Domain, F> { 242 type Conjugate<'a>
219 type Conjugate<'a> = ZeroIndicator<Domain::DualSpace, F> where Self : 'a; 243 = ZeroIndicator<Domain::DualSpace, F>
244 where
245 Self: 'a;
220 246
221 #[inline] 247 #[inline]
222 fn conjugate(&self) -> Self::Conjugate<'_> { 248 fn conjugate(&self) -> Self::Conjugate<'_> {
223 ZeroIndicator::new() 249 ZeroIndicator::new()
224 } 250 }
225 } 251 }
226 252
227 impl<Domain, Predual, F : Float> Preconjugable<Domain, Predual, F> for Zero<Domain, F> 253 impl<Domain, Predual, F: Float> Preconjugable<Domain, Predual, F> for Zero<Domain, F>
228 where 254 where
229 Domain : Space, 255 Domain: Normed<F>,
230 Predual : HasDual<F> 256 Predual: HasDual<F, PrincipalV = Predual>,
231 { 257 {
232 type Preconjugate<'a> = ZeroIndicator<Predual, F> where Self : 'a; 258 type Preconjugate<'a>
259 = ZeroIndicator<Predual, F>
260 where
261 Self: 'a;
233 262
234 #[inline] 263 #[inline]
235 fn preconjugate(&self) -> Self::Preconjugate<'_> { 264 fn preconjugate(&self) -> Self::Preconjugate<'_> {
236 ZeroIndicator::new() 265 ZeroIndicator::new()
237 } 266 }
238 } 267 }
239 268
240 impl<Domain : Space + Clone, F : Num> Prox<Domain> for Zero<Domain, F> { 269 impl<Domain: Space, F: Num> Prox<Domain> for Zero<Domain, F> {
241 type Prox<'a> = IdOp<Domain> where Self : 'a; 270 type Prox<'a>
242 271 = IdOp<Domain>
243 #[inline] 272 where
244 fn prox_mapping(&self, _τ : Self::Codomain) -> Self::Prox<'_> { 273 Self: 'a;
274
275 #[inline]
276 fn prox_mapping(&self, _τ: Self::Codomain) -> Self::Prox<'_> {
245 IdOp::new() 277 IdOp::new()
246 } 278 }
247 } 279 }
248 280
249
250 /// The zero indicator 281 /// The zero indicator
251 pub struct ZeroIndicator<Domain : Space, F : Num>(PhantomData<(Domain, F)>); 282 #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
252 283 pub struct ZeroIndicator<Domain: Space, F: Num>(PhantomData<(Domain, F)>);
253 impl<Domain : Space, F : Num> ZeroIndicator<Domain, F> { 284
285 impl<Domain: Space, F: Num> ZeroIndicator<Domain, F> {
254 pub fn new() -> Self { 286 pub fn new() -> Self {
255 ZeroIndicator(PhantomData) 287 ZeroIndicator(PhantomData)
256 } 288 }
257 } 289 }
258 290
259 impl<Domain : Normed<F>, F : Float> Mapping<Domain> for ZeroIndicator<Domain, F> { 291 impl<Domain, F> Mapping<Domain> for ZeroIndicator<Domain, F>
292 where
293 F: Float,
294 Domain: Space,
295 Domain::Principal: Normed<F>,
296 {
260 type Codomain = F; 297 type Codomain = F;
261 298
262 /// Compute the value of `self` at `x`. 299 /// Compute the value of `self` at `x`.
263 fn apply<I : Instance<Domain>>(&self, x : I) -> Self::Codomain { 300 fn apply<I: Instance<Domain>>(&self, x: I) -> Self::Codomain {
264 x.eval(|x̃| if x̃.is_zero() { F::ZERO } else { F::INFINITY }) 301 x.eval(|x̃| if x̃.is_zero() { F::ZERO } else { F::INFINITY })
265 } 302 }
266 } 303 }
267 304
268 impl<Domain : Normed<F>, F : Float> ConvexMapping<Domain, F> for ZeroIndicator<Domain, F> { } 305 impl<Domain, F: Float> ConvexMapping<Domain, F> for ZeroIndicator<Domain, F>
269 306 where
270 impl<Domain : HasDual<F>, F : Float> Conjugable<Domain, F> for ZeroIndicator<Domain, F> { 307 Domain: Space,
271 type Conjugate<'a> = Zero<Domain::DualSpace, F> where Self : 'a; 308 Domain::Principal: Normed<F>,
309 {
310 fn factor_of_strong_convexity(&self) -> F {
311 F::INFINITY
312 }
313 }
314
315 impl<Domain, F: Float> Conjugable<Domain, F> for ZeroIndicator<Domain, F>
316 where
317 Domain: HasDual<F>,
318 Domain::PrincipalV: Normed<F>,
319 {
320 type Conjugate<'a>
321 = Zero<Domain::DualSpace, F>
322 where
323 Self: 'a;
272 324
273 #[inline] 325 #[inline]
274 fn conjugate(&self) -> Self::Conjugate<'_> { 326 fn conjugate(&self) -> Self::Conjugate<'_> {
275 Zero::new() 327 Zero::new()
276 } 328 }
277 } 329 }
278 330
279 impl<Domain, Predual, F : Float> Preconjugable<Domain, Predual, F> for ZeroIndicator<Domain, F> 331 impl<Domain, Predual, F: Float> Preconjugable<Domain, Predual, F> for ZeroIndicator<Domain, F>
280 where 332 where
281 Domain : Normed<F>, 333 Domain: Space,
282 Predual : HasDual<F> 334 Domain::Principal: Normed<F>,
283 { 335 Predual: HasDual<F>,
284 type Preconjugate<'a> = Zero<Predual, F> where Self : 'a; 336 {
337 type Preconjugate<'a>
338 = Zero<Predual, F>
339 where
340 Self: 'a;
285 341
286 #[inline] 342 #[inline]
287 fn preconjugate(&self) -> Self::Preconjugate<'_> { 343 fn preconjugate(&self) -> Self::Preconjugate<'_> {
288 Zero::new() 344 Zero::new()
289 } 345 }
290 } 346 }
347
348 impl<Domain, F> Prox<Domain> for ZeroIndicator<Domain, F>
349 where
350 Domain: AXPY<Field = F, PrincipalV = Domain> + Normed<F>,
351 F: Float,
352 {
353 type Prox<'a>
354 = SimpleZeroOp
355 where
356 Self: 'a;
357
358 /// Returns a proximal mapping with weight τ
359 fn prox_mapping(&self, _τ: F) -> Self::Prox<'_> {
360 return SimpleZeroOp;
361 }
362 }
363
364 /// The squared Euclidean norm divided by two
365 #[derive(Copy, Clone, Serialize, Deserialize)]
366 pub struct Norm222<F: Float>(PhantomData<F>);
367
368 impl</*Domain: Euclidean<F>,*/ F: Float> Norm222<F> {
369 pub fn new() -> Self {
370 Norm222(PhantomData)
371 }
372 }
373
374 impl<X: Euclidean<F>, F: Float> Mapping<X> for Norm222<F> {
375 type Codomain = F;
376
377 /// Compute the value of `self` at `x`.
378 fn apply<I: Instance<X>>(&self, x: I) -> Self::Codomain {
379 x.eval(|z| z.norm2_squared() / F::TWO)
380 }
381 }
382
383 impl<X: Euclidean<F>, F: Float> ConvexMapping<X, F> for Norm222<F> {
384 fn factor_of_strong_convexity(&self) -> F {
385 F::ONE
386 }
387 }
388
389 impl<X: Euclidean<F>, F: Float> Conjugable<X, F> for Norm222<F> {
390 type Conjugate<'a>
391 = Self
392 where
393 Self: 'a;
394
395 #[inline]
396 fn conjugate(&self) -> Self::Conjugate<'_> {
397 Self::new()
398 }
399 }
400
401 impl<X: Euclidean<F>, F: Float> Preconjugable<X, X, F> for Norm222<F> {
402 type Preconjugate<'a>
403 = Self
404 where
405 Self: 'a;
406
407 #[inline]
408 fn preconjugate(&self) -> Self::Preconjugate<'_> {
409 Self::new()
410 }
411 }
412
413 impl<X, F> Prox<X> for Norm222<F>
414 where
415 F: Float,
416 X: Euclidean<F>,
417 {
418 type Prox<'a>
419 = Scaled<F>
420 where
421 Self: 'a;
422
423 fn prox_mapping(&self, τ: F) -> Self::Prox<'_> {
424 Scaled(F::ONE / (F::ONE + τ))
425 }
426 }
427
428 impl<X, F> DifferentiableImpl<X> for Norm222<F>
429 where
430 F: Float,
431 X: Euclidean<F>,
432 {
433 type Derivative = X::PrincipalV;
434
435 fn differential_impl<I: Instance<X>>(&self, x: I) -> Self::Derivative {
436 x.own()
437 }
438 }
439
440 impl<X, F> LipschitzDifferentiableImpl<X, L2> for Norm222<F>
441 where
442 F: Float,
443 X: Euclidean<F>,
444 {
445 type FloatType = F;
446
447 fn diff_lipschitz_factor(&self, _: L2) -> DynResult<Self::FloatType> {
448 Ok(F::ONE)
449 }
450 }

mercurial