6.6 Geometric Programming¶
Geometric programs (GP) are a particular class of optimization problems which can be expressed in special polynomial form as positive sums of generalized monomials. More precisely, a geometric problem in canonical form is
where each \(f_0,\ldots,f_m\) is a posynomial, that is a function of the form
with arbitrary real \(\alpha_{ki}\) and \(c_k>0\). The standard way to formulate GPs in convex form is to introduce a variable substitution
Under this substitution all constraints in a GP can be reduced to the form
involving a log-sum-exp bound. Moreover, constraints involving only a single monomial in \(x\) can be even more simply written as a linear inequality:
We refer to the MOSEK Modeling Cookbook and to [BKVH07] for more details on this reformulation. A geometric problem formulated in convex form can be entered into MOSEK with the help of exponential cones.
6.6.1 Example GP1¶
The following problem comes from [BKVH07]. Consider maximizing the volume of a \(h\times w\times d\) box subject to upper bounds on the area of the floor and of the walls and bounds on the ratios \(h/w\) and \(d/w\):
The decision variables in the problem are \(h,w,d\). We make a substitution
after which (6.19) becomes
Next, we demonstrate how to implement a log-sum-exp constraint (6.18). It can be written as:
This presentation requires one extra variable \(u_k\) for each monomial appearing in the original posynomial constraint. In this case the affine conic constraints (ACC, see Sec. 6.2 (From Linear to Conic Optimization)) take the form:
As a matter of demonstration we will also add the constraint
as an affine conic constraint. It means that to define the all the ACCs we need to produce the following affine expressions (AFE) and store them:
We implement it by adding all the affine expressions (AFE) and then picking the ones required for each ACC:
// Affine expressions appearing in affine conic constraints
// in this order:
// u1, u2, x+y+log(2/Awall), x+z+log(2/Awall), 1.0, u1+u2-1.0
long numafe = 6;
int u1 = 3, u2 = 4; // Indices of slack variables
long[] afeidx = {0, 1, 2, 2, 3, 3, 5, 5};
int[] varidx = {u1, u2, x, y, x, z, u1, u2};
double[] fval = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0};
double[] gfull = {0, 0, Math.Log(2/Aw), Math.Log(2/Aw), 1.0, -1.0};
// New variables u1, u2
task.appendvars(2);
task.putvarboundsliceconst(u1, u2+1, boundkey.fr, -inf, inf);
// Append affine expressions
task.appendafes(numafe);
task.putafefentrylist(afeidx, varidx, fval);
task.putafegslice(0, numafe, gfull);
// Two affine conic constraints
long expdom = task.appendprimalexpconedomain();
// (u1, 1, x+y+log(2/Awall)) \in EXP
task.appendacc(expdom, new long[]{0, 4, 2}, null);
// (u2, 1, x+z+log(2/Awall)) \in EXP
task.appendacc(expdom, new long[]{1, 4, 3}, null);
// The constraint u1+u2-1 \in \ZERO is added also as an ACC
task.appendacc(task.appendrzerodomain(1), new long[]{5}, null);
We can now use this function to assemble all constraints in the model. The linear part of the problem is entered as in Sec. 6.1 (Linear Optimization).
public static double[] max_volume_box(double Aw, double Af,
double alpha, double beta, double gamma, double delta)
{
// Basic dimensions of our problem
int numvar = 3; // Variables in original problem
int x=0, y=1, z=2; // Indices of variables
int numcon = 3; // Linear constraints in original problem
// Linear part of the problem
double[] cval = {1, 1, 1};
int[] asubi = {0, 0, 1, 1, 2, 2};
int[] asubj = {y, z, x, y, z, y};
double[] aval = {1.0, 1.0, 1.0, -1.0, 1.0, -1.0};
boundkey[] bkc = {boundkey.up, boundkey.ra, boundkey.ra};
double[] blc = {-inf, Math.Log(alpha), Math.Log(gamma)};
double[] buc = {Math.Log(Af), Math.Log(beta), Math.Log(delta)};
using (Task task = new Task())
{
// Directs the log task stream to the user specified
// method task_msg_obj.stream
task.set_Stream (mosek.streamtype.log, new msgclass (""));
// Add variables and constraints
task.appendvars(numvar);
task.appendcons(numcon);
// Objective is the sum of three first variables
task.putobjsense(objsense.maximize);
task.putcslice(0, numvar, cval);
task.putvarboundsliceconst(0, numvar, boundkey.fr, -inf, inf);
// Add the three linear constraints
task.putaijlist(asubi, asubj, aval);
task.putconboundslice(0, numvar, bkc, blc, buc);
// Affine expressions appearing in affine conic constraints
// in this order:
// u1, u2, x+y+log(2/Awall), x+z+log(2/Awall), 1.0, u1+u2-1.0
long numafe = 6;
int u1 = 3, u2 = 4; // Indices of slack variables
long[] afeidx = {0, 1, 2, 2, 3, 3, 5, 5};
int[] varidx = {u1, u2, x, y, x, z, u1, u2};
double[] fval = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0};
double[] gfull = {0, 0, Math.Log(2/Aw), Math.Log(2/Aw), 1.0, -1.0};
// New variables u1, u2
task.appendvars(2);
task.putvarboundsliceconst(u1, u2+1, boundkey.fr, -inf, inf);
// Append affine expressions
task.appendafes(numafe);
task.putafefentrylist(afeidx, varidx, fval);
task.putafegslice(0, numafe, gfull);
// Two affine conic constraints
long expdom = task.appendprimalexpconedomain();
// (u1, 1, x+y+log(2/Awall)) \in EXP
task.appendacc(expdom, new long[]{0, 4, 2}, null);
// (u2, 1, x+z+log(2/Awall)) \in EXP
task.appendacc(expdom, new long[]{1, 4, 3}, null);
// The constraint u1+u2-1 \in \ZERO is added also as an ACC
task.appendacc(task.appendrzerodomain(1), new long[]{5}, null);
// Solve and map to original h, w, d
task.optimize();
double[] xyz = task.getxxslice(soltype.itr, 0, numvar);
double[] hwd = new double[numvar];
for(int i = 0; i < numvar; i++) hwd[i] = Math.Exp(xyz[i]);
return hwd;
}
}
Given sample data we obtain the solution \(h,w,d\) as follows:
public static void Main(String[] args)
{
double Aw = 200.0;
double Af = 50.0;
double alpha = 2.0;
double beta = 10.0;
double gamma = 2.0;
double delta = 10.0;
double[] hwd = max_volume_box(Aw, Af, alpha, beta, gamma, delta);
Console.WriteLine("h={0:f4} w={1:f4} d={2:f4}", hwd[0], hwd[1], hwd[2]);
}