Kyle
Kyle

Reputation: 23

using a variable in addConstraint produces a wrong answer but not using variables works fine

my code is working if done like so

from constraint import *
import itertools
def main():
    problem = Problem()
    x = [0,1,2,3]
    f = list(itertools.product(x,x,x,x))

    problem.addVariable("a", f)

    problem.addConstraint(lambda a: a[0] == a.count(0), "a",)

    problem.addConstraint(lambda a: a[1] == a.count(1), "a",)

    problem.addConstraint(lambda a: a[2] == a.count(2), "a",)

    problem.addConstraint(lambda a: a[3] == a.count(3), "a",)    

    solutions = problem.getSolutions()
    print "Found %d solutions!" % len(solutions)

the answer would be [{'a': (2, 0, 2, 0)}, {'a': (1, 2, 1, 0)}]

but if I use variables it goes haywire

from constraint import *
import itertools
def main():
    problem = Problem()
    x = [0,1,2,3]
    f = list(itertools.product(x,x,x,x))

    problem.addVariable("a", f)

    x = 0
    problem.addConstraint(lambda a: a[x] == a.count(0), "a",)
    x = 1
    problem.addConstraint(lambda a: a[x] == a.count(1), "a",)
    x = 2
    problem.addConstraint(lambda a: a[x] == a.count(2), "a",)

    problem.addConstraint(lambda a: a[3] == a.count(3), "a",)  

    solutions = problem.getSolutions()
    print "Found %d solutions!" % len(solutions)

which results to an empty list. I want to be able to put this in a loop but I don't know what's going on. I may just be missing something very basic but it only works if I use real numbers

Upvotes: 2

Views: 216

Answers (1)

mgilson
mgilson

Reputation: 309831

The problem is that when you "add variables", the values are looked up with the lambda functions are called, not when they are defined. In this case, I'm guessing they don't get called until problem.getSolutions() which means that the value of x will be 2 in each of your function calls (instead of 0, 1 and 2 respectively as in the initial code).

This is a very common "gotcha" in python code and you can fix it by setting a default argument (as those get evaluated once, when the function is created).

lambda a, x=x: a[x] == a.count(0)

Upvotes: 3

Related Questions