The Primal & Dual Linear Programming Problems: Canonical Form

*James D. Gaboardi*


*Florida State University*     |     *Department of Geography*



Adapted from:

Daskin, M. S. 1995. Network and Discrete Location: Models, Algorithms, and Applications. Hoboken, NJ, USA: John Wiley & Sons, Inc.


0. Imports and Data Creation


In [1]:
# Imports
import numpy as np
import gurobipy as gbp
import datetime as dt

#  Constants
Aij = np.random.randint(5, 50, 400)
Aij = Aij.reshape(20,20)
AijSum = np.sum(Aij)
Cj = np.random.randint(10, 20, 20)
CjSum = np.sum(Cj)
Bi = np.random.randint(10, 20, 20)
BiSum = np.sum(Bi)

# Matrix Shape
rows = range(len(Aij))
cols = range(len(Aij[0]))

1. Primal


In [2]:
def GbpPrimCan():    
    # Instantiate Model
    mPrimal_Canonical_GUROBI = gbp.Model(' -- Canonical Primal Linear Programming Problem -- ')

    # Set Focus to Optimality
    gbp.setParam('MIPFocus', 2)

    # Decision Variables
    desc_var = []
    for dest in cols:
        desc_var.append([])
        desc_var[dest].append(mPrimal_Canonical_GUROBI.addVar(vtype=gbp.GRB.CONTINUOUS, 
                                        name='y'+str(dest+1)))
    # Update Model
    mPrimal_Canonical_GUROBI.update()

    #Objective Function
    mPrimal_Canonical_GUROBI.setObjective(gbp.quicksum(Cj[dest]*desc_var[dest][0] 
                            for dest in cols), 
                            gbp.GRB.MINIMIZE)
    # Constraints
    for orig in rows:
        mPrimal_Canonical_GUROBI.addConstr(gbp.quicksum(Aij[orig][dest]*desc_var[dest][0] 
                            for dest in cols) - Bi[orig] >= 0)
    # Optimize
    try:
        mPrimal_Canonical_GUROBI.optimize()
    except Exception as e:
        print '   ################################################################'
        print ' < ISSUE : ', e, ' >'
        print '   ################################################################'
    # Write LP file
    mPrimal_Canonical_GUROBI.write('LP.lp')
    print '\n*************************************************************************'
    print '    |   Decision Variables'
    for v in mPrimal_Canonical_GUROBI.getVars():
        print '    |  ', v.VarName, '=', v.x
    print '*************************************************************************'
    val = mPrimal_Canonical_GUROBI.objVal
    print '    |   Objective Value ------------------ ', val
    print '    |   Aij Sum -------------------------- ', AijSum
    print '    |   Cj Sum --------------------------- ', CjSum
    print '    |   Bi Sum --------------------------- ', BiSum
    print '    |   Matrix Dimensions ---------------- ', Aij.shape
    print '    |   Date/Time ------------------------ ', dt.datetime.now()
    print '*************************************************************************'
    print '-- Gurobi Canonical Primal Linear Programming Problem --'
    
try:
    GbpPrimCan()
    print '\nJames Gaboardi, 2015'
except Exception as e:
    print '   ################################################################'
    print ' < ISSUE : ', e, ' >'
    print '   ################################################################'


Changed value of parameter MIPFocus to 2
   Prev: 0   Min: 0   Max: 3   Default: 0
Optimize a model with 20 rows, 20 columns and 400 nonzeros
Coefficient statistics:
  Matrix range    [5e+00, 5e+01]
  Objective range [1e+01, 2e+01]
  Bounds range    [0e+00, 0e+00]
  RHS range       [1e+01, 2e+01]
Presolve time: 0.00s
Presolved: 20 rows, 20 columns, 400 nonzeros

Iteration    Objective       Primal Inf.    Dual Inf.      Time
       0    0.0000000e+00   4.687500e+00   0.000000e+00      0s
      11    7.4815903e+00   0.000000e+00   0.000000e+00      0s

Solved in 11 iterations and 0.01 seconds
Optimal objective  7.481590294e+00

*************************************************************************
    |   Decision Variables
    |   y1 = 0.0318421970971
    |   y2 = 0.0
    |   y3 = 0.0687163240813
    |   y4 = 0.0173262243046
    |   y5 = 0.0
    |   y6 = 0.0
    |   y7 = 0.00578178597961
    |   y8 = 0.0
    |   y9 = 0.0270323672164
    |   y10 = 0.0
    |   y11 = 0.0
    |   y12 = 0.0823155371905
    |   y13 = 0.0
    |   y14 = 0.0
    |   y15 = 0.0
    |   y16 = 0.0
    |   y17 = 0.107217852703
    |   y18 = 0.157976724062
    |   y19 = 0.123731798441
    |   y20 = 0.0
