nucleic / kiwi

Efficient C++ implementation of the Cassowary constraint solving algorithm
https://kiwisolver.readthedocs.io/en/latest/
Other
679 stars 88 forks source link

Is it possible to tell the Solver to prefer smaller or larger solutions? #164

Open gsingh93 opened 1 year ago

gsingh93 commented 1 year ago

Consider this example:

from kiwisolver import Solver, Variable

x = Variable("x")
s = Solver()

c = x >= 10
s.addConstraint(c)
s.updateVariables()
print(f"Added constraint {c}, x is now {x.value()}")

c = x <= 20
s.addConstraint(c)
s.updateVariables()
print(f"Added constraint {c}, x is now {x.value()}")

print("Making a new Solver")

s = Solver()

c = x <= 20
s.addConstraint(c)
s.updateVariables()
print(f"Added constraint {c}, x is now {x.value()}")

c = x >= 10
s.addConstraint(c)
s.updateVariables()
print(f"Added constraint {c}, x is now {x.value()}")

The output shows that the order in which constraints are added affects the solution:

Added constraint 1 * x + -10 >= 0 | strength = 1.001e+09, x is now 10.0
Added constraint 1 * x + -20 <= 0 | strength = 1.001e+09, x is now 10.0
Making a new Solver
Added constraint 1 * x + -20 <= 0 | strength = 1.001e+09, x is now 20.0
Added constraint 1 * x + -10 >= 0 | strength = 1.001e+09, x is now 20.0

I'd like the solver to always prefer the largest or smallest possible solution, if possible. I'm guessing this may be difficult or impossible with a linear constraint solver, but I wanted to make sure there's no way to get around this aspect of the constraint solving system.

To be clear, in the real world the code will add a complicated set of constraints to the solver, so I don't actually know what the min and max values are, like in this example.

Qix- commented 1 year ago

Have you tried suggesting values, or using weak constraints to give high bounds to the values?

gsingh93 commented 1 year ago

Well, I don't know what values to suggest or what concrete bounds to add as weak constraints. The valid range for x could be [5, 10], [100, 1000], etc. If the range was [100, 1000], should I just suggest any small value and even if it's not satisfied the solver will give me the closest possible solution? I haven't used the suggestValue feature yet, I will experiment with it.

Qix- commented 1 year ago

I'm not entirely sure how suggest value works. I don't believe Cassowary has any way of suggesting how values are iterated upon, that's more how finite domain constraint solvers work. Cassowary (perhaps all linear constraint solvers? I'm not an expert) is more "any solution that fits the constraint space is considered 'correct'", which makes it perfect for layouts et al. It will try to break the least number of constraints possible, with the exception of producing an error if any required constraints are broken.

Hope that helps! Maybe the maintainers can give some more pointed, technical insight. I too am curious if this is feasible in any deterministic way.