8.1. Integer Programming with Simple Branch and Bound#

\[\begin{split}\begin{align*} \min \quad & Z = x + y_1 + 3 y_2 + 2 y_3 \\ \mathrm{s.t.} \quad & -x + 3 y_1 + 2 y_2 + y_3 \leq 0 \\ & -5 y_1 - 8 y_2 - 3 y_3 \leq -9 \\ & x \geq 0, y \in \{0,1\}^3 \end{align*}\end{split}\]
from pyomo.environ import *
from pyomo.opt import SolverStatus, TerminationCondition

def create_relaxation():
    
    ## Create Pyomo Model
    m = ConcreteModel()
    
    ## Declare variables (all continous for now)
    m.x = Var(domain=NonNegativeReals)
    m.y1 = Var(bounds=(0,1))
    m.y2 = Var(bounds=(0,1))
    m.y3 = Var(bounds=(0,1))
    
    ## Declare constraints
    def con1_rule(m):
        return -1.0*m.x + 3.0*m.y1 + 2.0*m.y2 + m.y3 <= 0
    m.con1 = Constraint(rule=con1_rule)
    
    def con2_rule(m):
        return -5.0*m.y1 - 8.0*m.y2 - 3.0*m.y3 <= -9
    m.con2 = Constraint(rule=con2_rule)
    
    ## Declare objective
    def obj_rule(m):
        return m.x + m.y1 + 3*m.y2 + 2*m.y3
    
    m.obj = Objective(rule=obj_rule,sense=minimize)
    
    return m

def solve_print(m,verbose=False):
    
    # Solve the model
    opt = SolverFactory('cbc')
    results = opt.solve(m, tee=verbose)

    if (results.solver.status == SolverStatus.ok) and (results.solver.termination_condition == TerminationCondition.optimal):
        # Print solution when the solution is optimal
        print("x = ",value(m.x))
        print("y1 = ",value(m.y1))
        print("y2 = ",value(m.y2))
        print("y3 = ",value(m.y3))
        print("Z = ",value(m.obj))
    
    elif (results.solver.termination_condition == TerminationCondition.infeasible):
        print("Infeasible.")
        
    else:
        # Something else is wrong
        print('Solver Status:',result.solver.status)
    
    # m.pprint()

8.1.1. Node 1 (Root)#

Full LP relaxation.

m = create_relaxation()
solve_print(m,False)
x =  2.6
y1 =  0.2
y2 =  1.0
y3 =  0.0
Z =  5.800000000000001

8.1.2. Node 2#

m = create_relaxation()
m.y1.fix(0.0)
solve_print(m,False)
x =  2.3333333
y1 =  0.0
y2 =  1.0
y3 =  0.33333333
Z =  5.999999959999999

8.1.3. Node 3#

m = create_relaxation()
m.y1.fix(1.0)
solve_print(m,False)
x =  4.0
y1 =  1.0
y2 =  0.5
y3 =  0.0
Z =  6.5

8.1.4. Node 4#

m = create_relaxation()
m.y1.fix(0.0)
m.y3.fix(0.0)
solve_print(m,False)
WARNING: Loading a SolverResults object with a warning status into
    model.name="unknown";
      - termination condition: infeasible
      - message from solver: <undefined>
Infeasible.

8.1.5. Node 5#

m = create_relaxation()
m.y1.fix(0.0)
m.y3.fix(1.0)
solve_print(m,False)
x =  2.5
y1 =  0.0
y2 =  0.75
y3 =  1.0
Z =  6.75

8.1.6. Node 6#

m = create_relaxation()
m.y1.fix(1.0)
m.y2.fix(0.0)
solve_print(m,False)
WARNING: Loading a SolverResults object with a warning status into
    model.name="unknown";
      - termination condition: infeasible
      - message from solver: <undefined>
Infeasible.

8.1.7. Node 7#

m = create_relaxation()
m.y1.fix(1.0)
m.y2.fix(1.0)
solve_print(m,False)
x =  5.0
y1 =  1.0
y2 =  1.0
y3 =  0.0
Z =  9.0

8.1.8. Node 8#

m = create_relaxation()
m.y1.fix(0.0)
m.y3.fix(1.0)
m.y2.fix(0.0)
solve_print(m,False)
WARNING: Loading a SolverResults object with a warning status into
    model.name="unknown";
      - termination condition: infeasible
      - message from solver: <undefined>
Infeasible.

8.1.9. Node 9#

m = create_relaxation()
m.y1.fix(0.0)
m.y3.fix(1.0)
m.y2.fix(1.0)
solve_print(m,False)
x =  3.0
y1 =  0.0
y2 =  1.0
y3 =  1.0
Z =  8.0