File tree Expand file tree Collapse file tree 2 files changed +56
-2
lines changed
Expand file tree Collapse file tree 2 files changed +56
-2
lines changed Original file line number Diff line number Diff line change @@ -3293,14 +3293,17 @@ impl LinearAlgebra<Matrix> for Matrix {
32933293 ///
32943294 /// Implementation of [RosettaCode](https://rosettacode.org/wiki/Reduced_row_echelon_form)
32953295 fn rref ( & self ) -> Matrix {
3296+ let max_abs = self . data . iter ( ) . fold ( 0f64 , |acc, & x| acc. max ( x. abs ( ) ) ) ;
3297+ let epsilon = ( max_abs * 1e-12 ) . max ( 1e-15 ) ;
3298+
32963299 let mut lead = 0usize ;
32973300 let mut result = self . clone ( ) ;
32983301 ' outer: for r in 0 ..self . row {
32993302 if self . col <= lead {
33003303 break ;
33013304 }
33023305 let mut i = r;
3303- while result[ ( i, lead) ] == 0f64 {
3306+ while result[ ( i, lead) ] . abs ( ) < epsilon {
33043307 i += 1 ;
33053308 if self . row == i {
33063309 i = r;
@@ -3314,7 +3317,7 @@ impl LinearAlgebra<Matrix> for Matrix {
33143317 result. swap ( i, r, Row ) ;
33153318 }
33163319 let tmp = result[ ( r, lead) ] ;
3317- if tmp != 0f64 {
3320+ if tmp. abs ( ) > epsilon {
33183321 unsafe {
33193322 result. row_mut ( r) . iter_mut ( ) . for_each ( |t| * ( * t) /= tmp) ;
33203323 }
Original file line number Diff line number Diff line change @@ -111,3 +111,54 @@ fn test_kronecker() {
111111 let c1 = a1. kronecker ( & b1) ;
112112 assert_eq ! ( c1, ml_matrix( "0 5 0 10;6 7 12 14;0 15 0 20;18 21 24 28" ) ) ;
113113}
114+
115+ #[ test]
116+ fn test_rref ( ) {
117+ let a = ml_matrix (
118+ r#"
119+ -3 2 -1 -1;
120+ 6 -6 7 -7;
121+ 3 -4 4 -6"# ,
122+ ) ;
123+ let b = a. rref ( ) ;
124+
125+ assert_eq ! (
126+ b,
127+ ml_matrix(
128+ r#"
129+ 1 0 0 2;
130+ 0 1 0 2;
131+ 0 0 1 -1"#
132+ )
133+ ) ;
134+ }
135+
136+ #[ test]
137+ fn test_rref_unstable ( ) {
138+ let epsilon = 1e-10 ;
139+
140+ // this matrix used to become unstable during rref
141+ let a = ml_matrix (
142+ r#"
143+ 1 1 0 0 0 1 0 1 31;
144+ 1 1 1 1 0 0 1 1 185;
145+ 0 0 1 0 0 1 1 1 165;
146+ 1 0 1 0 1 1 0 1 32;
147+ 1 0 1 0 0 0 1 1 174;
148+ 0 0 1 0 1 1 1 1 171;
149+ 0 1 1 0 1 1 0 1 27;
150+ 1 0 0 1 0 1 0 0 20;
151+ 1 0 1 1 0 1 0 0 23"# ,
152+ ) ;
153+
154+ let b = a. rref ( ) ;
155+
156+ // creating a row like "0 0 0 0 0 0 0 0 1" will "prove" 0 == 1
157+ // which is a tell of numeric instability
158+ for row in 0 ..b. row {
159+ let ends_in_1 = ( b[ ( row, b. col - 1 ) ] - 1.0 ) . abs ( ) < epsilon;
160+ let rest_zeroes = ( 0 ..b. col - 1 ) . all ( |col| b[ ( row, col) ] . abs ( ) < epsilon) ;
161+
162+ assert ! ( !( ends_in_1 && rest_zeroes) ) ;
163+ }
164+ }
You can’t perform that action at this time.
0 commit comments