| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Math::Vector::Real::kdTree; |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
our $VERSION = '0.15'; |
|
4
|
|
|
|
|
|
|
|
|
5
|
3
|
|
|
3
|
|
14457
|
use 5.010; |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
85
|
|
|
6
|
3
|
|
|
3
|
|
9
|
use strict; |
|
|
3
|
|
|
|
|
3
|
|
|
|
3
|
|
|
|
|
64
|
|
|
7
|
3
|
|
|
3
|
|
8
|
use warnings; |
|
|
3
|
|
|
|
|
5
|
|
|
|
3
|
|
|
|
|
68
|
|
|
8
|
3
|
|
|
3
|
|
11
|
use Carp; |
|
|
3
|
|
|
|
|
3
|
|
|
|
3
|
|
|
|
|
184
|
|
|
9
|
|
|
|
|
|
|
|
|
10
|
3
|
|
|
3
|
|
484
|
use Math::Vector::Real; |
|
|
3
|
|
|
|
|
9543
|
|
|
|
3
|
|
|
|
|
121
|
|
|
11
|
3
|
|
|
3
|
|
418
|
use Sort::Key::Top qw(nkeypartref nhead ntail nkeyhead); |
|
|
3
|
|
|
|
|
1636
|
|
|
|
3
|
|
|
|
|
243
|
|
|
12
|
3
|
|
|
3
|
|
1576
|
use Hash::Util::FieldHash qw(idhash); |
|
|
3
|
|
|
|
|
2244
|
|
|
|
3
|
|
|
|
|
183
|
|
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
our $max_per_pole = 12; |
|
15
|
|
|
|
|
|
|
our $recommended_per_pole = 6; |
|
16
|
|
|
|
|
|
|
|
|
17
|
3
|
|
|
3
|
|
13
|
use constant _n => 0; # elements on subtree |
|
|
3
|
|
|
|
|
3
|
|
|
|
3
|
|
|
|
|
155
|
|
|
18
|
3
|
|
|
3
|
|
12
|
use constant _c0 => 1; # corner 0 |
|
|
3
|
|
|
|
|
4
|
|
|
|
3
|
|
|
|
|
141
|
|
|
19
|
3
|
|
|
3
|
|
11
|
use constant _c1 => 2; # corner 1 |
|
|
3
|
|
|
|
|
4
|
|
|
|
3
|
|
|
|
|
109
|
|
|
20
|
3
|
|
|
3
|
|
11
|
use constant _sum => 3; # centroid * n |
|
|
3
|
|
|
|
|
2
|
|
|
|
3
|
|
|
|
|
89
|
|
|
21
|
3
|
|
|
3
|
|
9
|
use constant _s0 => 4; # subtree 0 |
|
|
3
|
|
|
|
|
2
|
|
|
|
3
|
|
|
|
|
83
|
|
|
22
|
3
|
|
|
3
|
|
10
|
use constant _s1 => 5; # subtree 1 |
|
|
3
|
|
|
|
|
4
|
|
|
|
3
|
|
|
|
|
95
|
|
|
23
|
3
|
|
|
3
|
|
17
|
use constant _axis => 6; # cut axis |
|
|
3
|
|
|
|
|
3
|
|
|
|
3
|
|
|
|
|
82
|
|
|
24
|
3
|
|
|
3
|
|
9
|
use constant _cut => 7; # cut point (mediam) |
|
|
3
|
|
|
|
|
3
|
|
|
|
3
|
|
|
|
|
82
|
|
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
# on leaf nodes: |
|
27
|
3
|
|
|
3
|
|
8
|
use constant _ixs => 4; |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
117
|
|
|
28
|
3
|
|
|
3
|
|
9
|
use constant _leaf_size => _ixs + 1; |
|
|
3
|
|
|
|
|
2
|
|
|
|
3
|
|
|
|
|
18461
|
|
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
sub new { |
|
31
|
683
|
|
|
683
|
1
|
200000338
|
my $class = shift; |
|
32
|
683
|
|
|
|
|
2860
|
my @v = map V(@$_), @_; |
|
33
|
683
|
100
|
|
|
|
88487
|
my $self = { vs => \@v, |
|
34
|
|
|
|
|
|
|
tree => (@v ? _build(\@v, [0..$#v]) : undef) }; |
|
35
|
683
|
|
|
|
|
24150
|
bless $self, $class; |
|
36
|
|
|
|
|
|
|
} |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
sub clone { |
|
39
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
40
|
0
|
|
|
|
|
0
|
require Storable; |
|
41
|
0
|
|
|
|
|
0
|
my $clone = { vs => [@{$self->{vs}}], |
|
|
0
|
|
|
|
|
0
|
|
|
42
|
|
|
|
|
|
|
tree => Storable::dclone($self->{tree}) }; |
|
43
|
0
|
0
|
|
|
|
0
|
$clone->{hidden} = { %{$self->{hidden}} } if $self->{hidden}; |
|
|
0
|
|
|
|
|
0
|
|
|
44
|
0
|
|
|
|
|
0
|
bless $clone, ref $self; |
|
45
|
|
|
|
|
|
|
} |
|
46
|
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
sub _build { |
|
48
|
38771
|
|
|
38771
|
|
31171
|
my ($v, $ixs) = @_; |
|
49
|
38771
|
100
|
|
|
|
49499
|
if (@$ixs > $recommended_per_pole) { |
|
50
|
18845
|
|
|
|
|
51321
|
my ($b, $t) = Math::Vector::Real->box(@$v[@$ixs]); |
|
51
|
18845
|
|
|
|
|
3621459
|
my $axis = ($t - $b)->max_component_index; |
|
52
|
18845
|
|
|
|
|
427721
|
my $bstart = @$ixs >> 1; |
|
53
|
18845
|
|
|
383835
|
|
79852
|
my ($p0, $p1) = nkeypartref { $v->[$_][$axis] } $bstart => @$ixs; |
|
|
474209
|
|
|
|
|
528820
|
|
|
54
|
18845
|
|
|
|
|
39702
|
my $s0 = _build($v, $p0); |
|
55
|
18845
|
|
|
|
|
486096
|
my $s1 = _build($v, $p1); |
|
56
|
18845
|
|
|
|
|
469477
|
my ($c0, $c1) = Math::Vector::Real->box(@{$s0}[_c0, _c1], @{$s1}[_c0, _c1]); |
|
|
18845
|
|
|
|
|
17579
|
|
|
|
18845
|
|
|
|
|
30140
|
|
|
57
|
18845
|
|
|
|
|
604866
|
my $cut = 0.5 * ($s0->[_c1][$axis] + $s1->[_c0][$axis]); |
|
58
|
|
|
|
|
|
|
# warn "b: $b, t: $t, axis: $axis, p0: $p0, p1: $p1, s0: $s0, s1: $s1, c0: $c0, c1: $c1, cut: $cut\n"; |
|
59
|
|
|
|
|
|
|
# [n sum s0 s1 axis cut] |
|
60
|
18845
|
|
|
|
|
33441
|
[scalar(@$ixs), $c0, $c1, $s0->[_sum] + $s1->[_sum], $s0, $s1, $axis, $cut]; |
|
61
|
|
|
|
|
|
|
} |
|
62
|
|
|
|
|
|
|
else { |
|
63
|
|
|
|
|
|
|
# [n, sum, ixs] |
|
64
|
19926
|
|
|
|
|
14720
|
my @vs = @{$v}[@$ixs]; |
|
|
19926
|
|
|
|
|
28720
|
|
|
65
|
19926
|
|
|
|
|
33512
|
my ($c0, $c1) = Math::Vector::Real->box(@vs); |
|
66
|
19926
|
|
|
|
|
695034
|
[scalar(@$ixs), $c0, $c1, Math::Vector::Real->sum(@vs), $ixs]; |
|
67
|
|
|
|
|
|
|
} |
|
68
|
|
|
|
|
|
|
} |
|
69
|
|
|
|
|
|
|
|
|
70
|
0
|
|
|
0
|
1
|
0
|
sub size { scalar @{shift->{vs}} } |
|
|
0
|
|
|
|
|
0
|
|
|
71
|
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
sub at { |
|
73
|
38976
|
|
|
38976
|
1
|
1219862
|
my ($self, $ix) = @_; |
|
74
|
38976
|
|
|
|
|
48393
|
Math::Vector::Real::clone($self->{vs}[$ix]); |
|
75
|
|
|
|
|
|
|
} |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
sub insert { |
|
78
|
6536
|
|
|
6536
|
1
|
2428378
|
my $self = shift; |
|
79
|
6536
|
50
|
|
|
|
12418
|
@_ or return; |
|
80
|
6536
|
|
|
|
|
6240
|
my $vs = $self->{vs}; |
|
81
|
6536
|
|
|
|
|
6352
|
my $ix = @$vs; |
|
82
|
6536
|
100
|
|
|
|
9975
|
if (my $tree = $self->{tree}) { |
|
83
|
6495
|
|
|
|
|
8285
|
for (@_) { |
|
84
|
6495
|
|
|
|
|
16357
|
my $v = V(@$_); |
|
85
|
6495
|
|
|
|
|
26083
|
push @$vs, $v; |
|
86
|
6495
|
|
|
|
|
9798
|
_insert($vs, $self->{tree}, $#$vs) |
|
87
|
|
|
|
|
|
|
} |
|
88
|
|
|
|
|
|
|
} |
|
89
|
|
|
|
|
|
|
else { |
|
90
|
41
|
|
|
|
|
252
|
@$vs = map V(@$_), @_; |
|
91
|
41
|
|
|
|
|
340
|
$self->{tree} = _build($vs, [0..$#$vs]); |
|
92
|
|
|
|
|
|
|
} |
|
93
|
6536
|
|
|
|
|
11869
|
return $ix; |
|
94
|
|
|
|
|
|
|
} |
|
95
|
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
# _insert does not return anything but modifies its $t argument in |
|
97
|
|
|
|
|
|
|
# place. This is really ugly but done to improve performance. |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
sub _insert { |
|
100
|
35009
|
|
|
35009
|
|
30119
|
my ($vs, $t, $ix) = @_; |
|
101
|
35009
|
|
|
|
|
26808
|
my $v = $vs->[$ix]; |
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
# update aggregated values |
|
104
|
35009
|
|
|
|
|
28488
|
my $n = $t->[_n]++; |
|
105
|
35009
|
|
|
|
|
22902
|
@{$t}[_c0, _c1] = Math::Vector::Real->box($v, @{$t}[_c0, _c1]); |
|
|
35009
|
|
|
|
|
912595
|
|
|
|
35009
|
|
|
|
|
66508
|
|
|
106
|
35009
|
|
|
|
|
84425
|
$t->[_sum] += $v; |
|
107
|
|
|
|
|
|
|
|
|
108
|
35009
|
100
|
|
|
|
404138
|
if (defined (my $axis = $t->[_axis])) { |
|
109
|
28562
|
|
|
|
|
22858
|
my $cut = $t->[_cut]; |
|
110
|
28562
|
|
|
|
|
22677
|
my $c = $v->[$axis]; |
|
111
|
|
|
|
|
|
|
|
|
112
|
28562
|
|
|
|
|
25126
|
my $n0 = $t->[_s0][_n]; |
|
113
|
28562
|
|
|
|
|
21902
|
my $n1 = $t->[_s1][_n]; |
|
114
|
|
|
|
|
|
|
|
|
115
|
28562
|
100
|
|
|
|
32232
|
if ($c <= $cut) { |
|
116
|
14735
|
100
|
|
|
|
22228
|
if (2 * $n1 + $max_per_pole >= $n0) { |
|
117
|
14710
|
|
|
|
|
18249
|
_insert($vs, $t->[_s0], $ix); |
|
118
|
14710
|
|
|
|
|
19870
|
return; |
|
119
|
|
|
|
|
|
|
} |
|
120
|
|
|
|
|
|
|
} |
|
121
|
|
|
|
|
|
|
else { |
|
122
|
13827
|
100
|
|
|
|
21977
|
if (2 * $n0 + $max_per_pole >= $n1) { |
|
123
|
13804
|
|
|
|
|
18230
|
_insert($vs, $t->[_s1], $ix); |
|
124
|
13804
|
|
|
|
|
18364
|
return; |
|
125
|
|
|
|
|
|
|
} |
|
126
|
|
|
|
|
|
|
} |
|
127
|
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
# tree needs rebalancing |
|
129
|
48
|
|
|
|
|
65
|
my @store; |
|
130
|
48
|
|
|
|
|
123
|
$#store = $n; # preallocate space |
|
131
|
48
|
|
|
|
|
72
|
@store = ($ix); |
|
132
|
48
|
|
|
|
|
144
|
_push_all($t, \@store); |
|
133
|
48
|
|
|
|
|
117
|
$_[1] = _build($vs, \@store); |
|
134
|
|
|
|
|
|
|
} |
|
135
|
|
|
|
|
|
|
else { |
|
136
|
6447
|
|
|
|
|
6758
|
my $ixs = $t->[_ixs]; |
|
137
|
6447
|
|
|
|
|
8888
|
push @$ixs, $ix; |
|
138
|
6447
|
100
|
|
|
|
12285
|
if ($n > $max_per_pole) { |
|
139
|
350
|
|
|
|
|
840
|
$_[1] = _build($vs, $ixs); |
|
140
|
|
|
|
|
|
|
} |
|
141
|
|
|
|
|
|
|
} |
|
142
|
|
|
|
|
|
|
} |
|
143
|
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
sub move { |
|
145
|
0
|
|
|
0
|
1
|
0
|
my ($self, $ix, $v) = @_; |
|
146
|
0
|
|
|
|
|
0
|
my $vs = $self->{vs}; |
|
147
|
0
|
0
|
0
|
|
|
0
|
($ix >= 0 and $ix < @$vs) or croak "index out of range"; |
|
148
|
0
|
|
|
|
|
0
|
_delete($vs, $self->{tree}, $ix); |
|
149
|
0
|
|
|
|
|
0
|
$vs->[$ix] = Math::Vector::Real::clone($v); |
|
150
|
0
|
|
|
|
|
0
|
_insert($vs, $self->{tree}, $ix); |
|
151
|
|
|
|
|
|
|
} |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
sub _delete { |
|
154
|
0
|
|
|
0
|
|
0
|
my ($vs, $t, $ix) = @_; |
|
155
|
0
|
0
|
|
|
|
0
|
if (defined (my $axis = $t->[_axis])) { |
|
156
|
0
|
|
|
|
|
0
|
my $v = $vs->[$ix]; |
|
157
|
0
|
|
|
|
|
0
|
my $c = $v->[$axis]; |
|
158
|
0
|
|
|
|
|
0
|
my ($s0, $s1, $cut) = @{$t}[_s0, _s1, _cut]; |
|
|
0
|
|
|
|
|
0
|
|
|
159
|
0
|
0
|
0
|
|
|
0
|
if ($c <= $cut and _delete($vs, $s0, $ix)) { |
|
|
|
0
|
0
|
|
|
|
|
|
160
|
0
|
0
|
|
|
|
0
|
if ($s0->[_n]) { |
|
161
|
0
|
|
|
|
|
0
|
$t->[_n]--; |
|
162
|
0
|
|
|
|
|
0
|
$t->[_sum] -= $v; |
|
163
|
|
|
|
|
|
|
} |
|
164
|
|
|
|
|
|
|
else { |
|
165
|
|
|
|
|
|
|
# when one subnode becomes empty, the other gets promoted up: |
|
166
|
0
|
|
|
|
|
0
|
@$t = @$s1; |
|
167
|
|
|
|
|
|
|
} |
|
168
|
0
|
|
|
|
|
0
|
return 1; |
|
169
|
|
|
|
|
|
|
} |
|
170
|
|
|
|
|
|
|
elsif ($c >= $cut and _delete($vs, $s1, $ix)) { |
|
171
|
0
|
0
|
|
|
|
0
|
if ($s1->[_n]) { |
|
172
|
0
|
|
|
|
|
0
|
$t->[_n]--; |
|
173
|
0
|
|
|
|
|
0
|
$t->[_sum] -= $v; |
|
174
|
|
|
|
|
|
|
} |
|
175
|
|
|
|
|
|
|
else { |
|
176
|
0
|
|
|
|
|
0
|
@$t = @$s0; |
|
177
|
|
|
|
|
|
|
} |
|
178
|
0
|
|
|
|
|
0
|
return 1; |
|
179
|
|
|
|
|
|
|
} |
|
180
|
|
|
|
|
|
|
} |
|
181
|
|
|
|
|
|
|
else { |
|
182
|
0
|
|
|
|
|
0
|
my $ixs = $t->[_ixs]; |
|
183
|
0
|
|
|
|
|
0
|
for (0..$#$ixs) { |
|
184
|
0
|
0
|
|
|
|
0
|
if ($ixs->[$_] == $ix) { |
|
185
|
0
|
|
|
|
|
0
|
splice(@$ixs, $_, 1); |
|
186
|
0
|
|
|
|
|
0
|
$t->[_n]--; |
|
187
|
0
|
|
|
|
|
0
|
$t->[_sum] -= $vs->[$ix]; |
|
188
|
0
|
|
|
|
|
0
|
return 1; |
|
189
|
|
|
|
|
|
|
} |
|
190
|
|
|
|
|
|
|
} |
|
191
|
|
|
|
|
|
|
} |
|
192
|
0
|
|
|
|
|
0
|
return 0; |
|
193
|
|
|
|
|
|
|
} |
|
194
|
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
sub hide { |
|
196
|
0
|
|
|
0
|
0
|
0
|
my ($self, $ix) = @_; |
|
197
|
0
|
|
|
|
|
0
|
my $vs = $self->{vs}; |
|
198
|
0
|
0
|
0
|
|
|
0
|
($ix >= 0 and $ix < @$vs) or croak "index out of range"; |
|
199
|
0
|
|
|
|
|
0
|
_delete($vs, $self->{tree}, $ix); |
|
200
|
0
|
|
0
|
|
|
0
|
($self->{hidden} //= {})->{$ix} = 1; |
|
201
|
|
|
|
|
|
|
} |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
sub _push_all { |
|
204
|
48
|
|
|
48
|
|
82
|
my ($t, $store) = @_; |
|
205
|
48
|
|
|
|
|
52
|
my @q; |
|
206
|
48
|
|
|
|
|
123
|
while ($t) { |
|
207
|
880
|
100
|
|
|
|
828
|
if (defined $t->[_axis]) { |
|
208
|
416
|
|
|
|
|
306
|
push @q, $t->[_s1]; |
|
209
|
416
|
|
|
|
|
495
|
$t = $t->[_s0]; |
|
210
|
|
|
|
|
|
|
} |
|
211
|
|
|
|
|
|
|
else { |
|
212
|
464
|
|
|
|
|
270
|
push @$store, @{$t->[_ixs]}; |
|
|
464
|
|
|
|
|
551
|
|
|
213
|
464
|
|
|
|
|
595
|
$t = pop @q; |
|
214
|
|
|
|
|
|
|
} |
|
215
|
|
|
|
|
|
|
} |
|
216
|
|
|
|
|
|
|
} |
|
217
|
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
sub path { |
|
219
|
0
|
|
|
0
|
0
|
0
|
my ($self, $ix) = @_; |
|
220
|
0
|
|
|
|
|
0
|
my $p = _path($self->{vs}, $self->{tree}, $ix); |
|
221
|
0
|
|
|
|
|
0
|
my $l = 1; |
|
222
|
0
|
|
|
|
|
0
|
$l = (($l << 1) | $_) for @$p; |
|
223
|
0
|
|
|
|
|
0
|
$l |
|
224
|
|
|
|
|
|
|
} |
|
225
|
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
sub _path { |
|
227
|
0
|
|
|
0
|
|
0
|
my ($vs, $t, $ix) = @_; |
|
228
|
0
|
0
|
|
|
|
0
|
if (defined (my $axis = $t->[_axis])) { |
|
229
|
0
|
|
|
|
|
0
|
my $v = $vs->[$ix]; |
|
230
|
0
|
|
|
|
|
0
|
my $c = $v->[$axis]; |
|
231
|
0
|
|
|
|
|
0
|
my $cut = $t->[_cut]; |
|
232
|
0
|
|
|
|
|
0
|
my $p; |
|
233
|
0
|
0
|
|
|
|
0
|
if ($c <= $cut) { |
|
234
|
0
|
0
|
|
|
|
0
|
if ($p = _path($vs, $t->[_s0], $ix)) { |
|
235
|
0
|
|
|
|
|
0
|
unshift @$p, 0; |
|
236
|
0
|
|
|
|
|
0
|
return $p; |
|
237
|
|
|
|
|
|
|
} |
|
238
|
|
|
|
|
|
|
} |
|
239
|
0
|
0
|
|
|
|
0
|
if ($c >= $cut) { |
|
240
|
0
|
0
|
|
|
|
0
|
if ($p = _path($vs, $t->[_s1], $ix)) { |
|
241
|
0
|
|
|
|
|
0
|
unshift @$p, 1; |
|
242
|
0
|
|
|
|
|
0
|
return $p; |
|
243
|
|
|
|
|
|
|
} |
|
244
|
|
|
|
|
|
|
} |
|
245
|
|
|
|
|
|
|
} |
|
246
|
|
|
|
|
|
|
else { |
|
247
|
0
|
0
|
|
|
|
0
|
return [] if grep $_ == $ix, @{$t->[_ixs]} |
|
|
0
|
|
|
|
|
0
|
|
|
248
|
|
|
|
|
|
|
} |
|
249
|
|
|
|
|
|
|
() |
|
250
|
0
|
|
|
|
|
0
|
} |
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
sub find { |
|
253
|
0
|
|
|
0
|
0
|
0
|
my ($self, $v) = @_; |
|
254
|
0
|
|
|
|
|
0
|
_find($self->{vs}, $self->{tree}, $v); |
|
255
|
|
|
|
|
|
|
} |
|
256
|
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
sub _find { |
|
258
|
0
|
|
|
0
|
|
0
|
my ($vs, $t, $v) = @_; |
|
259
|
0
|
|
|
|
|
0
|
while (defined (my $axis = $t->[_axis])) { |
|
260
|
0
|
|
|
|
|
0
|
my $cut = $t->[_cut]; |
|
261
|
0
|
|
|
|
|
0
|
my $c = $v->[$axis]; |
|
262
|
0
|
0
|
|
|
|
0
|
if ($c < $cut) { |
|
263
|
0
|
|
|
|
|
0
|
$t = $t->[_s0]; |
|
264
|
|
|
|
|
|
|
} |
|
265
|
|
|
|
|
|
|
else { |
|
266
|
0
|
0
|
|
|
|
0
|
if ($c == $cut) { |
|
267
|
0
|
|
|
|
|
0
|
my $ix = _find($vs, $t->[_s0], $v); |
|
268
|
0
|
0
|
|
|
|
0
|
return $ix if defined $ix; |
|
269
|
|
|
|
|
|
|
} |
|
270
|
0
|
|
|
|
|
0
|
$t = $t->[_s1]; |
|
271
|
|
|
|
|
|
|
} |
|
272
|
|
|
|
|
|
|
} |
|
273
|
|
|
|
|
|
|
|
|
274
|
0
|
|
|
|
|
0
|
for (@{$t->[_ixs]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
275
|
0
|
0
|
|
|
|
0
|
return $_ if $vs->[$_] == $v; |
|
276
|
|
|
|
|
|
|
} |
|
277
|
|
|
|
|
|
|
() |
|
278
|
0
|
|
|
|
|
0
|
} |
|
279
|
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
sub find_nearest_vector { |
|
281
|
67728
|
|
|
67728
|
1
|
78285
|
my ($self, $v, $d, @but) = @_; |
|
282
|
67728
|
50
|
|
|
|
100751
|
my $t = $self->{tree} or return; |
|
283
|
67728
|
|
|
|
|
47125
|
my $vs = $self->{vs}; |
|
284
|
67728
|
50
|
|
|
|
68571
|
my $d2 = (defined $d ? $d * $d : 'inf'); |
|
285
|
|
|
|
|
|
|
|
|
286
|
67728
|
|
|
|
|
46283
|
my $but; |
|
287
|
67728
|
100
|
|
|
|
83941
|
if (@but) { |
|
288
|
12992
|
50
|
33
|
|
|
36644
|
if (@but == 1 and ref $but[0] eq 'HASH') { |
|
289
|
0
|
|
|
|
|
0
|
$but = $but[0]; |
|
290
|
|
|
|
|
|
|
} |
|
291
|
|
|
|
|
|
|
else { |
|
292
|
12992
|
|
|
|
|
13595
|
my %but = map { $_ => 1 } @but; |
|
|
12992
|
|
|
|
|
33962
|
|
|
293
|
12992
|
|
|
|
|
17690
|
$but = \%but; |
|
294
|
|
|
|
|
|
|
} |
|
295
|
|
|
|
|
|
|
} |
|
296
|
|
|
|
|
|
|
|
|
297
|
67728
|
|
|
|
|
80975
|
my ($rix, $rd2) = _find_nearest_vector($vs, $t, $v, $d2, undef, $but); |
|
298
|
67728
|
|
50
|
|
|
96131
|
$rix // return; |
|
299
|
67728
|
50
|
|
|
|
201429
|
wantarray ? ($rix, sqrt($rd2)) : $rix; |
|
300
|
|
|
|
|
|
|
} |
|
301
|
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
*find_nearest_neighbor = \&find_nearest_vector; # for backwards compatibility |
|
303
|
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
sub find_nearest_vector_internal { |
|
305
|
12992
|
|
|
12992
|
0
|
1036523
|
my ($self, $ix, $d) = @_; |
|
306
|
12992
|
50
|
|
|
|
19225
|
$ix >= 0 or croak "index out of range"; |
|
307
|
12992
|
|
|
|
|
24746
|
$self->find_nearest_vector($self->{vs}[$ix], $d, $ix); |
|
308
|
|
|
|
|
|
|
} |
|
309
|
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
*find_nearest_neighbor_internal = \&find_nearest_vector_internal; # for backwards compatibility |
|
311
|
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
sub _find_nearest_vector { |
|
313
|
92505
|
|
|
92505
|
|
98342
|
my ($vs, $t, $v, $best_d2, $best_ix, $but) = @_; |
|
314
|
|
|
|
|
|
|
|
|
315
|
92505
|
|
|
|
|
60114
|
my @queue; |
|
316
|
|
|
|
|
|
|
my @queue_d2; |
|
317
|
|
|
|
|
|
|
|
|
318
|
92505
|
|
|
|
|
59986
|
while (1) { |
|
319
|
998013
|
100
|
|
|
|
1222062
|
if (defined (my $axis = $t->[_axis])) { |
|
320
|
|
|
|
|
|
|
# substitute the current one by the best subtree and queue |
|
321
|
|
|
|
|
|
|
# the worst for later |
|
322
|
639556
|
100
|
|
|
|
866550
|
($t, my ($q)) = @{$t}[($v->[$axis] <= $t->[_cut]) ? (_s0, _s1) : (_s1, _s0)]; |
|
|
639556
|
|
|
|
|
751782
|
|
|
323
|
639556
|
|
|
|
|
460347
|
my $q_d2 = $v->dist2_to_box(@{$q}[_c0, _c1]); |
|
|
639556
|
|
|
|
|
1063177
|
|
|
324
|
639556
|
100
|
|
|
|
24486846
|
if ($q_d2 <= $best_d2) { |
|
325
|
410338
|
|
|
|
|
244157
|
my $j; |
|
326
|
410338
|
|
|
|
|
596396
|
for ($j = $#queue_d2; $j >= 0; $j--) { |
|
327
|
1195851
|
100
|
|
|
|
1917703
|
last if $queue_d2[$j] >= $q_d2; |
|
328
|
|
|
|
|
|
|
} |
|
329
|
410338
|
|
|
|
|
372457
|
splice @queue, ++$j, 0, $q; |
|
330
|
410338
|
|
|
|
|
404146
|
splice @queue_d2, $j, 0, $q_d2; |
|
331
|
|
|
|
|
|
|
} |
|
332
|
|
|
|
|
|
|
} |
|
333
|
|
|
|
|
|
|
else { |
|
334
|
358457
|
|
|
|
|
211838
|
for (@{$t->[_ixs]}) { |
|
|
358457
|
|
|
|
|
448994
|
|
|
335
|
1656568
|
100
|
100
|
|
|
3181704
|
next if $but and $but->{$_}; |
|
336
|
1643576
|
|
|
|
|
2533900
|
my $d21 = $vs->[$_]->dist2($v); |
|
337
|
1643576
|
100
|
|
|
|
29101283
|
if ($d21 <= $best_d2) { |
|
338
|
261272
|
|
|
|
|
167259
|
$best_d2 = $d21; |
|
339
|
261272
|
|
|
|
|
241233
|
$best_ix = $_; |
|
340
|
|
|
|
|
|
|
} |
|
341
|
|
|
|
|
|
|
} |
|
342
|
|
|
|
|
|
|
|
|
343
|
358457
|
100
|
|
|
|
533732
|
if ($t = pop @queue) { |
|
344
|
309551
|
100
|
|
|
|
398393
|
if ($best_d2 >= pop @queue_d2) { |
|
345
|
265952
|
|
|
|
|
238931
|
next; |
|
346
|
|
|
|
|
|
|
} |
|
347
|
|
|
|
|
|
|
} |
|
348
|
|
|
|
|
|
|
|
|
349
|
92505
|
|
|
|
|
196013
|
return ($best_ix, $best_d2); |
|
350
|
|
|
|
|
|
|
} |
|
351
|
|
|
|
|
|
|
} |
|
352
|
|
|
|
|
|
|
} |
|
353
|
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
sub find_nearest_vector_in_box { |
|
355
|
0
|
|
|
0
|
1
|
0
|
my ($self, $v, $a, $b, $d, @but) = @_; |
|
356
|
|
|
|
|
|
|
|
|
357
|
0
|
0
|
|
|
|
0
|
my $t = $self->{tree} or return; |
|
358
|
0
|
|
|
|
|
0
|
my $vs = $self->{vs}; |
|
359
|
0
|
|
|
|
|
0
|
my ($a1, $b1) = Math::Vector::Real->box($a, $b); |
|
360
|
0
|
0
|
|
|
|
0
|
my $d2 = (defined $d ? $d * $d : $v->max_dist2_to_box($a1, $b1)); |
|
361
|
0
|
|
|
|
|
0
|
my $but; |
|
362
|
0
|
0
|
|
|
|
0
|
if (@but) { |
|
363
|
0
|
0
|
0
|
|
|
0
|
if (@but == 1 and ref $but[0] eq 'HASH') { |
|
364
|
0
|
|
|
|
|
0
|
$but = $but[0]; |
|
365
|
|
|
|
|
|
|
} |
|
366
|
|
|
|
|
|
|
else { |
|
367
|
0
|
|
|
|
|
0
|
my %but = map { $_ => 1 } @but; |
|
|
0
|
|
|
|
|
0
|
|
|
368
|
0
|
|
|
|
|
0
|
$but = \%but; |
|
369
|
|
|
|
|
|
|
} |
|
370
|
|
|
|
|
|
|
} |
|
371
|
0
|
|
|
|
|
0
|
my ($rix, $rd2) = _find_nearest_vector_in_box($vs, $t, $v, $a1, $b1, $d2, $but); |
|
372
|
0
|
|
0
|
|
|
0
|
$rix // return; |
|
373
|
0
|
0
|
|
|
|
0
|
wantarray ? ($rix, sqrt($rd2)) : $rix; |
|
374
|
|
|
|
|
|
|
} |
|
375
|
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
sub _find_nearest_vector_in_box { |
|
377
|
0
|
|
|
0
|
|
0
|
my ($vs, $t, $v, $a, $b, $best_d2, $but) = @_; |
|
378
|
0
|
|
|
|
|
0
|
my $best_ix; |
|
379
|
0
|
|
|
|
|
0
|
my @queue = $t; |
|
380
|
0
|
|
|
|
|
0
|
my @queue_d2 = 0; |
|
381
|
|
|
|
|
|
|
|
|
382
|
0
|
|
|
|
|
0
|
while (my $t = pop @queue) { |
|
383
|
0
|
0
|
|
|
|
0
|
last if $best_d2 < pop @queue_d2; |
|
384
|
0
|
0
|
|
|
|
0
|
if (defined (my $axis = $t->[_axis])) { |
|
385
|
0
|
|
|
|
|
0
|
my @sides; |
|
386
|
0
|
0
|
|
|
|
0
|
push @sides, $t->[_s0] if $a->[$axis] <= $t->[_cut]; |
|
387
|
0
|
0
|
|
|
|
0
|
push @sides, $t->[_s1] if $b->[$axis] >= $t->[_cut]; |
|
388
|
0
|
|
|
|
|
0
|
for my $s (@sides) { |
|
389
|
0
|
|
|
|
|
0
|
my $d2 = $v->dist2_to_box(@$s[_c0, _c1]); |
|
390
|
0
|
0
|
|
|
|
0
|
if ($d2 <= $best_d2) { |
|
391
|
0
|
|
|
|
|
0
|
my $j; |
|
392
|
0
|
|
|
|
|
0
|
for ($j = $#queue_d2; $j >= 0; $j--) { |
|
393
|
0
|
0
|
|
|
|
0
|
last if $queue_d2[$j] >= $d2; |
|
394
|
|
|
|
|
|
|
} |
|
395
|
0
|
|
|
|
|
0
|
splice @queue, ++$j, 0, $s; |
|
396
|
0
|
|
|
|
|
0
|
splice @queue_d2, $j, 0, $d2; |
|
397
|
|
|
|
|
|
|
} |
|
398
|
|
|
|
|
|
|
} |
|
399
|
|
|
|
|
|
|
} |
|
400
|
|
|
|
|
|
|
else { |
|
401
|
0
|
|
|
|
|
0
|
for (@{$t->[_ixs]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
402
|
0
|
0
|
0
|
|
|
0
|
next if $but and $but->{$_}; |
|
403
|
0
|
|
|
|
|
0
|
my $v1 = $vs->[$_]; |
|
404
|
0
|
|
|
|
|
0
|
my $d2 = $v1->dist2($v); |
|
405
|
0
|
0
|
0
|
|
|
0
|
if ($d2 <= $best_d2 and $v1->dist2_to_box($a, $b) == 0) { |
|
406
|
0
|
|
|
|
|
0
|
$best_d2 = $d2; |
|
407
|
0
|
|
|
|
|
0
|
$best_ix = $_; |
|
408
|
|
|
|
|
|
|
} |
|
409
|
|
|
|
|
|
|
} |
|
410
|
|
|
|
|
|
|
} |
|
411
|
|
|
|
|
|
|
} |
|
412
|
0
|
|
|
|
|
0
|
return ($best_ix, $best_d2); |
|
413
|
|
|
|
|
|
|
} |
|
414
|
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
sub find_nearest_vector_in_box_chebyshev { |
|
416
|
0
|
|
|
0
|
1
|
0
|
my ($self, $v, $a, $b, $d, @but) = @_; |
|
417
|
|
|
|
|
|
|
|
|
418
|
0
|
0
|
|
|
|
0
|
my $t = $self->{tree} or return; |
|
419
|
0
|
|
|
|
|
0
|
my $vs = $self->{vs}; |
|
420
|
0
|
|
|
|
|
0
|
my ($a1, $b1) = Math::Vector::Real->box($a, $b); |
|
421
|
0
|
0
|
|
|
|
0
|
my $d2 = (defined $d ? $d * $d : $v->max_dist2_to_box($a1, $b1)); |
|
422
|
0
|
|
|
|
|
0
|
my $but; |
|
423
|
0
|
0
|
|
|
|
0
|
if (@but) { |
|
424
|
0
|
0
|
0
|
|
|
0
|
if (@but == 1 and ref $but[0] eq 'HASH') { |
|
425
|
0
|
|
|
|
|
0
|
$but = $but[0]; |
|
426
|
|
|
|
|
|
|
} |
|
427
|
|
|
|
|
|
|
else { |
|
428
|
0
|
|
|
|
|
0
|
my %but = map { $_ => 1 } @but; |
|
|
0
|
|
|
|
|
0
|
|
|
429
|
0
|
|
|
|
|
0
|
$but = \%but; |
|
430
|
|
|
|
|
|
|
} |
|
431
|
|
|
|
|
|
|
} |
|
432
|
0
|
|
|
|
|
0
|
my ($rix, $rd2) = _find_nearest_vector_in_box($vs, $t, $v, $a1, $b1, $d2, $but); |
|
433
|
0
|
|
0
|
|
|
0
|
$rix // return; |
|
434
|
0
|
0
|
|
|
|
0
|
wantarray ? ($rix, sqrt($rd2)) : $rix; |
|
435
|
|
|
|
|
|
|
} |
|
436
|
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
sub _find_nearest_vector_in_box_chebyshev { |
|
438
|
0
|
|
|
0
|
|
0
|
my ($vs, $t, $v, $a, $b, $best_d, $but) = @_; |
|
439
|
0
|
|
|
|
|
0
|
my $best_ix; |
|
440
|
0
|
|
|
|
|
0
|
my @queue = $t; |
|
441
|
0
|
|
|
|
|
0
|
my @queue_d = 0; |
|
442
|
|
|
|
|
|
|
|
|
443
|
0
|
|
|
|
|
0
|
while (my $t = pop @queue) { |
|
444
|
0
|
0
|
|
|
|
0
|
last if $best_d < pop @queue_d; |
|
445
|
0
|
0
|
|
|
|
0
|
if (defined (my $axis = $t->[_axis])) { |
|
446
|
0
|
|
|
|
|
0
|
my @sides; |
|
447
|
0
|
0
|
|
|
|
0
|
push @sides, $t->[_s0] if $a->[$axis] <= $t->[_cut]; |
|
448
|
0
|
0
|
|
|
|
0
|
push @sides, $t->[_s1] if $b->[$axis] >= $t->[_cut]; |
|
449
|
0
|
|
|
|
|
0
|
for my $s (@sides) { |
|
450
|
0
|
|
|
|
|
0
|
my $d = $v->chebyshev_dist_to_box(@$s[_c0, _c1]); |
|
451
|
0
|
0
|
|
|
|
0
|
if ($d <= $best_d) { |
|
452
|
0
|
|
|
|
|
0
|
my $j; |
|
453
|
0
|
|
|
|
|
0
|
for ($j = $#queue_d; $j >= 0; $j--) { |
|
454
|
0
|
0
|
|
|
|
0
|
last if $queue_d[$j] >= $d; |
|
455
|
|
|
|
|
|
|
} |
|
456
|
0
|
|
|
|
|
0
|
splice @queue, ++$j, 0, $s; |
|
457
|
0
|
|
|
|
|
0
|
splice @queue_d, $j, 0, $d; |
|
458
|
|
|
|
|
|
|
} |
|
459
|
|
|
|
|
|
|
} |
|
460
|
|
|
|
|
|
|
} |
|
461
|
|
|
|
|
|
|
else { |
|
462
|
0
|
|
|
|
|
0
|
for (@{$t->[_ixs]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
463
|
0
|
0
|
0
|
|
|
0
|
next if $but and $but->{$_}; |
|
464
|
0
|
|
|
|
|
0
|
my $v1 = $vs->[$_]; |
|
465
|
0
|
|
|
|
|
0
|
my $d = $v1->chebyshev_dist($v); |
|
466
|
0
|
0
|
0
|
|
|
0
|
if ($d <= $best_d and $v1->chebyshev_dist_to_box($a, $b) == 0) { |
|
467
|
0
|
|
|
|
|
0
|
$best_d = $d; |
|
468
|
0
|
|
|
|
|
0
|
$best_ix = $_; |
|
469
|
|
|
|
|
|
|
} |
|
470
|
|
|
|
|
|
|
} |
|
471
|
|
|
|
|
|
|
} |
|
472
|
|
|
|
|
|
|
} |
|
473
|
0
|
|
|
|
|
0
|
return ($best_ix, $best_d); |
|
474
|
|
|
|
|
|
|
} |
|
475
|
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
sub find_nearest_vector_all_internal { |
|
477
|
80
|
|
|
80
|
1
|
2079689
|
my ($self, $d) = @_; |
|
478
|
80
|
|
|
|
|
195
|
my $vs = $self->{vs}; |
|
479
|
80
|
50
|
|
|
|
257
|
return unless @$vs > 1; |
|
480
|
80
|
50
|
|
|
|
226
|
my $d2 = (defined $d ? $d * $d : 'inf'); |
|
481
|
|
|
|
|
|
|
|
|
482
|
80
|
|
|
|
|
639
|
my @best = ((undef) x @$vs); |
|
483
|
80
|
|
|
|
|
2705
|
my @d2 = (($d2) x @$vs); |
|
484
|
80
|
|
|
|
|
277
|
_find_nearest_vector_all_internal($vs, $self->{tree}, \@best, \@d2); |
|
485
|
80
|
|
|
|
|
11139
|
return @best; |
|
486
|
|
|
|
|
|
|
} |
|
487
|
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
*find_nearest_neighbor_all_internal = \&find_nearest_vector_all_internal; # for backwards compatibility |
|
489
|
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
sub _find_nearest_vector_all_internal { |
|
491
|
5508
|
|
|
5508
|
|
5136
|
my ($vs, $t, $bests, $d2s) = @_; |
|
492
|
5508
|
100
|
|
|
|
7079
|
if (defined (my $axis = $t->[_axis])) { |
|
493
|
2714
|
|
|
|
|
1816
|
my @all_leafs; |
|
494
|
2714
|
|
|
|
|
2203
|
for my $side (0, 1) { |
|
495
|
5428
|
|
|
|
|
8279
|
my @leafs = _find_nearest_vector_all_internal($vs, $t->[_s0 + $side], $bests, $d2s); |
|
496
|
5428
|
|
|
|
|
6422
|
my $other = $t->[_s1 - $side]; |
|
497
|
5428
|
|
|
|
|
3837
|
my ($c0, $c1) = @{$other}[_c0, _c1]; |
|
|
5428
|
|
|
|
|
6418
|
|
|
498
|
5428
|
|
|
|
|
4544
|
for my $leaf (@leafs) { |
|
499
|
17557
|
|
|
|
|
175534
|
for my $ix (@{$leaf->[_ixs]}) { |
|
|
17557
|
|
|
|
|
20839
|
|
|
500
|
79694
|
|
|
|
|
872920
|
my $v = $vs->[$ix]; |
|
501
|
79694
|
100
|
|
|
|
108495
|
if ($v->dist2_to_box($c0, $c1) < $d2s->[$ix]) { |
|
502
|
24777
|
|
|
|
|
1046365
|
($bests->[$ix], $d2s->[$ix]) = |
|
503
|
|
|
|
|
|
|
_find_nearest_vector($vs, $other, $v, $d2s->[$ix], $bests->[$ix]); |
|
504
|
|
|
|
|
|
|
} |
|
505
|
|
|
|
|
|
|
} |
|
506
|
|
|
|
|
|
|
} |
|
507
|
5428
|
|
|
|
|
78450
|
push @all_leafs, @leafs; |
|
508
|
|
|
|
|
|
|
} |
|
509
|
2714
|
|
|
|
|
6575
|
return @all_leafs; |
|
510
|
|
|
|
|
|
|
} |
|
511
|
|
|
|
|
|
|
else { |
|
512
|
2794
|
|
|
|
|
2603
|
my $ixs = $t->[_ixs]; |
|
513
|
2794
|
|
|
|
|
3725
|
for my $i (1 .. $#$ixs) { |
|
514
|
10198
|
|
|
|
|
9041
|
my $ix_i = $ixs->[$i]; |
|
515
|
10198
|
|
|
|
|
7857
|
my $v_i = $vs->[$ix_i]; |
|
516
|
10198
|
|
|
|
|
10251
|
for my $ix_j (@{$ixs}[0 .. $i - 1]) { |
|
|
10198
|
|
|
|
|
10281
|
|
|
517
|
28540
|
|
|
|
|
39162
|
my $d2 = $v_i->dist2($vs->[$ix_j]); |
|
518
|
28540
|
100
|
|
|
|
379511
|
if ($d2 < $d2s->[$ix_i]) { |
|
519
|
15644
|
|
|
|
|
12268
|
$d2s->[$ix_i] = $d2; |
|
520
|
15644
|
|
|
|
|
14725
|
$bests->[$ix_i] = $ix_j; |
|
521
|
|
|
|
|
|
|
} |
|
522
|
28540
|
100
|
|
|
|
43874
|
if ($d2 < $d2s->[$ix_j]) { |
|
523
|
8496
|
|
|
|
|
5881
|
$d2s->[$ix_j] = $d2; |
|
524
|
8496
|
|
|
|
|
12076
|
$bests->[$ix_j] = $ix_i; |
|
525
|
|
|
|
|
|
|
} |
|
526
|
|
|
|
|
|
|
} |
|
527
|
|
|
|
|
|
|
} |
|
528
|
2794
|
|
|
|
|
4917
|
return $t; |
|
529
|
|
|
|
|
|
|
} |
|
530
|
|
|
|
|
|
|
} |
|
531
|
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
sub find_two_nearest_vectors { |
|
533
|
418
|
|
|
418
|
1
|
995776
|
my $self = shift; |
|
534
|
418
|
50
|
|
|
|
1479
|
my $t = $self->{tree} or return; |
|
535
|
418
|
|
|
|
|
596
|
my $vs = $self->{vs}; |
|
536
|
418
|
50
|
|
|
|
1116
|
if (my ($rix0, $rix1, $rd2) = _find_two_nearest_vectors($vs, $t)) { |
|
537
|
418
|
50
|
|
|
|
2404
|
return wantarray ? ($rix0, $rix1, sqrt($rd2)) : sqrt($rd2) |
|
538
|
|
|
|
|
|
|
} |
|
539
|
|
|
|
|
|
|
() |
|
540
|
0
|
|
|
|
|
0
|
} |
|
541
|
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
sub _pole_id { |
|
543
|
0
|
|
|
0
|
|
0
|
my ($id, $deep) = __pole_id(@_); |
|
544
|
0
|
|
|
|
|
0
|
"$id/$deep"; |
|
545
|
|
|
|
|
|
|
} |
|
546
|
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
sub __pole_id { |
|
548
|
0
|
|
|
0
|
|
0
|
my ($vs, $t) = @_; |
|
549
|
0
|
0
|
|
|
|
0
|
if (defined $t->[_axis]) { |
|
550
|
0
|
|
|
|
|
0
|
my ($id, $deep) = __pole_id($vs, $t->[_s0]); |
|
551
|
0
|
|
|
|
|
0
|
return ($id, $deep+1); |
|
552
|
|
|
|
|
|
|
} |
|
553
|
0
|
|
|
|
|
0
|
return ($t->[_ixs][0], 0) |
|
554
|
|
|
|
|
|
|
} |
|
555
|
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
sub _find_two_nearest_vectors { |
|
557
|
418
|
|
|
418
|
|
504
|
my ($vs, $t) = @_; |
|
558
|
|
|
|
|
|
|
|
|
559
|
418
|
|
|
|
|
876
|
my @best_ixs = (undef, undef); |
|
560
|
418
|
|
|
|
|
488
|
my $best_d2 = 'inf' + 0; |
|
561
|
|
|
|
|
|
|
|
|
562
|
418
|
|
|
|
|
436
|
my @inner; |
|
563
|
|
|
|
|
|
|
my @queue_t1; |
|
564
|
0
|
|
|
|
|
0
|
my @queue_t2; |
|
565
|
418
|
|
|
|
|
781
|
while ($t) { |
|
566
|
31038
|
100
|
|
|
|
34418
|
if (defined $t->[_axis]) { |
|
567
|
15310
|
|
|
|
|
9529
|
my ($s0, $s1) = @{$t}[_s0, _s1]; |
|
|
15310
|
|
|
|
|
16890
|
|
|
568
|
15310
|
|
|
|
|
12227
|
push @inner, $s1; |
|
569
|
15310
|
|
|
|
|
9483
|
push @queue_t1, $s0; |
|
570
|
15310
|
|
|
|
|
9671
|
push @queue_t2, $s1; |
|
571
|
15310
|
|
|
|
|
18698
|
$t = $s0; |
|
572
|
|
|
|
|
|
|
} |
|
573
|
|
|
|
|
|
|
else { |
|
574
|
15728
|
|
|
|
|
12747
|
my $ixs = $t->[_ixs]; |
|
575
|
15728
|
|
|
|
|
16600
|
for my $i (1 .. $#$ixs) { |
|
576
|
52235
|
|
|
|
|
41868
|
my $ix1 = $ixs->[$i]; |
|
577
|
52235
|
|
|
|
|
38618
|
my $v1 = $vs->[$ix1]; |
|
578
|
52235
|
|
|
|
|
41978
|
for my $j (0 .. $i - 1) { |
|
579
|
121855
|
|
|
|
|
81089
|
my $ix2 = $ixs->[$j]; |
|
580
|
121855
|
|
|
|
|
145644
|
my $d2 = Math::Vector::Real::dist2($v1, $vs->[$ix2]); |
|
581
|
121855
|
100
|
|
|
|
1556033
|
if ($d2 < $best_d2) { |
|
582
|
1956
|
|
|
|
|
1305
|
$best_d2 = $d2; |
|
583
|
1956
|
|
|
|
|
3245
|
@best_ixs = ($ix1, $ix2); |
|
584
|
|
|
|
|
|
|
} |
|
585
|
|
|
|
|
|
|
} |
|
586
|
|
|
|
|
|
|
} |
|
587
|
15728
|
|
|
|
|
23830
|
$t = pop @inner; |
|
588
|
|
|
|
|
|
|
} |
|
589
|
|
|
|
|
|
|
} |
|
590
|
|
|
|
|
|
|
|
|
591
|
418
|
|
|
|
|
2490
|
my @queue_d2 = (0) x @queue_t1; |
|
592
|
418
|
|
|
|
|
1065
|
while (my $t1 = pop @queue_t1) { |
|
593
|
119352
|
|
|
|
|
93649
|
my $t2 = pop @queue_t2; |
|
594
|
119352
|
|
|
|
|
97935
|
my $d2 = pop @queue_d2; |
|
595
|
119352
|
100
|
|
|
|
143969
|
if ($d2 < $best_d2) { |
|
596
|
115655
|
100
|
|
|
|
147726
|
unless (defined $t1->[_axis]) { |
|
597
|
36385
|
100
|
|
|
|
41846
|
unless (defined $t2->[_axis]) { |
|
598
|
34452
|
|
|
|
|
20374
|
for my $ix1 (@{$t1->[_ixs]}) { |
|
|
34452
|
|
|
|
|
39434
|
|
|
599
|
160816
|
|
|
|
|
131834
|
my $v1 = $vs->[$ix1]; |
|
600
|
160816
|
|
|
|
|
90344
|
for my $ix2 (@{$t2->[_ixs]}) { |
|
|
160816
|
|
|
|
|
155477
|
|
|
601
|
738847
|
|
|
|
|
877021
|
my $d2 = Math::Vector::Real::dist2($v1, $vs->[$ix2]); |
|
602
|
738847
|
100
|
|
|
|
11894110
|
if ($d2 < $best_d2) { |
|
603
|
101
|
|
|
|
|
108
|
$best_d2 = $d2; |
|
604
|
101
|
|
|
|
|
233
|
@best_ixs = ($ix1, $ix2); |
|
605
|
|
|
|
|
|
|
} |
|
606
|
|
|
|
|
|
|
} |
|
607
|
|
|
|
|
|
|
} |
|
608
|
34452
|
|
|
|
|
69833
|
next; |
|
609
|
|
|
|
|
|
|
} |
|
610
|
1933
|
|
|
|
|
2182
|
($t1, $t2) = ($t2, $t1); |
|
611
|
|
|
|
|
|
|
} |
|
612
|
81203
|
|
|
|
|
50670
|
for my $s (@{$t1}[_s0, _s1]) { |
|
|
81203
|
|
|
|
|
84820
|
|
|
613
|
162406
|
|
|
|
|
99725
|
my $d2 = Math::Vector::Real->dist2_between_boxes(@{$s}[_c0, _c1], @{$t2}[_c0, _c1]); |
|
|
162406
|
|
|
|
|
140033
|
|
|
|
162406
|
|
|
|
|
254116
|
|
|
614
|
162406
|
100
|
|
|
|
10416569
|
if ($d2) { |
|
615
|
153202
|
100
|
|
|
|
239143
|
if ($d2 < $best_d2) { |
|
616
|
94838
|
|
|
|
|
76145
|
unshift @queue_t1, $t2; |
|
617
|
94838
|
|
|
|
|
66284
|
unshift @queue_t2, $s; |
|
618
|
94838
|
|
|
|
|
163077
|
unshift @queue_d2, $d2; |
|
619
|
|
|
|
|
|
|
} |
|
620
|
|
|
|
|
|
|
} |
|
621
|
|
|
|
|
|
|
else { |
|
622
|
9204
|
|
|
|
|
7649
|
push @queue_t1, $t2; |
|
623
|
9204
|
|
|
|
|
6028
|
push @queue_t2, $s; |
|
624
|
9204
|
|
|
|
|
15507
|
push @queue_d2, 0; |
|
625
|
|
|
|
|
|
|
} |
|
626
|
|
|
|
|
|
|
} |
|
627
|
|
|
|
|
|
|
} |
|
628
|
|
|
|
|
|
|
} |
|
629
|
418
|
|
|
|
|
1740
|
(@best_ixs, $best_d2) |
|
630
|
|
|
|
|
|
|
} |
|
631
|
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
sub find_in_ball { |
|
633
|
6496
|
|
|
6496
|
1
|
38463302
|
my ($self, $z, $d, $but) = @_; |
|
634
|
6496
|
50
|
33
|
|
|
36444
|
if (defined $but and ref $but ne 'HASH') { |
|
635
|
6496
|
|
|
|
|
21868
|
$but = { $but => 1 }; |
|
636
|
|
|
|
|
|
|
} |
|
637
|
6496
|
|
|
|
|
21844
|
_find_in_ball($self->{vs}, $self->{tree}, $z, $d * $d, $but); |
|
638
|
|
|
|
|
|
|
} |
|
639
|
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
sub _find_in_ball { |
|
641
|
6496
|
|
|
6496
|
|
8795
|
my ($vs, $t, $z, $d2, $but) = @_; |
|
642
|
6496
|
|
|
|
|
5544
|
my (@queue, @r); |
|
643
|
6496
|
|
|
|
|
6159
|
my $r = 0; |
|
644
|
|
|
|
|
|
|
|
|
645
|
6496
|
|
|
|
|
4764
|
while (1) { |
|
646
|
286240
|
100
|
|
|
|
4584866
|
if (defined (my $axis = $t->[_axis])) { |
|
647
|
161868
|
|
|
|
|
124456
|
my $c = $z->[$axis]; |
|
648
|
161868
|
|
|
|
|
123276
|
my $cut = $t->[_cut]; |
|
649
|
161868
|
100
|
|
|
|
170305
|
($t, my ($q)) = @{$t}[$c <= $cut ? (_s0, _s1) : (_s1, _s0)]; |
|
|
161868
|
|
|
|
|
207905
|
|
|
650
|
161868
|
100
|
|
|
|
115487
|
push @queue, $q if $z->dist2_to_box(@{$q}[_c0, _c1]) <= $d2; |
|
|
161868
|
|
|
|
|
263671
|
|
|
651
|
|
|
|
|
|
|
} |
|
652
|
|
|
|
|
|
|
else { |
|
653
|
124372
|
|
|
|
|
99869
|
my $ixs = $t->[_ixs]; |
|
654
|
124372
|
50
|
|
|
|
115474
|
if (wantarray) { |
|
655
|
124372
|
|
|
|
|
120517
|
push @r, grep { $vs->[$_]->dist2($z) <= $d2 } @$ixs; |
|
|
735912
|
|
|
|
|
7832418
|
|
|
656
|
|
|
|
|
|
|
} |
|
657
|
|
|
|
|
|
|
else { |
|
658
|
0
|
0
|
|
|
|
0
|
$r += ( $but |
|
659
|
0
|
|
|
|
|
0
|
? grep { !$but->{$_} and $vs->[$_]->dist2($z) <= $d2 } @$ixs |
|
660
|
0
|
0
|
|
|
|
0
|
: grep { $vs->[$_]->dist2($z) <= $d2 } @$ixs ); |
|
661
|
|
|
|
|
|
|
} |
|
662
|
|
|
|
|
|
|
|
|
663
|
124372
|
100
|
|
|
|
1632959
|
$t = pop @queue or last; |
|
664
|
|
|
|
|
|
|
} |
|
665
|
|
|
|
|
|
|
} |
|
666
|
|
|
|
|
|
|
|
|
667
|
6496
|
50
|
|
|
|
12386
|
if (wantarray) { |
|
668
|
6496
|
50
|
|
|
|
12237
|
if ($but) { |
|
669
|
6496
|
|
|
|
|
245630
|
return grep !$but->{$_}, @r; |
|
670
|
|
|
|
|
|
|
} |
|
671
|
0
|
|
|
|
|
0
|
return @r; |
|
672
|
|
|
|
|
|
|
} |
|
673
|
0
|
|
|
|
|
0
|
return $r; |
|
674
|
|
|
|
|
|
|
} |
|
675
|
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
sub find_in_box { |
|
677
|
0
|
|
|
0
|
1
|
0
|
my ($self, $a, $b, $but) = @_; |
|
678
|
0
|
|
|
|
|
0
|
my ($a1, $b1) = Math::Vector::Real->box($a, $b); |
|
679
|
0
|
0
|
0
|
|
|
0
|
if (defined $but and ref $but ne 'HASH') { |
|
680
|
0
|
|
|
|
|
0
|
$but = { $but => 1 }; |
|
681
|
|
|
|
|
|
|
} |
|
682
|
0
|
|
|
|
|
0
|
_find_in_box($self->{vs}, $self->{tree}, $a1, $b1, $but); |
|
683
|
|
|
|
|
|
|
} |
|
684
|
|
|
|
|
|
|
|
|
685
|
|
|
|
|
|
|
sub _find_in_box { |
|
686
|
0
|
|
|
0
|
|
0
|
my ($vs, $t, $a, $b, $but) = @_; |
|
687
|
0
|
|
|
|
|
0
|
my (@r, $r); |
|
688
|
0
|
|
|
|
|
0
|
my @queue; |
|
689
|
0
|
|
|
|
|
0
|
while (1) { |
|
690
|
0
|
0
|
|
|
|
0
|
if (defined (my $axis = $t->[_axis])) { |
|
691
|
0
|
|
|
|
|
0
|
my $cut = $t->[_cut]; |
|
692
|
0
|
0
|
|
|
|
0
|
push @queue, $t->[_s0] if $cut >= $a->[$axis]; |
|
693
|
0
|
0
|
|
|
|
0
|
push @queue, $t->[_s1] if $cut <= $b->[$axis]; |
|
694
|
|
|
|
|
|
|
} |
|
695
|
|
|
|
|
|
|
else { |
|
696
|
0
|
|
|
|
|
0
|
my $ixs = $t->[_ixs]; |
|
697
|
0
|
0
|
|
|
|
0
|
if (wantarray) { |
|
698
|
0
|
|
|
|
|
0
|
push @r, grep { $vs->[$_]->dist2_to_box($a, $b) <= 0 } @$ixs; |
|
|
0
|
|
|
|
|
0
|
|
|
699
|
|
|
|
|
|
|
} |
|
700
|
|
|
|
|
|
|
else { |
|
701
|
0
|
0
|
|
|
|
0
|
$r += ( $but |
|
702
|
0
|
|
|
|
|
0
|
? grep { !$but->{$_} and $vs->[$_]->dist2_to_box($a, $b) <= 0 } @$ixs |
|
703
|
0
|
0
|
|
|
|
0
|
: grep { $vs->[$_]->dist2_to_box($a, $b) <= 0 } @$ixs ); |
|
704
|
|
|
|
|
|
|
} |
|
705
|
|
|
|
|
|
|
} |
|
706
|
0
|
0
|
|
|
|
0
|
$t = pop @queue or last; |
|
707
|
|
|
|
|
|
|
} |
|
708
|
|
|
|
|
|
|
|
|
709
|
0
|
0
|
|
|
|
0
|
if (wantarray) { |
|
710
|
0
|
0
|
|
|
|
0
|
if ($but) { |
|
711
|
0
|
|
|
|
|
0
|
return grep !$but->{$_}, @r; |
|
712
|
|
|
|
|
|
|
} |
|
713
|
0
|
|
|
|
|
0
|
return @r; |
|
714
|
|
|
|
|
|
|
} |
|
715
|
0
|
|
|
|
|
0
|
return $r; |
|
716
|
|
|
|
|
|
|
} |
|
717
|
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
sub find_farthest_vector { |
|
719
|
6496
|
|
|
6496
|
1
|
7884
|
my ($self, $v, $d, @but) = @_; |
|
720
|
6496
|
50
|
|
|
|
10216
|
my $t = $self->{tree} or return; |
|
721
|
6496
|
|
|
|
|
4894
|
my $vs = $self->{vs}; |
|
722
|
6496
|
50
|
|
|
|
8450
|
my $d2 = ($d ? $d * $d : -1); |
|
723
|
6496
|
|
|
|
|
3888
|
my $but; |
|
724
|
6496
|
50
|
|
|
|
8686
|
if (@but) { |
|
725
|
6496
|
50
|
33
|
|
|
18386
|
if (@but == 1 and ref $but[0] eq 'HASH') { |
|
726
|
0
|
|
|
|
|
0
|
$but = $but[0]; |
|
727
|
|
|
|
|
|
|
} |
|
728
|
|
|
|
|
|
|
else { |
|
729
|
6496
|
|
|
|
|
6419
|
my %but = map { $_ => 1 } @but; |
|
|
6496
|
|
|
|
|
16177
|
|
|
730
|
6496
|
|
|
|
|
8580
|
$but = \%but; |
|
731
|
|
|
|
|
|
|
} |
|
732
|
|
|
|
|
|
|
} |
|
733
|
|
|
|
|
|
|
|
|
734
|
6496
|
|
|
|
|
9519
|
my ($rix, $rd2) = _find_farthest_vector($vs, $t, $v, $d2, undef, $but); |
|
735
|
6496
|
|
50
|
|
|
8829
|
$rix // return; |
|
736
|
6496
|
50
|
|
|
|
31547
|
wantarray ? ($rix, sqrt($d2)) : $rix; |
|
737
|
|
|
|
|
|
|
} |
|
738
|
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
sub find_farthest_vector_internal { |
|
740
|
6496
|
|
|
6496
|
1
|
16491266
|
my ($self, $ix, $d) = @_; |
|
741
|
6496
|
50
|
|
|
|
10079
|
$ix >= 0 or croak "index out of range"; |
|
742
|
6496
|
|
|
|
|
12267
|
$self->find_farthest_vector($self->{vs}[$ix], $d, $ix); |
|
743
|
|
|
|
|
|
|
} |
|
744
|
|
|
|
|
|
|
|
|
745
|
|
|
|
|
|
|
sub _find_farthest_vector { |
|
746
|
6496
|
|
|
6496
|
|
6334
|
my ($vs, $t, $v, $best_d2, $best_ix, $but) = @_; |
|
747
|
|
|
|
|
|
|
|
|
748
|
6496
|
|
|
|
|
4130
|
my @queue; |
|
749
|
|
|
|
|
|
|
my @queue_d2; |
|
750
|
|
|
|
|
|
|
|
|
751
|
6496
|
|
|
|
|
4416
|
while (1) { |
|
752
|
196107
|
100
|
|
|
|
252061
|
if (defined (my $axis = $t->[_axis])) { |
|
753
|
|
|
|
|
|
|
# substitute the current one by the best subtree and queue |
|
754
|
|
|
|
|
|
|
# the worst for later |
|
755
|
126964
|
100
|
|
|
|
170200
|
($t, my ($q)) = @{$t}[($v->[$axis] >= $t->[_cut]) ? (_s0, _s1) : (_s1, _s0)]; |
|
|
126964
|
|
|
|
|
147863
|
|
|
756
|
126964
|
|
|
|
|
89250
|
my $q_d2 = $v->max_dist2_to_box(@{$q}[_c0, _c1]); |
|
|
126964
|
|
|
|
|
204832
|
|
|
757
|
126964
|
100
|
|
|
|
5269507
|
if ($q_d2 >= $best_d2) { |
|
758
|
88329
|
|
|
|
|
51777
|
my $j; |
|
759
|
88329
|
|
|
|
|
125181
|
for ($j = $#queue_d2; $j >= 0; $j--) { |
|
760
|
495875
|
100
|
|
|
|
730100
|
last if $queue_d2[$j] <= $q_d2; |
|
761
|
|
|
|
|
|
|
} |
|
762
|
88329
|
|
|
|
|
76908
|
splice @queue, ++$j, 0, $q; |
|
763
|
88329
|
|
|
|
|
84978
|
splice @queue_d2, $j, 0, $q_d2; |
|
764
|
|
|
|
|
|
|
} |
|
765
|
|
|
|
|
|
|
} |
|
766
|
|
|
|
|
|
|
else { |
|
767
|
69143
|
|
|
|
|
42515
|
for (@{$t->[_ixs]}) { |
|
|
69143
|
|
|
|
|
93177
|
|
|
768
|
444090
|
100
|
66
|
|
|
1137538
|
next if $but and $but->{$_}; |
|
769
|
443910
|
|
|
|
|
638891
|
my $d21 = $vs->[$_]->dist2($v); |
|
770
|
443910
|
100
|
|
|
|
7803159
|
if ($d21 >= $best_d2) { |
|
771
|
53073
|
|
|
|
|
32483
|
$best_d2 = $d21; |
|
772
|
53073
|
|
|
|
|
48445
|
$best_ix = $_; |
|
773
|
|
|
|
|
|
|
} |
|
774
|
|
|
|
|
|
|
} |
|
775
|
|
|
|
|
|
|
|
|
776
|
69143
|
100
|
|
|
|
102827
|
if ($t = pop @queue) { |
|
777
|
68173
|
100
|
|
|
|
81477
|
if ($best_d2 <= pop @queue_d2) { |
|
778
|
62647
|
|
|
|
|
51086
|
next; |
|
779
|
|
|
|
|
|
|
} |
|
780
|
|
|
|
|
|
|
} |
|
781
|
6496
|
|
|
|
|
14110
|
return ($best_ix, $best_d2); |
|
782
|
|
|
|
|
|
|
} |
|
783
|
|
|
|
|
|
|
} |
|
784
|
|
|
|
|
|
|
} |
|
785
|
|
|
|
|
|
|
|
|
786
|
|
|
|
|
|
|
sub find_random_vector { |
|
787
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
|
788
|
0
|
0
|
|
|
|
0
|
my $t = $self->{tree} or return; |
|
789
|
0
|
|
|
|
|
0
|
my $vs = $self->{vs}; |
|
790
|
0
|
|
|
|
|
0
|
my $hidden = $self->{hidden}; |
|
791
|
0
|
0
|
0
|
|
|
0
|
if (not $hidden or @$vs > 20 * keys(%$hidden)) { |
|
792
|
|
|
|
|
|
|
# pick directly when the hidden elements are less than 5% of the total |
|
793
|
0
|
|
|
|
|
0
|
while (1) { |
|
794
|
0
|
|
|
|
|
0
|
my $ix = int rand @$vs; |
|
795
|
0
|
0
|
0
|
|
|
0
|
return $ix unless $hidden and $hidden->{$ix}; |
|
796
|
|
|
|
|
|
|
} |
|
797
|
|
|
|
|
|
|
} |
|
798
|
0
|
|
|
|
|
0
|
_find_random_vector($vs, $t); |
|
799
|
|
|
|
|
|
|
} |
|
800
|
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
sub _find_random_vector { |
|
802
|
0
|
|
|
0
|
|
0
|
my ($vs, $t) = @_; |
|
803
|
0
|
|
|
|
|
0
|
while (defined $t->[_axis]) { |
|
804
|
0
|
0
|
|
|
|
0
|
$t = $t->[rand($t->[_n]) < $t->[_s0][_n] ? _s0 : _s1]; |
|
805
|
|
|
|
|
|
|
} |
|
806
|
0
|
|
|
|
|
0
|
$t->[_ixs][rand $t->[_n]] |
|
807
|
|
|
|
|
|
|
} |
|
808
|
|
|
|
|
|
|
|
|
809
|
|
|
|
|
|
|
sub k_means_seed { |
|
810
|
224
|
|
|
224
|
1
|
18266404
|
my ($self, $n_req) = @_; |
|
811
|
224
|
50
|
|
|
|
765
|
$n_req = int($n_req) or return; |
|
812
|
224
|
50
|
|
|
|
768
|
my $t = $self->{tree} or return; |
|
813
|
224
|
|
|
|
|
351
|
my $vs = $self->{vs}; |
|
814
|
224
|
|
|
|
|
557
|
_k_means_seed($vs, $t, $n_req); |
|
815
|
|
|
|
|
|
|
} |
|
816
|
|
|
|
|
|
|
|
|
817
|
|
|
|
|
|
|
*k_means_start = \&k_means_seed; |
|
818
|
|
|
|
|
|
|
|
|
819
|
|
|
|
|
|
|
sub _k_means_seed { |
|
820
|
7616
|
|
|
7616
|
|
20033
|
my ($vs, $t, $n_req) = @_; |
|
821
|
7616
|
100
|
|
|
|
7360
|
if ($n_req <= 1) { |
|
822
|
2353
|
100
|
|
|
|
2705
|
return if $n_req < 1; |
|
823
|
|
|
|
|
|
|
# print STDERR "returning centroid\n"; |
|
824
|
2337
|
|
|
|
|
4236
|
return $t->[_sum] / $t->[_n]; |
|
825
|
|
|
|
|
|
|
} |
|
826
|
|
|
|
|
|
|
else { |
|
827
|
5263
|
|
|
|
|
3813
|
my $n = $t->[_n]; |
|
828
|
5263
|
100
|
|
|
|
5990
|
if (defined $t->[_axis]) { |
|
829
|
3696
|
|
|
|
|
2474
|
my ($s0, $s1) = @{$t}[_s0, _s1]; |
|
|
3696
|
|
|
|
|
4657
|
|
|
830
|
3696
|
|
|
|
|
4067
|
my $n0 = $s0->[_n]; |
|
831
|
3696
|
|
|
|
|
3266
|
my $n1 = $s1->[_n]; |
|
832
|
3696
|
|
|
|
|
3845
|
my $n0_req = int(0.5 + $n_req * ($n0 / $n)); |
|
833
|
3696
|
50
|
|
|
|
4254
|
$n0_req = $n0 if $n0_req > $n0; |
|
834
|
3696
|
|
|
|
|
3995
|
return (_k_means_seed($vs, $s0, $n0_req), |
|
835
|
|
|
|
|
|
|
_k_means_seed($vs, $s1, $n_req - $n0_req)); |
|
836
|
|
|
|
|
|
|
} |
|
837
|
|
|
|
|
|
|
else { |
|
838
|
1567
|
|
|
|
|
1423
|
my $ixs = $t->[_ixs]; |
|
839
|
1567
|
|
|
|
|
958
|
my @out; |
|
840
|
1567
|
|
|
|
|
1872
|
for (0..$#$ixs) { |
|
841
|
10383
|
100
|
|
|
|
18602
|
push @out, $vs->[$ixs->[$_]] |
|
842
|
|
|
|
|
|
|
if rand($n - $_) < ($n_req - @out); |
|
843
|
|
|
|
|
|
|
} |
|
844
|
|
|
|
|
|
|
# print STDERR "asked for $n_req elements, returning ".scalar(@out)."\n"; |
|
845
|
|
|
|
|
|
|
|
|
846
|
1567
|
|
|
|
|
4101
|
return @out; |
|
847
|
|
|
|
|
|
|
} |
|
848
|
|
|
|
|
|
|
} |
|
849
|
|
|
|
|
|
|
} |
|
850
|
|
|
|
|
|
|
|
|
851
|
|
|
|
|
|
|
our $k_means_seed_pp_test; |
|
852
|
|
|
|
|
|
|
|
|
853
|
|
|
|
|
|
|
sub _k_means_seed_pp_test { |
|
854
|
0
|
|
|
0
|
|
0
|
my ($self, $err, $kms, $players, $weights) = @_; |
|
855
|
0
|
|
|
|
|
0
|
my @w; |
|
856
|
0
|
|
|
|
|
0
|
my $last = 0; |
|
857
|
0
|
|
|
|
|
0
|
for my $i (0..$#$players) { |
|
858
|
0
|
|
|
|
|
0
|
my $p = $players->[$i]; |
|
859
|
0
|
|
|
|
|
0
|
my $w = $weights->[$i] - $last; |
|
860
|
0
|
|
|
|
|
0
|
$last = $weights->[$i]; |
|
861
|
|
|
|
|
|
|
|
|
862
|
0
|
|
|
|
|
0
|
my @store; |
|
863
|
0
|
0
|
|
|
|
0
|
if (ref $p) { |
|
864
|
0
|
|
|
|
|
0
|
_push_all($p, \@store); |
|
865
|
|
|
|
|
|
|
} |
|
866
|
|
|
|
|
|
|
else { |
|
867
|
0
|
|
|
|
|
0
|
@store = $p |
|
868
|
|
|
|
|
|
|
} |
|
869
|
0
|
0
|
|
|
|
0
|
if (@store) { |
|
870
|
0
|
|
|
|
|
0
|
$w /= @store; |
|
871
|
0
|
|
|
|
|
0
|
$w[$_] = $w for @store; |
|
872
|
|
|
|
|
|
|
} |
|
873
|
|
|
|
|
|
|
} |
|
874
|
0
|
|
|
|
|
0
|
my $vs = $self->{vs}; |
|
875
|
0
|
|
0
|
|
|
0
|
$w[$_] //= 0 for 0..$#$vs; |
|
876
|
|
|
|
|
|
|
|
|
877
|
0
|
|
|
|
|
0
|
$k_means_seed_pp_test->($self, $err, [map $self->{vs}[$_], @$kms], \@w); |
|
878
|
|
|
|
|
|
|
} |
|
879
|
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
sub k_means_seed_pp { |
|
881
|
0
|
|
|
0
|
0
|
0
|
my ($self, $n_req, $err) = @_; |
|
882
|
0
|
0
|
|
|
|
0
|
$n_req = int($n_req) or return; |
|
883
|
0
|
|
0
|
|
|
0
|
$err ||= 0.5; |
|
884
|
0
|
0
|
|
|
|
0
|
my $t = $self->{tree} or return; |
|
885
|
0
|
|
|
|
|
0
|
my $vs = $self->{vs}; |
|
886
|
0
|
|
|
|
|
0
|
my $km = $self->find_random_vector; |
|
887
|
|
|
|
|
|
|
|
|
888
|
0
|
|
|
|
|
0
|
my (@km, @d2); |
|
889
|
0
|
|
|
|
|
0
|
idhash my %extra; # [$min_d2, $max_d2] |
|
890
|
|
|
|
|
|
|
|
|
891
|
|
|
|
|
|
|
# my (@player, @weight, @queue); |
|
892
|
|
|
|
|
|
|
# $#player = @$vs; # preallocate memory |
|
893
|
|
|
|
|
|
|
|
|
894
|
0
|
|
|
|
|
0
|
my (@weight, @queue); |
|
895
|
0
|
|
|
|
|
0
|
$#weight = @$vs; # preallocate memory |
|
896
|
|
|
|
|
|
|
|
|
897
|
0
|
|
|
|
|
0
|
while (1) { |
|
898
|
0
|
|
|
|
|
0
|
push @km, $km; |
|
899
|
0
|
0
|
|
|
|
0
|
last unless @km < $n_req; |
|
900
|
|
|
|
|
|
|
|
|
901
|
|
|
|
|
|
|
# update distances |
|
902
|
0
|
|
|
|
|
0
|
@queue = $t; |
|
903
|
0
|
|
|
|
|
0
|
while (my $p = pop @queue) { |
|
904
|
0
|
|
|
|
|
0
|
my $kmv = $vs->[$km]; |
|
905
|
0
|
|
|
|
|
0
|
my ($c0, $c1) = @{$p}[_c0, _c1]; |
|
|
0
|
|
|
|
|
0
|
|
|
906
|
0
|
|
0
|
|
|
0
|
my $extra = $extra{$p} //= ['inf', 'inf']; |
|
907
|
0
|
|
|
|
|
0
|
my ($min_d2, $max_d2) = @$extra; |
|
908
|
0
|
|
|
|
|
0
|
my $min_d2_to_box = $kmv->dist2_to_box($c0, $c1); |
|
909
|
0
|
0
|
|
|
|
0
|
if ($max_d2 > $min_d2_to_box) { |
|
910
|
0
|
0
|
|
|
|
0
|
if (defined $p->[_axis]) { |
|
911
|
0
|
|
|
|
|
0
|
push @queue, @{$p}[_s0, _s1]; |
|
|
0
|
|
|
|
|
0
|
|
|
912
|
|
|
|
|
|
|
} |
|
913
|
|
|
|
|
|
|
else { |
|
914
|
0
|
|
|
|
|
0
|
for (@{$p->[_ixs]}) { |
|
|
0
|
|
|
|
|
0
|
|
|
915
|
0
|
|
|
|
|
0
|
my $d2 = $kmv->dist2($vs->[$_]); |
|
916
|
0
|
0
|
0
|
|
|
0
|
if ($d2 < ($d2[$_] //= $d2)) { |
|
917
|
0
|
|
|
|
|
0
|
$d2[$_] = $d2; |
|
918
|
|
|
|
|
|
|
} |
|
919
|
|
|
|
|
|
|
} |
|
920
|
|
|
|
|
|
|
} |
|
921
|
|
|
|
|
|
|
|
|
922
|
0
|
0
|
|
|
|
0
|
if ($min_d2_to_box < $min_d2) { |
|
923
|
0
|
|
|
|
|
0
|
$extra->[0] = $min_d2_to_box; |
|
924
|
|
|
|
|
|
|
} |
|
925
|
|
|
|
|
|
|
|
|
926
|
0
|
|
|
|
|
0
|
my $max_d2_to_box = $kmv->max_dist2_to_box($c0, $c1); |
|
927
|
0
|
0
|
|
|
|
0
|
if ($max_d2_to_box < $max_d2) { |
|
928
|
0
|
|
|
|
|
0
|
$extra->[1] = $max_d2_to_box; |
|
929
|
|
|
|
|
|
|
} |
|
930
|
|
|
|
|
|
|
} |
|
931
|
|
|
|
|
|
|
} |
|
932
|
|
|
|
|
|
|
|
|
933
|
|
|
|
|
|
|
# find players and weight them |
|
934
|
0
|
|
|
|
|
0
|
my $weight = 0; |
|
935
|
|
|
|
|
|
|
# @player = (); |
|
936
|
0
|
|
|
|
|
0
|
@weight = (); |
|
937
|
|
|
|
|
|
|
|
|
938
|
|
|
|
|
|
|
# @queue = $t; |
|
939
|
|
|
|
|
|
|
# while (my $p = pop @queue) { |
|
940
|
|
|
|
|
|
|
# my $extra = $extra{$p} or die "internal error: extra information missing for $p"; |
|
941
|
|
|
|
|
|
|
# my ($min_d2, $max_d2) = @$extra; |
|
942
|
|
|
|
|
|
|
|
|
943
|
|
|
|
|
|
|
# if ($max_d2 * $err < $min_d2) { |
|
944
|
|
|
|
|
|
|
# $weight += $p->[_n] * ($min_d2 + $max_d2) * 0.5; |
|
945
|
|
|
|
|
|
|
# push @weight, $weight; |
|
946
|
|
|
|
|
|
|
# push @player, $p; |
|
947
|
|
|
|
|
|
|
# } |
|
948
|
|
|
|
|
|
|
# else { |
|
949
|
|
|
|
|
|
|
# if (defined $p->[_axis]) { |
|
950
|
|
|
|
|
|
|
# push @queue, @{$p}[_s0, _s1]; |
|
951
|
|
|
|
|
|
|
# } |
|
952
|
|
|
|
|
|
|
# else { |
|
953
|
|
|
|
|
|
|
# for (@{$p->[_ixs]}) { |
|
954
|
|
|
|
|
|
|
# if (my $d2 = $d2[$_]) { |
|
955
|
|
|
|
|
|
|
# $weight += $d2; |
|
956
|
|
|
|
|
|
|
# push @weight, $weight; |
|
957
|
|
|
|
|
|
|
# push @player, $_; |
|
958
|
|
|
|
|
|
|
# } |
|
959
|
|
|
|
|
|
|
# } |
|
960
|
|
|
|
|
|
|
# } |
|
961
|
|
|
|
|
|
|
# } |
|
962
|
|
|
|
|
|
|
# } |
|
963
|
|
|
|
|
|
|
|
|
964
|
0
|
|
|
|
|
0
|
for my $ix (0..@$vs) { |
|
965
|
0
|
|
0
|
|
|
0
|
$weight += $d2[$ix] // 0; |
|
966
|
0
|
|
|
|
|
0
|
$weight[$ix] += $weight; |
|
967
|
|
|
|
|
|
|
} |
|
968
|
|
|
|
|
|
|
|
|
969
|
|
|
|
|
|
|
# in order to check the algorithm we have to tap it here |
|
970
|
|
|
|
|
|
|
# $k_means_seed_pp_test and @km > 1 and |
|
971
|
|
|
|
|
|
|
# $self->_k_means_seed_pp_test($err, \@km, \@player, \@weight); |
|
972
|
|
|
|
|
|
|
|
|
973
|
|
|
|
|
|
|
# to many k-means requested? |
|
974
|
|
|
|
|
|
|
# @player or last; |
|
975
|
|
|
|
|
|
|
|
|
976
|
|
|
|
|
|
|
# select a position on the weight queue: |
|
977
|
0
|
|
|
|
|
0
|
my $dice = rand($weight); |
|
978
|
|
|
|
|
|
|
|
|
979
|
|
|
|
|
|
|
# and use binary search to look for it: |
|
980
|
0
|
|
|
|
|
0
|
my $i = 0; |
|
981
|
0
|
|
|
|
|
0
|
my $j = @weight; |
|
982
|
0
|
|
|
|
|
0
|
while ($i < $j) { |
|
983
|
0
|
|
|
|
|
0
|
my $pivot = (($i + $j) >> 1); |
|
984
|
0
|
0
|
|
|
|
0
|
if ($weight[$pivot] < $dice) { |
|
985
|
0
|
|
|
|
|
0
|
$i = $pivot + 1; |
|
986
|
|
|
|
|
|
|
} |
|
987
|
|
|
|
|
|
|
else { |
|
988
|
0
|
|
|
|
|
0
|
$j = $pivot; |
|
989
|
|
|
|
|
|
|
} |
|
990
|
|
|
|
|
|
|
} |
|
991
|
|
|
|
|
|
|
#my $player = $player[$i]; |
|
992
|
|
|
|
|
|
|
#$km = (ref $player ? _find_random_vector($vs, $player) : $player); |
|
993
|
0
|
|
|
|
|
0
|
$km = $i; |
|
994
|
|
|
|
|
|
|
} |
|
995
|
0
|
|
|
|
|
0
|
return @{$vs}[@km]; |
|
|
0
|
|
|
|
|
0
|
|
|
996
|
|
|
|
|
|
|
} |
|
997
|
|
|
|
|
|
|
|
|
998
|
|
|
|
|
|
|
sub k_means_loop { |
|
999
|
224
|
|
|
224
|
1
|
90587
|
my ($self, @k) = @_; |
|
1000
|
224
|
50
|
|
|
|
583
|
@k or next; |
|
1001
|
224
|
50
|
|
|
|
659
|
my $t = $self->{tree} or next; |
|
1002
|
224
|
|
|
|
|
422
|
my $vs = $self->{vs}; |
|
1003
|
224
|
|
|
|
|
329
|
while (1) { |
|
1004
|
1158
|
|
|
|
|
1257
|
my $diffs; |
|
1005
|
1158
|
|
|
|
|
4256
|
my @n = ((0) x @k); |
|
1006
|
1158
|
|
|
|
|
2646
|
my @sum = ((undef) x @k); |
|
1007
|
|
|
|
|
|
|
|
|
1008
|
1158
|
|
|
|
|
7947
|
_k_means_step($vs, $t, \@k, [0..$#k], \@n, \@sum); |
|
1009
|
|
|
|
|
|
|
|
|
1010
|
1158
|
|
|
|
|
36118
|
for (0..$#k) { |
|
1011
|
31048
|
100
|
|
|
|
40904
|
if (my $n = $n[$_]) { |
|
1012
|
29478
|
|
|
|
|
40086
|
my $k = $sum[$_] / $n; |
|
1013
|
29478
|
100
|
|
|
|
188863
|
$diffs++ if $k != $k[$_]; |
|
1014
|
29478
|
|
|
|
|
321120
|
$k[$_] = $k; |
|
1015
|
|
|
|
|
|
|
} |
|
1016
|
|
|
|
|
|
|
} |
|
1017
|
1158
|
100
|
|
|
|
15584
|
unless ($diffs) { |
|
1018
|
224
|
50
|
|
|
|
5047
|
return (wantarray ? @k : $k[0]); |
|
1019
|
|
|
|
|
|
|
} |
|
1020
|
|
|
|
|
|
|
} |
|
1021
|
|
|
|
|
|
|
} |
|
1022
|
|
|
|
|
|
|
|
|
1023
|
|
|
|
|
|
|
sub k_means_step { |
|
1024
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
1025
|
0
|
0
|
|
|
|
0
|
@_ or return; |
|
1026
|
0
|
0
|
|
|
|
0
|
my $t = $self->{tree} or return; |
|
1027
|
0
|
|
|
|
|
0
|
my $vs = $self->{vs}; |
|
1028
|
|
|
|
|
|
|
|
|
1029
|
0
|
|
|
|
|
0
|
my @n = ((0) x @_); |
|
1030
|
0
|
|
|
|
|
0
|
my @sum = ((undef) x @_); |
|
1031
|
|
|
|
|
|
|
|
|
1032
|
0
|
|
|
|
|
0
|
_k_means_step($vs, $t, \@_, [0..$#_], \@n, \@sum); |
|
1033
|
|
|
|
|
|
|
|
|
1034
|
0
|
|
|
|
|
0
|
for (0..$#n) { |
|
1035
|
0
|
0
|
|
|
|
0
|
if (my $n = $n[$_]) { |
|
1036
|
0
|
|
|
|
|
0
|
$sum[$_] /= $n; |
|
1037
|
|
|
|
|
|
|
} |
|
1038
|
|
|
|
|
|
|
else { |
|
1039
|
|
|
|
|
|
|
# otherwise let the original value stay |
|
1040
|
0
|
|
|
|
|
0
|
$sum[$_] = $_[$_]; |
|
1041
|
|
|
|
|
|
|
} |
|
1042
|
|
|
|
|
|
|
} |
|
1043
|
0
|
0
|
|
|
|
0
|
wantarray ? @sum : $sum[0]; |
|
1044
|
|
|
|
|
|
|
} |
|
1045
|
|
|
|
|
|
|
|
|
1046
|
|
|
|
|
|
|
sub _k_means_step { |
|
1047
|
109606
|
|
|
109606
|
|
113746
|
my ($vs, $t, $centers, $cixs, $ns, $sums) = @_; |
|
1048
|
109606
|
|
|
|
|
86689
|
my ($n, $sum, $c0, $c1) = @{$t}[_n, _sum, _c0, _c1]; |
|
|
109606
|
|
|
|
|
185080
|
|
|
1049
|
109606
|
50
|
|
|
|
167991
|
if ($n) { |
|
1050
|
109606
|
|
|
|
|
206291
|
my $centroid = $sum/$n; |
|
1051
|
109606
|
|
|
0
|
|
1256562
|
my $best = nkeyhead { $centroid->dist2($centers->[$_]) } @$cixs; |
|
|
2231698
|
|
|
|
|
32882164
|
|
|
1052
|
109606
|
|
|
|
|
1726030
|
my $max_d2 = Math::Vector::Real::max_dist2_to_box($centers->[$best], $c0, $c1); |
|
1053
|
109606
|
|
|
|
|
4285022
|
my @down = grep { Math::Vector::Real::dist2_to_box($centers->[$_], $c0, $c1) <= $max_d2 } @$cixs; |
|
|
2231738
|
|
|
|
|
72745958
|
|
|
1054
|
109606
|
100
|
|
|
|
3580041
|
if (@down <= 1) { |
|
1055
|
10438
|
|
|
|
|
10393
|
$ns->[$best] += $n; |
|
1056
|
|
|
|
|
|
|
# FIXME: M::V::R objects should support this undef + vector logic natively! |
|
1057
|
10438
|
100
|
|
|
|
12983
|
if (defined $sums->[$best]) { |
|
1058
|
8870
|
|
|
|
|
17477
|
$sums->[$best] += $sum; |
|
1059
|
|
|
|
|
|
|
} |
|
1060
|
|
|
|
|
|
|
else { |
|
1061
|
1568
|
|
|
|
|
3071
|
$sums->[$best] = V(@$sum); |
|
1062
|
|
|
|
|
|
|
} |
|
1063
|
|
|
|
|
|
|
} |
|
1064
|
|
|
|
|
|
|
else { |
|
1065
|
99168
|
100
|
|
|
|
169757
|
if (defined (my $axis = $t->[_axis])) { |
|
1066
|
54224
|
|
|
|
|
44936
|
my ($s0, $s1) = @{$t}[_s0, _s1]; |
|
|
54224
|
|
|
|
|
75514
|
|
|
1067
|
54224
|
|
|
|
|
107297
|
_k_means_step($vs, $t->[_s0], $centers, \@down, $ns, $sums); |
|
1068
|
54224
|
|
|
|
|
908782
|
_k_means_step($vs, $t->[_s1], $centers, \@down, $ns, $sums); |
|
1069
|
|
|
|
|
|
|
} |
|
1070
|
|
|
|
|
|
|
else { |
|
1071
|
44944
|
|
|
|
|
34468
|
for my $ix (@{$t->[_ixs]}) { |
|
|
44944
|
|
|
|
|
78293
|
|
|
1072
|
270081
|
|
|
|
|
2515976
|
my $v = $vs->[$ix]; |
|
1073
|
270081
|
|
|
0
|
|
950333
|
my $best = nkeyhead { $v->dist2($centers->[$_]) } @down; |
|
|
4610293
|
|
|
|
|
74405934
|
|
|
1074
|
270081
|
|
|
|
|
4101200
|
$ns->[$best]++; |
|
1075
|
270081
|
100
|
|
|
|
346538
|
if (defined $sums->[$best]) { |
|
1076
|
242171
|
|
|
|
|
397608
|
$sums->[$best] += $v; |
|
1077
|
|
|
|
|
|
|
} |
|
1078
|
|
|
|
|
|
|
else { |
|
1079
|
27910
|
|
|
|
|
60566
|
$sums->[$best] = V(@$v); |
|
1080
|
|
|
|
|
|
|
} |
|
1081
|
|
|
|
|
|
|
} |
|
1082
|
|
|
|
|
|
|
} |
|
1083
|
|
|
|
|
|
|
} |
|
1084
|
|
|
|
|
|
|
} |
|
1085
|
|
|
|
|
|
|
} |
|
1086
|
|
|
|
|
|
|
|
|
1087
|
|
|
|
|
|
|
sub k_means_assign { |
|
1088
|
224
|
|
|
224
|
1
|
126448
|
my $self = shift; |
|
1089
|
224
|
50
|
|
|
|
571
|
@_ or return; |
|
1090
|
224
|
50
|
|
|
|
657
|
my $t = $self->{tree} or return; |
|
1091
|
224
|
|
|
|
|
279
|
my $vs = $self->{vs}; |
|
1092
|
|
|
|
|
|
|
|
|
1093
|
224
|
|
|
|
|
3759
|
my @out = ((undef) x @$vs); |
|
1094
|
224
|
|
|
|
|
1712
|
_k_means_assign($vs, $t, \@_, [0..$#_], \@out); |
|
1095
|
224
|
|
|
|
|
9627
|
@out; |
|
1096
|
|
|
|
|
|
|
} |
|
1097
|
|
|
|
|
|
|
|
|
1098
|
|
|
|
|
|
|
sub _k_means_assign { |
|
1099
|
14110
|
|
|
14110
|
|
15913
|
my ($vs, $t, $centers, $cixs, $outs) = @_; |
|
1100
|
14110
|
|
|
|
|
12609
|
my ($n, $sum, $c0, $c1) = @{$t}[_n, _sum, _c0, _c1]; |
|
|
14110
|
|
|
|
|
24651
|
|
|
1101
|
14110
|
50
|
|
|
|
21728
|
if ($n) { |
|
1102
|
14110
|
|
|
|
|
32808
|
my $centroid = $sum/$n; |
|
1103
|
14110
|
|
|
0
|
|
168471
|
my $best = nkeyhead { $centroid->dist2($centers->[$_]) } @$cixs; |
|
|
426562
|
|
|
|
|
6151385
|
|
|
1104
|
14110
|
|
|
|
|
215047
|
my $max_d2 = Math::Vector::Real::max_dist2_to_box($centers->[$best], $c0, $c1); |
|
1105
|
14110
|
|
|
|
|
498707
|
my @down = grep { Math::Vector::Real::dist2_to_box($centers->[$_], $c0, $c1) <= $max_d2 } @$cixs; |
|
|
426602
|
|
|
|
|
13427211
|
|
|
1106
|
14110
|
100
|
|
|
|
431254
|
if (@down <= 1) { |
|
1107
|
1418
|
|
|
|
|
1928
|
_k_means_assign_1($t, $best, $outs); |
|
1108
|
|
|
|
|
|
|
} |
|
1109
|
|
|
|
|
|
|
else { |
|
1110
|
12692
|
100
|
|
|
|
21731
|
if (defined (my $axis = $t->[_axis])) { |
|
1111
|
6943
|
|
|
|
|
6460
|
my ($s0, $s1) = @{$t}[_s0, _s1]; |
|
|
6943
|
|
|
|
|
10395
|
|
|
1112
|
6943
|
|
|
|
|
14997
|
_k_means_assign($vs, $t->[_s0], $centers, \@down, $outs); |
|
1113
|
6943
|
|
|
|
|
24752
|
_k_means_assign($vs, $t->[_s1], $centers, \@down, $outs); |
|
1114
|
|
|
|
|
|
|
} |
|
1115
|
|
|
|
|
|
|
else { |
|
1116
|
5749
|
|
|
|
|
5356
|
for my $ix (@{$t->[_ixs]}) { |
|
|
5749
|
|
|
|
|
10479
|
|
|
1117
|
34081
|
|
|
|
|
41277
|
my $v = $vs->[$ix]; |
|
1118
|
34081
|
|
|
0
|
|
125325
|
my $best = nkeyhead { $v->dist2($centers->[$_]) } @down; |
|
|
831649
|
|
|
|
|
13423979
|
|
|
1119
|
34081
|
|
|
|
|
530220
|
$outs->[$ix] = $best; |
|
1120
|
|
|
|
|
|
|
} |
|
1121
|
|
|
|
|
|
|
} |
|
1122
|
|
|
|
|
|
|
} |
|
1123
|
|
|
|
|
|
|
} |
|
1124
|
|
|
|
|
|
|
} |
|
1125
|
|
|
|
|
|
|
|
|
1126
|
|
|
|
|
|
|
sub _k_means_assign_1 { |
|
1127
|
6452
|
|
|
6452
|
|
5331
|
my ($t, $best, $outs) = @_; |
|
1128
|
6452
|
100
|
|
|
|
7809
|
if (defined (my $axis = $t->[_axis])) { |
|
1129
|
2517
|
|
|
|
|
2858
|
_k_means_assign_1($t->[_s0], $best, $outs); |
|
1130
|
2517
|
|
|
|
|
3236
|
_k_means_assign_1($t->[_s1], $best, $outs); |
|
1131
|
|
|
|
|
|
|
} |
|
1132
|
|
|
|
|
|
|
else { |
|
1133
|
3935
|
|
|
|
|
2753
|
$outs->[$_] = $best for @{$t->[_ixs]}; |
|
|
3935
|
|
|
|
|
19155
|
|
|
1134
|
|
|
|
|
|
|
} |
|
1135
|
|
|
|
|
|
|
} |
|
1136
|
|
|
|
|
|
|
|
|
1137
|
|
|
|
|
|
|
sub ordered_by_proximity { |
|
1138
|
6536
|
|
|
6536
|
1
|
15923
|
my $self = shift; |
|
1139
|
6536
|
|
|
|
|
4932
|
my @r; |
|
1140
|
6536
|
|
|
|
|
4293
|
$#r = $#{$self->{vs}}; $#r = -1; # preallocate |
|
|
6536
|
|
|
|
|
13397
|
|
|
|
6536
|
|
|
|
|
8040
|
|
|
1141
|
6536
|
|
|
|
|
10102
|
_ordered_by_proximity($self->{tree}, \@r); |
|
1142
|
6536
|
|
|
|
|
181551
|
return @r; |
|
1143
|
|
|
|
|
|
|
} |
|
1144
|
|
|
|
|
|
|
|
|
1145
|
|
|
|
|
|
|
sub _ordered_by_proximity { |
|
1146
|
425866
|
|
|
425866
|
|
247750
|
my $t = shift; |
|
1147
|
425866
|
|
|
|
|
232085
|
my $r = shift; |
|
1148
|
425866
|
100
|
|
|
|
383227
|
if (defined $t->[_axis]) { |
|
1149
|
209665
|
|
|
|
|
174044
|
_ordered_by_proximity($t->[_s0], $r); |
|
1150
|
209665
|
|
|
|
|
199715
|
_ordered_by_proximity($t->[_s1], $r); |
|
1151
|
|
|
|
|
|
|
} |
|
1152
|
|
|
|
|
|
|
else { |
|
1153
|
216201
|
|
|
|
|
126418
|
push @$r, @{$t->[_ixs]} |
|
|
216201
|
|
|
|
|
329898
|
|
|
1154
|
|
|
|
|
|
|
} |
|
1155
|
|
|
|
|
|
|
} |
|
1156
|
|
|
|
|
|
|
|
|
1157
|
|
|
|
|
|
|
sub _dump_to_string { |
|
1158
|
0
|
|
|
0
|
|
|
my ($vs, $t, $indent, $opts) = @_; |
|
1159
|
0
|
|
|
|
|
|
my ($n, $c0, $c1, $sum) = @{$t}[_n, _c0, _c1, _sum]; |
|
|
0
|
|
|
|
|
|
|
|
1160
|
0
|
0
|
|
|
|
|
my $id = ($opts->{pole_id} ? _pole_id($vs, $t)." " : ''); |
|
1161
|
0
|
0
|
|
|
|
|
if (defined (my $axis = $t->[_axis])) { |
|
1162
|
0
|
|
|
|
|
|
my ($s0, $s1, $cut) = @{$t}[_s0, _s1, _cut]; |
|
|
0
|
|
|
|
|
|
|
|
1163
|
0
|
|
|
|
|
|
return ( "${indent}${id}n: $n, c0: $c0, c1: $c1, sum: $sum, axis: $axis, cut: $cut\n" . |
|
1164
|
|
|
|
|
|
|
_dump_to_string($vs, $s0, "$indent$opts->{tab}", $opts) . |
|
1165
|
|
|
|
|
|
|
_dump_to_string($vs, $s1, "$indent$opts->{tab}", $opts) ); |
|
1166
|
|
|
|
|
|
|
} |
|
1167
|
|
|
|
|
|
|
else { |
|
1168
|
0
|
|
0
|
|
|
|
my $remark = $opts->{remark} // []; |
|
1169
|
0
|
|
|
|
|
|
my $o = ( "${indent}${id}n: $n, c0: $c0, c1: $c1, sum: $sum\n" . |
|
1170
|
|
|
|
|
|
|
"${indent}$opts->{tab}ixs: [" ); |
|
1171
|
0
|
|
|
|
|
|
my @str; |
|
1172
|
0
|
|
|
|
|
|
for my $ix (@{$t->[_ixs]}) { |
|
|
0
|
|
|
|
|
|
|
|
1173
|
0
|
|
0
|
|
|
|
my $colored_ix = (@$remark and grep($ix == $_, @$remark) |
|
1174
|
|
|
|
|
|
|
? Term::ANSIColor::colored($ix, 'red') |
|
1175
|
|
|
|
|
|
|
: $ix); |
|
1176
|
0
|
0
|
0
|
|
|
|
if ($opts->{dump_vectors} // 1) { |
|
1177
|
0
|
|
|
|
|
|
push @str, "$colored_ix $vs->[$ix]"; |
|
1178
|
|
|
|
|
|
|
} |
|
1179
|
|
|
|
|
|
|
else { |
|
1180
|
0
|
|
|
|
|
|
push @str, $colored_ix; |
|
1181
|
|
|
|
|
|
|
} |
|
1182
|
|
|
|
|
|
|
} |
|
1183
|
0
|
|
|
|
|
|
return $o . join(', ', @str) . "]\n"; |
|
1184
|
|
|
|
|
|
|
} |
|
1185
|
|
|
|
|
|
|
} |
|
1186
|
|
|
|
|
|
|
|
|
1187
|
|
|
|
|
|
|
sub dump_to_string { |
|
1188
|
0
|
|
|
0
|
0
|
|
my ($self, %opts) = @_; |
|
1189
|
0
|
|
0
|
|
|
|
my $tab = $opts{tab} //= ' '; |
|
1190
|
0
|
|
|
|
|
|
my $vs = $self->{vs}; |
|
1191
|
0
|
|
|
|
|
|
my $nvs = @$vs; |
|
1192
|
0
|
0
|
|
|
|
|
my $hidden = join ", ", keys %{$self->{hidden} || {}}; |
|
|
0
|
|
|
|
|
|
|
|
1193
|
0
|
|
|
|
|
|
my $o = "tree: n: $nvs, hidden: {$hidden}\n"; |
|
1194
|
0
|
0
|
|
|
|
|
if (my $t = $self->{tree}) { |
|
1195
|
0
|
0
|
|
|
|
|
require Term::ANSIColor if $opts{remark}; |
|
1196
|
0
|
|
|
|
|
|
return $o . _dump_to_string($vs, $t, $tab, \%opts); |
|
1197
|
|
|
|
|
|
|
} |
|
1198
|
|
|
|
|
|
|
else { |
|
1199
|
0
|
|
|
|
|
|
return "$o${tab}(empty)\n"; |
|
1200
|
|
|
|
|
|
|
} |
|
1201
|
|
|
|
|
|
|
} |
|
1202
|
|
|
|
|
|
|
|
|
1203
|
|
|
|
|
|
|
sub dump { |
|
1204
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
1205
|
0
|
|
|
|
|
|
print $self->dump_to_string(@_); |
|
1206
|
|
|
|
|
|
|
} |
|
1207
|
|
|
|
|
|
|
|
|
1208
|
|
|
|
|
|
|
1; |
|
1209
|
|
|
|
|
|
|
__END__ |