Thanks Michael, my thoughts exactly -- that was the first thing that
jumped out at me. Here's my reformulation, with a few notes:
0. Scaling is very important -- it is often a good idea to scale your
variables and equations such that their ranges is approximately within
the [1,1000] range. Otherwise, you'll hit all kinds of numerical
conditioning problems (your Jacobians become ill-conditioned), and
solvers may have a hard time converging (or will converge to a
meaningless answer).
1. Variable scaling: All lengths
(MpW,MpL,MnW,MnL,minWidth,minLength,maxWidth,maxLength,LdNmos,LdPmos)
have been multiplied by 1e6 -- they are now in "mega" units. All other
variables retain their original units.
2. Equation scaling: equations with small LHS and RHS have been
premultiplied on both sides. (see constraints c1, c2, EqualCurrent)
3. Bound constraints have been rewritten as variable bounds, ie. var
x, >= U, <= L. Some solvers treat simple bounds specially, so this
formulation will aid those solvers.
4. Dummy variables (dummy1,dummy2) were introduced to remove the
divisions (quotients). Divisions are bad because they give rise to
more nonlinear Jacobian elements, and there is sometimes a possibility
of divisions by 0 during iterations.
5. This looks like a bilinear program. You can get pretty tight convex
over and underestimators for these to guide the solvers. The tightest
possible relaxation for bilinear terms (if you know the variable
bounds) are McCormick relaxations.
# ------------------------------------------------------
# Constants
param LdNmos := 4e-02; # was 4e-08
param LdPmos := 5e-02; # was 5e-08
param minWidth := 4e-01; # was 4e-07
param minLength := 3.5e-01; # was 3.5e-07
param maxWidth := 2e2; # was 0.0002
param maxLength := 2e1; # was 2e-05
param out := 1.65;
param MpCurFac := 1.144981598e-05;
param MpVth := 0.6798;
param MnCurFac := 6.455286683e-05;
param MnVth := 0.5591;
param Vnbias := 1;
param Vdd := 3.3;
# Variables
var MpW, >= minWidth, <= maxWidth := 1; # was 1e-06
var MpL, >= minLength, <= maxLength := 1; # was 1e-06
var MnW, >= minWidth, <= maxWidth := 1; # was 1e-06
var MnL, >= minLength, <= maxLength := 1; # was 1e-06
var Vpbias := 1.353;
var MnId;
var MpId;
var dummy1;
var dummy2;
# Objective
minimize area: MnW*MnL+MpW*MpL;
subject to
# Constraints
c1: 1e6 * MnId = 1e6 * MnCurFac*dummy1*(Vnbias-MnVth)^2;
c2: 1e6 * MpId = 1e6 * MpCurFac*dummy2*(Vdd-Vpbias-MpVth)^2;
c3: dummy1*(MnL-2*LdNmos) = MnW;
c4: dummy2*(MpL-2*LdPmos) = MpW;
SatP: out <= Vpbias + MpVth;
SatP2: Vdd - Vpbias >= MpVth;
EqualCurrent: 1e6 * MnId = 1e6 * MpId;
# Solve
option solver couenne;
solve;
printf "startWriteVars\n";
display area,MpW, MpL, MnW, MnL, Vpbias, MnId, MpId, dummy1, dummy2;
printf "endWriteVars\n";
display area.result;
display area.result_num;
display area.message;
display area.exitcode;
# ------------------------------------------------------
I invoked the Couenne solver (a global solver) and I managed to get a
global solution. (Incidentally, Couenne failed on the unscaled problem
-- I guess the convex envelopes must have been near infeasible because
the numbers were so close to the numerical tolerance). Here's the
output:
------------------------------------------------------
couenne: ANALYSIS TEST: Problem size before reformulation: 9 variables
(0 integer), 5 constraints.
Problem size after reformulation: 19 variables (0 integer), 1
constraints.
******************************************************************************
This program contains Ipopt, a library for large-scale nonlinear
optimization.
Ipopt is released as open source code under the Common Public License
(CPL).
For more information visit
http://projects.coin-or.org/Ipopt
******************************************************************************
Cbc0012I Integer solution of 0.28 found by Init Rounding NLP after 0
iterations and 0 nodes (-0.00 seconds)
Cbc0001I Search completed - best objective 0.2800000037782208, took 0
iterations and 0 nodes (0.00 seconds)
Cbc0035I Maximum depth 0, 0 variables fixed on reduced cost
"Finished"
couenne: Optimal
startWriteVars
area = 0.28
MpW = 0.4
MpL = 0.35
MnW = 0.4
MnL = 0.35
Vpbias = 1.61284
MnId = 1.85905e-05
MpId = 1.85905e-05
dummy1 = 1.48148
dummy2 = 1.6
endWriteVars
area.result = solved
area.result_num = 3
area.message = '\
couenne: Optimal'
area.exitcode = 0
# ------------------------------------------------------
Here are results from some local NLP solvers:
# ------------------------------------------------------
Ipopt 3.8.2:
area = 0.28
MpW = 0.4
MpL = 0.35
MnW = 0.4
MnL = 0.35
Vpbias = 1.61284
MnId = 1.85905e-05
MpId = 1.85905e-05
dummy1 = 1.48148
dummy2 = 1.6
# ------------------------------------------------------
SNOPT 7.2-8
area = 0.28
MpW = 0.4
MpL = 0.35
MnW = 0.4
MnL = 0.35
Vpbias = 1.61284
MnId = 1.85905e-05
MpId = 1.85905e-05
dummy1 = 1.48148
dummy2 = 1.6
# ------------------------------------------------------
CONOPT 3.14G
area = 0.28
MpW = 0.4
MpL = 0.35
MnW = 0.4
MnL = 0.35
Vpbias = 1.61284
MnId = 1.85905e-05
MpId = 1.85905e-05
dummy1 = 1.48148
dummy2 = 1.6
So it looks like all the solvers managed to get to the global solution
(area = 0.28 megaunits = 2.8e-7 in original units) from the given
initial guess. Lucky...
But the only way to be sure is to check it with global solvers like
Couenne or LaGO. (both free and available as AMPL solvers).
David
> >
ampl+uns...@googlegroups.com <
ampl%2Bunsu...@googlegroups.com>.