2

I am trying to solve a linear programming problem using IBM's CPLEX Python API. It involves two sets of equality constraints. The code below works fine when we use either one of the two sets of constraints, but fails to find a solution when both sets of constraints are used.

The constraints are: First constraint: Wx' = c', where W = [[20,0,0],[0,20,30]], x = [a,b,c], c=[20,30] Second constraint: Vx' = e', where V = [[1,1,0],[0,0,1]], x = [a,b,c], c=[1,1]

Objective function: minimize a + c

One solution which meets both sets of constrains is a=1, b=0, c=1.

There is an error in the way I am introducing the two sets of constrains in Cplex Python. My code is below. To check that the code works with either set of constraints by itself comment out on of the sets of constraints.

import cplex
from cplex.exceptions import CplexError
import sys



def populatebynonzero(prob):


    my_obj      = [1.0, 0.0, 1.0]
    my_ub       = [1.0] * len(my_obj)
    my_lb       = [0.0] * len(my_obj)
    my_colnames = ["a", "b", "c"]

    prob.objective.set_sense(prob.objective.sense.minimize)
    prob.variables.add(obj = my_obj, ub = my_ub, lb = my_lb ,names = my_colnames)

    # first set of equality constraints: Wx' = c', where W = [[20,0,0],[0,20,30]], x = [a,b,c], c=[20,30]
    my_rhs      = [20.0, 30.0]
    my_rownames = ["c1", "c2"]
    my_sense    = "E" * len(my_rownames)
    rows = [0,1,1] 
    cols = [0,1,2]
    vals = [20.0,20.0,30.0]
    prob.linear_constraints.add(rhs = my_rhs, senses = my_sense,names = my_rownames)
    prob.linear_constraints.set_coefficients(zip(rows, cols, vals))     

    # second set of equality constraints: Vx' = e', where V = [[1,1,0],[0,0,1]], x = [a,b,c], c=[1,1]

    my_rhs      = [1.0, 1.0]
    my_rownames = ["e1", "e2"]
    my_sense    = "E" * len(my_rownames)
    rows = [0,0,1] 
    cols = [0,1,2]
    vals = [1.0,1.0,1.0]
    prob.linear_constraints.add(rhs = my_rhs, senses = my_sense,names = my_rownames)
    prob.linear_constraints.set_coefficients(zip(rows, cols, vals))



def lpex1():
    try:
        my_prob = cplex.Cplex()
        handle = populatebynonzero(my_prob)
        my_prob.solve()
    except CplexError, exc:
        print exc
        return

    numrows = my_prob.linear_constraints.get_num()
    numcols = my_prob.variables.get_num()

    print
    # solution.get_status() returns an integer code
    print "Solution status = " , my_prob.solution.get_status(), ":",
    # the following line prints the corresponding string
    print my_prob.solution.status[my_prob.solution.get_status()]
    print "Solution value  = ", my_prob.solution.get_objective_value()
    slack = my_prob.solution.get_linear_slacks()
    pi    = my_prob.solution.get_dual_values()
    x     = my_prob.solution.get_values()
    dj    = my_prob.solution.get_reduced_costs()
    for i in range(numrows):
        print "Row %d:  Slack = %10f  Pi = %10f" % (i, slack[i], pi[i])
    for j in range(numcols):
        print "Column %d:  Value = %10f Reduced cost = %10f" % (j, x[j], dj[j])

    my_prob.write("lpex1.lp")




    print x, "SOLUTIONS"

lpex1()
rkersh
  • 4,447
  • 2
  • 22
  • 31
user58925
  • 1,537
  • 5
  • 19
  • 28

2 Answers2

0

It works if the two sets of constraints are combined into one matrix in the following way, though it would be good to find a solution which does not have to do combining

import cplex
from cplex.exceptions import CplexError
import sys



