line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# This library file contains Amoeba n-D Minimisation routine for Perl |
2
|
|
|
|
|
|
|
# $Id: Amoeba.pm,v 1.2 1995/12/24 12:37:46 willijar Exp $ |
3
|
|
|
|
|
|
|
# $Id: Amoeba.pm,v 1.2 1995/12/24 12:37:46 willijar Exp $ |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
package Math::Amoeba; |
6
|
|
|
|
|
|
|
|
7
|
1
|
|
|
1
|
|
29387
|
use strict; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
36
|
|
8
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
42
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
our $VERSION = 0.05; |
11
|
|
|
|
|
|
|
|
12
|
1
|
|
|
1
|
|
4
|
use Carp; |
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
101
|
|
13
|
1
|
|
|
1
|
|
5
|
use constant TINY => 1e-16; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
85
|
|
14
|
|
|
|
|
|
|
|
15
|
1
|
|
|
1
|
|
4
|
use Exporter; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
1382
|
|
16
|
|
|
|
|
|
|
our @ISA=qw(Exporter); |
17
|
|
|
|
|
|
|
our @EXPORT_OK=qw(ConstructVertices EvaluateVertices Amoeba MinimiseND); |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
=head1 NAME |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
Math::Amoeba - Multidimensional Function Minimisation |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
=head1 SYNOPSIS |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
use Math::Amoeba qw(ConstructVertices EvaluateVertices Amoeba MinimiseND); |
26
|
|
|
|
|
|
|
my ($vertice,$y)=MinimiseND(\@guess,\@scales,\&func,$tol,$itmax,$verbose); |
27
|
|
|
|
|
|
|
my @vertices=ConstructVertices(\@vector,\@offsets); |
28
|
|
|
|
|
|
|
my @y=EvaluateVertices(\@vertices,\&func); |
29
|
|
|
|
|
|
|
my ($vertice,$y)=Amoeba(\@vertices,\@y,\&func,$tol,$itmax,$verbose); |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
=head1 DESCRIPTION |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
This is an implimenation of the Downhill Simpex Method in |
34
|
|
|
|
|
|
|
Multidimensions (Nelder and Mead) for finding the (local) minimum of a |
35
|
|
|
|
|
|
|
function. Doing this in Perl makes it easy for that function to |
36
|
|
|
|
|
|
|
actually be the output of another program such as a simulator. |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
Arrays and the function are passed by reference to the routines. |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
=over |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
=item C |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
The simplest use is the B function. This takes a reference |
45
|
|
|
|
|
|
|
to an array of guess values for the parameters at the function |
46
|
|
|
|
|
|
|
minimum, a reference to an array of scales for these parameters |
47
|
|
|
|
|
|
|
(sensible ranges around the guess in which to look), a reference to |
48
|
|
|
|
|
|
|
the function, a convergence tolerence for the minimum, the maximum |
49
|
|
|
|
|
|
|
number of iterations to be taken and the verbose flag (default ON). |
50
|
|
|
|
|
|
|
It returns an array consisting of a reference to the function parameters |
51
|
|
|
|
|
|
|
at the minimum and the value there. |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
=item C |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
The B function is the actual implimentation of the Downhill |
56
|
|
|
|
|
|
|
Simpex Method in Multidimensions. It takes a reference to an array of |
57
|
|
|
|
|
|
|
references to arrays which are the initial n+1 vertices (where n is |
58
|
|
|
|
|
|
|
the number of function parameters), a reference to the function |
59
|
|
|
|
|
|
|
valuation at these vertices, a reference to the function, a |
60
|
|
|
|
|
|
|
convergence tolerence for the minimum, the maximum number of |
61
|
|
|
|
|
|
|
iterations to be taken and the verbose flag (default ON). |
62
|
|
|
|
|
|
|
It returns an array consisting of a reference to the function parameters |
63
|
|
|
|
|
|
|
at the minimum and the value there. |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
=item C |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
The B is used by B to construct the |
68
|
|
|
|
|
|
|
initial vertices for B as the initial guess plus the parameter |
69
|
|
|
|
|
|
|
scale parameters as vectors along the parameter axis. |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
=item C |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
The B takes these set of vertices, calling the |
74
|
|
|
|
|
|
|
function for each one and returning the vector of results. |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
=back |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
=head1 EXAMPLE |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
use Math::Amoeba qw(MinimiseND); |
81
|
|
|
|
|
|
|
sub afunc { |
82
|
|
|
|
|
|
|
my ($a,$b)=@_; |
83
|
|
|
|
|
|
|
print "$a\t$b\n"; |
84
|
|
|
|
|
|
|
return ($a-7)**2+($b+3)**2; |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
my @guess=(1,1); |
87
|
|
|
|
|
|
|
my @scale=(1,1); |
88
|
|
|
|
|
|
|
($p,$y)=MinimiseND(\@guess,\@scale,\&afunc,1e-7,100); |
89
|
|
|
|
|
|
|
print "(",join(',',@{$p}),")=$y\n"; |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
produces the output |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
(6.99978191653352,-2.99981241563247)=1.00000008274829 |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
=head1 LICENSE |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
PERL |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
=cut |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
my ($ALPHA,$BETA,$GAMMA)=(1.0,0.5,2.0); |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
sub MinimiseND { |
104
|
1
|
|
|
1
|
1
|
83
|
my ($guesses,$scales,$func,$tol,$itmax, $verbose)=@_; |
105
|
1
|
|
|
|
|
5
|
my @p=ConstructVertices($guesses,$scales); |
106
|
1
|
|
|
|
|
5
|
my @y=EvaluateVertices(\@p,$func); |
107
|
1
|
|
|
|
|
5
|
return Amoeba(\@p,\@y,$func,$tol,$itmax, $verbose); |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
sub ConstructVertices { |
111
|
|
|
|
|
|
|
# given 2 vector references constructs an amoeba |
112
|
|
|
|
|
|
|
# returning the vertices |
113
|
1
|
|
|
1
|
1
|
1
|
my ($vector,$ofs)=@_; |
114
|
1
|
|
|
|
|
2
|
my $n=$#{$vector}; |
|
1
|
|
|
|
|
2
|
|
115
|
1
|
|
|
|
|
3
|
my @vector=@{$vector}; |
|
1
|
|
|
|
|
3
|
|
116
|
1
|
|
|
|
|
2
|
my (@p,@y,$i); |
117
|
|
|
|
|
|
|
|
118
|
1
|
|
|
|
|
2
|
$p[0]=[]; @{$p[0]}=@{$vector}; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
2
|
|
119
|
1
|
|
|
|
|
4
|
for($i=0; $i<=$n; $i++) { |
120
|
9
|
|
|
|
|
12
|
my $v=[]; @{$v}=@{$vector}; |
|
9
|
|
|
|
|
10
|
|
|
9
|
|
|
|
|
21
|
|
|
9
|
|
|
|
|
13
|
|
121
|
9
|
|
|
|
|
16
|
$v->[$i]+=$ofs->[$i]; |
122
|
9
|
|
|
|
|
25
|
$p[$i+1]=$v; |
123
|
|
|
|
|
|
|
} |
124
|
1
|
|
|
|
|
6
|
return @p; |
125
|
|
|
|
|
|
|
} |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
sub EvaluateVertices { |
128
|
|
|
|
|
|
|
# evaluates functions for all vertices of the amoeba |
129
|
1
|
|
|
1
|
1
|
3
|
my ($p,$func)=@_; |
130
|
1
|
|
|
|
|
1
|
my ($i,@y); |
131
|
1
|
|
|
|
|
3
|
for($i=0; $i<=$#{$p}; $i++) { |
|
11
|
|
|
|
|
233
|
|
132
|
10
|
|
|
|
|
11
|
$y[$i]=&$func(@{$p->[$i]}); |
|
10
|
|
|
|
|
21
|
|
133
|
|
|
|
|
|
|
} |
134
|
1
|
|
|
|
|
5
|
return @y; |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
sub Amoeba { |
138
|
|
|
|
|
|
|
|
139
|
1
|
|
|
1
|
1
|
2
|
my ($p,$y,$func,$ftol,$itmax, $verbose)=@_; |
140
|
|
|
|
|
|
|
|
141
|
1
|
|
|
|
|
9
|
my $n=$#{$p}; # no points |
|
1
|
|
|
|
|
2
|
|
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
# Default parameters |
144
|
1
|
50
|
|
|
|
3
|
$verbose = (defined($verbose)) ? $verbose : 1; |
145
|
1
|
50
|
|
|
|
3
|
if (!$itmax) { $itmax=200; } |
|
0
|
|
|
|
|
0
|
|
146
|
1
|
50
|
|
|
|
3
|
if (!$ftol) { $ftol=1e-6; } |
|
0
|
|
|
|
|
0
|
|
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
# Member variables |
149
|
1
|
|
|
|
|
2
|
my ($i,$j); |
150
|
1
|
|
|
|
|
2
|
my $iter=0; |
151
|
1
|
|
|
|
|
1
|
my ($ilo, $inhi, $ihi); |
152
|
|
|
|
|
|
|
|
153
|
0
|
|
|
|
|
0
|
my ($pbar, $pr, $pe, $pc, $ypr, $ype, $ypc); |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
# To control the recalculation of centroid |
156
|
1
|
|
|
|
|
2
|
my $recalc = 1; |
157
|
1
|
|
|
|
|
2
|
my $ihi_o; |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
# Loop until any of stopping conditions hit |
160
|
1
|
|
|
|
|
1
|
while (1) |
161
|
|
|
|
|
|
|
{ |
162
|
1482
|
|
|
|
|
2185
|
($ilo, $inhi, $ihi) = _FindMarkers($y); |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
# Stopping conditions |
165
|
1482
|
|
|
|
|
3684
|
my $rtol = 2*abs($y->[$ihi]-$y->[$ilo])/(abs($y->[$ihi])+abs($y->[$ilo])+TINY); |
166
|
1482
|
100
|
|
|
|
2597
|
if ($rtol<$ftol) { last; } |
|
1
|
|
|
|
|
4
|
|
167
|
1481
|
50
|
|
|
|
2374
|
if ($iter++>$itmax) { |
168
|
0
|
0
|
|
|
|
0
|
carp "Amoeba exceeded maximum iterations\n" if ($verbose); |
169
|
0
|
|
|
|
|
0
|
last; |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
# Determine the Centroid |
173
|
1481
|
100
|
|
|
|
1934
|
if ($recalc) { |
174
|
1
|
|
|
|
|
4
|
$pbar = _CalcCentroid($p, $ihi); |
175
|
|
|
|
|
|
|
} else { |
176
|
1480
|
|
|
|
|
3058
|
_AdjustCentroid($pbar, $p, $ihi_o, $ihi); |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
# Reset the re-calculation flag, and remember the current highest |
180
|
1481
|
|
|
|
|
1391
|
$recalc = 0; |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
# Determine the reflection point, evaluate its value |
183
|
1481
|
|
|
|
|
2463
|
$pr = _CalcReflection($pbar, $p->[$ihi], $ALPHA); |
184
|
1481
|
|
|
|
|
3531
|
$ypr = &$func(@$pr); |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
# if it gives a better value than best point, try an |
187
|
|
|
|
|
|
|
# additional extrapolation by a factor gamma, accept best |
188
|
1481
|
100
|
|
|
|
26738
|
if ($ypr < $y->[$ilo]) { |
|
|
100
|
|
|
|
|
|
189
|
|
|
|
|
|
|
|
190
|
339
|
|
|
|
|
624
|
$pe = _CalcReflection($pbar, $pr, -$GAMMA); |
191
|
339
|
|
|
|
|
843
|
$ype=&$func(@$pe); |
192
|
339
|
100
|
|
|
|
5734
|
if ($ype < $y->[$ilo]) { |
193
|
105
|
|
|
|
|
125
|
$p->[$ihi] = $pe; $y->[$ihi] = $ype; |
|
105
|
|
|
|
|
176
|
|
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
else { |
196
|
234
|
|
|
|
|
298
|
$p->[$ihi] = $pr; $y->[$ihi] = $ypr; |
|
234
|
|
|
|
|
405
|
|
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
} |
199
|
|
|
|
|
|
|
# if reflected point worse than 2nd highest |
200
|
|
|
|
|
|
|
elsif ($ypr >= $y->[$inhi]) { |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
# if it is better than highest, replace it |
203
|
428
|
100
|
|
|
|
815
|
if ($ypr < $y->[$ihi] ) { |
204
|
62
|
|
|
|
|
80
|
$p->[$ihi] = $pr; $y->[$ihi] = $ypr; |
|
62
|
|
|
|
|
102
|
|
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
# look for an intermediate lower point by performing a |
208
|
|
|
|
|
|
|
# contraction of the simplex along one dimension |
209
|
428
|
|
|
|
|
785
|
$pc = _CalcReflection($pbar, $p->[$ihi], -$BETA); |
210
|
428
|
|
|
|
|
962
|
$ypc = &$func(@$pc); |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
# if contraction gives an improvement, accept it |
213
|
428
|
50
|
|
|
|
7316
|
if ($ypc < $y->[$ihi]) { |
214
|
428
|
|
|
|
|
525
|
$p->[$ihi] = $pc; $y->[$ihi] = $ypc; |
|
428
|
|
|
|
|
666
|
|
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
# otherwise cant seem to remove high point |
217
|
|
|
|
|
|
|
# so contract around lo (best) point |
218
|
|
|
|
|
|
|
else { |
219
|
0
|
|
|
|
|
0
|
for($i=0; $i<=$n; $i++) { |
220
|
0
|
0
|
|
|
|
0
|
if ($i!=$ilo) { |
221
|
0
|
|
|
|
|
0
|
$p->[$i] = _CalcReflection($p->[$ilo], $p->[$i], -$BETA); |
222
|
0
|
|
|
|
|
0
|
$y->[$i] = &$func(@{$p->[$i]}); |
|
0
|
|
|
|
|
0
|
|
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
} |
225
|
0
|
|
|
|
|
0
|
$recalc = 1; |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
# if reflected point is in-between lowest and 2nd highest |
229
|
|
|
|
|
|
|
else { |
230
|
714
|
|
|
|
|
803
|
$p->[$ihi] = $pr; $y->[$ihi] = $ypr; |
|
714
|
|
|
|
|
1065
|
|
231
|
|
|
|
|
|
|
} |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
# Remember the replacing position and its value |
234
|
1481
|
|
|
|
|
1705
|
$ihi_o = $ihi; |
235
|
|
|
|
|
|
|
} |
236
|
|
|
|
|
|
|
|
237
|
1
|
|
|
|
|
8
|
return ($p->[$ilo],$y->[$ilo]); |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
# Helper function - find the lowest, 2nd highest and highest position |
242
|
|
|
|
|
|
|
sub _FindMarkers |
243
|
|
|
|
|
|
|
{ |
244
|
1482
|
|
|
1482
|
|
1531
|
my $y = shift; |
245
|
|
|
|
|
|
|
|
246
|
1482
|
|
|
|
|
1351
|
my ($ilo, $inhi, $ihi); |
247
|
0
|
|
|
|
|
0
|
my ($i, $n); |
248
|
|
|
|
|
|
|
|
249
|
1482
|
|
|
|
|
1442
|
$n = @$y - 1; |
250
|
|
|
|
|
|
|
|
251
|
1482
|
|
|
|
|
1337
|
$ilo=0; |
252
|
1482
|
100
|
|
|
|
2482
|
if ($y->[0]>$y->[1]) { |
253
|
637
|
|
|
|
|
574
|
$ihi=0; $inhi=1; |
|
637
|
|
|
|
|
686
|
|
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
else { |
256
|
845
|
|
|
|
|
776
|
$ihi=1; $inhi=0; |
|
845
|
|
|
|
|
862
|
|
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
|
259
|
1482
|
|
|
|
|
2905
|
for($i = 0; $i <= $n; $i++) { |
260
|
14820
|
100
|
|
|
|
27186
|
if ($y->[$i] < $y->[$ilo]) { $ilo = $i; } |
|
2728
|
|
|
|
|
2571
|
|
261
|
14820
|
100
|
100
|
|
|
59565
|
if ($y->[$i] > $y->[$ihi]) { $inhi = $ihi; $ihi = $i; } |
|
2089
|
100
|
|
|
|
2031
|
|
|
2089
|
|
|
|
|
3780
|
|
262
|
2166
|
|
|
|
|
8286
|
elsif ($y->[$i] > $y->[$inhi] && $ihi != $i) { $inhi = $i; } |
263
|
|
|
|
|
|
|
} |
264
|
|
|
|
|
|
|
|
265
|
1482
|
|
|
|
|
3078
|
return ($ilo, $inhi, $ihi); |
266
|
|
|
|
|
|
|
} |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
# Determine the centroid (except the highest point) |
269
|
|
|
|
|
|
|
sub _CalcCentroid |
270
|
|
|
|
|
|
|
{ |
271
|
1
|
|
|
1
|
|
2
|
my ($p, $ihi) = @_; |
272
|
1
|
|
|
|
|
1
|
my ($i, $j, $n); |
273
|
|
|
|
|
|
|
|
274
|
1
|
|
|
|
|
2
|
$n = @$p - 1; |
275
|
|
|
|
|
|
|
|
276
|
1
|
|
|
|
|
2
|
my $pbar = []; |
277
|
1
|
|
|
|
|
4
|
for($j=0; $j<$n; $j++) { |
278
|
9
|
|
|
|
|
16
|
for($i=0; $i<=$n; $i++) { |
279
|
90
|
100
|
|
|
|
146
|
if ($i!=$ihi) { |
280
|
81
|
|
|
|
|
171
|
$pbar->[$j] += $p->[$i][$j]; |
281
|
|
|
|
|
|
|
} |
282
|
|
|
|
|
|
|
} |
283
|
9
|
|
|
|
|
20
|
$pbar->[$j] /= $n; |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
|
286
|
1
|
|
|
|
|
3
|
return $pbar; |
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
# Adjust the centroid only |
290
|
|
|
|
|
|
|
sub _AdjustCentroid |
291
|
|
|
|
|
|
|
{ |
292
|
1480
|
|
|
1480
|
|
1791
|
my ($pbar, $p, $ihi_o, $ihi) = @_; |
293
|
1480
|
|
|
|
|
1296
|
my ($j, $n); |
294
|
|
|
|
|
|
|
|
295
|
1480
|
|
|
|
|
1378
|
$n = @$pbar; |
296
|
|
|
|
|
|
|
|
297
|
1480
|
50
|
|
|
|
2592
|
if ($ihi_o != $ihi) { |
298
|
1480
|
|
|
|
|
2794
|
for($j=0; $j<$n; $j++) { |
299
|
13320
|
|
|
|
|
32826
|
$pbar->[$j] += ($p->[$ihi_o][$j] - $p->[$ihi][$j]) / $n; |
300
|
|
|
|
|
|
|
} |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
# Determine the reflection point |
305
|
|
|
|
|
|
|
sub _CalcReflection |
306
|
|
|
|
|
|
|
{ |
307
|
2248
|
|
|
2248
|
|
2595
|
my ($p1, $p2, $scale) = @_; |
308
|
2248
|
|
|
|
|
1878
|
my $j; |
309
|
|
|
|
|
|
|
|
310
|
2248
|
|
|
|
|
2122
|
my $n = @$p1; |
311
|
|
|
|
|
|
|
|
312
|
2248
|
|
|
|
|
2589
|
my $pr = []; |
313
|
2248
|
|
|
|
|
4691
|
for($j=0; $j<$n; $j++) { |
314
|
20232
|
|
|
|
|
51828
|
$pr->[$j] = $p1->[$j] + $scale*($p1->[$j]-$p2->[$j]); |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
|
317
|
2248
|
|
|
|
|
3673
|
return $pr; |
318
|
|
|
|
|
|
|
} |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
return 1; |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
__END__ |