view opt.cpp @ 1:6422640a802f

first upload
author Wen X <xue.wen@elec.qmul.ac.uk>
date Tue, 05 Oct 2010 10:45:57 +0100
parents
children 5f3c32dc6e17
line wrap: on
line source
//---------------------------------------------------------------------------


#include <math.h>
#include <memory.h>
#include <stdlib.h>
#include "opt.h"
#include "matrix.h"

//---------------------------------------------------------------------------
//macro nsign: judges if two double-precision floating pointer numbers have different signs
#define nsign(x1, x2) (0x80&(((char*)&x1)[7]^((char*)&x2)[7]))

//---------------------------------------------------------------------------
/*
  function GradientMax: gradient method maximizing F(x)

  In: function F(x) and its derivative dF(x)
      start[dim]: initial value of x
      ep: a stopping threshold
      maxiter: maximal number of iterates
  Out: start[dim]: the final x

  Returnx max F(final x)
*/
double GradientMax(void* params, double (*F)(int, double*, void*), void (*dF)(double*, int, double*, void*),
  int dim, double* start, double ep, int maxiter)
{
  double oldG, G=F(dim, start, params), *dG=new double[dim], *X=new double[dim];

  int iter=0;
  do
  {
    oldG=G;

    dF(dG, dim, start, params);
    Search1Dmaxfrom(params, F, dim, start, dG, 1e-2, 1e-6, 1e6, X, &G, ep);
    memcpy(start, X, sizeof(double)*dim);

    iter++;
  }
  while (iter<maxiter && G>oldG*(1+ep));
  return G;
}//GradientMax

/*
  function GradientOneMax: gradient method maximizing F(x), which searches $dim dimensions one after
  another instead of taking the gradient descent direction.

  In: function F(x) and its derivative dF(x)
      start[dim]: initial value of x
      ep: a stopping threshold
      maxiter: maximal number of iterates
  Out: start[dim]: the final x

  Returnx max F(final x)
*/
double GradientOneMax(void* params, double (*F)(int, double*, void*), void (*dF)(double*, int, double*, void*),
  int dim, double* start, double ep, int maxiter)
{
  double oldG, G=F(dim, start, params), *dG=new double[dim], *X=new double[dim];

  int iter=0;
  do
  {
    oldG=G;
    for (int d=0; d<dim; d++)
    {
      dF(dG, dim, start, params);
      for (int i=0; i<dim; i++) if (d!=i) dG[i]=0;
      if (dG[d]!=0)
      {
        Search1Dmaxfrom(params, F, dim, start, dG, 1e-2, 1e-6, 1e6, X, &G, ep);
        memcpy(start, X, sizeof(double)*dim);
      }
    }
    iter++;
  }
  while (iter<maxiter && G>oldG*(1+ep));
  return G;
}//GradientOneMax

//---------------------------------------------------------------------------
/*
  function mindenormaldouble: returns the minimal denormal double-precision floating point number.
*/
double mindenormaldouble()
{
  double result=0;
  *((unsigned char*)&result)=1;
  return result;
}//mindenormaldouble

/*
  function minnormaldouble: returns the minimal normal double-precision floating point number.
*/
double minnormaldouble()
{
  double result=0;
  ((unsigned char*)&result)[6]=16;
  return result;
}//minnormaldouble

/*
  //function nextdouble: returns the next double value after x in the direction of dir
*/
double nextdouble(double x, double dir)
{
  if (x==0)
  {
    if (dir<0) return -mindenormaldouble();
    else return mindenormaldouble();
  }
  else if ((x>0)^(dir>0)) *((__int64*)&x)-=1;
  else *((__int64*)&x)+=1;
  return x;
}//nextdouble

/*
  function Newton: Newton method for finding the root of y(x)

  In: function y(x) and its derivative y'(x)
      params: additional argument for calling y and y'
      x0: inital value of x
      epx, epy: stopping thresholds on x and y respectively
      maxiter: maximal number of iterates
  Out: x0: the root

  Returns 0 if successful.
*/
double Newton(double& x0, double (*y)(double, void*), double (*y1)(double, void*), void* params, double epx, int maxiter, double epy)
{
  double y0=y(x0, params), x2, y2, dx, dy, x3, y3;
  if (y0==0) return 0;

  int iter=0;
  while (iter<maxiter)
  {
    dy=y1(x0, params);
    if (dy==0) return -1;
    x2=x0-y0/dy;
    y2=y(x2, params);
    while (fabs(y2)>fabs(y0))
    {
      x2=(x2+x0)/2;
      y2=y(x2, params);
    }
    if (y2==0)
    {
      x0=x2;
      return 0;
    }
    dx=fabs(x0-x2);
    if (dx==0)
    {
      if (fabs(y0)<epy) return 0;
      else return -1;
    }
    else if (dx<epx)
    {
      if nsign(y2, y0)
      {
        x0=x2;
        return dx;
      }
      else
      {
        x3=2*x2-x0;
        y3=y(x3, params);
        if (y3==0)
        {
          x0=x3;
          return 0;
        }
        if nsign(y2, y3)
        {
          x0=x2;
          return dx;
        }
        else if (fabs(y3)<fabs(y2))
        {
          x2=x3, y2=y3;
        }
      }
    }
    x0=x2;
    y0=y2;
    iter++;
  }
  if (fabs(y0)<epy) return 0;
  else return -1;
}//Newton

