File Coverage

blib/lib/Math/Matrix/MaybeGSL.pm
Criterion Covered Total %
statement 100 172 58.1
branch 20 54 37.0
condition 8 19 42.1
subroutine 30 36 83.3
pod 2 2 100.0
total 160 283 56.5


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