/*-------------------------------------------------------------------*/	
bool DPMatchingCircular(int *C, double &T,			// output
						double *A, double thre,		// input
						int	M, int N,				// A is MxN matrix
						int n_search)
{
	double *A2	= new double[M*2*N];
	bool bSucc	= false;
	memcpy(A2,A,M*N*sizeof(double));
	memcpy(A2+M*N,A,M*N*sizeof(double));

	int		*CC	= new int[M];
	double	TT	= 1000000;
	int		id_best	= 0;
	T	= 100000;

	// try different start points
	bSucc	= DPMatchingFixStartPoint(C, T, A2, thre, M, N);
	id_best		= 0;
	int	iS1, iS2;
	//n_search=0;
	for(iS1=1;iS1<n_search;++iS1)	
	{
		bSucc	= DPMatchingFixStartPoint(CC, TT, A2+iS1*M, thre, M, N);
		if(TT<T) {
			T 	= TT;
			id_best	= iS1;
			memcpy(C,CC,M*sizeof(int));
		}

	
		// another direction
		iS2	= N-iS1;
		bSucc	= DPMatchingFixStartPoint(CC, TT, A2+iS2*M, thre, M, N);
		if(TT<T) {
			T 	= TT;
			id_best	= iS2;
			memcpy(C,CC,M*sizeof(int));
		}//*/
	}


	// adjust indices
	for(int ii=0;ii<M;++ii)
	{
		if(C[ii]<N)	{		// not occluded
			C[ii] += id_best;
			if(C[ii]>=N)	C[ii] -= N;
		}
	}

	delete	[]A2;
	delete	[]CC;
	return true;
}
void mexFunction( int nlhs, mxArray *plhs[],
                  int nrhs, const mxArray *prhs[] )
{
    /* Input data */
	double	*A		= mxGetPr(prhs[0]);
	double	thre	= *(mxGetPr(prhs[1]));
    int		M		= mxGetM(prhs[0]);
    int		N		= mxGetN(prhs[0]);
	
	int		n_start	= 1;
	if(nrhs>2)		n_start	= ROUND(*(mxGetPr(prhs[2])));

	int		n_search	= 1;
	if(nrhs>3)		n_search	= ROUND(*(mxGetPr(prhs[3])));


	/* call algorithm */
	D 				= new double[M*N];		// DP matrix, D[y,x] is the cost of contour 1 at x
	links			= new int[M*N];			//	matching to contour 2 at y
	int		*C		= new int[M];
	double	T		= 100000000;

	bool bSucc	= false;
	if(n_start==1 && n_search==1)
		bSucc	= DPMatchingFixStartPoint(C, T,	A, thre, M, N);
	else
		bSucc		= DPMatchingMultiStart(C,T, A,thre,M,N,n_start,n_search);
		//bSucc	= DPMatchingCircular(C, T,	A, thre, M, N, n_search);


    /* Output data */
    mxArray	*pMxC	= mxCreateDoubleMatrix(1,M,mxREAL);
    double	*pC		= mxGetPr(pMxC);
	for(int ii=0;ii<M;++ii)
		pC[ii]	= (double)C[ii]+1;

    mxArray	*pMxT	= mxCreateDoubleMatrix(1,1,mxREAL);
    *(mxGetPr(pMxT))= T;

    /* Return */
    plhs[0] = pMxC;
    plhs[1] = pMxT;

	delete	[]C;
	delete	[]D;
	delete	[]links;
}
void DPMatching( double *cvec, double *match_cost, double *A, double thre, int M, int N, int n_start, int n_search)
{
    /* Input data */

	



	/* call algorithm */
	D 				= new double[M*N];		// DP matrix, D[y,x] is the cost of contour 1 at x
	links			= new int[M*N];			//	matching to contour 2 at y
	int		*C		= new int[M];
	double	T		= 100000000;

	bool bSucc	= false;
	if(n_start==1 && n_search==1)
		bSucc	= DPMatchingFixStartPoint(C, T,	A, thre, M, N);
	else
		bSucc		= DPMatchingMultiStart(C,T, A,thre,M,N,n_start,n_search);
		//bSucc	= DPMatchingCircular(C, T,	A, thre, M, N, n_search);


    /* Output data */
    
	
	for(int ii=0;ii<M;++ii)
		cvec[ii]	= (double)C[ii]+1;

   *match_cost=T;

    /* Return */
   

	delete	[]C;
	delete	[]D;
	delete	[]links;
}
/*-------------------------------------------------------------------*/	
bool DPMatchingMultiStart (	int *C, double &T_best,		// output
							double *A, double thre,		// input
							int	M, int N,				// A is MxN matrix
							int	n_start,
							int n_search)
{
	double *A2	= new double[M*2*N];
	bool bSucc	= false;
	memcpy(A2,A,M*N*sizeof(double));
	memcpy(A2+M*N,A,M*N*sizeof(double));

	int		*CC	= new int[M*N];
	double	TT;
	int		id_best;

	id_best		= -1;
	T_best		= 4000*N;
	n_start	= MIN(N,n_start);

	// try different start points
	int	id_start, iS, iS1, iS2, dS;
	for(iS=0;iS<n_start;++iS)
	{
		id_start	= ROUND(N*iS/(double)n_start);
		bSucc		= DPMatchingFixStartPoint(CC+id_start*M, TT, A2+id_start*M, thre, M, N);
		if(TT<T_best) {
			T_best 	= TT;
			id_best	= id_start;
		}

		for(dS=1;dS<n_search;++dS)	
		{
			// forward
			iS1	= id_start+dS;
			if(iS1>N)	iS1-=N;
			bSucc = DPMatchingFixStartPoint(CC+iS1*M, TT, A2+iS1*M, thre, M, N);
			if(TT<T_best) {
				T_best 	= TT;
				id_best	= iS1;
			}
		
			// backward
			iS2	= id_start-dS;
			if(iS2<0)	iS2+=N;
			bSucc	= DPMatchingFixStartPoint(CC+iS2*M, TT, A2+iS2*M, thre, M, N);
			if(TT<T_best) {
				T_best 	= TT;
				id_best	= iS2;
			}
		}
	}

	// adjust indices 
	if(id_best<0)	printf("\n\tId_best=%d !!!!!!!\n",id_best);

	memcpy(C,CC+id_best*M,M*sizeof(int));				
	for(int ii=0;ii<M;++ii)
	{
		if(C[ii]<N)	{		// not occluded
			C[ii] += id_best;
			if(C[ii]>=N)	C[ii] -= N;
		}
	}

	delete	[]A2;
	delete	[]CC;
	return true;
}