/*
  function Newton: Newton method for finding the root of y(x), for use when it's more efficient for y'
  and y to be calculated in one function call

  In: function dy(x) that computes y and y' at x
      params: additional argument for calling dy
      yshift: the byte shift in params where dy(x) put the value of y(x) as double type
      x0: inital value of x
      epx, epy: stopping thresholds on x and y respectively
      maxiter: maximal number of iterates
  Out: x0: the root

  Returns 0 if successful.
*/
int Newton(double& x0, double (*dy)(double, void*), void* params, int yshift, double epx, int maxiter, double epy, double xmin, double xmax)
{
  double y0, x2, y2, dx, dy0, dy2, dy3, x3, y3;
  dy0=dy(x0, params);
  y0=*(double*)((char*)params+yshift);
  if (y0==0) return 0;

  int iter=0;
  while (iter<maxiter)
  {
    if (dy0==0) return -1;
    dx=-y0/dy0;

    x2=x0+dx;
    dy2=dy(x2, params);
    y2=*(double*)((char*)params+yshift);
    //make sure the iteration yields a y closer to 0
    while (fabs(y2)>fabs(y0))
    {
      dx/=2;
      x2=x0+dx;
      dy2=dy(x2, params);
      y2=*(double*)((char*)params+yshift);
    }
    //the above may fail due to precision problem, i.e. x0+dx=x0
    if (x2==x0)
    {
      if (fabs(y0)<epy) return 0;
      else
      {
        x2=nextdouble(x0, dx);
        dy2=dy(x2, params);
        y2=*(double*)((char*)params+yshift);
        if (y2==0)
        {
          x0=x2;
          return 0;
        }
        else
        {
          dx=x2-x0;
          while (y2==y0)
          {
            dx*=2;
            x2=x0+dx;
            dy2=dy(x2, params);
            y2=*(double*)((char*)params+yshift);
          }
          if nsign(y2, y0)
            return fabs(dx);
          else if (fabs(y2)>fabs(y0))
            return -1;
        }
      }
    }
    else if (y2==0)
    {
      x0=x2;
      return 0;
    }
    else
    {
      double fabsdx=fabs(dx);
      if (fabsdx<epx)
      {
        if nsign(y2, y0)
        {
          x0=x2;
          return fabsdx;
        }
        else
        {
          x3=x2+dx;
          dy3=dy(x3, params);
          y3=*(double*)((char*)params+yshift);
          if (y3==0){x0=x3; return 0;}
          if nsign(y2, y3)
          {
            x0=x2;
            return dx;
          }
          else if (fabs(y3)<fabs(y2))
          {
            x2=x3, y2=y3, dy2=dy3;
          }
        }
      }
    }
    if (x2<xmin || x2>xmax) return -1;
    x0=x2;
    y0=y2;
    dy0=dy2;
    iter++;
  }
  if (fabs(y0)<epy) return 0;
  else return -1;
}//Newton

/*
  function init_Newton_1d: finds an initial x and interval (xa, xb) from which to search for an extremum

  On calling, xa<x0<xb, y(x0)>=y(xa), y(x0)>=y(xb) (or y(x0)<=y(xa), y(x0)<=y(xb)).
  On return, y(x0)>=y(xa), y(x0)>=y(xb) (or y(x0)<=y(xa), y(x0)<=y(xb)), and either y'(xa)>0, y'(xb)<0
  (or y'(xa)<0, y'(xb)>0), or xb-xa<epx.

  In: function dy(x) that computes y and y' at x
      params: additional argument for calling dy
      yshift: the byte shift in params where dy(x) put the value of y(x) as double type
      x0: inital value of x
      (xa, xb): initial search range
      epx: tolerable error of extremum
  Out: improved initial value x0 and search range (xa, xb)

  Returns xb-xa if successful, -0.5 or -0.6 if y(x0) is not bigger(smaller) than both y(xa) and y(xb)
*/
double init_Newton_1d(double& x0, double& xa, double& xb, double (*dy)(double, void*), void* params, int yshift, double epx)
{
  double dy0, dya, dyb, y0, ya, yb;
  dy0=dy(x0, params); y0=*(double*)((char*)params+yshift);
  dya=dy(xa, params); ya=*(double*)((char*)params+yshift);
  dyb=dy(xb, params); yb=*(double*)((char*)params+yshift);
  if (y0>=ya && y0>=yb)
  {
    //look for xa<x0<xb, ya<y0>yb, so that dya>0, dyb<0
    while ((dya<=0 || dyb>=0) && xb-xa>=epx)
    {
      double x1=(x0+xa)/2;
      double dy1=dy(x1, params);
      double y1=*(double*)((char*)params+yshift);
      double x2=(x0+xb)/2;
      double dy2=dy(x2, params);
      double y2=*(double*)((char*)params+yshift);
      if (y0>=y1 && y0>=y2) xa=x1, ya=y1, dya=dy1, xb=x2, yb=y2, dyb=dy2;
      else if (y1>=y0 && y1>=y2) {xb=x0, yb=y0, dyb=dy0; x0=x1, y0=y1, dy0=dy1;}
      else {xa=x0, ya=y0, dya=dy0; x0=x2, y0=y2, dy0=dy2;}
    }
    return xb-xa;
  }
  else if (y0<=ya && y0<=yb)
  {
    //look for xa<x0<xb, ya>y0<yb, so that dya<0, dyb>0
    while ((dya>=0 || dyb<=0) && xb-xa>=epx)
    {
      double x1=(x0+xa)/2;
      double dy1=dy(x1, params);
      double y1=*(double*)((char*)params+yshift);
      double x2=(x0+xb)/2;
      double dy2=dy(x2, params);
      double y2=*(double*)((char*)params+yshift);
      if (y0<=y1 && y0<=y2) xa=x1, ya=y1, dya=dy1, xb=x2, yb=y2, dyb=dy2;
      else if (y1<=y0 && y1<=y2) {xb=x0, yb=y0, dyb=dy0; x0=x1, y0=y1, dy0=dy1;}
      else {xa=x0, ya=y0, dya=dy0; x0=x2, y0=y2, dy0=dy2;}
    }
    return xb-xa;
  }
  else//meaning y(x0) is not bigger(smaller) than both y(xa) and y(xb)
  {
    if (y0<=yb) return -0.5; //ya<=y0<=yb
    if (y0<=ya) return -0.6; //ya>=y0>=yb
  }
  return -0;
}//init_Newton_1d

