| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394 |
- package fr.jaquin.bdlg.planner.controller;
- import java.util.UUID;
- import java.util.concurrent.ExecutionException;
- import java.util.stream.Collector;
- import java.util.stream.Collectors;
- import org.optaplanner.core.api.score.ScoreExplanation;
- import org.optaplanner.core.api.score.ScoreManager;
- import org.optaplanner.core.api.score.buildin.hardmediumsoft.HardMediumSoftScore;
- import org.optaplanner.core.api.solver.SolverJob;
- import org.optaplanner.core.api.solver.SolverManager;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.PostMapping;
- import org.springframework.web.bind.annotation.RequestBody;
- import org.springframework.web.bind.annotation.RestController;
- import fr.jaquin.bdlg.planner.solver.domain.Assignement;
- import fr.jaquin.bdlg.planner.solver.domain.MealAssignement;
- import fr.jaquin.bdlg.planner.solver.domain.MealSlot;
- import fr.jaquin.bdlg.planner.solver.domain.Planning;
- import fr.jaquin.bdlg.planner.solver.domain.PlanningInput;
- import fr.jaquin.bdlg.planner.solver.domain.PlanningSolution;
- @RestController
- public class SolverController {
- @Autowired
- private SolverManager<Planning, UUID> solverManager;
- @Autowired
- private ScoreManager<Planning, HardMediumSoftScore> scoreManager;
- private Collector<CharSequence, ?, String> listCollector = Collectors.joining(",", "[", "]");
- @PostMapping("/planning/solve")
- public PlanningSolution solve(@RequestBody PlanningInput inputs) {
- Planning problem = inputs.generatePlanningProblem();
- UUID problemId = UUID.randomUUID();
- // Submit the problem to start solving
- SolverJob<Planning, UUID> solverJob = solverManager.solve(problemId, problem);
- Planning solution;
- try {
- // Wait until the solving ends
- solution = solverJob.getFinalBestSolution();
- } catch (InterruptedException | ExecutionException e) {
- throw new IllegalStateException("Solving failed.", e);
- }
- ScoreExplanation<Planning, HardMediumSoftScore> explanation =
- scoreManager.explainScore(solution);
- PlanningSolution output = PlanningSolution.from(solution);
- output.setExplanation(stringifyExplanation(explanation));
- // System.out.println(explanation.getSummary());
- return output;
- }
- private String stringifyExplanation(ScoreExplanation<Planning, HardMediumSoftScore> explanation) {
- return explanation.getConstraintMatchTotalMap().values().stream()
- // Return only Hard Constraint
- .filter(predicate -> predicate.getScore().getHardScore() < 0)
- // Create a dictionnary with the name of the constraint as key
- .map(constraint -> "\"" + constraint.getConstraintName() + "\":"
- // Populate the value with an array of justification objects
- + constraint.getConstraintMatchSet().stream()
- // Filter pair that have a negative impact on the score
- .filter(matchElt -> matchElt.getScore().getHardScore() < 0)
- .map(match -> match.getJustificationList().stream()
- .map(elt -> stringifyConstraint(elt)).collect(listCollector))
- .collect(listCollector))
- .collect(Collectors.joining(",", "{", "}"));
- }
- private String stringifyConstraint(Object val) {
- if (val instanceof Assignement) {
- Assignement casted = (Assignement) val;
- return "{\"type\":\"Assignement\",\"slotId\":\"" + casted.getSlot().getId()
- + "\",\"volonteerId\":" + casted.getVolonteer().getId().toString() + "}";
- }
- if (val instanceof MealAssignement) {
- MealAssignement casted = (MealAssignement) val;
- return "{\"type\":\"MealAssignement\",\"slotId\":\"" + casted.getMealSlot().getId()
- + "\",\"volonteerId\":" + casted.getVolonteer().getId().toString() + "}";
- }
- if (val instanceof MealSlot) {
- MealSlot casted = (MealSlot) val;
- return "{\"type\":\"MealSlot\",\"slotId\":\"" + casted.getId() + "\"}";
- }
- if (val instanceof Integer) {
- return val.toString();
- }
- return "\"" + val.getClass().getName() + "\"";
- }
- }
|