/*
   File:        simple_kdtree.h
   Author:      Andrew W. Moore
   Created:     Sun Apr  5 11:49:13 EDT 1998
   Description: Header for Kd-tree

   Copyright 1998, Carnegie Mellon University
*/


#ifndef SIMPLE_KDTREE_H
#define SIMPLE_KDTREE_H

#include "hrect.h"
#include "amiv.h"
#include "utils.h"
#include "amdmex.h"
#include "dsut.h"

#define KDTREE_NO_POINT (-1)

#ifdef DEBUGGING_FREEDYVS
#define free_dyv(D) { printf("%s\n", __FUNCTION__); free_dyv(D); }
#endif /* DEBUGGING_FREEDYVS */

struct cached_stats;

typedef struct simple_kdtree {
  /* these values make sense for non-leaves only */
  int split_dim;
  double split_val;
  struct simple_kdtree *left;
  struct simple_kdtree *right;
  
  /* these always make sense */
  int num_points;
  dyv *sum;						/* sum of points in tree rooted here */
  double sum_mags;				/* sum of magnitues of points in tree rooted here */
  hrect *hr;					/* hrect bounding these points */
  double rel_width;				/* at widest dimension. universal node = 1.0 */
  double bias;					/* some measure of error, TBA */
  
  struct cached_stats *cached;	/* NULL or points to stats found at earlier time */

  /* these values make sense for leaves only */
  dyv_array *points;			/* elems in data which are contained in this leaf */
  ivec *point_ids;              /* matching indices with points, with the "serial number"
                                   (in the input file) of each point  */
} simple_kdtree;

int kd_num_nodes(simple_kdtree *kd);

int kd_num_dims(const simple_kdtree *kd); /* may be expensive */

/* min_box_width_rel is as fraction of width of pts in x in each dimension */
simple_kdtree *mk_simple_kdtree(const dyv_array *x, double min_box_width_rel, int max_leaf_size);

/* min_box_width is a relative value (relative to universe) */
simple_kdtree *mk_simple_kdtree_basic(const dyv_array *points, const ivec *point_ids,
                                      const dyv *universe,
									  double min_box_width_rel,
									  int max_leaf_size);

void make_simple_left_and_right_points(const dyv_array *points, const ivec *point_ids,
                                       int split_dim,
									   double split_val,
									   dyv_array **left, dyv_array **right,
                                       ivec **left_ids, ivec **right_ids);

typedef struct {
  int left, right;
} lrsize;

lrsize make_left_and_right_points(const dyv_array *points, const ivec *point_ids, 
                                  int npoints_in_points,
								  int split_dim, double split_val,
                                  dyv_array **left, dyv_array **right,
                                  ivec **left_ids, ivec **right_ids,
                                  int prealloc_size);

lrsize get_left_and_right_sizes(const dyv_array *points, int npoints_in_points,
                                int split_dim, double split_val);

void free_simple_kdtree(simple_kdtree *kd);

bool is_kd_leaf(const simple_kdtree *node);

unsigned long simple_kdtree_size(simple_kdtree *node);

/* return distance from point to closest point in/on surface of hr to it */
/* work is a dyv the size of point which can be used for scratch area */
double dsqd_hrect_point(const hrect *hr, const dyv *point, dyv *work);

/* given centers, candidate to ownership over all points in hr, and a competitor 
   to ownership, answer whether competitor thretens candidate's ownership */

/* scale all values to be in [0,1] by columns */
dym *mk_scaledx_from_x(dym *x);

/* rows may be NULL dneoting "use all rows" */
double sum_mags_of_dym_rows(dym *dm,ivec *rows);

double sum_mags_of_dyv_array(const dyv_array *da);

void blacklist_update_error(dym *data, simple_kdtree *node, dyv_array *centers,
							ivec *candidates, double *error);

void fprint_simple_kdtree(FILE *s, const char *m1, const char *m2, const simple_kdtree *kd);
dyv_array *mk_dyv_array_of_zeroes(int array_size,int dyv_size);

ivec *mk_random_subset_of_ints(int n,int size);

void draw_simple_kdtree(const simple_kdtree *kd, int min_depth, int max_depth);

void draw_simple_x(dym *x);

/* Draws all the rows in x mentioned in "rows" but no others */
void draw_x_simple_sample(dym *x,ivec *rows);

/* debug level directives */
enum {D_SHOWCOUNTERS, D_TRACE, D_INTERACTIVE,
	  D_SHOW_START_CENTERS, D_SHOW_END_CENTERS,
	  D_SHOW_RUNNING_CENTERS, D_SHOWDATA, D_DRAWPOINTS,
	  D_DRAW_END_CENTERS, D_PASSES,
	  D_SHOW_LKLIHOOD, D_VCTR, D_KDCACHE, D_SHOW_BVALUE,
	  D_EXTRA, D_PRINTCLUSTERS,
      D_DELETE_CTRS
};

extern const char *const DEBUG_FLAG_NAMES_SIMPLE_KDTREE[];

#endif /* #ifndef SIMPLE_KDTREE_H */
