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