/*
  function init_Newton_1d_max: finds an initial x and interval (xa, xb) from which to search for an
  maximum.

  On calling xa<x0<xb, and it is assumed that y(x0)>=y(xa), y(x0)>=y(xb). If the conditions on y are met,
  it find a new set of xa<x0<xb, so that y(x0)>y(xa), y(x0)>=y(xb), y'(xa)>0, y'(xb)<0, or xb-xa<epx,
  and returns xb-xa>0; otherwise it returns a negative value showing the initial order of y(x0), y(xa)
  and y(xb) as
    -0.5 for ya<=y0<yb
    -0.6 for yb<=y0<ya
    -0.7 for y0<ya<yb
    -0.8 for y0<yb<=ya

  In: function dy(x) that computes y and y' at x
      params: additional argument for calling dy
      yshift: the byte shift in params where dy(x) put the value of y(x) as double type
      x0: inital value of x
      (xa, xb): initial search range
      epx: tolerable error of extremum
  Out: improved initial value x0 and search range (xa, xb)

  Returns xb-xa if successful, a negative value as above if not.
*/
double init_Newton_1d_max(double& x0, double& xa, double& xb, double (*dy)(double, void*), void* params, int yshift, double epx)
{
  double dy0, dya, dyb, y0, ya, yb;
  dy0=dy(x0, params); y0=*(double*)((char*)params+yshift);
  dya=dy(xa, params); ya=*(double*)((char*)params+yshift);
  dyb=dy(xb, params); yb=*(double*)((char*)params+yshift);
  if (y0>=ya && y0>=yb)
  {
    //look for xa<x0<xb, ya<y0>yb, so that dya>0, dyb<0
    while ((dya<=0 || dyb>=0) && xb-xa>=epx)
    {
      double x1=(x0+xa)/2;
      double dy1=dy(x1, params);
      double y1=*(double*)((char*)params+yshift);
      double x2=(x0+xb)/2;
      double dy2=dy(x2, params);
      double y2=*(double*)((char*)params+yshift);
      if (y0>=y1 && y0>=y2) xa=x1, ya=y1, dya=dy1, xb=x2, yb=y2, dyb=dy2;
      else if (y1>=y0 && y1>=y2) {xb=x0, yb=y0, dyb=dy0; x0=x1, y0=y1, dy0=dy1;}
      else {xa=x0, ya=y0, dya=dy0; x0=x2, y0=y2, dy0=dy2;}
    }
    return xb-xa;
  }
  else//meaning y(x0) is not bigger than both y(xa) and y(xb)
  {
    if (y0<yb && y0>=ya) return -0.5; //ya<=y0<yb
    if (y0<ya && y0>=yb) return -0.6; //ya>y0>=yb
    if (ya<yb) return -0.7; //y0<ya<yb
    return -0.8; //y0<yb<=ya
  }
}//init_Newton_1d_max

/*
  function init_Newton_1d_min: finds an initial x and interval (xa, xb) from which to search for an
  manimum.

  On calling xa<x0<xb, and it is assumed that y(x0)<=y(xa), y(x0)<=y(xb). If the conditions on y are met,
  it find a new set of xa<x0<xb, so that y(x0)<y(xa), y(x0)<=y(xb), y'(xa)<0, y'(xb)>0, or xb-xa<epx,
  and returns xb-xa>0; otherwise it returns a negative value showing the initial order of y(x0), y(xa)
  and y(xb) as
    -0.5 for ya<=y0<yb
    -0.6 for yb<=y0<ya
    -0.7 for y0>yb>ya
    -0.8 for y0>ya>=yb

  In: function dy(x) that computes y and y' at x
      params: additional argument for calling dy
      yshift: the byte shift in params where dy(x) put the value of y(x) as double type
      x0: inital value of x
      (xa, xb): initial search range
      epx: tolerable error of extremum
  Out: improved initial value x0 and search range (xa, xb)

  Returns xb-xa if successful, a negative value as above if not.
*/
double init_Newton_1d_min(double& x0, double& xa, double& xb, double (*dy)(double, void*), void* params, int yshift, double epx)
{
  double dy0, dya, dyb, y0, ya, yb;
  dy0=dy(x0, params); y0=*(double*)((char*)params+yshift);
  dya=dy(xa, params); ya=*(double*)((char*)params+yshift);
  dyb=dy(xb, params); yb=*(double*)((char*)params+yshift);
  if (y0<=ya && y0<=yb)
  {
    //look for xa<x0<xb, ya>y0<yb, so that dya<0, dyb>0
    while ((dya>=0 || dyb<=0) && xb-xa>=epx)
    {
      double x1=(x0+xa)/2;
      double dy1=dy(x1, params);
      double y1=*(double*)((char*)params+yshift);
      double x2=(x0+xb)/2;
      double dy2=dy(x2, params);
      double y2=*(double*)((char*)params+yshift);
      if (y0<=y1 && y0<=y2) xa=x1, ya=y1, dya=dy1, xb=x2, yb=y2, dyb=dy2;
      else if (y1<=y0 && y1<=y2) {xb=x0, yb=y0, dyb=dy0; x0=x1, y0=y1, dy0=dy1;}
      else {xa=x0, ya=y0, dya=dy0; x0=x2, y0=y2, dy0=dy2;}
    }
    return xb-xa;
  }
  else//meaning y(x0) is not bigger than both y(xa) and y(xb)
  {
    if (y0<yb && y0>=ya) return -0.5; //ya<=y0<yb
    if (y0<ya && y0>=yb) return -0.6; //ya>y0>=yb
    if (ya<yb) return -0.7; //ya<yb<y0
    return -0.8; //yb<=ya<y0
  }
}//init_Newton_1d_min

