int  Steepest_Descent(double (*f)(double *), void (*df)(double *, double *),
	int (*stopping_rule)(double*, double, double*, double, double*, int, int),
                          double a[], double *fa, double *dfa, double cutoff,
                          double cutoff_scale_factor, double tolerance, int n)
{
   double* x;
   double* initial_a = a;
   double* tmp;
   double fx;
   double p;
   int err = 0;
   int iteration = 0;
   x = (double *) malloc(n * sizeof(double));
   if ( x == NULL) { err = -4; }

   df(a, dfa);
   if (Vector_Max_Norm(dfa,n) == 0.0) err = -5;
   while (!err) {
	  //printf("xMin = (%f , %f) \nf(xMin) = %f\n", a[0], a[1], *fa );
      if (Vector_Max_Norm(dfa,n) == 0.0) break;
      err = Minimize_Down_the_Line(f, a, *fa, &p, dfa, x, cutoff,
                                            cutoff_scale_factor, tolerance, n);
      if ( err ) break;
      fx = f(x);
      iteration++;
      df(x, dfa);
      err = stopping_rule( a, *fa, x, fx, dfa, iteration, n);
      *fa = fx;
      tmp = a;
      a = x;
      x = tmp;
   }
   if (a != initial_a ) {
      Copy_Vector(initial_a, a, n);
      x = a;
   }
   free(x);
   return err;
}
//---------------------------------------------------------
template <class T> double * CSG_mRMR::Get_JointProb(T * img1, T * img2, long len, long maxstatenum, int &nstate1, int &nstate2)
{
    long	i, j;

    //-----------------------------------------------------
    // get and check size information

    if (!img1 || !img2 || len < 0)
    {
        SG_UI_Msg_Add_Error("At least one of the input vectors is invalid.");

        return( NULL );
    }

    int	b_findstatenum	= 1;	//  int nstate1 = 0, nstate2 = 0;
    int	b_returnprob	= 1;

    //-----------------------------------------------------
    // copy data into new INT type array (hence quantization) and then reange them begin from 0 (i.e. state1)

    int	*vec1	= new int[len];
    int	*vec2	= new int[len];

    if( !vec1 || !vec2 )
    {
        SG_UI_Msg_Add_Error("Fail to allocate memory.\n");

        return( NULL );
    }

    int	nrealstate1 = 0, nrealstate2 = 0;

    Copy_Vector(img1, len, vec1, nrealstate1);
    Copy_Vector(img2, len, vec2, nrealstate2);

    //update the #state when necessary
    nstate1 = (nstate1 < nrealstate1) ? nrealstate1 : nstate1;
    //printf("First vector #state = %i\n",nrealstate1);
    nstate2 = (nstate2 < nrealstate2) ? nrealstate2 : nstate2;
    //printf("Second vector #state = %i\n",nrealstate2);

    //  if (nstate1!=maxstatenum || nstate2!=maxstatenum)
    //    printf("find nstate1=%d nstate2=%d\n", nstate1, nstate2);

    //-----------------------------------------------------
    // generate the joint-distribution table

    double	 *hab	= new double[nstate1 * nstate2];
    double	**hab2d	= new double *[nstate2];

    if( !hab || !hab2d )
    {
        SG_UI_Msg_Add_Error("Fail to allocate memory.");

        return( NULL );
    }

    for(j=0; j<nstate2; j++)
    {
        hab2d[j]	= hab + (long)j * nstate1;
    }

    for(i=0; i<nstate1; i++)
    {
        for(j=0; j<nstate2; j++)
        {
            hab2d[j][i]	= 0;
        }
    }

    for(i=0; i<len; i++)
    {
        // old method -- slow
        //    indx = (long)(vec2[i]) * nstate1 + vec1[i];
        //    hab[indx] += 1;

        // new method -- fast
        hab2d[vec2[i]][vec1[i]]	+= 1;
        //printf("vec2[%d]=%d vec1[%d]=%d\n", i, vec2[i], i, vec1[i]);
    }

    //-----------------------------------------------------
    // return the probabilities, otherwise return count numbers

    if( b_returnprob )
    {
        for(i=0; i<nstate1; i++)
        {
            for(j=0; j<nstate2; j++)
            {
                hab2d[j][i]	/= len;
            }
        }
    }

    //-----------------------------------------------------
    // finish

    DELETE_ARRAY(hab2d);
    DELETE_ARRAY(vec1);
    DELETE_ARRAY(vec2);

    return hab;
}