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