|
| 1 | +//! Reciprocal conditional number |
| 2 | +
|
1 | 3 | use crate::{error::*, layout::MatrixLayout, *}; |
2 | 4 | use cauchy::*; |
3 | 5 | use num_traits::Zero; |
4 | 6 |
|
5 | | -pub trait Rcond_: Scalar + Sized { |
6 | | - /// Estimates the the reciprocal of the condition number of the matrix in 1-norm. |
7 | | - /// |
8 | | - /// `anorm` should be the 1-norm of the matrix `a`. |
9 | | - fn rcond(l: MatrixLayout, a: &[Self], anorm: Self::Real) -> Result<Self::Real>; |
| 7 | +pub struct RcondWork<T: Scalar> { |
| 8 | + pub layout: MatrixLayout, |
| 9 | + pub work: Vec<MaybeUninit<T>>, |
| 10 | + pub rwork: Option<Vec<MaybeUninit<T::Real>>>, |
| 11 | + pub iwork: Option<Vec<MaybeUninit<i32>>>, |
10 | 12 | } |
11 | 13 |
|
12 | | -macro_rules! impl_rcond_real { |
13 | | - ($scalar:ty, $gecon:path) => { |
14 | | - impl Rcond_ for $scalar { |
15 | | - fn rcond(l: MatrixLayout, a: &[Self], anorm: Self::Real) -> Result<Self::Real> { |
16 | | - let (n, _) = l.size(); |
17 | | - let mut rcond = Self::Real::zero(); |
18 | | - let mut info = 0; |
| 14 | +pub trait RcondWorkImpl { |
| 15 | + type Elem: Scalar; |
| 16 | + fn new(l: MatrixLayout) -> Self; |
| 17 | + fn calc( |
| 18 | + &mut self, |
| 19 | + a: &[Self::Elem], |
| 20 | + anorm: <Self::Elem as Scalar>::Real, |
| 21 | + ) -> Result<<Self::Elem as Scalar>::Real>; |
| 22 | +} |
| 23 | + |
| 24 | +macro_rules! impl_rcond_work_c { |
| 25 | + ($c:ty, $con:path) => { |
| 26 | + impl RcondWorkImpl for RcondWork<$c> { |
| 27 | + type Elem = $c; |
| 28 | + |
| 29 | + fn new(layout: MatrixLayout) -> Self { |
| 30 | + let (n, _) = layout.size(); |
| 31 | + let work = vec_uninit(2 * n as usize); |
| 32 | + let rwork = vec_uninit(2 * n as usize); |
| 33 | + RcondWork { |
| 34 | + layout, |
| 35 | + work, |
| 36 | + rwork: Some(rwork), |
| 37 | + iwork: None, |
| 38 | + } |
| 39 | + } |
19 | 40 |
|
20 | | - let mut work: Vec<MaybeUninit<Self>> = vec_uninit(4 * n as usize); |
21 | | - let mut iwork: Vec<MaybeUninit<i32>> = vec_uninit(n as usize); |
22 | | - let norm_type = match l { |
| 41 | + fn calc( |
| 42 | + &mut self, |
| 43 | + a: &[Self::Elem], |
| 44 | + anorm: <Self::Elem as Scalar>::Real, |
| 45 | + ) -> Result<<Self::Elem as Scalar>::Real> { |
| 46 | + let (n, _) = self.layout.size(); |
| 47 | + let mut rcond = <Self::Elem as Scalar>::Real::zero(); |
| 48 | + let mut info = 0; |
| 49 | + let norm_type = match self.layout { |
23 | 50 | MatrixLayout::C { .. } => NormType::Infinity, |
24 | 51 | MatrixLayout::F { .. } => NormType::One, |
25 | 52 | }; |
26 | 53 | unsafe { |
27 | | - $gecon( |
| 54 | + $con( |
28 | 55 | norm_type.as_ptr(), |
29 | 56 | &n, |
30 | 57 | AsPtr::as_ptr(a), |
31 | | - &l.lda(), |
| 58 | + &self.layout.lda(), |
32 | 59 | &anorm, |
33 | 60 | &mut rcond, |
34 | | - AsPtr::as_mut_ptr(&mut work), |
35 | | - AsPtr::as_mut_ptr(&mut iwork), |
| 61 | + AsPtr::as_mut_ptr(&mut self.work), |
| 62 | + AsPtr::as_mut_ptr(self.rwork.as_mut().unwrap()), |
36 | 63 | &mut info, |
37 | 64 | ) |
38 | 65 | }; |
39 | 66 | info.as_lapack_result()?; |
40 | | - |
41 | 67 | Ok(rcond) |
42 | 68 | } |
43 | 69 | } |
44 | 70 | }; |
45 | 71 | } |
| 72 | +impl_rcond_work_c!(c64, lapack_sys::zgecon_); |
| 73 | +impl_rcond_work_c!(c32, lapack_sys::cgecon_); |
| 74 | + |
| 75 | +macro_rules! impl_rcond_work_r { |
| 76 | + ($r:ty, $con:path) => { |
| 77 | + impl RcondWorkImpl for RcondWork<$r> { |
| 78 | + type Elem = $r; |
46 | 79 |
|
47 | | -impl_rcond_real!(f32, lapack_sys::sgecon_); |
48 | | -impl_rcond_real!(f64, lapack_sys::dgecon_); |
| 80 | + fn new(layout: MatrixLayout) -> Self { |
| 81 | + let (n, _) = layout.size(); |
| 82 | + let work = vec_uninit(4 * n as usize); |
| 83 | + let iwork = vec_uninit(n as usize); |
| 84 | + RcondWork { |
| 85 | + layout, |
| 86 | + work, |
| 87 | + rwork: None, |
| 88 | + iwork: Some(iwork), |
| 89 | + } |
| 90 | + } |
49 | 91 |
|
50 | | -macro_rules! impl_rcond_complex { |
51 | | - ($scalar:ty, $gecon:path) => { |
52 | | - impl Rcond_ for $scalar { |
53 | | - fn rcond(l: MatrixLayout, a: &[Self], anorm: Self::Real) -> Result<Self::Real> { |
54 | | - let (n, _) = l.size(); |
55 | | - let mut rcond = Self::Real::zero(); |
| 92 | + fn calc( |
| 93 | + &mut self, |
| 94 | + a: &[Self::Elem], |
| 95 | + anorm: <Self::Elem as Scalar>::Real, |
| 96 | + ) -> Result<<Self::Elem as Scalar>::Real> { |
| 97 | + let (n, _) = self.layout.size(); |
| 98 | + let mut rcond = <Self::Elem as Scalar>::Real::zero(); |
56 | 99 | let mut info = 0; |
57 | | - let mut work: Vec<MaybeUninit<Self>> = vec_uninit(2 * n as usize); |
58 | | - let mut rwork: Vec<MaybeUninit<Self::Real>> = vec_uninit(2 * n as usize); |
59 | | - let norm_type = match l { |
| 100 | + let norm_type = match self.layout { |
60 | 101 | MatrixLayout::C { .. } => NormType::Infinity, |
61 | 102 | MatrixLayout::F { .. } => NormType::One, |
62 | 103 | }; |
63 | 104 | unsafe { |
64 | | - $gecon( |
| 105 | + $con( |
65 | 106 | norm_type.as_ptr(), |
66 | 107 | &n, |
67 | 108 | AsPtr::as_ptr(a), |
68 | | - &l.lda(), |
| 109 | + &self.layout.lda(), |
69 | 110 | &anorm, |
70 | 111 | &mut rcond, |
71 | | - AsPtr::as_mut_ptr(&mut work), |
72 | | - AsPtr::as_mut_ptr(&mut rwork), |
| 112 | + AsPtr::as_mut_ptr(&mut self.work), |
| 113 | + AsPtr::as_mut_ptr(self.iwork.as_mut().unwrap()), |
73 | 114 | &mut info, |
74 | 115 | ) |
75 | 116 | }; |
76 | 117 | info.as_lapack_result()?; |
77 | | - |
78 | 118 | Ok(rcond) |
79 | 119 | } |
80 | 120 | } |
81 | 121 | }; |
82 | 122 | } |
83 | | - |
84 | | -impl_rcond_complex!(c32, lapack_sys::cgecon_); |
85 | | -impl_rcond_complex!(c64, lapack_sys::zgecon_); |
| 123 | +impl_rcond_work_r!(f64, lapack_sys::dgecon_); |
| 124 | +impl_rcond_work_r!(f32, lapack_sys::sgecon_); |
0 commit comments