def populatebynonzero(prob):


    my_obj      = [1.0, 0.0, 1.0]
    my_ub       = [1.0] * len(my_obj)
    my_lb       = [0.0] * len(my_obj)
    my_colnames = ["a", "b", "c"]

    prob.objective.set_sense(prob.objective.sense.minimize)
    prob.variables.add(obj = my_obj, ub = my_ub, lb = my_lb ,names = my_colnames)

    #combined constraints
    my_rhs      = [20.0, 30.0, 1.0, 1.0]
    my_rownames = ["c1", "c2", "e1", "e2"]
    my_sense    = "E" * len(my_rownames)
    rows = [0,1,1,2,2,3] 
    cols = [0,1,2,0,1,2]
    vals = [20.0,20.0,30.0,1,1,1]
    prob.linear_constraints.add(rhs = my_rhs, senses = my_sense,names = my_rownames)
    prob.linear_constraints.set_coefficients(zip(rows, cols, vals))     


    """

    # first set of equality constraints: Wx' = c', where W = [[20,0,0],[0,20,30]], x = [a,b,c], c=[20,30]
    my_rhs      = [20.0, 30.0]
    my_rownames = ["c1", "c2"]
    my_sense    = "E" * len(my_rownames)
    rows = [0,1,1] 
    cols = [0,1,2]
    vals = [20.0,20.0,30.0]
    prob.linear_constraints.add(rhs = my_rhs, senses = my_sense,names = my_rownames)
    prob.linear_constraints.set_coefficients(zip(rows, cols, vals))     

    # second set of equality constraints: Vx' = e', where V = [[1,1,0],[0,0,1]], x = [a,b,c], c=[1,1]

    my_rhs      = [1.0, 1.0]
    my_rownames = ["e1", "e2"]
    my_sense    = "E" * len(my_rownames)
    rows = [0,0,1] 
    cols = [0,1,2]
    vals = [1.0,1.0,1.0]
    prob.linear_constraints.add(rhs = my_rhs, senses = my_sense,names = my_rownames)
    prob.linear_constraints.set_coefficients(zip(rows, cols, vals))
    """


def lpex1():
    try:
        my_prob = cplex.Cplex()
        handle = populatebynonzero(my_prob)
        my_prob.solve()
    except CplexError, exc:
        print exc
        return

    numrows = my_prob.linear_constraints.get_num()
    numcols = my_prob.variables.get_num()

    print
    # solution.get_status() returns an integer code
    print "Solution status = " , my_prob.solution.get_status(), ":",
    # the following line prints the corresponding string
    print my_prob.solution.status[my_prob.solution.get_status()]
    print "Solution value  = ", my_prob.solution.get_objective_value()
    slack = my_prob.solution.get_linear_slacks()
    pi    = my_prob.solution.get_dual_values()
    x     = my_prob.solution.get_values()
    dj    = my_prob.solution.get_reduced_costs()
    for i in range(numrows):
        print "Row %d:  Slack = %10f  Pi = %10f" % (i, slack[i], pi[i])
    for j in range(numcols):
        print "Column %d:  Value = %10f Reduced cost = %10f" % (j, x[j], dj[j])

    my_prob.write("lpex1.lp")




    print x, "SOLUTIONS"

lpex1()
user58925
  • 1,537
  • 5
  • 19
  • 28
0

When you are attempting to create the second set of constraints, you are using the wrong indices for the rows:

# second set of equality constraints: Vx' = e', where V = [[1,1,0],[0,0,1]], x = [a,b,c], c=[1,1]

my_rhs      = [1.0, 1.0]
my_rownames = ["e1", "e2"]
my_sense    = "E" * len(my_rownames)
rows = [0,0,1]  # <- HERE
cols = [0,1,2]
vals = [1.0,1.0,1.0]

That is, you're using the row indices 0 and 1, which were created for the first set of constraints. Instead, you should do something like the following:

# second set of equality constraints: Vx' = e', where V = [[1,1,0],[0,0,1]], x = [a,b,c], c=[1,1]

my_rhs      = [1.0, 1.0]
my_rownames = ["e1", "e2"]
my_sense    = "E" * len(my_rownames)
cols = [0,1,2]
vals = [1.0,1.0,1.0]
rowindices = list(prob.linear_constraints.add(rhs = my_rhs, senses = my_sense,names = my_rownames))
assert len(rowindices) == 2
rows = [rowindices[0], rowindices[0], rowindices[1]]
prob.linear_constraints.set_coefficients(zip(rowindices, cols, vals))

Above, we get the new row indices from the call to prob.linear_constriants.add. With this change, the script works fine.

In addition, it's a good idea to write out the problem in LP format to make sure that it looks correct, like so:

prob.write("model.lp")
rkersh
  • 4,447
  • 2
  • 22
  • 31