/*
  function Newton_1d_max: Newton method for maximizing y(x). On calling y(x0)>=y(xa), y(x0)>=y(xb),
  y'(xa)>0, y'(xb)<0

  In: function ddy(x) that computes y, y' and y" at x
      params: additional argument for calling ddy
      y1shift: the byte shift in params where ddy(x) put the value of y'(x) as double type
      yshift: the byte shift in params where ddy(x) put the value of y(x) as double type
      x0: inital value of x
      (xa, xb): initial search range
      epx, epdy: stopping threshold for x and y', respectively
      maxiter: maximal number of iterates
  Out: x0: the maximum

  Returns the error bound for the maximum x0, or
       -2 if y(*) do not satisfy input conditions
       -3 if y'(*) do not satisfy input conditions
*/
double Newton_1d_max(double& x0, double xa, double xb, double (*ddy)(double, void*), void* params, int y1shift, int yshift, double epx, int maxiter, double epdy, bool checkinput)
{
  double x1, y1, x2, y2, dx, dy1, dy2, dy3, x3, y3, ddy1, ddy2, ddy3;
  double y0, ya, yb, dy0, dya, dyb, ddy0;
  if (xb-xa<epx) {return xb-xa;}
  ddy(xa, params);
  dya=*(double*)((char*)params+y1shift), ya=*(double*)((char*)params+yshift);
  ddy(xb, params);
  dyb=*(double*)((char*)params+y1shift), yb=*(double*)((char*)params+yshift);
  ddy0=ddy(x0, params);
  dy0=*(double*)((char*)params+y1shift), y0=*(double*)((char*)params+yshift);

  if (checkinput)
  {
    if (y0>=ya && y0>=yb)
    {
      if (dya<=0 || dyb>=0) return -3;
    }
    else return -2;
  }

  if (dy0==0) return 0;

  int iter=0;
  while (iter<maxiter)
  {
    if (ddy0>=0) //newton method not applicable
    {
      do
      {
        x1=(x0+xa)/2;
        ddy1=ddy(x1, params);
        dy1=*(double*)((char*)params+y1shift), y1=*(double*)((char*)params+yshift);
        x2=(x0+xb)/2;
        ddy2=ddy(x2, params);
        dy2=*(double*)((char*)params+y1shift), y2=*(double*)((char*)params+yshift);
        if (y0>=y1 && y0>=y2) xa=x1, ya=y1, dya=dy1, xb=x2, yb=y2, dyb=dy2;
        else if (y1>=y0 && y1>=y2) {xb=x0, yb=y0, dyb=dy0; x0=x1, y0=y1, dy0=dy1, ddy0=ddy1;}
        else {xa=x0, ya=y0, dya=dy0; x0=x2, y0=y2, dy0=dy2, ddy0=ddy2;}
      }
      while(ddy0>=0 && (dya<=0 || dyb>=0) && xb-xa>=epx);
      if (xb-xa<epx) return xb-xa;
    }
    if (fabs(dy0)<epdy) return 0;
    //x2: Newton point
    //dx is the same direction as dy0 if ddy0<0
    dx=-dy0/ddy0;
    x2=x0+dx;
    if (x2==x0) return 0;

    //make sure x2 lies in [xa, xb]
    if (x2<xa) {x2=(xa+x0)/2; dx=x2-x0;}
    else if (x2>xb) {x2=(xb+x0)/2; dx=x2-x0;}
    ddy2=ddy(x2, params);
    y2=*(double*)((char*)params+yshift);

    //make sure the iteration yields a larger y
    if (y2<y0)
    {
      while (y2<y0 && dx>epx)
      {
        dx/=2;
        x2=x0+dx;
        ddy2=ddy(x2, params);
        y2=*(double*)((char*)params+yshift);
      }
      if (y2<y0) return fabs(dx);
    }

    //new x2 lies between xa and xb and y2>=y0
    dy2=*(double*)((char*)params+y1shift);
    if (fabs(dy2)<epdy){x0=x2; return 0;}

    double fabsdx=fabs(dx);
    if (fabsdx<epx)
    {
      if nsign(dy0, dy2){x0=x2; return fabsdx;}
      x3=x2+dx;
      ddy3=ddy(x3, params);
      dy3=*(double*)((char*)params+y1shift), y3=*(double*)((char*)params+yshift);
      if (dy3==0) {x0=x3; return 0;}
      if (y2>=y3) {x0=x2; return fabsdx;}
      else x2=x3, y2=y3, dy2=dy3, ddy2=ddy3;
    }

    if (x0<x2) xa=x0, ya=y0, dya=dy0;
    else xb=x0, yb=y0, dyb=dy0;
    x0=x2, y0=y2, dy0=dy2, ddy0=ddy2;
    iter++;
  }
  if (fabs(dy0)<epdy) return 0;
  else return -1;
}//Newton_1d_max

