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__ |