OptaPlanner continues as Timefold
All blog posts

Timefold Solver 1.4.0 brings explainable score

Have you ever received a solution from the Solver and wondered what -3hard/-11soft actually means? Or had to explain it to your end-users? Now, you can just show it to them. In Timefold Solver 1.4.0, you can break down the score of a solution into constraints and constraint matches, to make it understandable for your end-users.

Let’s take a closer look and find out what’s new in another exciting monthly release of Timefold Solver.

Break down the score per constraint

We expand on our existing functionality by making score explanations easier to use than ever before. Here’s how you start using this new feature:

// First, we get some solution from the solver. Nothing new here, business as usual.
SolverJob<Timetable, ...> solverJob = solverManager.solve(...);
Timetable timetable = solverJob.getFinalBestSolution();

// Now that we have the timetable, we can analyze the score.
ScoreAnalysis<HardSoftScore> scoreAnalysis = solutionManager.analyze(timetable);

The ScoreAnalysis object holds the total score of the analyzed solution, and a breakdown of the score per constraints. This allows you to easily see which constraints are impacting your solution the most.

System.out.println("Total score: " + scoreAnalysis.score());
scoreAnalysis.constraintMap().forEach((constraint, constraintAnalysis) -> {
   System.out.println("              Constraint: " + constraint);
   System.out.println("Score for the constraint: " + constraintAnalysis.score());

You can break the score down even further, by going deeper into the ConstraintAnalysis object. Each such object contains a list of matches, which are the individual violations of the constraint. This allows you to see which planning entities or values are causing the constraint to be violated. also called a justification.

for (MatchAnalysis<HardSoftScore> match: constraintAnalysis.matches()) {
    System.out.println("        Match score: " + match.score());
    System.out.println("Match justification: " + match.justification());

With this data structure, you have the full overview of your planning solution and how it was scored by Timefold Solver. But we did not stop there!

Score analysis is JSON-friendly

In today’s world, what good are excellent backend APIs if you cannot send the results over the wire to the frontend? We’ve got you covered. The ScoreAnalysis object is JSON-friendly, which means you can easily serialize it and send it over the wire. In Quarkus and Spring Boot, the ScoreAnalysis object will automatically serialize to JSON such as this:

  "score" : "0hard/4soft",
  "constraints" : [ {
    "package" : "org.acme.schooltimetabling.domain",
    "name" : "Teacher time efficiency",
    "score" : "0hard/5soft",
    "matches" : [ {
      "score" : "0hard/1soft",
      "justification" : {
        "lessonId1": 5,
        "lessonId2": 17,
        "teacher": "I. Jones"
      ... ] }
    }, {
    "package" : "org.acme.schooltimetabling.domain",
    "name" : "Student group subject variety",
    "score" : "0hard/-1soft",
    "matches" : [ ... ]
    } ]

We see the score is made up of two constraints here, each with their own score and matches. The frontend can then easily display the score breakdown to the user, such as this:

Score breakdown on the front end.

Note that in this case, we have chosen not to display the individual constraint matches to make the visualization simpler. In a more detail-oriented view, you may choose to display the individual matches as well.

See it in action

The code snippets above are taken from the School Timetabling quickstart in the Timefold Quickstarts Github repository. You can run the quickstart locally by following a few short steps. Clone it today and experience Timefold Solver for yourself!

Comparing solutions to one another

In addition to the new score explanation functionality, we have also made it easier to compare two solutions to one another. You can use the same score analysis functionality above to compare two solutions.

The ScoreAnalysis object has a diff(ScoreAnalysis otherScoreAnalysis) method which, when called, returns a new ScoreAnalysis object. This object holds the differences between the two solutions. It shows the difference in score and the difference in individual constraints, down to every single constraint match.

Check out our docs to learn everything there is about understanding the score.

What else is new?

Besides the features above, we have brought the usual battery of bug fixes and performance improvements. With Timefold Solver 1.4.0, you can enjoy slightly faster Constraint Streams and an even more stable experience. We also upgraded Quarkus, Spring and other dependencies to their latest versions.

We are also happy to have been included in Spring Initializr, making your getting started experience with Spring Boot and Timefold Solver even easier!


Timefold Solver continues full steam ahead. The new explainable score functionality is a great addition, and a feature much requested by our users. Upgrade now to get the best release yet!