/*
  function Newton_1d_max: Newton method for maximizing y(x). On calling y(x0)<=y(xa), y(x0)<=y(xb),
  y'(xa)<0, y'(xb)>0

  In: function ddy(x) that computes y, y' and y" at x
      params: additional argument for calling ddy
      y1shift: the byte shift in params where ddy(x) put the value of y'(x) as double type
      yshift: the byte shift in params where ddy(x) put the value of y(x) as double type
      x0: inital value of x
      (xa, xb): initial search range
      epx, epdy: stopping threshold for x and y', respectively
      maxiter: maximal number of iterates
  Out: x0: the maximum

  Returns the error bound for the maximum x0, or
       -2 if y(*) do not satisfy input conditions
       -3 if y'(*) do not satisfy input conditions
*/
double Newton_1d_min(double& x0, double xa, double xb, double (*ddy)(double, void*), void* params, int y1shift, int yshift, double epx, int maxiter, double epdy, bool checkinput)
{
  double x1, y1, x2, y2, dx, dy1, dy2, dy3, x3, y3, ddy1, ddy2, ddy3;
  double y0, ya, yb, dy0, dya, dyb, ddy0;
  if (xb-xa<epx) {return xb-xa;}
  ddy(xa, params);
  dya=*(double*)((char*)params+y1shift), ya=*(double*)((char*)params+yshift);
  ddy(xb, params);
  dyb=*(double*)((char*)params+y1shift), yb=*(double*)((char*)params+yshift);
  ddy0=ddy(x0, params);
  dy0=*(double*)((char*)params+y1shift), y0=*(double*)((char*)params+yshift);

  if (checkinput)
  {
    if (y0<=ya && y0<=yb)
    {
      if (dya>=0 || dyb<=0) return -3;
    }
    else return -2;
  }

  if (dy0==0) return 0;

  int iter=0;
  while (iter<maxiter)
  {
    if (ddy0<=0) //newton method not applicable
    {
      do
      {
        x1=(x0+xa)/2;
        ddy1=ddy(x1, params);
        dy1=*(double*)((char*)params+y1shift), y1=*(double*)((char*)params+yshift);
        x2=(x0+xb)/2;
        ddy2=ddy(x2, params);
        dy2=*(double*)((char*)params+y1shift), y2=*(double*)((char*)params+yshift);
        if (y0<=y1 && y0<=y2) xa=x1, ya=y1, dya=dy1, xb=x2, yb=y2, dyb=dy2;
        else if (y1<=y0 && y1<=y2) {xb=x0, yb=y0, dyb=dy0; x0=x1, y0=y1, dy0=dy1, ddy0=ddy1;}
        else {xa=x0, ya=y0, dya=dy0; x0=x2, y0=y2, dy0=dy2, ddy0=ddy2;}
      }
      while((dya>=0 || dyb<=0) && xb-xa>=epx);
    }
    else
    {
      //Newton point
      //dx is the same direction as dy0 if ddy0<0
      if (fabs(dy0)<epdy) return 0;
      dx=-dy0/ddy0;
      x2=x0+dx;
      if (x2==x0) return 0;
      //make sure x2 lies in [xa, xb]
      if (x2<xa) {x2=(xa+x0)/2; dx=x2-x0;}
      else if (x2>xb) {x2=(xb+x0)/2; dx=x2-x0;}
      ddy2=ddy(x2, params);
      y2=*(double*)((char*)params+yshift);
      //make sure the iteration yields a larger y
      if (y2>y0)
      {
        while (y2>y0)
        {
          dx/=2;
          x2=x0+dx;
          ddy2=ddy(x2, params);
          y2=*(double*)((char*)params+yshift);
        }
        if (x2==x0) return 0; //dy0<0 but all y(x+(ep)dx)<0
      }
      dy2=*(double*)((char*)params+y1shift);
      if (fabs(dy2)<epdy)
      {
        x0=x2;
        return 0;
      }
      else
      {
        double fabsdx=fabs(dx);
        if (fabsdx<epx)
        {
          if nsign(dy2, dy0)
          {
            x0=x2;
            return fabsdx;
          }
          else
          {
            x3=x2+dx;
            ddy3=ddy(x3, params);
            dy3=*(double*)((char*)params+y1shift), y3=*(double*)((char*)params+yshift);
            if (dy3==0) {x0=x3; return 0;}
            if nsign(dy2, dy3)
            {
              x0=x2;
              return dx;
            }
            else if (y3<y2)
            {
              x2=x3, y2=y3, dy2=dy3, ddy2=ddy3;
            }
          }
        }
      }
      if (x0<x2) xa=x0, ya=y0, dya=dy0;
      else xb=x0, yb=y0, dyb=dy0;

      x0=x2, y0=y2, dy0=dy2, ddy0=ddy2;
    }

    iter++;
  }
  if (fabs(dy0)<epdy) return 0;
  else return -1;
}//Newton_1d_min

/*
  function Newton1dmax: uses init_Newton_1d_max and Newton_1d_max to search for a local maximum of y.

  By default ddy and dy use the same parameter structure and returns the lower order derivatives at
  specific offsets within that structure. However, since the same params is used, it's possible the same
  variable may take different offsets when returned from ddy() and dy().

  On calling xa<x0<xb, and it is assumed that y0>=ya, y0>=yb. If the conditions on y are not met, it
  returns a negative value showing the order of y0, ya and yb, i.e.
    -0.5 for ya<=y0<yb
    -0.6 for yb<=y0<ya
    -0.7 for y0<ya<yb
    -0.8 for y0<yb<=ya

  In: function ddy(x) that computes y, y' and y" at x
      function dy(x) that computes y and y' at x
      params: additional argument for calling ddy and dy
      y1shift: the byte shift in params where ddy(x) put the value of y'(x) as double type
      yshift: the byte shift in params where ddy(x) put the value of y(x) as double type
      dyshift: the byte shift in params where dy(x) put the value of y(x) as double type
      x0: inital value of x
      (xa, xb): initial search range
      epx, epdy: stopping threshold for x and y', respectively
      maxiter: maximal number of iterates
  Out: x0: the maximum

  Returns the error bound for maximum x0, or a negative value if the initial point does not satisfy
  relevent assumptions.
*/
double Newton1dmax(double& x0, double xa, double xb, double (*ddy)(double, void*), void* params, int y1shift, int yshift, double (*dy)(double, void*), int dyshift, double epx, int maxiter, double epdy, bool checkinput)
{
  double ep=init_Newton_1d_max(x0, xa, xb, dy, params, dyshift, epx);
  if (ep>epx) ep=Newton_1d_max(x0, xa, xb, ddy, params, y1shift, yshift, epx, maxiter, epdy, true);
  return ep;
}//Newton1dmax

//function Newton1dmin: same as Newton1dmax, in the other direction.
double Newton1dmin(double& x0, double xa, double xb, double (*ddy)(double, void*), void* params, int y1shift, int yshift, double (*dy)(double, void*), int dyshift, double epx, int maxiter, double epdy, bool checkinput)
{
  double ep=init_Newton_1d_min(x0, xa, xb, dy, params, dyshift, epx);
  if (ep>epx) ep=Newton_1d_min(x0, xa, xb, ddy, params, y1shift, yshift, epx, maxiter, epdy, true);
  return ep;
}//Newton1dmin

