Release Notes

This chapter lists new and noteworthy updates in OptaPlanner releases. OptaPlanner follows a 3-week release cycle. Bug fixes and minor improvements are generally not announced, which is why some of the minor releases are not mentioned here.

For release notes on OptaPlanner 7.x and older, please visit Release Notes on optaplanner.org.

OptaPlanner 8.x Release Notes

OptaPlanner 8.31.0.Final

Several OptaPlanner examples removed from the distribution

In an ongoing effort to clean up code and reduce technical debt, the following examples were removed the optaplanner-examples module:

  • Batch Scheduling,

  • Cheap Time,

  • Coach Shuttle Gathering,

  • Investment

  • and Rock Tour.

We believe these examples were rarely used if ever, and they did not showcase any unique feature of OptaPlanner that would not be showcased already in any of the 16 remaining examples and many quickstarts.

No OptaPlanner feature was removed or deprecated in the process.

Multiple entity classes with chained planning variables

Fixed a bug that prevented using two or more chained planning variables, each defined on a different planning entity class.

OptaPlanner 8.30.0.Final

OptaPlanner operator (experimental) is available in the distribution

While the OptaPlanner operator remains experimental, it has now become a part of the OptaPlanner distribution.

If you want to learn more about the operator, follow the Kubernetes demo.

OptaPlanner 8.29.0.Final

Custom justifications and indictments in Constraint Streams

With a new Constraint Streams API, it is now easy to define custom constraint justifications and indictments in your constraints:

    protected Constraint vehicleCapacity(ConstraintFactory factory) {
        return factory.forEach(Customer.class)
                .filter(customer -> customer.getVehicle() != null)
                .groupBy(Customer::getVehicle, sum(Customer::getDemand))
                .filter((vehicle, demand) -> demand > vehicle.getCapacity())
                .penalizeLong(HardSoftLongScore.ONE_HARD,
                        (vehicle, demand) -> demand - vehicle.getCapacity())
                .justifyWith((vehicle, demand, score) ->
                    new VehicleDemandOveruse(vehicle, demand, score))
                .indictWith((vehicle, demand) -> List.of(vehicle))
                .asConstraint("vehicleCapacity");
    }

Note the new methods: justifyWith(…​) and indictWith(…​). To find out more, see customizing justifications and indictments.

Compatible with JDK 19

OpenJDK 19 was recently released and OptaPlanner is fully compatible with it.

We always test our releases against the long-term supported versions of the JDK, currently 11 and 17, as well as against the latest release. We encourage you to upgrade your JDK regularly to benefit from the enhancements that come with the new releases.

New @ShadowVariable and @PiggybackShadowVariable annotations replace the @CustomShadowVariable

@ShadowVariable annotation is repeatable and allows to specify 1 listener per source variable.

@PiggybackShadowVariable is a specialized annotation to mark shadow variables that are updated by another shadow variable’s listener.

The @CustomShadowVariable has been deprecated.

Read more about custom shadow variables in the documentation.

Planning list variable

OptaPlanner now adds a limited support for planning list variables that can hold multiple planning values. The planning list variable provides an alternative approach to modeling planning problems that were previously modeled using the chained planning variable.

Both the planning list variable and the chained planning variable should be used with problems where the goal is to distribute a number of workload elements among limited resources in a specific order. For example, in vehicle routing, vehicles represent the limited resource and customers represent the workload elements.

The chained planning variable defines a recursive data structure, in which customers form chains ending with vehicles. On the other hand, the planning list variable allows for a more intuitive model where each vehicle holds a list of customers it goes to. It is defined using the new @PlaningListVariable annotation.

The planning list variable is a new feature and lacks some advanced features, that are available with the chained planning variable.

OptaPlanner 8.27.0.Final

Bavet is feature complete

The alternative constraint streams implementation Bavet is feature complete. You can now use it as an alternative to Drools (which is still the default).

Bavet will not be supported in Red Hat’s support offering. Drools intends to catch up performance wise.

OptaPlanner 8.24.0.Final

OptaWeb Employee Rostering demo application abandoned

The codebase for OptaWeb Employee Rostering demo application has been frozen and will no longer receive any updates.

We encourage users to check out the OptaPlanner Employee Rostering Quickstart for a simple and straight-forward way of integrating OptaPlanner in your application.

OptaPlanner 8.23.0.Final

Score DRL deprecated in favor of Constraint Streams

Support for Score DRL has been deprecated and users are encouraged to migrate to Constraint Streams at their earliest convenience. Read the migration guide from score DRL to Constraint Streams. Score DRL is not going away in OptaPlanner 8.

OptaPlanner 8.20.0.Final

SolverManager.addProblemChange() now returns CompletableFuture<Void>

SolverManager.addProblemChange() returns CompletableFuture<Void>, which completes when a new best solution containing the problem change has been passed to a user-defined Consumer.

OptaPlanner 8.17.0.Final

Real-time planning available on the SolverManager

The SolverManager now accepts problem changes via the addProblemChange() method, allowing for real-time planning without much boilerplate code.

Faster Solver creation

SolverFactory newly caches some internal data structures, leading to much faster Solver creation times. This is beneficial if you instantiate multiple Solver instances in quick succession.

OptaPlanner 8.12.0.Final

Documentation website

The latest final OptaPlanner documentation is now available on a new documentation website built using Antora. The single-HTML and PDF documentation will continue to be published in the archive.

