HNHacker News
TopNewBestAskShowJobs

cchianel

160 karma · joined July 3, 2024

Software Engineer at Timefold <https://timefold.ai/>
submissionscomments
cchianel··on A practical introduction to constraint programming using CP-SAT and Python
Does

  constraint_factory.create_from_chain(
      ForEach(Shift)
      | Filter(lambda shift: shift.required_skill not in shift.employee.skills)
      | Penalize(HardSoftScore.ONE_HARD)
      | AsConstraint("Missing required skill")
  )
Feel more Pythonic than

  (
      constraint_factory.for_each(Shift)
      .filter(lambda shift: shift.required_skill not in shift.employee.skills)
      .penalize(HardSoftScore.ONE_HARD)
      .as_constraint("Missing required skill")
  )

?
cchianel··on A practical introduction to constraint programming using CP-SAT and Python
Let us know how we can improve! Feel free to start a discussion (https://github.com/TimefoldAI/timefold-solver/discussions) or submit an issue (https://github.com/TimefoldAI/timefold-solver-python/issues).

We aim to treat Python as a first-class citizen (while keeping it maintainable). For instance, many of the Java methods are mapped to properties on the Python classes with more Pythonic names (see `ScoreExplanation` for an example).

I suspect what gives the Java smell is probably the `SolverFactory`/`SolverConfig`, which is a lot of boilerplate code. A lot of the code can be generated, although we would need to design an API for that.

The fluent (method chaining) API might also be giving the Java smell; I don't see many fluent API being used in Python. In particular, needing to either end lines with `\` or surround the statement with brackets make long fluent chains annoying to use. This is harder to change, since there is no Pythonic alternative that I know of for method chaining.

cchianel··on A practical introduction to constraint programming using CP-SAT and Python
Well, you still write code. The difference is the code is written either in ordinary Python or Java and not as mathematical equations.

For example, to do the "Some employees are qualified to do either role, but others can only be a cashier, or a restocker." constraint in the article, it would be written like this:

  def required_skill(constraint_factory: ConstraintFactory):
      return (constraint_factory.for_each(Shift)
              .filter(lambda shift: shift.required_skill not in shift.employee.skills)
              .penalize(HardSoftScore.ONE_HARD)
              .as_constraint("Missing required skill")
              )
Some examples taken from Timefold quickstarts:

- Employee scheduling (https://github.com/TimefoldAI/timefold-quickstarts/tree/stab...)

- Vehicle routing (https://github.com/TimefoldAI/timefold-quickstarts/tree/stab...)

- School timetabling (https://github.com/TimefoldAI/timefold-quickstarts/tree/stab...)

cchianel··on A practical introduction to constraint programming using CP-SAT and Python
I think the reason why these tools are not accessible as they could be is because the vast majority of solvers are MIPs (Mixed Integer Programming) based, meaning the domain need to be written down using mathematical equations. This in turn means a user would need to be familiar with both the domain and mathematics in order to correctly write constraints.

That being said, MIPs are not the only kind of solvers. There are also "local search" based constraint solvers, which does not have the restriction that each constraint must be modelled as a relation or equation of integer variables. In local search solvers, the constraints are mostly treated as a black box that tells how good a particular solution is. As a consequent, local search solvers are typically unable to find the optimal solution (since it would require testing all possible solutions because the constraint is treated as a black box), but rather finds a "near-optimal" solution in reasonable time.

One local search based solver is Timefold Solver. In it, users annotate their domain so the solver knows what are the variables and possible values. This means instead of your constraints dealing with `int`, it would deal with `Shift` and `Employee`, and can access any of their methods.

Disclosure: I work on Timefold Solver

← PreviousPage 2 of 2