/*
  function NewtonMax: looks for the maximum of y within [x0, x1] using Newton method.

  In: function ddy(x) that computes y, y' and y" at x
      params: additional argument for calling ddy
      y1shift: the byte shift in params where ddy(x) put the value of y'(x) as double type
      yshift: the byte shift in params where ddy(x) put the value of y(x) as double type
      (x0, x1): initial search range
      epx, epy: stopping threshold for x and y, respectively
      maxiter: maximal number of iterates
  Out: maximum x0

  Returns an error bound on maximum x0 if successful, a negative value if not.
*/
double NewtonMax(double& x0, double x1, double (*ddy)(double, void*), void* params, int y1shift, int yshift, double epx, int maxiter, double epy)
{
  double y0, x2, y2, dx, dy0, dy2, dy3, x3, y3;
  dy0=ddy(x0, params);
  y0=*(double*)((char*)params+yshift);
  if (y0==0) return 0;

  int iter=0;
  while (iter<maxiter)
  {
    if (dy0==0) return -1;
    dx=-y0/dy0;

    x2=x0+dx;
    dy2=ddy(x2, params);
    y2=*(double*)((char*)params+yshift);
    //make sure the iteration yields a y closer to 0
    while (fabs(y2)>fabs(y0))
    {
      dx/=2;
      x2=x0+dx;
      dy2=ddy(x2, params);
      y2=*(double*)((char*)params+yshift);
    }
    //the above may fail due to precision problem, i.e. x0+dx=x0
    if (x2==x0)
    {
      if (fabs(y0)<epy) return 0;
      else
      {
        x2=nextdouble(x0, dx);
        dy2=ddy(x2, params);
        y2=*(double*)((char*)params+yshift);
        if (y2==0)
        {
          x0=x2;
          return 0;
        }
        else
        {
          dx=x2-x0;
          while (y2==y0)
          {
            dx*=2;
            x2=x0+dx;
            dy2=ddy(x2, params);
            y2=*(double*)((char*)params+yshift);
          }
          if nsign(y2, y0)
            return fabs(dx);
          else if (fabs(y2)>fabs(y0))
            return -1;
        }
      }
    }
    else if (y2==0)
    {
      x0=x2;
      return 0;
    }
    else
    {
      double fabsdx=fabs(dx);
      if (fabsdx<epx)
      {
        if nsign(y2, y0)
        {
          x0=x2;
          return fabsdx;
        }
        else
        {
          x3=x2+dx;
          dy3=ddy(x3, params);
          y3=*(double*)((char*)params+yshift);
          if (y3==0){x0=x3; return 0;}
          if nsign(y2, y3)
          {
            x0=x2;
            return dx;
          }
          else if (fabs(y3)<fabs(y2))
          {
            x2=x3, y2=y3, dy2=dy3;
          }
        }
      }
    }
    x0=x2;
    y0=y2;
    dy0=dy2;
    iter++;
  }
  if (fabs(y0)<epy) return 0;
  else return -1;
}//NewtonMax

//---------------------------------------------------------------------------
/*
  function rootsearchhalf: searches for the root of y(x) in (x1, x2) by half-split method. On calling
  y(x1) and y(x2) must not have the same sign, or -1 is returned signaling a failure.

  In: function y(x),
      params: additional arguments for calling y
      (x1, x2): inital range
      epx: stopping threshold on x
      maxiter: maximal number of iterates
  Out: root x1

  Returns a positive error estimate if a root is found, -1 if not.
*/
double rootsearchhalf(double&x1, double x2, double (*y)(double, void*), void* params, double epx, int maxiter)
{
  if (x1>x2) {double tmp=x1; x1=x2; x2=tmp;}
  double y1=y(x1, params), y3, x3, ep2=epx*2;
  if (y1==0) return 0;
  else
  {
    double y2=y(x2, params);
    if (y2==0)
    {
      x1=x2;
      return 0;
    }
    else if nsign(y1, y2) //y1 and y2 have different signs
    {
      int iter=0;
      while (x2-x1>ep2 && iter<maxiter)
      {
        x3=(x1+x2)/2;
        y3=y(x3, params);
        if (y3==0)
        {
          x1=x3;
          return 0;
        }
        else
        {
          if nsign(y1, y3) x2=x3, y2=y3;
          else x1=x3, y1=y3;
        }
        iter++;
      }
      x1=(x1+x2)/2;
      return x2-x1;
    }
    else
      return -1;
  }
}//rootsearchhalf

//---------------------------------------------------------------------------
/*
  function rootsearchsecant: searches for the root of y(x) in (x1, x2) by secant method.

  In: function y(x),
      params: additional arguments for calling y
      (x1, x2): inital range
      epx: stopping threshold on x
      maxiter: maximal number of iterates
  Out: root x1

  Returns a positive error estimate if a root is found, -1 if not.
*/
double rootsearchsecant(double& x1, double x2, double (*y)(double, void*), void* params, double epx, int maxiter)
{
  double y1=y(x1, params), y2=y(x2, params), y3, x3, dx, x0, y0;
  if (y1==0) return 0;
  if (y2==0)
  {
    x1=x2;
    return 0;
  }
  if (fabs(y1)>fabs(y2))
  {
    x3=x1, y3=y1;
  }
  else
  {
    x3=x2, y3=y2;
    x2=x1, y2=y1;
  }

  int iter=0;
  while (iter<maxiter)
  {
    x1=(y3*x2-y2*x3)/(y3-y2);
    y1=y(x1, params);

    dx=fabs(x1-x2);
    if (dx<epx)
    {
      if nsign(y1, y2)
      {
        return dx;
      }
      else
      {
        x0=2*x1-x2;
        y0=y(x0, params);
        if nsign(y0, y1)
        {
          return dx;
        }
      }
    }
    x3=x2, y3=y2;
    x2=x1, y2=y1;
    iter++;
  }
  return -1;
}//rootsearchsecant

