Невозможное повреждение variableListener с помощью пользовательского variableListener - PullRequest
0 голосов
/ 08 мая 2018

Я пытаюсь оптимизировать задачу планирования для моего университета.

Чтобы оптимизировать компактность моих уроков, я пытаюсь обновить Список всех уроков в тот же день в моем классе урока, который является объектом планирования. Я делаю это через PlanningVariableListener

Это мой урок:

private int id;
private Course course;
private Period period;
private Room room;
private int blockLength = 1;

private boolean prime = false;
private boolean uKW = false;
private boolean gKW = false;
private boolean FWPM = false;
private boolean biWeekly = false;
private boolean pinned = false;

private List<Student> fwpmStudents = new ArrayList<>();
private int altId = 0;
private String collisionReason;
private String group = "NO_GROUP";
public String[] groupArray;

private List<Lesson> sameDay = new ArrayList<>();

public Lesson() {

}

@PlanningPin
public boolean isPinned() {
    return pinned;
}

public void setPin(boolean pin) {
    pinned = pin;
}

public int getId() {
    return id;
}

public void setId(int id) {
    this.id = id;
}

public Course getCourse() {
    return course;
}

public void setCourse(Course course) {
    this.course = course;
}

@PlanningVariable(valueRangeProviderRefs = "periodId")
public Period getPeriod() {
    return period;
}

public void setPeriod(Period period) {
    this.period = period;
}

@PlanningVariable(valueRangeProviderRefs = "roomId") //IDK if nullable is accepted
public Room getRoom() {
    return room;
}

public void setRoom(Room room) {
    this.room = room;
}

public boolean isPrime() {
    return prime;
}

public void setPrime(boolean prime) {
    this.prime = prime;
}

public int getBlockLength() {
    return blockLength;
}

public void setBlockLength(int blockLength) {
    this.blockLength = blockLength;
}

public boolean getUKWFlag() {
    return uKW;
}

public void setUKWFlag(boolean straight) {
    this.uKW = straight;
}

public boolean getGKWFlag() {
    return gKW;
}

public void setGKWFlag(boolean gKW) {
    this.gKW = gKW;
}

public String getGroup() {
    return group;
}

public void setGroup(String group) {
    this.group = group;
}

public int getAltId() {
    return altId;
}

public void setAltId(int altId) {
    this.altId = altId;
}

public boolean getFWPM() {
    return FWPM;
}

public void setFWPM(boolean FWPM) {
    this.FWPM = FWPM;
}

public boolean isBiWeekly() {
    return biWeekly;
}

public void setBiWeekly(boolean biWeekly) {
    this.biWeekly = biWeekly;
}

public String[] getGroupArray() {
    return groupArray;
}

public void setGroupArray(String[] groupArray) {
    this.groupArray = groupArray;
}

public void addFWPMStudent(Student student) {
    this.fwpmStudents.add(student);
}

public List<Student> getFWPMStudents() {
    return this.fwpmStudents;
}

public String getCollisionReason() {
    return collisionReason;
}

public void setCollisionReason(String collisionReason) {
    this.collisionReason = collisionReason;
}

public boolean collides(Lesson lesson) {
    return CollisionDetector.getCollision(this,lesson);
}

public boolean globalCollides(Lesson lesson) {
    return CollisionDetector.getGlobalCollision(this, lesson);
}

public boolean softCollides(Lesson lesson) {
    return CollisionDetector.softFWPMCollision(this, lesson);
}

public boolean prefCollides(Preference preference) {
    return CollisionDetector.getPreferenceCollision(this, preference);
}

public String toString() {
    return this.getId()
            + " " + this.getCourse().getSemester().getShortName()
            + " " + this.getCourse().getLecturer().getShortName()
            + " " + this.getCourse().getSubject().getShortName()
            + " " + this.getRoom().getNumber() + " " + this.getGroup()
            + "\t" + this.getPeriod().getDay() + " " + this.getPeriod().getHour() + " " + this.getBlockLength();
}

public void addSameDay(Lesson lesson) {
    this.sameDay.add(lesson);
}

