Search code examples
pythonoptimizationcplextraveling-salesman

CPLEX-python (3.6) keeps showing a "not list" ERROR


I am using the CPLEX solver with python 3.6 to solve mathematical programming models. I used to do this on my old computer and now reinstall cplex on the new one without problems, however when I try to run models that originally ran without errors, now I always get the same error, for example for the Traveling Salesman Problem:


TypeError                                 Traceback (most recent call last)
~\Dropbox\CPLEX\TSP_MTZ\TSP.py in <module>
    137
    138
--> 139 TSP(4)

~\Dropbox\CPLEX\TSP_MTZ\TSP.py in TSP(N)
     38                 for j in range(N):
     39                         x_varobj.append(float(c[i,j]))
---> 40         Model.variables.add(obj = x_varobj, lb = x_varlb, ub = x_varub, types = x_vartypes, names = x_varnames)
     41
     42         u_vars=list(np.array(["u("+str(i)+")" for i in range(0,N)]))

c:\users\healh\.conda\envs\py36\lib\site-packages\cplex\_internal\_subinterfaces.py in add(self, obj, lb, ub, types, names, columns)
    454                                                      columns)
    455         return self._add_iter(self.get_num, self._add,
--> 456                               obj, lb, ub, types, names, columns)
    457
    458     def delete(self, *args):

c:\users\healh\.conda\envs\py36\lib\site-packages\cplex\_internal\_baseinterface.py in _add_iter(getnumfun, addfun, *args, **kwargs)
     39         """non-public"""
     40         old = getnumfun()
---> 41         addfun(*args, **kwargs)
     42         return range(old, getnumfun())
     43

