Esempio n. 1
0
void compute(int nlhs, mxArray  *plhs[], int nrhs, const mxArray  *prhs[], const int atria_preprocessing_given,  METRIC dummy)
{
	long bins = 32;
	double start_dist = 0;
	double maximal_search_radius = 0;
	double scale_factor = 1;
	long opt_flag = 0;	// 0 => eucl.norm, 1 => max.norm, utm, 2 => eucl, silent 3 => max., silent

	/* handle matrix I/O */
		
	const long N = mxGetM(prhs[0]);	
	const long dim = mxGetN(prhs[0]);
	const double* p  	= (double *)mxGetPr(prhs[0]);
	
	const long R = mxGetM(prhs[1]);   
	const double* ref 	= (double *)mxGetPr(prhs[1]);
	
	const double relative_range = (double) *((double *)mxGetPr(prhs[2]));
	
	if (nrhs > 3) bins = (long) *((double *)mxGetPr(prhs[3]));
	
	if (nrhs > 4) opt_flag = (long) *((double *)mxGetPr(prhs[4]));
	
	if (N < 1) {
		mexErrMsgTxt("Data set must consist of at least two points (row vectors)");
		return;
	}		
	if (dim < 1) {
		mexErrMsgTxt("Data points must be at least of dimension one");
		return;
	}	
	if (relative_range <= 0) {
		mexErrMsgTxt("Relative range must be greater zero");
		return;
	}	
	if ((mxGetN(prhs[1]) == 0) || (mxGetM(prhs[1]) == 0)) {
		mexErrMsgTxt("Wrong reference indices given");
		return;
	}	
	if (bins < 2) {
		mexErrMsgTxt("Number of bins should be two");
		return;
	}
	if (R < 1) {
		mexErrMsgTxt("At least one reference point must be given");
		return;
	}	
	if (mxGetN(prhs[1]) != dim) {
		mexErrMsgTxt("Dimension of reference points and data set points is not the same");
		return;	
	}
	if ((opt_flag < 0) || (opt_flag > 3)) {
		mexErrMsgTxt("Flag must be out of 0...3");
		return;
	}	

	point_set<METRIC> points(N,dim, p);	
	point_set<METRIC> ref_points(R, dim, ref);
	
	ATRIA< point_set<METRIC> >* searcher = 0;	

#ifdef MATLAB_MEX_FILE	
	if (atria_preprocessing_given) {
		searcher = new ATRIA< point_set<METRIC> >(points, prhs[-1]);	// this constructor used the data from the preprocessing 
		if (searcher->geterr()) {
			delete searcher;
			searcher = 0;
		}
	} 
#endif 
	
	if (searcher == 0) {
		searcher = new ATRIA< point_set<METRIC> >(points);	
	}
	
	if (searcher->geterr()) {
		mexErrMsgTxt("Error preparing searcher");
		return;
	}	 
	
	if (mxGetM(prhs[2])*mxGetN(prhs[2]) == 2) {
		start_dist = (double) ((double *)mxGetPr(prhs[2]))[0];
		maximal_search_radius = (double) ((double *)mxGetPr(prhs[2]))[1];	
		
		if (start_dist <= 0) {
			mexErrMsgTxt("Starting radius is zero or negativ");
			return;		
		}
		if (maximal_search_radius <= start_dist) {
			mexErrMsgTxt("Maximal search radius must be greater than starting radius");
			return;		
		}		
	}
	else {
		maximal_search_radius = relative_range * searcher->data_set_radius();  // compute the maximal search radius using information about attractor size
		
		// try to determine an estimate for the minimum inter-point distance in the data set, but greater zero

		double*	const coord = new double[dim]; 

		for (long n=0; n < 128; n++) { 
			const long actual = (long) (((double)rand() * (double) (N-2))/(double)RAND_MAX);
			vector<neighbor> v;

			for (long k=0; k < dim; k++) coord[k] = points.coordinate(actual,k);

			searcher->search_k_neighbors(v, 1, coord, actual, actual);	// search the nearest neighbor

			if (v.size() > 0) {	
	    		if (start_dist == 0) start_dist = v[0].dist();

				if (v[0].dist() > 0) {
					if (v[0].dist() < start_dist) start_dist = v[0].dist();
				}
			}
		}

		if (start_dist <= 0) {	// first try to search again for a minimum inter-point distance greater zero
			for (long n=0; n < 512; n++) {
				const long actual = (long) (((double)rand() * (double) (N-2))/(double)RAND_MAX);
				vector<neighbor> v;

				for (long k=0; k < dim; k++) coord[k] = points.coordinate(actual,k);
				searcher->search_k_neighbors(v, 1, coord, actual, actual);	// search the nearest neighbor

				if (v.size() > 0) {
		    		if (start_dist == 0) start_dist = v[0].dist();

					if (v[0].dist() > 0) {
						if (v[0].dist() < start_dist) start_dist = v[0].dist();
					}
				}
			}
		}
	
		delete[] coord;
	
		if (start_dist <= 0) {	// give up if we cannot find an interpoint distance greater zero
			mexErrMsgTxt("Cannot find an interpoint distance greater zero, maybe ill-conditioned data set given");
			return;
		}
		if (maximal_search_radius <= start_dist) {
			mexErrMsgTxt("Maximal search radius must be greater than starting radius");
			return;
		}		
	}
	
	scale_factor = pow(maximal_search_radius/start_dist, 1.0/(bins-1));
	
	if (be_verbose)	{
		mexPrintf("Number of reference points            : %d\n", R);
		mexPrintf("Upper bound for attractor size        : %f\n", 2 * searcher->data_set_radius());
		mexPrintf("Starting distance                     : %f\n", start_dist);	
		mexPrintf("Maximal search radius                 : %f\n", maximal_search_radius);
		mexPrintf("Number of partitions used             : %d\n\n", bins);
	}
	
	plhs[0] = mxCreateDoubleMatrix(bins, 1, mxREAL);
	double* corrsums = (double *) mxGetPr(plhs[0]);
	double* dists;
	
	if (nlhs > 1) {
		plhs[1] = mxCreateDoubleMatrix(bins, 1, mxREAL);
		dists = (double *) mxGetPr(plhs[1]);
	} else
		dists = new double[bins]; 

	double x = start_dist;
	
	// initialize vectors
	// corrsum[i] counts the number of points/distances (real) smaller than dists[i]
	for  (long bin=0; bin < bins; bin++) {
		corrsums[bin] = 0;
		dists[bin] = x;
		x *= scale_factor;
	}
	
	long total_pairs = 0;	// count the total number of points pairs that were at least theoretically tested	

	for (long n=0; n < R; n++) { 		/* iterate over all reference points */ 
		vector<neighbor> v;
		const long pairs = N;
		
		if (pairs <= 0)
			continue;

		total_pairs += pairs;

		searcher->search_range(v, maximal_search_radius, ref_points.point_begin(n), -1, -1); 
		
		if (v.size() > 0) {	
			for (vector<neighbor>::iterator i = v.begin(); i < v.end(); i++) { // v is unsorted (!!!)
				const double dist = (*i).dist();

				int mi, ni; 	// index of first and last (inclusive) element of array dists

				if (dist >= dists[ni = bins-1]) 	// => we know that dist <= dists[ni]
					continue;

				if (dist < dists[mi = 0]) { 		// => we know that dists[mi] < dist  
					corrsums[0]++;
					continue;
				}

				do
                {
                    const int ki = (mi + ni) / 2;	// "mi < ki < ni" if "mi + 1 < ni"					
                    if (dist < dists[ki])  
						ni = ki;    	// "dists[mi] < dist <= dists[ni]" is still valid
					else 
                        mi = ki;    	// "dists[mi] < dist <= dists[ni]" is still valid
                } while (ni > mi+1);           

				// now, "ni == mi+1" and "dists[mi] < dist <= dists[ni]" is true,
				// so "dists[mi] < dist <= dists[mi+1]", so mi+1 is the desired bin where
				// to count this distance

				corrsums[ni]++;										
			}
		}
	}

	if (total_pairs > 0) {
		unsigned long sum = 0;
		for  (long bin=0; bin < bins; bin++) {
			sum += (long) corrsums[bin];
			corrsums[bin] = ((double) sum) / (double) total_pairs; 
		}
	}
	
	if (nlhs > 2) {
		plhs[2] = mxCreateDoubleMatrix(1, 1, mxREAL);
		*((double *) mxGetPr(plhs[2])) = (double) total_pairs;	
	}
		
	if (!(nlhs > 1)) delete[] dists;	
	
	delete searcher;
} 
void compute(int nlhs, mxArray  *plhs[], int nrhs, const mxArray  *prhs[], const int atria_preprocessing_given,  METRIC dummy)
{ 
	long i,j,n,k;		/* loop variables */ 

	/* handle matrix I/O */
	
	const long N = mxGetM(prhs[0]);	
	const long dim = mxGetN(prhs[0]);
	const double* p  	= (double *)mxGetPr(prhs[0]);
	
	const long R = max(mxGetM(prhs[1]), mxGetN(prhs[1]));
	const double* ref 	= (double *)mxGetPr(prhs[1]);
	
	const double  relative_range = (double) *((double *)mxGetPr(prhs[2]));
	const long past	= (long) *((double *)mxGetPr(prhs[3]));
	
	if (N < 1) {
		mexErrMsgTxt("Data set must consist of at least two points (row vectors)");
		return;
	}		
	if (dim < 2) {
		mexErrMsgTxt("Data points must be at least of dimension two");
		return;
	}		
	if ((mxGetN(prhs[1]) == 0) || (mxGetM(prhs[1]) == 0)) {
		mexErrMsgTxt("Wrong reference indices given");
		return;
	}	
		
	if (R < 1) {
		mexErrMsgTxt("At least one reference index or point must be given");
		return;
	}	

	for (i=0; i < R; i++) {
		if ((ref[i] < 1) || (ref[i]>N)) {
			mexErrMsgTxt("Reference indices out of range");
			return;
		}	
	}
	
	point_set<METRIC> points(N,dim, p);	
	ATRIA< point_set<METRIC> >* searcher = 0;	

#ifdef MATLAB_MEX_FILE	
	if (atria_preprocessing_given) {
		searcher = new ATRIA< point_set<METRIC> >(points, prhs[-1]);	// this constructor used the data from the preprocessing 
		if (searcher->geterr()) {
			delete searcher;
			searcher = 0;
		}
	} 
#endif
	
	if (searcher == 0) {
		searcher = new ATRIA< point_set<METRIC> >(points);	
	}
	
	if (searcher->geterr()) {
		mexErrMsgTxt("Error preparing searcher");
		return;
	}	 		
	
	double range;
	
	if (relative_range > 0)	
		range = relative_range * searcher->data_set_radius();  // compute the maximal search radius using information about attractor size
	else
		range = fabs(relative_range); 	// if relative_range is negativ, use it's value (without sign) as maximal search radius  

	mexPrintf("Number of reference points            : %d\n", R);
	mexPrintf("Upper bound for attractor size        : %f\n", 2 * searcher->data_set_radius());	
	mexPrintf("Maximal search radius                 : %f\n", range);

	plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL);
	double* out = (double *) mxGetPr(plhs[0]);
	
	unsigned long counter = 0;	
	double sum = 0;

	for (n=0; n < R; n++) { 		/* iterate over all reference points */ 
          const long actual = (long) ref[n]-1;		/* Matlab to C means indices change from 1 to 0, 2 to 1, 3 to 2 ...*/

		if (actual > past) {
			vector<neighbor> v;

			searcher->search_range(v, range, points.point_begin(actual), actual-past, N); // don't search points from [actual-past .. N-1]
			//overall_points += (actual-past);	// count the total number of points pairs that were at least theoretically tested

			if (v.size() > 0) {	
				vector<neighbor>::iterator i;
				
				for (i = v.begin(); i < v.end(); i++) { // v is unsorted
					const double dist = (*i).dist();
					if (dist > 0) {
						sum += log(dist/range);
						counter++;
					}
				}
			}
		}
	}

	if (counter > 0) *out = -((double)counter)/sum;
	else *out = 0;
		
	delete searcher;
}
Esempio n. 3
0
void compute(int nlhs, mxArray  *plhs[], int nrhs, const mxArray  *prhs[], const int atria_preprocessing_given,  METRIC dummy)
{
	long bins = 32;
	double start_dist = 0;
	double maximal_search_radius = 0;
	double scale_factor = 1;
	long opt_flag = 0;	// 0 => eucl.norm, upper triangle matrix, 1 => max.norm, utm, 2 => eucl,full matrix, 3 => max.,full matrix
	long Nref_min;
	long Nref_max;
	
	/* handle matrix I/O */
		
#ifdef C_STYLE_POINT_SET		
	const long N = mxGetN(prhs[0]); 
    const long dim = mxGetM(prhs[0]);
#else	// this is the default 
	const long N = mxGetM(prhs[0]);		
	const long dim = mxGetN(prhs[0]);
#endif	
	const double* p  	= (double *)mxGetPr(prhs[0]);

	const long Npairs = (long) *((double *)mxGetPr(prhs[1])); // number of pairs
	
	if (mxGetM(prhs[1])*mxGetN(prhs[1]) == 3) {
		Nref_min = (long) ((double *)mxGetPr(prhs[1]))[1];
		Nref_max = (long) ((double *)mxGetPr(prhs[1]))[2];
	} else {
		Nref_min = 1;
		Nref_max = N;
	}	
	
	const double relative_range = (double) *((double *)mxGetPr(prhs[2]));
	const long past	= (long) *((double *)mxGetPr(prhs[3]));
	
	if (nrhs > 4) bins = (long) *((double *)mxGetPr(prhs[4]));
	
	if (nrhs > 5) opt_flag = (long) *((double *)mxGetPr(prhs[5]));
	
	if (N < 1) {
		mexErrMsgTxt("Data set must consist of at least two points (row vectors)");
		return;
	}		
	if (dim < 1) {
		mexErrMsgTxt("Data points must be at least of dimension one");
		return;
	}	
	if (relative_range <= 0) {
		mexErrMsgTxt("Relative range must be greater zero");
		return;
	}	
	if (bins < 2) {
		mexErrMsgTxt("Number of bins should be two");
		return;
	}
	if (Npairs < 1) {
		mexErrMsgTxt("Number of pairs must be positive");
		return;
	}	
	if ((opt_flag < 0) || (opt_flag > 7)) {
		mexErrMsgTxt("Flag must be out of 0..7");
		return;
	}	
	if (Nref_min < 1) Nref_min = 1;
	if (Nref_max > N) Nref_max = N;
	
	point_set<METRIC> points(N,dim, p);	
	ATRIA< point_set<METRIC> >* searcher = 0;	

#ifdef MATLAB_MEX_FILE	
	if (atria_preprocessing_given) {
		searcher = new ATRIA< point_set<METRIC> >(points, prhs[-1]);	// this constructor used the data from the preprocessing 
		if (searcher->geterr()) {
			delete searcher;
			searcher = 0;
		}
	} 
#endif 
	
	if (searcher == 0) {
		searcher = new ATRIA< point_set<METRIC> >(points);	
	}
	
	if (searcher->geterr()) {
		mexErrMsgTxt("Error preparing searcher");
		return;
	}	 
	
	if (mxGetM(prhs[2])*mxGetN(prhs[2]) == 2) {
		start_dist = (double) ((double *)mxGetPr(prhs[2]))[0];
		maximal_search_radius = (double) ((double *)mxGetPr(prhs[2]))[1];	
		
		if (start_dist <= 0) {
			mexErrMsgTxt("Starting radius is zero or negativ");
			return;		
		}
		if (maximal_search_radius <= start_dist) {
			mexErrMsgTxt("Maximal search radius must be greater than starting radius");
			return;		
		}		
	}
	else {
		maximal_search_radius = relative_range * searcher->data_set_radius();  // compute the maximal search radius using information about attractor size
		
		// try to determine an estimate for the minimum inter-point distance in the data set, but greater zero
		for (long n=0; n < 128; n++) { 
			const long actual = (long) (((double)rand() * (double) (N-2))/(double)RAND_MAX);
			vector<neighbor> v;
			searcher->search_k_neighbors(v, 1, points.point_begin(actual), actual, actual);	// search the nearest neighbor

			if (v.size() > 0) {	
	    		if (start_dist == 0) start_dist = v[0].dist();

				if (v[0].dist() > 0) {
					if (v[0].dist() < start_dist) start_dist = v[0].dist();
				}
			}
		}
		if (start_dist <= 0) {	// first try to search again for a minimum inter-point distance greater zero
			for (long n=0; n < 512; n++) {
				const long actual = (long) (((double)rand() * (double) (N-2))/(double)RAND_MAX);
				vector<neighbor> v;

				searcher->search_k_neighbors(v, 1, points.point_begin(actual), actual, actual);	// search the nearest neighbor

				if (v.size() > 0) {
		    		if (start_dist == 0) start_dist = v[0].dist();

					if (v[0].dist() > 0) {
						if (v[0].dist() < start_dist) start_dist = v[0].dist();
					}
				}
			}
		}
		if (start_dist <= 0) {	// give up if we cannot find an interpoint distance greater zero
			mexErrMsgTxt("Cannot find an interpoint distance greater zero, maybe ill-conditioned data set given");
			return;
		}
		if (maximal_search_radius <= start_dist) {
			mexErrMsgTxt("Maximal search radius must be greater than starting radius");
			return;
		}		
	}
	
	scale_factor = pow(maximal_search_radius/start_dist, 1.0/(bins-1));
	
	if (be_verbose)	{
		//mexPrintf("Number of reference points            : %d\n", R);	
		mexPrintf("Number of data set points             : %d\n", N);	
		mexPrintf("Number of pairs to find               : %d\n", Npairs);
		mexPrintf("Miniumum number of reference points   : %d\n", Nref_min);
		mexPrintf("Maximum number of reference points    : %d\n", Nref_max);	
		mexPrintf("Upper bound for attractor size        : %f\n", 2 * searcher->data_set_radius());
		mexPrintf("Number of partitions used             : %d\n", bins);
		mexPrintf("Time window to exclude from search    : %d\n", past);
		mexPrintf("Minimal length scale                  : %f\n", start_dist);	
		mexPrintf("Starting at maximal length scale      : %f\n", maximal_search_radius);
	}
	
	plhs[0] = mxCreateDoubleMatrix(bins, 1, mxREAL);
	double* corrsums = (double *) mxGetPr(plhs[0]);
	
	long* const ref = new long[N];				// needed to create random reference indices
	long* const total_pairs = new long[bins];	// number of total pairs is not equal for all bins
	long* const pairs_found = new long[bins];	// number of pairs found within distance dist
	
	double* dists;
	
	if (nlhs > 1) {
		plhs[1] = mxCreateDoubleMatrix(bins, 1, mxREAL);
		dists = (double *) mxGetPr(plhs[1]);
	} else
		dists = new double[bins]; 

	double x = start_dist;
	
	// initialize vectors
	// pairs_found[i] counts the number of points/distances (real) smaller than dists[i]
	for  (long bin=0; bin < bins; bin++) {
		pairs_found[bin] = 0;
		total_pairs[bin] = 0;
		dists[bin] = x;
		x *= scale_factor;
	}
	
	for (long r=0; r < N; r++) ref[r] = r;
	
	long R = 0; 		// number of reference points actually used
	long bin = bins-1;	// the current highest bin (and length scale) that needs to be filled over Npairs
	
	while(((R < Nref_min) || (pairs_found[bin] < Npairs)) && (R < Nref_max)) {
		vector<neighbor> v;
		long first, last;			// all points with indices i so that first <= i <= last are excluded(!) from search
		long pairs = 0;
		
		const long actual = random_permutation(ref, N, R++);  // choose random index from 0...N-1, without reoccurences
		
		if (opt_flag & (long)2) {
			first = actual-past;
			last = actual+past;
		
			if (past >= 0)
				pairs = lmax(0,first) + lmax(N-1-last,0);	
			else
				pairs = N;
				
		} else {
			if (past >= 0)
				first = actual-past;
			else
				first = actual;
				
			last = N;
			pairs = lmin(first,last);	// don't search points from [actual-past .. N-1]			
		}

		if (pairs <= 0) {
			continue;
		}

		searcher->search_range(v, dists[bin], points.point_begin(actual), first, last);
		
		if (v.size() > 0) {	
			for (vector<neighbor>::iterator i = v.begin(); i < v.end(); i++) { // v is unsorted (!!!)
				const double d = (*i).dist();
	
				for (long n = bin; n >= 0; n--) {
					if (d > dists[n])
						break;
						
					pairs_found[n]++;	
				}											
			}
		}
		
		for (long n = 0; n <= bin; n++) {
			total_pairs[n] += pairs;
		}			
		
		// see if we can reduce length scale
		int bins_changed = 0;
		while((pairs_found[bin] >= Npairs) && (bin > 0) && (R >= Nref_min)) {
			bin--;
			bins_changed = 1;
		}
		if (be_verbose)	{
			if (bins_changed) {
				mexPrintf("Reference points used so far          : %d\n", R);
				mexPrintf("Switching to length scale             : %f\n", dists[bin]);	
			}	
		}				
	}

	if (be_verbose)	{
		mexPrintf("Number of reference points used       : %d\n", R);	
	}
	for  (long bin=0; bin < bins; bin++) {
		corrsums[bin] = ((double) pairs_found[bin]) / ((double) total_pairs[bin]); 
	}
	
	if (nlhs > 2) {
		plhs[2] = mxCreateDoubleMatrix(bins, 1, mxREAL);
		double* const y = mxGetPr(plhs[2]);
		
		for (long b=0; b < bins; b++) 
			y[b] = (double) pairs_found[b];			
	}
	if (nlhs > 3) {
		plhs[3] = mxCreateDoubleMatrix(bins, 1, mxREAL);
		double* const y = mxGetPr(plhs[3]);
		
		for (long b=0; b < bins; b++) 
			y[b] = (double) total_pairs[b];			
	}			
	if (nlhs > 4) {
		plhs[4] = mxCreateDoubleMatrix(R, 1, mxREAL);
		double* const y = mxGetPr(plhs[4]);
		
		for (long r=0; r < R; r++) 
			y[r] = (double) ref[r]+1;	// C to Matlab means			
	}
		
	delete[] total_pairs;
	delete[] pairs_found;	
	delete[] ref;
	if (!(nlhs > 1)) delete[] dists;	
	delete searcher;
} 
Esempio n. 4
0
void mexFunction(int nlhs, mxArray  *plhs[], int nrhs, const mxArray  *prhs[])
{	
	int atria_preprocessing_given = 0;		// flag wheter preprocessing is already given on command line

	ATRIA< point_set<euclidian_distance> >* searcher = 0;	
	// try to see if the first parameter given is an atria structure
	// If this is true, the order of input parameters is shifted by one
	
	// try to see if the first parameter given is an atria structure
	// If this is true, the order of input parameters is shifted by one
	if ((nrhs) && (mxIsStruct(prhs[0]))) {
		atria_preprocessing_given = 1;			
		prhs++; 	// these two lines enable us to use the old argument parsing block without changing it
		nrhs--;
	}

	/* check input args */
	if (nrhs < 5)
	{
		mexErrMsgTxt("Largest lyapunov exponent : Data set of points (row vectors), reference indices, length of prediction, maximal number of neighbours and past must be given");
		return;
	}
	
	/* handle matrix I/O */
	
	const long N = mxGetM(prhs[0]);	
	const long dim = mxGetN(prhs[0]);
	const double* p 	= (double *)mxGetPr(prhs[0]);
	
	const long R = mxGetM(prhs[1]) * mxGetN(prhs[1]);			// number of reference points
	const double* ref 	= (double *)mxGetPr(prhs[1]);
	
	const long length 	= (long) *((double *)mxGetPr(prhs[2])); 	// length of prediction
	const long NNR = (long) *((double *)mxGetPr(prhs[3]));			// number of nearest neighbors
	const long past	= (long) *((double *)mxGetPr(prhs[4])); 		// number of points to be excluded from search
	
	if (fabs((double) N) - fabs((double)length) < 1) {
		mexErrMsgTxt("Data set must consist of at least two points (row vectors)");
		return;
	}		
	if (dim < 1) {
		mexErrMsgTxt("Data points must be at least of dimension one");
		return;
	}	
	if (length <= 0) {
		mexErrMsgTxt("Prediction length must be greater zero");
		return;
	}	
	if ((mxGetN(prhs[1]) == 0) || (mxGetM(prhs[1]) == 0)) {
		mexErrMsgTxt("Wrong reference indices given");
		return;
	}	
	if ((NNR < 1) || (NNR > N)) {
		mexErrMsgTxt("Number of nearest neighbours must be within 1 and number of points in the data set");
		return;
	}
		
	mexPrintf("Number of reference points : %d\n", R);
	
	if (R < 1) {
		mexErrMsgTxt("At least one reference index or point must be given");
		return;
	}	

	for (long i=0; i < R; i++) { 	// check reference indices
		if ((ref[i] < 1) || (ref[i]>N-length)) {
			mexErrMsgTxt("Reference indices out of range");
			return;
		}	
	}
	
#include "create_searcher.cpp"	

	plhs[0] = mxCreateDoubleMatrix(length+1, 1, mxREAL);
	double* x = (double *) mxGetPr(plhs[0]);
	
	const double logarithm_of_2 = log(2.0);
	int issue_warning = 1;
	long count = 0; 	// count the number of pairs with distance > 0
	
	for (long step = 0; step <= length; step++) x[step] = 0;
	
	for (long n=0; n < R; n++) { 		/* main loop, iterate over all reference points */ 
		vector<neighbor>::iterator i;
		vector<neighbor> v;
		
		const long actual = (long) ref[n]-1;		/* Matlab to C means indices change from 1 to 0, 2 to 1, 3 to 2 ...*/
				
		// try to find at least NNR valid pairs (reference point - neighbor)
		// a valid pair must fullfil several criteria :
		// 1) both must have a known future of at least lenght steps, so that we
		//    don't run out of the data set size when computing the divergence
		// 2) initial distance must be greater zero
		// 3) inital indices must differ by at least "past" steps
		for (long nnr=NNR; nnr < 4 * NNR; nnr++) {
			vector<neighbor> v_test;
			v.erase(v.begin(), v.end());	
			
			searcher->search_k_neighbors(v_test, nnr, points.point_begin(actual), actual-past, actual+past);
			
			for (i = v_test.begin(); i < v_test.end(); i++) { 
				if (((*i).dist() > 0) && ((*i).index() < N-length)) {
					v.push_back(*i);
				}	
			}
			if (v.size() >= NNR) 
				break;	
		}
				
		for (i = v.begin(); i < v.end(); i++) { 	// v is the sorted vector of neighbors
			const long nnindex = (*i).index();
			const double nndist = (*i).dist();		
			const double log_nndist = log(nndist);
			
			count++;

			for (long step = 0; step <= length; step++) {
				const double dist = points.distance(actual+step, nnindex+step);

				if (dist > 0) {
					x[step] += log(dist) - log_nndist;
				}
				else {
					if (issue_warning) {
						issue_warning = 0;	// don't issue this warning again
						mexPrintf("Largelyap warning : cannot take logarithm of distance zero \n");
					}
				}
			}		
		}		
	}
	
	if (count > 0)	{
		for (long step = 0; step <= length; step++) x[step] /= (count*logarithm_of_2);
	}
	
	delete searcher;
}