#ifndef RSPL_H
#define RSPL_H

/* 
 * Argyll Color Management System
 * Multi-dimensional regularized spline data structure
 *
 * Author: Graeme W. Gill
 * Date:   2000/10/29
 *
 * Copyright 1996 - 2004 Graeme W. Gill
 * All rights reserved.
 *
 * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
 * see the License.txt file for licencing details.
 */

#include "numsup.h"

/** Configuration **/

#undef CHECK_NNLU		/* [und] Check nn lookup results against exaustive searches */
						/*       as well as other asserts. */

/** General Limits **/

#define MXDI 10				/* Maximum input dimensionality */
#define MXDO 10				/* Maximum output dimensionality (Is not fully tested!!!) */
#define LOG2MXDI 4			/* log2 MXDI */
#define DEF2MXDI 16			/* Default allocation size for 2^di (di=4) */
#define POW2MXDI 1024		/* 2 ^ MXDI */
#define DEF3MXDI 81			/* Default allocation size for 3^di (di=4) */
#define POW3MXDI 59049		/* 3 ^ MXDI */
#define HACOMPS ((POW3MXDI + 2 * MXDI + 1)/2) /* Maximum number of array components */
							/* 295255 - not used ? */

#if MXDI > MXDO		/* Maximum of either DI or DO */
# define MXDIDO MXDI
#else
# define MXDIDO MXDO
#endif

/* RESTRICTED SIZE Limits, used for reverse and spline */

#define MXRI 4			/* Maximum input dimensionality */
#define MXRO 10			/* Maximum output dimensionality (Is not fully tested!!!) */
#define LOG2MXRI 2		/* log2 MXRI */
#define POW2MXRI 16		/* 2 ^ MXRI */
#define POW3MXRI 81		/* 3 ^ MXRI */
#define POW2MXRO 1024	/* 2 ^ MXRO */

#if MXRI > MXRO		/* Maximum of either RI or RO */
# define MXRIRO MXRI
#else
# define MXRIRO MXRO
#endif


/** Definitions **/

/* General data point position/value structure */
/* This is mean't to be compatible with color structure */
/* when MXDI and MXDO == 4 */
typedef double datai[MXDI];
typedef double datao[MXDO];
typedef float dati[MXDI];
typedef float dato[MXDO];

/* Restricted size versions */
typedef double ratai[MXRI];
typedef double ratao[MXRO];
typedef float rati[MXRI];
typedef float rato[MXRO];

/* Interface coordinate value */
typedef struct {
	double p[MXDI];		/* coordinate position */
	double v[MXDO];		/* function values */
} co;

/* Interface coordinate value + weighting */
typedef struct {
	double p[MXDI];		/* coordinate position */
	double v[MXDO];		/* function values */
	double w;			/* Weight to give this point, nominally 1.0 */ 
} cow;

/* Interface coordinate value + per out component weighting */
typedef struct {
	double p[MXDI];		/* coordinate position */
	double v[MXDO];		/* function values */
	double w[MXDO];		/* Weight to give this point, nominally 1.0 */ 
} coww;

/* Scattered data Per data point data (internal) */
struct _rpnts {
	double p[MXDI];		/* Data position [di] */
	double v[MXDO];		/* Data value    [fdi] */
	double k[MXDO];		/* Weight factor (nominally 1.0, less for lower confidence data point) */
//	double fe;			/* Fit error in output pass (ausm) */
}; typedef struct _rpnts rpnts;

/* Hermite interpolation magic data */
typedef struct {
	int p;			/* The parameter power combination */
	int i;			/* The surrounding cube vertex index */
	int j;			/* The dimension combination */
	float wgt;
} magic_data;

#include "rev.h"			/* Reverse interpolation defintions */
#include "gam.h"			/* Gamut defintions */

/* Sub-fit itteration information */
typedef struct {
	int niters;		/* Number of multigrid itterations needed */
	int **ires; 	/* Resolution for each itteration and dimension */
	void **mgtmps[MXDO]; /* Store pointers to re-usable mgtmp when incremental */
					/* (These don't seem to be used anymore. was incremental removed ?) */
} it_info;

/* Structure for final resolution multi-dimensional regularized spline data */
struct _rspl {

