
/*
 * Author: Graeme Gill
 * Date:   30/10/2005
 *
 * Copyright 2005 Graeme W. Gill
 * Parts derived from rspl/c1.c, cv.c etc.
 *
 * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
 * see the License.txt file for licencing details.
 *
 * Test monocurve class.
 *
 */

#undef DIAG
#undef TEST_SYM

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <math.h>
#include "copyright.h"
#include "aconfig.h"
#include "numlib.h"
#include "moncurve.h"
#include "plot.h"
#include "ui.h"

double lin(double x, double xa[], double ya[], int n);
void usage(void);

#define TRIALS 30	/* Number of random trials */
#define SKIP 0		/* Number of random trials to skip */
#undef NORMONLY	/* Defined to use 0.0 - 1.0 limited curve */

#undef ORDER_STEP		/* Step orders from 2 to SHAPE_ORDERS */
//#define SHAPE_ORDS 30		/* Number of order to use */
#define SHAPE_ORDS 12		/* Number of order to use */

#define ABS_MAX_PNTS 100

#define MIN_PNTS 2
#define MAX_PNTS 20

#define MIN_RES 20
#define MAX_RES 500

double xa[ABS_MAX_PNTS];
double ya[ABS_MAX_PNTS];

#define XRES 100

#define TSETS 3			/* Number of special test sets */
#define PNTS 11
#define GRES 100
int t1p[TSETS] = {
	4,
	11,
	11
};

double t1xa[TSETS][PNTS] = {
	{ 0.0, 0.2,  0.8,  1.0  },
	{ 0.0, 0.1,  0.2,  0.3,   0.4,   0.5,  0.6,  0.7,   0.8,   0.9,  1.0  },
	{ 0.0, 0.25, 0.30, 0.35,  0.40,  0.44, 0.48, 0.51,  0.64,  0.75, 1.0  }
};

double t1ya[TSETS][PNTS] = {
	{ 0.0, 0.5,  0.6,  1.0  },
	{ 0.0, 0.0,  0.5,  0.5,   0.5,   0.5,   0.5,  0.8,  1.0,   1.0,   1.0  },
	{ 0.0, 0.35, 0.4,  0.41,  0.42,  0.46, 0.5,  0.575, 0.48,  0.75,  1.0  }
};


mcvco test_points[ABS_MAX_PNTS];

double lin(double x, double xa[], double ya[], int n);

void
usage(void) {
	puts("usage: monctest");
	exit(1);
}

int main() {
	mcv *p;
	int i, n;
	double x, y;
	double xx[XRES];
	double y1[XRES];
	double y2[XRES];
	int np = SHAPE_ORDS;					/* Number of harmonics */

	error_program = "monctest";

#ifdef NORMONLY
	printf("Testing fixed offset = 0 and scale = 1.0\n");
	if ((p = new_mcv_noos()) == NULL)
#else
	if ((p = new_mcv()) == NULL)
#endif
		error("new_mcv failed");

	for (n = 0; n < TRIALS; n++) {
		double lrand;		/* Amount of level randomness */
		int pnts;

		if (n < TSETS)	/* Standard versions */ {
			pnts = t1p[n];
			for (i = 0; i < pnts; i++) {
				xa[i] = t1xa[n][i];
				ya[i] = t1ya[n][i];
			}
		} else if (n == TSETS) {				/* Exponential function aproximation */
			double ex = 2.4;
			pnts = MAX_PNTS;

			printf("Trial %d, no points = %d, exponential %f\n",n,pnts,ex);

			/* Create X values */
			for (i = 0; i < pnts; i++)
				xa[i] = pow(i/(pnts-1.0), 1.0);

			for (i = 0; i < pnts; i++)
				ya[i] = pow(xa[i], ex);

		} else if (n == TSETS + 1) {			/* inverse exponential function aproximation */
			double ex = 1.0/2.4;
			pnts = MAX_PNTS;

			printf("Trial %d, no points = %d, exponential %f\n",n,pnts,ex);

			/* Create X values */
			for (i = 0; i < pnts; i++)
				xa[i] = pow(i/(pnts-1.0), 3.0);

			for (i = 0; i < pnts; i++)
				ya[i] = pow(xa[i], ex);

		} else {	/* Random versions */
			double ymax;
			lrand = d_rand(0.0,0.2);		/* Amount of level randomness */
			lrand *= lrand;
			pnts = i_rand(MIN_PNTS,MAX_PNTS);

			printf("Trial %d, no points = %d, level randomness = %f\n",n,pnts,lrand);

			/* Create X values */
			xa[0] = 0.0;
			for (i = 1; i < pnts; i++)
				xa[i] = xa[i-1] + d_rand(0.5,1.0);
			for (i = 0; i < pnts; i++)	/* Divide out */
				xa[i] = (xa[i]/xa[pnts-1]);

			/* Create y values */
			ya[0] = xa[0] + d_rand(-0.2, 0.7);
			for (i = 1; i < pnts; i++)
				ya[i] = ya[i-1] + d_rand(0.1,1.0) + d_rand(-0.1,0.4) + d_rand(-0.4,0.5);

			ymax = d_rand(0.6, 10.2);		/* Scale target */
			for (i = 0; i < pnts; i++) {
				ya[i] = ymax * (ya[i]/ya[pnts-1]);
//				if (ya[i] < 0.0)
//					ya[i] = 0.0;
//				else if (ya[i] > 1.0)
//					ya[i] = 1.0;
			}
		}

		if (n < SKIP)
			continue;

		for (i = 0; i < pnts; i++) {
			test_points[i].p = xa[i];
			test_points[i].v = ya[i];
			test_points[i].w = 1.0;
		}
		/* Test weighting */
		test_points[pnts-1].w = 1.0;

#ifdef ORDER_STEP
		for (np = 2; np <= SHAPE_ORDS; np++) {
#else	/* Full number of orders */
		for (np = SHAPE_ORDS; np <= SHAPE_ORDS; np++) {
#endif

			/* Fit to scattered data */
			p->fit(p,
			    1,						/* Vebose */
			    np,						/* Number of curve parameters */
			    test_points,			/* Test points */
			    pnts,					/* Number of test points */
			    1.0						/* Smoothing */
			);
	
			printf("Residual = %f\n",p->resid);
			printf("Total number of params = %d\n",p->luord);
			for (i = 0; i < p->luord; i++) {
				printf("Param %d = %f\n",i,p->pms[i]);
			}
	
			/* Display the result */
			for (i = 0; i < XRES; i++) {
				x = i/(double)(XRES-1);
				xx[i] = x;
				y1[i] = lin(x,xa,ya,pnts);
				y2[i] = p->interp(p, x);
				y = p->inv_interp(p, y2[i]);
				if (fabs(x - y) > 0.00001)
					printf("Inverse mismatch: %f -> %f -> %f\n",x,y2[i],y);
//				if (y2[i] < -0.2)
//					y2[i] = -0.2;
//				else if (y2[i] > 1.2)
//					y2[i] = 1.2;
			}
			do_plot(xx,y1,y2,NULL,XRES);
		}

	}	/* next trial */

	p->del(p);

	return 0;
}

double lin(
double x,
double xa[],
double ya[],
int n) {
	int i;
	double y;

	if (x < xa[0])
		return ya[0];
	else if (x > xa[n-1])
		return ya[n-1];

	for (i = 0; i < (n-1); i++)
		if (x >=xa[i] && x <= xa[i+1])
			break;

	x = (x - xa[i])/(xa[i+1] - xa[i]);

	y = ya[i] + (ya[i+1] - ya[i]) * x;
	
	return y;
	}














