title: python-constraint: setting a constraint dependent on a function's output
body: <p>I've been making a system that takes in data about drivers, potential passengers and their locations, and attempts to optimise the number of passengers that can get a lift with a driver given some constraints. I am using the python-constraint module, and the decision variables are represented thusly:</p>
  
  <pre><code>p = [(passenger, driver) for driver in drivers for passenger in passengers]
  driver_set = [zip(passengers, [e1]*len(drivers)) for e1 in drivers]
  passenger_set = [zip([e1]*len(passengers), drivers) for e1 in passengers]
  self.problem.addVariables(p, [0,1])
  </code></pre>
  
  <p>So, when I print the value of p and the driver_set and passenger_set, I get the following output (given the test data I provided):</p>
  
  <pre><code>[(0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1)] # p
  [[(0, 0), (0, 1)], [(1, 0), (1, 1)], [(2, 0), (2, 1)]] # passenger_set
  [[(0, 0), (1, 0)], [(0, 1), (1, 1)]] # driver_set
  </code></pre>
  
  <p>So, there are 3 passengers and 2 drivers: the variable (2,0) would mean that passenger 2 is in car 0, and so on. I have added the following constraints to make sure that no passenger goes in more than one car, and that a driver can't have more people than seats:</p>
  
  <pre><code>for passenger in passenger_set:
          self.problem.addConstraint(MaxSumConstraint(1), passenger)
  for driver in driver_set:
          realdriver = self.getDriverByOpId(driver[0][1])
          self.problem.addConstraint(MaxSumConstraint(realdriver.numSeats), driver)
  </code></pre>
  
  <p>This worked - all the solutions generated satisfied these constraints. However, I would now like to add constraints saying that any solution shouldn't involve the drivers going more than a certain distance. I have a function that takes in a driver (same format as an entity from driver_set) and calculates the shortest distance for the driver to pick up all passengers. I have tried to add the constraints like this:</p>
  
  <pre><code>for driver in driver_set:
          self.problem.addConstraint(MaxSumConstraint(MAX_DISTANCE), [self.getRouteDistance(self.getShortestRoute(driver))])
  </code></pre>
  
  <p>This gave the following error:</p>
  
  <pre><code>KeyError: 1.8725031790578293
  </code></pre>
  
  <p>I'm not sure how this constraint should be defined for python-constraint: there's only one shortest distance value for each driver. Should I use a lambda function for this?</p>
  
  <p><strong>EDIT</strong></p>
  
  <p>I tried implementing a lambda version of this, however I don't seem to have the lambda syntax down. I've looked everywhere but can't seem to find what's wrong with this. Basically I replaced the last snippet of code (adding the constraint to limit the value of getRouteDistance(driver)) and instead put this:</p>
  
  <pre><code>for driver in driver_set:
      self.problem.addConstraint(lambda d: self.getRouteDistance(d) &lt;= float(MAX_DISTANCE), driver)
  </code></pre>
  
  <p>But then I got this error (notice it's not called from the line I edited, it's from problem.getSolutions() which comes after):</p>
  
  <pre><code>File "allocation.py", line 130, in buildProblem
  for solution in self.problem.getSolutions():
  File "/Users/wadben/Documents/Dev/Python/sp-allocation/constraint.py", line 236, in getSolutions
  return self._solver.getSolutions(domains, constraints, vconstraints)
  File "/Users/wadben/Documents/Dev/Python/sp-allocation/constraint.py", line 529, in getSolutions
  return list(self.getSolutionIter(domains, constraints, vconstraints))
  File "/Users/wadben/Documents/Dev/Python/sp-allocation/constraint.py", line 506, in getSolutionIter
  pushdomains):
  File "/Users/wadben/Documents/Dev/Python/sp-allocation/constraint.py", line 939, in __call__
  self.forwardCheck(variables, domains, assignments)))
  File "/Users/wadben/Documents/Dev/Python/sp-allocation/constraint.py", line 891, in forwardCheck
  if not self(variables, domains, assignments):
  File "/Users/wadben/Documents/Dev/Python/sp-allocation/constraint.py", line 940, in __call__
  return self._func(*parms)
  TypeError: &lt;lambda&gt;() takes exactly 1 argument (3 given)
  </code></pre>
  
  <p>Has anyone else tried to do anything like this? I can't see why the constraint library wouldn't allow this.</p>