	/* Global rspl state */
	int debug;		/* 0 = no debug */
	int verbose;	/* 0 = no verbose */
	double smooth;	/* Smoothness factor */
	double avgdev[MXDO];
	                /* Average Deviation of function values as proportion of function range. */
	int symdom;		/* 0 = non-symetric smoothness with different grid resolutions, */
	           		/* 1 = symetric smoothness with different grid resolutions, */

	int di;			/* Input dimensionality */
	int fdi;		/* Output function dimensionality */

	/* Weak default function related information */
	double weak;	/* Weak total weighting, nominal = 1.0 */
	void *dfctx;	/* Opaque function context */
	void (*dfunc)(void *cbntx, double *out, double *in);
					/* Function to set from */

	/* Scattered Data point related information */
	int ausm;		/* Automatic smoothing enabled flag. */
	struct {
		int no;			/* Number of data points in array */
		rpnts *a;		/* Array of data points */
		datao vl, vw;	/* Data value low/width - not used */
		datao va;		/* Data value averages */
//		double fea;		/* Fit error average */
	} d;
	
	it_info ii;		/* Main itteration information for final rspl */

	it_info as_ii;		/* Automatic smoothing pre-fit itteration info */
	it_info asm_ii;		/* Automatic smoothing map itteration info */

	/* Grid points data */
	struct {
		int res[MXDI];	/* Single dimension grid resolution for each axis */
		int bres, brix;	/* Biggest resolution and its index */
		double mres;	/* Geometric mean res[] */
		int no;			/* Total number of points in grid = res[0] * res[1] * .. res[di-1] */
		datai l,h,w;	/* Grid low, high, grid cell width */
						/* This is used to map from the input domain to the grid */

		datao fmin, fmax;	/* Min & max values of grid output (function) variables */
		int fminx[MXDO], fmaxx[MXDO];	/* Grid indexes of points that set min/max output values */
		double fscale;		/* Overall magnitude of output values */
		double *ipos[MXDI]; /* Optional relative grid cell position for each input dim cell, */
						/* gres[] entries per dimension. Allows for the possibility of */
						/* a non-uniform grid spacing, by adjusting the curvature evaluation */
						/* appropriately. */
		int fminmax_valid;	/* Min/max/scale cached values valid flag. */
		int limitv_cached;	/* Flag: Ink limit values have been set in the grid array */

#define G_XTRA 3		/* Extra floats per grid point */
		float *alloc;	/* Grid points allocated address */
		float *a;		/* Grid point flags + data */
						/* Array is res[] ^ di entries float[fdi+G_XTRA], offset by G_XTRA */
						/* (But is expanded when spline interpolaton is active) */
						/* float[-1] contains the ink limit function value, L_UNINIT if not initd */
						/* float[-2] contains the edge flag values, 3 bits per in dim. */
						/* float[-3] contains the touched flag generation count. */
						/* (k value for non-linear fit would be another entry.) */
						/* Flag values are 3 bits for each dimension. Bits 1,0 form */
						/* 2 bit distance from edge: 0 for on edge of grid, */
	                    /* 1 for next row, 2 for 3rd row and beyond. If bit 2 is set, */
						/* then we are on the lower edge. This limits di to 10 or less, */
						/* with the two MS bits spare. */
		int pss;		/* Grid point structure size = fdi+G_XTRA */

		/* Uninitialised limit value */
#define L_UNINIT ((float)-1e38)

#define FL_BITS 3	/* flag bits per dimension */
		/* Macros to access flags. Arguments are a pointer to base grid point and  */
		/* Flag value is distance from edge in bottom 2 bits, values 0, 1 or 2 maximum. */
		/* bit 2 is set if the distance is to the lower edge. ie: */
		/* 0 = at top edge */
		/* 1 = next to top edge */
		/* 2, 6 = not at or next to any edge */
		/* 4 = at bottom edge */
		/* 5 = next to bottom edge */
#define FLV(fp) (*((unsigned int *)((fp)-2)))
		/* Init the flag values to 0 */
#define I_FL(fp) (FLV(fp) = 0)
		/* Return 3 bit flag data */
#define G_FL(fp,di) ((FLV(fp) >> (3 * (di))) & 7)
		/* Set 3 bit flag data */
#define S_FL(fp,di,v) (FLV(fp) = (FLV(fp) & ~(7 << (3 * (di)))) | (((v) & 7) << (3 * (di))))

