Решение задания с большим количеством предварительных заданий

Проблема, которую я хочу решить, состоит из примерно 800 задач, которые должны быть назначены примерно 120 работникам. Рабочие должны иметь квалификацию для выполнения задачи и иметь только определенное количество часов в неделю. Около 80 % заданий уже предварительно назначены. Это означает, что их следует сохранить, но если остальные 20% не могут быть решены, предварительные задания могут быть нарушены.
У меня уже есть модель, использующая решатель Choco, который использует штрафы, если предварительное назначение нарушается, и цель состоит в том, чтобы минимизировать штраф. Однако я думаю, что это не очень эффективно, потому что решатель не начнет стратегию поиска с присвоением предварительно назначенных переменных. Я уже задавал вопрос специально для Choco здесь (Как определить начальную точку распространения в Choco 3.3).

Но есть ли другой решатель, где это можно сделать проще? Может быть, лучше написать свой собственный решатель? Буду признателен за любые предложения.

РЕДАКТИРОВАТЬ: я пытался написать свою собственную стратегию Choco. Для небольшой проблемы работает нормально, а для большой не находит решения. Я не уверен, разрешено ли все, что я делаю в getDecision (например, проверка isInstantiated), и я не могу найти документацию или руководство о том, как написать стратегию, расширяющую AbstractStrategy. Буду признателен за любые подсказки, в чем может быть проблема. (Чем выше абсолютный приоритет в матрице prios, тем раньше должна быть назначена переменная. Если приоритет отрицательный, следует присвоить 0, если положительный — 1. Наивысший приоритет — 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;
        }

    }

person Dora    schedule 28.06.2016    source источник
comment
Может быть, сделать это в два этапа. Сначала исправьте все предварительно назначенные задания и посмотрите, сможете ли вы решить оставшуюся часть (это должно быть быстро). Если это не удается, удалите и используйте свой штрафной метод.   -  person Erwin Kalvelagen    schedule 29.06.2016
comment
Я определенно попробую это, но это даст мне довольно плохую производительность, если не все предварительные назначения будут выполнены. Я бы предпочел, чтобы решатель всегда начинал со всех предварительных назначений.   -  person Dora    schedule 01.07.2016
comment
Если вы беспокоитесь о производительности, я, вероятно, рассмотрю решатель LP / MIP, который обычно очень быстр для таких проблем.   -  person Erwin Kalvelagen    schedule 02.07.2016


Ответы (1)


Почему бы вам не изменить стратегию поиска решателя, чтобы он начинал с заранее заданных переменных? Это описано в документации.

person Jean-Guillaume Fages    schedule 30.06.2016
comment
Вы имеете в виду, что описано, как запустить стратегию поиска с предварительно назначенными переменными, или просто как определить пользовательскую стратегию поиска? Потому что я ничего не мог найти о предварительных заданиях. Сейчас я пытаюсь написать свою собственную стратегию, но в документации есть только пример для VariableSelector, а не для всей стратегии. Поскольку я бы использовал массив, чтобы сохранить, какие переменные должны быть предварительно назначены в первую очередь, и найти правильный порядок, я не думаю, что достаточно определить пользовательские переменные и селекторы значений, не так ли? - person Dora; 01.07.2016
comment
Вы можете реализовать AbstractStrategy (см. исходный код) или использовать селекторы (использовать карту или имя переменной для получения индекса). или вы можете просто применить inputOrderUB к переменным овеществления (перед переходом к переменным решения). Это установит для булвара значение 1 (UB), поэтому будет применено предварительное назначение. Вы также можете перейти к переменной штрафа (на этот раз сначала LB, так как вы хотите минимизировать ее). - person Jean-Guillaume Fages; 02.07.2016
comment
Я попытался реализовать AbstractStrategy, но не уверен, что сделал это правильно (см. редактирование вопроса). - person Dora; 07.07.2016
comment
Имеет ли смысл проверять isInstantiated() в getDecision? Или это будет портить распространение? Но иначе как я могу выбирать переменные в порядке их статического приоритета? Если я не проверю, созданы ли они, я всегда буду получать переменную с наивысшим приоритетом, верно? - person Dora; 12.07.2016
comment
Вы можете вызывать var.isInstantiated() в любое время, и вам определенно нужно вызывать его в стратегии поиска. Это не будет мешать распространению. - person Jean-Guillaume Fages; 21.07.2016