Monitoring Support

OptaPlanner now uses Micrometer to monitor key metrics such as active solver count, solve durations, and error count.

OptaPlanner 8.10.0.Final

Support for Quarkus 2.0

OptaPlanner is now fully compatible with the recently released Quarkus 2.0.

OptaPlanner 8.7.0.Final

OptaPlanner quickstarts repository

There is a new quarkus-call-center quickstart that shows real-time planning of incoming calls in a call center.

Quarkus Call Center

OptaPlanner 8.5.0.Final

Mapping in Constraint Streams

The Constraint Streams API received a major new functionality. You can now modify your streams using mapping functions.

Ready for OpenJDK 16

We have made some tweaks under the hood so that your experience with the recently released OpenJDK 16 continues to be smooth.

Inject and Autowire ConstraintVerifier in Quarkus and Spring Boot

OptaWebs on Quarkus

OptaWeb Vehicle Routing and OptaWeb Employee Rostering have been migrated from Spring Boot to Quarkus.

Other noteworthy changes done during the migration to Quarkus:

  • OptaWeb Vehicle Routing back end has a new RESTful API. Client-server communication, that was previously done using WebSockets, now uses a combination of REST calls and Server-Sent Events.

  • OptaWeb Employee Rostering now uses Constraint Streams instead of DRL for score calculation.

Faster domain accessors and cloning with Gizmo

We have added Gizmo generated domain accessors and solution cloners, which offer better performance than the reflection based domain accessors and solution cloners.

OptaPlanner quickstarts repository

There is a new activemq-quarkus-school-timetabling quickstart that shows how to integrate ActiveMQ with OptaPlanner to horizontally scale when solving multiple data sets.

OptaPlanner 8.3.0.Final

Major performance improvements for Constraint Streams

The default implementation of the Constraint Streams API has seen major performance improvements. Use cases with tri and quad streams may experience order of magnitude speedups. Use cases with grouping are likely to experience some speedups too, albeit comparatively smaller.

Kudos to the Drools team for helping make this possible!

Constraint Streams groupBy() overloads for multiple collectors

The Constraint Streams API has been extended to allow using more than 2 collectors in a single grouping. The following is now possible:

return constraintFactory.from(ProductPrice.class)
    .groupBy(min(), max(), sum())
    .penalize(..., SimpleScore.ONE, (minPrice, maxPrice, sumPrices) -> ...);

OptaPlanner 8.0.0.Final

OptaPlanner quickstarts repository

The new OptaPlanner Quickstarts repository contains pretty web demos for several use cases. It also shows you how to integrate OptaPlanner with different technologies:

  • School timetabling: Assign lessons to timeslots and rooms to produce a better schedule for teachers and students.

    This application connects to a relational database and exposes a REST API, rendered by a pretty JavaScript UI.

    • quarkus-school-timetabling: Java, Maven or Gradle, Quarkus, H2

    • spring-boot-school-timetabling: Java, Maven or Gradle, Spring Boot, H2

    • kotlin-quarkus-school-timetabling: Kotlin, Maven, Quarkus, H2

  • Facility location problem (FLP): Pick the best geographical locations for new stores, distribution centers, COVID-19 test centers or telco masts.

    • quarkus-facility-location: Java, Maven, Quarkus

  • Factorio layout: Assign machines to assembly line locations to design the best factory layout.

    • quarkus-factorio-layout: Java, Maven, Quarkus

  • Maintenance scheduling: Coming soon

Future Java compatibility

The OptaPlanner 8 API has been groomed to maximize compatibility with the latest OpenJDK and GraalVM releases and game-changing platforms such as Quarkus. Meanwhile, we still fully support OpenJDK 11 and platforms such as Spring Boot or plain Java.

For example, when running OptaPlanner in Java 11 or higher with a classpath, OptaPlanner no longer triggers WARNING: An illegal reflective access operation has occurred for XStream.

Code completion for solverConfig.xml and benchmarkConfig.xml through XSD

To validate XML configuration during development, add the new XML Schema Definition (XSD) on the solver or benchmark configuration:

<?xml version="1.0" encoding="UTF-8"?>
<solver xmlns="https://www.optaplanner.org/xsd/solver" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://www.optaplanner.org/xsd/solver https://www.optaplanner.org/xsd/solver/solver.xsd">
  ...
</solver>

This enables code completion for XML in most IDEs:

SolverConfigCodeCompletion

Improved Quarkus extension

The OptaPlanner Quarkus extension is now stable and displays no warnings when compiling Java to a native executable.

ScoreManager now supports score explanation

The ScoreManager can now also explain why a solution has a certain score:

ScoreManager<TimeTable, HardSoftScore> scoreManager = ScoreManager.create(solverFactory);
...
ScoreExplanation<TimeTable, HardSoftScore> scoreExplanation = scoreManager.explain(timeTable);
System.out.println(scoreExplanation.getSummary());
...

Additionally, use scoreExplanation.getConstraintMatchTotalMap() and scoreExplanation.getIndictmentMap() to extract the ConstraintMatchTotal<HardSoftScore> and Indictment<HardSoftScore> information without triggering a new score calculation.

Various improvements

  • The ConstraintStreams API is now richer, more stable with better error messages and faster.

  • The SolverManager API now supports to listen to both best solution events and the solving ended event.

  • OptaPlanner no longer depends on Guava or Reflections.