		/* Macro to access touched flag. Arguments are a pointer to base grid point. */
#define TOUCHF(fp) (*((unsigned int *)((fp)-3)))

		/* Grid array offset lookups - in floats */
		int ci[MXDI];		/* Grid coordinate increments for each dimension */
		int fci[MXDI];		/* Grid coordinate increments for each dimension in floats */
		int *hi;			/* 2^di Combination offset for sequence through cube. */
		int a_hi[DEF2MXDI];	/* Default allocation for *hi */
		int *fhi;			/* Combination offset for sequence through cube of */
							/* 2^di points, starting at base, in floats */
		int a_fhi[DEF2MXDI];/* Default allocation for *hi */

		unsigned int touch;	/* Cell touched flag count */
	} g;


	/* Ink limit related information */
	int limiten;		/* Flag - limiting is enabled */
	double (*limitf)(void *cntx, double *in);	/* Optional input space qualifier function. */
	void *lcntx;		/* Context passed to limit() */
	double limitv;		/* Value not to be exceeded by limit() */

	/* Hermite spline interpolation support */
	struct {
		magic_data *magic;	/* Magic matrix - non-zero elements only, Non-NULL if splining */
		int nm;			/* number in magic data list */
		int spline;		/* Non-zero if spline data is present in g.a */
						/* Changes from float g.a[res ^ di][fdi+G_XTRA], offset by G_XTRA, */
						/* to float g.a[res ^ di][(2^di * fdi)+G_XTRA], offset by G_XTRA, */
	} spline;

	/* Gamut support */
	gam_struct gam;		/* See gam.h */

	/* Reverse Interpolation support */
	rev_struct rev;		/* See rev.h */

	/* Methods */

	/* Free ourselves */
	void (*del)(struct _rspl *ss);

	/* Combination lags used by various functions */
#define RSPL_NOFLAGS      0x0000
#define RSPL_AUTOSMOOTH   0x0001	/* Automatically determin local optimal avgdev smoothing */
#define RSPL_SYMDOMAIN    0x0004	/* Maintain symetric smoothness with nonsym. resolution */
#define RSPL_SET_APXLS    0x0020	/* For set_rspl, adjust samples for aproximate least squares */
#define RSPL_FASTREVSETUP 0x0010	/* Do a fast reverse setup at the cost of subsequent speed */
#define RSPL_VERBOSE      0x8000	/* Turn on print progress messages */
#define RSPL_NOVERBOSE    0x4000	/* Turn off print progress messages */

	/* Initialise from scattered data. */
	/* Return non-zero if result is non-monotonic */
	int
	(*fit_rspl)(
		struct _rspl *s,	/* this */
		int flags,		/* Combination of flags */
		co *d,			/* Array holding position and function values of data points */
		int ndp,		/* Number of data points */
		datai glow,		/* Grid low scale - will expand to enclose data, NULL = default 0.0 */
		datai ghigh,	/* Grid high scale - will expand to enclose data, NULL = default 1.0 */
		int gres[MXDI],	/* Spline grid resolution, ncells = gres-1 */
		datao vlow,		/* Data value low normalize, NULL = default 0.0 */
		datao vhigh,	/* Data value high normalize - NULL = default 1.0 */
		double smooth,	/* Smoothing factor, 0.0 = default 1.0 */
		double avgdev[MXDO],
		                /* Average Deviation of function values as proportion of function range, */
						/* typical value 0.005 (aprox. = 0.564 times the standard deviation) */
						/* NULL = default 0.005 */
		double *ipos[MXDI] /* Optional relative grid cell position for each input dim cell, */
						/* gres[] entries per dimension. Used to scale smoothness criteria */
	); 

