0

I have this MILP model that I am solving by cplex python API:

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 is a variable that I am using to make the 5th constraint (I'm just using it to restrict y on certain ranges to 0). In the solution pool I just need the indices of y where y==1. I have this solution pool for solving the model:

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)

Before I add constriant #5 there was no problem with the solution pool function but after adding #5 I get this error:

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

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

Hiw can I access only variable y values on solution pool and convert then to integers?

Sana.Nz
  • 81
  • 11

2 Answers2

0

You can just check v.name.startswith('y') to filter out anything that is not a plain y variable. My guess is that the offending variable is some auxiliary variable that was created under the hood. You could print the full v.name to see the name of the offending variable's name. If it is an autocreated variable then its name will tell for which constraint it was created.

Also note that you have

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

and later

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

The latter overwrites the former. That is probably not what you intend to do.

Daniel Junglas
  • 5,830
  • 1
  • 5
  • 22
0

Daniel is right. Model.if_then generates a boolean variable. You can check this with this small code:

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)}')

which generates output like:

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

which represents the truth variable for constraint y_20_2_3==1.

As you can see, calling is_generated() on a variable return True when the variable has been generated by Docplex, so you can just filter out those variables in you split code.

Philippe Couronne
  • 826
  • 1
  • 5
  • 6