Search code examples
pythonlinear-programmingcplexquadratic-programming

Linear and Quadratic terms in CPLEX Objective Function


I would like to minimize an objective function which is rather simple, but I am somehow having problems making the correct calls to from the Python API to CPLEX

I looked at how to use set_quadratic and set_quadratic_coefficients here but that didn't result in a solution to my problem.

My objective function has a set of linear variables and a set of quadratic variables

varCoefs = [1]*(numB + numQ)
varLower = [0]*(numB + numQ)
varNames = [(x,"b%s"%x) for x in range( numB )]
varNames += [(len(varNames) + x,"q%s"%x) for x in range( numQ )]

varCoefs += [10]*len(deltas)
varLower += [1]*len(deltas)
varNames += [(len(varNames) + x,"delta%s"%x) for x in range( len(deltas) )]

varCoefs += [0]*len(target.v)
varLower += [0]*len(target.v)

sContent = [(len(varNames) + x,"s%s"%x) for x in range( len(target.v) )]
varNames += sContent

varCoefs += [-1]
varLower += [0]
varNames += [(len(varNames),'mu')]


problem.variables.add(obj = varCoefs, lb = varLower)
problem.variables.set_names(varNames)

# problem.objective.set_quadratic_coefficients([[['s%s' % x], [1]] for x in range( len(target.v) )])

problem.objective.set_quadratic(
    [cplex.SparsePair(ind=[sContent[x][0]], val=[1]) for x in range( len(target.v) )]
    )

Everything works up to the last call add the quadratic terms. At which point CPLEX throws the following error CPLEX Error 1226: Array entry 13919 not ascending. twice, ignoring the command, and the Python code continues.

I looked up the error, but that didn't seem to help me either.

I did try re-writing the above to add the variables by name and lower bound first... and then call set_linear and set_quadratic afterward, but that doesn't help either.

What am I missing here?


Solution

  • I solved the problem by adding the quadratic terms first, setting their coefficients, and then adding the linear terms in a separate call see below.

    problem.objective.set_sense(problem.objective.sense.minimize)
    
    varLower = [0]*len(target.v)
    varNames = ["s%s"%x for x in range( len(target.v) )]
    
    problem.variables.add(names=varNames, lb=varLower)
    
    problem.objective.set_quadratic(
        [[[x],[1]] for x in range( len(target.v) )]
        )
    
    varCoefs = [-1]
    varLower = [0]
    varNames = ['mu']
    
    
    varCoefs += [1]*(numB + numQ)
    varLower += [0]*(numB + numQ)
    varNames += ["b%s"%x for x in range( numB )]
    varNames += ["q%s"%x for x in range( numQ )]
    
    varCoefs += [10]*len(deltas)
    varLower += [1]*len(deltas)
    varNames += ["delta%s"%x for x in range( len(deltas) )]
    
    problem.variables.add(names=varNames, lb=varLower, obj=varCoefs)
    

    However, I would still like to know why it works this way, and not the other way.