title: Traveling salesman variant
body: <p>I'm trying to build a model using the traveling salesman as a starting point.
  Instead of being just one traveling salesman I need it to be multiple salesmans that have to reach the same end node and then come back to the origin node. The logic is the same, trying to minimize distance traveled by all salesmans and that between all of them, they cover every node (city).
  I implemented the model using excel's solver, but it has problems with subtours, so I decided to use gurobi since it had pre made constraint to fix that in the <a href="https://gurobi.github.io/modeling-examples/traveling_salesman/tsp.html" rel="nofollow noreferrer">traveling salesman example</a>.</p>
  
  <p>The basic optimization model is this:</p>
  
  <p><a href="https://i.stack.imgur.com/W9uyT.gif" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/W9uyT.gif" alt="enter image description here"></a></p>
  
  <p>Plus the subtour constraints. </p>
  
  <p>The model I'm doing is more complicated because it needs times of arrivals, volume restrictions and others, so if I can't make this work, I surely cannot proceed.</p>
  
  <p>Before typing the code my inputs are:</p>
  
  <pre><code>nodes = ['Node 1', 'Node 2', ... , 'Node9'] 
  dist = {(Node1,Node2): 0.03, ..., (Node9, Node8): 0.5} #--&gt; Distances between nodes for different nodes
  salesmans = ['salesman1', 'salesman2']
  </code></pre>
  
  <p>The code I used in gurobi/python is:</p>
  
  <pre><code>import math
  import json
  from itertools import combinations,product
  
  def subtourelim(model, where):
      if where == GRB.Callback.MIPSOL:
          # make a list of edges selected in the solution
          vals = model.cbGetSolution(model._vars)
          selected = gp.tuplelist((i, j, k) for i, j, k in model._vars.keys()
                           if vals[i, j, k] &gt; 0.5)
          # find the shortest cycle in the selected edge list
          tour = subtour(selected)
          if len(tour) &lt; len(nodes):
              # add subtour elimination constr. for every pair of cities in subtour
              model.cbLazy(gp.quicksum(model._vars[i, j, k] for i, j, k in combinations(tour, 2))
                       &lt;= len(tour)-1)
  def subtour(edges):
      unvisited = nodes[:]
      cycle = nodes[:] # Dummy - guaranteed to be replaced
      while unvisited:  # true if list is non-empty
          thiscycle = []
          neighbors = unvisited
          while neighbors:
              current = neighbors[0]
              thiscycle.append(current)
              unvisited.remove(current)
              neighbors = [j for i, j, k in edges.select(current, '*')
                       if j in unvisited]
          if len(thiscycle) &lt;= len(cycle):
              cycle = thiscycle # New shortest subtour
      return cycle
  
  import gurobipy as gp
  from gurobipy import GRB
  
  m = gp.Model()
  
  # Variables: is city 'i' adjacent to city 'j' on the tour?
  vars = m.addVars(dist.keys(), salesmans, obj=dist, vtype=GRB.BINARY, name='asignacion')
  
  
  # Constraints: A node can't be visited by itself o leave to visit itself
  for i, j, k in vars.keys():
      if i==j:
          m.addConstr(vars[i, j, k] == 0)
  
  # From each node you have to visit one other node
  m.addConstrs((vars.sum(i,'*','*') == 1 for i in nodes))
  # Each node has to be visited once
  m.addConstrs((vars.sum('*',j,'*') == 1 for j in nodes))
  
  
  # Optimize the model
  m._vars = vars
  m.Params.lazyConstraints = 1
  m.optimize(subtourelim)
  </code></pre>
  
  <p>When I just try to add those few constraints, the model has errors on the subtour functions that I don't understand</p>
  
  <pre><code>ValueError                                Traceback (most recent call last)
  callback.pxi in gurobipy.CallbackClass.callback()
  
  &lt;ipython-input-2-a1cb8952ed8c&gt; in subtourelim(model, where)
       13         if len(tour) &lt; len(nodes):
       14             # add subtour elimination constr. for every pair of cities in subtour
  ---&gt; 15             model.cbLazy(gp.quicksum(model._vars[i, j, k] for i, j, k in combinations(tour, 2))
       16                          &lt;= len(tour)-1)
  
  gurobi.pxi in gurobipy.quicksum()
  
  &lt;ipython-input-2-a1cb8952ed8c&gt; in &lt;genexpr&gt;(.0)
       13         if len(tour) &lt; len(nodes):
       14             # add subtour elimination constr. for every pair of cities in subtour
  ---&gt; 15             model.cbLazy(gp.quicksum(model._vars[i, j, k] for i, j, k in combinations(tour, 2))
       16                          &lt;= len(tour)-1)
  
  ValueError: not enough values to unpack (expected 3, got 2)
  </code></pre>
  
  <p>If anyone can help me I would be very very grateful :) </p>