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 ];
186 return wantarray ? @{ $matrix } : $matrix;
190 sub matrix_rotate_right
192 # Martin A. Hansen, April 2007
194 # Rotates elements in a given matrix a given
195 # number of positions to the right by popping columns,
196 # from the right matrix edge and prefixed to the left edge.
198 my ( $matrix, # AoA data structure
199 $shift, # number of shifts - DEFAULT=1
204 my ( $i, $dims, $col, $AoA );
208 die qq(ERROR: cannot right rotate uneven matrix\n) if not matrix_check( $matrix );
210 $dims = matrix_dims( $matrix );
212 for ( $i = 0; $i < $shift; $i++ )
214 $col = cols_get( $matrix, $dims->[ COLS ] - 1, $dims->[ COLS ] - 1 );
215 $AoA = cols_get( $matrix, 0, $dims->[ COLS ] - 2 );
217 cols_unshift( $AoA, $col );
222 return wantarray ? @{ $matrix } : $matrix;
226 sub matrix_rotate_left
228 # Martin A. Hansen, April 2007
230 # Rotates elements in a given matrix a given
231 # number of positions to the left while columns
232 # are shifted from the left matrix edge and appended,
235 my ( $matrix, # AoA data structure
236 $shift, # number of shifts - DEFAULT=1
241 my ( $i, $dims, $col, $AoA );
245 die qq(ERROR: cannot right rotate uneven matrix\n) if not matrix_check( $matrix );
247 $dims = matrix_dims( $matrix );
249 for ( $i = 0; $i < $shift; $i++ )
251 $col = cols_get( $matrix, 0, 0 );
252 $AoA = cols_get( $matrix, 1, $dims->[ COLS ] - 1 );
254 cols_push( $AoA, $col );
259 return wantarray ? @{ $matrix } : $matrix;
265 # Martin A. Hansen, April 2007
267 # Rotates elements in a given matrix a given
268 # number of positions up while rows are shifted
269 # from the top of the matrix to the bottom.
271 my ( $matrix, # AoA data structure
272 $shift, # number of shifts - DEFAULT=1
277 my ( $dims, $i, $row, $AoA );
281 $dims = matrix_dims( $matrix );
283 for ( $i = 0; $i < $shift; $i++ )
285 $row = rows_get( $matrix, 0, 0 );
286 $AoA = rows_get( $matrix, 1, $dims->[ ROWS ] - 1 );
288 rows_push( $AoA, dclone $row );
293 return wantarray ? @{ $matrix } : $matrix;
297 sub matrix_rotate_down
299 # Martin A. Hansen, April 2007
301 # Rotates elements in a given matrix a given
302 # number of positions down while rows are shifted
303 # from the bottom matrix edge to the top edge.
305 my ( $matrix, # AoA data structure
306 $shift, # number of shifts - DEFAULT=1
311 my ( $dims, $i, $row, $AoA );
315 $dims = matrix_dims( $matrix );
317 for ( $i = 0; $i < $shift; $i++ )
319 $row = rows_get( $matrix, $dims->[ ROWS ] - 1, $dims->[ ROWS ] - 1 );
320 $AoA = rows_get( $matrix, 0, $dims->[ ROWS ] - 2 );
322 rows_unshift( $AoA, $row );
327 return wantarray ? @{ $matrix } : $matrix;
333 # Martin A. Hansen, April 2007
335 # returns a submatrix sliced from a given matrix
337 my ( $matrix, # AoA data structure
338 $row_beg, # first row - OPTIONAL (default 0)
339 $row_end, # last row - OPTIONAL (default last row)
340 $col_beg, # first col - OPTIONAL (default 0)
341 $col_end, # last col - OPTIONAL (default last col)
346 my ( $submatrix, $subsubmatrix );
348 $submatrix = rows_get( $matrix, $row_beg, $row_end );
349 $subsubmatrix = cols_get( $submatrix, $col_beg, $col_end );
351 return wantarray ? @{ $subsubmatrix } : $subsubmatrix;
357 # Martin A. Hansen, April 2008.
359 # Returns a single row from a given matrix.
361 my ( $matrix, # AoA data structure
367 my ( $dims, $i, @list );
369 $dims = matrix_dims( $matrix );
371 Maasha::Common::error( qq(Row->$row outside of matrix->$dims->[ ROWS ]) ) if $row > $dims->[ ROWS ];
373 @list = @{ $matrix->[ $row ] };
375 return wantarray ? @list : \@list;
381 # Martin A. Hansen, April 2007
383 # returns a range of requested rows 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)
396 if ( not defined $row_end ) {
397 $row_end = scalar @{ $matrix };
400 if ( $row_end >= scalar @{ $matrix } )
402 warn qq(WARNING: row end larger than matrix\n);
403 $row_end = scalar( @{ $matrix } ) - 1;
406 die qq(ERROR: row begin "$row_beg" larger than row end "$row_end"\n) if $row_end < $row_beg;
408 if ( $row_beg == 0 and $row_end == scalar( @{ $matrix } ) - 1 ) {
409 @rows = @{ $matrix };
411 @rows = @{ $matrix }[ $row_beg .. $row_end ];
414 return wantarray ? @rows : \@rows;
420 # Martin A. Hansen, April 2008.
422 # Returns a single column from a given matrix.
424 my ( $matrix, # AoA data structure
425 $col, # column to get
430 my ( $dims, $i, @list );
432 $dims = matrix_dims( $matrix );
434 Maasha::Common::error( qq(Column->$col outside of matrix->$dims->[ COLS ]) ) if $col > $dims->[ COLS ];
436 for ( $i = 0; $i < $dims->[ ROWS ]; $i++ ) {
437 push @list, $matrix->[ $i ]->[ $col ];
440 return wantarray ? @list : \@list;
446 # Martin A. Hansen, April 2007
448 # returns a range of requested columns from a given matrix
450 my ( $matrix, # AoA data structure
451 $col_beg, # first column - OPTIONAL (default 0)
452 $col_end, # last column - OPTIONAL (default last column)
457 my ( $dims, @cols, $row, @AoA );
459 $dims = matrix_dims( $matrix );
463 if ( not defined $col_end ) {
464 $col_end = $dims->[ COLS ] - 1;
467 if ( $col_end > $dims->[ COLS ] - 1 )
469 warn qq(WARNING: column end larger than matrix\n);
470 $col_end = $dims->[ COLS ] - 1;
473 die qq(ERROR: column begin "$col_beg" larger than column end "$col_end"\n) if $col_end < $col_beg;
475 if ( $col_beg == 0 and $col_end == $dims->[ COLS ] - 1 )
481 foreach $row ( @{ $matrix } )
483 @cols = @{ $row }[ $col_beg .. $col_end ];
485 push @AoA, [ @cols ];
489 return wantarray ? @AoA : \@AoA;
501 $list = cols_get( $matrix, $col, $col );
502 $list = matrix_flip( $list )->[ 0 ];
504 die qq(ERROR: cannot sum non-nummerical column\n);
506 $sum = Maasha::Calc::sum( $list );
514 # Martin A. Hansen, April 2007.
516 # Appends one or more rows to a matrix.
518 my ( $matrix, # AoA data structure
519 $rows, # list of rows
524 push @{ $matrix }, @{ $rows };
526 return wantarray ? @{ $matrix } : $matrix;
532 # Martin A. Hansen, April 2007.
534 # Prefixes one or more rows to a matrix.
536 my ( $matrix, # AoA data structure
537 $rows, # list of rows
542 unshift @{ $matrix }, @{ $rows };
544 return wantarray ? @{ $matrix } : $matrix;
550 # Martin A. Hansen, April 2007.
552 # Appends one or more lists as columns to a matrix.
554 my ( $matrix, # AoA data structure
555 $cols, # list of columns
560 my ( $dims_matrix, $dims_cols, $i );
562 $dims_matrix = matrix_dims( $matrix );
563 $dims_cols = matrix_dims( $cols );
565 die qq(ERROR: Cannot merge columns with different row count\n) if $dims_matrix->[ ROWS ] != $dims_cols->[ ROWS ];
567 for ( $i = 0; $i < $dims_matrix->[ ROWS ]; $i++ )
569 push @{ $matrix->[ $i ] }, @{ $cols->[ $i ] };
572 return wantarray ? @{ $matrix } : $matrix;
578 # Martin A. Hansen, April 2007.
580 # Prefixes one or more lists as columns to a matrix.
582 my ( $matrix, # AoA data structure
583 $cols, # list of columns
588 my ( $dims_matrix, $dims_cols, $i );
590 $dims_matrix = matrix_dims( $matrix );
591 $dims_cols = matrix_dims( $cols );
593 die qq(ERROR: Cannot merge columns with different row count\n) if $dims_matrix->[ ROWS ] != $dims_cols->[ ROWS ];
595 for ( $i = 0; $i < $dims_matrix->[ ROWS ]; $i++ ) {
596 unshift @{ $matrix->[ $i ] }, @{ $cols->[ $i ] };
599 return wantarray ? @{ $matrix } : $matrix;
605 # Martin A. Hansen, April 2007.
607 # Given a matrix and a range of rows, rotates these rows
608 # left by shifting a given number of elements from
609 # the first position to the last.
611 my ( $matrix, # AoA data structure
612 $beg, # first row to shift
613 $end, # last row to shit
614 $shift, # number of shifts - DEFAULT=1
623 for ( $i = $beg; $i <= $end; $i++ )
625 $row = rows_get( $matrix, $i, $i );
627 for ( $c = 0; $c < $shift; $c++ )
629 $row = list_rotate_left( @{ $row } );
630 $matrix->[ $i ] = $row;
634 return wantarray ? @{ $matrix } : $matrix;
638 sub rows_rotate_right
640 # Martin A. Hansen, April 2007.
642 # Given a matrix and a range of rows, rotates these rows
643 # right by shifting a given number of elements from the
644 # last position to the first.
646 my ( $matrix, # AoA data structure
647 $beg, # first row to shift
648 $end, # last row to shit
649 $shift, # number of shifts - DEFAULT=1
654 my ( $dims, $i, $c, $row );
658 $dims = matrix_dims( $matrix );
660 die qq(ERROR: end < beg: $end < $beg\n) if $end < $beg;
661 die qq(ERROR: row outside matrix\n) if $end >= $dims->[ ROWS ];
663 for ( $i = $beg; $i <= $end; $i++ )
665 $row = rows_get( $matrix, $i, $i );
667 for ( $c = 0; $c < $shift; $c++ )
669 $row = list_rotate_right( @{ $row } );
670 $matrix->[ $i ] = $row;
674 return wantarray ? @{ $matrix } : $matrix;
680 # Martin A. Hansen, April 2007.
682 # Given a matrix and a range of columns, rotates these columns
683 # ups by shifting the the first cell of each row from the
684 # first position to the last.
686 my ( $matrix, # AoA data structure
687 $beg, # first row to shift
688 $end, # last row to shit
689 $shift, # number of shifts - DEFAULT=1
694 my ( $dims, $i, $c, $cols_pre, $col_select, $cols_post, $list );
698 $dims = matrix_dims( $matrix );
700 $cols_pre = cols_get( $matrix, 0, $beg - 1 ) if $beg > 0;
701 $cols_post = cols_get( $matrix, $end + 1, $dims->[ COLS ] - 1 ) if $end < $dims->[ COLS ] - 1;
703 for ( $i = $beg; $i <= $end; $i++ )
705 $col_select = cols_get( $matrix, $i, $i );
707 $list = matrix_flip( $col_select )->[ 0 ];
709 for ( $c = 0; $c < $shift; $c++ ) {
710 $list = list_rotate_left( $list );
713 $col_select = matrix_flip( [ $list ] );
716 cols_push( $cols_pre, $col_select );
718 $cols_pre = $col_select;
722 cols_push( $cols_pre, $cols_post ) if $cols_post;
726 return wantarray ? @{ $matrix } : $matrix;
732 # Martin A. Hansen, April 2007.
734 # Given a matrix and a range of columns, rotates these columns
735 # ups by shifting the the first cell of each row from the
736 # first position to the last.
738 my ( $matrix, # AoA data structure
739 $beg, # first row to shift
740 $end, # last row to shit
741 $shift, # number of shifts - DEFAULT=1
746 my ( $dims, $i, $c, $cols_pre, $col_select, $cols_post, $list );
750 $dims = matrix_dims( $matrix );
752 $cols_pre = cols_get( $matrix, 0, $beg - 1 ) if $beg > 0;
753 $cols_post = cols_get( $matrix, $end + 1, $dims->[ COLS ] - 1 ) if $end < $dims->[ COLS ] - 1;
755 for ( $i = $beg; $i <= $end; $i++ )
757 $col_select = cols_get( $matrix, $i, $i );
759 $list = matrix_flip( $col_select )->[ 0 ];
761 for ( $c = 0; $c < $shift; $c++ ) {
762 $list = list_rotate_right( $list );
765 $col_select = matrix_flip( [ $list ] );
768 cols_push( $cols_pre, $col_select );
770 $cols_pre = $col_select;
774 cols_push( $cols_pre, $cols_post ) if $cols_post;
778 return wantarray ? @{ $matrix } : $matrix;
784 # Martin A. Hansen, April 2007.
786 # given a list, shifts off the first element,
787 # and appends to the list, which is returned.
789 my ( $list, # list to rotate
792 my ( @new_list, $elem );
794 @new_list = @{ $list };
796 $elem = shift @new_list;
798 push @new_list, $elem;
800 return wantarray ? @new_list : \@new_list;
804 sub list_rotate_right
806 # Martin A. Hansen, April 2007.
808 # given a list, pops off the last element,
809 # and prefixes to the list, which is returned.
811 my ( $list, # list to rotate
814 my ( @new_list, $elem );
816 @new_list = @{ $list };
818 $elem = pop @new_list;
820 unshift @new_list, $elem;
822 return wantarray ? @new_list : \@new_list;
826 sub list_check_numeric
828 # Martin A. Hansen, April 2007.
830 # Checks if a given list only contains
831 # numerical elements. return 1 if numerical,
834 my ( $list, # list to check
841 foreach $elem ( @{ $list } ) {
842 return 0 if not Maasha::Calc::is_a_number( $elem );
851 # Martin A. Hansen, April 2007.
853 # Checks if a given list is sorted.
854 # If the sort type is not specified, we
855 # are going to check the type and make a guess.
856 # Returns 1 if sorted else 0.
858 my ( $list, # list to check
859 $type, # numerical of alphabetical
868 if ( list_check_numeric( $list ) ) {
876 if ( $type =~ /^a.*/i ) {
883 if ( @{ $list } > 1 )
887 for ( $i = 1; $i < @{ $list }; $i++ )
889 $cmp = $list->[ $i - 1 ] <=> $list->[ $i ];
891 return 0 if $cmp > 0;
896 for ( $i = 1; $i < @{ $list }; $i++ )
898 $cmp = $list->[ $i - 1 ] cmp $list->[ $i ];
900 return 0 if $cmp > 0;
911 # Martin A. Hansen, September 2009.
913 # Defaltes a list of values to a specified size
914 # and at the same time average the values.
922 my ( $old_size, $bucket_size, $bucket_rest, $i, @new_list );
924 $old_size = scalar @{ $list };
926 Maasha::Common::error( qq(Can't shrink to a bigger list: $old_size < $new_size ) ) if $old_size < $new_size;
928 $bucket_size = int( $old_size / $new_size );
929 $bucket_rest = $old_size - ( $new_size * $bucket_size );
931 print STDERR "old_size: $old_size new_size: $new_size bucket_size: $bucket_size bucket_rest: $bucket_rest\n";
935 while ( $i < $new_size )
937 # push @new_list, [ @{ $list }[ $i * $bucket_size .. $i * $bucket_size + $bucket_size - 1 ] ];
938 push @new_list, Maasha::Calc::mean( [ @{ $list }[ $i * $bucket_size .. $i * $bucket_size + $bucket_size - 1 ] ] );
943 @{ $list } = @new_list;
949 # Martin A. Hansen, April 2007.
951 # returns the number of unique elements in a
959 my ( %hash, $count );
961 map { $hash{ $_ } = 1 } @{ $list };
963 $count = scalar keys %hash;
971 # Martin A. Hansen, April 2007.
973 my ( $matrix, # AoA data structure
977 my ( $dims, $list, $i, $max, $len, %hash, $elem, @list );
979 $dims = matrix_dims( $matrix );
981 $list = cols_get( $matrix, $col, $col );
982 $list = matrix_flip( $list )->[ 0 ];
986 for ( $i = 0; $i < @{ $list }; $i++ )
988 $hash{ $list->[ $i ] }++;
990 $len = length $list->[ $i ];
992 $max = $len if $len > $max;
997 if ( list_check_numeric( $list ) ) {
998 @list = sort { $a <=> $b } @list;
1000 @list = sort { $a cmp $b } @list;
1003 foreach $elem ( @list )
1005 print $elem, " " x ( $max - length( $elem ) ),
1006 sprintf( " %6s ", $hash{ $elem } ),
1007 sprintf( "%.2f\n", ( $hash{ $elem } / $dims->[ ROWS ] ) * 100 );
1014 # Martin A. Hansen, July 2008.
1016 # Merge two given tables based on identifiers in a for each table
1017 # specified column which should contain a unique identifier.
1018 # Initially the tables are sorted and tab2 is merged onto tab1
1021 my ( $tab1, # table 1 - an AoA.
1022 $tab2, # table 2 - an AoA.
1023 $col1, # identifier in row1
1024 $col2, # identifier in row2
1025 $sort_type, # alphabetical or numeric comparison
1030 my ( $num, $cmp, $i, $c, @row_cpy, $max );
1035 if ( $sort_type =~ /num/i )
1039 @{ $tab1 } = sort { $a->[ $col1 ] <=> $b->[ $col1 ] } @{ $tab1 };
1040 @{ $tab2 } = sort { $a->[ $col2 ] <=> $b->[ $col2 ] } @{ $tab2 };
1044 @{ $tab1 } = sort { $a->[ $col1 ] cmp $b->[ $col1 ] } @{ $tab1 };
1045 @{ $tab2 } = sort { $a->[ $col2 ] cmp $b->[ $col2 ] } @{ $tab2 };
1051 while ( $i < @{ $tab1 } and $c < @{ $tab2 } )
1054 $cmp = $tab1->[ $i ]->[ $col1 ] <=> $tab2->[ $c ]->[ $col2 ];
1056 $cmp = $tab1->[ $i ]->[ $col1 ] cmp $tab2->[ $c ]->[ $col2 ];
1061 @row_cpy = @{ $tab2->[ $c ] };
1063 splice @row_cpy, $col2, 1;
1065 push @{ $tab1->[ $i ] }, @row_cpy;
1076 map { push @{ $tab1->[ $i ] }, "null" } 0 .. ( scalar @{ $tab2->[ $c ] } - 2 );
1082 map { push @{ $tab1->[ -1 ] }, "null" } 0 .. ( scalar @{ $tab1->[ 0 ] } - scalar @{ $tab1->[ -1 ] } + 1 );
1086 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> BINARY SEARCH <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
1091 # Martin A. Hansen, February 2008.
1093 # Uses binary search to locate the interval containing a
1094 # given number. The intervals are defined by begin and end
1095 # positions in seperate columns in a matrix. If a interval is
1096 # found then the index of that matrix row is returned, otherwise
1099 my ( $matrix, # data structure
1100 $col1, # column with interval begins
1101 $col2, # column with interval ends
1102 $num, # number to search for
1105 # Returns an integer.
1107 my ( $high, $low, $try );
1110 $high = @{ $matrix };
1112 while ( $low < $high )
1114 $try = int( ( $high + $low ) / 2 );
1116 # print "num->$num low->$low high->$high try->$try int1->$matrix->[ $try ]->[ $col1 ] int2->$matrix->[ $try ]->[ $col2 ]\n";
1118 if ( $num < $matrix->[ $try ]->[ $col1 ] ) {
1120 } elsif ( $num > $matrix->[ $try ]->[ $col2 ] ) {
1133 # Martin A. Hansen, February 2008.
1135 # Uses binary search to locate a number in a list of numbers.
1136 # If the number is found, then the index (the position of the number
1137 # in the list) is returned, otherwise -1 is returned.
1139 my ( $list, # list of numbers
1140 $num, # number to search for
1143 # Returns an integer.
1145 my ( $high, $low, $try );
1150 while ( $low < $high )
1152 $try = int( ( $high + $low ) / 2 );
1154 # print "num->$num low->$low high->$high try->$try int->$list->[ $try ]\n";
1156 if ( $num < $list->[ $try ] ) {
1158 } elsif ( $num > $list->[ $try ] ) {
1169 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> DISK SUBROUTINES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
1174 # Martin A. Hansen, April 2007
1176 # Reads tabular data from file into a matrix
1177 # AoA data structure.
1179 my ( $path, # full path to file with data
1180 $delimiter, # column delimiter - OPTIONAL (default tab)
1181 $comments, # regex for comment lines to skip - OPTIONAL
1182 $fields_ok, # list of fields to accept - OPTIONAL
1187 my ( $fh, $line, @fields, @AoA );
1189 $delimiter ||= "\t";
1191 $fh = Maasha::Filesys::file_read_open( $path );
1193 while ( $line = <$fh> )
1197 next if $comments and $line =~ /^$comments/;
1199 @fields = split /$delimiter/, $line;
1201 map { splice( @fields, $_, 1 ) } @{ $fields_ok } if $fields_ok;
1203 push @AoA, [ @fields ];
1208 return wantarray ? @AoA : \@AoA;
1214 # Martin A. Hansen, April 2007
1216 # Writes a tabular data structure to STDOUT or file.
1218 my ( $matrix, # AoA data structure
1219 $path, # full path to output file - OPTIONAL (default STDOUT)
1220 $delimiter, # column delimiter - OPTIONAL (default tab)
1225 $fh = Maasha::Filesys::file_write_open( $path ) if $path;
1227 $delimiter ||= "\t";
1229 foreach $row ( @{ $matrix } )
1232 print $fh join( $delimiter, @{ $row } ), "\n";
1234 print join( $delimiter, @{ $row } ), "\n";
1244 # Martin A. Hansen, April 2007.
1246 # stores a matrix to a binary file.
1248 my ( $path, # full path to file
1249 $matrix, # data structure
1252 Maasha::Filesys::file_store( $path, $matrix );
1258 # Martin A. Hansen, April 2007.
1260 # retrieves a matrix from a binary file
1262 my ( $path, # full path to file
1265 my $matrix = Maasha::Filesys::file_retrieve( $path );
1267 return wantarray ? @{ $matrix } : $matrix;
1271 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<