Ищете правильный способ использовать «DoubleValueRange» в OptaPlanner

#java #linear-programming #optaplanner

#java #линейное программирование #optaplanner

Вопрос:

Я изучаю, как использовать OptaPlanner, решая линейное программирование. Я знаю, что существует довольно много решателей LP, но я думаю, что это хорошая отправная точка для меня, чтобы понять моделирование.

Но когда я начал работать над этим, я столкнулся с проблемой, которая выглядит так, как будто переменная планирования сущности может быть только счетной.

Исключение выглядит следующим образом:

 The selector is not countable, check the ValueRanges involved.
Verify that a ValueRangeProvider does not return ValueRange when it can return CountableValueRange or Collection.
 

Могу ли я знать:

  1. Каков «законный» способ использования «двойного значения»?
  2. Есть ли «лучшая практика» для LP в OptaPlanner?

Спасибо.

Мое решение:

 
@PlanningSolution
public class Solution {
    @PlanningEntityProperty
    private Entity entity;

    @PlanningScore
    private HardSoftScore score = HardSoftScore.ZERO;

    public Solution(Entity entity) {
        this.entity = entity;
    }

    @ValueRangeProvider(id = "x_1")
    public ValueRange<Double> getX1Range() {
        return ValueRangeFactory.createDoubleValueRange(0.0, 100.0);
    }

    @ValueRangeProvider(id = "x_2")
    public ValueRange<Double> getX2Range() {
        return ValueRangeFactory.createDoubleValueRange(0.0, 100.0);
    }
...<getters setters>...

 

Моя сущность:

 @PlanningEntity
public class Entity {
    private long id;

    @PlanningVariable(valueRangeProviderRefs = "x_1")
    private Double x1;

    @PlanningVariable(valueRangeProviderRefs = "x_2")
    private Double x2;
...<getters setters>...
 

Мои ограничения:

 ...
    private Constraint c1(ConstraintFactory constraintFactory) {
        return constraintFactory.from(Entity.class)
                .filter(e -> !(3.0 * e.getX1()   5.0 * e.getX2() < 5.0 ))
                .penalize("C1", HardSoftScore.ONE_HARD);
    }

    private Constraint c2(ConstraintFactory constraintFactory) {
        return constraintFactory.from(Entity.class)
                .filter(e -> !(2.0 * e.getX1() - 6.0 * e.getX2() > 0.0 ))
                .penalize("C2", HardSoftScore.ONE_HARD);
    }

    private Constraint min(ConstraintFactory constraintFactory) {
        return constraintFactory.from(Entity.class)
                .penalize("MIN", HardSoftScore.ONE_SOFT, e -> (int)(-e.getX1()   6.0 * e.getX2()));
    }
...
 

Комментарии:

1. Решатели LP намного лучше решают LPS, чем OptaPlanner, который действительно является прославленной эвристикой (это неплохо: эти алгоритмы отлично подходят для задач, в которых точные методы исчерпаны). Хорошие решатели LP могут обрабатывать (редкие) проблемы с десятками миллионов переменных и ограничений.

Ответ №1:

Просматривая типы возвращаемых значений из набора методов createXXXValueRange() ValueRangeFactory, я замечаю, что все, кроме одного, возвращают счетный диапазон значений. Единственным исключением из этого правила является createDoubleValueRange() , который возвращает «простой» ValueRange (ValueRange).

Ваша ошибка указывает в том же направлении: ValueRange не считается допустимым счетным ValueRange. Для меня это имеет смысл: OptaPlanner хочет выбрать из набора дискретных значений для выполнения своих ходов. Так что я не думаю, что есть какой-либо «законный» способ использовать его для решающего хода OptaPlanner.

По причине, которую я не могу определить, я бы сам не выбрал OptaPlanner в качестве первого выбора для решения проблем LP, поскольку набор возможных решений может быть рассчитан. Но в любом случае, используя OptaPlanner (как в вашем случае), я бы тогда работал с кратными (10, 100, 1000, …) дискретными значениями (при вычислении результата деля их на 10, 100, 1000, …). И / НО в то же время я был бы крайне осторожен чтобы избежать коррупции в счетах, опасность которой никогда не будет очень далеко.

Ответ №2:

В настоящее время в OptaPlanner (версии 8.3 или ниже) нет селекторов перемещения для работы с DoubleValueRange s. Смотрите Пример инвестиционного портфеля о том, как подключить свой собственный, чтобы иметь дело с диапазонами значений на основе границ, такими как DoubleValueRanges.

Это, как говорится. Если ваши диапазоны значений действительно непрерывны (то есть не дискретны), вам, вероятно, действительно лучше использовать LP. Обратите внимание, что в большинстве задач планирования диапазоны значений являются незаметными, потому что вы не можете отправить 0,75 транспортного средства / человека в местоположение A, а остальные 0,25 его / его / ее в местоположение B.

Смотрите также прекрасный ответ sudo.