#include <stdio.h>
#include <math.h>
#include <assert.h>
#include <stdlib.h>
#include <gpklib.h>
#include <gpklib/numerics.h>


#define D if(0)

double func(const double *p, int n, void *c, int nc)
{
 int i;
 double err = 0.0;
 for(i=0; i<n; i++)
 	err += p[i]*p[i]*(i+1);
 return err/2.0;
}


/* Runtest runs amoeba_anneal on a simple function to calibrate
 * the relationship between temperature and the variance of the
 * parameters.
 * N is the number of parameters for the model.
 */
void runtest( int N)
{
	/* M is the number of points in the annealing process:
	 * i.e. the number of vertices in the simplex (though it's
	 * not really a simplex if M>N+1).
	 */
	C int M = N+5;
	assert(M > N);
	int i;
	int n = 0;
	double *sum = double1alloc(N);
	double *ssum = double1alloc(N);
	double **p = double2alloc(M, N);
	for(i=0; i<N; i++)	{
		int j;
		for(j=0; j<M; j++)
			p[j][i] = Nnoise();
			/* Here we fill the parameters with more-or-less
			 * randomly chosen initial values.
			 */
		}
	/* This is an initial run to make sure that we are near the minimum,
	 * and equilibrated an the correct temperature.
	 */
	amoeba_anneal_allfree2(p, N, M, 0.0, func, 30*M*N, 0, 0, 1.0, 1.0, 0);
	for(i=0; i<500; i++)	{
		int j;
		/* Here, we run it a few steps so we get a new result
		 * that's roughly independent of the previous result.
		 */
		amoeba_anneal_allfree2(p, N, M, 0.0, func, 2*M*N, 0, 0, 1.0, 1.0, 0);
		for(j=0; j<M; j++) {
			int k;
			for(k=0; k<N; k++) {
				D printf("%.3f ", p[j][k]);
				sum[k] += p[j][k];
				ssum[k] += p[j][k]*p[j][k];
				}
			n += 1;
			D printf("\n");
			fflush(stdout);
			}
		D printf("#\n");
		}
	for(i=0; i<N; i++)
		printf("n= %d mean[%d]= %g sigma= %g %g\n", N, i, sum[i]/n, i, sqrt((i+1)*ssum[i]/(double)n),
				n/(ssum[i]*(double)(i+1))
				);
}



int main(int argc, char **argv)
{
 runtest(atoi(argv[1]));
}
