printf( "Starting the npsol test...\n" );

assert = strip (function (t)
{
  if (!test(t))
  {
    message ("...failed.\a");
    exception ();
  }
});

#  This code attempts to find the polygon with largest area among all
#  polygons with N sides and diameter no greater than one.  For N odd
#  the answer is a regular polygon, but that's not the case when N is
#  even.  (For quadrilaterals, though, the regular figure has the same
#  area as the non-regular solution.)

#  More information, and some optimization program benchmarks, may be
#  found at http://www-unix.mcs.anl.gov/~more/cops/bcops/polygon.html.

#  I stuck this here mainly because I thought it was cool, the npsol
#  performance seemed to compare pretty well with the benchmarked
#  codes, and because I'm a packrat.

#  The design variables are stored in a vector as pairs of distance
#  and angle.  The final vertex is taken at the origin.

dv2r = function (dv)
{
  dv = vector (dv);
  return dv [1:dv.ne:2];
};

dv2theta = function (dv)
{
  dv = vector (dv);
  return dv [2:dv.ne:2];
};

objf = function (dv)
{
  local (r; theta; r1; r2);

  r = dv2r (dv);
  theta = dv2theta (dv);

  r1 = r[1:r.ne-1];
  r2 = r[2:r.ne];

  return - 0.5 * sum (r1 @ r2 @ sin (diff (theta)));
};

objgrd = function (dv)
{
  local (r; theta; r1; r2; dt; st; ct; n; g);

  dv = vector (dv);
  r = dv2r (dv);
  theta = dv2theta (dv);

  r1 = r[1:r.ne-1];
  r2 = r[2:r.ne];
  dt = diff (theta);
  st = sin (dt);
  ct = cos (dt);

  n = dv.ne;
  g = fill (n; 0.0);
  g[1:n-3:2] = r2 @ st;
  g[3:n:2] += r1 @ st;
  g[2:n-2:2] = - r1 @ r2 @ ct;
  g[4:n:2] += r1 @ r2 @ ct;

  return -g/2;
};

conf = function (dv)
{
  local (r; theta; n; nc; i; j; k; c);

  r = dv2r (dv);
  n = r.ne;
  theta = dv2theta (dv);

  nc = n*(n-1)/2 + (n-1);
  c = fill (nc; 0.0);

  k = 0;
  for (i in seq(n-1))
  {
    for (j in i+1:n)
    {
      c[k+=1] = 1.0 - r[i]^2 - r[j]^2 + 2.0*r[i]*r[j]*cos(theta[j]-theta[i]);
    }
  }

  for (i in seq(n-1))
  {
    c[k+=1] = theta[i+1] - theta[i];
  }

  return c;
};

congrd = function (dv)
{
  local (r; theta; n; nc; i; j; k; c);

  r = dv2r (dv);
  n = r.ne;
  theta = dv2theta (dv);

  nc = n*(n-1)/2 + (n-1);
  c = fill (nc,dv.ne; 0.0);

  k = 0;
  for (i in seq(n-1))
  {
    for (j in i+1:n)
    {
      k += 1;
      c[k;2*i-1] = 2.0 * (r[j]*cos(theta[j]-theta[i]) - r[i]);
      c[k;2*j-1] = 2.0 * (r[i]*cos(theta[j]-theta[i]) - r[j]);
      c[k;2*i] = 2.0*r[i]*r[j]*sin(theta[j]-theta[i]);
      c[k;2*j] = -2.0*r[i]*r[j]*sin(theta[j]-theta[i]);
    }
  }

  for (i in seq(n-1))
  {
    k += 1;
    c[k;2*i] = -1.0;
    c[k;2*(i+1)] = 1.0;
  }

  return c;
};

crd = function (dv)
{
  local (r; theta);

  r = dv2r (dv);
  theta = dv2theta (dv);

  return 0.0, label (r@sin(theta); r@cos(theta)), 0.0;
};

sides = function (dv)
{
  local (s; n);

  dv = vector (dv);
  n = dv.ne;
  s = fill (n,2; 0.0);

  s [1:n; 1] = 0.0;
  s [1:n:2; 2] = 1.0;
  s [2:n:2; 2] = acos (-1);

  return s;
};

bounds = function (dv)
{
  local (b; n);

  n = conf(dv).ne;
  b = fill (n,2; 0.0);

  b [;1] = 0.0;
  b [;2] = 1e10;

  return b;
};

start = function (n)
{
  local (i; pi; z; s);

  i = sqrt (-1);
  pi = acos (-1);

  z = (exp (i*(2*pi*seq(n)/n-pi/2)) + i) / 2;

  s = fill (2*n; 0.0);
  s [1:2*n:2] = abs (z);
  s [2:2*n:2] = atan2 (imag (z); real (z));

  return s[1:s.ne-2];
};

go = function (n)
{
  local (s);

  n = vector (n);
  if (n.ne == 1)
  {
    s = start (n[1]);
  elseif (n.ne%2)
    message ("start vector must have even length");
    exception ();
  elseif (n.ne >= 4)
    s = n;
  else
    message ("start vector too short");
    exception ();
  }
  
  return npsol ({objf; objgrd}; s;
		{side_constraints = sides(s);
		 nonlinear_constraints = {values = {conf; congrd};
					  bounds = bounds(s);
					 }};
		{derivative_level = 3; verify_level = -1});
};

nudge = function (n)
{
  local (i; pi; z; s);

  i = sqrt (-1);
  pi = acos (-1);

  z = (exp (i*(2*pi*sort(rand(n))-pi/2)) + i) / 2;

  s = fill (2*n; 0.0);
  s [1:2*n:2] = abs (z);
  s [2:2*n:2] = atan2 (imag (z); real (z));

  return s[1:s.ne-2];
};

tries = function (n; N)
{
  local (i; r; rr; v);

  r = go (n);
  v = r.objective;

  for (i in 1:N)
  {
    rr = go (nudge (n));
    if (rr.objective < v)
    {
      r = rr;
      v = r.objective;
    }
  }

  return r;
};

poly = function (n)
{
  local (r);
  r = tries (n; 5);
  plot (crd (adjust (r.solution)); crd (start (50)); 1);
  return -r.objective;
};

adjust = function (dv)
{
  dv[2:dv.ne:2] += (acos(1-2*min(dv[1],1)^2)/2 - dv[2] +
		    acos(-1)-acos(1-2*min(dv[dv.ne-1],1)^2)/2 - dv[dv.ne]) / 2;
  return dv;
};


if (npsol)
{

    npsol_test_fn = function( x )
    {
	local( x1; x2 );
	x1 = scalar( x[1] ); x2 = scalar( x[2] );
	return x1^4 - 4*x1*x2 + x2^4;
    };

    N = npsol( npsol_test_fn; 10,10; {}; { deriv = 0 } );

    assert (norm( N.solution - (1,1) ) < 1e-5);

    assert (abs (tries(5; 10).objective + 0.6571638901) < 1e-7);

    printf ("...passed.\n");

else

    printf ("...skipped.\n");
}


syntax highlighted by Code2HTML, v. 0.9.1