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