#include "numerics.h"
#include "innerloop2.h"
#include <assert.h>
#include "gpk_std.h"
#include <stdlib.h>


static double avg(const double *x, int i, int j)
{
 int k;
 double sum = 0;
 for(k=i; k<j; k++)
	sum += x[k];
 return sum/(j-i);
}


static int cmpf(const void *a, const void *b)
{
	const double *aa = (const double *)a;
	const double *bb = (const double *)b;
	if (*aa > *bb)
		return 1;
	else if(*aa < *bb)
		return -1;
	return 0;
}


static double median_avg(const double *x, int i, int j)
{
	int n = j-i;
	if(n == 1)
		return x[i];
	else if(n == 2)
		return 0.5*(x[i]+x[i+1]);
	{
	double *xx = new double [n];
	assert(xx);
	INNERLOOP(k, 0, n, xx[k] = x[k+i]);
	qsort(xx, n, sizeof(*xx), cmpf);
	double o = 0.5*(xx[n/2] + xx[(n+1)/2]);
	delete [] xx;
	return o;
	}
}


double *monotonic_guts(const double *x, int n, int sign,
			double (*averager)(const double *x, int i, int j))
{
 double *o = (double *)malloc(n * sizeof(*x));
 assert(o);
 INNERLOOP(q, 0, n, o[q] = x[q]);
 int changed = 0;
 do	{
	int i = 0;
	changed = 0;
	while(i<n)	{
		int change;
		int j = i+1;
		while(j<n && o[j]*sign<=o[j-1]*sign)
			j++;
		change = j>i+1 && o[j-1]!=o[i];
		if(change)	{
			double a = averager(x, i, j);
			int k;
			for(k=i; k<j; k++)
				o[k] = a;
			changed = 1;
			}
		i = j;
		}
	} while(changed);
 return o;
}


double * monotonic(const double *x, int n, int sign)
{
	return monotonic_guts(x, n, sign, avg);
}


double * monotonic_median(const double *x, int n, int sign)
{
	return monotonic_guts(x, n, sign, median_avg);
}





#if 0

#define NX	10000

#include <stdio.h>

main(int argc, char **argv)
{
 char line[1000];
 double x[NX], a[NX];
 double *q;
 int i=0, n;
 while(fgets(line, sizeof(line), stdin) && i<NX)
	if(sscanf(line, "%lg %lg", &a[i], &x[i])==2)
		i++;
 n = i;
 q = monotonic(x, n, 1);
 for(i=0;i<n;i++)
	printf("%g %g %g\n", a[i], x[i], q[i]);
}

#endif
