The problem I want to solve consists of about 800 tasks that have to be assigned to about 120 workers. The workers have to be qualified to do the task and only have a certain number of hours per week available. About 80% of the assignments are already preassigned. This means they should be kept, but if the other 20% cannot be solved, the preassignments can be violated.
I already have a model using the Choco solver that uses penalties if a preassignment is violated and the objective is to minimize the penalty. I however think that this is not very efficient, because the solver will not start the search strategy with assigning the preassigned variables. I already asked the question specifically for Choco here (How to define propagation starting point in Choco 3.3).
But is there another solver where this can be done easier? May it be best to write my own solver? I would appreciate any suggestions.
EDIT: I have tried writing my own Choco strategy. For a small problem it works fine, but for the big one it does not find a solution. I am not sure if everything I do in getDecision is allowed (eg check for isInstantiated) and I can't find any documentation or tutorial on how to write a strategy extending AbstractStrategy. I'd appreciate any pointers on what could be the problem. (The higher the absolute priority in the prios matrix is, the earlier the variable should be assigned. If the priority is negative, a 0 should be assigned, if it is positive a 1 should be assigned. The highest priority is 9999)
public class PriorityStrategy extends AbstractStrategy<IntVar> {
int[] prios;
// Search strategy parameters
VariableSelector<IntVar> variableSelector;
IntValueSelector valueSelectorLB;
IntValueSelector valueSelectorUB;
DecisionOperator<IntVar> decisionOperator;
// object recycling management
PoolManager<IntDecision> decisionPool;
int currentIndex = -1;
HashMap<IntVar, Integer> bestsMap = new HashMap<IntVar, Integer>();
public PriorityStrategy(IntVar[] vars, int[] prios) {
super(vars);
this.prios = prios;
valueSelectorLB = new IntDomainMin();
valueSelectorUB = new IntDomainMax();
variableSelector = new Random<IntVar>(123); //new Occurrence<IntVar>();
this.decisionPool = new PoolManager<>();
}
@Override
public Decision<IntVar> getDecision() {
IntVar next = null;
List<IntVar> bests = new ArrayList<IntVar>();
int bestPrio = 0;
for (int i = 0; i < vars.length; i++) {
int currentPrio = Math.abs(prios[i]);
if (currentPrio >= bestPrio && !vars[i].isInstantiated() ||
(next == null && !vars[i].isInstantiated())) {
if(currentPrio == 9999) {
currentIndex = i;
bests.clear();
bestsMap.clear();
return computeDecision(vars[i]);
}
if(currentPrio > bestPrio) {
bestPrio = currentPrio;
bests.clear();
bestsMap.clear();
}
bests.add(vars[i]);
bestsMap.put(vars[i], i);
}
}
if(bests.size()>0) {
next = variableSelector.getVariable(bests.toArray(new IntVar[bests.size()]));
currentIndex = bestsMap.get(next);
}
return computeDecision(next);
}
@Override
public Decision<IntVar> computeDecision(IntVar variable) {
if (variable == null || variable.isInstantiated()) {
return null;
}
int currentVal;
if(prios[currentIndex] > 0){
currentVal = valueSelectorUB.selectValue(variable);
} else {
currentVal = valueSelectorLB.selectValue(variable);
}
System.out.println("Idx " + currentIndex);
IntDecision current = decisionPool.getE();
if (current == null) {
current = new IntDecision(decisionPool);
}
current.set(variable, currentVal, DecisionOperator.int_eq);
return current;
}
}