Search code examples
benchmarkingoptaplanner

OptaPlanner benchmarking won't run


I'm trying to run an OptaPlanner benchmark with the following configuration:

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

    <inheritedSolverBenchmark>
        <solver>
            <solutionClass>org.acme.domain.Main</solutionClass>
            <entityClass>org.acme.domain.Standstill</entityClass>
            <entityClass>org.acme.domain.Visit</entityClass>
            <scoreDirectorFactory>
                <constraintProviderClass>org.acme.solver.MainConstraintProvider</constraintProviderClass>
                <initializingScoreTrend>ONLY_DOWN</initializingScoreTrend>
            </scoreDirectorFactory>
            <termination>
                <secondsSpentLimit>30</secondsSpentLimit>
            </termination>
        </solver>
        <problemBenchmarks>
            <solutionFileIOClass>org.acme.bootstrap.AcmeSolutionIO</solutionFileIOClass>
            <inputSolutionFile>data/latest.xml</inputSolutionFile>
        </problemBenchmarks>
    </inheritedSolverBenchmark>
    <solverBenchmark>
        <solver>
            <constructionHeuristic>
                <constructionHeuristicType>FIRST_FIT</constructionHeuristicType>
            </constructionHeuristic>
            <localSearch>
                <localSearchType>LATE_ACCEPTANCE</localSearchType>
            </localSearch>
        </solver>
    </solverBenchmark>
</plannerBenchmark>

However, I get this error message:

Exception in thread "main" org.optaplanner.benchmark.api.PlannerBenchmarkException: Benchmarking failed: failureCount (1). The exception of the firstFailureSingleBenchmarkRunner (blankData_Config_0_0) is chained.
    at org.optaplanner.benchmark.impl.DefaultPlannerBenchmark.benchmarkingEnded(DefaultPlannerBenchmark.java:326)
    at org.optaplanner.benchmark.impl.DefaultPlannerBenchmark.benchmark(DefaultPlannerBenchmark.java:100)
    at org.optaplanner.benchmark.impl.DefaultPlannerBenchmark.benchmarkAndShowReportInBrowser(DefaultPlannerBenchmark.java:424)
    at org.acme.bootstrap.BenchmarkApp.main(BenchmarkApp.kt:29)
Caused by: java.lang.IllegalStateException: The class (class java.lang.Long) should have a no-arg constructor to create a planning clone.
    at org.optaplanner.core.impl.domain.solution.cloner.FieldAccessingSolutionCloner.lambda$retrieveCachedConstructor$0(FieldAccessingSolutionCloner.java:90)
    at java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1708)
    at org.optaplanner.core.impl.domain.common.ConcurrentMemoization.computeIfAbsent(ConcurrentMemoization.java:44)
    at org.optaplanner.core.impl.domain.solution.cloner.FieldAccessingSolutionCloner.retrieveCachedConstructor(FieldAccessingSolutionCloner.java:85)
    at org.optaplanner.core.impl.domain.solution.cloner.FieldAccessingSolutionCloner$FieldAccessingSolutionClonerRun.constructClone(FieldAccessingSolutionCloner.java:158)
    at org.optaplanner.core.impl.domain.solution.cloner.FieldAccessingSolutionCloner$FieldAccessingSolutionClonerRun.clone(FieldAccessingSolutionCloner.java:150)
    at org.optaplanner.core.impl.domain.solution.cloner.FieldAccessingSolutionCloner$FieldAccessingSolutionClonerRun.process(FieldAccessingSolutionCloner.java:207)
    at org.optaplanner.core.impl.domain.solution.cloner.FieldAccessingSolutionCloner$FieldAccessingSolutionClonerRun.processQueue(FieldAccessingSolutionCloner.java:194)
    at org.optaplanner.core.impl.domain.solution.cloner.FieldAccessingSolutionCloner$FieldAccessingSolutionClonerRun.cloneSolution(FieldAccessingSolutionCloner.java:136)
    at org.optaplanner.core.impl.domain.solution.cloner.FieldAccessingSolutionCloner.cloneSolution(FieldAccessingSolutionCloner.java:73)
    at org.optaplanner.core.impl.score.director.AbstractScoreDirector.cloneSolution(AbstractScoreDirector.java:257)
    at org.optaplanner.core.impl.score.director.AbstractScoreDirector.cloneWorkingSolution(AbstractScoreDirector.java:250)
    at org.optaplanner.core.impl.solver.recaller.BestSolutionRecaller.updateBestSolutionAndFire(BestSolutionRecaller.java:129)
    at org.optaplanner.core.impl.constructionheuristic.DefaultConstructionHeuristicPhase.phaseEnded(DefaultConstructionHeuristicPhase.java:146)
    at org.optaplanner.core.impl.constructionheuristic.DefaultConstructionHeuristicPhase.solve(DefaultConstructionHeuristicPhase.java:98)
    at org.optaplanner.core.impl.solver.AbstractSolver.runPhases(AbstractSolver.java:99)
    at org.optaplanner.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:192)
    at org.optaplanner.benchmark.impl.SubSingleBenchmarkRunner.call(SubSingleBenchmarkRunner.java:122)
    at org.optaplanner.benchmark.impl.SubSingleBenchmarkRunner.call(SubSingleBenchmarkRunner.java:42)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
    at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.NoSuchMethodException: java.lang.Long.<init>()
    at java.base/java.lang.Class.getConstructor0(Class.java:3585)
    at java.base/java.lang.Class.getDeclaredConstructor(Class.java:2754)
    at org.optaplanner.core.impl.domain.solution.cloner.FieldAccessingSolutionCloner.lambda$retrieveCachedConstructor$0(FieldAccessingSolutionCloner.java:88)
    ... 22 more

I've tried many other benchmark configs including with <solverBenchmarkBluePrintType>CONSTRUCTION_HEURISTIC_WITH_AND_WITHOUT_LOCAL_SEARCH</solverBenchmarkBluePrintType> but none of them work either.

I had it working previously, but I went back to it after a number of changes and it no longer works.

I'm using a SimpleLongScore now instead of a SimpleScore and I'm wondering if that has anything to do with the error since before it wasn't throwing this exception.

Any ideas?

Edit #1:
I wish I could provide more code, but I really don't know what code to include.

The bizarre thing is that OptaPlanner runs just fine through mvn compile quarkus:dev, but when I run my benchmark app, from the main entry, it gives the errors as mentioned before, java.lang.IllegalStateException: The class (class java.lang.Long) should have a no-arg constructor to create a planning clone.

Here's my main:

    fun main(args: Array<String>) {
        val plannerBenchmarkFactory:PlannerBenchmarkFactory = PlannerBenchmarkFactory.createFromXmlResource("benchmarkBluePrintConfig.xml")
        val plannerBenchmark: PlannerBenchmark = plannerBenchmarkFactory.buildPlannerBenchmark()
        plannerBenchmark.benchmarkAndShowReportInBrowser()
    }

The solverConfig.xml can also be the same for both, but only the benchmark app throws the error. It's pretty odd to me.


Solution

  • I figured it out.

    In my Visit class I was using a @CustomShadowVariable:

        @DeepPlanningClone
        @CustomShadowVariable(
            variableListenerClass = ArrivalTimeUpdatingVariableListener::class,
            sources = [PlanningVariableReference(variableName = "previousStandstill")]
        )
        var arrivalTime: Long? = null
    

    Removing @DeepPlanningClone solved the problem.

    I have no idea why it runs fine when the SolverManager is @Inject'd as opposed to throwing the error when SolverConfig/SolverManager is created through the API (as it is in my Benchmark App).