public void removeSameDay(Lesson lesson) {
    this.sameDay.remove(lesson);
}

@CustomShadowVariable(variableListenerClass = DayLessonVariableListener.class,
        sources = {@PlanningVariableReference( variableName = "period")})
public List<Lesson> getSameDay() {
    return this.sameDay;
}

public void setSameDay(List<Lesson> sameDay) {
    this.sameDay = sameDay;
}

public boolean isOnlyLesson() {
    if (sameDay.size() == 0)
        return true;
    else
        return false;
}

public void print() {
    System.out.println(toString());
}

Это моя пользовательская переменнаяListener

private void update(ScoreDirector<ScheduleSolution> scoreDirector, Lesson lesson) {
    List<Lesson> lessons = scoreDirector.getWorkingSolution().getLessons();
    for (Lesson l : lessons) {
        if (l.getPeriod().getDay() == lesson.getPeriod().getDay()){
            if (!l.equals(lesson)) {
                scoreDirector.beforeVariableChanged(lesson, "sameDay");
                lesson.addSameDay(l);
                scoreDirector.afterVariableChanged(lesson, "sameDay");
            }
        }
    }
    Iterator<Lesson> iter = lesson.getSameDay().iterator();
    while (iter.hasNext()) {
        Lesson x = iter.next();
        if (x.getPeriod().getDay() != lesson.getPeriod().getDay()) {
            scoreDirector.beforeVariableChanged(lesson, "sameDay");
            iter.remove();
            scoreDirector.afterVariableChanged(lesson, "sameDay");
        }
    }
}


@Override
public void beforeEntityAdded(ScoreDirector scoreDirector, Lesson lesson) {
}

@Override
public void afterEntityAdded(ScoreDirector scoreDirector, Lesson lesson) {
}

@Override
public void beforeVariableChanged(ScoreDirector scoreDirector, Lesson lesson) {
    update(scoreDirector, lesson);
}

@Override
public void afterVariableChanged(ScoreDirector scoreDirector, Lesson lesson) {
    update(scoreDirector, lesson);
}

@Override
public void beforeEntityRemoved(ScoreDirector scoreDirector, Lesson lesson) {
}

@Override
public void afterEntityRemoved(ScoreDirector scoreDirector, Lesson lesson) {

}

Если я запускаю это, я получаю следующее сообщение об ошибке:

Исключение в потоке "main" java.lang.IllegalStateException: Невозможное повреждение VariableListener: ожидаемыйWorkingScore (0hard / -50soft) не является рабочимScore (0hard / 0soft) после того, как все VariableListeners были запущены без изменений в подлинных переменных после завершения 137 AIF2 Koller üphy HS134 P3 4 2 2 {День: 4 Час: 2 -> День: 4 Час: 2}). Но все значения теневых переменных все те же, поэтому это невозможно. Может быть, запустить с FULL_ASSERT, если вы еще не сделали, чтобы потерпеть неудачу раньше в org.optaplanner.core.impl.score.director.AbstractScoreDirector.assertShadowVariablesAreNotStale (AbstractScoreDirector.java:475) в org.optaplanner.core.impl.solver.scope.DefaultSolverScope.assertShadowVariablesAreNotStale (DefaultSolverScope.java:140) в org.optaplanner.core.impl.phase.scope.AbstractPhaseScope.assertShadowVariablesAreNotStale (AbstractPhaseScope.java:171) в org.optaplanner.core.impl.phase.AbstractPhase.predictWorkingStepScore (AbstractPhase.java:169) в org.optaplanner.core.impl.localsearch.DefaultLocalSearchPhase.doStep (DefaultLocalSearchPhase.java:102) в org.optaplanner.core.impl.localsearch.DefaultLocalSearchPhase.solve (DefaultLocalSearchPhase.java:92) в org.optaplanner.core.impl.solver.AbstractSolver.runPhases (AbstractSolver.java:87) в org.optaplanner.core.impl.solver.DefaultSolver.solve (DefaultSolver.java:173) в app.Main.solve (Main.java:35) в app.Main.main (Main.java:25)

