在cplex解决方案池中访问不同类型的变量值的问题

时间:2020-07-06 11:31:48

标签: python python-3.x cplex docplex

我有要通过cplex python API解决的MILP模型:

def CModel():
    
 mdl=Model('Generate')

#variable declaration
        y=mdl.binary_var_dict(ijk,name='y')
        Sum=mdl.integer_var_dict(ij,name='S')
#objective
        mdl.minimize(0)

#constraints
        #1
        mdl.add_constraints(mdl.sum(y[(i,j,k)]+y[(j,i,k)] for j in T)==1 for i in T for k in K)
        #2

        mdl.add_constraints(mdl.sum(y[(i,j,k)]+y[(j,i,k)] for k in K1 )==1 for i in T for j in T if i!=j)
        #3

        mdl.add_constraints(mdl.sum(y[(i,j,k)]+y[(j,i,k)] for k in K2 )==1 for i in T for j in T if i!=j)
        #4

        mdl.add_constraints(mdl.sum(y[(i,j,k)] for k in K )==1 for i in T for j in T if i!=j)
        #5     
        for i,j in ij:
            for k in K4:
                Sum=mdl.sum(y[(j,i,k1)] for k1 in range(k+1,k+8 ))
                mdl.add(mdl.if_then(y[(i,j,k)]==1, Sum==0))
 return mdl

Sum是一个变量,我用它来构成第5个约束(我只是用它来将y在某些范围内限制为0)。在解决方案池中,我只需要y的索引,其中y == 1。我有用于解决模型的解决方案池:

def soln_pool(mdl):
    cpx = mdl.get_cplex()
    cpx.parameters.parallel.set(1)
    cpx.parameters.mip.pool.intensity.set(4)
    cpx.populatelim=50
    st2=time.time()
    try:
        cpx.populate_solution_pool()
    except CplexSolverError:
        print("Exception raised during populate")
        return []
    numsol = cpx.solution.pool.get_num() #max timing by 29 second
    sol_pool = []
    pool=[]
    pool2=[]

    if numsol!=0:
        for i in range(numsol):
            indices = [j for j, a in enumerate(cpx.solution.pool.get_values(i)) if a > 0.5]  

        for element in sol_pool:
              
                for j in element:
                        v = mdl.get_var_by_index(j)                        
                        i1 = int(v.name.split('_')[1])
                        i2 = int(v.name.split('_')[2])
                        i3 = int(v.name.split('_')[3])
                        pool.append([i1,i2,i3])
                pool2.append(pool)

在添加约束5之前,解决方案池功能没有问题,但是在添加5之后,出现此错误:

    i1 = int(v.name.split('_')[1])

ValueError: invalid literal for int() with base 10: '{y'

我可以只访问溶液池中的变量y值,然后将其转换为整数吗?

2 个答案:

答案 0 :(得分:0)

您可以仅选中v.name.startswith('y')来过滤掉不是纯y变量的任何内容。我的猜测是,令人讨厌的变量是在后台创建的一些辅助变量。您可以打印完整的v.name来查看违规变量的名称。如果它是一个自动创建的变量,那么它的名称将告诉您创建了哪个约束。

还请注意,您拥有

Sum=mdl.integer_var_dict(ij,name='S')

及以后

Sum=mdl.sum(y[(j,i,k1)] for k1 in range(k+1,k+8 ))

后者覆盖了前者。那可能不是您打算做的。

答案 1 :(得分:0)

丹尼尔(Daniel)是对的。 Model.if_then生成一个布尔变量。您可以使用以下小代码进行检查:

def is_gen(dv):
    return 'yes' if dv.is_generated() else 'no'
for dv in cm.iter_variables():
    print(f'-- variable: {dv.name}, index={dv.index}, generated={is_gen(dv)}')

生成如下输出:

-- variable: _bool{y_10_2_3 == 1}, index=5887, generated=yes

代表约束y_20_2_3 == 1的真变量。

如您所见,在Docplex生成变量后,对变量调用is_generated()会返回True,因此您可以在拆分代码中过滤掉那些变量。