/*
  function rootsearchbisecant: searches for the root of y(x) in (x1, x2) by bi-secant method. On calling
  given that y(x1) and y(x2) have different signs. The bound interval (x1, x2) converges to 0, as
  compared to standared secant method.

  In: function y(x),
      params: additional arguments for calling y
      (x1, x2): inital range
      epx: stopping threshold on x
      maxiter: maximal number of iterates
  Out: root x1

  Returns an estimated error bound if a root is found, a negative value if not.
*/
double rootsearchbisecant(double&x1, double x2, double (*y)(double, void*), void* params, double epx, int maxiter)
{
  if (x1>x2) {double tmp=x1; x1=x2; x2=tmp;}
  double y1=y(x1, params), y3, y4, dy2, dy3, x3, x4, ep2=epx*2;
  if (y1==0) return 0;
  else
  {
    double y2=y(x2, params);
    if (y2==0)
    {
      x1=x2;
      return 0;
    }
    else if nsign(y1, y2) //y1 and y2 have different signs
    {
      int iter=0;
      while (x2-x1>ep2 && iter<maxiter)
      {
        dy2=y1-y2;
        x3=(y1*x2-y2*x1)/dy2;
        y3=y(x3, params);
        if (y3==0)
        {
          x1=x3;
          return 0;
        }
        else
        {
          if nsign(y1, y3)
          {
            dy3=y3-y2;
            if (dy3==0 || nsign(dy3, dy2)) x2=x3, y2=y3;
            else
            {
              x4=(y3*x2-y2*x3)/dy3; //x4<x3
              if (x4<=x1) x2=x3, y2=y3;
              else
              {
                y4=y(x4, params);
                if (y4==0)
                {
                  x1=x4;
                  return 0;
                }
                else
                {
                  if nsign(y4, y3) x1=x4, y1=y4, x2=x3, y2=y3;
                  else x2=x4, y2=y4;
                }
              }
            }
          }
          else
          {
            dy3=y1-y3;
            if (dy3==0 || nsign(dy3, dy2)) x1=x3, y1=y3;
            else
            {
              x4=(y1*x3-y3*x1)/dy3; //x4>x3
              if (x4>=x2) x1=x3, y1=y3;
              else
              {
                y4=y(x4, params);
                if (y4==0)
                {
                  x1=x4;
                  return 0;
                }
                else
                {
                  if nsign(y4, y3) x1=x3, y1=y3, x2=x4, y2=y4;
                  else x1=x4, y1=y4;
                }
              }
            }
          }
        }
        iter++;
      }
      x1=(x1+x2)/2;
      return x2-x1;
    }
    else
      return -1;
  }
}//rootsearchbisecant

//---------------------------------------------------------------------------
/*
  function Search1Dmax: 1-dimensional maximum search within interval [inf, sup] using 0.618 method

  In: function F(x),
      params: additional arguments for calling F
      (inf, sup): inital range
      epx: stopping threshold on x
      maxiter: maximal number of iterates
      convcheck: specifies if convexity is checked at each interate, false recommended.
  Out: x: the maximum
       maxresult: the maximal value, if specified

  Returns an estimated error bound of x if successful, a negative value if not.
*/
double Search1Dmax(double& x, void* params, double (*F)(double, void*), double inf, double sup, double* maxresult, double ep, int maxiter, bool convcheck)
{
  double v0618=(sqrt(5.0)-1)/2, iv0618=1-v0618;
  double l=sup-inf;
  double startsup=sup, startinf=inf, startl=l;
  double x1=inf+l*(1-v0618);
  double x2=inf+l*v0618;
  double result;

  double v0=F(inf, params);
  double v1=F(x1, params);
  double v2=F(x2, params);
  double v3=F(sup, params);
  int iter=0;

  if (v1<v0 && v1<v3 && v2<v0 && v2<v3) goto return1;
  if (convcheck && (v1<v0*v0618+v3*iv0618 || v2<v0*iv0618+v3*v0618 || v1<v0*iv0618+v2*v0618 || v2<v1*v0618+v3*iv0618)) goto return1;

  while (iter<maxiter)
  {
    if (l<startl*ep) break;
    if (v1>v2)
    {
      sup=x2, v3=v2;
      l=sup-inf;
      x2=x1, v2=v1;
      x1=inf+l*(1-v0618);
      v1=F(x1, params);
      if (convcheck && (v1<v0*v0618+v3*iv0618 || v1<v0*iv0618+v2*v0618 || v2<v1*v0618+v3*iv0618)) goto return1;
    }
    else
    {
      inf=x1, v0=v1;
      l=sup-inf;
      x1=x2, v1=v2;
      x2=inf+l*v0618;
      v2=F(x2, params);
      if (convcheck && (v2<v0*iv0618+v3*v0618 || v1<v0*iv0618+v2*v0618 || v2<v1*v0618+v3*iv0618)) goto return1;
    }
    iter++;
  }
  if (v1>v2) {x=x1; if (maxresult) maxresult[0]=v1; result=x1-inf;}
  else {x=x2; if (maxresult) maxresult[0]=v2; result=sup-x2;}
  return result;

return1: //where at some stage v(.) fails to be convex
  if (v0>=v1 && v0>=v2 && v0>=v3){x=inf; if (maxresult) maxresult[0]=v0; result=(x==startinf)?(-1):(sup-x1);}
  else if (v1>=v0 && v1>=v2 && v1>=v3){x=x1; if (maxresult) maxresult[0]=v1; result=x1-inf;}
  else if (v2>=v0 && v2>=v1 && v2>=v3){x=x2; if (maxresult) maxresult[0]=v2; result=sup-x2;}
  else {x=sup; if (maxresult) maxresult[0]=v3; result=(x==startsup)?(-1):(x2-inf);}
  return result;
}//Search1Dmax