	/* Initialise from scattered data, with per point weighting. */
	/* Return non-zero if result is non-monotonic */
	int
	(*fit_rspl_w)(
		struct _rspl *s,	/* this */
		int flags,		/* Combination of flags */
		cow *d,			/* Array holding position, function and weight values of data points */
		int ndp,		/* Number of data points */
		datai glow,		/* Grid low scale - will expand to enclose data, NULL = default 0.0 */
		datai ghigh,	/* Grid high scale - will expand to enclose data, NULL = default 1.0 */
		int gres[MXDI],	/* Spline grid resolution, ncells = gres-1 */
		datao vlow,		/* Data value low normalize, NULL = default 0.0 */
		datao vhigh,	/* Data value high normalize - NULL = default 1.0 */
		double smooth,	/* Smoothing factor, 0.0 = default 1.0 */
		double avgdev[MXDO],
		                /* Average Deviation of function values as proportion of function range, */
						/* typical value 0.005 (aprox. = 0.564 times the standard deviation) */
						/* NULL = default 0.005 */
		double *ipos[MXDI] /* Optional relative grid cell position for each input dim cell, */
						/* gres[] entries per dimension. Used to scale smoothness criteria */
	);

	/* Initialise from scattered data, with per point individual out weighting. */
	/* Return non-zero if result is non-monotonic */
	int
	(*fit_rspl_ww)(
		struct _rspl *s,	/* this */
		int flags,		/* Combination of flags */
		coww *d,		/* Array holding position, function and weight values of data points */
		int ndp,		/* Number of data points */
		datai glow,		/* Grid low scale - will expand to enclose data, NULL = default 0.0 */
		datai ghigh,	/* Grid high scale - will expand to enclose data, NULL = default 1.0 */
		int gres[MXDI],	/* Spline grid resolution, ncells = gres-1 */
		datao vlow,		/* Data value low normalize, NULL = default 0.0 */
		datao vhigh,	/* Data value high normalize - NULL = default 1.0 */
		double smooth,	/* Smoothing factor, 0.0 = default 1.0 */
		double avgdev[MXDO],
		                /* Average Deviation of function values as proportion of function range, */
						/* typical value 0.005 (aprox. = 0.564 times the standard deviation) */
						/* NULL = default 0.005 */
		double *ipos[MXDI] /* Optional relative grid cell position for each input dim cell, */
						/* gres[] entries per dimension. Used to scale smoothness criteria */
	);

	/* Initialise from scattered data, with weak default function. */
	/* Return non-zero if result is non-monotonic */
	int
	(*fit_rspl_df)(
		struct _rspl *s,	/* this */
		int flags,		/* Combination of flags */
		co *d,			/* Array holding position and function values of data points */
		int ndp,		/* Number of data points */
		datai glow,		/* Grid low scale - will expand to enclose data, NULL = default 0.0 */
		datai ghigh,	/* Grid high scale - will expand to enclose data, NULL = default 1.0 */
		int gres[MXDI],	/* Spline grid resolution, ncells = gres-1 */
		datao vlow,		/* Data value low normalize, NULL = default 0.0 */
		datao vhigh,	/* Data value high normalize - NULL = default 1.0 */
		double smooth,	/* Smoothing factor, 0.0 = default 1.0 */
		double avgdev[MXDO],
		                /* Average Deviation of function values as proportion of function range, */
						/* typical value 0.005 (aprox. = 0.564 times the standard deviation) */
						/* NULL = default 0.005 */
		double *ipos[MXDI],/* Optional relative grid cell position for each input dim cell, */
						/* gres[] entries per dimension. Used to scale smoothness criteria */
		double weak,	/* Weak weighting, nominal = 1.0 */
		void *cbntx,	/* Opaque function context */
		void (*func)(void *cbntx, double *out, double *in)		/* Function to set from */
	);

	/* Initialise from scattered data, with per point weighting and weak default function. */
	/* Return non-zero if result is non-monotonic */
	int
	(*fit_rspl_w_df)(
		struct _rspl *s,	/* this */
		int flags,		/* Combination of flags */
		cow *d,			/* Array holding position, function and weight values of data points */
		int ndp,		/* Number of data points */
		datai glow,		/* Grid low scale - will expand to enclose data, NULL = default 0.0 */
		datai ghigh,	/* Grid high scale - will expand to enclose data, NULL = default 1.0 */
		int gres[MXDI],	/* Spline grid resolution, ncells = gres-1 */
		datao vlow,		/* Data value low normalize, NULL = default 0.0 */
		datao vhigh,	/* Data value high normalize - NULL = default 1.0 */
		double smooth,	/* Smoothing factor, 0.0 = default 1.0 */
		double avgdev[MXDO],
		                /* Average Deviation of function values as proportion of function range, */
						/* typical value 0.005 (aprox. = 0.564 times the standard deviation) */
						/* NULL = default 0.005 */
		double *ipos[MXDI],/* Optional relative grid cell position for each input dim cell, */
						/* gres[] entries per dimension. Used to scale smoothness criteria */
		double weak,	/* Weak weighting, nominal = 1.0 */
		void *cbntx,	/* Opaque function context */
		void (*func)(void *cbntx, double *out, double *in)		/* Function to set from */
	);

