Hello everyone,
I'm encountering a strange behavior from the Nearby selection on the local search phase.
I have implemented a Task Assigning scheduler based on skills, workload, and holidays. The solver works at its best under the 2K tasks mark. So I decided to introduce in my code the nearby selection. I followed the guide on the OptaPlanner website, but after the local search starts, it bugs out after its first iteration.
Let's say we have 10 resources and 100 tasks.
For Task-0 (the origin), the destination is correct, iterating between the 10 resources. BUT for Task-1, the destination is Task-0, causing this exception
class org.digimark.planner.domain.tasks.Task cannot be cast to class org.digimark.planner.domain.resources.Risorsa (org.digimark.planner.domain.tasks.Task and org.digimark.planner.domain.resources.Risorsa are in unnamed module of loader io.quarkus.bootstrap.classloading.QuarkusClassLoader @181e72d3)
Where I'm doing wrong? Any ideas?
PlanningEntities:
Risorsa (with @PlanningListVariable on List<Task> tasks),
Task (with @InverseRelationShadowVariable(sourceVariableName = "tasks")
NearbyDistanceMeter implementation:
public double getNearbyDistance(Task origin, Risorsa destination) {
String originReparto = origin.getRepartoRichiesto();
List<Reparto> destinationListaReparti = destination.getListaReparti();
List<Competenze> originCompetenze = origin.getCompetenzaRichiesta();
List<Competenze> destinationCompetenze = destination.getCompetenze();
if (originReparto != null &&
destinationListaReparti != null &&
originCompetenze != null &&
destinationCompetenze != null) {
boolean repartoMatch = false;
boolean competenzeMatch = false;
for (Reparto r : destinationListaReparti) {
if (Objects.equals(r.getNomeReparto(), originReparto)) {
repartoMatch = true;
break;
}
}
for (Competenze c : originCompetenze) {
for (Competenze d : destinationCompetenze) {
if (Objects.equals(c.getNomeCompetenza(), d.getNomeCompetenza())) {
competenzeMatch = true;
break;
}
}
}
if (repartoMatch && competenzeMatch) {
return 0.0;
}
else {
return Double.MAX_VALUE;
}
}
else {
return Double.MAX_VALUE;
}
}
Solve configuration:
<localSearch>
<unionMoveSelector>
<listChangeMoveSelector>
<valueSelector id="valueSelector1"/>
<destinationSelector>
<nearbySelection>
<originValueSelector mimicSelectorRef="valueSelector1"/>
<nearbyDistanceMeterClass>org.digimark.planner.domain.scheduler.TaskNerbyDistanceMeter</nearbyDistanceMeterClass>
<parabolicDistributionSizeMaximum>40</parabolicDistributionSizeMaximum>
</nearbySelection>
</destinationSelector>
</listChangeMoveSelector>
<listSwapMoveSelector>
<valueSelector id="valueSelector2"/>
<secondaryValueSelector>
<nearbySelection>
<originValueSelector mimicSelectorRef="valueSelector2"/>
<nearbyDistanceMeterClass>org.digimark.planner.domain.scheduler.TaskNerbyDistanceMeter</nearbyDistanceMeterClass>
<parabolicDistributionSizeMaximum>40</parabolicDistributionSizeMaximum>
</nearbySelection>
</secondaryValueSelector>
</listSwapMoveSelector>
<subListChangeMoveSelector>
<selectReversingMoveToo>true</selectReversingMoveToo>
<subListSelector id="subListSelector3"/>
<destinationSelector>
<nearbySelection>
<originSubListSelector mimicSelectorRef="subListSelector3"/>
<nearbyDistanceMeterClass>org.digimark.planner.domain.scheduler.TaskNerbyDistanceMeter</nearbyDistanceMeterClass>
<parabolicDistributionSizeMaximum>40</parabolicDistributionSizeMaximum>
</nearbySelection>
</destinationSelector>
</subListChangeMoveSelector>
<subListSwapMoveSelector>
<selectReversingMoveToo>true</selectReversingMoveToo>
<subListSelector id="subListSelector4"/>
<secondarySubListSelector>
<nearbySelection>
<originSubListSelector mimicSelectorRef="subListSelector4"/>
<nearbyDistanceMeterClass>org.digimark.planner.domain.scheduler.TaskNerbyDistanceMeter</nearbyDistanceMeterClass>
<parabolicDistributionSizeMaximum>40</parabolicDistributionSizeMaximum>
</nearbySelection>
</secondarySubListSelector>
</subListSwapMoveSelector>
</unionMoveSelector>
</localSearch>