/*
  function Search1DmaxEx: 1-dimensional maximum search using Search1Dmax, but allows setting a $len
  argument so that a pre-location of the maximum is performed by sampling (inf, sup) at interval $len,
  so that Search1Dmax will work on an interval no longer than 2*len.

  In: function F(x),
      params: additional arguments for calling F
      (inf, sup): inital range
      len: rough sampling interval for pre-locating maximum
      epx: stopping threshold on x
      maxiter: maximal number of iterates
      convcheck: specifies if convexity is checked at each interate, false recommended.
  Out: x: the maximum
       maxresult: the maximal value, if specified

  Returns an estimated error bound of x if successful, a negative value if not.
*/
double Search1DmaxEx(double& x, void* params, double (*F)(double, void*), double inf, double sup, double* maxresult, double ep, int maxiter, double len)
{
  int c=ceil((sup-inf)/len+1);
  if (c<8) c=8;
  double* vs=new double[c+1], step=(sup-inf)/c;
  for (int i=0; i<=c; i++) vs[i]=F(inf+step*i, params);
  int max=0; for (int i=1; i<=c; i++) if (vs[max]<vs[i]) max=i;
  *maxresult=vs[max]; delete[] vs;
  if (max>0 && max<c) return Search1Dmax(x, params, F, inf+step*(max-1), inf+step*(max+1), maxresult, ep, maxiter);
  else if (max==0)
  {
    if (step<=ep) {x=inf; return ep;}
    else return Search1DmaxEx(x, params, F, inf, inf+step, maxresult, ep, maxiter, len);
  }
  else
  {
    if (step<=ep) {x=sup; return ep;}
    else return Search1DmaxEx(x, params, F, sup-step, sup, maxresult, ep, maxiter, len);
  }
}//Search1DmaxEx

/*
  function Search1Dmaxfrom: 1-dimensional maximum search from start[] towards start+direct[]. The
  function tries to locate an interval ("step") for which the 4-point convexity rule confirms the
  existence of a convex maximum.

  In: function F(x)
      params: additional arguments for calling F
      start[dim]: initial x[]
      direct[dim]: search direction
      step: initial step size
      minstep: minimal step size in 4-point scheme between x0 and x3
      maxstep: maximal step size in 4-point scheme between x0 and x3
  Out: opt[dim]: the maximum, if specified
       max: maximal value, if specified

  Returns x>0 that locally maximizes F(start+x*direct)
    or x|-x>0 that maximizes F(start-x*direct) at calculated points if convex check fails.
*/
double Search1Dmaxfrom(void* params, double (*F)(int, double*, void*), int dim, double* start, double* direct,
  double step, double minstep, double maxstep, double* opt, double* max, double ep, int maxiter, bool convcheck)
{
  bool record=true;
  if (!opt)
  {
    record=false;
    opt=new double[dim];
  }
  
  double v0618=(sqrt(5.0)-1)/2, iv0618=1-v0618;
  double x3=step, x0=0, x1=-1, x2=-1, l=x3-x0;

  //prepares x0~x3, v0~v3, x0=0, v2>v3
  memcpy(opt, start, sizeof(double)*dim);
  double v0=F(dim, opt, params);
  MultiAdd(dim, opt, start, direct, x3);
  double v1, v2, v3=F(dim, opt, params);
  if (v0>=v3)
  {
    x1=x0+l*iv0618;
    MultiAdd(dim, opt, start, direct, x1);
    v1=F(dim, opt, params);
    x2=x0+l*v0618;
    MultiAdd(dim, opt, start, direct, x2);
    v2=F(dim, opt, params);
    while (l>minstep && v0>v1)
    {
      x3=x2, v3=v2;
      x2=x1, v2=v1;
      l=x3-x0;
      x1=x0+l*iv0618;
      MultiAdd(dim, opt, start, direct, x1);
      v1=F(dim, opt, params);
    }
    if (l<=minstep)
    {
      if (max) max[0]=v0;
      if (!record) delete[] opt;
      return x0;
    }
  }
  else//v0<=v3
  {
    do
    {
      x1=x2, v1=v2;
      x2=x3, v2=v3;
      x3+=l*v0618;
      l=x3-x0;
      MultiAdd(dim, opt, start, direct, x3);
      v3=F(dim, opt, params);
    } while (v2<v3 && x3-x0<maxstep);
    if (l>=maxstep) //increasing all the way to maxstep
    {
      if (max) max[0]=v3;
      if (!record) delete opt;
      return x3;
    }
    else if (x1<0)
    {
      x1=x0+l*iv0618;
      MultiAdd(dim, opt, start, direct, x1);
      v1=F(dim, opt, params);
    }
  }

  double oldl=l;

  int iter=0;

  if (convcheck && (v1<v0*v0618+v3*iv0618 || v2<v0*iv0618+v3*v0618
    || v1<v0*iv0618+v2*v0618 || v2<v1*v0618+v3*iv0618)) goto return1;

  while (iter<maxiter)
  {
    if (l<oldl*ep) break;
    if (v1>v2)
    {
      x3=x2, v3=v2;
      l=x3-x0;
      x2=x1, v2=v1;
      x1=x0+l*iv0618;
      MultiAdd(dim, opt, start, direct, x1);
      v1=F(dim, opt, params);
      if (convcheck && (v1<v0*v0618+v3*iv0618 || v1<v0*iv0618+v2*v0618 || v2<v1*v0618+v3*iv0618)) goto return1;
    }
    else
    {
      x0=x1, v0=v1;
      l=x3-x0;
      x1=x2, v1=v2;
      x2=x0+l*v0618;
      MultiAdd(dim, opt, start, direct, x2);
      v2=F(dim, opt, params);
      if (convcheck && (v2<v0*iv0618+v3*v0618 || v1<v0*iv0618+v2*v0618 || v2<v1*v0618+v3*iv0618)) goto return1;
    }
    iter++;
  }

  if (!record) delete[] opt;

  if (max) max[0]=v1;
  return x1;

return1:
  if (!record) delete[] opt;
  if (v1>v0) v0=v1,x0=x1; if (v2>v0) v0=v2, x0=x2; if (v3>v0) v0=v3, x0=x3;
  if (max) max[0]=v0;
  return -x0;
}//Search1Dmaxfrom