File Coverage

blib/lib/Math/Vector/Real/Neighbors.pm
Criterion Covered Total %
statement 9 77 11.6
branch 0 14 0.0
condition n/a
subroutine 3 8 37.5
pod 2 2 100.0
total 14 101 13.8


line stmt bran cond sub pod time code
1             package Math::Vector::Real::Neighbors;
2              
3             our $VERSION = '0.01';
4              
5 1     1   56877 use strict;
  1         3  
  1         43  
6 1     1   5 use warnings;
  1         2  
  1         34  
7              
8 1     1   883 use Sort::Key::Radix qw(nkeysort_inplace);
  1         801  
  1         1089  
9              
10             sub neighbors {
11 0     0 1   my $class = shift;
12 0           my ($bottom, $top) = Math::Vector::Real->box(@_);
13 0           my $box = $top - $bottom;
14 0           my $v = [map $_ - $bottom, @_];
15 0           my $ixs = [0..$#_];
16 0           my $dist2 = [($box->abs2 * 10) x @_];
17 0           my $neighbors = [(undef) x @_];
18 0           _neighbors($v, $ixs, $dist2, $neighbors, $box, 0);
19 0           return @$neighbors;
20             }
21              
22             sub neighbors_bruteforce {
23 0     0 1   my $class = shift;
24 0           my ($bottom, $top) = Math::Vector::Real->box(@_);
25 0           my $box = $top - $bottom;
26 0           my $v = [map $_ - $bottom, @_];
27 0           my $ixs = [0..$#_];
28 0           my $dist2 = [($box->abs2 * 10) x @_];
29 0           my $neighbors = [(undef) x @_];
30 0           _neighbors_bruteforce($v, $ixs, $dist2, $neighbors, $box, 0);
31 0           return @$neighbors;
32             }
33              
34             sub _neighbors_bruteforce {
35 0     0     my ($v, $ixs, $dist2, $neighbors) = @_;
36 0           my $ixix = 0;
37 0           for my $i (@$ixs) {
38 0           $ixix++;
39 0           my $v0 = $v->[$i];
40 0           for my $j (@$ixs[$ixix..$#$ixs]) {
41 0           my $d2 = $v0->dist2($v->[$j]);
42 0 0         if ($dist2->[$i] > $d2) {
43 0           $dist2->[$i] = $d2;
44 0           $neighbors->[$i] = $j;
45             }
46 0 0         if ($dist2->[$j] > $d2) {
47 0           $dist2->[$j] = $d2;
48 0           $neighbors->[$j] = $i;
49             }
50             }
51             }
52             }
53              
54             sub _neighbors {
55 0 0   0     if (@{$_[1]} < 6) {
  0            
56 0           _neighbors_bruteforce(@_);
57             }
58             else {
59 0           my ($v, $ixs, $dist2, $neighbors, $box) = @_;
60 0           my $dim = $box->max_component_index;
61 0     0     nkeysort_inplace { $v->[$_][$dim] } @$ixs;
  0            
62              
63 0           my $bfirst = @$ixs >> 1;
64 0           my $alast = $bfirst - 1;
65              
66 0           my $abox = $box->clone;
67 0           $abox->[$dim] = $v->[$ixs->[$alast]][$dim] - $v->[$ixs->[0]][$dim];
68 0           my $bbox = $box->clone;
69 0           $bbox->[$dim] = $v->[$ixs->[$#$ixs]][$dim] - $v->[$ixs->[$bfirst]][$dim];
70              
71 0           _neighbors($v, [@$ixs[0..$alast]], $dist2, $neighbors, $abox);
72 0           _neighbors($v, [@$ixs[$bfirst..$#$ixs]], $dist2, $neighbors, $bbox);
73              
74 0           for my $i (@$ixs[0..$alast]) {
75 0           my $vi = $v->[$i];
76 0           my $mind2 = $dist2->[$i];
77 0           for my $j (@$ixs[$bfirst..$#$ixs]) {
78 0           my $vj = $v->[$j];
79 0           my $dc = $vj->[$dim] - $vi->[$dim];
80 0 0         last unless ($mind2 > $dc * $dc);
81 0           my $d2 = $vi->dist2($vj);
82 0 0         if ($d2 < $mind2) {
83 0           $mind2 = $dist2->[$i] = $d2;
84 0           $neighbors->[$i] = $j;
85             }
86             }
87             }
88              
89 0           for my $i (@$ixs[$bfirst..$#$ixs]) {
90 0           my $vi = $v->[$i];
91 0           my $mind2 = $dist2->[$i];
92 0           for my $j (reverse @$ixs[0..$alast]) {
93 0           my $vj = $v->[$j];
94 0           my $dc = $vj->[$dim] - $vi->[$dim];
95 0 0         last unless ($mind2 > $dc * $dc);
96 0           my $d2 = $vi->dist2($vj);
97 0 0         if ($d2 < $mind2) {
98 0           $mind2 = $dist2->[$i] = $d2;
99 0           $neighbors->[$i] = $j;
100             }
101             }
102             }
103              
104             # my @dist2_cp = @$dist2;
105             # my @neighbors_cp = @$neighbors;
106             # _neighbors_bruteforce($v, $ixs, $dist2, $neighbors, $abox);
107             # use 5.010;
108             # say "ixs : @$ixs";
109             # say "neighbors_cp: @neighbors_cp[@$ixs]";
110             # say "neighbors : @$neighbors[@$ixs]";
111             }
112             }
113              
114             1;
115             __END__