1
1
//! Least squares
2
2
3
- use crate :: { error:: * , layout:: MatrixLayout } ;
3
+ use crate :: { error:: * , layout:: * } ;
4
4
use cauchy:: * ;
5
5
use num_traits:: { ToPrimitive , Zero } ;
6
6
@@ -46,16 +46,37 @@ macro_rules! impl_least_squares_real {
46
46
b_layout: MatrixLayout ,
47
47
b: & mut [ Self ] ,
48
48
) -> Result <LeastSquaresOutput <Self >> {
49
- let m = a_layout. lda( ) ;
50
- let n = a_layout. len( ) ;
49
+ // Minimize |b - Ax|_2
50
+ //
51
+ // where
52
+ // A : (m, n)
53
+ // b : (m, p)
54
+ // x : (n, p)
55
+ let ( m, n) = a_layout. size( ) ;
56
+ let ( m_, p) = b_layout. size( ) ;
51
57
let k = m. min( n) ;
52
- if ( m as usize ) > b. len( )
53
- || ( n as usize ) > b. len( )
54
- || a_layout. lapacke_layout( ) != b_layout. lapacke_layout( )
55
- {
56
- return Err ( Error :: InvalidShape ) ;
57
- }
58
- let ( b_lda, nrhs) = b_layout. size( ) ;
58
+ assert_eq!( m, m_) ;
59
+
60
+ // Transpose if a is C-continuous
61
+ let mut a_t = None ;
62
+ let a_layout = match a_layout {
63
+ MatrixLayout :: C { .. } => {
64
+ a_t = Some ( vec![ Self :: zero( ) ; a. len( ) ] ) ;
65
+ transpose( a_layout, a, a_t. as_mut( ) . unwrap( ) )
66
+ }
67
+ MatrixLayout :: F { .. } => a_layout,
68
+ } ;
69
+
70
+ // Transpose if b is C-continuous
71
+ let mut b_t = None ;
72
+ let b_layout = match b_layout {
73
+ MatrixLayout :: C { .. } => {
74
+ b_t = Some ( vec![ Self :: zero( ) ; b. len( ) ] ) ;
75
+ transpose( b_layout, b, b_t. as_mut( ) . unwrap( ) )
76
+ }
77
+ MatrixLayout :: F { .. } => b_layout,
78
+ } ;
79
+
59
80
let rcond: Self :: Real = -1. ;
60
81
let mut singular_values: Vec <Self :: Real > = vec![ Self :: Real :: zero( ) ; k as usize ] ;
61
82
let mut rank: i32 = 0 ;
@@ -67,11 +88,11 @@ macro_rules! impl_least_squares_real {
67
88
$gelsd(
68
89
m,
69
90
n,
70
- nrhs ,
71
- a ,
72
- m ,
73
- b ,
74
- b_lda ,
91
+ p ,
92
+ a_t . as_mut ( ) . map ( |v| v . as_mut_slice ( ) ) . unwrap_or ( a ) ,
93
+ a_layout . lda ( ) ,
94
+ b_t . as_mut ( ) . map ( |v| v . as_mut_slice ( ) ) . unwrap_or ( b ) ,
95
+ b_layout . lda ( ) ,
75
96
& mut singular_values,
76
97
rcond,
77
98
& mut rank,
@@ -90,11 +111,11 @@ macro_rules! impl_least_squares_real {
90
111
$gelsd(
91
112
m,
92
113
n,
93
- nrhs ,
94
- a ,
95
- m ,
96
- b ,
97
- b_lda ,
114
+ p ,
115
+ a_t . as_mut ( ) . map ( |v| v . as_mut_slice ( ) ) . unwrap_or ( a ) ,
116
+ a_layout . lda ( ) ,
117
+ b_t . as_mut ( ) . map ( |v| v . as_mut_slice ( ) ) . unwrap_or ( b ) ,
118
+ b_layout . lda ( ) ,
98
119
& mut singular_values,
99
120
rcond,
100
121
& mut rank,
@@ -105,6 +126,12 @@ macro_rules! impl_least_squares_real {
105
126
) ;
106
127
info. as_lapack_result( ) ?;
107
128
129
+ // Skip a_t -> a transpose because A has been destroyed
130
+ // Re-transpose b
131
+ if let Some ( b_t) = b_t {
132
+ transpose( b_layout, & b_t, b) ;
133
+ }
134
+
108
135
Ok ( LeastSquaresOutput {
109
136
singular_values,
110
137
rank,
0 commit comments