我正在尝试为我的大学优化调度问题。
为了优化课程的紧凑性,我试图在我的课程课程(即规划实体)中更新同一课程的所有课程列表。 我通过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());
}
这是我的自定义variableListener
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损坏:在completedAction之后触发所有VariableListener而没有更改真实变量之后,expectedWorkingScore(0hard / -50soft)不是workingScore(0hard / 0soft)( 137 AIF2KollerüphyHS134P3 4 2 2 {日:4小时:2 - >日:4小时:2})。 但是所有阴影变量值仍然相同,所以这是不可能的。 如果您还没有,可能会使用FULL_ASSERT运行,之前会失败。 at org.optaplanner.core.impl.score.director.AbstractScoreDirector.assertShadowVariablesAreNotStale(AbstractScoreDirector.java:475) at org.optaplanner.core.impl.solver.scope.DefaultSolverScope.assertShadowVariablesAreNotStale(DefaultSolverScope.java:140) at 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) at 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),它是workingSolution的uncorruptedScore(0hard / -10soft)。 1)启用EnvironmentMode FULL_ASSERT(如果您还没有)在出现分数损坏的情况下更快失败。 2)检查moveClass的Move.createUndoMove(...)方法(类util.helpers.optaplanner.moves.ResistantSwapMove)。移动(70 AIF2 Mareczek peme LS103 EM7 / EM8 {Day:1 Hour:3}&lt; - &gt; 136 AIF2 Koller phys A0.02 NO_GROUP {Day:5 Hour:5})可能有一个损坏的undoMove(撤消(70) AIF2 Mareczek peme LS103 EM7 / EM8 {Day:1 Hour:3}&lt; - &gt; 136 AIF2 Koller phys A0.02 NO_GROUP {Day:5 Hour:5}))。 3)检查您的自定义VariableListeners(如果有的话),分数约束使用的影子变量在beforeMoveScore(0hard / -20soft)和undoScore(0hard / -10soft)之间具有不同的分数权重。
这是引起问题的规则。因为通过我的实现只有Lesson只能是0或1,所以要么在scoreDirector中添加-10或0。
rule "avoidDaysWithOneLesson"
when
$lesson : Lesson($only : onlyLesson)
then
scoreHolder.addSoftConstraintMatch(kcontext, -$lesson.getOnlyLesson() * 10);
end
这些是使用的Shadowvariables。原来只有两个,相同的日和前期。 如果我只是更新一个Integer(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之间的一致性问题?
任何帮助表示感谢。
答案 0 :(得分:0)
现在我想做的是根据阴影调用softConstraint 变量。这是不允许的吗?
软(和硬)约束可以使用阴影变量(这是阴影变量的点)。
这是某种并发问题吗?
这一切都发生在求解器线程中(或分区搜索中的部分线程,或多线程求解中的移动线程)。无论如何,在一个ScoreDirector中,它是单线程的,因此您不必担心并发问题。