1 package Maasha::Matrix;
3 # Copyright (C) 2007 Martin A. Hansen.
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 # http://www.gnu.org/copyleft/gpl.html
22 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> DESCRIPTION <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
25 # This modules contains subroutines for simple matrix manipulations.
28 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
34 use Storable qw( dclone );
38 use vars qw ( @ISA @EXPORT );
41 @ISA = qw( Exporter );
49 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> SUBROUTINES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
54 # Martin A. Hansen, April 2007
56 # returns the dimensions of a matrix: rows x cols
58 my ( $matrix, # AoA data structure
65 $rows = scalar @{ $matrix };
66 $cols = scalar @{ $matrix->[ 0 ] };
68 return wantarray ? ( $rows, $cols ) : [ $rows, $cols ];
74 # Martin A. Hansen, April 2007.
76 # Checks that the matrix of even columns.
77 # return 1 if ok else 0.
79 my ( $matrix, # AoA data structure
84 my ( $dims, $row, $check );
86 $dims = matrix_dims( $matrix );
88 $check = $dims->[ COLS ];
90 foreach $row ( @{ $matrix } ) {
91 return 0 if scalar @{ $row } != $check;
100 # Martin A. Hansen, April 2007.
102 # For each column in a given matrix print:
104 my ( $matrix, # AoA data structure
107 my ( $dims, $i, $col, $list, $type, $sort, $uniq, $min, $max, $mean );
109 die qq(ERROR: cannot summarize uneven matrix\n) if not matrix_check( $matrix );
111 $dims = matrix_dims( $matrix );
113 print join( "\t", "TYPE", "LEN", "UNIQ", "SORT", "MIN", "MAX", "MEAN" ), "\n";
115 for ( $i = 0; $i < $dims->[ COLS ]; $i++ )
117 $col = cols_get( $matrix, $i, $i );
118 $list = matrix_flip( $col )->[ 0 ];
120 if ( list_check_numeric( $list ) ) {
126 if ( list_check_sort( $list, $type ) ) {
132 if ( $type eq "num" )
134 if ( $sort eq "yes" )
137 $max = $list->[ -1 ];
141 ( $min, $max ) = Maasha::Calc::minmax( $list );
144 $mean = sprintf( "%.2f", Maasha::Calc::mean( $list ) );
153 $uniq = list_uniq( $list );
155 print join( "\t", $type, $dims->[ ROWS ], $uniq, $sort, $min, $max, $mean ), "\n";
162 # Martin A. Hansen, April 2007
164 # flips a matrix making rows to columns and visa versa.
166 my ( $matrix, # AoA data structure
171 my ( $i, $c, $dims, $AoA );
173 die qq(ERROR: cannot flip uneven matrix\n) if not matrix_check( $matrix );
175 $dims = matrix_dims( $matrix );
177 for ( $i = 0; $i < $dims->[ ROWS ]; $i++ )
179 for ( $c = 0; $c < $dims->[ COLS ]; $c++ ) {
180 $AoA->[ $c ]->[ $i ] = $matrix->[ $i ]->[ $c ];
184 @{ $matrix } = @{ $AoA };
186 return wantarray ? @{ $matrix } : $matrix;
190 sub matrix_deflate_rows
192 # Martin A. Hansen, September 2009.
194 # Reduces the number of elements in all rows,
195 # by collectiong elements in buckets that are
198 my ( $matrix, # AoA data structure
206 foreach $row ( @{ $matrix } ) {
207 list_deflate( $row, $new_size );
212 sub matrix_deflate_cols
214 # Martin A. Hansen, September 2009.
216 # Reduces the number of elements in all columns,
217 # by collectiong elements in buckets that are
220 my ( $matrix, # AoA data structure
228 matrix_flip( $matrix );
230 foreach $col ( @{ $matrix } ) {
231 list_deflate( $col, $new_size );
234 matrix_flip( $matrix );
238 sub matrix_rotate_right
240 # Martin A. Hansen, April 2007
242 # Rotates elements in a given matrix a given
243 # number of positions to the right by popping columns,
244 # from the right matrix edge and prefixed to the left edge.
246 my ( $matrix, # AoA data structure
247 $shift, # number of shifts - DEFAULT=1
252 my ( $i, $dims, $col, $AoA );
256 die qq(ERROR: cannot right rotate uneven matrix\n) if not matrix_check( $matrix );
258 $dims = matrix_dims( $matrix );
260 for ( $i = 0; $i < $shift; $i++ )
262 $col = cols_get( $matrix, $dims->[ COLS ] - 1, $dims->[ COLS ] - 1 );
263 $AoA = cols_get( $matrix, 0, $dims->[ COLS ] - 2 );
265 cols_unshift( $AoA, $col );
270 return wantarray ? @{ $matrix } : $matrix;
274 sub matrix_rotate_left
276 # Martin A. Hansen, April 2007
278 # Rotates elements in a given matrix a given
279 # number of positions to the left while columns
280 # are shifted from the left matrix edge and appended,
283 my ( $matrix, # AoA data structure
284 $shift, # number of shifts - DEFAULT=1
289 my ( $i, $dims, $col, $AoA );
293 die qq(ERROR: cannot right rotate uneven matrix\n) if not matrix_check( $matrix );
295 $dims = matrix_dims( $matrix );
297 for ( $i = 0; $i < $shift; $i++ )
299 $col = cols_get( $matrix, 0, 0 );
300 $AoA = cols_get( $matrix, 1, $dims->[ COLS ] - 1 );
302 cols_push( $AoA, $col );
307 return wantarray ? @{ $matrix } : $matrix;
313 # Martin A. Hansen, April 2007
315 # Rotates elements in a given matrix a given
316 # number of positions up while rows are shifted
317 # from the top of the matrix to the bottom.
319 my ( $matrix, # AoA data structure
320 $shift, # number of shifts - DEFAULT=1
325 my ( $dims, $i, $row, $AoA );
329 $dims = matrix_dims( $matrix );
331 for ( $i = 0; $i < $shift; $i++ )
333 $row = rows_get( $matrix, 0, 0 );
334 $AoA = rows_get( $matrix, 1, $dims->[ ROWS ] - 1 );
336 rows_push( $AoA, dclone $row );
341 return wantarray ? @{ $matrix } : $matrix;
345 sub matrix_rotate_down
347 # Martin A. Hansen, April 2007
349 # Rotates elements in a given matrix a given
350 # number of positions down while rows are shifted
351 # from the bottom matrix edge to the top edge.
353 my ( $matrix, # AoA data structure
354 $shift, # number of shifts - DEFAULT=1
359 my ( $dims, $i, $row, $AoA );
363 $dims = matrix_dims( $matrix );
365 for ( $i = 0; $i < $shift; $i++ )
367 $row = rows_get( $matrix, $dims->[ ROWS ] - 1, $dims->[ ROWS ] - 1 );
368 $AoA = rows_get( $matrix, 0, $dims->[ ROWS ] - 2 );
370 rows_unshift( $AoA, $row );
375 return wantarray ? @{ $matrix } : $matrix;
381 # Martin A. Hansen, April 2007
383 # returns a submatrix sliced from a given matrix
385 my ( $matrix, # AoA data structure
386 $row_beg, # first row - OPTIONAL (default 0)
387 $row_end, # last row - OPTIONAL (default last row)
388 $col_beg, # first col - OPTIONAL (default 0)
389 $col_end, # last col - OPTIONAL (default last col)
394 my ( $submatrix, $subsubmatrix );
396 $submatrix = rows_get( $matrix, $row_beg, $row_end );
397 $subsubmatrix = cols_get( $submatrix, $col_beg, $col_end );
399 return wantarray ? @{ $subsubmatrix } : $subsubmatrix;
405 # Martin A. Hansen, April 2008.
407 # Returns a single row from a given matrix.
409 my ( $matrix, # AoA data structure
415 my ( $dims, $i, @list );
417 $dims = matrix_dims( $matrix );
419 Maasha::Common::error( qq(Row->$row outside of matrix->$dims->[ ROWS ]) ) if $row > $dims->[ ROWS ];
421 @list = @{ $matrix->[ $row ] };
423 return wantarray ? @list : \@list;
429 # Martin A. Hansen, April 2007
431 # returns a range of requested rows from a given matrix.
433 my ( $matrix, # AoA data structure
434 $row_beg, # first row - OPTIONAL (default 0)
435 $row_end, # last row - OPTIONAL (default last row)
444 if ( not defined $row_end ) {
445 $row_end = scalar @{ $matrix };
448 if ( $row_end >= scalar @{ $matrix } )
450 warn qq(WARNING: row end larger than matrix\n);
451 $row_end = scalar( @{ $matrix } ) - 1;
454 die qq(ERROR: row begin "$row_beg" larger than row end "$row_end"\n) if $row_end < $row_beg;
456 if ( $row_beg == 0 and $row_end == scalar( @{ $matrix } ) - 1 ) {
457 @rows = @{ $matrix };
459 @rows = @{ $matrix }[ $row_beg .. $row_end ];
462 return wantarray ? @rows : \@rows;
468 # Martin A. Hansen, April 2008.
470 # Returns a single column from a given matrix.
472 my ( $matrix, # AoA data structure
473 $col, # column to get
478 my ( $dims, $i, @list );
480 $dims = matrix_dims( $matrix );
482 Maasha::Common::error( qq(Column->$col outside of matrix->$dims->[ COLS ]) ) if $col > $dims->[ COLS ];
484 for ( $i = 0; $i < $dims->[ ROWS ]; $i++ ) {
485 push @list, $matrix->[ $i ]->[ $col ];
488 return wantarray ? @list : \@list;
494 # Martin A. Hansen, April 2007.
496 # returns a range of requested columns from a given matrix
498 my ( $matrix, # AoA data structure
499 $col_beg, # first column - OPTIONAL (default 0)
500 $col_end, # last column - OPTIONAL (default last column)
505 my ( $dims, @cols, $row, @AoA );
507 $dims = matrix_dims( $matrix );
511 if ( not defined $col_end ) {
512 $col_end = $dims->[ COLS ] - 1;
515 if ( $col_end > $dims->[ COLS ] - 1 )
517 warn qq(WARNING: column end larger than matrix\n);
518 $col_end = $dims->[ COLS ] - 1;
521 die qq(ERROR: column begin "$col_beg" larger than column end "$col_end"\n) if $col_end < $col_beg;
523 if ( $col_beg == 0 and $col_end == $dims->[ COLS ] - 1 )
529 foreach $row ( @{ $matrix } )
531 @cols = @{ $row }[ $col_beg .. $col_end ];
533 push @AoA, [ @cols ];
537 return wantarray ? @AoA : \@AoA;
549 $list = cols_get( $matrix, $col, $col );
550 $list = matrix_flip( $list )->[ 0 ];
552 die qq(ERROR: cannot sum non-nummerical column\n);
554 $sum = Maasha::Calc::sum( $list );
562 # Martin A. Hansen, April 2007.
564 # Appends one or more rows to a matrix.
566 my ( $matrix, # AoA data structure
567 $rows, # list of rows
572 push @{ $matrix }, @{ $rows };
574 return wantarray ? @{ $matrix } : $matrix;
580 # Martin A. Hansen, April 2007.
582 # Prefixes one or more rows to a matrix.
584 my ( $matrix, # AoA data structure
585 $rows, # list of rows
590 unshift @{ $matrix }, @{ $rows };
592 return wantarray ? @{ $matrix } : $matrix;
598 # Martin A. Hansen, April 2007.
600 # Appends one or more lists as columns to a matrix.
602 my ( $matrix, # AoA data structure
603 $cols, # list of columns
608 my ( $dims_matrix, $dims_cols, $i );
610 $dims_matrix = matrix_dims( $matrix );
611 $dims_cols = matrix_dims( $cols );
613 die qq(ERROR: Cannot merge columns with different row count\n) if $dims_matrix->[ ROWS ] != $dims_cols->[ ROWS ];
615 for ( $i = 0; $i < $dims_matrix->[ ROWS ]; $i++ )
617 push @{ $matrix->[ $i ] }, @{ $cols->[ $i ] };
620 return wantarray ? @{ $matrix } : $matrix;
626 # Martin A. Hansen, April 2007.
628 # Prefixes one or more lists as columns to a matrix.
630 my ( $matrix, # AoA data structure
631 $cols, # list of columns
636 my ( $dims_matrix, $dims_cols, $i );
638 $dims_matrix = matrix_dims( $matrix );
639 $dims_cols = matrix_dims( $cols );
641 die qq(ERROR: Cannot merge columns with different row count\n) if $dims_matrix->[ ROWS ] != $dims_cols->[ ROWS ];
643 for ( $i = 0; $i < $dims_matrix->[ ROWS ]; $i++ ) {
644 unshift @{ $matrix->[ $i ] }, @{ $cols->[ $i ] };
647 return wantarray ? @{ $matrix } : $matrix;
653 # Martin A. Hansen, April 2007.
655 # Given a matrix and a range of rows, rotates these rows
656 # left by shifting a given number of elements from
657 # the first position to the last.
659 my ( $matrix, # AoA data structure
660 $beg, # first row to shift
661 $end, # last row to shit
662 $shift, # number of shifts - DEFAULT=1
671 for ( $i = $beg; $i <= $end; $i++ )
673 $row = rows_get( $matrix, $i, $i );
675 for ( $c = 0; $c < $shift; $c++ )
677 $row = list_rotate_left( @{ $row } );
678 $matrix->[ $i ] = $row;
682 return wantarray ? @{ $matrix } : $matrix;
686 sub rows_rotate_right
688 # Martin A. Hansen, April 2007.
690 # Given a matrix and a range of rows, rotates these rows
691 # right by shifting a given number of elements from the
692 # last position to the first.
694 my ( $matrix, # AoA data structure
695 $beg, # first row to shift
696 $end, # last row to shit
697 $shift, # number of shifts - DEFAULT=1
702 my ( $dims, $i, $c, $row );
706 $dims = matrix_dims( $matrix );
708 die qq(ERROR: end < beg: $end < $beg\n) if $end < $beg;
709 die qq(ERROR: row outside matrix\n) if $end >= $dims->[ ROWS ];
711 for ( $i = $beg; $i <= $end; $i++ )
713 $row = rows_get( $matrix, $i, $i );
715 for ( $c = 0; $c < $shift; $c++ )
717 $row = list_rotate_right( @{ $row } );
718 $matrix->[ $i ] = $row;
722 return wantarray ? @{ $matrix } : $matrix;
728 # Martin A. Hansen, April 2007.
730 # Given a matrix and a range of columns, rotates these columns
731 # ups by shifting the the first cell of each row from the
732 # first position to the last.
734 my ( $matrix, # AoA data structure
735 $beg, # first row to shift
736 $end, # last row to shit
737 $shift, # number of shifts - DEFAULT=1
742 my ( $dims, $i, $c, $cols_pre, $col_select, $cols_post, $list );
746 $dims = matrix_dims( $matrix );
748 $cols_pre = cols_get( $matrix, 0, $beg - 1 ) if $beg > 0;
749 $cols_post = cols_get( $matrix, $end + 1, $dims->[ COLS ] - 1 ) if $end < $dims->[ COLS ] - 1;
751 for ( $i = $beg; $i <= $end; $i++ )
753 $col_select = cols_get( $matrix, $i, $i );
755 $list = matrix_flip( $col_select )->[ 0 ];
757 for ( $c = 0; $c < $shift; $c++ ) {
758 $list = list_rotate_left( $list );
761 $col_select = matrix_flip( [ $list ] );
764 cols_push( $cols_pre, $col_select );
766 $cols_pre = $col_select;
770 cols_push( $cols_pre, $cols_post ) if $cols_post;
774 return wantarray ? @{ $matrix } : $matrix;
780 # Martin A. Hansen, April 2007.
782 # Given a matrix and a range of columns, rotates these columns
783 # ups by shifting the the first cell of each row from the
784 # first position to the last.
786 my ( $matrix, # AoA data structure
787 $beg, # first row to shift
788 $end, # last row to shit
789 $shift, # number of shifts - DEFAULT=1
794 my ( $dims, $i, $c, $cols_pre, $col_select, $cols_post, $list );
798 $dims = matrix_dims( $matrix );
800 $cols_pre = cols_get( $matrix, 0, $beg - 1 ) if $beg > 0;
801 $cols_post = cols_get( $matrix, $end + 1, $dims->[ COLS ] - 1 ) if $end < $dims->[ COLS ] - 1;
803 for ( $i = $beg; $i <= $end; $i++ )
805 $col_select = cols_get( $matrix, $i, $i );
807 $list = matrix_flip( $col_select )->[ 0 ];
809 for ( $c = 0; $c < $shift; $c++ ) {
810 $list = list_rotate_right( $list );
813 $col_select = matrix_flip( [ $list ] );
816 cols_push( $cols_pre, $col_select );
818 $cols_pre = $col_select;
822 cols_push( $cols_pre, $cols_post ) if $cols_post;
826 return wantarray ? @{ $matrix } : $matrix;
832 # Martin A. Hansen, April 2007.
834 # given a list, shifts off the first element,
835 # and appends to the list, which is returned.
837 my ( $list, # list to rotate
840 my ( @new_list, $elem );
842 @new_list = @{ $list };
844 $elem = shift @new_list;
846 push @new_list, $elem;
848 return wantarray ? @new_list : \@new_list;
852 sub list_rotate_right
854 # Martin A. Hansen, April 2007.
856 # given a list, pops off the last element,
857 # and prefixes to the list, which is returned.
859 my ( $list, # list to rotate
862 my ( @new_list, $elem );
864 @new_list = @{ $list };
866 $elem = pop @new_list;
868 unshift @new_list, $elem;
870 return wantarray ? @new_list : \@new_list;
874 sub list_check_numeric
876 # Martin A. Hansen, April 2007.
878 # Checks if a given list only contains
879 # numerical elements. return 1 if numerical,
882 my ( $list, # list to check
889 foreach $elem ( @{ $list } ) {
890 return 0 if not Maasha::Calc::is_a_number( $elem );
899 # Martin A. Hansen, April 2007.
901 # Checks if a given list is sorted.
902 # If the sort type is not specified, we
903 # are going to check the type and make a guess.
904 # Returns 1 if sorted else 0.
906 my ( $list, # list to check
907 $type, # numerical of alphabetical
916 if ( list_check_numeric( $list ) ) {
924 if ( $type =~ /^a.*/i ) {
931 if ( @{ $list } > 1 )
935 for ( $i = 1; $i < @{ $list }; $i++ )
937 $cmp = $list->[ $i - 1 ] <=> $list->[ $i ];
939 return 0 if $cmp > 0;
944 for ( $i = 1; $i < @{ $list }; $i++ )
946 $cmp = $list->[ $i - 1 ] cmp $list->[ $i ];
948 return 0 if $cmp > 0;
959 # Martin A. Hansen, September 2009.
961 # Defaltes a list of values to a specified size
962 # and at the same time average the values.
964 my ( $list, # list to deflate
965 $new_size, # new number of elements in list
970 my ( $old_size, $bucket_size, $bucket_rest, $i, @new_list );
972 $old_size = scalar @{ $list };
974 Maasha::Common::error( qq(Can't shrink to a bigger list: $old_size < $new_size ) ) if $old_size < $new_size;
976 $bucket_size = int( $old_size / $new_size );
977 $bucket_rest = $old_size - ( $new_size * $bucket_size );
981 while ( $i < $new_size )
983 # push @new_list, [ @{ $list }[ $i * $bucket_size .. $i * $bucket_size + $bucket_size - 1 ] ];
984 push @new_list, Maasha::Calc::mean( [ @{ $list }[ $i * $bucket_size .. $i * $bucket_size + $bucket_size - 1 ] ] );
989 @{ $list } = @new_list;
995 # Martin A. Hansen, April 2007.
997 # returns the number of unique elements in a
1005 my ( %hash, $count );
1007 map { $hash{ $_ } = 1 } @{ $list };
1009 $count = scalar keys %hash;
1017 # Martin A. Hansen, April 2007.
1019 my ( $matrix, # AoA data structure
1023 my ( $dims, $list, $i, $max, $len, %hash, $elem, @list );
1025 $dims = matrix_dims( $matrix );
1027 $list = cols_get( $matrix, $col, $col );
1028 $list = matrix_flip( $list )->[ 0 ];
1032 for ( $i = 0; $i < @{ $list }; $i++ )
1034 $hash{ $list->[ $i ] }++;
1036 $len = length $list->[ $i ];
1038 $max = $len if $len > $max;
1043 if ( list_check_numeric( $list ) ) {
1044 @list = sort { $a <=> $b } @list;
1046 @list = sort { $a cmp $b } @list;
1049 foreach $elem ( @list )
1051 print $elem, " " x ( $max - length( $elem ) ),
1052 sprintf( " %6s ", $hash{ $elem } ),
1053 sprintf( "%.2f\n", ( $hash{ $elem } / $dims->[ ROWS ] ) * 100 );
1060 # Martin A. Hansen, July 2008.
1062 # Merge two given tables based on identifiers in a for each table
1063 # specified column which should contain a unique identifier.
1064 # Initially the tables are sorted and tab2 is merged onto tab1
1067 my ( $tab1, # table 1 - an AoA.
1068 $tab2, # table 2 - an AoA.
1069 $col1, # identifier in row1
1070 $col2, # identifier in row2
1071 $sort_type, # alphabetical or numeric comparison
1076 my ( $num, $cmp, $i, $c, @row_cpy, $max );
1081 if ( $sort_type =~ /num/i )
1085 @{ $tab1 } = sort { $a->[ $col1 ] <=> $b->[ $col1 ] } @{ $tab1 };
1086 @{ $tab2 } = sort { $a->[ $col2 ] <=> $b->[ $col2 ] } @{ $tab2 };
1090 @{ $tab1 } = sort { $a->[ $col1 ] cmp $b->[ $col1 ] } @{ $tab1 };
1091 @{ $tab2 } = sort { $a->[ $col2 ] cmp $b->[ $col2 ] } @{ $tab2 };
1097 while ( $i < @{ $tab1 } and $c < @{ $tab2 } )
1100 $cmp = $tab1->[ $i ]->[ $col1 ] <=> $tab2->[ $c ]->[ $col2 ];
1102 $cmp = $tab1->[ $i ]->[ $col1 ] cmp $tab2->[ $c ]->[ $col2 ];
1107 @row_cpy = @{ $tab2->[ $c ] };
1109 splice @row_cpy, $col2, 1;
1111 push @{ $tab1->[ $i ] }, @row_cpy;
1122 map { push @{ $tab1->[ $i ] }, "null" } 0 .. ( scalar @{ $tab2->[ $c ] } - 2 );
1128 map { push @{ $tab1->[ -1 ] }, "null" } 0 .. ( scalar @{ $tab1->[ 0 ] } - scalar @{ $tab1->[ -1 ] } + 1 );
1132 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> BINARY SEARCH <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
1137 # Martin A. Hansen, February 2008.
1139 # Uses binary search to locate the interval containing a
1140 # given number. The intervals are defined by begin and end
1141 # positions in seperate columns in a matrix. If a interval is
1142 # found then the index of that matrix row is returned, otherwise
1145 my ( $matrix, # data structure
1146 $col1, # column with interval begins
1147 $col2, # column with interval ends
1148 $num, # number to search for
1151 # Returns an integer.
1153 my ( $high, $low, $try );
1156 $high = @{ $matrix };
1158 while ( $low < $high )
1160 $try = int( ( $high + $low ) / 2 );
1162 # print "num->$num low->$low high->$high try->$try int1->$matrix->[ $try ]->[ $col1 ] int2->$matrix->[ $try ]->[ $col2 ]\n";
1164 if ( $num < $matrix->[ $try ]->[ $col1 ] ) {
1166 } elsif ( $num > $matrix->[ $try ]->[ $col2 ] ) {
1179 # Martin A. Hansen, February 2008.
1181 # Uses binary search to locate a number in a list of numbers.
1182 # If the number is found, then the index (the position of the number
1183 # in the list) is returned, otherwise -1 is returned.
1185 my ( $list, # list of numbers
1186 $num, # number to search for
1189 # Returns an integer.
1191 my ( $high, $low, $try );
1196 while ( $low < $high )
1198 $try = int( ( $high + $low ) / 2 );
1200 # print "num->$num low->$low high->$high try->$try int->$list->[ $try ]\n";
1202 if ( $num < $list->[ $try ] ) {
1204 } elsif ( $num > $list->[ $try ] ) {
1215 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> DISK SUBROUTINES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
1220 # Martin A. Hansen, April 2007
1222 # Reads tabular data from file into a matrix
1223 # AoA data structure.
1225 my ( $path, # full path to file with data
1226 $delimiter, # column delimiter - OPTIONAL (default tab)
1227 $comments, # regex for comment lines to skip - OPTIONAL
1228 $fields_ok, # list of fields to accept - OPTIONAL
1233 my ( $fh, $line, @fields, @AoA );
1235 $delimiter ||= "\t";
1237 $fh = Maasha::Filesys::file_read_open( $path );
1239 while ( $line = <$fh> )
1243 next if $comments and $line =~ /^$comments/;
1245 @fields = split /$delimiter/, $line;
1247 map { splice( @fields, $_, 1 ) } @{ $fields_ok } if $fields_ok;
1249 push @AoA, [ @fields ];
1254 return wantarray ? @AoA : \@AoA;
1260 # Martin A. Hansen, April 2007
1262 # Writes a tabular data structure to STDOUT or file.
1264 my ( $matrix, # AoA data structure
1265 $path, # full path to output file - OPTIONAL (default STDOUT)
1266 $delimiter, # column delimiter - OPTIONAL (default tab)
1271 $fh = Maasha::Filesys::file_write_open( $path ) if $path;
1273 $delimiter ||= "\t";
1275 foreach $row ( @{ $matrix } )
1278 print $fh join( $delimiter, @{ $row } ), "\n";
1280 print join( $delimiter, @{ $row } ), "\n";
1290 # Martin A. Hansen, April 2007.
1292 # stores a matrix to a binary file.
1294 my ( $path, # full path to file
1295 $matrix, # data structure
1298 Maasha::Filesys::file_store( $path, $matrix );
1304 # Martin A. Hansen, April 2007.
1306 # retrieves a matrix from a binary file
1308 my ( $path, # full path to file
1311 my $matrix = Maasha::Filesys::file_retrieve( $path );
1313 return wantarray ? @{ $matrix } : $matrix;
1317 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<