*************************************************************************
    |   Objective Value ------------------  7.48159029398
    |   Aij Sum --------------------------  10844
    |   Cj Sum ---------------------------  293
    |   Bi Sum ---------------------------  300
    |   Matrix Dimensions ----------------  (20, 20)
    |   Date/Time ------------------------  2015-08-31 11:12:41.820614
*************************************************************************
-- Gurobi Canonical Primal Linear Programming Problem --

James Gaboardi, 2015

2. Dual


In [3]:
def GbpDualCan():    
    # Instantiate Model
    mDual_Canonical_GUROBI = gbp.Model(' -- Canonical Dual Linear Programming Problem -- ')

    # Set Focus to Optimality
    gbp.setParam('MIPFocus', 2)

    # Decision Variables
    desc_var = []
    for dest in cols:
        desc_var.append([])
        desc_var[dest].append(mDual_Canonical_GUROBI.addVar(vtype=gbp.GRB.CONTINUOUS, 
                                        name='u'+str(dest+1)))
    # Update Model
    mDual_Canonical_GUROBI.update()

    #Objective Function
    mDual_Canonical_GUROBI.setObjective(gbp.quicksum(Bi[orig]*desc_var[orig][0] 
                            for orig in rows), 
                            gbp.GRB.MAXIMIZE)
    # Constraints
    for dest in cols:
        mDual_Canonical_GUROBI.addConstr(gbp.quicksum(Aij[orig][dest]*desc_var[dest][0] 
                            for orig in rows) - Cj[dest] <= 0)
    # Optimize
    try:
        mDual_Canonical_GUROBI.optimize()
    except Exception as e:
        print '   ################################################################'
        print ' < ISSUE : ', e, ' >'
        print '   ################################################################'
    # Write LP file
    mDual_Canonical_GUROBI.write('LP.lp')
    print '\n*************************************************************************'
    print '    |   Decision Variables'
    for v in mDual_Canonical_GUROBI.getVars():
        print '    |  ', v.VarName, '=', v.x
    print '*************************************************************************'
    val = mDual_Canonical_GUROBI.objVal
    print '    |   Objective Value ------------------ ', val
    print '    |   Aij Sum -------------------------- ', AijSum
    print '    |   Cj Sum --------------------------- ', CjSum
    print '    |   Bi Sum --------------------------- ', BiSum
    print '    |   Matrix Dimensions ---------------- ', Aij.shape
    print '    |   Date/Time ------------------------ ', dt.datetime.now()
    print '*************************************************************************'
    print '-- Gurobi Canonical Dual Linear Programming Problem --'
    
try:
    GbpDualCan()
    print '\nJames Gaboardi, 2015'
except Exception as e:
    print '   ################################################################'
    print ' < ISSUE : ', e, ' >'
    print '   ################################################################'


Parameter MIPFocus unchanged
   Value: 2   Min: 0   Max: 3   Default: 0
Optimize a model with 20 rows, 20 columns and 20 nonzeros
Coefficient statistics:
  Matrix range    [5e+02, 6e+02]
  Objective range [1e+01, 2e+01]
  Bounds range    [0e+00, 0e+00]
  RHS range       [1e+01, 2e+01]
Presolve removed 20 rows and 20 columns
Presolve time: 0.01s
Presolve: All rows and columns removed
Iteration    Objective       Primal Inf.    Dual Inf.      Time
       0    8.2286943e+00   0.000000e+00   0.000000e+00      0s

Solved in 0 iterations and 0.01 seconds
Optimal objective  8.228694293e+00

*************************************************************************
    |   Decision Variables
    |   u1 = 0.0357894736842
    |   u2 = 0.0299401197605
    |   u3 = 0.0269749518304
    |   u4 = 0.0204460966543
    |   u5 = 0.0308008213552
    |   u6 = 0.0247619047619
    |   u7 = 0.0267111853088
    |   u8 = 0.0320284697509
    |   u9 = 0.0290697674419
    |   u10 = 0.0289855072464
    |   u11 = 0.0313588850174
    |   u12 = 0.0192307692308
    |   u13 = 0.0349344978166
    |   u14 = 0.0385395537525
    |   u15 = 0.0271739130435
    |   u16 = 0.0240963855422
    |   u17 = 0.018115942029
    |   u18 = 0.0181818181818
    |   u19 = 0.0215384615385
    |   u20 = 0.0265780730897
*************************************************************************
    |   Objective Value ------------------  8.22869429269
    |   Aij Sum --------------------------  10844
    |   Cj Sum ---------------------------  293
    |   Bi Sum ---------------------------  300
    |   Matrix Dimensions ----------------  (20, 20)
    |   Date/Time ------------------------  2015-08-31 11:14:56.112995
*************************************************************************
-- Gurobi Canonical Dual Linear Programming Problem --

James Gaboardi, 2015