/*
   File:        cachedinterp.h
   Author:      Weng-Keen Wong
   Created:     Fri Nov 24 20:05:00 EDT 2000
   Description: Lazy N-dimensional function interpolation using cached values

   Copyright (C) 2000, Weng-Keen Wong
*/

#ifndef _CACHEDINTERP_H
#define _CACHEDINTERP_H

#include "hash.h"
#include "stack.h"
#include "hrect.h"

/*
   Terminology:
   1. knot
      A knot is a point at which we do a function evaluation in
      the n-dimensional space.  
   2. knot_index
      A knot_index is an integer value between 0 and the maximum knots 
      allowed for that dimension - 1.  The maximum knots allowed for
      each dimension is stored in the knots_per_dimension ivec of the
      cached interp structure.

      The following example will illustrate knots and knot indexes
      Suppose we have 3 knots in the x-coordinate plane and 5 knots in 
      the y-coordinate plane.   Then the "grid" we place over the
      n-dimensional space looks like:

      *---*---*
      |   |   |
      *---*---*
      |   |   |
      *---*---*
      |   |   |
      *---*---*
      |   |   |
      *---*---*
      
   3. corner
      For each query, there are 2^(num_dims) corners required to do
      the interpolation.  These corners are the corners of the hypercube
      that surround the query point
 */

typedef struct cachedinterp 
{
  int num_dims;
  int cache_size;  
  hrect* bounds;
  ivec* knots_per_dimension;
  hash_table* cache;
  stack* order;      /* FIFO stack to keep track of which elements we remove */
                     /* from the cache when the cache goes beyond its */
                     /* allowable size*/
  int hits;          /* Number of times we access the cache and find what we */
                     /* are looking for */
  int accesses;      /* Number of accesses to the cache */
  bool is_data_copied;
  dym* input;
  dym* output;
} cachedinterp;

typedef double (*cachedinterp_fn)(dyv* query, 
				  dym* input,
				  dym* output,
				  void* data);

/* Makes a cached interp.  An explanation of the arguments is as follows:
   1. cache_size
      The size of the cache used by the cached function interpolator.  The
      bigger the cache_size, the less times the value of a corner needs to be 
      calculated from scratch.  However, the cachedinterp structure eats up
      more memory
   2. bounds
      The bounds of the input space, given as a hrect structure.  
      mk_cachedinterp makes a copy of this hrect.
   3. knots_per_dimension
      An ivec of size equal to the number of dimensions of the input space.
      The ivec contains the number of knots for each dimension.  There must
      be at least 2 knots for each dimension.  mk_cachedinterp makes a copy of
      this ivec.
   4. is_data_copied
      Set to TRUE if you want the cachedinterp structure to copy the input
      and output dyms.  Otherwise, if you're concerned about memory usage,
      set it to FALSE and the pointers to the dyms will be stored.
   5. input
      A matrix of input values (values taken from the domain of the function 
      you want to interpolate).
   6. output
      A matrix of output values (values taken from the range of the function
      you want to interpolate), corresponding to the input values.
      */
cachedinterp* mk_cachedinterp(int cache_size,
			      hrect* bounds,
			      ivec* knots_per_dimension,
			      bool is_data_copied,
			      dym* input,
			      dym* output);

/* 
   Frees the cachedinterp structure.  Note that if the is_data_copied field
   is set to TRUE, the input and output dyms are freed.  Otherwise, they
   are not and the fields are just NULLed out
 */
void free_cachedinterp(cachedinterp* ci);


/*
   Obtains the value of the query point using lazy cached function 
   interpolation.
 */
double cachedinterp_eval(cachedinterp* ci,
			 cachedinterp_fn fn,
			 dyv* query,
			 void* data);

/*
    Translates a knot index to the actual coordinate value for a given
    dimension
 */
double cachedinterp_knot_index_to_coord(cachedinterp* ci,
					int dim,
					int knot_index);

/*
   Returns the number of knots in a particular dimension
 */
int cachedinterp_num_knots(cachedinterp* ci, int dim);

/*
   Prints the hit ratio for the cached
 */
void cachedinterp_fprintf_hit_ratio(FILE* fp, cachedinterp* ci);

hrect* cachedinterp_get_bounds(cachedinterp* ci);

#endif





