Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.ALGLIB-2.5.0/ALGLIB-2.5.0/nearestneighbor.cs @ 5192

Last change on this file since 5192 was 3839, checked in by mkommend, 14 years ago

implemented first version of LR (ticket #1012)

File size: 48.4 KB
Line 
1/*************************************************************************
2Copyright (c) 2010, Sergey Bochkanov (ALGLIB project).
3
4>>> SOURCE LICENSE >>>
5This program is free software; you can redistribute it and/or modify
6it under the terms of the GNU General Public License as published by
7the Free Software Foundation (www.fsf.org); either version 2 of the
8License, or (at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13GNU General Public License for more details.
14
15A copy of the GNU General Public License is available at
16http://www.fsf.org/licensing/licenses
17
18>>> END OF LICENSE >>>
19*************************************************************************/
20
21using System;
22
23namespace alglib
24{
25    public class nearestneighbor
26    {
27        public struct kdtree
28        {
29            public int n;
30            public int nx;
31            public int ny;
32            public int normtype;
33            public int distmatrixtype;
34            public double[,] xy;
35            public int[] tags;
36            public double[] boxmin;
37            public double[] boxmax;
38            public double[] curboxmin;
39            public double[] curboxmax;
40            public double curdist;
41            public int[] nodes;
42            public double[] splits;
43            public double[] x;
44            public int kneeded;
45            public double rneeded;
46            public bool selfmatch;
47            public double approxf;
48            public int kcur;
49            public int[] idx;
50            public double[] r;
51            public double[] buf;
52            public int debugcounter;
53        };
54
55
56
57
58        public const int splitnodesize = 6;
59
60
61        /*************************************************************************
62        KD-tree creation
63
64        This subroutine creates KD-tree from set of X-values and optional Y-values
65
66        INPUT PARAMETERS
67            XY      -   dataset, array[0..N-1,0..NX+NY-1].
68                        one row corresponds to one point.
69                        first NX columns contain X-values, next NY (NY may be zero)
70                        columns may contain associated Y-values
71            N       -   number of points, N>=1
72            NX      -   space dimension, NX>=1.
73            NY      -   number of optional Y-values, NY>=0.
74            NormType-   norm type:
75                        * 0 denotes infinity-norm
76                        * 1 denotes 1-norm
77                        * 2 denotes 2-norm (Euclidean norm)
78                       
79        OUTPUT PARAMETERS
80            KDT     -   KD-tree
81           
82           
83        NOTES
84
85        1. KD-tree  creation  have O(N*logN) complexity and O(N*(2*NX+NY))  memory
86           requirements.
87        2. Although KD-trees may be used with any combination of N  and  NX,  they
88           are more efficient than brute-force search only when N >> 4^NX. So they
89           are most useful in low-dimensional tasks (NX=2, NX=3). NX=1  is another
90           inefficient case, because  simple  binary  search  (without  additional
91           structures) is much more efficient in such tasks than KD-trees.
92
93          -- ALGLIB --
94             Copyright 28.02.2010 by Bochkanov Sergey
95        *************************************************************************/
96        public static void kdtreebuild(ref double[,] xy,
97            int n,
98            int nx,
99            int ny,
100            int normtype,
101            ref kdtree kdt)
102        {
103            int[] tags = new int[0];
104            int i = 0;
105
106            System.Diagnostics.Debug.Assert(n>=1, "KDTreeBuild: N<1!");
107            System.Diagnostics.Debug.Assert(nx>=1, "KDTreeBuild: NX<1!");
108            System.Diagnostics.Debug.Assert(ny>=0, "KDTreeBuild: NY<0!");
109            System.Diagnostics.Debug.Assert(normtype>=0 & normtype<=2, "KDTreeBuild: incorrect NormType!");
110            tags = new int[n];
111            for(i=0; i<=n-1; i++)
112            {
113                tags[i] = 0;
114            }
115            kdtreebuildtagged(ref xy, ref tags, n, nx, ny, normtype, ref kdt);
116        }
117
118
119        /*************************************************************************
120        KD-tree creation
121
122        This  subroutine  creates  KD-tree  from set of X-values, integer tags and
123        optional Y-values
124
125        INPUT PARAMETERS
126            XY      -   dataset, array[0..N-1,0..NX+NY-1].
127                        one row corresponds to one point.
128                        first NX columns contain X-values, next NY (NY may be zero)
129                        columns may contain associated Y-values
130            Tags    -   tags, array[0..N-1], contains integer tags associated
131                        with points.
132            N       -   number of points, N>=1
133            NX      -   space dimension, NX>=1.
134            NY      -   number of optional Y-values, NY>=0.
135            NormType-   norm type:
136                        * 0 denotes infinity-norm
137                        * 1 denotes 1-norm
138                        * 2 denotes 2-norm (Euclidean norm)
139
140        OUTPUT PARAMETERS
141            KDT     -   KD-tree
142
143        NOTES
144
145        1. KD-tree  creation  have O(N*logN) complexity and O(N*(2*NX+NY))  memory
146           requirements.
147        2. Although KD-trees may be used with any combination of N  and  NX,  they
148           are more efficient than brute-force search only when N >> 4^NX. So they
149           are most useful in low-dimensional tasks (NX=2, NX=3). NX=1  is another
150           inefficient case, because  simple  binary  search  (without  additional
151           structures) is much more efficient in such tasks than KD-trees.
152
153          -- ALGLIB --
154             Copyright 28.02.2010 by Bochkanov Sergey
155        *************************************************************************/
156        public static void kdtreebuildtagged(ref double[,] xy,
157            ref int[] tags,
158            int n,
159            int nx,
160            int ny,
161            int normtype,
162            ref kdtree kdt)
163        {
164            int i = 0;
165            int j = 0;
166            int maxnodes = 0;
167            int nodesoffs = 0;
168            int splitsoffs = 0;
169            int i_ = 0;
170            int i1_ = 0;
171
172            System.Diagnostics.Debug.Assert(n>=1, "KDTreeBuildTagged: N<1!");
173            System.Diagnostics.Debug.Assert(nx>=1, "KDTreeBuildTagged: NX<1!");
174            System.Diagnostics.Debug.Assert(ny>=0, "KDTreeBuildTagged: NY<0!");
175            System.Diagnostics.Debug.Assert(normtype>=0 & normtype<=2, "KDTreeBuildTagged: incorrect NormType!");
176           
177            //
178            // initialize
179            //
180            kdt.n = n;
181            kdt.nx = nx;
182            kdt.ny = ny;
183            kdt.normtype = normtype;
184            kdt.distmatrixtype = 0;
185            kdt.xy = new double[n, 2*nx+ny];
186            kdt.tags = new int[n];
187            kdt.idx = new int[n];
188            kdt.r = new double[n];
189            kdt.x = new double[nx];
190            kdt.buf = new double[Math.Max(n, nx)];
191           
192            //
193            // Initial fill
194            //
195            for(i=0; i<=n-1; i++)
196            {
197                for(i_=0; i_<=nx-1;i_++)
198                {
199                    kdt.xy[i,i_] = xy[i,i_];
200                }
201                i1_ = (0) - (nx);
202                for(i_=nx; i_<=2*nx+ny-1;i_++)
203                {
204                    kdt.xy[i,i_] = xy[i,i_+i1_];
205                }
206                kdt.tags[i] = tags[i];
207            }
208           
209            //
210            // Determine bounding box
211            //
212            kdt.boxmin = new double[nx];
213            kdt.boxmax = new double[nx];
214            kdt.curboxmin = new double[nx];
215            kdt.curboxmax = new double[nx];
216            for(i_=0; i_<=nx-1;i_++)
217            {
218                kdt.boxmin[i_] = kdt.xy[0,i_];
219            }
220            for(i_=0; i_<=nx-1;i_++)
221            {
222                kdt.boxmax[i_] = kdt.xy[0,i_];
223            }
224            for(i=1; i<=n-1; i++)
225            {
226                for(j=0; j<=nx-1; j++)
227                {
228                    kdt.boxmin[j] = Math.Min(kdt.boxmin[j], kdt.xy[i,j]);
229                    kdt.boxmax[j] = Math.Max(kdt.boxmax[j], kdt.xy[i,j]);
230                }
231            }
232           
233            //
234            // prepare tree structure
235            // * MaxNodes=N because we guarantee no trivial splits, i.e.
236            //   every split will generate two non-empty boxes
237            //
238            maxnodes = n;
239            kdt.nodes = new int[splitnodesize*2*maxnodes];
240            kdt.splits = new double[2*maxnodes];
241            nodesoffs = 0;
242            splitsoffs = 0;
243            for(i_=0; i_<=nx-1;i_++)
244            {
245                kdt.curboxmin[i_] = kdt.boxmin[i_];
246            }
247            for(i_=0; i_<=nx-1;i_++)
248            {
249                kdt.curboxmax[i_] = kdt.boxmax[i_];
250            }
251            kdtreegeneratetreerec(ref kdt, ref nodesoffs, ref splitsoffs, 0, n, 8);
252           
253            //
254            // Set current query size to 0
255            //
256            kdt.kcur = 0;
257        }
258
259
260        /*************************************************************************
261        K-NN query: K nearest neighbors
262
263        INPUT PARAMETERS
264            KDT         -   KD-tree
265            X           -   point, array[0..NX-1].
266            K           -   number of neighbors to return, K>=1
267            SelfMatch   -   whether self-matches are allowed:
268                            * if True, nearest neighbor may be the point itself
269                              (if it exists in original dataset)
270                            * if False, then only points with non-zero distance
271                              are returned
272
273        RESULT
274            number of actual neighbors found (either K or N, if K>N).
275
276        This  subroutine  performs  query  and  stores  its result in the internal
277        structures of the KD-tree. You can use  following  subroutines  to  obtain
278        these results:
279        * KDTreeQueryResultsX() to get X-values
280        * KDTreeQueryResultsXY() to get X- and Y-values
281        * KDTreeQueryResultsTags() to get tag values
282        * KDTreeQueryResultsDistances() to get distances
283
284          -- ALGLIB --
285             Copyright 28.02.2010 by Bochkanov Sergey
286        *************************************************************************/
287        public static int kdtreequeryknn(ref kdtree kdt,
288            ref double[] x,
289            int k,
290            bool selfmatch)
291        {
292            int result = 0;
293
294            result = kdtreequeryaknn(ref kdt, ref x, k, selfmatch, 0.0);
295            return result;
296        }
297
298
299        /*************************************************************************
300        R-NN query: all points within R-sphere centered at X
301
302        INPUT PARAMETERS
303            KDT         -   KD-tree
304            X           -   point, array[0..NX-1].
305            R           -   radius of sphere (in corresponding norm), R>0
306            SelfMatch   -   whether self-matches are allowed:
307                            * if True, nearest neighbor may be the point itself
308                              (if it exists in original dataset)
309                            * if False, then only points with non-zero distance
310                              are returned
311
312        RESULT
313            number of neighbors found, >=0
314
315        This  subroutine  performs  query  and  stores  its result in the internal
316        structures of the KD-tree. You can use  following  subroutines  to  obtain
317        actual results:
318        * KDTreeQueryResultsX() to get X-values
319        * KDTreeQueryResultsXY() to get X- and Y-values
320        * KDTreeQueryResultsTags() to get tag values
321        * KDTreeQueryResultsDistances() to get distances
322
323          -- ALGLIB --
324             Copyright 28.02.2010 by Bochkanov Sergey
325        *************************************************************************/
326        public static int kdtreequeryrnn(ref kdtree kdt,
327            ref double[] x,
328            double r,
329            bool selfmatch)
330        {
331            int result = 0;
332            int i = 0;
333            int j = 0;
334            double vx = 0;
335            double vmin = 0;
336            double vmax = 0;
337
338            System.Diagnostics.Debug.Assert((double)(r)>(double)(0), "KDTreeQueryRNN: incorrect R!");
339           
340            //
341            // Prepare parameters
342            //
343            kdt.kneeded = 0;
344            if( kdt.normtype!=2 )
345            {
346                kdt.rneeded = r;
347            }
348            else
349            {
350                kdt.rneeded = AP.Math.Sqr(r);
351            }
352            kdt.selfmatch = selfmatch;
353            kdt.approxf = 1;
354            kdt.kcur = 0;
355           
356            //
357            // calculate distance from point to current bounding box
358            //
359            kdtreeinitbox(ref kdt, ref x);
360           
361            //
362            // call recursive search
363            // results are returned as heap
364            //
365            kdtreequerynnrec(ref kdt, 0);
366           
367            //
368            // pop from heap to generate ordered representation
369            //
370            // last element is non pop'ed because it is already in
371            // its place
372            //
373            result = kdt.kcur;
374            j = kdt.kcur;
375            for(i=kdt.kcur; i>=2; i--)
376            {
377                tsort.tagheappopi(ref kdt.r, ref kdt.idx, ref j);
378            }
379            return result;
380        }
381
382
383        /*************************************************************************
384        K-NN query: approximate K nearest neighbors
385
386        INPUT PARAMETERS
387            KDT         -   KD-tree
388            X           -   point, array[0..NX-1].
389            K           -   number of neighbors to return, K>=1
390            SelfMatch   -   whether self-matches are allowed:
391                            * if True, nearest neighbor may be the point itself
392                              (if it exists in original dataset)
393                            * if False, then only points with non-zero distance
394                              are returned
395            Eps         -   approximation factor, Eps>=0. eps-approximate  nearest
396                            neighbor  is  a  neighbor  whose distance from X is at
397                            most (1+eps) times distance of true nearest neighbor.
398
399        RESULT
400            number of actual neighbors found (either K or N, if K>N).
401           
402        NOTES
403            significant performance gain may be achieved only when Eps  is  is  on
404            the order of magnitude of 1 or larger.
405
406        This  subroutine  performs  query  and  stores  its result in the internal
407        structures of the KD-tree. You can use  following  subroutines  to  obtain
408        these results:
409        * KDTreeQueryResultsX() to get X-values
410        * KDTreeQueryResultsXY() to get X- and Y-values
411        * KDTreeQueryResultsTags() to get tag values
412        * KDTreeQueryResultsDistances() to get distances
413
414          -- ALGLIB --
415             Copyright 28.02.2010 by Bochkanov Sergey
416        *************************************************************************/
417        public static int kdtreequeryaknn(ref kdtree kdt,
418            ref double[] x,
419            int k,
420            bool selfmatch,
421            double eps)
422        {
423            int result = 0;
424            int i = 0;
425            int j = 0;
426            double vx = 0;
427            double vmin = 0;
428            double vmax = 0;
429
430            System.Diagnostics.Debug.Assert(k>0, "KDTreeQueryKNN: incorrect K!");
431            System.Diagnostics.Debug.Assert((double)(eps)>=(double)(0), "KDTreeQueryKNN: incorrect Eps!");
432           
433            //
434            // Prepare parameters
435            //
436            k = Math.Min(k, kdt.n);
437            kdt.kneeded = k;
438            kdt.rneeded = 0;
439            kdt.selfmatch = selfmatch;
440            if( kdt.normtype==2 )
441            {
442                kdt.approxf = 1/AP.Math.Sqr(1+eps);
443            }
444            else
445            {
446                kdt.approxf = 1/(1+eps);
447            }
448            kdt.kcur = 0;
449           
450            //
451            // calculate distance from point to current bounding box
452            //
453            kdtreeinitbox(ref kdt, ref x);
454           
455            //
456            // call recursive search
457            // results are returned as heap
458            //
459            kdtreequerynnrec(ref kdt, 0);
460           
461            //
462            // pop from heap to generate ordered representation
463            //
464            // last element is non pop'ed because it is already in
465            // its place
466            //
467            result = kdt.kcur;
468            j = kdt.kcur;
469            for(i=kdt.kcur; i>=2; i--)
470            {
471                tsort.tagheappopi(ref kdt.r, ref kdt.idx, ref j);
472            }
473            return result;
474        }
475
476
477        /*************************************************************************
478        X-values from last query
479
480        INPUT PARAMETERS
481            KDT     -   KD-tree
482            X       -   pre-allocated array, at least K rows, at least NX columns
483           
484        OUTPUT PARAMETERS
485            X       -   K rows are filled with X-values
486            K       -   number of points
487
488        NOTE
489            points are ordered by distance from the query point (first = closest)
490
491        SEE ALSO
492        * KDTreeQueryResultsXY()            X- and Y-values
493        * KDTreeQueryResultsTags()          tag values
494        * KDTreeQueryResultsDistances()     distances
495
496          -- ALGLIB --
497             Copyright 28.02.2010 by Bochkanov Sergey
498        *************************************************************************/
499        public static void kdtreequeryresultsx(ref kdtree kdt,
500            ref double[,] x,
501            ref int k)
502        {
503            int i = 0;
504            int i_ = 0;
505            int i1_ = 0;
506
507            k = kdt.kcur;
508            for(i=0; i<=k-1; i++)
509            {
510                i1_ = (kdt.nx) - (0);
511                for(i_=0; i_<=kdt.nx-1;i_++)
512                {
513                    x[i,i_] = kdt.xy[kdt.idx[i],i_+i1_];
514                }
515            }
516        }
517
518
519        /*************************************************************************
520        X- and Y-values from last query
521
522        INPUT PARAMETERS
523            KDT     -   KD-tree
524            XY      -   pre-allocated array, at least K rows, at least NX+NY columns
525
526        OUTPUT PARAMETERS
527            X       -   K rows are filled with points: first NX columns with
528                        X-values, next NY columns - with Y-values.
529            K       -   number of points
530
531        NOTE
532            points are ordered by distance from the query point (first = closest)
533
534        SEE ALSO
535        * KDTreeQueryResultsX()             X-values
536        * KDTreeQueryResultsTags()          tag values
537        * KDTreeQueryResultsDistances()     distances
538
539          -- ALGLIB --
540             Copyright 28.02.2010 by Bochkanov Sergey
541        *************************************************************************/
542        public static void kdtreequeryresultsxy(ref kdtree kdt,
543            ref double[,] xy,
544            ref int k)
545        {
546            int i = 0;
547            int i_ = 0;
548            int i1_ = 0;
549
550            k = kdt.kcur;
551            for(i=0; i<=k-1; i++)
552            {
553                i1_ = (kdt.nx) - (0);
554                for(i_=0; i_<=kdt.nx+kdt.ny-1;i_++)
555                {
556                    xy[i,i_] = kdt.xy[kdt.idx[i],i_+i1_];
557                }
558            }
559        }
560
561
562        /*************************************************************************
563        point tags from last query
564
565        INPUT PARAMETERS
566            KDT     -   KD-tree
567            Tags    -   pre-allocated array, at least K elements
568
569        OUTPUT PARAMETERS
570            Tags    -   first K elements are filled with tags associated with points,
571                        or, when no tags were supplied, with zeros
572            K       -   number of points
573
574        NOTE
575            points are ordered by distance from the query point (first = closest)
576
577        SEE ALSO
578        * KDTreeQueryResultsX()             X-values
579        * KDTreeQueryResultsXY()            X- and Y-values
580        * KDTreeQueryResultsDistances()     distances
581
582          -- ALGLIB --
583             Copyright 28.02.2010 by Bochkanov Sergey
584        *************************************************************************/
585        public static void kdtreequeryresultstags(ref kdtree kdt,
586            ref int[] tags,
587            ref int k)
588        {
589            int i = 0;
590
591            k = kdt.kcur;
592            for(i=0; i<=k-1; i++)
593            {
594                tags[i] = kdt.tags[kdt.idx[i]];
595            }
596        }
597
598
599        /*************************************************************************
600        Distances from last query
601
602        INPUT PARAMETERS
603            KDT     -   KD-tree
604            R       -   pre-allocated array, at least K elements
605
606        OUTPUT PARAMETERS
607            R       -   first K elements are filled with distances
608                        (in corresponding norm)
609            K       -   number of points
610
611        NOTE
612            points are ordered by distance from the query point (first = closest)
613
614        SEE ALSO
615        * KDTreeQueryResultsX()             X-values
616        * KDTreeQueryResultsXY()            X- and Y-values
617        * KDTreeQueryResultsTags()          tag values
618
619          -- ALGLIB --
620             Copyright 28.02.2010 by Bochkanov Sergey
621        *************************************************************************/
622        public static void kdtreequeryresultsdistances(ref kdtree kdt,
623            ref double[] r,
624            ref int k)
625        {
626            int i = 0;
627
628            k = kdt.kcur;
629           
630            //
631            // unload norms
632            //
633            // Abs() call is used to handle cases with negative norms
634            // (generated during KFN requests)
635            //
636            if( kdt.normtype==0 )
637            {
638                for(i=0; i<=k-1; i++)
639                {
640                    r[i] = Math.Abs(kdt.r[i]);
641                }
642            }
643            if( kdt.normtype==1 )
644            {
645                for(i=0; i<=k-1; i++)
646                {
647                    r[i] = Math.Abs(kdt.r[i]);
648                }
649            }
650            if( kdt.normtype==2 )
651            {
652                for(i=0; i<=k-1; i++)
653                {
654                    r[i] = Math.Sqrt(Math.Abs(kdt.r[i]));
655                }
656            }
657        }
658
659
660        /*************************************************************************
661        Rearranges nodes [I1,I2) using partition in D-th dimension with S as threshold.
662        Returns split position I3: [I1,I3) and [I3,I2) are created as result.
663
664        This subroutine doesn't create tree structures, just rearranges nodes.
665        *************************************************************************/
666        private static void kdtreesplit(ref kdtree kdt,
667            int i1,
668            int i2,
669            int d,
670            double s,
671            ref int i3)
672        {
673            int i = 0;
674            int j = 0;
675            int ileft = 0;
676            int iright = 0;
677            double v = 0;
678
679           
680            //
681            // split XY/Tags in two parts:
682            // * [ILeft,IRight] is non-processed part of XY/Tags
683            //
684            // After cycle is done, we have Ileft=IRight. We deal with
685            // this element separately.
686            //
687            // After this, [I1,ILeft) contains left part, and [ILeft,I2)
688            // contains right part.
689            //
690            ileft = i1;
691            iright = i2-1;
692            while( ileft<iright )
693            {
694                if( (double)(kdt.xy[ileft,d])<=(double)(s) )
695                {
696                   
697                    //
698                    // XY[ILeft] is on its place.
699                    // Advance ILeft.
700                    //
701                    ileft = ileft+1;
702                }
703                else
704                {
705                   
706                    //
707                    // XY[ILeft,..] must be at IRight.
708                    // Swap and advance IRight.
709                    //
710                    for(i=0; i<=2*kdt.nx+kdt.ny-1; i++)
711                    {
712                        v = kdt.xy[ileft,i];
713                        kdt.xy[ileft,i] = kdt.xy[iright,i];
714                        kdt.xy[iright,i] = v;
715                    }
716                    j = kdt.tags[ileft];
717                    kdt.tags[ileft] = kdt.tags[iright];
718                    kdt.tags[iright] = j;
719                    iright = iright-1;
720                }
721            }
722            if( (double)(kdt.xy[ileft,d])<=(double)(s) )
723            {
724                ileft = ileft+1;
725            }
726            else
727            {
728                iright = iright-1;
729            }
730            i3 = ileft;
731        }
732
733
734        /*************************************************************************
735        Recursive kd-tree generation subroutine.
736
737        PARAMETERS
738            KDT         tree
739            NodesOffs   unused part of Nodes[] which must be filled by tree
740            SplitsOffs  unused part of Splits[]
741            I1, I2      points from [I1,I2) are processed
742           
743        NodesOffs[] and SplitsOffs[] must be large enough.
744
745          -- ALGLIB --
746             Copyright 28.02.2010 by Bochkanov Sergey
747        *************************************************************************/
748        private static void kdtreegeneratetreerec(ref kdtree kdt,
749            ref int nodesoffs,
750            ref int splitsoffs,
751            int i1,
752            int i2,
753            int maxleafsize)
754        {
755            int n = 0;
756            int nx = 0;
757            int ny = 0;
758            int i = 0;
759            int j = 0;
760            int oldoffs = 0;
761            int i3 = 0;
762            int cntless = 0;
763            int cntgreater = 0;
764            double minv = 0;
765            double maxv = 0;
766            int minidx = 0;
767            int maxidx = 0;
768            int d = 0;
769            double ds = 0;
770            double s = 0;
771            double v = 0;
772            int i_ = 0;
773            int i1_ = 0;
774
775            System.Diagnostics.Debug.Assert(i2>i1, "KDTreeGenerateTreeRec: internal error");
776           
777            //
778            // Generate leaf if needed
779            //
780            if( i2-i1<=maxleafsize )
781            {
782                kdt.nodes[nodesoffs+0] = i2-i1;
783                kdt.nodes[nodesoffs+1] = i1;
784                nodesoffs = nodesoffs+2;
785                return;
786            }
787           
788            //
789            // Load values for easier access
790            //
791            nx = kdt.nx;
792            ny = kdt.ny;
793           
794            //
795            // select dimension to split:
796            // * D is a dimension number
797            //
798            d = 0;
799            ds = kdt.curboxmax[0]-kdt.curboxmin[0];
800            for(i=1; i<=nx-1; i++)
801            {
802                v = kdt.curboxmax[i]-kdt.curboxmin[i];
803                if( (double)(v)>(double)(ds) )
804                {
805                    ds = v;
806                    d = i;
807                }
808            }
809           
810            //
811            // Select split position S using sliding midpoint rule,
812            // rearrange points into [I1,I3) and [I3,I2)
813            //
814            s = kdt.curboxmin[d]+0.5*ds;
815            i1_ = (i1) - (0);
816            for(i_=0; i_<=i2-i1-1;i_++)
817            {
818                kdt.buf[i_] = kdt.xy[i_+i1_,d];
819            }
820            n = i2-i1;
821            cntless = 0;
822            cntgreater = 0;
823            minv = kdt.buf[0];
824            maxv = kdt.buf[0];
825            minidx = i1;
826            maxidx = i1;
827            for(i=0; i<=n-1; i++)
828            {
829                v = kdt.buf[i];
830                if( (double)(v)<(double)(minv) )
831                {
832                    minv = v;
833                    minidx = i1+i;
834                }
835                if( (double)(v)>(double)(maxv) )
836                {
837                    maxv = v;
838                    maxidx = i1+i;
839                }
840                if( (double)(v)<(double)(s) )
841                {
842                    cntless = cntless+1;
843                }
844                if( (double)(v)>(double)(s) )
845                {
846                    cntgreater = cntgreater+1;
847                }
848            }
849            if( cntless>0 & cntgreater>0 )
850            {
851               
852                //
853                // normal midpoint split
854                //
855                kdtreesplit(ref kdt, i1, i2, d, s, ref i3);
856            }
857            else
858            {
859               
860                //
861                // sliding midpoint
862                //
863                if( cntless==0 )
864                {
865                   
866                    //
867                    // 1. move split to MinV,
868                    // 2. place one point to the left bin (move to I1),
869                    //    others - to the right bin
870                    //
871                    s = minv;
872                    if( minidx!=i1 )
873                    {
874                        for(i=0; i<=2*kdt.nx+kdt.ny-1; i++)
875                        {
876                            v = kdt.xy[minidx,i];
877                            kdt.xy[minidx,i] = kdt.xy[i1,i];
878                            kdt.xy[i1,i] = v;
879                        }
880                        j = kdt.tags[minidx];
881                        kdt.tags[minidx] = kdt.tags[i1];
882                        kdt.tags[i1] = j;
883                    }
884                    i3 = i1+1;
885                }
886                else
887                {
888                   
889                    //
890                    // 1. move split to MaxV,
891                    // 2. place one point to the right bin (move to I2-1),
892                    //    others - to the left bin
893                    //
894                    s = maxv;
895                    if( maxidx!=i2-1 )
896                    {
897                        for(i=0; i<=2*kdt.nx+kdt.ny-1; i++)
898                        {
899                            v = kdt.xy[maxidx,i];
900                            kdt.xy[maxidx,i] = kdt.xy[i2-1,i];
901                            kdt.xy[i2-1,i] = v;
902                        }
903                        j = kdt.tags[maxidx];
904                        kdt.tags[maxidx] = kdt.tags[i2-1];
905                        kdt.tags[i2-1] = j;
906                    }
907                    i3 = i2-1;
908                }
909            }
910           
911            //
912            // Generate 'split' node
913            //
914            kdt.nodes[nodesoffs+0] = 0;
915            kdt.nodes[nodesoffs+1] = d;
916            kdt.nodes[nodesoffs+2] = splitsoffs;
917            kdt.splits[splitsoffs+0] = s;
918            oldoffs = nodesoffs;
919            nodesoffs = nodesoffs+splitnodesize;
920            splitsoffs = splitsoffs+1;
921           
922            //
923            // Recirsive generation:
924            // * update CurBox
925            // * call subroutine
926            // * restore CurBox
927            //
928            kdt.nodes[oldoffs+3] = nodesoffs;
929            v = kdt.curboxmax[d];
930            kdt.curboxmax[d] = s;
931            kdtreegeneratetreerec(ref kdt, ref nodesoffs, ref splitsoffs, i1, i3, maxleafsize);
932            kdt.curboxmax[d] = v;
933            kdt.nodes[oldoffs+4] = nodesoffs;
934            v = kdt.curboxmin[d];
935            kdt.curboxmin[d] = s;
936            kdtreegeneratetreerec(ref kdt, ref nodesoffs, ref splitsoffs, i3, i2, maxleafsize);
937            kdt.curboxmin[d] = v;
938        }
939
940
941        /*************************************************************************
942        Recursive subroutine for NN queries.
943
944          -- ALGLIB --
945             Copyright 28.02.2010 by Bochkanov Sergey
946        *************************************************************************/
947        private static void kdtreequerynnrec(ref kdtree kdt,
948            int offs)
949        {
950            double ptdist = 0;
951            int i = 0;
952            int j = 0;
953            int k = 0;
954            int ti = 0;
955            int nx = 0;
956            int i1 = 0;
957            int i2 = 0;
958            int k1 = 0;
959            int k2 = 0;
960            double r1 = 0;
961            double r2 = 0;
962            int d = 0;
963            double s = 0;
964            double v = 0;
965            double t1 = 0;
966            int childbestoffs = 0;
967            int childworstoffs = 0;
968            int childoffs = 0;
969            double prevdist = 0;
970            bool todive = new bool();
971            bool bestisleft = new bool();
972            bool updatemin = new bool();
973
974           
975            //
976            // Leaf node.
977            // Process points.
978            //
979            if( kdt.nodes[offs]>0 )
980            {
981                i1 = kdt.nodes[offs+1];
982                i2 = i1+kdt.nodes[offs];
983                for(i=i1; i<=i2-1; i++)
984                {
985                   
986                    //
987                    // Calculate distance
988                    //
989                    ptdist = 0;
990                    nx = kdt.nx;
991                    if( kdt.normtype==0 )
992                    {
993                        for(j=0; j<=nx-1; j++)
994                        {
995                            ptdist = Math.Max(ptdist, Math.Abs(kdt.xy[i,j]-kdt.x[j]));
996                        }
997                    }
998                    if( kdt.normtype==1 )
999                    {
1000                        for(j=0; j<=nx-1; j++)
1001                        {
1002                            ptdist = ptdist+Math.Abs(kdt.xy[i,j]-kdt.x[j]);
1003                        }
1004                    }
1005                    if( kdt.normtype==2 )
1006                    {
1007                        for(j=0; j<=nx-1; j++)
1008                        {
1009                            ptdist = ptdist+AP.Math.Sqr(kdt.xy[i,j]-kdt.x[j]);
1010                        }
1011                    }
1012                   
1013                    //
1014                    // Skip points with zero distance if self-matches are turned off
1015                    //
1016                    if( (double)(ptdist)==(double)(0) & !kdt.selfmatch )
1017                    {
1018                        continue;
1019                    }
1020                   
1021                    //
1022                    // We CAN'T process point if R-criterion isn't satisfied,
1023                    // i.e. (RNeeded<>0) AND (PtDist>R).
1024                    //
1025                    if( (double)(kdt.rneeded)==(double)(0) | (double)(ptdist)<=(double)(kdt.rneeded) )
1026                    {
1027                       
1028                        //
1029                        // R-criterion is satisfied, we must either:
1030                        // * replace worst point, if (KNeeded<>0) AND (KCur=KNeeded)
1031                        //   (or skip, if worst point is better)
1032                        // * add point without replacement otherwise
1033                        //
1034                        if( kdt.kcur<kdt.kneeded | kdt.kneeded==0 )
1035                        {
1036                           
1037                            //
1038                            // add current point to heap without replacement
1039                            //
1040                            tsort.tagheappushi(ref kdt.r, ref kdt.idx, ref kdt.kcur, ptdist, i);
1041                        }
1042                        else
1043                        {
1044                           
1045                            //
1046                            // New points are added or not, depending on their distance.
1047                            // If added, they replace element at the top of the heap
1048                            //
1049                            if( (double)(ptdist)<(double)(kdt.r[0]) )
1050                            {
1051                                if( kdt.kneeded==1 )
1052                                {
1053                                    kdt.idx[0] = i;
1054                                    kdt.r[0] = ptdist;
1055                                }
1056                                else
1057                                {
1058                                    tsort.tagheapreplacetopi(ref kdt.r, ref kdt.idx, kdt.kneeded, ptdist, i);
1059                                }
1060                            }
1061                        }
1062                    }
1063                }
1064                return;
1065            }
1066           
1067            //
1068            // Simple split
1069            //
1070            if( kdt.nodes[offs]==0 )
1071            {
1072               
1073                //
1074                // Load:
1075                // * D  dimension to split
1076                // * S  split position
1077                //
1078                d = kdt.nodes[offs+1];
1079                s = kdt.splits[kdt.nodes[offs+2]];
1080               
1081                //
1082                // Calculate:
1083                // * ChildBestOffs      child box with best chances
1084                // * ChildWorstOffs     child box with worst chances
1085                //
1086                if( (double)(kdt.x[d])<=(double)(s) )
1087                {
1088                    childbestoffs = kdt.nodes[offs+3];
1089                    childworstoffs = kdt.nodes[offs+4];
1090                    bestisleft = true;
1091                }
1092                else
1093                {
1094                    childbestoffs = kdt.nodes[offs+4];
1095                    childworstoffs = kdt.nodes[offs+3];
1096                    bestisleft = false;
1097                }
1098               
1099                //
1100                // Navigate through childs
1101                //
1102                for(i=0; i<=1; i++)
1103                {
1104                   
1105                    //
1106                    // Select child to process:
1107                    // * ChildOffs      current child offset in Nodes[]
1108                    // * UpdateMin      whether minimum or maximum value
1109                    //                  of bounding box is changed on update
1110                    //
1111                    if( i==0 )
1112                    {
1113                        childoffs = childbestoffs;
1114                        updatemin = !bestisleft;
1115                    }
1116                    else
1117                    {
1118                        updatemin = bestisleft;
1119                        childoffs = childworstoffs;
1120                    }
1121                   
1122                    //
1123                    // Update bounding box and current distance
1124                    //
1125                    if( updatemin )
1126                    {
1127                        prevdist = kdt.curdist;
1128                        t1 = kdt.x[d];
1129                        v = kdt.curboxmin[d];
1130                        if( (double)(t1)<=(double)(s) )
1131                        {
1132                            if( kdt.normtype==0 )
1133                            {
1134                                kdt.curdist = Math.Max(kdt.curdist, s-t1);
1135                            }
1136                            if( kdt.normtype==1 )
1137                            {
1138                                kdt.curdist = kdt.curdist-Math.Max(v-t1, 0)+s-t1;
1139                            }
1140                            if( kdt.normtype==2 )
1141                            {
1142                                kdt.curdist = kdt.curdist-AP.Math.Sqr(Math.Max(v-t1, 0))+AP.Math.Sqr(s-t1);
1143                            }
1144                        }
1145                        kdt.curboxmin[d] = s;
1146                    }
1147                    else
1148                    {
1149                        prevdist = kdt.curdist;
1150                        t1 = kdt.x[d];
1151                        v = kdt.curboxmax[d];
1152                        if( (double)(t1)>=(double)(s) )
1153                        {
1154                            if( kdt.normtype==0 )
1155                            {
1156                                kdt.curdist = Math.Max(kdt.curdist, t1-s);
1157                            }
1158                            if( kdt.normtype==1 )
1159                            {
1160                                kdt.curdist = kdt.curdist-Math.Max(t1-v, 0)+t1-s;
1161                            }
1162                            if( kdt.normtype==2 )
1163                            {
1164                                kdt.curdist = kdt.curdist-AP.Math.Sqr(Math.Max(t1-v, 0))+AP.Math.Sqr(t1-s);
1165                            }
1166                        }
1167                        kdt.curboxmax[d] = s;
1168                    }
1169                   
1170                    //
1171                    // Decide: to dive into cell or not to dive
1172                    //
1173                    if( (double)(kdt.rneeded)!=(double)(0) & (double)(kdt.curdist)>(double)(kdt.rneeded) )
1174                    {
1175                        todive = false;
1176                    }
1177                    else
1178                    {
1179                        if( kdt.kcur<kdt.kneeded | kdt.kneeded==0 )
1180                        {
1181                           
1182                            //
1183                            // KCur<KNeeded (i.e. not all points are found)
1184                            //
1185                            todive = true;
1186                        }
1187                        else
1188                        {
1189                           
1190                            //
1191                            // KCur=KNeeded, decide to dive or not to dive
1192                            // using point position relative to bounding box.
1193                            //
1194                            todive = (double)(kdt.curdist)<=(double)(kdt.r[0]*kdt.approxf);
1195                        }
1196                    }
1197                    if( todive )
1198                    {
1199                        kdtreequerynnrec(ref kdt, childoffs);
1200                    }
1201                   
1202                    //
1203                    // Restore bounding box and distance
1204                    //
1205                    if( updatemin )
1206                    {
1207                        kdt.curboxmin[d] = v;
1208                    }
1209                    else
1210                    {
1211                        kdt.curboxmax[d] = v;
1212                    }
1213                    kdt.curdist = prevdist;
1214                }
1215                return;
1216            }
1217        }
1218
1219
1220        /*************************************************************************
1221        Copies X[] to KDT.X[]
1222        Loads distance from X[] to bounding box.
1223        Initializes CurBox[].
1224
1225          -- ALGLIB --
1226             Copyright 28.02.2010 by Bochkanov Sergey
1227        *************************************************************************/
1228        private static void kdtreeinitbox(ref kdtree kdt,
1229            ref double[] x)
1230        {
1231            int i = 0;
1232            double vx = 0;
1233            double vmin = 0;
1234            double vmax = 0;
1235
1236           
1237            //
1238            // calculate distance from point to current bounding box
1239            //
1240            kdt.curdist = 0;
1241            if( kdt.normtype==0 )
1242            {
1243                for(i=0; i<=kdt.nx-1; i++)
1244                {
1245                    vx = x[i];
1246                    vmin = kdt.boxmin[i];
1247                    vmax = kdt.boxmax[i];
1248                    kdt.x[i] = vx;
1249                    kdt.curboxmin[i] = vmin;
1250                    kdt.curboxmax[i] = vmax;
1251                    if( (double)(vx)<(double)(vmin) )
1252                    {
1253                        kdt.curdist = Math.Max(kdt.curdist, vmin-vx);
1254                    }
1255                    else
1256                    {
1257                        if( (double)(vx)>(double)(vmax) )
1258                        {
1259                            kdt.curdist = Math.Max(kdt.curdist, vx-vmax);
1260                        }
1261                    }
1262                }
1263            }
1264            if( kdt.normtype==1 )
1265            {
1266                for(i=0; i<=kdt.nx-1; i++)
1267                {
1268                    vx = x[i];
1269                    vmin = kdt.boxmin[i];
1270                    vmax = kdt.boxmax[i];
1271                    kdt.x[i] = vx;
1272                    kdt.curboxmin[i] = vmin;
1273                    kdt.curboxmax[i] = vmax;
1274                    if( (double)(vx)<(double)(vmin) )
1275                    {
1276                        kdt.curdist = kdt.curdist+vmin-vx;
1277                    }
1278                    else
1279                    {
1280                        if( (double)(vx)>(double)(vmax) )
1281                        {
1282                            kdt.curdist = kdt.curdist+vx-vmax;
1283                        }
1284                    }
1285                }
1286            }
1287            if( kdt.normtype==2 )
1288            {
1289                for(i=0; i<=kdt.nx-1; i++)
1290                {
1291                    vx = x[i];
1292                    vmin = kdt.boxmin[i];
1293                    vmax = kdt.boxmax[i];
1294                    kdt.x[i] = vx;
1295                    kdt.curboxmin[i] = vmin;
1296                    kdt.curboxmax[i] = vmax;
1297                    if( (double)(vx)<(double)(vmin) )
1298                    {
1299                        kdt.curdist = kdt.curdist+AP.Math.Sqr(vmin-vx);
1300                    }
1301                    else
1302                    {
1303                        if( (double)(vx)>(double)(vmax) )
1304                        {
1305                            kdt.curdist = kdt.curdist+AP.Math.Sqr(vx-vmax);
1306                        }
1307                    }
1308                }
1309            }
1310        }
1311
1312
1313        /*************************************************************************
1314        Returns norm_k(x)^k (root-free = faster, but preserves ordering)
1315
1316          -- ALGLIB --
1317             Copyright 28.02.2010 by Bochkanov Sergey
1318        *************************************************************************/
1319        private static double vrootfreenorm(ref double[] x,
1320            int n,
1321            int normtype)
1322        {
1323            double result = 0;
1324            int i = 0;
1325
1326            result = 0;
1327            if( normtype==0 )
1328            {
1329                result = 0;
1330                for(i=0; i<=n-1; i++)
1331                {
1332                    result = Math.Max(result, Math.Abs(x[i]));
1333                }
1334                return result;
1335            }
1336            if( normtype==1 )
1337            {
1338                result = 0;
1339                for(i=0; i<=n-1; i++)
1340                {
1341                    result = result+Math.Abs(x[i]);
1342                }
1343                return result;
1344            }
1345            if( normtype==2 )
1346            {
1347                result = 0;
1348                for(i=0; i<=n-1; i++)
1349                {
1350                    result = result+AP.Math.Sqr(x[i]);
1351                }
1352                return result;
1353            }
1354            return result;
1355        }
1356
1357
1358        /*************************************************************************
1359        Returns norm_k(x)^k (root-free = faster, but preserves ordering)
1360
1361          -- ALGLIB --
1362             Copyright 28.02.2010 by Bochkanov Sergey
1363        *************************************************************************/
1364        private static double vrootfreecomponentnorm(double x,
1365            int normtype)
1366        {
1367            double result = 0;
1368
1369            result = 0;
1370            if( normtype==0 )
1371            {
1372                result = Math.Abs(x);
1373            }
1374            if( normtype==1 )
1375            {
1376                result = Math.Abs(x);
1377            }
1378            if( normtype==2 )
1379            {
1380                result = AP.Math.Sqr(x);
1381            }
1382            return result;
1383        }
1384
1385
1386        /*************************************************************************
1387        Returns range distance: distance from X to [A,B]
1388
1389          -- ALGLIB --
1390             Copyright 28.02.2010 by Bochkanov Sergey
1391        *************************************************************************/
1392        private static double vrangedist(double x,
1393            double a,
1394            double b)
1395        {
1396            double result = 0;
1397
1398            if( (double)(x)<(double)(a) )
1399            {
1400                result = a-x;
1401            }
1402            else
1403            {
1404                if( (double)(x)>(double)(b) )
1405                {
1406                    result = x-b;
1407                }
1408                else
1409                {
1410                    result = 0;
1411                }
1412            }
1413            return result;
1414        }
1415    }
1416}
Note: See TracBrowser for help on using the repository browser.