	/* Initialize the grid from a provided function. By default the grid */
	/* values are set to exactly the value returned by func(), unless the */
	/* RSPL_SET_APXLS flag is set, in which case an attempt is made to have */
	/* the grid points represent a least squares aproximation to the underlying */
	/* surface. */
	/* Grid index values are supplied "under" in[] at *((int*)&in[-e-1]) */
	/* Return non-monotonic status */
	int
	(*set_rspl)(
		struct _rspl *s,	/* this */
		int flags,		/* Combination of flags */
		void *cbntx,	/* Opaque function context */
		void (*func)(void *cbntx, double *out, double *in),		/* Function to set from */
		datai glow,		/* Grid low scale - will expand to enclose data, NULL = default 0.0 */
		datai ghigh,	/* Grid high scale - will expand to enclose data, NULL = default 1.0 */
		int gres[MXDI],	/* Spline grid resolution */
		datao vlow,		/* Data value low normalize, NULL = default 0.0 */
		datao vhigh		/* Data value high normalize - NULL = default 1.0 */
	);

	/* Re-set values from a function. Grid index values are supplied */
	/* "under" in[] at *((int*)&iv[-e-1]) */
	/* Return non-monotonic status. Clears all the reverse lookup information. */
	/* It is assumed that the output range remains unchanged. */
	/* Existing output values are supplied in out[] */
	int
	(*re_set_rspl)(
		struct _rspl *s,/* this */
		int flags,		/* Combination of flags (not used) */
		void *cbntx,	/* Opaque function context */
		void (*func)(void *cbntx, double *out, double *in) /* Function to set from */
	);

	/* Scan the rspl grid point locations and values. Grid index values are */
	/* supplied "under" in[] at *((int*)&iv[-e-1]) */
	/* Return non-monotonic status. */
	void
	(*scan_rspl)(
		struct _rspl *s,	/* this */
		int flags,			/* Combination of flags (not used) */
		void *cbntx,		/* Opaque function context */
		void (*func)(void *cbntx, double *out, double *in) /* Function that gets given values */
	);

	/* Tune a single value. */
	/* Return 0 on success, 1 if input clipping occured, 2 if output clipping occured */
	int (*tune_value) (
		struct _rspl *s,				/* Pointer to Lut object */
		co *p							/* Target value */
	);

	/* Set values by multi-grid optimisation using the provided function. */
	int (*opt_rspl)(
		struct _rspl *s,/* this */
		int flags,		/* Combination of flags */
		int tdi,		/* Dimensionality of target data */
		int adi,		/* Additional grid point data allowance */
		double **vdata,	/* di^2 array of function, target and additional values to init */
						/* array corners with. */
		double (*func)(void *fdata, double *inout, double *surav, int first, double *cw),
						/* Optimisation function */
		void *fdata,	/* Opaque data needed by function */
		datai glow,		/* Grid low scale - NULL = default 0.0 */
		datai ghigh,	/* Grid high scale - NULL = default 1.0 */
		int gres[MXDI],	/* Spline grid resolution */
		datao vlow,		/* Data value low normalize - NULL = default 0.0 */
		datao vhigh		/* Data value high normalize - NULL = default 1.0 */
	);

	/* Filter the existing values using the surrounding 3x3 cells. */
	/* Grid index values are supplied "under" in[] */
	void
	(*filter_rspl)(
		struct _rspl *s,	/* this */
		int flags,			/* Combination of flags (not used) */
		void *cbntx,		/* Opaque function context */
		void (*func)(void *cbntx, float **out, double *in, int cvi) /* Function to set from */
	);

	/* Do forward interpolation */
	/* Return 0 if OK, 1 if input was clipped to grid */
	int (*interp)(
		struct _rspl *s,	/* this */
		co *p);				/* Input and output values */

	/* Do forward 1d interpolation of and return the value. */
	double (*interp1)(		/* Return value */
		struct _rspl *s,	/* this */
		double in);			/* Input value */

