cplexdocplex

DOcplex: the dual of the dual is not the same as primal?


I have a very simple primal problem defined like this:

mdl = Model(name='tubs_primal')

aqua = mdl.continuous_var(name='aqua')
hydro = mdl.continuous_var(name='hydro')
typhoon = mdl.continuous_var(name='typhoon')

pump = mdl.add_constraint(aqua + hydro + typhoon <= 200, 'pump')
hour = mdl.add_constraint(9*aqua + 6*hydro + 8*typhoon<= 1566, 'hour')
tubing = mdl.add_constraint(12*aqua+16*hydro + 13*typhoon <= 2880, 'tubing')

profit = 350*aqua + 300*hydro + 320*typhoon

mdl.maximize(profit)

I also wrote down its dual problem like this

mdl = Model(name='tubs_dual')

pump = mdl.continuous_var(name='pump', lb=None)    
hour = mdl.continuous_var(name='hour', lb=None)    
tubing = mdl.continuous_var(name='tubing', lb=None)

aqua = mdl.add_constraint(pump + 9*hour + 12*tubing >= 350, 'aqua')
hydro = mdl.add_constraint(pump + 6*hour + 16*tubing >= 300, 'hydro')
typhoon = mdl.add_constraint(pump + 8*hour + 13*tubing >= 320, 'typhoon')

cost = 200*pump + 1566*hour + 2880*tubing

mdl.minimize(cost)

The primal code works perfect. However, when I ran the dual problem, CPLEX tells me that the dual objective and primal objective are different. So the dual problem of a dual is not same as primal? I am quite puzzled. Any help? Thanks.

Iteration log . . .
Iteration:     1   Dual objective     =         60900.000000
objective: 66100.000
  pump=200.000
  hour=16.667

Solution

  • The reason is because of not full log display. Suppose you solve the 2 models primal and dual with primal method

    from docplex.mp.model import Model
    
    mdl = Model(name='tubs_primal')
    
    aqua = mdl.continuous_var(name='aqua')
    hydro = mdl.continuous_var(name='hydro')
    typhoon = mdl.continuous_var(name='typhoon')
    
    pump = mdl.add_constraint(aqua + hydro + typhoon <= 200, 'pump')
    hour = mdl.add_constraint(9*aqua + 6*hydro + 8*typhoon<= 1566, 'hour')
    tubing = mdl.add_constraint(12*aqua+16*hydro + 13*typhoon <= 2880, 'tubing')
    
    profit = 350*aqua + 300*hydro + 320*typhoon
    mdl.maximize(profit)
    
    mdl.parameters.lpmethod=1
    
    mdl.solve(log_output=True)
    
    print("obj=",mdl.objective_value)
    
    mdl2 = Model(name='tubs_dual')
    
    pump = mdl2.continuous_var(name='pump', lb=None)    
    hour = mdl2.continuous_var(name='hour', lb=None)    
    tubing = mdl2.continuous_var(name='tubing', lb=None)
    
    aqua = mdl2.add_constraint(pump + 9*hour + 12*tubing >= 350, 'aqua')
    hydro = mdl2.add_constraint(pump + 6*hour + 16*tubing >= 300, 'hydro')
    typhoon = mdl2.add_constraint(pump + 8*hour + 13*tubing >= 320, 'typhoon')
    
    cost = 200*pump + 1566*hour + 2880*tubing
    
    mdl2.minimize(cost)
    mdl2.parameters.lpmethod=1
    
    mdl2.solve(log_output=True)
    
    print("obj=",mdl2.objective_value)
    

    Then you will get

    Iteration log . . .
    Iteration:     1    Objective     =         60900.000000
    obj= 66100.0
    
    
    Iteration log . . .
    Iteration:     1    Scaled infeas =             0.000000
    Switched to devex.
    Iteration:     2    Objective     =         66100.000000
    obj= 66100.0