File Coverage

blib/lib/Math/Matrix/MaybeGSL.pm
Criterion Covered Total %
statement 115 206 55.8
branch 24 62 38.7
condition 8 19 42.1
subroutine 35 44 79.5
pod 2 2 100.0
total 184 333 55.2


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