From afea8eea51e0bc612465bb0044f7971ab5bde695 Mon Sep 17 00:00:00 2001 From: tomas-muller Date: Thu, 25 Jun 2020 13:29:36 +0200 Subject: [PATCH] Student Scheduling Solver: Priority Students - use the setting of Sectioning.PriorityStudentsFirstSelection.AllIn when comparting two requests for student and request priority - when Sectioning.PriorityStudentsFirstSelection.AllIn is set to true - request of a priority student is always considered more important e.g., do not assign a critical request of non-priority student when it conflicts with a non-critical request of a priority student (priority student takes precedence over non-priority) - when Sectioning.PriorityStudentsFirstSelection.AllIn is set to false - more critical request is always connsidered more important (using request priority) e.g., do not assign a non-critical request of a priority student when it conflicts with a critical request of a non-priority students (critical request takes precedence over non-critical) --- .../studentsct/constraint/ConfigLimit.java | 57 +++++++++++++------ .../studentsct/constraint/CourseLimit.java | 4 +- .../constraint/ReservationLimit.java | 9 +-- .../studentsct/constraint/SectionLimit.java | 7 ++- ...RandomizedBacktrackNeighbourSelection.java | 6 +- .../selection/StandardSelection.java | 6 +- .../selection/SwapStudentSelection.java | 6 +- .../cpsolver/studentsct/model/Request.java | 3 + 8 files changed, 70 insertions(+), 28 deletions(-) diff --git a/src/org/cpsolver/studentsct/constraint/ConfigLimit.java b/src/org/cpsolver/studentsct/constraint/ConfigLimit.java index ca05fbdb..8ccc0ae5 100644 --- a/src/org/cpsolver/studentsct/constraint/ConfigLimit.java +++ b/src/org/cpsolver/studentsct/constraint/ConfigLimit.java @@ -67,6 +67,7 @@ public class ConfigLimit extends GlobalConstraint { private static double sNominalWeight = 0.00001; private boolean iPreferDummyStudents = false; + private boolean iPreferPriorityStudents = true; /** * Constructor @@ -77,6 +78,7 @@ public class ConfigLimit extends GlobalConstraint { public ConfigLimit(DataProperties cfg) { super(); iPreferDummyStudents = cfg.getPropertyBoolean("ConfigLimit.PreferDummyStudents", false); + iPreferPriorityStudents = cfg.getPropertyBoolean("Sectioning.PriorityStudentsFirstSelection.AllIn", true); } @@ -165,7 +167,7 @@ public void computeConflicts(Assignment assignment, Enrollm // pick adept (prefer dummy students & students w/o reservation), decrease enrollment // weight, make conflict - Enrollment conflict = new Adepts(iPreferDummyStudents, adepts, assignment).get(); + Enrollment conflict = new Adepts(iPreferDummyStudents, iPreferPriorityStudents, adepts, assignment).get(); adepts.remove(conflict); enrlWeight -= conflict.getRequest().getWeight(); conflicts.add(conflict); @@ -225,19 +227,23 @@ static class Adepts { private RequestPriority iRequestPriority; private boolean iReservation; private boolean iConsiderDummy; + private boolean iPriorityFirst; - public Adepts(boolean preferDummy) { + public Adepts(boolean preferDummy, boolean priorityFirst) { iConsiderDummy = preferDummy; + iPriorityFirst = priorityFirst; iEnrollments = new ArrayList(); } - public Adepts(boolean preferDummy, int size) { + public Adepts(boolean preferDummy, boolean priorityFirst, int size) { iConsiderDummy = preferDummy; + iPriorityFirst = priorityFirst; iEnrollments = new ArrayList(size); } - public Adepts(boolean preferDummy, Collection adepts, Assignment assignment) { + public Adepts(boolean preferDummy, boolean priorityFirst, Collection adepts, Assignment assignment) { iConsiderDummy = preferDummy; + iPriorityFirst = priorityFirst; iEnrollments = new ArrayList(adepts.size()); for (Enrollment adept: adepts) add(adept, assignment); @@ -261,19 +267,36 @@ public void add(Enrollment enrollment, Assignment assignmen iEnrollments.add(enrollment); return; } - if (iPriority != priority) { // different priority - if (priority) return; // ignore priority students - iEnrollments.clear(); - iValue = value; iDummy = dummy; iPriority = priority; iRequestPriority = rp; iReservation = reservation; - iEnrollments.add(enrollment); - return; - } - if (iRequestPriority != rp) { // different request priority - if (rp.ordinal() < iRequestPriority.ordinal()) return; // ignore more critical courses - iEnrollments.clear(); - iValue = value; iDummy = dummy; iPriority = priority; iRequestPriority = rp; iReservation = reservation; - iEnrollments.add(enrollment); - return; + if (iPriorityFirst) { + if (iPriority != priority) { // different priority + if (priority) return; // ignore priority students + iEnrollments.clear(); + iValue = value; iDummy = dummy; iPriority = priority; iRequestPriority = rp; iReservation = reservation; + iEnrollments.add(enrollment); + return; + } + if (iRequestPriority != rp) { // different request priority + if (rp.ordinal() < iRequestPriority.ordinal()) return; // ignore more critical courses + iEnrollments.clear(); + iValue = value; iDummy = dummy; iPriority = priority; iRequestPriority = rp; iReservation = reservation; + iEnrollments.add(enrollment); + return; + } + } else { + if (iRequestPriority != rp) { // different request priority + if (rp.ordinal() < iRequestPriority.ordinal()) return; // ignore more critical courses + iEnrollments.clear(); + iValue = value; iDummy = dummy; iPriority = priority; iRequestPriority = rp; iReservation = reservation; + iEnrollments.add(enrollment); + return; + } + if (iPriority != priority) { // different priority + if (priority) return; // ignore priority students + iEnrollments.clear(); + iValue = value; iDummy = dummy; iPriority = priority; iRequestPriority = rp; iReservation = reservation; + iEnrollments.add(enrollment); + return; + } } if (iReservation != reservation) { // different reservation if (reservation) return; // ignore students with reservation diff --git a/src/org/cpsolver/studentsct/constraint/CourseLimit.java b/src/org/cpsolver/studentsct/constraint/CourseLimit.java index ae2a3156..da10b246 100644 --- a/src/org/cpsolver/studentsct/constraint/CourseLimit.java +++ b/src/org/cpsolver/studentsct/constraint/CourseLimit.java @@ -65,6 +65,7 @@ public class CourseLimit extends GlobalConstraint { private static double sNominalWeight = 0.00001; private boolean iPreferDummyStudents = false; + private boolean iPreferPriorityStudents = true; /** * Constructor @@ -75,6 +76,7 @@ public class CourseLimit extends GlobalConstraint { public CourseLimit(DataProperties cfg) { super(); iPreferDummyStudents = cfg.getPropertyBoolean("CourseLimit.PreferDummyStudents", false); + iPreferPriorityStudents = cfg.getPropertyBoolean("Sectioning.PriorityStudentsFirstSelection.AllIn", true); } @@ -163,7 +165,7 @@ public void computeConflicts(Assignment assignment, Enrollm // pick adept (prefer dummy students), decrease unreserved space, // make conflict - Enrollment conflict = new Adepts(iPreferDummyStudents, adepts, assignment).get(); + Enrollment conflict = new Adepts(iPreferDummyStudents, iPreferPriorityStudents, adepts, assignment).get(); adepts.remove(conflict); enrlWeight -= conflict.getRequest().getWeight(); conflicts.add(conflict); diff --git a/src/org/cpsolver/studentsct/constraint/ReservationLimit.java b/src/org/cpsolver/studentsct/constraint/ReservationLimit.java index cb6b6787..1f851fed 100644 --- a/src/org/cpsolver/studentsct/constraint/ReservationLimit.java +++ b/src/org/cpsolver/studentsct/constraint/ReservationLimit.java @@ -7,7 +7,6 @@ import org.cpsolver.ifs.assignment.Assignment; import org.cpsolver.ifs.model.GlobalConstraint; import org.cpsolver.ifs.util.DataProperties; -import org.cpsolver.ifs.util.ToolBox; import org.cpsolver.studentsct.constraint.ConfigLimit.Adepts; import org.cpsolver.studentsct.model.Config; import org.cpsolver.studentsct.model.Enrollment; @@ -63,6 +62,7 @@ public class ReservationLimit extends GlobalConstraint { private static double sNominalWeight = 0.00001; private boolean iPreferDummyStudents = false; + private boolean iPreferPriorityStudents = true; /** * Constructor @@ -73,6 +73,7 @@ public class ReservationLimit extends GlobalConstraint { public ReservationLimit(DataProperties cfg) { super(); iPreferDummyStudents = cfg.getPropertyBoolean("ReservationLimit.PreferDummyStudents", false); + iPreferPriorityStudents = cfg.getPropertyBoolean("Sectioning.PriorityStudentsFirstSelection.AllIn", true); } @@ -166,7 +167,7 @@ public void computeConflicts(Assignment assignment, Enrollm // pick adept (prefer dummy students), decrease unreserved space, // make conflict - Enrollment conflict = new Adepts(iPreferDummyStudents, adepts, assignment).get(); + Enrollment conflict = new Adepts(iPreferDummyStudents, iPreferPriorityStudents, adepts, assignment).get(); adepts.remove(conflict); reserved += conflict.getRequest().getWeight(); conflicts.add(conflict); @@ -213,7 +214,7 @@ public void computeConflicts(Assignment assignment, Enrollm // pick adept (prefer dummy students), decrease unreserved space, // make conflict - Enrollment conflict = new Adepts(iPreferDummyStudents, adepts, assignment).get(); + Enrollment conflict = new Adepts(iPreferDummyStudents, iPreferPriorityStudents, adepts, assignment).get(); adepts.remove(conflict); unreserved += conflict.getRequest().getWeight(); conflicts.add(conflict); @@ -257,7 +258,7 @@ public void computeConflicts(Assignment assignment, Enrollm // pick adept (prefer dummy students), decrease unreserved space, // make conflict - Enrollment conflict = new Adepts(iPreferDummyStudents, adepts, assignment).get(); + Enrollment conflict = new Adepts(iPreferDummyStudents, iPreferPriorityStudents, adepts, assignment).get(); adepts.remove(conflict); unreserved += conflict.getRequest().getWeight(); conflicts.add(conflict); diff --git a/src/org/cpsolver/studentsct/constraint/SectionLimit.java b/src/org/cpsolver/studentsct/constraint/SectionLimit.java index 0303e253..c01183f5 100644 --- a/src/org/cpsolver/studentsct/constraint/SectionLimit.java +++ b/src/org/cpsolver/studentsct/constraint/SectionLimit.java @@ -7,7 +7,6 @@ import org.cpsolver.ifs.assignment.Assignment; import org.cpsolver.ifs.model.GlobalConstraint; import org.cpsolver.ifs.util.DataProperties; -import org.cpsolver.ifs.util.ToolBox; import org.cpsolver.studentsct.constraint.ConfigLimit.Adepts; import org.cpsolver.studentsct.model.Enrollment; import org.cpsolver.studentsct.model.Request; @@ -71,6 +70,7 @@ public class SectionLimit extends GlobalConstraint { private static double sNominalWeight = 0.00001; private boolean iPreferDummyStudents = false; + private boolean iPreferPriorityStudents = true; /** * Constructor @@ -81,6 +81,7 @@ public class SectionLimit extends GlobalConstraint { public SectionLimit(DataProperties cfg) { super(); iPreferDummyStudents = cfg.getPropertyBoolean("SectionLimit.PreferDummyStudents", false); + iPreferPriorityStudents = cfg.getPropertyBoolean("Sectioning.PriorityStudentsFirstSelection.AllIn", true); } /** @@ -196,7 +197,7 @@ public void computeConflicts(Assignment assignment, Enrollm // pick adept (prefer dummy students), decrease unreserved space, // make conflict - Enrollment conflict = new Adepts(iPreferDummyStudents, adepts, assignment).get(); + Enrollment conflict = new Adepts(iPreferDummyStudents, iPreferPriorityStudents, adepts, assignment).get(); adepts.remove(conflict); unreserved += conflict.getRequest().getWeight(); conflicts.add(conflict); @@ -237,7 +238,7 @@ public void computeConflicts(Assignment assignment, Enrollm // pick adept (prefer dummy students & students w/o reservation), decrease enrollment // weight, make conflict - Enrollment conflict = new Adepts(iPreferDummyStudents, adepts, assignment).get(); + Enrollment conflict = new Adepts(iPreferDummyStudents, iPreferPriorityStudents, adepts, assignment).get(); adepts.remove(conflict); enrlWeight -= conflict.getRequest().getWeight(); conflicts.add(conflict); diff --git a/src/org/cpsolver/studentsct/heuristics/RandomizedBacktrackNeighbourSelection.java b/src/org/cpsolver/studentsct/heuristics/RandomizedBacktrackNeighbourSelection.java index 294cccf4..993d98d3 100644 --- a/src/org/cpsolver/studentsct/heuristics/RandomizedBacktrackNeighbourSelection.java +++ b/src/org/cpsolver/studentsct/heuristics/RandomizedBacktrackNeighbourSelection.java @@ -63,6 +63,7 @@ */ public class RandomizedBacktrackNeighbourSelection extends BacktrackNeighbourSelection { private int iMaxValues = 100; + private boolean iPreferPriorityStudents = true; /** * Constructor @@ -74,6 +75,7 @@ public class RandomizedBacktrackNeighbourSelection extends BacktrackNeighbourSel public RandomizedBacktrackNeighbourSelection(DataProperties properties) throws Exception { super(properties); iMaxValues = properties.getPropertyInt("Neighbour.MaxValues", iMaxValues); + iPreferPriorityStudents = properties.getPropertyBoolean("Sectioning.PriorityStudentsFirstSelection.AllIn", true); } /** @@ -130,8 +132,10 @@ public boolean canUnassign(Enrollment enrollment, Enrollment conflict, Assignmen float credit = conflict.getRequest().getStudent().getAssignedCredit(assignment) - conflict.getCredit(); if (credit < conflict.getRequest().getStudent().getMinCredit()) return false; } - if (!enrollment.getStudent().isPriority() && conflict.getStudent().isPriority()) return false; if (!conflict.getRequest().isAlternative() && conflict.getRequest().getRequestPriority().isHigher(enrollment.getRequest())) return false; + if (iPreferPriorityStudents || conflict.getRequest().getRequestPriority().isSame(enrollment.getRequest())) { + if (!enrollment.getStudent().isPriority() && conflict.getStudent().isPriority()) return false; + } return true; } diff --git a/src/org/cpsolver/studentsct/heuristics/selection/StandardSelection.java b/src/org/cpsolver/studentsct/heuristics/selection/StandardSelection.java index f281dccb..810a6a0c 100644 --- a/src/org/cpsolver/studentsct/heuristics/selection/StandardSelection.java +++ b/src/org/cpsolver/studentsct/heuristics/selection/StandardSelection.java @@ -65,6 +65,7 @@ public class StandardSelection implements NeighbourSelection iValueSelection = null; private VariableSelection iVariableSelection = null; protected long iNrIterations = -1; + private boolean iPreferPriorityStudents = true; /** * Constructor (variable and value selection are expected to be already @@ -81,6 +82,7 @@ public StandardSelection(DataProperties properties, VariableSelection valueSelection) { iVariableSelection = variableSelection; iValueSelection = valueSelection; + iPreferPriorityStudents = properties.getPropertyBoolean("Sectioning.PriorityStudentsFirstSelection.AllIn", true); } /** Initialization */ @@ -110,8 +112,10 @@ public boolean canUnassign(Enrollment enrollment, Enrollment conflict, Assignmen float credit = conflict.getRequest().getStudent().getAssignedCredit(assignment) - conflict.getCredit(); if (credit < conflict.getRequest().getStudent().getMinCredit()) return false; } - if (!enrollment.getStudent().isPriority() && conflict.getStudent().isPriority()) return false; if (!conflict.getRequest().isAlternative() && conflict.getRequest().getRequestPriority().isHigher(enrollment.getRequest())) return false; + if (iPreferPriorityStudents || conflict.getRequest().getRequestPriority().isSame(enrollment.getRequest())) { + if (!enrollment.getStudent().isPriority() && conflict.getStudent().isPriority()) return false; + } return true; } diff --git a/src/org/cpsolver/studentsct/heuristics/selection/SwapStudentSelection.java b/src/org/cpsolver/studentsct/heuristics/selection/SwapStudentSelection.java index 6bf972fb..945998fd 100644 --- a/src/org/cpsolver/studentsct/heuristics/selection/SwapStudentSelection.java +++ b/src/org/cpsolver/studentsct/heuristics/selection/SwapStudentSelection.java @@ -101,6 +101,7 @@ public class SwapStudentSelection implements NeighbourSelection