<commit_before>= Upgrade recipe 7.3
:awestruct-description: Upgrade to OptaPlanner 7.3 from a previous version.
:awestruct-layout: upgradeRecipeBase
:awestruct-priority: 0.5
:awestruct-upgrade_recipe_version: 7.3

== From 7.2.0.Final to 7.3.0.Final

[.upgrade-recipe-minor]
=== `SolutionFileIO`: `getOutputFileExtension()` is now defaulted

It's no longer needed to implement `getOutputFileExtension()` of the `SolutionFileIO` interface
if it returns the same as `getInputFileExtension()`.

Before in `*.java`:
[source, java]
----
public class VehicleRoutingFileIO implements SolutionFileIO<VehicleRoutingSolution> {

    @Override
    public String getInputFileExtension() {
        return "vrp";
    }

    @Override
    public String getOutputFileExtension() {
        return "vrp";
    }

    ...
}
----

After in `*.java`:
[source, java]
----
public class VehicleRoutingFileIO implements SolutionFileIO<VehicleRoutingSolution> {

    @Override
    public String getInputFileExtension() {
        return "vrp";
    }

    ...
}
----

[.upgrade-recipe-minor]
=== Benchmarker: direct POJO input

The benchmarker now also accepts problem instances directly, without reading them from disk.
If you're generating your problems or fetching them from a database,
it might be interesting to switch to this approach (otherwise stick with the old approach because it works offline).

Before in `*.java`:
[source, java]
----
    CloudBalance problem1 = readFromDatabase(...);
    CloudBalance problem2 = readFromDatabase(...);
    ...
    CloudBalanceFileIO solutionFileIO = new CloudBalanceFileIO();
    solutionFileIO.write(problem1, new File("tmp/problem1.xml"));
    solutionFileIO.write(problem2, new File("tmp/problem1.xml"));
    ...
    PlannerBenchmark plannerBenchmark = benchmarkFactory.buildPlannerBenchmark();
    plannerBenchmark.benchmark();
----

Before in `*BenchmarkConfig.xml`:
[source, xml]
----
    <problemBenchmarks>
      <solutionFileIOClass>...CloudBalanceFileIO</solutionFileIOClass>
      <inputSolutionFile>tmp/problem1.xml</inputSolutionFile>
      <inputSolutionFile>tmp/problem2.xml</inputSolutionFile>
      ...
    </problemBenchmarks>
----

After in `*.java`:
[source, java]
----
    CloudBalance problem1 = readFromDatabase(...);
    CloudBalance problem2 = readFromDatabase(...);
    ...
    PlannerBenchmark plannerBenchmark = benchmarkFactory.buildPlannerBenchmark(problem1, problem2, ...);
    plannerBenchmark.benchmark();
----

After in `*BenchmarkConfig.xml`:
[source, xml]
----
    <problemBenchmarks>
    </problemBenchmarks>
----<commit_msg>PLANNER-724 Benchmarker should include BEST_SCORE statistic by default<commit_after>= Upgrade recipe 7.3
:awestruct-description: Upgrade to OptaPlanner 7.3 from a previous version.
:awestruct-layout: upgradeRecipeBase
:awestruct-priority: 0.5
:awestruct-upgrade_recipe_version: 7.3

== From 7.2.0.Final to 7.3.0.Final

[.upgrade-recipe-minor]
=== `SolutionFileIO`: `getOutputFileExtension()` is now defaulted

It's no longer needed to implement `getOutputFileExtension()` of the `SolutionFileIO` interface
if it returns the same as `getInputFileExtension()`.

Before in `*.java`:
[source, java]
----
public class VehicleRoutingFileIO implements SolutionFileIO<VehicleRoutingSolution> {

    @Override
    public String getInputFileExtension() {
        return "vrp";
    }

    @Override
    public String getOutputFileExtension() {
        return "vrp";
    }

    ...
}
----

After in `*.java`:
[source, java]
----
public class VehicleRoutingFileIO implements SolutionFileIO<VehicleRoutingSolution> {

    @Override
    public String getInputFileExtension() {
        return "vrp";
    }

    ...
}
----

[.upgrade-recipe-minor]
=== Benchmarker: direct POJO input

The benchmarker now also accepts problem instances directly, without reading them from disk.
If you're generating your problems or fetching them from a database,
it might be interesting to switch to this approach (otherwise stick with the old approach because it works offline).

Before in `*.java`:
[source, java]
----
    CloudBalance problem1 = readFromDatabase(...);
    CloudBalance problem2 = readFromDatabase(...);
    ...
    CloudBalanceFileIO solutionFileIO = new CloudBalanceFileIO();
    solutionFileIO.write(problem1, new File("tmp/problem1.xml"));
    solutionFileIO.write(problem2, new File("tmp/problem1.xml"));
    ...
    PlannerBenchmark plannerBenchmark = benchmarkFactory.buildPlannerBenchmark();
    plannerBenchmark.benchmark();
----

Before in `*BenchmarkConfig.xml`:
[source, xml]
----
    <problemBenchmarks>
      <solutionFileIOClass>...CloudBalanceFileIO</solutionFileIOClass>
      <inputSolutionFile>tmp/problem1.xml</inputSolutionFile>
      <inputSolutionFile>tmp/problem2.xml</inputSolutionFile>
      ...
    </problemBenchmarks>
----

After in `*.java`:
[source, java]
----
    CloudBalance problem1 = readFromDatabase(...);
    CloudBalance problem2 = readFromDatabase(...);
    ...
    PlannerBenchmark plannerBenchmark = benchmarkFactory.buildPlannerBenchmark(problem1, problem2, ...);
    plannerBenchmark.benchmark();
----

After in `*BenchmarkConfig.xml`:
[source, xml]
----
    <problemBenchmarks>
    </problemBenchmarks>
----

[.upgrade-recipe-minor]
=== Benchmarker: `BEST_SCORE` statistic by default

The benchmarker now includes the `BEST_SCORE` statistic by default.
It no longer needs to be explicitly configured.

Before in `*BenchmarkConfig.xml`:
[source, xml]
----
    <problemBenchmarks>
      ...
      <problemStatisticType>BEST_SCORE</problemStatisticType>
    </problemBenchmarks>
----

After in `*BenchmarkConfig.xml`:
[source, xml]
----
    <problemBenchmarks>
      ...
    </problemBenchmarks>
----

To disable the `BEST_SCORE` statistic, use `<problemStatisticEnabled>` in `*BenchmarkConfig.xml`:
[source, xml]
----
    <problemBenchmarks>
      ...
      <problemStatisticEnabled>false</problemStatisticEnabled>
    </problemBenchmarks>
----
{'fraction_non_alphanumeric': 0.1275201612903226, 'fraction_numerical': 0.009240591397849463, 'mean_word_length': 3.7246031746031747, 'pattern_counts': {'":': 0, '<': 38, '<?xml version=': 0, '>': 38, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 22}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5207016', 'n_tokens_mistral': 1898, 'n_tokens_neox': 1789, 'n_words': 441}