1#[cfg(all(feature = "alloc", not(feature = "std")))]
2use alloc::vec::Vec;
3
4use num::Zero;
5use std::ops::Neg;
6
7use crate::allocator::Allocator;
8use crate::base::{DefaultAllocator, Dim, DimName, Matrix, Normed, OMatrix, OVector};
9use crate::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
10use crate::storage::{Storage, StorageMut};
11use crate::{ComplexField, Scalar, SimdComplexField, Unit};
12use simba::scalar::ClosedNeg;
13use simba::simd::{SimdOption, SimdPartialOrd, SimdValue};
14
15pub trait Norm<T: SimdComplexField> {
20 fn norm<R, C, S>(&self, m: &Matrix<T, R, C, S>) -> T::SimdRealField
22 where
23 R: Dim,
24 C: Dim,
25 S: Storage<T, R, C>;
26 fn metric_distance<R1, C1, S1, R2, C2, S2>(
28 &self,
29 m1: &Matrix<T, R1, C1, S1>,
30 m2: &Matrix<T, R2, C2, S2>,
31 ) -> T::SimdRealField
32 where
33 R1: Dim,
34 C1: Dim,
35 S1: Storage<T, R1, C1>,
36 R2: Dim,
37 C2: Dim,
38 S2: Storage<T, R2, C2>,
39 ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>;
40}
41
42#[derive(Copy, Clone, Debug)]
44pub struct EuclideanNorm;
45#[derive(Copy, Clone, Debug)]
47pub struct LpNorm(pub i32);
48#[derive(Copy, Clone, Debug)]
50pub struct UniformNorm;
51
52impl<T: SimdComplexField> Norm<T> for EuclideanNorm {
53 #[inline]
54 fn norm<R, C, S>(&self, m: &Matrix<T, R, C, S>) -> T::SimdRealField
55 where
56 R: Dim,
57 C: Dim,
58 S: Storage<T, R, C>,
59 {
60 m.norm_squared().simd_sqrt()
61 }
62
63 #[inline]
64 fn metric_distance<R1, C1, S1, R2, C2, S2>(
65 &self,
66 m1: &Matrix<T, R1, C1, S1>,
67 m2: &Matrix<T, R2, C2, S2>,
68 ) -> T::SimdRealField
69 where
70 R1: Dim,
71 C1: Dim,
72 S1: Storage<T, R1, C1>,
73 R2: Dim,
74 C2: Dim,
75 S2: Storage<T, R2, C2>,
76 ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>,
77 {
78 m1.zip_fold(m2, T::SimdRealField::zero(), |acc, a, b| {
79 let diff = a - b;
80 acc + diff.simd_modulus_squared()
81 })
82 .simd_sqrt()
83 }
84}
85
86impl<T: SimdComplexField> Norm<T> for LpNorm {
87 #[inline]
88 fn norm<R, C, S>(&self, m: &Matrix<T, R, C, S>) -> T::SimdRealField
89 where
90 R: Dim,
91 C: Dim,
92 S: Storage<T, R, C>,
93 {
94 m.fold(T::SimdRealField::zero(), |a, b| {
95 a + b.simd_modulus().simd_powi(self.0)
96 })
97 .simd_powf(crate::convert(1.0 / (self.0 as f64)))
98 }
99
100 #[inline]
101 fn metric_distance<R1, C1, S1, R2, C2, S2>(
102 &self,
103 m1: &Matrix<T, R1, C1, S1>,
104 m2: &Matrix<T, R2, C2, S2>,
105 ) -> T::SimdRealField
106 where
107 R1: Dim,
108 C1: Dim,
109 S1: Storage<T, R1, C1>,
110 R2: Dim,
111 C2: Dim,
112 S2: Storage<T, R2, C2>,
113 ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>,
114 {
115 m1.zip_fold(m2, T::SimdRealField::zero(), |acc, a, b| {
116 let diff = a - b;
117 acc + diff.simd_modulus().simd_powi(self.0)
118 })
119 .simd_powf(crate::convert(1.0 / (self.0 as f64)))
120 }
121}
122
123impl<T: SimdComplexField> Norm<T> for UniformNorm {
124 #[inline]
125 fn norm<R, C, S>(&self, m: &Matrix<T, R, C, S>) -> T::SimdRealField
126 where
127 R: Dim,
128 C: Dim,
129 S: Storage<T, R, C>,
130 {
131 m.fold(T::SimdRealField::zero(), |acc, a| {
134 acc.simd_max(a.simd_modulus())
135 })
136 }
137
138 #[inline]
139 fn metric_distance<R1, C1, S1, R2, C2, S2>(
140 &self,
141 m1: &Matrix<T, R1, C1, S1>,
142 m2: &Matrix<T, R2, C2, S2>,
143 ) -> T::SimdRealField
144 where
145 R1: Dim,
146 C1: Dim,
147 S1: Storage<T, R1, C1>,
148 R2: Dim,
149 C2: Dim,
150 S2: Storage<T, R2, C2>,
151 ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>,
152 {
153 m1.zip_fold(m2, T::SimdRealField::zero(), |acc, a, b| {
154 let val = (a - b).simd_modulus();
155 acc.simd_max(val)
156 })
157 }
158}
159
160impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
162 #[inline]
164 #[must_use]
165 pub fn norm_squared(&self) -> T::SimdRealField
166 where
167 T: SimdComplexField,
168 {
169 let mut res = T::SimdRealField::zero();
170
171 for i in 0..self.ncols() {
172 let col = self.column(i);
173 res += col.dotc(&col).simd_real()
174 }
175
176 res
177 }
178
179 #[inline]
183 #[must_use]
184 pub fn norm(&self) -> T::SimdRealField
185 where
186 T: SimdComplexField,
187 {
188 self.norm_squared().simd_sqrt()
189 }
190
191 #[inline]
195 #[must_use]
196 pub fn metric_distance<R2, C2, S2>(&self, rhs: &Matrix<T, R2, C2, S2>) -> T::SimdRealField
197 where
198 T: SimdComplexField,
199 R2: Dim,
200 C2: Dim,
201 S2: Storage<T, R2, C2>,
202 ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>,
203 {
204 self.apply_metric_distance(rhs, &EuclideanNorm)
205 }
206
207 #[inline]
220 #[must_use]
221 pub fn apply_norm(&self, norm: &impl Norm<T>) -> T::SimdRealField
222 where
223 T: SimdComplexField,
224 {
225 norm.norm(self)
226 }
227
228 #[inline]
243 #[must_use]
244 pub fn apply_metric_distance<R2, C2, S2>(
245 &self,
246 rhs: &Matrix<T, R2, C2, S2>,
247 norm: &impl Norm<T>,
248 ) -> T::SimdRealField
249 where
250 T: SimdComplexField,
251 R2: Dim,
252 C2: Dim,
253 S2: Storage<T, R2, C2>,
254 ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>,
255 {
256 norm.metric_distance(self, rhs)
257 }
258
259 #[inline]
265 #[must_use]
266 pub fn magnitude(&self) -> T::SimdRealField
267 where
268 T: SimdComplexField,
269 {
270 self.norm()
271 }
272
273 #[inline]
279 #[must_use]
280 pub fn magnitude_squared(&self) -> T::SimdRealField
281 where
282 T: SimdComplexField,
283 {
284 self.norm_squared()
285 }
286
287 #[inline]
289 pub fn set_magnitude(&mut self, magnitude: T::SimdRealField)
290 where
291 T: SimdComplexField,
292 S: StorageMut<T, R, C>,
293 {
294 let n = self.norm();
295 self.scale_mut(magnitude / n)
296 }
297
298 #[inline]
300 #[must_use = "Did you mean to use normalize_mut()?"]
301 pub fn normalize(&self) -> OMatrix<T, R, C>
302 where
303 T: SimdComplexField,
304 DefaultAllocator: Allocator<R, C>,
305 {
306 self.unscale(self.norm())
307 }
308
309 #[inline]
311 #[must_use]
312 pub fn lp_norm(&self, p: i32) -> T::SimdRealField
313 where
314 T: SimdComplexField,
315 {
316 self.apply_norm(&LpNorm(p))
317 }
318
319 #[inline]
323 #[must_use = "Did you mean to use simd_try_normalize_mut()?"]
324 pub fn simd_try_normalize(&self, min_norm: T::SimdRealField) -> SimdOption<OMatrix<T, R, C>>
325 where
326 T: SimdComplexField,
327 T::Element: Scalar,
328 DefaultAllocator: Allocator<R, C>,
329 {
330 let n = self.norm();
331 let le = n.clone().simd_le(min_norm);
332 let val = self.unscale(n);
333 SimdOption::new(val, le)
334 }
335
336 #[inline]
341 pub fn try_set_magnitude(&mut self, magnitude: T::RealField, min_magnitude: T::RealField)
342 where
343 T: ComplexField,
344 S: StorageMut<T, R, C>,
345 {
346 let n = self.norm();
347
348 if n > min_magnitude {
349 self.scale_mut(magnitude / n)
350 }
351 }
352
353 #[inline]
355 #[must_use]
356 pub fn cap_magnitude(&self, max: T::RealField) -> OMatrix<T, R, C>
357 where
358 T: ComplexField,
359 DefaultAllocator: Allocator<R, C>,
360 {
361 let n = self.norm();
362
363 if n > max {
364 self.scale(max / n)
365 } else {
366 self.clone_owned()
367 }
368 }
369
370 #[inline]
372 #[must_use]
373 pub fn simd_cap_magnitude(&self, max: T::SimdRealField) -> OMatrix<T, R, C>
374 where
375 T: SimdComplexField,
376 T::Element: Scalar,
377 DefaultAllocator: Allocator<R, C>,
378 {
379 let n = self.norm();
380 let scaled = self.scale(max.clone() / n.clone());
381 let use_scaled = n.simd_gt(max);
382 scaled.select(use_scaled, self.clone_owned())
383 }
384
385 #[inline]
389 #[must_use = "Did you mean to use try_normalize_mut()?"]
390 pub fn try_normalize(&self, min_norm: T::RealField) -> Option<OMatrix<T, R, C>>
391 where
392 T: ComplexField,
393 DefaultAllocator: Allocator<R, C>,
394 {
395 let n = self.norm();
396
397 if n <= min_norm {
398 None
399 } else {
400 Some(self.unscale(n))
401 }
402 }
403}
404
405impl<T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
407 #[inline]
411 pub fn normalize_mut(&mut self) -> T::SimdRealField
412 where
413 T: SimdComplexField,
414 {
415 let n = self.norm();
416 self.unscale_mut(n.clone());
417
418 n
419 }
420
421 #[inline]
425 #[must_use = "Did you mean to use simd_try_normalize_mut()?"]
426 pub fn simd_try_normalize_mut(
427 &mut self,
428 min_norm: T::SimdRealField,
429 ) -> SimdOption<T::SimdRealField>
430 where
431 T: SimdComplexField,
432 T::Element: Scalar,
433 DefaultAllocator: Allocator<R, C>,
434 {
435 let n = self.norm();
436 let le = n.clone().simd_le(min_norm);
437 self.apply(|e| *e = e.clone().simd_unscale(n.clone()).select(le, e.clone()));
438 SimdOption::new(n, le)
439 }
440
441 #[inline]
445 pub fn try_normalize_mut(&mut self, min_norm: T::RealField) -> Option<T::RealField>
446 where
447 T: ComplexField,
448 {
449 let n = self.norm();
450
451 if n <= min_norm {
452 None
453 } else {
454 self.unscale_mut(n.clone());
455 Some(n)
456 }
457 }
458}
459
460impl<T: SimdComplexField, R: Dim, C: Dim> Normed for OMatrix<T, R, C>
461where
462 DefaultAllocator: Allocator<R, C>,
463{
464 type Norm = T::SimdRealField;
465
466 #[inline]
467 fn norm(&self) -> T::SimdRealField {
468 self.norm()
469 }
470
471 #[inline]
472 fn norm_squared(&self) -> T::SimdRealField {
473 self.norm_squared()
474 }
475
476 #[inline]
477 fn scale_mut(&mut self, n: Self::Norm) {
478 self.scale_mut(n)
479 }
480
481 #[inline]
482 fn unscale_mut(&mut self, n: Self::Norm) {
483 self.unscale_mut(n)
484 }
485}
486
487impl<T: Scalar + ClosedNeg, R: Dim, C: Dim> Neg for Unit<OMatrix<T, R, C>>
488where
489 DefaultAllocator: Allocator<R, C>,
490{
491 type Output = Unit<OMatrix<T, R, C>>;
492
493 #[inline]
494 fn neg(self) -> Self::Output {
495 Unit::new_unchecked(-self.value)
496 }
497}
498
499impl<T: ComplexField, D: DimName> OVector<T, D>
505where
506 DefaultAllocator: Allocator<D>,
507{
508 #[inline]
510 fn canonical_basis_element(i: usize) -> Self {
511 let mut res = Self::zero();
512 res[i] = T::one();
513 res
514 }
515
516 #[inline]
520 pub fn orthonormalize(vs: &mut [Self]) -> usize {
521 let mut nbasis_elements = 0;
522
523 for i in 0..vs.len() {
524 {
525 let (elt, basis) = vs[..i + 1].split_last_mut().unwrap();
526
527 for basis_element in &basis[..nbasis_elements] {
528 *elt -= basis_element * elt.dot(basis_element)
529 }
530 }
531
532 if vs[i].try_normalize_mut(T::RealField::zero()).is_some() {
533 vs.swap(nbasis_elements, i);
536 nbasis_elements += 1;
537
538 if nbasis_elements == D::dim() {
540 break;
541 }
542 }
543 }
544
545 nbasis_elements
546 }
547
548 #[inline]
553 pub fn orthonormal_subspace_basis<F>(vs: &[Self], mut f: F)
554 where
555 F: FnMut(&Self) -> bool,
556 {
557 assert!(
559 vs.len() <= D::dim(),
560 "The given set of vectors has no chance of being a free family."
561 );
562
563 match D::dim() {
564 1 => {
565 if vs.is_empty() {
566 let _ = f(&Self::canonical_basis_element(0));
567 }
568 }
569 2 => {
570 if vs.is_empty() {
571 let _ = f(&Self::canonical_basis_element(0))
572 && f(&Self::canonical_basis_element(1));
573 } else if vs.len() == 1 {
574 let v = &vs[0];
575 let res = Self::from_column_slice(&[-v[1].clone(), v[0].clone()]);
576
577 let _ = f(&res.normalize());
578 }
579
580 }
582 3 => {
583 if vs.is_empty() {
584 let _ = f(&Self::canonical_basis_element(0))
585 && f(&Self::canonical_basis_element(1))
586 && f(&Self::canonical_basis_element(2));
587 } else if vs.len() == 1 {
588 let v = &vs[0];
589 let mut a;
590
591 if v[0].clone().norm1() > v[1].clone().norm1() {
592 a = Self::from_column_slice(&[v[2].clone(), T::zero(), -v[0].clone()]);
593 } else {
594 a = Self::from_column_slice(&[T::zero(), -v[2].clone(), v[1].clone()]);
595 };
596
597 let _ = a.normalize_mut();
598
599 if f(&a.cross(v)) {
600 let _ = f(&a);
601 }
602 } else if vs.len() == 2 {
603 let _ = f(&vs[0].cross(&vs[1]).normalize());
604 }
605 }
606 _ => {
607 #[cfg(any(feature = "std", feature = "alloc"))]
608 {
609 let mut known_basis = Vec::new();
611
612 for v in vs.iter() {
613 known_basis.push(v.normalize())
614 }
615
616 for i in 0..D::dim() - vs.len() {
617 let mut elt = Self::canonical_basis_element(i);
618
619 for v in &known_basis {
620 elt -= v * elt.dot(v)
621 }
622
623 if let Some(subsp_elt) = elt.try_normalize(T::RealField::zero()) {
624 if !f(&subsp_elt) {
625 return;
626 };
627
628 known_basis.push(subsp_elt);
629 }
630 }
631 }
632 #[cfg(all(not(feature = "std"), not(feature = "alloc")))]
633 {
634 panic!("Cannot compute the orthogonal subspace basis of a vector with a dimension greater than 3 \
635 if #![no_std] is enabled and the 'alloc' feature is not enabled.")
636 }
637 }
638 }
639 }
640}