/*
   File:        vctr.h
   Author:      Andrew W. Moore, Dan Pelleg
   Created:     Sun Apr  5 11:49:13 EDT 1998
   Description: "virtual centers" ADT for write-once dyv's
   $Id: vctr.h,v 1.11 2000/04/27 16:33:43 dpelleg Exp $

   Copyright 1999, Carnegie Mellon University
*/


#ifndef VCTR_H
#define VCTR_H

#include "amiv.h"
#include "amdmex.h"

#define VCTR_NCHILDREN (2)

typedef struct vctr_struct
{
  /* arrays indexed by "physical" indices: */
  dyv_array *pctr;				/* center coordinates */
  ivec *child[VCTR_NCHILDREN];	/* in child[j][i], store virtual index of j-th child of ctr i */
								/* child[0][i] holds DEAD value for inactive ctrs */
								/* child[0][i] holds ZOMBIE value for resurrectable ctrs */
  ivec *parent;					/* holds the (physical) parent of ctr i or NOPARENT */

  /* this is the only array indexed by "virtual" indices */
  ivec *pidx;					/* virtual-to-physical mapping */

  ivec *freelist;				/* free-for-use indices in pctr */
  int nfree;					/* number of items in freelist, indexed 0..nfree-1 */
  int nzombies;					/* num of resurrectable ctrs */
  int ndims;
} vctr, *vctr_ptr;

/* create an empty set of centers */
vctr *mk_empty_vctr(int ndims);

/* create a set of centers from a file */
vctr *mk_vctr_from_filename(const char *filename);

/* save a set of centers to a file */
void save_vctr_to_filename(const vctr *obj, const char *filename);

/* add a new ctr to list, return its virtual index
   logprob, sigsqd of new ctr set to 0 and 1 */
int add_to_vctr(vctr *obj, const dyv *ctr);

/* create a new center to replace ctr idx, with coordinate new_loc.
   return the movement magnitude (dyv_magnitude(new_loc - curr_loc))
   note that a parent of idx will point to the new ctr
   logprob of new center is set to new_logprob
   sigsqd of new center is set to new_sigsqd
*/
double move_vctr(vctr *obj, int idx, dyv *new_loc, double new_logprob, double new_sigsqd);

/* invalidate the center with the given index */
/* if kill_children, all zombie children it may have are killed */
void remove_from_vctr(vctr *obj, int idx, bool kill_children);

/* move all children of the center with the given index to a zombie state */
void remove_children_from_vctr(vctr *obj, int parent);

/* add new vctrs as in *children, and mark the center "parent" to be their parent 
 logprob, sigsqd of new centers set to 0 and 1
*/
void vctr_give_birth(vctr *obj, int parent, const dyv_array *children);

/* true iff center had children and was passed to remove_children_from_vctr */
bool has_dead_children(const vctr *obj, int parent);

/* if has_dead_children, brings them back to life */
void resurrect_children(vctr *obj, int parent);

#ifdef AMFAST

#define vctr_ref(obj,i) (dyv_array_ref(obj->pctr, ivec_ref(obj->pidx, i)))
#define vctr_pidx(obj, i) (ivec_ref(obj->pidx, i))
#define is_zombie(obj, i) (ivec_ref(obj->child[0], vctr_pidx(obj, i)) == ZOMBIE)
#define vctr_logprob_ref(obj, i) (dyv_ref(obj->logprob, ivec_ref(obj->pidx, i)))
#define vctr_logprob_set(obj, i, v) (dyv_set(obj->logprob, ivec_ref(obj->pidx, i), v))
#define vctr_sigsqd_ref(obj, i) (dyv_ref(obj->sigsqd, ivec_ref(obj->pidx, i)))
#define vctr_sigsqd_set(obj, i, v) (dyv_set(obj->sigsqd, ivec_ref(obj->pidx, i), v))

#else

/* return ref to ctr #index */
dyv *safe_vctr_ref(const vctr *obj, int index);
#define vctr_ref(obj,i) (safe_vctr_ref(obj, i))
/* return a "physical" index for a virtual center 
   at any given time, guaranteed that every live virtual has a distinct
   physical index. Once that center is invalidated, the physical index means nothing.
   In addition, physical indices may have smaller values than virtual ones
*/
int safe_vctr_pidx(const vctr *obj, int idx);
#define vctr_pidx(obj,i) (safe_vctr_pidx(obj, i))

bool safe_is_zombie(const vctr *obj, int idx);
#define is_zombie(obj, i) (safe_is_zombie(obj, i))

#endif /* AMFAST */

/* make and return the ivec with the sorted indices of the children of ctr parent */
ivec *mk_vctr_children(const vctr *obj, int parent);

/* return largest possible physical index for current set of live centers */
int vctr_max_pidx(const vctr *);

/* return #of live centers */
int vctr_live_size(const vctr *);

/* return indices of all live centers as a sivec */
ivec *mk_live_ctrs(const vctr *);

/* The next funcs are used to enumerate the live centers. Order is unspecified.
   You should NOT enumerate elements across func-calls that change
   the set of live centers.*/
int get_first_live_vctr(const vctr *);
int get_next_live_vctr(const vctr *obj, int prev);
bool is_valid_vctr(const vctr *obj, int idx);

/* print coordinates of live centers */
void fprintf_vctr(FILE *s, char *m1, vctr *obj, char *m2);

/* print probabilities (=exp(logprob)) of live centers */
void fprintf_vctr_logprob(FILE *s, char *m1, vctr *obj, char *m2);

/* print out *everthing* */
void fprintf_vctr_full(FILE *s, char *m1, vctr *obj, char *m2);

/* create an return a duplicate */
vctr *mk_copy_vctr(const vctr *other);

void free_vctr(vctr *obj);

#endif /* #ifndef VCTR_H */