	/* Do forward (partial) interpolation to allow input & output curves to be applied, */
	/* and allow input delta E to be estimated from output delta E. */
	/* Call with input value in p1[0].p[], */
	/* In order smallest to largest weight: */
	/* Return di+1 vertex values in p1[]].v[] and */
	/* 0-1 sub-cell weight values as (p1[].p[0] - p1[].p[1]). */
	/* Optionally in input channel order: */
	/* Returns di+1 partial derivatives + base value in p2[].v[], */
	/* with matching weight values for each in p2[].p[0] (last weight = 1)*/
	/* Return 0 if OK, 1 if input was clipped to grid */
	int (*part_interp)(
		struct _rspl *s,	/* this */
		co *p1,
		co *p2);			/* optional - return partial derivatives for each input channel */

	/* Do splined forward interpolation. RESTRICTED SIZE */
	/* Return 0 if OK, 1 if input was clipped to grid */
	int (*spline_interp)(
		struct _rspl *s,	/* this */
		co *p);				/* Input and output values */


	/* ------------------------------- */
	/* Create a surface gamut representation. */
	/* Return NZ on error */
	int (*comp_gamut)(struct _rspl *s,
		double *cent,		/* Optional center of gamut [fdi], default center of out range */
		double *scale,		/* Optional Scale of output values in vector to center [fdi] */
							/*               default 1.0 */
		void (*outf)(void *cntxf, double *out, double *in),	/* Optional rspl val -> output value */
		void *cntxf,					/* Context for function */
		void (*outb)(void *cntxb, double *out, double *in),	/* Optional output value -> rspl val */
		void *cntxb						/* Context for function */
	);

	/* ------------------------------- */

	/* Set the ink limit information for any reverse interpolation. */
	/* Calling this will clear the reverse interpolaton cache. */
	void (*rev_set_limit)(
		struct _rspl *s,	/* this */
		double (*limitf)(void *lcntx, double *in),	/* Optional input space limit function. */
		                	/* Function should evaluate in[0..di-1], and return a number */
		                	/* that is not to exceed limitv. NULL if not used. */
		void *lcntx,		/* Context passed to limit() */
		double limitv		/* Value that limit() is not to exceed */
	);

	/* Get the ink limit information for any reverse interpolation. */
	void (*rev_get_limit)(
		struct _rspl *s,	/* this */
		double (**limitf)(void *lcntx, double *in),
							/* Return pointer to function of NULL if not set */
		void **lcntx,		/* return context pointer */
		double *limitv		/* Return limit value */
	);

	/* Set the RSPL_NEARCLIP LCh weightings. */
	/* Will only work with L*a*b* like output spaces. */
	/* Calling this will clear the reverse interpolaton cache. */
	void (*rev_set_lchw)(
		struct _rspl *s,	/* this */
		double lchw[MXRO]	/* Weighting */
	);

	/* Possible reverse hint flags */
#define RSPL_WILLCLIP  0x0001		/* Hint that clipping will be needed */
#define RSPL_EXACTAUX  0x0002		/* Hint that auxiliary target will be matched exactly */
#define RSPL_MAXAUX    0x0004		/* If not possible to match exactly, return the */
									/* closest value larger than the target, rather than */
									/* absolute closest. */
#define RSPL_AUXLOCUS  0x0008		/* Auxiliary target is proportion of locus, not */
									/* absolute. Implies EXACTAUX hint. */
#define RSPL_NEARCLIP  0x0010		/* If clipping occurs, return the nearest solution, */
									/* rather than the one in the clip direction. */
#define RSPL_NONNSETUP 0x0020		/* Sets RSPL_FASTREVSETUP flag, which avoids NN grid */
									/* setup if this is the first call using RSPL_NEARCLIP. */
	/* Return value masks */
#define RSPL_DIDCLIP 0x8000		/* If this bit is set, at least one soln. and clipping occured */
#define RSPL_NOSOLNS 0x7fff		/* And return value with this mask to get number of solutions */

