Menu Close

Chapter 7. Configuring the Red Hat build of OptaPlanner solver

You can use the following methods to configure your OptaPlanner solver:

  • Use an XML file.
  • Use the SolverConfig API.
  • Add class annotations and JavaBean property annotations on the domain model.
  • Control the method that OptaPlanner uses to access your domain.
  • Define custom properties.

7.1. Using an XML file to configure the OptaPlanner solver

You can use an XML file to configure the solver. In a typical project that follows the Maven directory structure, after you build a Solver instance with the SolverFactory, the solverConfig XML file is located in the $PROJECT_DIR/src/main/resources/org/optaplanner/examples/<PROJECT>/solver directory, where <PROJECT> is the name of your OptaPlanner project. Alternatively, you can create a SolverFactory from a file with SolverFactory.createFromXmlFile(). However, for portability reasons, a classpath resource is recommended.

Both a Solver and a SolverFactory have a generic type called Solution_, which is the class representing a planning problem and solution.

OptaPlanner makes it relatively easy to switch optimization algorithms by changing the configuration.

Procedure

  1. Build a Solver instance with the SolverFactory.
  2. Configure the solver configuration XML file:

    1. Define the model.
    2. Define the score function.
    3. Optional: Configure the optimization algorithm.

      The following example is a solver XML file for the NQueens problem:

      <?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">
        <!-- Define the model -->
        <solutionClass>org.optaplanner.examples.nqueens.domain.NQueens</solutionClass>
        <entityClass>org.optaplanner.examples.nqueens.domain.Queen</entityClass>
      
        <!-- Define the score function -->
        <scoreDirectorFactory>
          <scoreDrl>org/optaplanner/examples/nqueens/solver/nQueensConstraints.drl</scoreDrl>
        </scoreDirectorFactory>
      
        <!-- Configure the optimization algorithms (optional) -->
        <termination>
          ...
        </termination>
        <constructionHeuristic>
          ...
        </constructionHeuristic>
        <localSearch>
          ...
        </localSearch>
      </solver>
      Note

      On some environments, for example OSGi and JBoss modules, classpath resources such as the solver config, score DRLs, and domain classe) in your JAR files might not be available to the default ClassLoader of the optaplanner-core JAR file. In those cases, provide the ClassLoader of your classes as a parameter:

             SolverFactory<NQueens> solverFactory = SolverFactory.createFromXmlResource(
                     ".../nqueensSolverConfig.xml", getClass().getClassLoader());
  3. Configure the SolverFactory with a solver configuration XML file, provided as a classpath resource as defined by ClassLoader.getResource():

           SolverFasctory<NQueens> solverFactory = SolverFactory.createFromXmlResource(
                   "org/optaplanner/examples/nqueens/solver/nqueensSolverConfig.xml");
           Solver<NQueens> solver = solverFactory.buildSolver();

7.2. Using the Java API to configure the OptaPlanner solver

You can configure a solver by using the SolverConfig API. This is especially useful to change values dynamically at runtime. The following example changes the running time based on system properties before building the Solver in the NQueens project:

        SolverConfig solverConfig = SolverConfig.createFromXmlResource(
                "org/optaplanner/examples/nqueens/solver/nqueensSolverConfig.xml");
        solverConfig.withTerminationConfig(new TerminationConfig()
                        .withMinutesSpentLimit(userInput));

        SolverFactory<NQueens> solverFactory = SolverFactory.create(solverConfig);
        Solver<NQueens> solver = solverFactory.buildSolver();

Every element in the solver configuration XML file is available as a Config class or a property on a Config class in the package namespace org.optaplanner.core.config. These Config classes are the Java representation of the XML format. They build the runtime components of the package namespace org.optaplanner.core.impl and assemble them into an efficient Solver.

Note

To configure a SolverFactory dynamically for each user request, build a template SolverConfig during initialization and copy it with the copy constructor for each user request. The following example shows how to do this with the NQueens problem:

    private SolverConfig template;

    public void init() {
        template = SolverConfig.createFromXmlResource(
                "org/optaplanner/examples/nqueens/solver/nqueensSolverConfig.xml");
        template.setTerminationConfig(new TerminationConfig());
    }

    // Called concurrently from different threads
    public void userRequest(..., long userInput) {
        SolverConfig solverConfig = new SolverConfig(template); // Copy it
        solverConfig.getTerminationConfig().setMinutesSpentLimit(userInput);
        SolverFactory<NQueens> solverFactory = SolverFactory.create(solverConfig);
        Solver<NQueens> solver = solverFactory.buildSolver();
        ...
    }

7.3. OptaPlanner annotation

You must specify which classes in your domain model are planning entities, which properties are planning variables, and so on. Use one of the following methods to add annotations to your OptaPlanner project:

  • Add class annotations and JavaBean property annotations on the domain model. The property annotations must be on the getter method, not on the setter method. Annotated getter methods do not need to be public. This is the recommended method.
  • Add class annotations and field annotations on the domain model. Annotated fields do not need to be public.

7.4. Specifying OptaPlanner domain access

By default, OptaPlanner accesses your domain using reflection. Reflection is reliable but slow compared to direct access. Alternatively, you can configure OptaPlanner to access your domain using Gizmo, which will generate bytecode that directly accesses the fields and methods of your domain without reflection. However, this method has the following restrictions:

  • The planning annotations can only be on public fields and public getters.
  • io.quarkus.gizmo:gizmo must be on the classpath.
Note

These restrictions do not apply when you use OptaPlanner with Quarkus because Gizmo is the default domain access type.

Procedure

To use Gizmo outside of Quarkus, set the domainAccessType in the solver configuration:

  <solver>
    <domainAccessType>GIZMO</domainAccessType>
  </solver>

7.5. Configuring custom properties

In your OptaPlanner projects, you can add custom properties to solver configuration elements that instantiate classes and have documents that explicitly mention custom properties.

Prerequisites

  • You have a solver.

Procedure

  1. Add a custom property.

    For example, if your EasyScoreCalculator has heavy calculations which are cached and you want to increase the cache size in one benchmark add the myCacheSize property:

      <scoreDirectorFactory>
        <easyScoreCalculatorClass>...MyEasyScoreCalculator</easyScoreCalculatorClass>
        <easyScoreCalculatorCustomProperties>
          <property name="myCacheSize" value="1000"/><!-- Override value -->
        </easyScoreCalculatorCustomProperties>
      </scoreDirectorFactory>
  2. Add a public setter for each custom property, which is called when a Solver is built.

    public class MyEasyScoreCalculator extends EasyScoreCalculator<MySolution, SimpleScore> {
    
            private int myCacheSize = 500; // Default value
    
            @SuppressWarnings("unused")
            public void setMyCacheSize(int myCacheSize) {
                this.myCacheSize = myCacheSize;
            }
    
        ...
    }

    Most value types are supported, including boolean, int, double, BigDecimal, String and enums.