c:\users\healh\.conda\envs\py36\lib\site-packages\cplex\_internal\_subinterfaces.py in _add(self, obj, lb, ub, types, names, columns)
    376         if columns == []:
    377             CPX_PROC.newcols(self._env._e, self._cplex._lp, obj, lb, ub,
--> 378                              types, names)
    379         else:
    380             with CPX_PROC.chbmatrix(columns, self._cplex._env_lp_ptr,

c:\users\healh\.conda\envs\py36\lib\site-packages\cplex\_internal\_procedural.py in newcols(env, lp, obj, lb, ub, xctype, colname)
    965         status = CR.CPXXnewcols(
    966             env, lp, ccnt, c_obj, c_lb, c_ub,
--> 967             xctype, colname)
    968     check_status(env, status)
    969

c:\users\healh\.conda\envs\py36\lib\site-packages\cplex\_internal\_pycplex.py in CPXXnewcols(env, lp, ccnt, py_obj, py_lb, py_ub, xctype, colname)
   1783
   1784 def CPXXnewcols(env: 'CPXCENVptr', lp: 'CPXLPptr', ccnt: 'CPXDIM', py_obj: 'double const *', py_lb: 'double const *', py_ub: 'double const *', xctype: 'char const *', colname: 'char const *const *') -> "int":
-> 1785     return _pycplex_platform.CPXXnewcols(env, lp, ccnt, py_obj, py_lb, py_ub, xctype, colname)
   1786
   1787 def CPXXaddcols(env: 'CPXCENVptr', lp: 'CPXLPptr', ccnt: 'CPXDIM', nzcnt: 'CPXNNZ', py_obj: 'double const *', py_matbeg: 'CPXNNZ const *', py_lb: 'double const *', py_ub: 'double const *', colname: 'char const *const *') -> "int":

TypeError: not a list

My code is the following:

import time
import numpy as np
import cplex
from cplex import Cplex
from cplex.exceptions import CplexError
import sys
import networkx as nx
import matplotlib.pyplot as plt
from openpyxl import Workbook
import xlrd

def TSP(N):
    wb = Workbook()
    ws = wb.active
    book = xlrd.open_workbook('C.xlsx')            #LECTURA DE PARÁMETROS.
    sheet = book.sheet_by_name("C")
    c=[[int(sheet.cell_value(r,c)) for c in range(sheet.ncols)] for r in range(sheet.nrows)]
    c=np.matrix(c)  
    print("")
    print("MATRIZ DE DISTANCIAS")
    print("")        
    print(c)    
    print("")
    print("")
    print("") 

    Model=cplex.Cplex()

    x_vars=np.array([["x("+str(i)+","+str(j)+")" for j in range(N)] for i in range(N)])
    x_varnames = x_vars.flatten()
    x_vartypes='B'*N*N
    x_varlb = [0.0]*len(x_varnames)
    x_varub = [1.0]*len(x_varnames)
    x_varobj = []
    for i in range(N):
        for j in range(N):
            x_varobj.append(float(c[i,j]))
    Model.variables.add(obj = x_varobj, lb = x_varlb, ub = x_varub, types = x_vartypes, names = x_varnames)

    u_vars=np.array(["u("+str(i)+")" for i in range(0,N)])
    u_varnames=u_vars.flatten()
    u_vartypes='I'*N
    u_varlb=[1.0]*N
    u_varub=[float(N)-1.0]*N
    u_varobj=[0.0]*N

    Model.variables.add(obj = u_varobj, lb = u_varlb, ub = u_varub, types = u_vartypes, names = u_varnames)
    Model.objective.set_sense(Model.objective.sense.minimize)
    # suma(J,x[i,j])==1.0, forall i in N
    for i in range(N):
        row1=[]
        val1=[]
        for j in range(N):
            row1.append(x_vars[i,j])
            val1.append(1.0)

        Model.linear_constraints.add(lin_expr = [cplex.SparsePair(ind = row1, val= val1)], senses = 'E', rhs = [1.0])

    # suma(i,x[i,j])==1.0, forall j in N
    for j in range(N):
        row2=[]
        val2=[]
        for i in range(N):
            row2.append(x_vars[i,j])
            val2.append(1.0)

        Model.linear_constraints.add(lin_expr = [cplex.SparsePair(ind = row2, val= val2)], senses = 'E', rhs = [1.0])
    
    #u[i]-u[j]-(N-1)x[i,ji]<=N-2 , forall i in N, forall j in N, con i!=j.
    for i in range(1,N):
        for j in range(1,N):
            if i!=j:
                row3=[]
                val3=[]
                row3.append(u_vars[i])
                val3.append(1.0)
                row3.append(u_vars[j])
                val3.append(-1.0)
                row3.append(x_vars[i,j])
                val3.append(float(N)-1.0)
                Model.linear_constraints.add(lin_expr = [cplex.SparsePair(ind = row3, val= val3)], senses = 'L', rhs = [float(N)-2.0])

    
    solution=Model.solve()
    Model.write('modelo.lp')
    #Model.parameters.mip.pool.relgap.set(0.6)
    
    pool_solution=Model.populate_solution_pool()
    #print(pool_solution)

    def show_solution():
        print("\nVARLOS FUNCION OBJETIVO - DISTANCIA MINIMIA = {}".format(Model.solution.get_objective_value()))
        V=[i for i in range(N)]
        E=[]
        E1=[(i,j) for i in range(N) for j in range(N) if i!=j]
        for i in range(0,N):
            for j in range(0,N):
                if(Model.solution.get_values("x("+str(i)+","+str(j)+")")!=0.0):
                    print("x("+str(i)+","+str(j)+")"+" = "+str(Model.solution.get_values("x("+str(i)+","+str(j)+")")))
                    E.append((i,j))
        print("")

        for i in range(0,N):
            if(Model.solution.get_values("u("+str(i)+")")!=0.0):
                print("u("+str(i)+")"+" = "+str(Model.solution.get_values("u("+str(i)+")")))
        print("")

        G=nx.DiGraph()
        G.add_edges_from(E)
        G.add_nodes_from(V)

        
        pos=nx.spring_layout(G,k=0.3)

        print(Model.solution.get_values("x("+str(1)+","+str(0)+")")) #OBTENER VALOR DE UNA VARIABLE.
        print("ESTATUS_DE_LA_SOLUCION_ENCONTRADA:", Model.solution.get_status_string())
        print("SOLUCION_PRIMAL_OPTIMA?:", Model.solution.is_primal_feasible())
        #print(Model.variables.get_cols())
        
        nx.draw_networkx_nodes(G, pos)
        nx.draw_networkx_labels(G, pos)
        nx.draw_networkx_edges(G, pos, edgelist=E1, edge_color='blue', width=0.3 ,arrows=True) # highlight elist
        nx.draw_networkx_edges(G, pos, edge_color='black', width=1.8,arrows=True) # show all edges, thin lines
        

# turn off axis markings
        plt.axis('off')
        plt.savefig('grafo_tsp.png',dpi=20)
        plt.show()
    
    show_solution()

TSP(4)

And here is the data:

DATA

I really do not understand the problem, I use to do this daily and now I have this problem, any hints?


Solution

  • The problem is that

    x_varnames = x_vars.flatten()
    

    creates x_varnames as a numpy array while the argument to names for variables.add() is expected to be a list.

    You can fix this by defining x_varnames as

    x_varnames = x_vars.flatten().tolist()
    

    I am not sure whether it is a change in CPLEX or a change in numpy that causes this trouble.