File Coverage

blib/lib/Math/Matrix/MaybeGSL.pm
Criterion Covered Total %
statement 98 170 57.6
branch 20 54 37.0
condition 8 19 42.1
subroutine 28 34 82.3
pod 2 2 100.0
total 156 279 55.9


line stmt bran cond sub pod time code
1             # ABSTRACT: Uniform use of Math::MatrixReal and Math::GSL::Matrix.
2              
3 1     1   27928 use strict;
  1         2  
  1         45  
4 1     1   6 use warnings;
  1         2  
  1         53  
5              
6             package Math::Matrix::MaybeGSL;
7             $Math::Matrix::MaybeGSL::VERSION = '0.006';
8 1     1   10 use parent 'Exporter';
  1         1540  
  1         8  
9             our @EXPORT = qw{Matrix};
10              
11             use overload
12 1         11 '*=' => '_assign_multiply',
13             '*' => '_multiply',
14 1     1   84 'fallback' => undef;
  1         2  
15              
16             sub _choose_matrix_module {
17 1 50   1   7 return 'Math::GSL::Matrix' if $INC{'Math/GSL/Matrix.pm'};
18 1 50       5 return 'Math::MatrixReal' if $INC{'Math/MatrixReal.pm'};
19              
20 1         2 my @err;
21              
22 1 50       2 return 'Math::GSL::Matrix' if eval {
23 1         11 require Math::GSL;
24 0         0 require Math::GSL::Matrix;
25 0         0 1;
26             };
27 1         648 push @err, "Error loading Math::GSL::Matrix: $@";
28              
29 1 50       3 return 'Math::MatrixReal' if eval { require Math::MatrixReal; 1; };
  1         9  
  1         38469  
30 0         0 push @err, "Error loading Math::MatrixReal: $@";
31              
32 0         0 die join( "\n", "Couldn't load a Matrix module:", @err );
33             }
34              
35 5     5 1 8982 sub Matrix { __PACKAGE__ }
36              
37             sub _call {
38 49     49   119 my ($method, $obj, @args) = @_;
39 49         311 $obj->{matrix}->$method(@args);
40             }
41              
42             sub isGSL {
43 0     0 1 0 our $matrix_module;
44 0         0 return $matrix_module eq "Math::GSL::Matrix";
45             }
46              
47             BEGIN {
48 1     1   5 our $matrix_module = _choose_matrix_module();
49             my %functions
50             = (
51             'any' => {
52             new => sub {
53 1     1   4 my (undef, $rows, $cols) = @_;
54 1         8 return _new( $matrix_module->new($rows, $cols) );
55             },
56 1     1   1085 dim => sub { _call(dim => @_) },
57 1     1   643 each => sub { _new(_call(each => @_)) },
58             },
59             'Math::GSL::Matrix' => {
60 0         0 assign => sub { _call(set_elem => ($_[0], $_[1]-1, $_[2]-1, $_[3])); },
61 0         0 element => sub { _call(get_elem => ($_[0], $_[1]-1, $_[2]-1, $_[3])); },
62 0         0 new_from_cols => sub { _new(_gsl_new_from_cols($_[1])) },
63 0         0 new_from_rows => sub { _new(_gsl_new_from_rows($_[1])) },
64 0         0 vconcat => sub { _new(_call(vconcat => $_[0], $_[1]{matrix})) },
65 0         0 hconcat => sub { _new(_call(hconcat => $_[0], $_[1]{matrix})) },
66 0         0 write => sub { _gsl_write(@_) },
67 0         0 read => sub { _gsl_read($_[1]) },
68             max => sub {
69 0 0       0 if (wantarray) {
70 0         0 my ($v, @pos) = _call(max => @_);
71 0         0 return ($v, map { $_ + 1 } @pos);
  0         0  
72             } else {
73 0         0 return scalar(_call(max => @_));
74             };
75             },
76             min => sub {
77 0 0       0 if (wantarray) {
78 0         0 my ($v, @pos) = _call(min => @_);
79 0         0 return ($v, map { $_ + 1 } @pos);
  0         0  
80             } else {
81 0         0 return scalar(_call(min => @_));
82             };
83             },
84             },
85             'Math::MatrixReal' => {
86 1     1   1247 assign => sub { _call(assign => @_); },
87 46     46   31659 element => sub { _call(element => @_); },
88 2     2   16 new_from_cols => sub { _new( $matrix_module->new_from_cols($_[1])) },
89 1     1   7 new_from_rows => sub { _new( $matrix_module->new_from_rows($_[1])) },
90 1     1   532 vconcat => sub { _new( ~((~$_[0]{matrix}) . (~$_[1]{matrix})) ) },
91 1     1   14 hconcat => sub { _new( $_[0]{matrix} . $_[1]{matrix} ) },
92 1     1   597 write => sub { _mreal_write(@_) },
93 1     1   5 read => sub { _mreal_read($_[1]) },
94 1     1   424 max => sub { _mreal_max($_[0]{matrix}) },
95 1     1   1261 min => sub { _mreal_min($_[0]{matrix}) },
96             },
97 1         145 );
98              
99 1     1   1537 no strict 'refs';
  1         3  
  1         328  
100              
101 1         3 for my $func (keys %{$functions{$matrix_module}}) {
  1         8  
102             # Use Sub::Install later?
103 10         20 $_ = __PACKAGE__ . "::$func";
104 10         55 *$_ = $functions{$matrix_module}{$func};
105             }
106 1         4 for my $func (keys %{$functions{any}}) {
  1         4  
107             # Use Sub::Install later?
108 3         8 $_ = __PACKAGE__ . "::$func";
109 3         2439 *$_ = $functions{any}{$func};
110             }
111              
112             }
113              
114             sub _mreal_max {
115 1     1   20 my $matrix = shift;
116 1         6 my ($rs, $cs) = $matrix->dim();
117 1 50 33     14 return $matrix->max() if ($rs == 1 || $cs == 1);
118              
119 1         3 my ($m, $r, $c, $v) = ($matrix->[0], 1, 1, undef);
120              
121 1         3 for my $i (1..$rs) {
122 2         4 for my $j (1..$cs) {
123 4 50 66     19 if (!$v || $v < $m->[$i-1][$j-1]) {
124 4         3 $r = $i;
125 4         5 $c = $j;
126 4         10 $v = $m->[$i-1][$j-1];
127             }
128             }
129             }
130              
131 1 50       4 return wantarray ? ($v, $r, $c) : $v;
132             }
133              
134             sub _mreal_min {
135 1     1   3 my $matrix = shift;
136 1         4 my ($rs, $cs) = $matrix->dim();
137 1 50 33     13 return $matrix->min() if ($rs == 1 || $cs == 1);
138              
139 1         3 my ($m, $r, $c, $v) = ($matrix->[0], 1, 1, undef);
140              
141 1         3 for my $i (1..$rs) {
142 2         6 for my $j (1..$cs) {
143 4 100 66     90 if (!$v || $v > $m->[$i-1][$j-1]) {
144 1         2 $r = $i;
145 1         2 $c = $j;
146 1         2 $v = $m->[$i-1][$j-1];
147             }
148             }
149             }
150              
151 1 50       5 return wantarray ? ($v, $r, $c) : $v;
152             }
153              
154             sub _gsl_new_from_cols {
155 0     0   0 my $cols = shift;
156              
157 0         0 my $nr_columns = scalar(@$cols);
158 0         0 my $nr_rows = 0;
159 0         0 for my $row (@$cols) {
160 0 0       0 $nr_rows = scalar(@$row) if @$row > $nr_rows;
161             }
162 0         0 my $m = Math::GSL::Matrix->new($nr_rows, $nr_columns);
163 0         0 for my $r (0..$nr_rows - 1) {
164 0         0 for my $c (0..$nr_columns - 1) {
165 0   0     0 $m->set_elem($r, $c, $cols->[$c][$r] || 0);
166             }
167             }
168 0         0 return $m;
169             }
170              
171             sub _gsl_new_from_rows {
172 0     0   0 my $rows = shift;
173              
174 0         0 my $nr_rows = scalar(@$rows);
175 0         0 my $nr_columns = 0;
176 0         0 for my $col (@$rows) {
177 0 0       0 $nr_columns = scalar(@$col) if @$col > $nr_columns;
178             }
179 0         0 my $m = Math::GSL::Matrix->new($nr_rows, $nr_columns);
180 0         0 for my $c (0..$nr_columns - 1) {
181 0         0 for my $r (0..$nr_rows - 1) {
182 0   0     0 $m->set_elem($r, $c, $rows->[$r][$c] || 0);
183             }
184             }
185 0         0 return $m;
186             }
187              
188             sub _new {
189 11     11   2821 my $mat = shift;
190 11         109 return bless { matrix => $mat }, __PACKAGE__;
191             }
192              
193             sub _assign_multiply {
194 0     0   0 my($object,$argument) = @_;
195              
196 0         0 return( &_multiply($object,$argument,undef) );
197             }
198              
199             sub _multiply {
200 3     3   1380 my ($object, $argument, $flag) = @_;
201              
202 3 100       13 $argument = $argument->{matrix} if ref $argument eq __PACKAGE__;
203 3 50       10 $object = $object->{matrix} if ref $object eq __PACKAGE__;
204              
205 3 100 66     17 if ((defined $flag) && $flag) {
206 1         4 return _new($argument * $object);
207             } else {
208 2         7 return _new($object * $argument);
209             }
210             }
211              
212             sub _mreal_write {
213 1     1   3 my ($m, $filename) = @_;
214              
215 1         3 my $matrix = $m->{matrix};
216              
217 1 50       197 open my $fh, ">", $filename or
218             die "Could not create file '$filename': $!";
219              
220             # probably faster than creating a full string in memory
221 1         7 my ($rows, $cols) = $matrix->dim();
222              
223 1         13 for my $r (0..$rows-1) {
224 2         7 for my $c (0..$cols-1) {
225 4         15 print $fh $matrix->[0][$r][$c];
226 4 100       15 print $fh "\t" unless $c == $cols-1;
227             }
228 2         8 print $fh "\n";
229             }
230 1         75 close $fh;
231             }
232              
233             sub _mreal_read {
234 1     1   3 my $filename = shift;
235              
236 1         2 my $m = [];
237              
238 1 50       35 open my $fh, "<", $filename or
239             die "could not open file '$filename': $!";
240              
241 1         29 while (<$fh>) {
242 2         4 chomp;
243 2         14 push @$m, [split /\s+/];
244             }
245              
246 1         8 return _new( Math::MatrixReal->new_from_rows($m) );
247             }
248              
249             sub _gsl_read {
250 0     0     my $filename = shift;
251              
252 0 0         die "$filename does not exist" unless -f $filename;
253              
254 0           my $fh = Math::GSL::gsl_fopen($filename, "r");
255 0 0         die "error opening file $filename for reading" unless $fh;
256              
257 0           my $dim = Math::GSL::Matrix::gsl_matrix_alloc(1, 2);
258 0           my $err = Math::GSL::Matrix::gsl_matrix_fread($fh, $dim);
259 0 0         die "error reading matrix" if $err;
260              
261 0           my $m = Math::GSL::Matrix::gsl_matrix_alloc(
262             Math::GSL::Matrix::gsl_matrix_get($dim, 0, 0),
263             Math::GSL::Matrix::gsl_matrix_get($dim, 0, 1));
264 0           $err = Math::GSL::Matrix::gsl_matrix_fread($fh, $m);
265 0 0         die "error reading matrix" if $err;
266              
267 0           Math::GSL::Matrix::gsl_matrix_free($dim);
268              
269 0           Math::GSL::gsl_fclose($fh);
270 0           _new( Math::GSL::Matrix->new($m) );
271             }
272              
273             sub _gsl_write {
274 0     0     my ($self, $filename) = @_;
275              
276 0           my $fh = Math::GSL::gsl_fopen($filename, "w");
277 0 0         die "error opening file: $filename" unless $fh;
278              
279             # create a temporary matrix with the main matrix dimensions
280 0           my $dim = Math::GSL::Matrix::gsl_matrix_alloc(1, 2);
281 0           my ($rows, $cols) = $self->dim;
282 0           Math::GSL::Matrix::gsl_matrix_set($dim, 0, 0, $rows);
283 0           Math::GSL::Matrix::gsl_matrix_set($dim, 0, 1, $cols);
284              
285 0           my $err = Math::GSL::Matrix::gsl_matrix_fwrite($fh, $dim);
286 0 0         die "error gsl-writting matrix" if $err;
287              
288 0           Math::GSL::Matrix::gsl_matrix_free($dim);
289              
290 0           $err = Math::GSL::Matrix::gsl_matrix_fwrite($fh, $self->{matrix}->raw);
291 0 0         die "error gsl-writting matrix" if $err;
292              
293 0           Math::GSL::gsl_fclose($fh);
294              
295             }
296              
297              
298              
299              
300             1;
301              
302             __END__