timefold-solver
timefold-solver copied to clipboard
Python easy_score_calculator results in KeyError
Describe the bug Attempting to use easy_score_calculator in a python solver causes a runtime error
Expected behavior No error
Actual behavior
Traceback (most recent call last):
File "DefaultSolver.java", line 196, in ai.timefold.solver.core.impl.solver.DefaultSolver.solve
Exception: Java Exception
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/home/jonathan/Development/eterna/OpenKnotScorePipeline/.venv/lib/python3.12/site-packages/timefold/solver/_solver.py", line 109, in solve
java_solution = self._delegate.solve(java_problem)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ai.timefold.jpyinterpreter.types.errors.lookup.ai.timefold.jpyinterpreter.types.errors.lookup.KeyError: ai.timefold.jpyinterpreter.types.errors.lookup.KeyError: HardSoftScore
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/jonathan/Development/eterna/OpenKnotScorePipeline/repro.py", line 51, in <module>
res = solver.solve(problem)
^^^^^^^^^^^^^^^^^^^^^
File "/home/jonathan/Development/eterna/OpenKnotScorePipeline/.venv/lib/python3.12/site-packages/timefold/solver/_solver.py", line 111, in solve
raise unwrap_python_like_object(e)
_jpyinterpreter.conversions.unwrap_python_like_object.<locals>.WrappedException:
KeyError: HardSoftScore
Traceback (most recent call last):
File "DefaultSolver.java", line 196, in solve
File "DefaultSolver.java", line 225, in solvingStarted
File "AbstractSolver.java", line 66, in solvingStarted
File "BestSolutionRecaller.java", line 50, in solvingStarted
File "EasyScoreDirector.java", line 49, in calculateScore
File "<unknown>", line -1, in calculateScore
File "/home/jonathan/Development/eterna/OpenKnotScorePipeline/.venv/lib/python3.12/site-packages/timefold/solver/score/_annotations.py", line 89, in wrapped_easy_score_calculator
return easy_score_calculator_function(solution)._to_java_score()
File "<unknown>", line -1, in $call
File "/home/jonathan/Development/eterna/OpenKnotScorePipeline/.venv/lib/python3.12/site-packages/timefold/solver/score/_score.py", line 169, in HardSoftScore
def _to_java_score(self):
File "/home/jonathan/Development/eterna/OpenKnotScorePipeline/.venv/lib/python3.12/site-packages/timefold/solver/score/_score.py", line 173, in _to_java_score
return _java_score_mapping_dict['HardSoftScore'].of(self.hard_score, self.soft_score)
KeyError: HardSoftScore
To Reproduce
from typing import Annotated
from dataclasses import dataclass, field
from timefold.solver.domain import (
PlanningVariable,
PlanningEntityCollectionProperty,
PlanningScore, ValueRangeProvider,
planning_entity, planning_solution
)
from timefold.solver.score import HardSoftScore, easy_score_calculator
from timefold.solver import SolverFactory
from timefold.solver.config import SolverConfig, ScoreDirectorFactoryConfig, TerminationConfig, Duration
@planning_entity
@dataclass
class ResourceConfiguration:
cpus: Annotated[int, PlanningVariable(value_range_provider_refs = ['cpu_range'])] = 1
def get_cpu_range(self) -> Annotated[list[int], ValueRangeProvider(id='cpu_range')]:
return list(range(1, 5))
@planning_solution
@dataclass
class Schedule:
resource_configurations: Annotated[list[ResourceConfiguration], PlanningEntityCollectionProperty]
score: Annotated[HardSoftScore, PlanningScore] = field(default=None)
@easy_score_calculator
def score(solution):
return HardSoftScore(0, 0)
solver_factory = SolverFactory.create(
SolverConfig(
solution_class=Schedule,
entity_class_list=[ResourceConfiguration],
score_director_factory_config=ScoreDirectorFactoryConfig(
easy_score_calculator_function=score,
),
termination_config=TerminationConfig(
spent_limit=Duration(seconds=1)
)
)
)
problem = Schedule([ResourceConfiguration()])
solver_factory.build_solver().solve(problem)
Environment
Timefold Solver Version or Git ref: 1.17.0
Output of java -version:
openjdk version "23" 2024-09-17
OpenJDK Runtime Environment (build 23)
OpenJDK 64-Bit Server VM (build 23, mixed mode, sharing)
Output of uname -a or ver:
Linux 6.6.63-1-MANJARO #1 SMP PREEMPT_DYNAMIC Sat Nov 23 02:15:34 UTC 2024 x86_64 GNU/Linux