Может быть, я что-то упускаю, но я не знаю, как это исправить. По моему расписанию два урока могут быть одновременно для некоторых случаев из-за чередующегося характера этих двух уроков.

Любая помощь приветствуется.

РЕДАКТИРОВАТЬ: Итак, я исправил это сообщение об ошибке, после работы над моим customVariableListener, казалось, была проблема согласованности с методами, вызываемыми до и после ScoreDirector.

Теперь я хотел вызвать softConstraint, основанный на теневых переменных. Разве это не разрешено? Это какая-то проблема параллелизма?

Исключение в потоке "main" java.lang.IllegalStateException: повреждение UndoMove: beforeMoveScore (0hard / -20soft) не является undoScore (0hard / -10soft), который является uncorruptedScore (0hard / -10soft) рабочего решения. 1) Включите EnvironmentMode FULL_ASSERT (если вы этого еще не сделали), чтобы сбой происходил быстрее в случае повреждения счета. 2) Проверьте метод Move.createUndoMove (...) класса moveClass (класс util.helpers.optaplanner.moves.ResistantSwapMove). Движение (70 AIF2 Mareczek peme LS103 EM7 / EM8 {День: 1 час: 3} <-> 136 AIF2 Koller phys A0.02 NO_GROUP {День: 5 час: 5}) может привести к повреждению отмены перемещения (Отмена (70 AIF2 Mareczek) peme LS103 EM7 / EM8 {День: 1 час: 3} <-> 136 AIF2 Koller phys A0.02 NO_GROUP {День: 5 час: 5})). 3) Проверьте свои пользовательские переменные переменных (если они есть) на наличие теневых переменных, которые используются ограничениями оценки с разным весом оценки между beforeMoveScore (0hard / -20soft) и undoScore (0hard / -10soft).

Это правило, вызывающее проблему. Поскольку onlyLesson может быть только 0 или 1 моей реализацией, это добавляет -10 или 0 к ScoreDirector.

rule "avoidDaysWithOneLesson"
    when
        $lesson : Lesson($only : onlyLesson)
    then
        scoreHolder.addSoftConstraintMatch(kcontext, -$lesson.getOnlyLesson() * 10);
end

И это использованные переменные тени. Первоначально было только два, тот же день и предыдущий период. япросто попытался поиграться, если это будет решено, если я просто обновлю целое число (onlyLesson). Но это не решило проблему.

@CustomShadowVariable(variableListenerClass = DayLessonVariableListener.class,
        sources = {@PlanningVariableReference(variableName = "period")})
public List<Lesson> getSameDay() {
    return this.sameDay;
}

@CustomShadowVariable(variableListenerRef = @PlanningVariableReference(variableName = "sameDay"))
public Period getPreviousPeriod() {
    return previousPeriod;
}

public void setPreviousPeriod(Period period) {
    this.previousPeriod = period;
}

public void addSameDay(Lesson lesson) {
    if (this.getCourse().getSemester().getShortName().equals(lesson.getCourse().getSemester().getShortName())) {
        this.sameDay.add(lesson);
    }
}

public void setSameDay(List<Lesson> sameDay) {
    this.sameDay = sameDay;
}

@CustomShadowVariable(variableListenerRef = @PlanningVariableReference(variableName = "sameDay"))
public Integer getOnlyLesson() {
    return onlyLesson;
}

У меня вопрос: разрешено ли вызывать ограничения с shadowVariables в качестве причины, или это приводит к проблемам согласованности между шагами и ScoreDirector?

Любая помощь приветствуется.

1 Ответ

0 голосов
/ 12 мая 2018

Теперь я хотел вызвать softConstraint, основанный на теневых переменных.Разве это не разрешено?

Мягкие (и жесткие) ограничения могут использовать теневые переменные (это точка теневых переменных).

Это какая-то проблема параллелизма?

Все это происходит в потоке решателя (или потоке детали в Секционированном поиске, или потоке перемещения в многопоточном решении),В любом случае, в пределах одного ScoreDirector он является однопоточным, поэтому вам не нужно беспокоиться о проблемах параллелизма.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...