use of org.cpsolver.studentsct.model.Request in project cpsolver by UniTime.
the class MultiCriteriaBranchAndBoundSelection method select.
/**
* Execute branch & bound, return the best found schedule for the selected
* student.
*/
public BranchBoundNeighbour select() {
iT0 = JProf.currentTimeMillis();
iTimeoutReached = false;
iCurrentAssignment = new Enrollment[iStudent.getRequests().size()];
iBestAssignment = null;
int i = 0;
for (Request r : iStudent.getRequests()) iCurrentAssignment[i++] = iAssignment.getValue(r);
saveBest();
for (int j = 0; j < iCurrentAssignment.length; j++) iCurrentAssignment[j] = null;
iValues = new HashMap<CourseRequest, List<Enrollment>>();
backTrack(0);
iT1 = JProf.currentTimeMillis();
if (iBestAssignment == null)
return null;
return new BranchBoundNeighbour(iStudent, iComparator.getTotalWeight(iAssignment, iBestAssignment), iBestAssignment);
}
use of org.cpsolver.studentsct.model.Request in project cpsolver by UniTime.
the class MultiCriteriaBranchAndBoundSelection method canAssign.
/** True if the given request can be assigned */
public boolean canAssign(Request request, int idx) {
if (!request.isAlternative() || iCurrentAssignment[idx] != null)
return true;
int alt = 0;
int i = 0;
for (Iterator<Request> e = iStudent.getRequests().iterator(); e.hasNext(); i++) {
Request r = e.next();
if (r.equals(request))
continue;
if (r.isAlternative()) {
if (iCurrentAssignment[i] != null || (r instanceof CourseRequest && ((CourseRequest) r).isWaitlist()))
alt--;
} else {
if (r instanceof CourseRequest && !((CourseRequest) r).isWaitlist() && iCurrentAssignment[i] == null)
alt++;
}
}
return (alt > 0);
}
use of org.cpsolver.studentsct.model.Request in project cpsolver by UniTime.
the class OnlineSectioningCriterion method canImprove.
@Override
public boolean canImprove(Assignment<Request, Enrollment> assignment, int maxIdx, Enrollment[] current, Enrollment[] best) {
// 0. best priority & alternativity ignoring free time requests
int alt = 0;
boolean ft = false;
for (int idx = 0; idx < current.length; idx++) {
if (isFreeTime(idx)) {
ft = true;
continue;
}
Request request = getRequest(idx);
if (idx < maxIdx) {
if (best[idx] != null) {
if (current[idx] == null)
// higher priority request assigned
return false;
if (best[idx].getPriority() < current[idx].getPriority())
// less alternative request assigned
return false;
if (request.isAlternative())
alt--;
} else {
if (current[idx] != null)
// higher priority request assigned
return true;
if (!request.isAlternative())
alt++;
}
} else {
if (best[idx] != null) {
if (best[idx].getPriority() > 0)
// alternativity can be improved
return true;
} else {
if (!request.isAlternative() || alt > 0)
// priority can be improved
return true;
}
}
}
// 0.5. avoid course time overlaps & unavailability overlaps
if (getModel().getTimeOverlaps() != null) {
int bestTimeOverlaps = 0, currentTimeOverlaps = 0;
for (int idx = 0; idx < current.length; idx++) {
if (best[idx] != null && best[idx].getRequest() instanceof CourseRequest) {
for (int x = 0; x < idx; x++) {
if (best[x] != null && best[x].getRequest() instanceof CourseRequest)
bestTimeOverlaps += getModel().getTimeOverlaps().nrConflicts(best[x], best[idx]);
}
}
if (current[idx] != null && idx < maxIdx && current[idx].getRequest() instanceof CourseRequest) {
for (int x = 0; x < idx; x++) {
if (current[x] != null && current[x].getRequest() instanceof CourseRequest)
currentTimeOverlaps += getModel().getTimeOverlaps().nrConflicts(current[x], current[idx]);
}
}
}
for (int idx = 0; idx < current.length; idx++) {
if (best[idx] != null && best[idx].getAssignments() != null && best[idx].isCourseRequest()) {
bestTimeOverlaps += getModel().getTimeOverlaps().nrNotAvailableTimeConflicts(best[idx]);
}
if (current[idx] != null && idx < maxIdx && current[idx].getAssignments() != null && current[idx].isCourseRequest()) {
currentTimeOverlaps += getModel().getTimeOverlaps().nrNotAvailableTimeConflicts(current[idx]);
}
}
if (currentTimeOverlaps < bestTimeOverlaps)
return true;
if (bestTimeOverlaps < currentTimeOverlaps)
return false;
}
// 1. maximize number of penalties
double bestPenalties = 0, currentPenalties = 0;
for (int idx = 0; idx < current.length; idx++) {
if (best[idx] != null) {
for (Section section : best[idx].getSections()) bestPenalties += getModel().getOverExpected(assignment, section, best[idx].getRequest());
}
if (current[idx] != null && idx < maxIdx) {
for (Section section : current[idx].getSections()) currentPenalties += getModel().getOverExpected(assignment, section, current[idx].getRequest());
}
}
if (currentPenalties < bestPenalties)
return true;
if (bestPenalties < currentPenalties)
return false;
// 2. best priority & alternativity including free times
if (ft) {
alt = 0;
for (int idx = 0; idx < current.length; idx++) {
Request request = getStudent().getRequests().get(idx);
if (idx < maxIdx) {
if (best[idx] != null) {
if (current[idx] == null)
// higher priority request assigned
return false;
if (best[idx].getPriority() < current[idx].getPriority())
// less alternative request assigned
return false;
if (request.isAlternative())
alt--;
} else {
if (current[idx] != null)
// higher priority request assigned
return true;
if (request instanceof CourseRequest && !request.isAlternative())
alt++;
}
} else {
if (best[idx] != null) {
if (best[idx].getPriority() > 0)
// alternativity can be improved
return true;
} else {
if (!request.isAlternative() || alt > 0)
// priority can be improved
return true;
}
}
}
}
// 3. maximize selection
int bestSelected = 0, currentSelected = 0;
for (int idx = 0; idx < current.length; idx++) {
if (best[idx] != null && best[idx].isCourseRequest()) {
Set<Section> preferred = getPreferredSections(best[idx].getRequest());
if (preferred != null && !preferred.isEmpty()) {
for (Section section : best[idx].getSections()) if (preferred.contains(section)) {
if (idx < maxIdx)
bestSelected++;
} else if (idx >= maxIdx)
bestSelected--;
}
}
if (current[idx] != null && idx < maxIdx && current[idx].isCourseRequest()) {
Set<Section> preferred = getPreferredSections(current[idx].getRequest());
if (preferred != null && !preferred.isEmpty()) {
for (Section section : current[idx].getSections()) if (preferred.contains(section))
currentSelected++;
}
}
}
if (currentSelected > bestSelected)
return true;
if (bestSelected > currentSelected)
return false;
// 3.5 maximize preferences
double bestSelectedConfigs = 0, currentSelectedConfigs = 0;
double bestSelectedSections = 0, currentSelectedSections = 0;
for (int idx = 0; idx < current.length; idx++) {
if (best[idx] != null && best[idx].getAssignments() != null && best[idx].isCourseRequest()) {
bestSelectedSections += best[idx].percentSelectedSameSection();
bestSelectedConfigs += best[idx].percentSelectedSameConfig();
if (idx >= maxIdx) {
bestSelectedSections -= 1.0;
bestSelectedConfigs -= 1.0;
}
}
if (current[idx] != null && idx < maxIdx && current[idx].getAssignments() != null && current[idx].isCourseRequest()) {
currentSelectedSections += current[idx].percentSelectedSameSection();
currentSelectedConfigs += current[idx].percentSelectedSameConfig();
}
}
if (0.3 * currentSelectedConfigs + 0.7 * currentSelectedSections > 0.3 * bestSelectedConfigs + 0.7 * bestSelectedSections)
return true;
if (0.3 * bestSelectedConfigs + 0.7 * bestSelectedSections > 0.3 * currentSelectedConfigs + 0.7 * currentSelectedSections)
return false;
// 4. avoid time overlaps
if (getModel().getTimeOverlaps() != null) {
int bestTimeOverlaps = 0, currentTimeOverlaps = 0;
for (int idx = 0; idx < current.length; idx++) {
if (best[idx] != null) {
for (int x = 0; x < idx; x++) {
if (best[x] != null)
bestTimeOverlaps += getModel().getTimeOverlaps().nrConflicts(best[x], best[idx]);
else if (getStudent().getRequests().get(x) instanceof FreeTimeRequest)
bestTimeOverlaps += getModel().getTimeOverlaps().nrConflicts(((FreeTimeRequest) getStudent().getRequests().get(x)).createEnrollment(), best[idx]);
}
}
if (current[idx] != null && idx < maxIdx) {
for (int x = 0; x < idx; x++) {
if (current[x] != null)
currentTimeOverlaps += getModel().getTimeOverlaps().nrConflicts(current[x], current[idx]);
else if (getStudent().getRequests().get(x) instanceof FreeTimeRequest)
currentTimeOverlaps += getModel().getTimeOverlaps().nrConflicts(((FreeTimeRequest) getStudent().getRequests().get(x)).createEnrollment(), current[idx]);
}
}
}
for (int idx = 0; idx < current.length; idx++) {
if (best[idx] != null && best[idx].getAssignments() != null && best[idx].isCourseRequest()) {
bestTimeOverlaps += getModel().getTimeOverlaps().nrNotAvailableTimeConflicts(best[idx]);
}
if (current[idx] != null && idx < maxIdx && current[idx].getAssignments() != null && current[idx].isCourseRequest()) {
currentTimeOverlaps += getModel().getTimeOverlaps().nrNotAvailableTimeConflicts(current[idx]);
}
}
if (currentTimeOverlaps < bestTimeOverlaps)
return true;
if (bestTimeOverlaps < currentTimeOverlaps)
return false;
}
// 5. avoid distance conflicts
if (getModel().getDistanceConflict() != null) {
int bestDistanceConf = 0, currentDistanceConf = 0;
for (int idx = 0; idx < current.length; idx++) {
if (best[idx] != null) {
for (int x = 0; x < idx; x++) {
if (best[x] != null)
bestDistanceConf += getModel().getDistanceConflict().nrConflicts(best[x], best[idx]);
}
}
if (current[idx] != null && idx < maxIdx) {
for (int x = 0; x < idx; x++) {
if (current[x] != null)
currentDistanceConf += getModel().getDistanceConflict().nrConflicts(current[x], current[idx]);
}
}
}
if (currentDistanceConf < bestDistanceConf)
return true;
if (bestDistanceConf < currentDistanceConf)
return false;
}
// 6. avoid no-time sections
int bestNoTime = 0, currentNoTime = 0;
for (int idx = 0; idx < current.length; idx++) {
if (best[idx] != null) {
for (Section section : best[idx].getSections()) if (section.getTime() == null)
bestNoTime++;
}
if (current[idx] != null && idx < maxIdx) {
for (Section section : current[idx].getSections()) if (section.getTime() == null)
currentNoTime++;
}
}
if (currentNoTime < bestNoTime)
return true;
if (bestNoTime < currentNoTime)
return false;
// 7. balance sections
double bestUnavailableSize = 0.0, currentUnavailableSize = 0.0;
int bestAltSectionsWithLimit = 0, currentAltSectionsWithLimit = 0;
for (int idx = 0; idx < current.length; idx++) {
if (best[idx] != null) {
for (Section section : best[idx].getSections()) {
Subpart subpart = section.getSubpart();
// skip unlimited and single section subparts
if (subpart.getSections().size() <= 1 || subpart.getLimit() <= 0)
continue;
// average size
double averageSize = ((double) subpart.getLimit()) / subpart.getSections().size();
// section is below average
if (section.getLimit() < averageSize)
bestUnavailableSize += (averageSize - section.getLimit()) / averageSize;
bestAltSectionsWithLimit++;
}
}
if (current[idx] != null && idx < maxIdx) {
for (Section section : current[idx].getSections()) {
Subpart subpart = section.getSubpart();
// skip unlimited and single section subparts
if (subpart.getSections().size() <= 1 || subpart.getLimit() <= 0)
continue;
// average size
double averageSize = ((double) subpart.getLimit()) / subpart.getSections().size();
// section is below average
if (section.getLimit() < averageSize)
currentUnavailableSize += (averageSize - section.getLimit()) / averageSize;
currentAltSectionsWithLimit++;
}
}
}
double bestUnavailableSizeFraction = (bestUnavailableSize > 0 ? bestUnavailableSize / bestAltSectionsWithLimit : 0.0);
double currentUnavailableSizeFraction = (currentUnavailableSize > 0 ? currentUnavailableSize / currentAltSectionsWithLimit : 0.0);
if (currentUnavailableSizeFraction < bestUnavailableSizeFraction)
return true;
if (bestUnavailableSizeFraction < currentUnavailableSizeFraction)
return false;
// 8. average penalty sections
double bestPenalty = 0.0, currentPenalty = 0.0;
for (int idx = 0; idx < current.length; idx++) {
if (best[idx] != null) {
for (Section section : best[idx].getSections()) bestPenalty += section.getPenalty();
if (idx >= maxIdx && best[idx].isCourseRequest())
bestPenalty -= ((CourseRequest) best[idx].getRequest()).getMinPenalty();
}
if (current[idx] != null && idx < maxIdx) {
for (Section section : current[idx].getSections()) currentPenalty += section.getPenalty();
}
}
if (currentPenalty < bestPenalty)
return true;
if (bestPenalty < currentPenalty)
return false;
return true;
}
use of org.cpsolver.studentsct.model.Request 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());
}
use of org.cpsolver.studentsct.model.Request in project cpsolver by UniTime.
the class ShuffleStudentsSelection method selectNeighbour.
@Override
public Neighbour<Request, Enrollment> selectNeighbour(Solution<Request, Enrollment> solution) {
Shuffle shuffle = null;
while ((shuffle = iQueue.poll()) != null) {
Progress.getInstance(solution.getModel()).incProgress();
// Take an item from the queue, try backtrack first
Neighbour<Request, Enrollment> n = iBacktrack.selectNeighbour(solution, shuffle);
if (n != null)
return n;
// If fails, just assign the request randomly and hope for the best
List<Enrollment> adepts = new ArrayList<Enrollment>();
for (Enrollment e : shuffle.getRequest().values(solution.getAssignment())) {
if (shuffle.matchFilter(e))
adepts.add(e);
}
if (!adepts.isEmpty()) {
return new SimpleNeighbour<Request, Enrollment>(shuffle.getRequest(), ToolBox.random(adepts));
}
}
return null;
}
Aggregations