Reputation: 95
I am using Quarkus optaplanner, so instead of using SolverFactory to build a solver, I us ethe Quarkus way to inject a solverManager then let it solve the problem:
val solverJob: SolverJob<SolarDesign, UUID> = solverManager.solve(problemId, problem)
But I want to still be able to addEventListener like:
solver.addEventListener(SolverEventListener<SolarDesign>() {
fun bestSolutionChanged(event: BestSolutionChangedEvent<MyProblem>) {
val solution = event.getNewBestSolution()
if (solution.score.isFeasible()) {
println("found new best solution")
println(solution)
}
}
})
Question is how do I get a solver instance in Quarkus optaplanner so I can use it to addEventListener? It does not seem to be doable from solverManager.
Thanks
Upvotes: 0
Views: 202
Reputation: 2358
The following example shows how to obtain a Solver
instance in Quarkus. The SolverManager
API does not cover this option so the alternative approach is to inject a SolverFactory
, use it to build a Solver
instance and manage its lifecycle yourself.
The example also shows how to get access to the Phase
lifecycle. It can be useful for experiments during development. However, that's only possible through casting the solver instance to DefaultSolver
, which is an internal API. There are no backward compatibility guarantees on the internal classes. They can significantly change in future minor releases and cause compilation errors if you use them in your code. Do not use it in production.
class MySolverResource(private val solverFactory: SolverFactory<SolarDesign>) {
fun solve(problemId : UUID) {
// WARNING: DefaultSolver is OptaPlanner's internal class.
// Backward compatibility is not guaranteed.
// Its usage is totally not recommended.
val solver: DefaultSolver<SolarDesign> = solverFactory.buildSolver() as DefaultSolver<SolarDesign>
solver.addPhaseLifecycleListener(object : PhaseLifecycleListenerAdapter<SolarDesign>() {
override fun stepEnded(stepScope: AbstractStepScope<SolarDesign>) {
printSolution(stepScope.createOrGetClonedSolution())
}
})
solver.solve(loadProblem(problemId))
}
fun printSolution(solution: SolarDesign) {}
}
Upvotes: 1
Reputation: 2358
Yes, that is possible with SolverManager
and you don't need to obtain a Solver
instance.
Use SolverManager.solverAndListen(problemId, problemFinder, bestSolutionConsumer)
. The third argument is a consumer where you can do whatever you want with each best solution that is found. It could look something like this in your case:
fun solve() {
val solverJob: SolverJob<SolarDesign, UUID> = solverManager
.solveAndListen(problemId, { problemId -> problem }, this::printSolution)
}
fun printSolution(solution: SolarDesign) {
if (solution.score.isFeasible()) {
println("found new best solution")
println(solution)
}
}
Find more details in this section about SolverManager
.
Upvotes: 2