@@ -236,7 +236,7 @@ impl SparseBinMat {
236236 pub fn empty ( ) -> Self {
237237 Self {
238238 column_indices : Vec :: new ( ) ,
239- row_ranges : Vec :: new ( ) ,
239+ row_ranges : Vec :: new ( ) ,
240240 number_of_columns : 0 ,
241241 }
242242 }
@@ -290,6 +290,28 @@ impl SparseBinMat {
290290 self . number_of_ones ( ) == 0
291291 }
292292
293+ /// Inserts a new row at the end the matrix.
294+ ///
295+ /// This update the matrix inplace.
296+ ///
297+ /// # Example
298+ ///
299+ /// ```
300+ /// # use sparse_bin_mat::SparseBinMat;
301+ /// let rows = vec![vec![0, 1], vec![1, 2]];
302+ /// let mut matrix = SparseBinMat::new(3, rows);
303+ /// matrix.push_row(&[0, 2]);
304+ ///
305+ /// let rows = vec![vec![0, 1], vec![1, 2], vec![0, 2]];
306+ /// let expected = SparseBinMat::new(3, rows);
307+ ///
308+ /// assert_eq!(matrix, expected);
309+ /// ```
310+ pub fn push_row ( & mut self , row : & [ usize ] ) {
311+ self . row_ranges . push ( self . number_of_ones ( ) + row. len ( ) ) ;
312+ self . column_indices . extend_from_slice ( row) ;
313+ }
314+
293315 /// Returns the value at the given row and column
294316 /// or None if one of the index is out of bound.
295317 ///
@@ -536,7 +558,7 @@ impl SparseBinMat {
536558 /// ```
537559 /// # use sparse_bin_mat::SparseBinMat;
538560 /// let matrix = SparseBinMat::new(3, vec![vec![0, 1, 2], vec![0], vec![1, 2], vec![0, 2]]);
539- /// let expected = SparseBinMat::new(3, vec![vec![0, 1, 2], vec![1], vec![2], vec![] ]);
561+ /// let expected = SparseBinMat::new(3, vec![vec![0, 1, 2], vec![1], vec![2]]);
540562 /// assert_eq!(matrix.echelon_form(), expected);
541563 /// ```
542564 pub fn echelon_form ( & self ) -> Self {
@@ -559,28 +581,16 @@ impl SparseBinMat {
559581 /// # use sparse_bin_mat::SparseBinMat;
560582 /// let matrix = SparseBinMat::new(3, vec![vec![0, 1], vec![1, 2]]);
561583 ///
562- /// let rhs = SparseBinMat::new(3, vec![vec![0, 2]]);
563- /// let expected = SparseBinMat::new(2, vec![vec![0, 1]]);
584+ /// let rhs = SparseBinMat::new(3, vec![vec![0, 1], vec![0, 2]]);
585+ /// let expected = SparseBinMat::new(2, vec![vec![0], vec![0 , 1]]);
564586 /// assert_eq!(matrix.solve(&rhs), Some(expected));
565587 ///
566588 /// let rhs = SparseBinMat::new(3, vec![vec![0]]);
567589 /// assert!(matrix.solve(&rhs).is_none());
568590 /// ```
569591 pub fn solve ( & self , rhs : & SparseBinMat ) -> Option < Self > {
570- // Compute combined echelon form and transpose for easier iteration.
571- let matrix = self
572- . vertical_concat_with ( & rhs)
573- . transposed ( )
574- . echelon_form ( )
575- . transposed ( ) ;
576- // lhs are the rows corresponding to self.
577- let lhs = matrix
578- . keep_only_rows ( & ( 0 ..self . number_of_rows ( ) ) . collect_vec ( ) )
579- . unwrap ( ) ;
580- // We iterate throught the remaining rows (corresponding to rhs).
581- matrix
582- . rows ( )
583- . skip ( self . number_of_rows ( ) )
592+ let ( lhs, rhs) = self . prepare_matrices_to_solve ( rhs) ;
593+ rhs. rows ( )
584594 . map ( |row| lhs. solve_vec ( row) )
585595 . fold_options ( Vec :: new ( ) , |mut acc, row| {
586596 acc. push ( row) ;
@@ -589,6 +599,22 @@ impl SparseBinMat {
589599 . map ( |rows| Self :: new ( self . number_of_rows ( ) , rows) )
590600 }
591601
602+ fn prepare_matrices_to_solve ( & self , rhs : & SparseBinMat ) -> ( Self , Self ) {
603+ // Compute combined echelon form and transpose for easier iteration.
604+ let mut matrix = self . vertical_concat_with ( & rhs) . transposed ( ) . echelon_form ( ) ;
605+ if let Some ( first) = matrix. row ( matrix. number_of_rows ( ) - 1 ) . and_then ( |row| {
606+ row. as_slice ( )
607+ . first ( )
608+ . filter ( |first| * * first < self . number_of_rows ( ) - 1 )
609+ . cloned ( )
610+ } ) {
611+ for _ in 0 ..( self . number_of_rows ( ) - first - 1 ) {
612+ matrix. push_row ( & [ ] ) ;
613+ }
614+ }
615+ matrix. transposed ( ) . split_rows ( self . number_of_rows ( ) )
616+ }
617+
592618 /// Solves self * x = vec and returns x.
593619 fn solve_vec ( & self , vec : SparseBinSlice ) -> Option < Vec < usize > > {
594620 let mut vec = vec. to_vec ( ) ;
@@ -888,6 +914,104 @@ impl SparseBinMat {
888914 self . keep_only_rows ( & to_keep)
889915 }
890916
917+ /// Returns two matrices where the first one contains
918+ /// all rows until split and the second one contains all
919+ /// rows starting from split.
920+ ///
921+ /// # Example
922+ ///
923+ /// ```
924+ /// # use sparse_bin_mat::SparseBinMat;
925+ /// let matrix = SparseBinMat::new(5, vec![
926+ /// vec![0, 1, 2],
927+ /// vec![2, 3, 4],
928+ /// vec![0, 2, 4],
929+ /// vec![1, 3],
930+ /// vec![0, 1, 3],
931+ /// ]);
932+ /// let (top, bottom) = matrix.split_rows(2);
933+ ///
934+ /// let expected_top = SparseBinMat::new(5, vec![
935+ /// vec![0, 1, 2],
936+ /// vec![2, 3, 4],
937+ /// ]);
938+ /// assert_eq!(top, expected_top);
939+ ///
940+ /// let expected_bottom = SparseBinMat::new(5, vec![
941+ /// vec![0, 2, 4],
942+ /// vec![1, 3],
943+ /// vec![0, 1, 3],
944+ /// ]);
945+ /// assert_eq!(bottom, expected_bottom);
946+ /// ```
947+ pub fn split_rows ( & self , split : usize ) -> ( Self , Self ) {
948+ ( self . split_rows_top ( split) , self . split_rows_bottom ( split) )
949+ }
950+
951+ /// Returns a matrix that contains all rows until split.
952+ ///
953+ ///
954+ /// # Example
955+ ///
956+ /// ```
957+ /// # use sparse_bin_mat::SparseBinMat;
958+ /// let matrix = SparseBinMat::new(5, vec![
959+ /// vec![0, 1, 2],
960+ /// vec![2, 3, 4],
961+ /// vec![0, 2, 4],
962+ /// vec![1, 3],
963+ /// vec![0, 1, 3],
964+ /// ]);
965+ /// let top = matrix.split_rows_top(1);
966+ ///
967+ /// let expected_top = SparseBinMat::new(5, vec![
968+ /// vec![0, 1, 2],
969+ /// ]);
970+ /// assert_eq!(top, expected_top);
971+ /// ```
972+ pub fn split_rows_top ( & self , split : usize ) -> Self {
973+ let row_ranges = self . row_ranges [ ..=split] . to_vec ( ) ;
974+ let column_indices =
975+ self . column_indices [ ..row_ranges. last ( ) . cloned ( ) . unwrap_or ( 0 ) ] . to_vec ( ) ;
976+ Self {
977+ row_ranges,
978+ column_indices,
979+ number_of_columns : self . number_of_columns ,
980+ }
981+ }
982+
983+ /// Returns a matrix that contains all rows starting from split.
984+ ///
985+ /// # Example
986+ ///
987+ /// ```
988+ /// # use sparse_bin_mat::SparseBinMat;
989+ /// let matrix = SparseBinMat::new(5, vec![
990+ /// vec![0, 1, 2],
991+ /// vec![2, 3, 4],
992+ /// vec![0, 2, 4],
993+ /// vec![1, 3],
994+ /// vec![0, 1, 3],
995+ /// ]);
996+ /// let bottom = matrix.split_rows_bottom(3);
997+ ///
998+ /// let expected_bottom = SparseBinMat::new(5, vec![
999+ /// vec![1, 3],
1000+ /// vec![0, 1, 3],
1001+ /// ]);
1002+ /// assert_eq!(bottom, expected_bottom);
1003+ /// ```
1004+ pub fn split_rows_bottom ( & self , split : usize ) -> Self {
1005+ let row_ranges = self . row_ranges [ split..] . to_vec ( ) ;
1006+ let column_indices =
1007+ self . column_indices [ row_ranges. first ( ) . cloned ( ) . unwrap_or ( 0 ) ..] . to_vec ( ) ;
1008+ Self {
1009+ row_ranges : row_ranges. iter ( ) . map ( |r| r - row_ranges[ 0 ] ) . collect ( ) ,
1010+ column_indices,
1011+ number_of_columns : self . number_of_columns ,
1012+ }
1013+ }
1014+
8911015 /// Returns a new matrix keeping only the given columns or an error
8921016 /// if columns are out of bound, unsorted or not unique.
8931017 ///
@@ -1120,7 +1244,7 @@ mod test {
11201244 ) ;
11211245 let b = SparseBinMat :: new ( 6 , vec ! [ vec![ 0 ] , vec![ 1 , 5 ] ] ) ;
11221246 let solution = a. solve ( & b) . unwrap ( ) ;
1123- let expected = SparseBinMat :: new ( 9 , vec ! [ vec![ 0 , 1 , 2 , 4 , 5 ] , vec![ 1 , 4 , 7 ] ] ) ;
1247+ let expected = SparseBinMat :: new ( 9 , vec ! [ vec![ 0 , 1 , 2 , 4 , 5 ] , vec![ 1 , 4 , 6 ] ] ) ;
11241248 assert_eq ! ( solution, expected) ;
11251249 }
11261250
0 commit comments