| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package PDL::Opt::Simplex; |
|
2
|
1
|
|
|
1
|
|
260917
|
use strict; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
41
|
|
|
3
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
59
|
|
|
4
|
1
|
|
|
1
|
|
8
|
use PDL; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
43
|
|
|
5
|
1
|
|
|
1
|
|
130583
|
use PDL::Exporter; |
|
|
1
|
|
|
|
|
6
|
|
|
|
1
|
|
|
|
|
7
|
|
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our @ISA = qw/PDL::Exporter/; |
|
8
|
|
|
|
|
|
|
our @EXPORT_OK = qw/simplex make_simplex/; |
|
9
|
|
|
|
|
|
|
our %EXPORT_TAGS = ( Func => [@EXPORT_OK] ); |
|
10
|
|
|
|
|
|
|
our $VERSION = '2.097'; |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
*simplex = \&PDL::simplex; |
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
sub make_simplex { |
|
15
|
7
|
|
|
7
|
0
|
3667
|
my ($init, $initsize) = @_; |
|
16
|
7
|
|
|
|
|
41
|
my ( $nd, $nd2, @otherdims ) = ( $init->dims, 1 ); |
|
17
|
7
|
100
|
|
|
|
29
|
pop @otherdims if @otherdims; # drop the spurious "1" |
|
18
|
7
|
50
|
66
|
|
|
47
|
return unless $nd2 == $nd + 1 or $nd2 == 1; |
|
19
|
7
|
100
|
|
|
|
33
|
return $init if $nd2 == $nd + 1; |
|
20
|
5
|
|
|
|
|
110
|
my $simp = PDL->zeroes( $nd, $nd + 1, @otherdims ); |
|
21
|
|
|
|
|
|
|
# Constructing a tetrahedron: |
|
22
|
|
|
|
|
|
|
# At step n (starting from zero) |
|
23
|
|
|
|
|
|
|
# take vertices 0..n and move them 1/(n+1) to negative dir on axis n. |
|
24
|
|
|
|
|
|
|
# Take vertex n+1 and move it n/(n+1) to positive dir on axis n |
|
25
|
5
|
|
|
|
|
22
|
my $uppertri = $simp->copy; |
|
26
|
5
|
|
|
|
|
126
|
ones($nd * ($nd+1) / 2)->tritosquare($uppertri->slice(",:-2")->t); |
|
27
|
5
|
|
|
|
|
1008
|
my $iseq = sequence($nd); |
|
28
|
5
|
|
|
|
|
554
|
my $pjseq = $iseq / ( $iseq + 1 ); |
|
29
|
5
|
|
|
|
|
433
|
$simp .= $init - $initsize * $pjseq * $uppertri; |
|
30
|
5
|
|
|
|
|
447
|
$simp->slice(",1:")->diagonal(0,1) += $initsize * (1-$pjseq); |
|
31
|
5
|
|
|
|
|
636
|
$simp; |
|
32
|
|
|
|
|
|
|
} |
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
sub PDL::simplex { |
|
35
|
6
|
|
|
6
|
0
|
322660
|
my ( $init, $initsize, $minsize, $maxiter, $sub, $logsub, $t ) = @_; |
|
36
|
6
|
|
50
|
|
|
31
|
my $simp = make_simplex($init, $initsize) // return; |
|
37
|
6
|
|
|
|
|
39
|
my $nd = $simp->dim(0); |
|
38
|
6
|
|
|
|
|
24
|
my $vals = $sub->($simp); |
|
39
|
6
|
|
|
|
|
618
|
my $ssize; |
|
40
|
6
|
|
|
|
|
24
|
while ($maxiter--) { |
|
41
|
354
|
|
|
|
|
16285
|
$ssize = ( $simp - $simp->slice(":,0") )->magnover->maxover; |
|
42
|
354
|
100
|
|
|
|
19263
|
$logsub->( $simp, $vals, $ssize ) if $logsub; |
|
43
|
354
|
100
|
|
|
|
1366
|
last unless $ssize > $minsize; |
|
44
|
348
|
50
|
|
|
|
28026
|
my $valsn = !$t ? $vals : $vals - $t * log( $vals->random + 0.00001 ); |
|
45
|
348
|
|
|
|
|
3218
|
my $minind = $valsn->minimum_ind; |
|
46
|
348
|
|
|
|
|
1206
|
my $maxind = $valsn->maxover_n_ind(2); |
|
47
|
348
|
|
|
|
|
10326
|
my $maxind0 = $maxind->at(0); |
|
48
|
348
|
|
|
|
|
4600
|
my @worstvals = $valsn->index($maxind)->list; |
|
49
|
348
|
|
|
|
|
7467
|
my $bestval = $valsn->at($minind); |
|
50
|
348
|
|
|
|
|
14872
|
my $ssum = ($simp->t->sumover - (my $worst = $simp->slice(":,($maxind0)"))) / $nd; |
|
51
|
348
|
|
|
|
|
31198
|
my $new = 2 * $ssum - $worst; |
|
52
|
348
|
|
|
|
|
9241
|
my $val = $sub->($new)->at(0); |
|
53
|
348
|
50
|
|
|
|
21175
|
$val += $t * log( rand() + 0.00001 ) if $t; |
|
54
|
348
|
|
|
|
|
655
|
my $removetop = 0; |
|
55
|
348
|
100
|
|
|
|
1064
|
if ( $val < $bestval ) { |
|
|
|
100
|
|
|
|
|
|
|
56
|
115
|
|
|
|
|
283
|
my $newnew = $new + $ssum - $worst; |
|
57
|
115
|
|
|
|
|
2814
|
my $val2 = $sub->($newnew); |
|
58
|
115
|
100
|
|
|
|
5269
|
if ( $val2->at(0) < $val ) { # CASE1 Reflection and Expansion |
|
59
|
80
|
|
|
|
|
861
|
$new = $newnew; |
|
60
|
80
|
|
|
|
|
145
|
$val = $val2; |
|
61
|
|
|
|
|
|
|
} # else CASE2 Reflection |
|
62
|
115
|
|
|
|
|
541
|
$removetop = 1; |
|
63
|
|
|
|
|
|
|
} elsif ( $val < $worstvals[1] ) { # CASE3 Reflection |
|
64
|
39
|
|
|
|
|
58
|
$removetop = 1; |
|
65
|
|
|
|
|
|
|
} else { |
|
66
|
194
|
|
|
|
|
474
|
my $newnew = 0.5 * ($ssum + $worst); |
|
67
|
194
|
|
|
|
|
6432
|
my $val2 = $sub->($newnew); |
|
68
|
194
|
50
|
|
|
|
9760
|
if ( $val2->at(0) < $worstvals[0] ) { # CASE4 Contraction |
|
69
|
194
|
|
|
|
|
2146
|
$new = $newnew; |
|
70
|
194
|
|
|
|
|
301
|
$val = $val2; |
|
71
|
194
|
|
|
|
|
351
|
$removetop = 1; |
|
72
|
|
|
|
|
|
|
} |
|
73
|
|
|
|
|
|
|
} |
|
74
|
348
|
50
|
|
|
|
773
|
if ($removetop) { |
|
75
|
348
|
|
|
|
|
1102
|
$worst .= $new; |
|
76
|
348
|
|
|
|
|
5965
|
$vals->slice( "($maxind0)" ) .= $val; |
|
77
|
|
|
|
|
|
|
} else { # CASE5 Multiple Contraction |
|
78
|
0
|
|
|
|
|
0
|
$simp .= 0.5 * ($simp->slice(":,$minind") + $simp); |
|
79
|
0
|
|
|
|
|
0
|
my $idx = which( sequence($nd+1) != $minind ); |
|
80
|
0
|
|
|
|
|
0
|
$vals->index($idx) .= $sub->($simp->dice_axis(1,$idx)); |
|
81
|
|
|
|
|
|
|
} |
|
82
|
|
|
|
|
|
|
} |
|
83
|
6
|
|
|
|
|
511
|
my $mmind = $vals->minimum_ind; |
|
84
|
6
|
|
|
|
|
46
|
return ( $simp->slice(":,$mmind"), $ssize, $vals->index($mmind) ); |
|
85
|
|
|
|
|
|
|
} |
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
1; |
|
88
|
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
__END__ |