use of org.cpsolver.studentsct.model.Subpart in project cpsolver by UniTime.
the class LinkedSections method computeConflicts.
/**
* Compute conflicting enrollments. If the given enrollment contains sections of this link
* (one for each subpart in {@link LinkedSections#getSubparts(Offering)}), another assignment
* of this student is in a conflict, if it does not contain the appropriate sections from
* {@link LinkedSections#getSubparts(Offering)} and {@link LinkedSections#getSections(Subpart)}.
*
* @param enrollment given enrollment
* @param assignment custom assignment
* @param conflicts found conflicts are given to this interface, see {@link ConflictHandler#onConflict(Enrollment)}
*/
public void computeConflicts(Enrollment enrollment, EnrollmentAssignment assignment, ConflictHandler conflicts) {
if (enrollment == null || enrollment.getCourse() == null)
return;
if (enrollment.getReservation() != null && enrollment.getReservation().canBreakLinkedSections())
return;
Map<Subpart, Set<Section>> subparts = iSections.get(enrollment.getCourse().getOffering());
if (subparts == null || subparts.isEmpty())
return;
boolean match = false, partial = false;
for (Section section : enrollment.getSections()) {
Set<Section> sections = subparts.get(section.getSubpart());
if (sections != null) {
if (sections.contains(section))
match = true;
else
partial = true;
}
}
boolean full = match && !partial;
if (isMustBeUsed()) {
if (!full) {
// not full match -> conflict if there is no other linked section constraint with a full match
// check if there is some other constraint taking care of this case
boolean hasOtherMatch = false;
for (LinkedSections other : enrollment.getStudent().getLinkedSections()) {
if (other.hasFullMatch(enrollment) && nrSharedOfferings(other) > 1) {
hasOtherMatch = true;
break;
}
}
// no other match -> problem
if (!hasOtherMatch && !conflicts.onConflict(enrollment))
return;
}
}
if (full) {
// full match -> check other enrollments
for (int i = 0; i < enrollment.getStudent().getRequests().size(); i++) {
Request request = enrollment.getStudent().getRequests().get(i);
// given enrollment
if (request.equals(enrollment.getRequest()))
continue;
Enrollment otherEnrollment = assignment.getEnrollment(request, i);
// not assigned or not course request
if (otherEnrollment == null || otherEnrollment.getCourse() == null)
continue;
if (otherEnrollment.getReservation() != null && otherEnrollment.getReservation().canBreakLinkedSections())
continue;
Map<Subpart, Set<Section>> otherSubparts = iSections.get(otherEnrollment.getCourse().getOffering());
// offering is not in the link
if (otherSubparts == null || otherSubparts.isEmpty())
continue;
boolean otherMatch = false, otherPartial = false;
for (Section section : otherEnrollment.getSections()) {
Set<Section> otherSections = otherSubparts.get(section.getSubpart());
if (otherSections != null) {
if (otherSections.contains(section))
otherMatch = true;
else
otherPartial = true;
}
}
boolean otherFull = otherMatch && !otherPartial;
// not full match -> conflict
if (!otherFull && !conflicts.onConflict(otherEnrollment))
return;
}
} else {
// no or only partial match -> there should be no match in other offerings too
for (int i = 0; i < enrollment.getStudent().getRequests().size(); i++) {
Request request = enrollment.getStudent().getRequests().get(i);
// given enrollment
if (request.equals(enrollment.getRequest()))
continue;
Enrollment otherEnrollment = assignment.getEnrollment(request, i);
// not assigned or not course request
if (otherEnrollment == null || otherEnrollment.getCourse() == null)
continue;
if (otherEnrollment.getReservation() != null && otherEnrollment.getReservation().canBreakLinkedSections())
continue;
Map<Subpart, Set<Section>> otherSubparts = iSections.get(otherEnrollment.getCourse().getOffering());
// offering is not in the link
if (otherSubparts == null || otherSubparts.isEmpty())
continue;
boolean otherMatch = false, otherPartial = false;
for (Section section : otherEnrollment.getSections()) {
Set<Section> otherSections = otherSubparts.get(section.getSubpart());
if (otherSections != null) {
if (otherSections.contains(section))
otherMatch = true;
else
otherPartial = true;
}
}
boolean otherFull = otherMatch && !otherPartial;
// full match -> conflict
if (otherFull && !conflicts.onConflict(otherEnrollment))
return;
}
}
}
use of org.cpsolver.studentsct.model.Subpart in project cpsolver by UniTime.
the class LinkedSections method hasFullMatch.
/**
* Check if the given enrollment fully matches this constraint
* @param enrollment an enrollment
* @return true, if there is a full match
*/
protected boolean hasFullMatch(Enrollment enrollment) {
// not assigned or not course request
if (enrollment == null || enrollment.getCourse() == null)
return false;
Map<Subpart, Set<Section>> subparts = iSections.get(enrollment.getCourse().getOffering());
// offering is not in the link
if (subparts == null || subparts.isEmpty())
return false;
boolean match = false, partial = false;
for (Section section : enrollment.getSections()) {
Set<Section> sections = subparts.get(section.getSubpart());
if (sections != null) {
if (sections.contains(section))
match = true;
else
partial = true;
}
}
return match && !partial;
}
use of org.cpsolver.studentsct.model.Subpart in project cpsolver by UniTime.
the class LinkedSections method toString.
@Override
public String toString() {
String sections = "";
for (Map.Entry<Offering, Map<Subpart, Set<Section>>> e : iSections.entrySet()) {
sections += (sections.isEmpty() ? "" : "; ") + e.getKey().getName();
Set<String> ids = new TreeSet<String>();
for (Map.Entry<Subpart, Set<Section>> f : e.getValue().entrySet()) {
for (Section s : f.getValue()) ids.add(s.getName());
sections += ":" + ids;
}
}
return "LinkedSections{" + sections + "}";
}
use of org.cpsolver.studentsct.model.Subpart in project cpsolver by UniTime.
the class OnlineSelection method setPenalties.
/**
* Set online sectioning penalties to all sections of all courses of the
* given student
*/
private static void setPenalties(Assignment<Request, Enrollment> assignment, Student student) {
for (Request request : student.getRequests()) {
if (!(request instanceof CourseRequest))
continue;
CourseRequest courseRequest = (CourseRequest) request;
for (Course course : courseRequest.getCourses()) {
for (Config config : course.getOffering().getConfigs()) {
for (Subpart subpart : config.getSubparts()) {
for (Section section : subpart.getSections()) {
section.setPenalty(section.getOnlineSectioningPenalty(assignment));
}
}
}
}
courseRequest.clearCache();
}
}
use of org.cpsolver.studentsct.model.Subpart in project cpsolver by UniTime.
the class ShuffleStudentsSelection method init.
@Override
public void init(Solver<Request, Enrollment> solver) {
StudentSectioningModel model = (StudentSectioningModel) solver.currentSolution().getModel();
iQueue = new LinkedList<Shuffle>();
Assignment<Request, Enrollment> assignment = solver.currentSolution().getAssignment();
// Check all request groups that have a spread < 1.0
RouletteWheelSelection<RequestGroup> groups = new RouletteWheelSelection<RequestGroup>();
for (Offering offering : model.getOfferings()) {
for (Course course : offering.getCourses()) {
for (RequestGroup group : course.getRequestGroups()) {
double spread = group.getAverageSpread(solver.currentSolution().getAssignment());
if (spread >= 1.0)
continue;
groups.add(group, 1.0 - spread);
}
}
}
// If there are some, pick one randomly (using roulette wheel selection)
if (groups.hasMoreElements()) {
RequestGroup group = groups.nextElement();
RouletteWheelSelection<Subpart> subparts = new RouletteWheelSelection<Subpart>();
for (CourseRequest cr : group.getRequests()) {
Enrollment e = assignment.getValue(cr);
if (e != null)
for (Section section : e.getSections()) if (group.getSectionSpread(assignment, section) < 1.0)
subparts.addExisting(section.getSubpart(), 1.0);
}
if (subparts.hasMoreElements()) {
// Pick a subpart that has sections with a section spread < 1.0
Subpart subpart = subparts.nextElement();
RouletteWheelSelection<Section> sections = new RouletteWheelSelection<Section>();
section: for (Section section : subpart.getSections()) {
// Only take sections that all requests can use
for (CourseRequest cr : group.getRequests()) {
boolean match = false;
for (Enrollment e : cr.values(assignment)) if (e.getSections().contains(section)) {
match = true;
break;
}
if (!match)
continue section;
}
// Take sections with conflicts with lower probability
int nrConflicts = 0;
if (!section.isAllowOverlap())
requests: for (CourseRequest cr : group.getRequests()) {
for (Request r : cr.getStudent().getRequests()) {
if (r.equals(cr))
continue;
Enrollment e = assignment.getValue(r);
if (e != null && !e.isAllowOverlap() && section.isOverlapping(e.getSections())) {
nrConflicts++;
continue requests;
}
}
}
sections.add(section, 1 + group.getRequests().size() - nrConflicts);
}
Set<Section> filter = new HashSet<Section>();
double space = 0.0;
// Pick enough sections
while (sections.hasMoreElements()) {
Section section = sections.nextElement();
if (filter.add(section)) {
if (section.getLimit() < 0)
break;
space += section.getLimit();
}
if (space >= group.getTotalWeight())
break;
}
// Add all requests that should be moved into the queue
for (CourseRequest cr : group.getRequests()) {
Shuffle shuffle = new Shuffle(group, cr, filter);
Enrollment e = assignment.getValue(cr);
if (e != null && shuffle.matchFilter(e))
continue;
iQueue.add(shuffle);
}
} else {
// No subpart -> no section filter
for (CourseRequest cr : group.getRequests()) iQueue.add(new Shuffle(group, cr, null));
}
}
// Shuffle the queue
Collections.shuffle((LinkedList<Shuffle>) iQueue);
// Initialize the backtrack selection, if needed
if (iBacktrack == null) {
try {
iBacktrack = new ShuffleBacktrackNeighbourSelection(solver.getProperties());
iBacktrack.init(solver);
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
// Change progress
Progress.getInstance(solver.currentSolution().getModel()).setPhase("Shuffling students along request groups...", iQueue.size());
}
Aggregations