首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >CPLEX目标函数中的线性项和二次项

CPLEX目标函数中的线性项和二次项
EN

Stack Overflow用户
提问于 2016-08-15 11:48:12
回答 2查看 1.4K关注 0票数 1

我想最小化一个相当简单的目标函数,但不知何故,我在从Python API到CPLEX的正确调用中遇到了问题

我研究了如何使用set_quadraticset_quadratic_coefficients here,但这并没有解决我的问题。

我的目标函数有一组线性变量和一组二次变量

代码语言:javascript
复制
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) )]
    )

直到最后一次调用,再加上二次项。这时,CPLEX会抛出两次错误CPLEX Error 1226: Array entry 13919 not ascending.,忽略该命令,然后Python代码继续执行。

我查了一下error,但似乎对我也没什么帮助。

我确实尝试了重写上面的代码,先按名称和下限添加变量……然后调用set_linearset_quadratic,但这也没有帮助。

这里我漏掉了什么?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-08-16 02:07:34

我通过首先添加二次项,设置它们的系数,然后在一个单独的调用中添加线性项来解决这个问题。

代码语言:javascript
复制
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)

然而,我仍然想知道为什么它是这样工作的,而不是另一种方式。

票数 0
EN

Stack Overflow用户

发布于 2016-08-16 00:39:24

如果您使用一个可分离的二次目标函数调用set_quadratic,那么它对应于CPXXcopyqpsep。如果您使用一个不可分的二次目标函数调用set_quadratic,那么它对应于CPXXcopyquad。我同意你得到的错误不是特别有用,但是如果你知道它来自Callable C库,它会更有意义一些。

话虽如此,这里有一个完整的例子,使用你的代码片段,带有一些虚拟输入:

代码语言:javascript
复制
import cplex

class MockTarget(object):
    pass

# Dummy data for testing

numB = 3
numQ = 3
deltas = [0.1, 0.1, 0.1]
problem = cplex.Cplex()

target = MockTarget()
target.v = [1, 2, 3]

# Build the problem

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)

# Print without quadratic terms so you can see the progression.
problem.write('test1.lp')

# Separable Q

qsepvec = []
for tpl in varNames:
    if tpl in sContent:
        qsepvec.append(1.0)
    else:
        qsepvec.append(0.0)
print qsepvec

problem.objective.set_quadratic(qsepvec)

problem.write('test2.lp')

# Inseparable Q (overwrites previous Q)

qmat = []
for tpl in varNames:
    if tpl in sContent:
        sp = cplex.SparsePair(ind=[tpl[0]], val=[1.0])
        qmat.append(sp)
    else:
        sp = cplex.SparsePair(ind=[], val=[])
        qmat.append(sp)
print qmat

problem.objective.set_quadratic(qmat)

problem.write('test3.lp')

我用很长的形式写了出来,而不是使用列表理解来使它更清楚一些。LP文件的内容如下:

test1.lp:

代码语言:javascript
复制
\ENCODING=ISO-8859-1
\Problem name: 

Minimize
 obj: b0 + b1 + b2 + q0 + q1 + q2 + 10 delta0 + 10 delta1 + 10 delta2 + 0 s0
      + 0 s1 + 0 s2 - mu
Bounds
      delta0 >= 1
      delta1 >= 1
      delta2 >= 1
End

test2.lp

代码语言:javascript
复制
\ENCODING=ISO-8859-1
\Problem name: 

Minimize
 obj: b0 + b1 + b2 + q0 + q1 + q2 + 10 delta0 + 10 delta1 + 10 delta2 + 0 s0
      + 0 s1 + 0 s2 - mu + [ s0 ^2 + s1 ^2 + s2 ^2 ] / 2
Bounds
      delta0 >= 1
      delta1 >= 1
      delta2 >= 1
End

test3.lp

代码语言:javascript
复制
\ENCODING=ISO-8859-1
\Problem name: 

Minimize
 obj: b0 + b1 + b2 + q0 + q1 + q2 + 10 delta0 + 10 delta1 + 10 delta2 + 0 s0
      + 0 s1 + 0 s2 - mu + [ s0 ^2 + s1 ^2 + s2 ^2 ] / 2
Bounds
      delta0 >= 1
      delta1 >= 1
      delta2 >= 1
End

您可以看到test2.lp和test3.lp是相同的(后者覆盖了前者,但做的是相同的事情)。希望这会让它更容易理解。一般来说,对于非常简单的问题,使用这种打印输出LP的技术是一种更有用的调试技术。

您还应该查看CPLEX附带的python示例。例如,qpex1.py、miqpex1.py、indefqpex1.py。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38949055

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档