	/* Do reverse interpolation given target output values and (optional) auxiliary target */
	/* input values. Return number of results and clip flag. If return value == mxsoln, then */
	/* there might be more results. RESTRICTED SIZE */
	int (*rev_interp)(
		struct _rspl *s,	/* this */
		int flags,			/* Hint flag */
		int mxsoln,			/* Maximum number of solutions allowed for */
		int *auxm,			/* Array of di mask flags, !=0 for valid auxliaries (NULL if no aux) */
		double cdir[MXRO],	/* Clip vector direction and length - NULL if not used */
		co *p);				/* Given target output space value in cpp[0].v[] +  */
							/* target input space auxiliaries in cpp[0].p[], return */
							/* input space solutions in cpp[0..retval-1].p[], and */
							/* (possibly) clipped target values in cpp[0].v[] */

	/* Do reverse search for the locus of the auxiliary input values given a target output. */
	/* Return 1 on finding a valid solution, and 0 if no solutions are found. RESTRICTED SIZE */
	int (*rev_locus)(
		struct _rspl *s,/* this */
		int *auxm,		/* Array of di mask flags, !=0 for valid auxliaries (NULL if no aux) */
		co *cpp,		/* Input target value in cpp[0].v[] */
		double min[MXRI],/* Return minimum auxiliary values */
		double max[MXRI]); /* Return maximum auxiliary values */

	/* Do reverse search for the auxiliary min/max ranges of the solution locus for the */
	/* given target output values. RESTRICTED SIZE */
	/* Return number of locus segments found, up to mxsoln. 0 will be returned if no solutions */
	/* are found. */
	int (*rev_locus_segs)(
		struct _rspl *s,/* this */
		int *auxm,		/* Array of di mask flags, !=0 for valid auxliaries (NULL if no aux) */
		co *cpp,		/* Input value in cpp[0].v[] */
		int mxsoln,		/* Maximum number of solutions allowed for */
		double min[][MXRI],	/* Array of min[MXRI] to hold return segment minimum values. */
		double max[][MXRI]	/* Array of max[MXRI] to hold return segment maximum values. */
	);


	/* ------------------------------- */

	/* Return the min and max of the input values valid in the grid */
	void (*get_in_range)(
		struct _rspl *s,			/* this */
		double *min, double *max);	/* Return min/max values */

	/* return the min and max of the output values contained in the grid */
	void (*get_out_range)(
		struct _rspl *s,			/* this */
		double *min, double *max);	/* Return min/max values */

	/* return the grid index of the grid values at the min & max output values */
	void (*get_out_range_points)(struct _rspl *s, int *minp, int *maxp);

	/* return the overall scale of the output values contained in the grid */
	double (*get_out_scale)(struct _rspl *s);

	/* return the next touched flag count value. */
	/* Whenever this rolls over, all the flags in the grid array will be reset */
	unsigned int (*get_next_touch)(
		struct _rspl *s);			/* this */

#   define wvals ad##jw

	/* Return a pointer to the resolution array */
	int *(*get_res)(struct _rspl *s);

	/* Return non-zero if this rspl can be */
	/* used with Restricted Size functions. */
	int (*within_restrictedsize)(
		struct _rspl *s);			/* this */

}; typedef struct _rspl rspl;

/* Create a new, empty rspl object */
rspl *new_rspl(int flags, int di, int fdi);	/* Input and output dimensiality */

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - */

/* Utility functions */

/* The multi-dimensional access sequence is a distributed */
/* Gray code sequence, with direction reversal */
/* on every alternate power of 2 scale. */
/* It is intended to aid cache access locality in multi-dimensional */
/* regular sampling. It approximates the Hilbert curve sequence. */

/* Structure to hold sequencer info */
struct _rpsh {
	int      di;	/* Dimensionality */
	unsigned res[MXDI];	 /* Resolution per coordinate */
	unsigned bits[MXDI]; /* Bits per coordinate */
	unsigned tbits;	/* Total bits */
	unsigned ix;	/* Current binary index */
	unsigned tmask;	/* Total 2^n count mask */
	unsigned count;	/* Usable count */
}; typedef struct _rpsh rpsh;

/* Initialise, returns total usable count */
unsigned
rpsh_init(rpsh *p, int di, unsigned res[], int co[]);

/* Reset the counter */
void rpsh_reset(rpsh *p);

/* Increment pseudo-hilbert coordinates */
/* Return non-zero if count rolls over to 0 */
int rpsh_inc(rpsh *p, int co[]);

#endif /* RSPL_H */























