SHOGUN  v3.0.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
JLCoverTree.h
Go to the documentation of this file.
1 #ifndef JLCOVERTREE_H
2 #define JLCOVERTREE_H
3 
6 
7 #include<math.h>
8 #include<stdio.h>
9 #define NDEBUG
10 #include<assert.h>
11 
12 /* First written by John Langford jl@hunch.net
13  Templatization by Dinoj Surendran dinojs@gmail.com
14  Adaptation to Shogun by Fernando José Iglesias García
15 */
16 
17 // the files below may not need to be included
18 
19 /* Whatever structure/class/type is used for P, it must have the following functions defined:
20 
21  float distance(P v1, P v2, float upper_bound);
22  : this returns the distance between two P objects
23  : the distance does not have to be calculated fully if it's more than upper_bound
24 
25  v_array<P> parse_points(char *filename);
26  : this fills up a v_array of P objects from the input file
27 
28  void print(point &P);
29  : this prints out the contents of a P object.
30 */
31 
32 using namespace std;
33 using namespace shogun;
34 
38 template<class P>
39 struct node {
40 
42  P p;
43 
45  float max_dist;
46 
48  float parent_dist;
49 
52 
54  unsigned short int num_children;
55 
57  short int scale;
58 
59 };
60 
61 //template<class P>
62 //node<P> insert(P newpoint, node<P> *top_node); // not yet implemented
63 //
64 //template<class P>
65 //void remove(P byepoint, node<P> *top_node); // not yet implemented
66 //query
67 
71 template<class P>
72 struct ds_node {
73 
76 
78  P p;
79 
80 };
81 
82 static float base = 1.3;
83 
84 
85 static float il2 = 1. / log(base);
86 
87 inline float dist_of_scale (int s)
88 {
89  return CMath::pow(base, s);
90 }
91 
92 inline int get_scale(float d)
93 {
94  return (int) CMath::ceil(il2 * log(d));
95 }
96 
97 template<class P>
98 node<P> new_node(const P &p)
99 {
101  new_node.p = p;
102  return new_node;
103 }
104 
105 template<class P>
106 node<P> new_leaf(const P &p)
107 {
108  node<P> new_leaf = {p,0.,0.,NULL,0,100};
109  return new_leaf;
110 }
111 
112 template<class P>
114 {
115  float max = 0.;
116  for (int i = 0; i < v.index; i++)
117  if ( max < v[i].dist.last())
118  max = v[i].dist.last();
119  return max;
120 }
121 
122 void print_space(int s)
123 {
124  for (int i = 0; i < s; i++)
125  SG_SPRINT(" ")
126 }
127 
128 template<class P>
129 void print(int depth, node<P> &top_node)
130 {
131  print_space(depth);
132  print(top_node.p);
133  if ( top_node.num_children > 0 )
134  {
135  print_space(depth);
136  SG_SPRINT("scale = %i\n",top_node.scale)
137  print_space(depth);
138  SG_SPRINT("max_dist = %f\n",top_node.max_dist)
139  print_space(depth);
140  SG_SPRINT("num children = %i\n",top_node.num_children)
141  for (int i = 0; i < top_node.num_children;i++)
142  print(depth+1, top_node.children[i]);
143  }
144 }
145 
146 template<class P>
147 void split(v_array<ds_node<P> >& point_set, v_array<ds_node<P> >& far_set, int max_scale)
148 {
149  unsigned int new_index = 0;
150  float fmax = dist_of_scale(max_scale);
151  for (int i = 0; i < point_set.index; i++)
152  {
153  if (point_set[i].dist.last() <= fmax)
154  {
155  point_set[new_index++] = point_set[i];
156  }
157  else
158  push(far_set,point_set[i]);
159  }
160  point_set.index=new_index;
161 }
162 
163 template<class P>
164 void dist_split(v_array<ds_node<P> >& point_set,
165  v_array<ds_node<P> >& new_point_set,
166  P new_point,
167  int max_scale)
168 {
169  unsigned int new_index = 0;
170  float fmax = dist_of_scale(max_scale);
171  for(int i = 0; i < point_set.index; i++)
172  {
173  float new_d;
174  new_d = distance(new_point, point_set[i].p, fmax);
175  if (new_d <= fmax )
176  {
177  push(point_set[i].dist, new_d);
178  push(new_point_set,point_set[i]);
179  }
180  else
181  point_set[new_index++] = point_set[i];
182  }
183  point_set.index = new_index;
184 }
185 
186 
187 
188 
189 /*
190  max_scale is the maximum scale of the node we might create here.
191  point_set contains points which are 2*max_scale or less away.
192 */
193 
194 template <class P>
195 node<P> batch_insert(const P& p,
196  int max_scale,
197  int top_scale,
198  v_array<ds_node<P> >& point_set,
199  v_array<ds_node<P> >& consumed_set,
200  v_array<v_array<ds_node<P> > >& stack)
201 {
202  if (point_set.index == 0)
203  return new_leaf(p);
204  else {
205  float max_dist = max_set(point_set); //O(|point_set|)
206  int next_scale = CMath::min(max_scale - 1, get_scale(max_dist));
207  if (next_scale == -2147483647-1) // We have points with distance 0.
208  {
209  v_array<node<P> > children;
210  push(children,new_leaf(p));
211  while (point_set.index > 0)
212  {
213  push(children,new_leaf(point_set.last().p));
214  push(consumed_set,point_set.last());
215  point_set.decr();
216  }
217  node<P> n = new_node(p);
218  n.scale = 100; // A magic number meant to be larger than all scales.
219  n.max_dist = 0;
220  alloc(children,children.index);
221  n.num_children = children.index;
222  n.children = children.elements;
223  return n;
224  }
225  else
226  {
227  v_array<ds_node<P> > far = pop(stack);
228  split(point_set,far,max_scale); //O(|point_set|)
229 
230  node<P> child = batch_insert(p, next_scale, top_scale, point_set, consumed_set, stack);
231 
232  if (point_set.index == 0)
233  {
234  push(stack,point_set);
235  point_set=far;
236  return child;
237  }
238  else {
239  node<P> n = new_node(p);
240  v_array<node<P> > children;
241  push(children, child);
242  v_array<ds_node<P> > new_point_set = pop(stack);
243  v_array<ds_node<P> > new_consumed_set = pop(stack);
244  while (point_set.index != 0) { //O(|point_set| * num_children)
245  P new_point = point_set.last().p;
246  float new_dist = point_set.last().dist.last();
247  push(consumed_set, point_set.last());
248  point_set.decr();
249 
250  dist_split(point_set, new_point_set, new_point, max_scale); //O(|point_saet|)
251  dist_split(far,new_point_set,new_point,max_scale); //O(|far|)
252 
253  node<P> new_child =
254  batch_insert(new_point, next_scale, top_scale, new_point_set, new_consumed_set, stack);
255  new_child.parent_dist = new_dist;
256 
257  push(children, new_child);
258 
259  float fmax = dist_of_scale(max_scale);
260  for(int i = 0; i< new_point_set.index; i++) //O(|new_point_set|)
261  {
262  new_point_set[i].dist.decr();
263  if (new_point_set[i].dist.last() <= fmax)
264  push(point_set, new_point_set[i]);
265  else
266  push(far, new_point_set[i]);
267  }
268  for(int i = 0; i< new_consumed_set.index; i++) //O(|new_point_set|)
269  {
270  new_consumed_set[i].dist.decr();
271  push(consumed_set, new_consumed_set[i]);
272  }
273  new_point_set.index = 0;
274  new_consumed_set.index = 0;
275  }
276  push(stack,new_point_set);
277  push(stack,new_consumed_set);
278  push(stack,point_set);
279  point_set=far;
280  n.scale = top_scale - max_scale;
281  n.max_dist = max_set(consumed_set);
282  alloc(children,children.index);
283  n.num_children = children.index;
284  n.children = children.elements;
285  return n;
286  }
287  }
288  }
289 }
290 
291 template<class P>
293 {
294  assert(points.index > 0);
295  v_array<ds_node<P> > point_set;
296  v_array<v_array<ds_node<P> > > stack;
297 
298  for (int i = 1; i < points.index; i++) {
299  ds_node<P> temp;
300  push(temp.dist, distance(points[0], points[i], FLT_MAX));
301  temp.p = points[i];
302  push(point_set,temp);
303  }
304 
305  v_array<ds_node<P> > consumed_set;
306 
307  float max_dist = max_set(point_set);
308 
309  node<P> top = batch_insert (points[0],
310  get_scale(max_dist),
311  get_scale(max_dist),
312  point_set,
313  consumed_set,
314  stack);
315  for (int i = 0; i<consumed_set.index;i++)
316  free(consumed_set[i].dist.elements);
317  free(consumed_set.elements);
318  for (int i = 0; i<stack.index;i++)
319  free(stack[i].elements);
320  free(stack.elements);
321  free(point_set.elements);
322  return top;
323 }
324 
325 void add_height(int d, v_array<int> &heights)
326 {
327  if (heights.index <= d)
328  for(;heights.index <= d;)
329  push(heights,0);
330  heights[d] = heights[d] + 1;
331 }
332 
333 template <class P>
334 int height_dist(const node<P> top_node,v_array<int> &heights)
335 {
336  if (top_node.num_children == 0)
337  {
338  add_height(0,heights);
339  return 0;
340  }
341  else
342  {
343  int max_v=0;
344  for (int i = 0; i<top_node.num_children ;i++)
345  {
346  int d = height_dist(top_node.children[i], heights);
347  if (d > max_v)
348  max_v = d;
349  }
350  add_height(1 + max_v, heights);
351  return (1 + max_v);
352  }
353 }
354 
355 template <class P>
356 void depth_dist(int top_scale, const node<P> top_node,v_array<int> &depths)
357 {
358  if (top_node.num_children > 0)
359  for (int i = 0; i<top_node.num_children ;i++)
360  {
361  add_height(top_node.scale, depths);
362  depth_dist(top_scale, top_node.children[i], depths);
363  }
364 }
365 
366 template <class P>
367 void breadth_dist(const node<P> top_node,v_array<int> &breadths)
368 {
369  if (top_node.num_children == 0)
370  add_height(0,breadths);
371  else
372  {
373  for (int i = 0; i<top_node.num_children ;i++)
374  breadth_dist(top_node.children[i], breadths);
375  add_height(top_node.num_children, breadths);
376  }
377 }
378 
382 template <class P>
383 struct d_node {
384 
386  float dist;
387 
389  const node<P> *n;
390 };
391 
392 template <class P>
393 inline float compare(const d_node<P> *p1, const d_node<P>* p2)
394 {
395  return p1 -> dist - p2 -> dist;
396 }
397 
398 template <class P>
399 void halfsort (v_array<d_node<P> > cover_set)
400 {
401 
402  if (cover_set.index <= 1)
403  return;
404  register d_node<P> *base_ptr = cover_set.elements;
405 
406  d_node<P> *hi = &base_ptr[cover_set.index - 1];
407  d_node<P> *right_ptr = hi;
408  d_node<P> *left_ptr;
409 
410  while (right_ptr > base_ptr)
411  {
412  d_node<P> *mid = base_ptr + ((hi - base_ptr) >> 1);
413 
414  if (compare ( mid, base_ptr) < 0.)
415  CMath::swap(*mid, *base_ptr);
416  if (compare ( hi, mid) < 0.)
417  CMath::swap(*mid, *hi);
418  else
419  goto jump_over;
420  if (compare ( mid, base_ptr) < 0.)
421  CMath::swap(*mid, *base_ptr);
422  jump_over:;
423 
424  left_ptr = base_ptr + 1;
425  right_ptr = hi - 1;
426 
427  do
428  {
429  while (compare (left_ptr, mid) < 0.)
430  left_ptr ++;
431 
432  while (compare (mid, right_ptr) < 0.)
433  right_ptr --;
434 
435  if (left_ptr < right_ptr)
436  {
437  CMath::swap(*left_ptr, *right_ptr);
438  if (mid == left_ptr)
439  mid = right_ptr;
440  else if (mid == right_ptr)
441  mid = left_ptr;
442  left_ptr ++;
443  right_ptr --;
444  }
445  else if (left_ptr == right_ptr)
446  {
447  left_ptr ++;
448  right_ptr --;
449  break;
450  }
451  }
452  while (left_ptr <= right_ptr);
453 
454  hi = right_ptr;
455  }
456 }
457 
458 
459 template <class P>
461 {
462  v_array<v_array<d_node<P> > > ret = pop(spare_cover_sets);
463  while (ret.index < 101)
464  {
465  v_array<d_node<P> > temp;
466  push(ret, temp);
467  }
468  return ret;
469 }
470 
471 inline bool shell(float parent_query_dist, float child_parent_dist, float upper_bound)
472 {
473  return parent_query_dist - child_parent_dist <= upper_bound;
474  // && child_parent_dist - parent_query_dist <= upper_bound;
475 }
476 
477 int internal_k =1;
478 void update_k(float *k_upper_bound, float upper_bound)
479 {
480  float *end = k_upper_bound + internal_k-1;
481  float *begin = k_upper_bound;
482  for (;end != begin; begin++)
483  {
484  if (upper_bound < *(begin+1))
485  *begin = *(begin+1);
486  else {
487  *begin = upper_bound;
488  break;
489  }
490  }
491  if (end == begin)
492  *begin = upper_bound;
493 }
494 float *alloc_k()
495 {
496  return (float *)malloc(sizeof(float) * internal_k);
497 }
498 void set_k(float* begin, float max)
499 {
500  for(float *end = begin+internal_k;end != begin; begin++)
501  *begin = max;
502 }
503 
505 void update_epsilon(float *upper_bound, float new_dist) {}
507 {
508  return (float *)malloc(sizeof(float));
509 }
510 void set_epsilon(float* begin, float max)
511 {
512  *begin = internal_epsilon;
513 }
514 
515 void update_unequal(float *upper_bound, float new_dist)
516 {
517  if (new_dist != 0.)
518  *upper_bound = new_dist;
519 }
520 float* (*alloc_unequal)() = alloc_epsilon;
521 void set_unequal(float* begin, float max)
522 {
523  *begin = max;
524 }
525 
526 void (*update)(float *foo, float bar) = update_k;
527 void (*setter)(float *foo, float bar) = set_k;
528 float* (*alloc_upper)() = alloc_k;
529 
530 template <class P>
531 inline void copy_zero_set(node<P>* query_chi, float* new_upper_bound,
532  v_array<d_node<P> > &zero_set, v_array<d_node<P> > &new_zero_set)
533 {
534  new_zero_set.index = 0;
535  d_node<P> *end = zero_set.elements + zero_set.index;
536  for (d_node<P> *ele = zero_set.elements; ele != end ; ele++)
537  {
538  float upper_dist = *new_upper_bound + query_chi->max_dist;
539  if (shell(ele->dist, query_chi->parent_dist, upper_dist))
540  {
541  float d = distance(query_chi->p, ele->n->p, upper_dist);
542 
543  if (d <= upper_dist)
544  {
545  if (d < *new_upper_bound)
546  update(new_upper_bound, d);
547  d_node<P> temp = {d, ele->n};
548  push(new_zero_set,temp);
549  }
550  }
551  }
552 }
553 
554 template <class P>
555 inline void copy_cover_sets(node<P>* query_chi, float* new_upper_bound,
556  v_array<v_array<d_node<P> > > &cover_sets,
557  v_array<v_array<d_node<P> > > &new_cover_sets,
558  int current_scale, int max_scale)
559 {
560  for (; current_scale <= max_scale; current_scale++)
561  {
562  d_node<P>* ele = cover_sets[current_scale].elements;
563  d_node<P>* end = cover_sets[current_scale].elements + cover_sets[current_scale].index;
564  for (; ele != end; ele++)
565  {
566  float upper_dist = *new_upper_bound + query_chi->max_dist + ele->n->max_dist;
567  if (shell(ele->dist, query_chi->parent_dist, upper_dist))
568  {
569  float d = distance(query_chi->p, ele->n->p, upper_dist);
570 
571  if (d <= upper_dist)
572  {
573  if (d < *new_upper_bound)
574  update(new_upper_bound,d);
575  d_node<P> temp = {d, ele->n};
576  push(new_cover_sets[current_scale],temp);
577  }
578  }
579  }
580  }
581 }
582 
583 template <class P>
584 void print_query(const node<P> *top_node)
585 {
586  SG_SPRINT ("query = \n")
587  print(top_node->p);
588  if ( top_node->num_children > 0 ) {
589  SG_SPRINT("scale = %i\n",top_node->scale)
590  SG_SPRINT("max_dist = %f\n",top_node->max_dist)
591  SG_SPRINT("num children = %i\n",top_node->num_children)
592  }
593 }
594 
595 template <class P>
597  v_array<d_node<P> > &zero_set,
598  int current_scale, int max_scale)
599 {
600  SG_SPRINT("cover set = \n")
601  for (; current_scale <= max_scale; current_scale++)
602  {
603  d_node<P> *ele = cover_sets[current_scale].elements;
604  d_node<P> *end = cover_sets[current_scale].elements + cover_sets[current_scale].index;
605  SG_SPRINT ("%i\n", current_scale)
606  for (; ele != end; ele++)
607  {
608  node<P> *n = (node<P> *)ele->n;
609  print(n->p);
610  }
611  }
612  d_node<P> *end = zero_set.elements + zero_set.index;
613  SG_SPRINT ("infinity\n")
614  for (d_node<P> *ele = zero_set.elements; ele != end ; ele++)
615  {
616  node<P> *n = (node<P> *)ele->n;
617  print(n->p);
618  }
619 }
620 
621 
622 /*
623  An optimization to consider:
624  Make all distance evaluations occur in descend.
625 
626  Instead of passing a cover_set, pass a stack of cover sets. The
627  last element holds d_nodes with your distance. The next lower
628  element holds a d_node with the distance to your query parent,
629  next = query grand parent, etc..
630 
631  Compute distances in the presence of the tighter upper bound.
632  */
633 
634 template <class P>
635 inline
636 void descend(const node<P>* query, float* upper_bound,
637  int current_scale,
638  int &max_scale, v_array<v_array<d_node<P> > > &cover_sets,
639  v_array<d_node<P> > &zero_set)
640 {
641  d_node<P> *end = cover_sets[current_scale].elements + cover_sets[current_scale].index;
642  for (d_node<P> *parent = cover_sets[current_scale].elements; parent != end; parent++)
643  {
644  const node<P> *par = parent->n;
645  float upper_dist = *upper_bound + query->max_dist + query->max_dist;
646  if (parent->dist <= upper_dist + par->max_dist)
647  {
648  node<P> *chi = par->children;
649  if (parent->dist <= upper_dist + chi->max_dist)
650  {
651  if (chi->num_children > 0)
652  {
653  if (max_scale < chi->scale)
654  max_scale = chi->scale;
655  d_node<P> temp = {parent->dist, chi};
656  push(cover_sets[chi->scale], temp);
657  }
658  else if (parent->dist <= upper_dist)
659  {
660  d_node<P> temp = {parent->dist, chi};
661  push(zero_set, temp);
662  }
663  }
664  node<P> *child_end = par->children + par->num_children;
665  for (chi++; chi != child_end; chi++)
666  {
667  float upper_chi = *upper_bound + chi->max_dist + query->max_dist + query->max_dist;
668  if (shell(parent->dist, chi->parent_dist, upper_chi))
669  {
670  float d = distance(query->p, chi->p, upper_chi);
671  if (d <= upper_chi)
672  {
673  if (d < *upper_bound)
674  update(upper_bound, d);
675  if (chi->num_children > 0)
676  {
677  if (max_scale < chi->scale)
678  max_scale = chi->scale;
679  d_node<P> temp = {d, chi};
680  push(cover_sets[chi->scale],temp);
681  }
682  else
683  if (d <= upper_chi - chi->max_dist)
684  {
685  d_node<P> temp = {d, chi};
686  push(zero_set, temp);
687  }
688  }
689  }
690  }
691  }
692  }
693 }
694 
695 template <class P>
696 void brute_nearest(const node<P>* query,v_array<d_node<P> > zero_set,
697  float* upper_bound,
698  v_array<v_array<P> > &results,
699  v_array<v_array<d_node<P> > > &spare_zero_sets)
700 {
701  if (query->num_children > 0)
702  {
703  v_array<d_node<P> > new_zero_set = pop(spare_zero_sets);
704  node<P> * query_chi = query->children;
705  brute_nearest(query_chi, zero_set, upper_bound, results, spare_zero_sets);
706  float* new_upper_bound = alloc_upper();
707 
708  node<P> *child_end = query->children + query->num_children;
709  for (query_chi++;query_chi != child_end; query_chi++)
710  {
711  setter(new_upper_bound,*upper_bound + query_chi->parent_dist);
712  copy_zero_set(query_chi, new_upper_bound, zero_set, new_zero_set);
713  brute_nearest(query_chi, new_zero_set, new_upper_bound, results, spare_zero_sets);
714  }
715  free (new_upper_bound);
716  new_zero_set.index = 0;
717  push(spare_zero_sets, new_zero_set);
718  }
719  else
720  {
721  v_array<P> temp;
722  push(temp, query->p);
723  d_node<P> *end = zero_set.elements + zero_set.index;
724  for (d_node<P> *ele = zero_set.elements; ele != end ; ele++)
725  if (ele->dist <= *upper_bound)
726  push(temp, ele->n->p);
727  push(results,temp);
728  }
729 }
730 
731 template <class P>
733  v_array<v_array<d_node<P> > > &cover_sets,
734  v_array<d_node<P> > &zero_set,
735  int current_scale,
736  int max_scale,
737  float* upper_bound,
738  v_array<v_array<P> > &results,
739  v_array<v_array<v_array<d_node<P> > > > &spare_cover_sets,
740  v_array<v_array<d_node<P> > > &spare_zero_sets)
741 {
742  if (current_scale > max_scale) // All remaining points are in the zero set.
743  brute_nearest(query, zero_set, upper_bound, results, spare_zero_sets);
744  else
745  if (query->scale <= current_scale && query->scale != 100)
746  // Our query has too much scale. Reduce.
747  {
748  node<P> *query_chi = query->children;
749  v_array<d_node<P> > new_zero_set = pop(spare_zero_sets);
750  v_array<v_array<d_node<P> > > new_cover_sets = get_cover_sets(spare_cover_sets);
751  float* new_upper_bound = alloc_upper();
752 
753  node<P> *child_end = query->children + query->num_children;
754  for (query_chi++; query_chi != child_end; query_chi++)
755  {
756  setter(new_upper_bound,*upper_bound + query_chi->parent_dist);
757  copy_zero_set(query_chi, new_upper_bound, zero_set, new_zero_set);
758  copy_cover_sets(query_chi, new_upper_bound, cover_sets, new_cover_sets,
759  current_scale, max_scale);
760  internal_batch_nearest_neighbor(query_chi, new_cover_sets, new_zero_set,
761  current_scale, max_scale, new_upper_bound,
762  results, spare_cover_sets, spare_zero_sets);
763  }
764  free (new_upper_bound);
765  new_zero_set.index = 0;
766  push(spare_zero_sets, new_zero_set);
767  push(spare_cover_sets, new_cover_sets);
768  internal_batch_nearest_neighbor(query->children, cover_sets, zero_set,
769  current_scale, max_scale, upper_bound, results,
770  spare_cover_sets, spare_zero_sets);
771  }
772  else // reduce cover set scale
773  {
774  halfsort(cover_sets[current_scale]);
775  descend(query, upper_bound, current_scale, max_scale,cover_sets, zero_set);
776  cover_sets[current_scale++].index = 0;
777  internal_batch_nearest_neighbor(query, cover_sets, zero_set,
778  current_scale, max_scale, upper_bound, results,
779  spare_cover_sets, spare_zero_sets);
780  }
781 }
782 
783 template <class P>
784 void batch_nearest_neighbor(const node<P> &top_node, const node<P> &query,
785  v_array<v_array<P> > &results)
786 {
787  v_array<v_array<v_array<d_node<P> > > > spare_cover_sets;
788  v_array<v_array<d_node<P> > > spare_zero_sets;
789 
790  v_array<v_array<d_node<P> > > cover_sets = get_cover_sets(spare_cover_sets);
791  v_array<d_node<P> > zero_set = pop(spare_zero_sets);
792 
793  float* upper_bound = alloc_upper();
794  setter(upper_bound,FLT_MAX);
795 
796  float top_dist = distance(query.p, top_node.p, FLT_MAX);
797  update(upper_bound, top_dist);
798 
799  d_node<P> temp = {top_dist, &top_node};
800  push(cover_sets[0], temp);
801 
802  internal_batch_nearest_neighbor(&query,cover_sets,zero_set,0,0,upper_bound,results,
803  spare_cover_sets,spare_zero_sets);
804 
805  free(upper_bound);
806  push(spare_cover_sets, cover_sets);
807 
808  for (int i = 0; i < spare_cover_sets.index; i++)
809  {
810  v_array<v_array<d_node<P> > > cover_sets2 = spare_cover_sets[i];
811  for (int j = 0; j < cover_sets2.index; j++)
812  free (cover_sets2[j].elements);
813  free(cover_sets2.elements);
814  }
815  free(spare_cover_sets.elements);
816 
817  push(spare_zero_sets, zero_set);
818 
819  for (int i = 0; i < spare_zero_sets.index; i++)
820  free(spare_zero_sets[i].elements);
821  free(spare_zero_sets.elements);
822 }
823 
824 template <class P>
825 void k_nearest_neighbor(const node<P> &top_node, const node<P> &query,
826  v_array<v_array<P> > &results, int k)
827 {
828  internal_k = k;
829  update = update_k;
830  setter = set_k;
832 
833  batch_nearest_neighbor(top_node, query,results);
834 }
835 
836 template <class P>
837 void epsilon_nearest_neighbor(const node<P> &top_node, const node<P> &query,
838  v_array<v_array<P> > &results, float epsilon)
839 {
844 
845  batch_nearest_neighbor(top_node, query,results);
846 }
847 
848 template <class P>
849 void unequal_nearest_neighbor(const node<P> &top_node, const node<P> &query,
850  v_array<v_array<P> > &results)
851 {
855 
856  batch_nearest_neighbor(top_node, query, results);
857 }
858 
859 #endif

SHOGUN Machine Learning Toolbox - Documentation