line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
|
2
|
|
|
|
|
|
|
=head1 NAME |
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
Bio::Metabolic::MatrixOps - Operations on PDL::Matrix objects |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
=head1 SYNOPSIS |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
use Bio::Metabolic::MatrixOps; |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=head1 DESCRIPTION |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
This module contains all matrix operations that are needed for calculations |
14
|
|
|
|
|
|
|
involving the stoichiometric matrix |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
=head1 AUTHOR |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
Oliver Ebenhoeh, oliver.ebenhoeh@rz.hu-berlin.de |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=head1 SEE ALSO |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
Bio::Metabolic |
23
|
|
|
|
|
|
|
Bio::Metabolic::Substrate |
24
|
|
|
|
|
|
|
Bio::Metabolic::Substrate::Cluster |
25
|
|
|
|
|
|
|
Bio::Metabolic::Reaction |
26
|
|
|
|
|
|
|
Bio::Metabolic::Network |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
=cut |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
=head1 METHODS |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
=head2 method xrow |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
$m->xrow($r1,$r2); |
35
|
|
|
|
|
|
|
Exchanges rows $r1 and $r2 in matrix $m. |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
=cut |
38
|
|
|
|
|
|
|
|
39
|
1
|
|
|
1
|
|
1743
|
use PDL; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
use PDL::Matrix; |
41
|
|
|
|
|
|
|
use Math::Fraction; |
42
|
|
|
|
|
|
|
use Math::Cephes qw(:fract); |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
sub PDL::Matrix::xrow { # $m, $row1, $row2 |
45
|
|
|
|
|
|
|
my $matrix = shift; |
46
|
|
|
|
|
|
|
my ( $r1, $r2 ) = @_; |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
my $d = $r1 - $r2; |
49
|
|
|
|
|
|
|
( my $tmp = $matrix->slice("$r1:$r2:$d,:") ) .= |
50
|
|
|
|
|
|
|
$matrix->slice("$r2:$r1:$d,:")->sever |
51
|
|
|
|
|
|
|
if $d != 0; |
52
|
|
|
|
|
|
|
} |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
=head2 method xcol |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
$m->xcol($r1,$r2); |
57
|
|
|
|
|
|
|
Exchanges columns $r1 and $r2 in matrix $m. |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
=cut |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
sub PDL::Matrix::xcol { |
62
|
|
|
|
|
|
|
my $matrix = shift; |
63
|
|
|
|
|
|
|
my ( $r1, $r2 ) = @_; |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
my $d = $r1 - $r2; |
66
|
|
|
|
|
|
|
( my $tmp = $matrix->slice(":,$r1:$r2:$d") ) .= |
67
|
|
|
|
|
|
|
$matrix->slice(":,$r2:$r1:$d")->sever |
68
|
|
|
|
|
|
|
if $d != 0; |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
=head2 method addrows |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
$m->addrows($r1,$r2[,$lambda]); |
74
|
|
|
|
|
|
|
Adds $lambda times the $r2-th row to $r1 |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
=cut |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
sub PDL::Matrix::addcols { # $matrix->($i,$j[,$lambda]) |
79
|
|
|
|
|
|
|
# adds lambda * j-th row to i-th row |
80
|
|
|
|
|
|
|
my $matrix = shift; |
81
|
|
|
|
|
|
|
my $i = shift; |
82
|
|
|
|
|
|
|
my $j = shift; |
83
|
|
|
|
|
|
|
my $lambda = @_ ? shift: 1; |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
( my $tmp = $matrix->slice(":,($i)") ) += |
86
|
|
|
|
|
|
|
$lambda * $matrix->slice(":,($j)")->sever; |
87
|
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
=head2 method addcols |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
$m->addcols($c1,$c2[,$lambda]); |
92
|
|
|
|
|
|
|
Adds $lambda times the $c2-th column to $c1 |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
=cut |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
sub PDL::Matrix::addrows { # $matrix->($i,$j[,$lambda]) |
97
|
|
|
|
|
|
|
# adds lambda * j-th row to i-th row |
98
|
|
|
|
|
|
|
my $matrix = shift; |
99
|
|
|
|
|
|
|
my $i = shift; |
100
|
|
|
|
|
|
|
my $j = shift; |
101
|
|
|
|
|
|
|
my $lambda = @_ ? shift: 1; |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
( my $tmp = $matrix->slice("($i),:") ) += |
104
|
|
|
|
|
|
|
$lambda * $matrix->slice("($j),:")->sever; |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
=head2 method delcol |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
$m->delcol($c); |
110
|
|
|
|
|
|
|
Sets all coefficients in the column $c to zero. |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
=cut |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
sub PDL::Matrix::delcol { # set row to zero |
115
|
|
|
|
|
|
|
my ( $matrix, $r ) = @_; |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
( my $tmp = $matrix->slice(":,$r") ) .= 0; |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
=head2 method delcols |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
$m->delcols(@c); |
123
|
|
|
|
|
|
|
Sets all coefficients in the columns specified in @c to zero. |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
=cut |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
sub PDL::Matrix::delcols { # set several rows to zero |
128
|
|
|
|
|
|
|
my ( $matrix, @rows ) = @_; |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
my $r; |
131
|
|
|
|
|
|
|
foreach $r (@rows) { |
132
|
|
|
|
|
|
|
$matrix->delcol($r); |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
=head2 method delrow |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
$m->delrow($r); |
139
|
|
|
|
|
|
|
Sets all coefficients in the row $r to zero. |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=cut |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
sub PDL::Matrix::delrow { # set row to zero |
144
|
|
|
|
|
|
|
my ( $matrix, $r ) = @_; |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
( my $tmp = $matrix->slice("$r,:") ) .= 0; |
147
|
|
|
|
|
|
|
} |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
=head2 method delrows |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
$m->delrows(@r); |
152
|
|
|
|
|
|
|
Sets all coefficients in the rows specified in @r to zero. |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
=cut |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
sub PDL::Matrix::delrows { # set several rows to zero |
157
|
|
|
|
|
|
|
my ( $matrix, @rows ) = @_; |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
my $r; |
160
|
|
|
|
|
|
|
foreach $r (@rows) { |
161
|
|
|
|
|
|
|
$matrix->delrow($r); |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
=head2 method det # probably obsolete!!!! Check with PDL::Matrix / PDL::MatrixOps |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
$det = $m->det; |
168
|
|
|
|
|
|
|
Returns the determinant of matrix $m, undef if $m is not square. |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
=cut |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
#sub PDL::Matrix::det { |
173
|
|
|
|
|
|
|
# my $matrix = shift->copy; |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
# my @dims = $matrix->dims; |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
# return undef if ( @dims < 2 ); |
178
|
|
|
|
|
|
|
# my $n = $dims[0] < $dims[1] ? $dims[0] : $dims[1]; |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
# my ( $nzindex, $tmp, $r2 ); |
181
|
|
|
|
|
|
|
# my $sign = 1; |
182
|
|
|
|
|
|
|
# my $r = 0; |
183
|
|
|
|
|
|
|
# my $rank = $n; |
184
|
|
|
|
|
|
|
# while ( $r < $rank ) { |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
# print "Entering loop with r=$r, rank=$rank\n"; |
187
|
|
|
|
|
|
|
# my $row = $matrix->slice("($r),:"); |
188
|
|
|
|
|
|
|
# if ( $row->where( $row == 0 )->nelem >= $n ) { |
189
|
|
|
|
|
|
|
# if ( $r < $rank - 1 ) { |
190
|
|
|
|
|
|
|
# $matrix->xrow( $r, $rank - 1 ) |
191
|
|
|
|
|
|
|
# ; #print("Reihenaustausch, $matrix\n"); |
192
|
|
|
|
|
|
|
# $sign = -$sign; |
193
|
|
|
|
|
|
|
# } |
194
|
|
|
|
|
|
|
# $rank--; |
195
|
|
|
|
|
|
|
# } |
196
|
|
|
|
|
|
|
# else { |
197
|
|
|
|
|
|
|
# $nzindex = which( $row != 0 )->at(0); |
198
|
|
|
|
|
|
|
# if ( $nzindex > $r ) { |
199
|
|
|
|
|
|
|
# $matrix->xcol( $r, $nzindex ) |
200
|
|
|
|
|
|
|
# ; #print("Spaltenaustausch, $matrix\n"); |
201
|
|
|
|
|
|
|
# $sign *= -1; |
202
|
|
|
|
|
|
|
# } |
203
|
|
|
|
|
|
|
# for ( $r2 = $r + 1 ; $r2 < $rank ; $r2++ ) { |
204
|
|
|
|
|
|
|
# $matrix->addrows( $r2, $r, |
205
|
|
|
|
|
|
|
# -$matrix->at( $r2, $r ) / $matrix->at( $r, $r ) ); |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
## ($tmp = $matrix->slice(":,$r2")) .= $matrix->slice(":,$r2") - $matrix->at($r,$r2)/$matrix->at($r,$r) * $matrix->slice(":,$r"); |
208
|
|
|
|
|
|
|
# } |
209
|
|
|
|
|
|
|
# $r++; |
210
|
|
|
|
|
|
|
# } |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
# # print "$r,$rank,$matrix\n"; |
213
|
|
|
|
|
|
|
# } |
214
|
|
|
|
|
|
|
# my $det = 1; |
215
|
|
|
|
|
|
|
# for ( $r = 0 ; $r < $n ; $r++ ) { |
216
|
|
|
|
|
|
|
# $det *= $matrix->at( $r, $r ); |
217
|
|
|
|
|
|
|
# } |
218
|
|
|
|
|
|
|
# return ( $det * $sign ); |
219
|
|
|
|
|
|
|
#} |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
=head2 method is_pos_def |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
$m->is_pos_def; |
224
|
|
|
|
|
|
|
Returns true if matrix $m is truely positive definite, false otherwise |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
=cut |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
sub PDL::Matrix::is_pos_def { |
229
|
|
|
|
|
|
|
my $matrix = shift; |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
my ( $n, $m ) = $matrix->dims; |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
for ( my $i = 0 ; $i < $n ; $i++ ) { |
234
|
|
|
|
|
|
|
return (0) unless $matrix->slice("0:$i,0:$i")->det > 0; |
235
|
|
|
|
|
|
|
} |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
return (1); |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
=head2 method row_echelon_int; |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
$row_echelon_matrix = $m->row_echelon_int; |
243
|
|
|
|
|
|
|
($row_echelon_matrix, $permutation_vector, $rank) = $m->row_echelon_int; |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
Returns the integer row echelon form of matrix $m. |
246
|
|
|
|
|
|
|
In array context also returns the permutation vector indication how the |
247
|
|
|
|
|
|
|
rows of $m were permuted while calculating the row echelon form and the |
248
|
|
|
|
|
|
|
rank of the matrix $m. |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
=cut |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
sub PDL::Matrix::row_echelon_int { |
253
|
|
|
|
|
|
|
my $matrix = shift->copy; |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
# print "reference of matrix is now: ".ref($matrix)."\n"; |
256
|
|
|
|
|
|
|
return ( null, null, 0 ) if ( $matrix->isempty ); |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
my ( $n, $m ) = $matrix->dims; |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
my $rank = $m; |
261
|
|
|
|
|
|
|
my $r = 0; |
262
|
|
|
|
|
|
|
my $perm = msequence 1, $n; |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
# bless $perm, ref($matrix); |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
my ( $nzindex, $tmp, $r2, $frac, $p, $q ); |
267
|
|
|
|
|
|
|
while ( $r < $rank ) { |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
# print "Entering loop with r=$r, rank=$rank\n"; |
270
|
|
|
|
|
|
|
my $row = $matrix->slice("($r),:"); |
271
|
|
|
|
|
|
|
if ( $row->where( $row == 0 )->nelem == $n ) { |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
# print "Exchange rows $r and ".eval($rank-1)."...\n"; |
274
|
|
|
|
|
|
|
$matrix->xrow( $r, $rank - 1 ); #print $matrix; |
275
|
|
|
|
|
|
|
$rank--; |
276
|
|
|
|
|
|
|
} |
277
|
|
|
|
|
|
|
else { |
278
|
|
|
|
|
|
|
$nzindex = which( $row != 0 )->at(0); |
279
|
|
|
|
|
|
|
if ( $nzindex > $r ) { |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
# print "Exchange columns $r and $nzindex...\n"; |
282
|
|
|
|
|
|
|
$matrix->xcol( $r, $nzindex ); |
283
|
|
|
|
|
|
|
$perm->xcol( $r, $nzindex ); |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
for ( $r2 = $r + 1 ; $r2 < $rank ; $r2++ ) { |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
# for ($r2=0;$r2<$rank;$r2++) { |
288
|
|
|
|
|
|
|
# if ($r2 != $r) { |
289
|
|
|
|
|
|
|
( $p, $q ) = |
290
|
|
|
|
|
|
|
frac( $matrix->at( $r2, $r ), $matrix->at( $r, $r ) )->list; |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
# print "Reihe $r2:p=$p,q=$q ".frac($matrix->at($r,$r2),$matrix->at($r,$r))->string."\n"; |
293
|
|
|
|
|
|
|
( $tmp = $matrix->slice("$r2,:") ) .= |
294
|
|
|
|
|
|
|
$q * $matrix->slice("$r2,:") - $p * $matrix->slice("$r,:"); |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
# } |
297
|
|
|
|
|
|
|
} |
298
|
|
|
|
|
|
|
$r++; |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
# print "$r,$rank,$matrix\n"; |
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
# return wantarray ? ( $matrix, $perm->slice("(0),:"), $rank ) : $matrix; |
305
|
|
|
|
|
|
|
return wantarray ? ( $matrix, $perm, $rank ) : $matrix; |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
=head2 method cutrow |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
$mnew = $m->cutrow($r); |
311
|
|
|
|
|
|
|
Returns a matrix without row $r, i.e. the number of rows is |
312
|
|
|
|
|
|
|
reduced by one. |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
=cut |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
sub PDL::Matrix::cutrow { |
317
|
|
|
|
|
|
|
my $matrix = shift->copy; |
318
|
|
|
|
|
|
|
my $r = shift; |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
my ( $x, $y ) = $matrix->mdims; |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
if ( $r < $x - 1 ) { |
323
|
|
|
|
|
|
|
my $slstr1 = "$r:" . eval( $x - 2 ) . ",:"; |
324
|
|
|
|
|
|
|
my $slstr2 = eval( $r + 1 ) . ":" . eval( $x - 1 ) . ",:"; |
325
|
|
|
|
|
|
|
( my $tmp = $matrix->slice("$slstr1") ) .= |
326
|
|
|
|
|
|
|
$matrix->slice("$slstr2")->sever; |
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
$x -= 2; |
329
|
|
|
|
|
|
|
return $x < 0 ? null: $matrix->slice("0:$x,:"); |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
=head2 method cutcol |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
$mnew = $m->cutcol($c); |
335
|
|
|
|
|
|
|
Returns a matrix without column $c, i.e. the number of columns is |
336
|
|
|
|
|
|
|
reduced by one. |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
=cut |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
sub PDL::Matrix::cutcol { |
341
|
|
|
|
|
|
|
my $matrix = shift->copy; |
342
|
|
|
|
|
|
|
my $r = shift; |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
my ( $x, $y ) = $matrix->mdims; |
345
|
|
|
|
|
|
|
return undef if ( !defined $y ); |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
if ( $r < $y - 1 ) { |
348
|
|
|
|
|
|
|
my $slstr1 = ":,$r:" . eval( $y - 2 ); |
349
|
|
|
|
|
|
|
my $slstr2 = ":," . eval( $r + 1 ) . ":" . eval( $y - 1 ); |
350
|
|
|
|
|
|
|
( my $tmp = $matrix->slice("$slstr1") ) .= |
351
|
|
|
|
|
|
|
$matrix->slice("$slstr2")->sever; |
352
|
|
|
|
|
|
|
} |
353
|
|
|
|
|
|
|
$y -= 2; |
354
|
|
|
|
|
|
|
return $y < 0 ? null: $matrix->slice(":,0:$y"); |
355
|
|
|
|
|
|
|
} |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
=head2 method cutrows |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
$mnew = $m->cutrows(@r); |
360
|
|
|
|
|
|
|
Returns a matrix without all rows specified in @r, i.e. the number |
361
|
|
|
|
|
|
|
of rows is reduced by the number of elements in @r. |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
=cut |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
sub PDL::Matrix::cutrows { |
366
|
|
|
|
|
|
|
my $matrix = shift->copy; |
367
|
|
|
|
|
|
|
my @rows = sort { $b <=> $a } @_; |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
for ( my $r = 0 ; $r < @rows ; $r++ ) { |
370
|
|
|
|
|
|
|
$matrix = $matrix->cutrow( $rows[$r] ); |
371
|
|
|
|
|
|
|
} |
372
|
|
|
|
|
|
|
return $matrix; |
373
|
|
|
|
|
|
|
} |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
=head2 method cutcols |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
$mnew = $m->cutcols(@c); |
378
|
|
|
|
|
|
|
Returns a matrix without all columns specified in @c, i.e. the number |
379
|
|
|
|
|
|
|
of columns is reduced by the number of elements in @c. |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
=cut |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
sub PDL::Matrix::cutcols { |
384
|
|
|
|
|
|
|
my $matrix = shift->copy; |
385
|
|
|
|
|
|
|
my @rows = sort { $b <=> $a } @_; |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
for ( my $r = 0 ; $r < @rows ; $r++ ) { |
388
|
|
|
|
|
|
|
$matrix = $matrix->cutcol( $rows[$r] ); |
389
|
|
|
|
|
|
|
} |
390
|
|
|
|
|
|
|
return $matrix; |
391
|
|
|
|
|
|
|
} |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
=head2 method permrows |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
$mnew = $m->permrows($permutation_vector); |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
Returns a matrix with the rows permuted as specified by $permutation_vector. |
398
|
|
|
|
|
|
|
$permutation_vector must be a PDL. |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
EXAMPLE: If $m is a 3x3 matrix, then |
401
|
|
|
|
|
|
|
$p = $m->permrows(pdl [2,0,1]); |
402
|
|
|
|
|
|
|
will return a matrix with the last row of $m as first row, the first row of $m |
403
|
|
|
|
|
|
|
as the second and the second row of $m as the last row. |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
=cut |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
*PDL::Matrix::permrows = \&permrows; |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
sub permrows { |
410
|
|
|
|
|
|
|
my $matrix = shift->copy; |
411
|
|
|
|
|
|
|
my $perm; |
412
|
|
|
|
|
|
|
if ( ref( $_[0] ) eq "PDL::Matrix" ) { |
413
|
|
|
|
|
|
|
$perm = shift; |
414
|
|
|
|
|
|
|
my @pdims = $perm->mdims; |
415
|
|
|
|
|
|
|
$perm = $perm->transpose if $pdims[1] == 1; |
416
|
|
|
|
|
|
|
} |
417
|
|
|
|
|
|
|
elsif ( ref( $_[0] ) eq "PDL" ) { |
418
|
|
|
|
|
|
|
$perm = shift->copy->dummy(1); |
419
|
|
|
|
|
|
|
bless $perm, 'PDL::Matrix'; |
420
|
|
|
|
|
|
|
} |
421
|
|
|
|
|
|
|
elsif ( ref( $_[0] ) eq "ARRAY" ) { |
422
|
|
|
|
|
|
|
$perm = pdl( $_[0] ); |
423
|
|
|
|
|
|
|
} |
424
|
|
|
|
|
|
|
else { |
425
|
|
|
|
|
|
|
$perm = pdl(@_); |
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
my ( $c, $r ) = $matrix->dims(); |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
# print "$c columns, $r rows, perm has ".eval($perm->nelem)." entries\n"; |
431
|
|
|
|
|
|
|
return undef if ( $r != $perm->nelem ); |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
# print "permrows called\n"; |
434
|
|
|
|
|
|
|
my $cnt; |
435
|
|
|
|
|
|
|
for ( $cnt = 0 ; $cnt < $r ; $cnt++ ) { |
436
|
|
|
|
|
|
|
my $xchpos = which( $perm->slice("(0),:") == $cnt )->at(0); |
437
|
|
|
|
|
|
|
if ( $xchpos != $cnt ) { |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
# print "exchange rows $xchpos and $cnt\n"; |
440
|
|
|
|
|
|
|
$matrix->xrow( $xchpos, $cnt ); |
441
|
|
|
|
|
|
|
$perm->xcol( $xchpos, $cnt ); |
442
|
|
|
|
|
|
|
} |
443
|
|
|
|
|
|
|
} |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
return $matrix; |
446
|
|
|
|
|
|
|
} |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
=head2 method kernel |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
$ker = $m->kernel; |
451
|
|
|
|
|
|
|
Returns the kernel of matrix $m, i.e. the matrix with linearly independent |
452
|
|
|
|
|
|
|
column vectors $c satisfying the equation $m x $c = 0. |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
=cut |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
sub PDL::Matrix::kernel { |
457
|
|
|
|
|
|
|
my $matrix = shift->copy; |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
my ( $rem, $perm, $rank ) = $matrix->row_echelon_int(); |
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
my ( $cols, $rows ) = $rem->dims(); |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
my $vec; |
464
|
|
|
|
|
|
|
my @veclist = (); |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
my ( $cnt, $r ); |
467
|
|
|
|
|
|
|
for ( $cnt = $rank ; $cnt < $cols ; $cnt++ ) { |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
# print "Solution number ".eval($cnt-$rank+1).":\n"; |
470
|
|
|
|
|
|
|
$vec = zeroes($cols); |
471
|
|
|
|
|
|
|
set $vec, $cnt, 1; |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
for ( $r = $rank - 1 ; $r >= 0 ; $r-- ) { |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
# print "Calculating row $r:\n"; |
476
|
|
|
|
|
|
|
my ($row) = $rem->slice("($r),:"); |
477
|
|
|
|
|
|
|
my $sum = inner( $row, $vec ); |
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
# ensure only integers remain |
480
|
|
|
|
|
|
|
my ( $gcd, $redsum, $redpivot ) = |
481
|
|
|
|
|
|
|
euclid( $sum, $rem->at( $r, $r ) ); |
482
|
|
|
|
|
|
|
$vec *= $redpivot; |
483
|
|
|
|
|
|
|
set $vec, $r, -( $sum * $redpivot / $rem->at( $r, $r ) ); |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
# print "$vec\n"; |
486
|
|
|
|
|
|
|
} |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
push( @veclist, $vec ); |
489
|
|
|
|
|
|
|
} |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
# print "kernel: Rank=$rank,Columns=$cols,vecs:@veclist\n"; |
492
|
|
|
|
|
|
|
# my $retmat = cat(@veclist)->xchg(0,1); |
493
|
|
|
|
|
|
|
# $retmat->permrows($perm); |
494
|
|
|
|
|
|
|
# return $retmat; |
495
|
|
|
|
|
|
|
return null unless @veclist; |
496
|
|
|
|
|
|
|
my $retmat = bless cat(@veclist)->xchg( 0, 1 ), ref($matrix); |
497
|
|
|
|
|
|
|
return $retmat->permrows($perm); |
498
|
|
|
|
|
|
|
} |
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
=head2 method invert # probably obsolete!!!! Check with PDL::Matrix / PDL::MatrixOps |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
$inv = $m->invert; |
503
|
|
|
|
|
|
|
Returns the inverse of $m, undef if $m is not invertible. |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
=cut |
506
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
sub PDL::Matrix::invert { |
508
|
|
|
|
|
|
|
my $matrix = shift->copy; |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
# print "ref(matrix) is ".ref($matrix)."\n"; |
511
|
|
|
|
|
|
|
# my ($pkg,$file,$line)=caller(); |
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
my @dims = $matrix->dims; |
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
if ( $dims[0] != $dims[1] ) { |
516
|
|
|
|
|
|
|
croak("Inverse for non-square matrix not defined!\n"); |
517
|
|
|
|
|
|
|
return undef; |
518
|
|
|
|
|
|
|
} |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
my $n = $dims[0]; # n x n matrix |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
# $inverse = 1 |
523
|
|
|
|
|
|
|
# print "matrix $matrix"; |
524
|
|
|
|
|
|
|
# print "invert called from package $pkg, file $file, line $line (n=$n)\n"; |
525
|
|
|
|
|
|
|
# my $inverse = ref($matrix)->new($n,$n); |
526
|
|
|
|
|
|
|
my $inverse = mzeroes( $n, $n ); |
527
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
# (my $tmp = $inverse->diagonal(0,1)) .= 1; # some strange error!!!! |
529
|
|
|
|
|
|
|
# for (my $del=0;$del<$n;$del++) {set($inverse,$del,$del,1)}; |
530
|
|
|
|
|
|
|
$inverse->diagonal( 0, 1 ) .= 1; |
531
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
for ( my $colnr = 0 ; $colnr < $n ; $colnr++ ) { |
533
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
# find pivot element |
535
|
|
|
|
|
|
|
my $colnz = which( $matrix->slice(":,($colnr)")->sever != 0 ); |
536
|
|
|
|
|
|
|
my $ppiv = which( $colnz >= $colnr ); |
537
|
|
|
|
|
|
|
if ( $ppiv->nelem == 0 ) { |
538
|
|
|
|
|
|
|
print "Matrix not invertible\n"; |
539
|
|
|
|
|
|
|
return undef; |
540
|
|
|
|
|
|
|
} |
541
|
|
|
|
|
|
|
my $pivotrow = $colnz->at( $ppiv->at(0) ); |
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
if ( $pivotrow != $colnr ) { |
544
|
|
|
|
|
|
|
$matrix->xrow( $colnr, $pivotrow ); |
545
|
|
|
|
|
|
|
$inverse->xrow( $colnr, $pivotrow ); |
546
|
|
|
|
|
|
|
} |
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
my $akk = $matrix->at( $colnr, $colnr ); # this is a_{kk} |
549
|
|
|
|
|
|
|
for ( my $rownr = 0 ; $rownr < $n ; $rownr++ ) { |
550
|
|
|
|
|
|
|
if ( $rownr != $colnr ) { |
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
# my $q = - $matrix->at($colnr,$rownr) / $akk; |
553
|
|
|
|
|
|
|
my $q = -$matrix->at( $rownr, $colnr ) / $akk; |
554
|
|
|
|
|
|
|
$matrix->addrows( $rownr, $colnr, $q ); |
555
|
|
|
|
|
|
|
$inverse->addrows( $rownr, $colnr, $q ); |
556
|
|
|
|
|
|
|
} |
557
|
|
|
|
|
|
|
} |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
# print "Matrix now (column $colnr) : $matrix\n"; |
560
|
|
|
|
|
|
|
# print "Inverse now (column $colnr) : $inverse\n"; |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
} |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
# my $diag = $matrix->diagonal(0,1); |
565
|
|
|
|
|
|
|
# if (!(which($diag==0)->isempty)) { |
566
|
|
|
|
|
|
|
# print "Matrix non inversible!\n"; |
567
|
|
|
|
|
|
|
# return undef; |
568
|
|
|
|
|
|
|
# } |
569
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
for ( my $d = 0 ; $d < $n ; $d++ ) { |
571
|
|
|
|
|
|
|
if ( $matrix->at( $d, $d ) == 0 ) { |
572
|
|
|
|
|
|
|
croak("Matrix non inversible!"); |
573
|
|
|
|
|
|
|
return undef; |
574
|
|
|
|
|
|
|
} |
575
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
# ($tmp = $inverse->slice(":,($d)")) /= $diag->at($d); |
577
|
|
|
|
|
|
|
my $tmp; |
578
|
|
|
|
|
|
|
( $tmp = $inverse->slice("($d),:") ) /= $matrix->at( $d, $d ); |
579
|
|
|
|
|
|
|
} |
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
# print "inverse: $inverse"; |
582
|
|
|
|
|
|
|
return $inverse; |
583
|
|
|
|
|
|
|
} |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
=head2 method char_pol |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
$coefficient_vector = $m->char_pol; |
588
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
Returns a PDL with the coefficients of the characteristic polynomial of $m. |
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
EXAMPLE: |
592
|
|
|
|
|
|
|
[1 2 1] |
593
|
|
|
|
|
|
|
The matrix M=[2 0 3] has the characeristic polynomial |
594
|
|
|
|
|
|
|
[1 1 1] |
595
|
|
|
|
|
|
|
p(x) = det(M-x1) = a_3 x^3 + a_2 x^2 + a_1 x + a_0 = -x^3+2x^2+7x+1. |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
$m = mdpl [[1,2,1],[2,0,3],[1,1,1]]; |
598
|
|
|
|
|
|
|
$cp = $m->char_pol; |
599
|
|
|
|
|
|
|
This returns [1,7,2,-1]. $cp->at(n) contains the coefficient a_n. |
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
=cut |
602
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
sub PDL::Matrix::char_pol { |
604
|
|
|
|
|
|
|
my $matrix = shift; |
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
my @dims = $matrix->dims; |
607
|
|
|
|
|
|
|
my $n = $dims[0]; |
608
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
# print "Dimension: $n\nMatrix: $matrix\n"; |
610
|
|
|
|
|
|
|
my $lvec = @_ ? shift: ones($n); |
611
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
# print "lvec: $lvec\n"; |
613
|
|
|
|
|
|
|
# if ($n == 1) { |
614
|
|
|
|
|
|
|
# return $lvec->at(0) == 1 ? [$matrix->at(0,0),-1] : [$matrix->at(0,0),0]; |
615
|
|
|
|
|
|
|
# } |
616
|
|
|
|
|
|
|
return pdl [ $matrix->at( 0, 0 ), -$lvec->at(0) ] if $n == 1; |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
my $lambdas = which( $lvec == 1 ); |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
# print "Lambdas at $lambdas\n"; |
621
|
|
|
|
|
|
|
return pdl [ eval( $matrix->determinant ) ] if ( $lambdas->nelem == 0 ); |
622
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
my $lambda = $lambdas->at(0); |
624
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
# print "...choosing lambda at $lambda\n"; |
626
|
|
|
|
|
|
|
set( $lvec, $lambda, 0 ); # now recursively calculate... |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
# print "calling char_pol with $lvec\n"; |
629
|
|
|
|
|
|
|
# print ">>>>>>>>>>>>>\n"; |
630
|
|
|
|
|
|
|
my $coeff1 = $matrix->char_pol( $lvec->copy ); |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
# print "<<<<<<<<<<<<< (lvec is $lvec)\n"; |
633
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
# print "Coefficients due to leaving out lambda: $coeff1\n"; |
635
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
# print "lvec before splicing: $lvec\n"; |
637
|
|
|
|
|
|
|
my @tmpl = $lvec->list; |
638
|
|
|
|
|
|
|
splice( @tmpl, $lambda, 1 ); |
639
|
|
|
|
|
|
|
$lvec = pdl(@tmpl); |
640
|
|
|
|
|
|
|
$lvec = $lvec->dummy(0) if $lvec->dims == 0; |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
# print "lvec after splicing: $lvec\n"; |
643
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
# reduce matrix |
645
|
|
|
|
|
|
|
my $redmat = $matrix->cutrow($lambda)->cutcol($lambda); |
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
# $redmat = $redmat->cutcol($lambda); |
648
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
# print "calling char_pol with $lvec and reduced matrix $redmat\n"; |
650
|
|
|
|
|
|
|
# print ">>>>>>>>>>>>>\n"; |
651
|
|
|
|
|
|
|
my $coeff2 = $redmat->char_pol( $lvec->copy ); |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
# print "<<<<<<<<<<<<<\n"; |
654
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
# print "Coefficients due to lambda: $coeff2\n"; |
656
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
# unshift(@$coeff2,0); |
658
|
|
|
|
|
|
|
$coeff2 = pdl [ 0, $coeff2->list ]; |
659
|
|
|
|
|
|
|
|
660
|
|
|
|
|
|
|
# print "after unshifting: ".join(',',@$coeff2)."\n"; |
661
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
# my $res = []; |
663
|
|
|
|
|
|
|
# for (my $i=0;$i<@$coeff2;$i++) { |
664
|
|
|
|
|
|
|
# $res->[$i] = $coeff1->[$i] - $coeff2->[$i]; |
665
|
|
|
|
|
|
|
# } |
666
|
|
|
|
|
|
|
$coeff1 = |
667
|
|
|
|
|
|
|
pdl [ $coeff1->list, zeroes( $coeff2->nelem - $coeff1->nelem )->list ] |
668
|
|
|
|
|
|
|
if $coeff2->nelem != $coeff1->nelem; |
669
|
|
|
|
|
|
|
my $res = $coeff1 - $coeff2; |
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
# print "returning ".join(',',@$res)."\n"; |
672
|
|
|
|
|
|
|
# if ($res->[@$res-1] < 0) { |
673
|
|
|
|
|
|
|
# foreach my $r (@$res) { |
674
|
|
|
|
|
|
|
# $r *= -1; |
675
|
|
|
|
|
|
|
# } |
676
|
|
|
|
|
|
|
# } |
677
|
|
|
|
|
|
|
# $res *= -1 if ($res->at($res->nelem-1) < 0); |
678
|
|
|
|
|
|
|
# return bless $res, 'PDL::Mat'; |
679
|
|
|
|
|
|
|
return $res; |
680
|
|
|
|
|
|
|
} |
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
=head2 method to_Hurwitz |
683
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
$hurwitz_matrix = $m->to_Hurwitz; |
685
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
Returns the Hurwitz matrix. |
687
|
|
|
|
|
|
|
The coefficients of the Hurwitz matrix are defined to be: |
688
|
|
|
|
|
|
|
H_ij = a_{n-2i+j} if 0 < 2i-j <= n, 0 otherwise where a_n are the |
689
|
|
|
|
|
|
|
coefficients of the characteristic polynomial. |
690
|
|
|
|
|
|
|
|
691
|
|
|
|
|
|
|
=cut |
692
|
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
sub PDL::Matrix::to_Hurwitz { |
694
|
|
|
|
|
|
|
my $matrix = shift; |
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
# my @dims = $matrix->dims; |
697
|
|
|
|
|
|
|
my $cp_coeff; |
698
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
# if (ref($matrix) =~ /PDL/) { |
700
|
|
|
|
|
|
|
if ( !$matrix->isempty ) { |
701
|
|
|
|
|
|
|
$cp_coeff = $matrix->char_pol; |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
# print "getting charac. pol. :".join(',',@$cp_coeff)."\n"; |
704
|
|
|
|
|
|
|
} |
705
|
|
|
|
|
|
|
else { |
706
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
# $cp_coeff = $matrix; |
708
|
|
|
|
|
|
|
# croak("to_Hurwitz: matrix is not 2-dim!"); |
709
|
|
|
|
|
|
|
$cp_coeff = shift; |
710
|
|
|
|
|
|
|
} |
711
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
# my $n = @$cp_coeff-1; |
713
|
|
|
|
|
|
|
my $n = $cp_coeff->nelem - 1; |
714
|
|
|
|
|
|
|
|
715
|
|
|
|
|
|
|
# my $hurwitz = ref($matrix)->new($n,$n); |
716
|
|
|
|
|
|
|
my $hurwitz = mzeroes( $n, $n ); |
717
|
|
|
|
|
|
|
for ( my $i = 1 ; $i <= $n ; $i++ ) { |
718
|
|
|
|
|
|
|
for ( |
719
|
|
|
|
|
|
|
my $j = 2 * $i - $n > 1 ? 2 * $i - $n : 1 ; |
720
|
|
|
|
|
|
|
$j <= $n && $j <= 2 * $i ; |
721
|
|
|
|
|
|
|
$j++ |
722
|
|
|
|
|
|
|
) |
723
|
|
|
|
|
|
|
{ |
724
|
|
|
|
|
|
|
|
725
|
|
|
|
|
|
|
# print "Setting ($i,$j) to a_".eval($n-2*$i+$j)."\n"; |
726
|
|
|
|
|
|
|
# set($hurwitz,$i-1,$j-1,$cp_coeff->at($n-2*$i+$j)); |
727
|
|
|
|
|
|
|
set( $hurwitz, $j - 1, $i - 1, $cp_coeff->at( $n - 2 * $i + $j ) ); |
728
|
|
|
|
|
|
|
} |
729
|
|
|
|
|
|
|
} |
730
|
|
|
|
|
|
|
|
731
|
|
|
|
|
|
|
return $hurwitz; |
732
|
|
|
|
|
|
|
} |
733
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
=head2 method Hurwitz_crit |
735
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
if ($m->Hurwitz_crit) { ... } |
737
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
Returns true if the Hurwitz condition is fulfilled, i.e. if all |
739
|
|
|
|
|
|
|
sub-determinants are larger than zero and a_n/a_0 > 0 for all n >= 1. |
740
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
=cut |
742
|
|
|
|
|
|
|
|
743
|
|
|
|
|
|
|
sub PDL::Matrix::Hurwitz_crit { |
744
|
|
|
|
|
|
|
my $matrix = shift; |
745
|
|
|
|
|
|
|
|
746
|
|
|
|
|
|
|
my $cp_coeff = $matrix->char_pol; |
747
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
$cp_coeff *= -1 if $cp_coeff->at( $cp_coeff->nelem - 1 ) < 0; |
749
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
# foreach my $c (@$cp_coeff) { |
751
|
|
|
|
|
|
|
# return(0) unless $c > 0; |
752
|
|
|
|
|
|
|
# } |
753
|
|
|
|
|
|
|
return (0) unless which( $cp_coeff > 0 )->nelem == $cp_coeff->nelem; |
754
|
|
|
|
|
|
|
|
755
|
|
|
|
|
|
|
# my $hurwitz = $cp_coeff->to_Hurwitz; |
756
|
|
|
|
|
|
|
my $hurwitz = PDL::Matrix::null->to_Hurwitz($cp_coeff); |
757
|
|
|
|
|
|
|
|
758
|
|
|
|
|
|
|
return $hurwitz->is_pos_def; |
759
|
|
|
|
|
|
|
} |
760
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
1; |