Вопрос или проблема
Проблема с пользовательским CompositeMove
У меня есть ситуация, когда существуют взаимозависимые планировочные сущности, и мне нужен перерасчет баллов после их перемещения “как одного целого”. Например, две задачи, которые планируются, имеют одинаковую зависимость начала, нарушение которой приводит к 1hard. Дело в том, что я никогда не могу получить 0hard, потому что сначала ОП перемещает одну задачу и пересчитывает баллы, затем перемещает вторую и т.д., и никогда не достигает момента, когда начало одно и то же.
Я пытаюсь реализовать пользовательский составной перенос, но застрял. Я добавил пользовательский перенос, как указано в документации: https://www.optaplanner.org/docs/optaplanner/latest/move-and-neighborhood-selection/move-and-neighborhood-selection.html#customMoves.
И вот мой код пользовательской фабрики:
public class CompositeMoveFactory implements MoveListFactory<PlanningSolution> {
@Override
public List<? extends Move<PlanningSolution>> createMoveList(PlanningSolution planningSolution) {
var compositeMoves = new ArrayList<CompositeMove<PlanningSolution>>();
var tasksWithDependencies = opPlanningSolution.getTasks().stream()
.filter(task -> task.isNewTask() && !task.getDependsOnTaskIds().isEmpty())
.toList();
var taskIdToTaskMap = tasksWithDependencies.stream()
.collect(Collectors.toMap(OPTask::getId, Function.identity()));
for (var task : tasksWithDependencies) {
for (var dependsOnTaskId : task.getDependsOnTaskIds()) {
var dependsOnTask = taskIdToTaskMap.get(dependsOnTaskId);
for (var it = opPlanningSolution.createDateTime().createOriginalIterator();
it.hasNext(); ) {
LocalDateTime newStartTime = it.next();
for (Resource newResource : planningSolution.getResources()) {
var taskMove = new ChangeStartTimeAndResourceMove(task, newStartTime, newResource);
var dependsOnTaskMove = new ChangeStartTimeAndResourceMove(dependsOnTask, newStartTime,
newResource);
var compositeMove = (CompositeMove<PlanningSolution>) CompositeMove.buildMove(
taskMove, dependsOnTaskMove);
compositeMoves.add(compositeMove);
}
}
}
}
return compositeMoves;
}
}
Подходит ли этот код для пользовательской фабрики для достижения моей цели?
Ответ или решение
Ваш подход к созданию пользовательского фабрики для составных перемещений (CompositeMove) выглядит перспективно, но есть некоторые моменты, которые могут улучшить вашу реализацию и помочь в решении вашей проблемы с взаимозависимыми сущностями планирования.
Анализ вашей реализации
-
Фильтрация задач с зависимостями:
- Вы правильно фильтруете задачи, у которых есть зависимости. Однако имейте в виду, что возможно стоит рассмотреть более комплексный подход для обработки зависимостей, как например, иерархия зависимых задач или использование графа для представления зависимостей.
-
Итерация по времени и ресурсам:
- Вы создаете новые движения для каждой комбинации задач, времени начала и ресурса, что является хорошим началом. Однако это может привести к большому количеству перемещений, что снижает производительность. Может быть, вам стоит рассмотреть возможность группировки задач, чтобы сократить количество итераций.
- Построение составных перемещений:
- Ваш код для создания составных перемещений выглядит корректным, но важно убедиться в том, что вы правильно обрабатываете все возможные условия для обеспечения отсутствия конфликтов между задачами в зависимости. Возможно, стоит добавить проверку на дополнительные ограничения, чтобы гарантировать создание только допустимых перемещений.
Рекомендации
-
Проверка допустимости движения:
- Перед добавлением перемещения в список
compositeMoves
, убедитесь, что оно не нарушает никаких ограничений. Например, если обе задачи зависят от одного и того же условия, убедитесь, что они действительно могут быть запланированы одновременно.
- Перед добавлением перемещения в список
-
Оптимизация:
- Рассмотрите возможность применения алгоритма, который бы сначала обрабатывал группы зависимых задач перед их перемещением. Это может существенно улучшить эффективность вашего кода.
-
Indexing and Memoization:
- Подумайте о том, чтобы создать индекс для уже рассчитанных перемещений, чтобы избежать их повторного вычисления. Вы также можете использовать мемоизацию для хранения уже проверенных состояний, что может значительно сократить время выполнения.
- Отладка и логи:
- Добавьте логирование в ключевые моменты вашего кода, чтобы вы могли отследить, каким образом и когда создаются и обрабатываются составные перемещения. Это может помочь выявить потенциальные проблемы.
Заключение
Ваш подход к созданию кастомного фабрики для составных перемещений в OptaPlanner на правильном пути, однако в нем присутствуют моменты, которые требуется оптимизировать и улучшить для достижения наилучших результатов. Внимательно переработайте вашу логику с учетом рекомендаций, и это поможет вам правильно осуществить перерасчет результатов после перемещения взаимозависимых задач. Если возникнут дополнительные вопросы, не стесняйтесь задавать их!