/*
   File:        kmeans.h
   Author:      Andrew W. Moore
   Created:     Sun Apr  5 11:49:13 EDT 1998
   Description: Kd-tree for simple k-means clustering
   $Id: kmeans.h,v 1.31 2004/01/19 21:11:29 dpelleg Exp $

   Copyright 1998, Carnegie Mellon University
*/


#ifndef KMEANS_H
#define KMEANS_H

#include "hrect.h"
#include "dsut.h"
#include "amiv.h"
#include "utils.h"
#include "amdmex.h"
#include "simple_kdtree.h"
#include "vctr.h"
#include "dyvp_array.h"

typedef enum {MTD_SLOW, MTD_HPLANE, MTD_BLACKLIST, 
			  MTD_BLACKLIST_RANDSTART, MTD_BLACKLIST_APPROX,
			  MTD_BLACKLIST_NOCACHE, MTD_SLOW_WEIGHTED} method;

typedef enum {CACHE_NONE, CACHE_RD_ONLY, CACHE_RDWR} cachemode;

typedef enum {SCORE_BIC, SCORE_AD} split_score_statistic;

typedef struct {
  method mtd;
  double cutoff_factor;
  unsigned short max_iter;
  unsigned short max_secs;
  unsigned short max_ctrs;
  cachemode usecache;			/* how to use kd-node caching */
  bool loop_over_k;				/* whether to loop with different values for k */
  bool delete_ctrs;             /* whether allowed to remove centers */
  split_score_statistic split_statistic; /* how to decide whether to split a center */
  bool maintain_memb;           /* whether the collected statistics should also include a
                                   set of points in each center (needed for
                                   the AD statistic). */

  dyvp_array *data_list;        /* If maintain_memb is true, this is a mapping 
                                   from a point ID, to a dyv * of the point.
                                */

  double split_cutoff;          /* after computing "birth values" for each parent/child
                                   center set, whatever is below this value is actually
                                   split.
                                */
  double split_fraction_if_all_bad; /* if no centers meet the criterion above,
                                       we may force splitting by choosing a cutoff
                                       value and split all centers with birth value less
                                       than it. The goal is to split this fraction of centers.
                                       So if it's 0.5, half the centers will be split.
                                    */

} kmeans_parm;

/* state of kmeans algorithm  */
typedef struct {
  simple_kdtree *kdtree;		/* kdtree for points */
  vctr *current_centers;		/* centers we have now */
  double b_cutoff;				/* current threshold value for aprx searches */
  enum {PHS_UNPHASED, PHS_PARENTS, PHS_CHILDREN
  } phase;						/* for phased search */
  const ivec *phase1_ctrs;		/* parent ctrs for phased search */
} kmeans_state;

/* do K-means, starting with initial_centers.
   if initial_centers is NULL, MAKES new set of centers.
   updates centers (and return them) */
vctr *test_kmeans(simple_kdtree *kd, int k, kmeans_parm *parm, vctr *centers, const int num_dims);

void kmeans(kmeans_state *kmstate, kmeans_parm *parm);

void gen_simple_gaussian_datafile(const char *filename, int num_rows, int num_cols,
								  int num_classes, double sigma, int seed);

void gen_simple_main(int argc,char *argv[]);
void kdtree_main(int argc,char *argv[]);

/* given centers, candidate to ownership over all points in hr, and a competitor 
   to ownership, answer whether competitor thretens candidate's ownership */
bool candidate_is_full_owner(const hrect *hr, const vctr *centers, 
                             int candidate, int competitor);

/* paint all points in x that fall in hr, and return their number */
int paint_points_in_hrect(const dym *data, const hrect *hr);

/* paint all points in kd node */
void paint_points_in_kdnode(const simple_kdtree *kd);

/* print all points in a kd node, and return their number 
   If just_ids, will print the IDs and not the coordinates
*/
int print_points_in_kdtree(FILE *fp, const simple_kdtree *kd, bool just_ids);

/* returns all points in a kd node as a sivec
*/
ivec *mk_sivec_points_in_kdtree(const simple_kdtree *kd);

/* scan only through those centers whose indices are in candidates, return 
   index of one which is closest to point x */ 
int find_closest_candidate(const dyv *x, const ivec *candidates, vctr *centers);

int center_color(int j);

void kmeans_main(int argc,char *argv[]);

dym *mk_dym_from_points_in_kdtree(simple_kdtree *kd, const int ndims);

#endif /* #ifndef KMEANS_H */
