Dual Generation

The questions below are due on Thursday August 05, 2021; 11:00:00 AM.
 
You are not logged in.

Please Log In for full access to the web site.
Note that this link will take you to an external site (https://shimmer.mit.edu) to authenticate, and then you will be redirected back to this page.

Description

In this problem, you'll write a function to generate a representation of the dual of a given LP. That is, you'll use your Python knowledge to answer a custom question which is difficult to answer even with powerful tools like Gurobi. (Indeed, as far as we're aware, Gurobi does not provide this functionality.)

If the primal describes a resource allocation problem, the dual describes a resource valuation problem. The dual enables sensitivity analysis like the direct computation of shadow prices. This motivates your pursuit of the dual in this exercise.

We'll use the sponge/butter cake problem from 15.066, reproduced below, as our running example.

Maximize
5b + 6s
subject to the constraints:
3b + 6s <= 420
6b + 4.5s <= 465
b <= 90
s <= 60
and nonnegativity constraints on s and b.

We'll work with a Python LP format which would represent this LP like so1:

lp = {'min': False,
      'obj': [5,6], 
      'A_ub': [[3,6],
               [6,4.5],
               [1,0],
               [0,1]],
      'b_ub': [420,
               465,
               90,
               60],
      'bounds': [(0, None), (0, None)]}

We describe this representation in more detail now. Call the number of variables in the LP num_vars.

  • The 'min' entry in the dictionary describes whether or not the LP is a minimization (True) or maximization (False) problem.
  • The 'obj' entry is a list of length num_vars, each element of which is the coefficient of the associated variable in the objective function.
  • The 'A_ub' entry is a list of lists. Each list has length num_vars, and contains coefficients of the asociated variables in a <= constraint.
  • The 'b_ub' entry is a list of the same length as A_ub, and contains the right hand side values of the 'A_ub' constraints.
  • The 'bounds' entry is a list of length num_vars, containing one (lower_bound, upper_bound) tuple for each variable. A bound of None represents the absence of a bound.2

Recall that an = or >= constraint can be represented as two <= constraints or as a <= constraint with negative coefficients (respectively). So our representation is sufficiently encompassing.

The dual of the cake problem is:

Minimize
420y_1 + 465y_2 + 90y_3 + 60y_4
subject to the constraints:
3y_1 + 6y_2 + y_3 >= 5
6y_1 + 4.5y_2 + y_4 >= 6
and nonnegativity constraints on y_1, y_2, y_3, and y_4.

which we would represent like:

dual = {'min': True,
        'obj': [420, 465, 90, 60], 
        'A_ub': [[-3, -6, -1, 0],
                 [-6, -4.5, 0, -1]],
        'b_ub': [-5,
                 -6],
        'bounds': [(0, None), (0, None), (0, None), (0, None)]}

Your Task

Your task is to write a function get_dual which takes in a dictionary representing an LP in standard form (a maximization, with all <= constraints, and all variables nonnegative), and returns a dictionary representing its dual. There are many equivalent representations of the dual in our form. Any are acceptable, but we encourage you to stick with that which comes most naturally from the primal. The dual need not be in standard form.

Test your function on the above and a few other manual test cases, then upload it below for checking.

  No file selected

Next Exercise: Electric Bill

Back to exercises


 
Footnotes

1Coincidentally, this is approximately the format required as input to the scipy package's linprog module, a "lighter" tool than Gurobi which also solves LPs. Try running from scipy.optimize import linprog and then c = [i*(1 if lp['min'] else -1) for i in lp['obj']] and print(linprog(c=c, A_ub=lp['A_ub'], b_ub=lp['b_ub'], bounds=lp['bounds'])) after initializing lp. (The linprog function assumes the given problem will be a minimization, so we need to flip the signs of the objective function if it is not.) (click to return to text)

2Notice that we could represent the cake LP in a different way: with two fewer constraints but with bounds [(0, 90), (0, 60)]. (click to return to text)