Skip to content

Commit

Permalink
Examination Timetabling: Availability
Browse files Browse the repository at this point in the history
- when instructor or student direct conflicts are not allowed, also do not allow for availability violations
  • Loading branch information
tomas-muller committed Aug 6, 2019
1 parent 70d0a03 commit 89c0918
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 3 deletions.
8 changes: 8 additions & 0 deletions src/org/cpsolver/exam/heuristics/ExamConstruction.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ public Neighbour<Exam, ExamPlacement> checkLocalOptimality(Assignment<Exam, Exam
if (context.assignments().contains(exam.getId() + ":" + period.getIndex()))
continue;
}
if (exam.countInstructorConflicts(assignment, period) > 0) {
if (context.assignments().contains(exam.getId() + ":" + period.getIndex()))
continue;
}
if (!exam.checkDistributionConstraints(assignment, period))
continue;
ExamPlacement placement = new ExamPlacement(exam, period, null);
Expand Down Expand Up @@ -165,6 +169,10 @@ public Neighbour<Exam, ExamPlacement> selectNeighbour(Solution<Exam, ExamPlaceme
if (context.assignments().contains(bestExam.getId() + ":" + period.getIndex()))
continue;
}
if (bestExam.countInstructorConflicts(assignment, period) > 0) {
if (context.assignments().contains(bestExam.getId() + ":" + period.getIndex()))
continue;
}
if (!bestExam.checkDistributionConstraints(assignment, period))
continue;
ExamPlacement placement = new ExamPlacement(bestExam, period, null);
Expand Down
46 changes: 43 additions & 3 deletions src/org/cpsolver/exam/model/Exam.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ public class Exam extends Variable<Exam, ExamPlacement> {

private ArrayList<ExamOwner> iOwners = new ArrayList<ExamOwner>();
private List<ExamPeriodPlacement> iPeriodPlacements = null;
private List<ExamPeriodPlacement> iAvailablePeriodPlacements = null;
private List<ExamRoomPlacement> iRoomPlacements = null;
private List<ExamRoomPlacement> iRoomPreferredPlacements = null;

Expand Down Expand Up @@ -250,9 +251,23 @@ public synchronized List<ExamRoomPlacement> getPreferredRoomPlacements() {
* @return list of {@link ExamPeriodPlacement}
*/
public List<ExamPeriodPlacement> getPeriodPlacements() {
return iPeriodPlacements;
if (iAvailablePeriodPlacements == null) {
iAvailablePeriodPlacements = new ArrayList<ExamPeriodPlacement>(iPeriodPlacements.size());
for (ExamPeriodPlacement p: iPeriodPlacements) {
boolean available = true;
for (ExamInstructor i: getInstructors())
if (!i.isAllowDirectConflicts() && !i.isAvailable(p.getPeriod())) { available = false; break; }
for (ExamStudent s: getStudents())
if (!s.isAllowDirectConflicts() && !s.isAvailable(p.getPeriod())) { available = false; break; }
if (available)
iAvailablePeriodPlacements.add(p);
}
if (iAvailablePeriodPlacements.isEmpty())
sLog.error(" Exam " + getName() + " has no available periods.");
}
return iAvailablePeriodPlacements;
}

/**
* Initialize exam's domain.
*/
Expand Down Expand Up @@ -466,6 +481,7 @@ public void addContstraint(Constraint<Exam, ExamPlacement> constraint) {
if (constraint instanceof ExamInstructor)
iInstructors.add((ExamInstructor) constraint);
super.addContstraint(constraint);
iAvailablePeriodPlacements = null;
}

/**
Expand All @@ -485,6 +501,7 @@ public void removeContstraint(Constraint<Exam, ExamPlacement> constraint) {
if (constraint instanceof ExamInstructor)
iInstructors.remove(constraint);
super.removeContstraint(constraint);
iAvailablePeriodPlacements = null;
}

/**
Expand Down Expand Up @@ -932,6 +949,29 @@ public int countStudentConflicts(Assignment<Exam, ExamPlacement> assignment, Exa
}
return conf;
}

/**
* Number of instructor of this exam (that does not have direct conflicts
* allowed, see {@link ExamInstructor#canConflict(Exam, Exam)}) that attend
* some other exam in the given period.
*
* @param assignment current assignment
* @param period
* a period
* @return number of direct student conflicts that are prohibited
*/
public int countInstructorConflicts(Assignment<Exam, ExamPlacement> assignment, ExamPeriodPlacement period) {
int conf = 0;
Map<ExamInstructor, Set<Exam>> instructorsOfPeriod = ((ExamModel)getModel()).getInstructorsOfPeriod(assignment, period.getPeriod());
for (ExamInstructor i : getInstructors()) {
Set<Exam> exams = instructorsOfPeriod.get(i);
if (exams == null) continue;
for (Exam exam : exams) {
if (!exam.equals(this) && !i.canConflict(this, exam)) conf++;
}
}
return conf;
}

/**
* List of exams that are assigned to the given period and share one or more
Expand Down Expand Up @@ -1092,7 +1132,7 @@ public Collection<ExamOwner> getOwners(ExamInstructor instructor) {
* @return the appropriate period placement
*/
public ExamPeriodPlacement getPeriodPlacement(Long periodId) {
for (ExamPeriodPlacement periodPlacement : iPeriodPlacements) {
for (ExamPeriodPlacement periodPlacement : getPeriodPlacements()) {
if (periodPlacement.getId().equals(periodId))
return periodPlacement;
}
Expand Down
15 changes: 15 additions & 0 deletions src/org/cpsolver/exam/model/ExamInstructor.java
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,21 @@ public void setAvailable(int period, boolean available) {
iAvailable[period] = available;
}

/**
* True if the given two exams can have a direct instructor conflict with this
* instructor, i.e., they can be placed at the same period.
*
* @param ex1
* an exam
* @param ex2
* an exam
* @return {@link ExamStudent#isAllowDirectConflicts()} and
* {@link Exam#isAllowDirectConflicts()} for both exams
*/
public boolean canConflict(Exam ex1, Exam ex2) {
return isAllowDirectConflicts() && ex1.isAllowDirectConflicts() && ex2.isAllowDirectConflicts();
}

/*
@Override
public Context createAssignmentContext(Assignment<Exam, ExamPlacement> assignment) {
Expand Down

0 comments on commit 89c0918

Please sign in to comment.