line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Math::Vector::Real::Farthest; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
our $VERSION = '0.02'; |
4
|
|
|
|
|
|
|
|
5
|
1
|
|
|
1
|
|
18547
|
use strict; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
45
|
|
6
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
36
|
|
7
|
|
|
|
|
|
|
|
8
|
1
|
|
|
1
|
|
6
|
use Math::Vector::Real; |
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
55
|
|
9
|
1
|
|
|
1
|
|
1093
|
use Sort::Key::Top qw(nslotpartref); |
|
1
|
|
|
|
|
1950
|
|
|
1
|
|
|
|
|
211
|
|
10
|
1
|
|
|
1
|
|
877
|
use Math::nSphere qw(nsphere_volumen); |
|
1
|
|
|
|
|
591
|
|
|
1
|
|
|
|
|
63
|
|
11
|
1
|
|
|
1
|
|
6
|
use Carp; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
106
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
our $optimization_core = 1; |
14
|
|
|
|
|
|
|
our $optimization_convex_hull = 0; |
15
|
|
|
|
|
|
|
our $threshold_brute_force = 16; |
16
|
|
|
|
|
|
|
our $O = 0; |
17
|
|
|
|
|
|
|
|
18
|
1
|
|
|
1
|
|
6
|
use constant _c0 => 0; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
81
|
|
19
|
1
|
|
|
1
|
|
6
|
use constant _c1 => 1; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
42
|
|
20
|
1
|
|
|
1
|
|
5
|
use constant _n => 2; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
50
|
|
21
|
1
|
|
|
1
|
|
5
|
use constant _vs => 3; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
41
|
|
22
|
1
|
|
|
1
|
|
5
|
use constant _s0 => 4; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
56
|
|
23
|
1
|
|
|
1
|
|
5
|
use constant _s1 => 5; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
2502
|
|
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
sub _find_brute_force { |
26
|
126
|
|
|
126
|
|
220
|
my $best_d2 = 0; |
27
|
126
|
|
|
|
|
298
|
my @best_vs = ($_[0], $_[0]); |
28
|
|
|
|
|
|
|
|
29
|
126
|
|
|
|
|
348
|
for my $i (0..$#_) { |
30
|
10642
|
|
|
|
|
24789
|
for my $j ($i + 1..$#_) { |
31
|
1836314
|
|
|
|
|
2422415
|
my $vi = $_[$i]; |
32
|
1836314
|
|
|
|
|
2038411
|
my $vj = $_[$j]; |
33
|
1836314
|
|
|
|
|
3714456
|
my $d2 = Math::Vector::Real::dist2($vi, $vj); |
34
|
1836314
|
100
|
|
|
|
44046019
|
if ($d2 > $best_d2) { |
35
|
837
|
|
|
|
|
955
|
$best_d2 = $d2; |
36
|
837
|
|
|
|
|
2348
|
@best_vs = ($vi, $vj); |
37
|
|
|
|
|
|
|
} |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
} |
40
|
|
|
|
|
|
|
|
41
|
126
|
50
|
|
|
|
911
|
wantarray ? ($best_d2, map V(@$_), @best_vs) : $best_d2; |
42
|
|
|
|
|
|
|
} |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
sub _find_1d { |
45
|
7
|
|
|
7
|
|
20
|
my $max = $_[0][0]; |
46
|
7
|
|
|
|
|
15
|
my $min = $max; |
47
|
7
|
100
|
|
|
|
26
|
shift if @_ & 1; |
48
|
7
|
|
|
|
|
22
|
while (@_) { |
49
|
233
|
|
|
|
|
322
|
my $a = shift->[0]; |
50
|
233
|
|
|
|
|
263
|
my $b = shift->[0]; |
51
|
233
|
100
|
|
|
|
512
|
if ($a > $b) { |
52
|
132
|
100
|
|
|
|
338
|
$max = $a if $a > $max; |
53
|
132
|
100
|
|
|
|
346
|
$min = $b if $b < $min; |
54
|
|
|
|
|
|
|
} |
55
|
|
|
|
|
|
|
else { |
56
|
101
|
100
|
|
|
|
174
|
$max = $b if $b > $max; |
57
|
101
|
100
|
|
|
|
269
|
$min = $a if $a < $min; |
58
|
|
|
|
|
|
|
} |
59
|
|
|
|
|
|
|
} |
60
|
7
|
|
|
|
|
14
|
my $d = $max - $min; |
61
|
7
|
|
|
|
|
13
|
my $d2 = $d * $d; |
62
|
7
|
50
|
|
|
|
38
|
wantarray ? ($d2, V($min), V($max)) : $d2; |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
my $skr_loaded; |
67
|
|
|
|
|
|
|
sub _find_2d_convex_hull { |
68
|
|
|
|
|
|
|
|
69
|
0
|
0
|
|
0
|
|
0
|
$skr_loaded++ or require Sort::Key::Radix; |
70
|
0
|
|
|
0
|
|
0
|
my @p = &Sort::Key::Radix::nkeysort(sub { $_->[0] }, @_); |
|
0
|
|
|
|
|
0
|
|
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
# use GD; |
73
|
|
|
|
|
|
|
# my $size = 1024; |
74
|
|
|
|
|
|
|
# my $im = new GD::Image($size, $size); |
75
|
|
|
|
|
|
|
# my $white = $im->colorAllocate(255,255,255); |
76
|
|
|
|
|
|
|
# my $black = $im->colorAllocate(0,0,0); |
77
|
|
|
|
|
|
|
# my $blue = $im->colorAllocate(0,0,255); |
78
|
|
|
|
|
|
|
# my $red = $im->colorAllocate(255,0,0); |
79
|
|
|
|
|
|
|
# my $green = $im->colorAllocate(0,255,0); |
80
|
|
|
|
|
|
|
# my $gray = $im->colorAllocate(200, 200, 200); |
81
|
|
|
|
|
|
|
# my $yellow = $im->colorAllocate(255, 255, 0); |
82
|
|
|
|
|
|
|
# $im->rectangle(0, 0, $size, $size, $white); |
83
|
|
|
|
|
|
|
# $im->filledEllipse($_->[0] * $size, $_->[1] * $size, 2, 2, $black) for @p; |
84
|
|
|
|
|
|
|
|
85
|
0
|
|
|
|
|
0
|
my (@u, @l); |
86
|
0
|
|
|
|
|
0
|
my $i = 0; |
87
|
0
|
|
|
|
|
0
|
while ($i < @p) { |
88
|
0
|
|
|
|
|
0
|
my $iu = my $il = $i; |
89
|
0
|
|
|
|
|
0
|
my ($x, $yu) = @{$p[$i]}; |
|
0
|
|
|
|
|
0
|
|
90
|
0
|
|
|
|
|
0
|
my $yl = $yu; |
91
|
|
|
|
|
|
|
# search for upper and lower Y for the current X |
92
|
0
|
|
0
|
|
|
0
|
while (++$i < @p and $p[$i][0] == $x) { |
93
|
0
|
|
|
|
|
0
|
my $y = $p[$i][1]; |
94
|
0
|
0
|
|
|
|
0
|
if ($y < $yl) { |
|
|
0
|
|
|
|
|
|
95
|
0
|
|
|
|
|
0
|
$il = $i; |
96
|
0
|
|
|
|
|
0
|
$yl = $y; |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
elsif ($y > $yu) { |
99
|
0
|
|
|
|
|
0
|
$iu = $i; |
100
|
0
|
|
|
|
|
0
|
$yu = $y; |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
} |
103
|
0
|
|
|
|
|
0
|
while (@l >= 2) { |
104
|
0
|
|
|
|
|
0
|
my ($ox, $oy) = @{$l[-2]}; |
|
0
|
|
|
|
|
0
|
|
105
|
0
|
0
|
|
|
|
0
|
last if ($l[-1][1] - $oy) * ($x - $ox) < ($yl - $oy) * ($l[-1][0] - $ox); |
106
|
0
|
|
|
|
|
0
|
pop @l; |
107
|
|
|
|
|
|
|
} |
108
|
0
|
|
|
|
|
0
|
push @l, $p[$il]; |
109
|
0
|
|
|
|
|
0
|
while (@u >= 2) { |
110
|
0
|
|
|
|
|
0
|
my ($ox, $oy) = @{$u[-2]}; |
|
0
|
|
|
|
|
0
|
|
111
|
0
|
0
|
|
|
|
0
|
last if ($u[-1][1] - $oy) * ($x - $ox) > ($yu - $oy) * ($u[-1][0] - $ox); |
112
|
0
|
|
|
|
|
0
|
pop @u; |
113
|
|
|
|
|
|
|
} |
114
|
0
|
|
|
|
|
0
|
push @u, $p[$iu]; |
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
# $im->filledEllipse($_->[0] * $size, $_->[1] * $size, 12, 12, $blue) for @u; |
118
|
|
|
|
|
|
|
# $im->filledEllipse($_->[0] * $size, $_->[1] * $size, 12, 12, $green) for @l; |
119
|
|
|
|
|
|
|
|
120
|
0
|
|
|
|
|
0
|
my $u = $l[-1]; |
121
|
0
|
|
|
|
|
0
|
my $l = $u[0]; |
122
|
0
|
|
|
|
|
0
|
my $d = V(0, 1); |
123
|
0
|
0
|
|
|
|
0
|
pop @u if $u->[1] == $u[-1][1]; |
124
|
0
|
0
|
|
|
|
0
|
shift @l if $l->[1] == $l[0][1]; |
125
|
0
|
|
|
|
|
0
|
my $best_d2 = 0; |
126
|
0
|
|
|
|
|
0
|
my @best_vs = ($u, $u); |
127
|
0
|
|
|
|
|
0
|
while (1) { |
128
|
|
|
|
|
|
|
# print "u: $u, l: $l\n"; |
129
|
|
|
|
|
|
|
# $im->line(map($_ * $size, @$u, @$l), $yellow); |
130
|
0
|
|
|
|
|
0
|
my $d2 = Math::Vector::Real::dist2($u, $l); |
131
|
0
|
0
|
|
|
|
0
|
if ($d2 > $best_d2) { |
132
|
0
|
|
|
|
|
0
|
$best_d2 = $d2; |
133
|
0
|
|
|
|
|
0
|
@best_vs = ($u, $l); |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
|
136
|
0
|
0
|
|
|
|
0
|
if (not @u) { |
|
|
0
|
|
|
|
|
|
137
|
0
|
0
|
|
|
|
0
|
last unless @l; |
138
|
0
|
|
|
|
|
0
|
$l = shift @l; |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
elsif(not @l) { |
141
|
0
|
|
|
|
|
0
|
$u = pop @u; |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
else { |
144
|
0
|
|
|
|
|
0
|
my $du = Math::Vector::Real::versor($u[-1] - $u); |
145
|
0
|
|
|
|
|
0
|
my $dl = Math::Vector::Real::versor($l - $l[0]); |
146
|
0
|
0
|
|
|
|
0
|
if ($du * $d > $dl * $d) { |
147
|
0
|
|
|
|
|
0
|
$u = pop @u; |
148
|
0
|
|
|
|
|
0
|
$d = $du; |
149
|
|
|
|
|
|
|
} |
150
|
|
|
|
|
|
|
else { |
151
|
0
|
|
|
|
|
0
|
$l = shift @l; |
152
|
0
|
|
|
|
|
0
|
$d = $dl; |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
#my ($alt_d2, @alt_vs) = _find_brute_force(@_); |
159
|
|
|
|
|
|
|
#if ($alt_d2 != $best_d2) { |
160
|
|
|
|
|
|
|
#$im->filledEllipse($_->[0] * $size, $_->[1] * $size, 8, 8, $gray) for @best_vs; |
161
|
|
|
|
|
|
|
#$im->filledEllipse($_->[0] * $size, $_->[1] * $size, 4, 4, $red) for @alt_vs; |
162
|
|
|
|
|
|
|
#open my $fh, '>', "frame.png"; |
163
|
|
|
|
|
|
|
#print $fh $im->png; |
164
|
|
|
|
|
|
|
#exit -1; |
165
|
|
|
|
|
|
|
#} |
166
|
0
|
0
|
|
|
|
0
|
wantarray ? ($best_d2, map V(@$_), @best_vs) : $best_d2; |
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
sub find { |
170
|
100
|
|
|
100
|
1
|
5292254
|
shift; |
171
|
|
|
|
|
|
|
|
172
|
100
|
50
|
|
|
|
435
|
return unless @_; |
173
|
100
|
|
|
|
|
148
|
my $dim = @{$_[0]}; |
|
100
|
|
|
|
|
345
|
|
174
|
|
|
|
|
|
|
|
175
|
100
|
|
|
|
|
190
|
my @vs; |
176
|
100
|
100
|
|
|
|
345
|
if (@_ <= 10) { |
177
|
33
|
100
|
|
|
|
708
|
if (@_ <= 2) { |
178
|
|
|
|
|
|
|
# shortcut for sets of 1 and 2 elements |
179
|
5
|
|
|
|
|
19
|
my @best_vs = @_[0, -1]; |
180
|
5
|
|
|
|
|
18
|
my $best_d2 = Math::Vector::Real::dist2(@best_vs); |
181
|
5
|
50
|
|
|
|
123
|
return (wantarray ? ($best_d2, map V(@$_), @best_vs) : $best_d2); |
182
|
|
|
|
|
|
|
} |
183
|
28
|
100
|
|
|
|
227
|
$dim > 1 and goto &_find_brute_force; |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
|
186
|
69
|
100
|
|
|
|
214
|
if ($dim <= 2) { |
187
|
|
|
|
|
|
|
# use specialized algorithm for 1D |
188
|
12
|
100
|
|
|
|
75
|
$dim == 1 and goto &_find_1d; |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
# use specialized algorithm for 2D |
191
|
5
|
50
|
|
|
|
21
|
goto &_find_2d_convex_hull if $optimization_convex_hull; |
192
|
|
|
|
|
|
|
} |
193
|
|
|
|
|
|
|
|
194
|
62
|
|
|
|
|
98
|
my ($best_d2, @best_vs); |
195
|
|
|
|
|
|
|
### $O++; |
196
|
62
|
|
|
|
|
574
|
my ($c0, $c1) = Math::Vector::Real->box(@_); |
197
|
62
|
|
|
|
|
148959
|
my $diag = $c1 - $c0; |
198
|
62
|
|
|
|
|
1971
|
my $max_comp = $diag->max_component; |
199
|
62
|
|
|
|
|
1265
|
$best_d2 = $max_comp * $max_comp; |
200
|
62
|
50
|
|
|
|
188
|
if ($best_d2) { |
201
|
|
|
|
|
|
|
|
202
|
62
|
|
|
|
|
136
|
my $vs0; |
203
|
|
|
|
|
|
|
|
204
|
62
|
50
|
|
|
|
196
|
if ($optimization_core) { |
205
|
|
|
|
|
|
|
# There is a place in the center of the box which is |
206
|
|
|
|
|
|
|
# guaranteed to not contain any of the target vectors. We |
207
|
|
|
|
|
|
|
# calculate its aproximate hyper-volumen and if it is at least |
208
|
|
|
|
|
|
|
# 10% of that of the box we filter out the points within. This |
209
|
|
|
|
|
|
|
# heuristic works well when the vectors are evenly |
210
|
|
|
|
|
|
|
# distributed. |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
# Benchmarks show that this optimization can provide a |
213
|
|
|
|
|
|
|
# huge gain in some cases while non impacting performance |
214
|
|
|
|
|
|
|
# on the rest. |
215
|
|
|
|
|
|
|
|
216
|
62
|
|
|
|
|
510
|
my $nellipsoid_volumen = nsphere_volumen(scalar(@$diag)); |
217
|
62
|
|
|
|
|
626
|
my $ncube_volumen = 1; |
218
|
62
|
|
|
|
|
239
|
my $half = 0.5 * $diag; |
219
|
62
|
|
|
|
|
886
|
my $t2 = $half->abs2 - $best_d2; |
220
|
62
|
|
|
|
|
929
|
for my $ix (0..$#$half) { |
221
|
369
|
|
|
|
|
470
|
my $y = $half->[$ix]; |
222
|
369
|
|
|
|
|
457
|
my $y2 = $y * $y; |
223
|
369
|
100
|
|
|
|
807
|
if ($t2 + 3 * $y2 > 0) { |
224
|
367
|
100
|
|
|
|
1976
|
if ($y2 > $t2) { |
225
|
104
|
|
|
|
|
177
|
$y = sqrt($y2 - $t2) - $y; |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
else { |
228
|
263
|
|
|
|
|
328
|
$y = 0; |
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
} |
231
|
369
|
|
|
|
|
444
|
$nellipsoid_volumen *= $y; |
232
|
369
|
|
|
|
|
1310
|
$ncube_volumen *= $diag->[$ix]; |
233
|
|
|
|
|
|
|
} |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
# we don't want to discard points that are at a distance |
236
|
|
|
|
|
|
|
# exactly equal to the bigest box side, so we apply a small |
237
|
|
|
|
|
|
|
# correction factor here: |
238
|
62
|
|
|
|
|
160
|
$best_d2 *= 0.99999; |
239
|
|
|
|
|
|
|
|
240
|
62
|
100
|
|
|
|
177
|
if ($nellipsoid_volumen > $ncube_volumen * 0.1) { |
241
|
|
|
|
|
|
|
# we aim at discarding at least 10% of the points |
242
|
5
|
|
|
|
|
23
|
my $zero = 0.5 * ($c0 + $c1); |
243
|
5
|
|
|
|
|
119
|
my $corner = $c0 - $zero; |
244
|
5
|
|
|
|
|
81
|
$vs0 = [grep { Math::Vector::Real::dist2($corner, ($_ - $zero)->first_orthant_reflection) > $best_d2 } @_]; |
|
493
|
|
|
|
|
15471
|
|
245
|
|
|
|
|
|
|
} |
246
|
|
|
|
|
|
|
else { |
247
|
57
|
|
|
|
|
381
|
$vs0 = \@_; |
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
} |
250
|
|
|
|
|
|
|
else { |
251
|
0
|
|
|
|
|
0
|
$best_d2 *= 0.99999; |
252
|
0
|
|
|
|
|
0
|
$vs0 = \@_; |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
|
255
|
62
|
|
|
|
|
444
|
my @d2 = $diag->abs2; |
256
|
62
|
|
|
|
|
772
|
my @a = [$c0, $c1, scalar(@$vs0), $vs0]; |
257
|
62
|
|
|
|
|
135
|
my @b = undef; |
258
|
|
|
|
|
|
|
|
259
|
62
|
|
|
|
|
170
|
while (@d2) { |
260
|
14132
|
|
|
|
|
22905
|
my $d2 = pop @d2; |
261
|
14132
|
100
|
|
|
|
33237
|
$d2 > $best_d2 or last; |
262
|
|
|
|
|
|
|
### $O++; |
263
|
14116
|
|
|
|
|
24375
|
my $a = pop @a; |
264
|
14116
|
|
|
|
|
25260
|
my $b = pop @b; |
265
|
14116
|
100
|
100
|
|
|
80911
|
($a, $b) = ($b, $a) if $b and $a->[_n] < $b->[_n]; |
266
|
14116
|
100
|
|
|
|
35884
|
if (my $avs = $a->[_vs]) { |
267
|
7041
|
100
|
|
|
|
15828
|
if ($a->[_n] <= $threshold_brute_force) { |
268
|
6296
|
100
|
|
|
|
12445
|
if ($b) { |
269
|
|
|
|
|
|
|
# brute force |
270
|
|
|
|
|
|
|
### $O += @$avs * $b->[_n]; |
271
|
6199
|
|
|
|
|
11700
|
for my $v0 (@{$b->[_vs]}) { |
|
6199
|
|
|
|
|
18395
|
|
272
|
73742
|
|
|
|
|
113991
|
for my $v1 (@$avs) { |
273
|
954822
|
|
|
|
|
1963931
|
my $d2 = Math::Vector::Real::dist2($v0, $v1); |
274
|
954822
|
100
|
|
|
|
30387231
|
if ($best_d2 < $d2) { |
275
|
448
|
|
|
|
|
514
|
$best_d2 = $d2; |
276
|
448
|
|
|
|
|
1083
|
@best_vs = ($v0, $v1); |
277
|
|
|
|
|
|
|
} |
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
} |
281
|
|
|
|
|
|
|
else { |
282
|
|
|
|
|
|
|
### $O += ((@$avs - 1) * @$avs) >> 1; |
283
|
97
|
|
|
|
|
225
|
for my $i (1..$#$avs) { |
284
|
967
|
|
|
|
|
1316
|
my $v0 = $avs->[$i]; |
285
|
967
|
|
|
|
|
2103
|
for my $v1 (@$avs[0 .. $i - 1]) { |
286
|
5566
|
|
|
|
|
11206
|
my $d2 = Math::Vector::Real::dist2($v0, $v1); |
287
|
5566
|
100
|
|
|
|
151660
|
if ($best_d2 < $d2) { |
288
|
27
|
|
|
|
|
37
|
$best_d2 = $d2; |
289
|
27
|
|
|
|
|
65
|
@best_vs = ($v0, $v1); |
290
|
|
|
|
|
|
|
} |
291
|
|
|
|
|
|
|
} |
292
|
|
|
|
|
|
|
} |
293
|
|
|
|
|
|
|
} |
294
|
6296
|
|
|
|
|
30266
|
next; |
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
# else part it in two... |
298
|
|
|
|
|
|
|
### $O += @$avs; |
299
|
745
|
|
|
|
|
2594
|
my $ix = ($a->[_c0] - $a->[_c1])->max_component_index; |
300
|
745
|
|
|
|
|
49292
|
my ($avs0, $avs1) = nslotpartref $ix => @$avs / 2 => @$avs; |
301
|
745
|
|
|
|
|
3155
|
$a->[_s0] = [Math::Vector::Real->box(@$avs0), scalar(@$avs0), $avs0]; |
302
|
745
|
|
|
|
|
372452
|
$a->[_s1] = [Math::Vector::Real->box(@$avs1), scalar(@$avs1), $avs1]; |
303
|
745
|
|
|
|
|
363956
|
undef $a->[_vs]; |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
# and fall-through... |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
|
308
|
7820
|
|
|
|
|
11591
|
my ($a0, $a1) = @{$a}[_s0, _s1]; |
|
7820
|
|
|
|
|
18163
|
|
309
|
|
|
|
|
|
|
# If $b is defined we generate the combinations ($a0-$b, |
310
|
|
|
|
|
|
|
# $a1-$b), otherwise it means we want to compare a with |
311
|
|
|
|
|
|
|
# itself and so we generate the trio of pairs ($a0-$a1, |
312
|
|
|
|
|
|
|
# $a0-$a0, $a1-$a1). |
313
|
7820
|
|
|
|
|
9318
|
my (@na, @nb, @nd2); |
314
|
7820
|
100
|
|
|
|
16339
|
if ($b) { |
315
|
7434
|
|
|
|
|
15220
|
@na = ($a0, $a1); |
316
|
7434
|
|
|
|
|
11885
|
@nb = ($b, $b); |
317
|
7434
|
|
|
|
|
15146
|
@nd2 = (Math::Vector::Real->max_dist2_between_boxes(@{$a0}[_c0, _c1], @{$b}[_c0, _c1]), |
|
7434
|
|
|
|
|
36459
|
|
|
7434
|
|
|
|
|
1488662
|
|
318
|
7434
|
|
|
|
|
9512
|
Math::Vector::Real->max_dist2_between_boxes(@{$a1}[_c0, _c1], @{$b}[_c0, _c1])); |
|
7434
|
|
|
|
|
23237
|
|
319
|
|
|
|
|
|
|
} |
320
|
|
|
|
|
|
|
else { |
321
|
386
|
|
|
|
|
892
|
@na = ($a0, $a0, $a1); |
322
|
386
|
|
|
|
|
617
|
@nb = ($a1); |
323
|
386
|
|
|
|
|
862
|
@nd2 = (Math::Vector::Real->max_dist2_between_boxes(@{$a0}[_c0, _c1], @{$a1}[_c0, _c1]), |
|
386
|
|
|
|
|
2153
|
|
|
386
|
|
|
|
|
47383
|
|
324
|
386
|
|
|
|
|
12236
|
Math::Vector::Real::dist2(@{$a0}[_c0, _c1]), |
325
|
386
|
|
|
|
|
654
|
Math::Vector::Real::dist2(@{$a1}[_c0, _c1])); |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
|
328
|
7820
|
|
|
|
|
827578
|
while (@na) { |
329
|
16026
|
|
|
|
|
22758
|
my $a = shift @na; |
330
|
16026
|
|
|
|
|
22547
|
my $b = shift @nb; |
331
|
16026
|
|
|
|
|
19965
|
my $d2 = shift @nd2; |
332
|
|
|
|
|
|
|
|
333
|
16026
|
100
|
|
|
|
38821
|
if ($d2 > $best_d2) { |
334
|
14179
|
|
|
|
|
13178
|
my $p; |
335
|
14179
|
|
|
|
|
31537
|
for ($p = @d2; $p > 0; $p--) { |
336
|
|
|
|
|
|
|
### $O++; |
337
|
2198637
|
100
|
|
|
|
5436440
|
last if $d2[$p - 1] <= $d2; |
338
|
|
|
|
|
|
|
} |
339
|
14179
|
|
|
|
|
29543
|
splice @d2, $p, 0, $d2; |
340
|
14179
|
|
|
|
|
22706
|
splice @a, $p, 0, $a; |
341
|
14179
|
|
|
|
|
59193
|
splice @b, $p, 0, $b; |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
} |
344
|
|
|
|
|
|
|
} |
345
|
|
|
|
|
|
|
} |
346
|
|
|
|
|
|
|
else { |
347
|
0
|
|
|
|
|
0
|
@best_vs = ($_[0], $_[0]); |
348
|
|
|
|
|
|
|
} |
349
|
62
|
50
|
|
|
|
479
|
wantarray ? ($best_d2, map V(@$_), @best_vs) : $best_d2; |
350
|
|
|
|
|
|
|
} |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
sub find_brute_force { |
353
|
100
|
|
|
100
|
1
|
2918
|
shift; |
354
|
100
|
|
|
|
|
531
|
goto &_find_brute_force; |
355
|
|
|
|
|
|
|
} |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
sub find_2d_convex_hull { |
358
|
0
|
|
|
0
|
1
|
|
shift; |
359
|
|
|
|
|
|
|
|
360
|
0
|
0
|
|
|
|
|
return unless @_; |
361
|
0
|
|
|
|
|
|
my $dim = @{$_[0]}; |
|
0
|
|
|
|
|
|
|
362
|
0
|
0
|
|
|
|
|
$dim == 2 or croak "find_2d_convex_hull called with vectors of dimension $dim"; |
363
|
|
|
|
|
|
|
|
364
|
0
|
|
|
|
|
|
goto &_find_2d_convex_hull; |
365
|
|
|
|
|
|
|
} |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
1; |
368
|
|
|
|
|
|
|
__END__ |