Skip to content

Commit

Permalink
Student Scheduling: Student Groups & Accommodations
Browse files Browse the repository at this point in the history
in preparation for being able to start using student minors:
- created separate lists for student groups and accommodations (instead of storing them as minors which have not been used so far)
- removed the old student academic area - classification and student academic area - major pairs (use the student area, classification, major tripplets)
- updated XML load and save (XML load does understand the old format, creting student groups and accommodations)
  • Loading branch information
tomas-muller committed Jan 7, 2021
1 parent e152854 commit f5fe357
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 202 deletions.
29 changes: 20 additions & 9 deletions src/org/cpsolver/studentsct/StudentSectioningXMLLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import org.cpsolver.ifs.util.Progress;
import org.cpsolver.studentsct.constraint.FixedAssignments;
import org.cpsolver.studentsct.filter.StudentFilter;
import org.cpsolver.studentsct.model.AcademicAreaCode;
import org.cpsolver.studentsct.model.AreaClassificationMajor;
import org.cpsolver.studentsct.model.Choice;
import org.cpsolver.studentsct.model.Config;
Expand All @@ -37,6 +36,7 @@
import org.cpsolver.studentsct.model.RequestGroup;
import org.cpsolver.studentsct.model.Section;
import org.cpsolver.studentsct.model.Student;
import org.cpsolver.studentsct.model.StudentGroup;
import org.cpsolver.studentsct.model.Subpart;
import org.cpsolver.studentsct.model.Unavailability;
import org.cpsolver.studentsct.reservation.CourseReservation;
Expand Down Expand Up @@ -949,29 +949,40 @@ protected Student loadStudent(Element studentEl, Map<Long, Offering> offeringTab
String maxCredit = studentEl.attributeValue("maxCredit");
if (maxCredit != null)
student.setMaxCredit(Float.parseFloat(maxCredit));
List<String[]> clasf = new ArrayList<String[]>();
List<String[]> major = new ArrayList<String[]>();
for (Iterator<?> j = studentEl.elementIterator(); j.hasNext();) {
Element requestEl = (Element) j.next();
if ("classification".equals(requestEl.getName())) {
student.getAcademicAreaClasiffications().add(
new AcademicAreaCode(requestEl.attributeValue("area"), requestEl.attributeValue("code"), requestEl.attributeValue("label")));
clasf.add(new String[] {requestEl.attributeValue("area"), requestEl.attributeValue("code"), requestEl.attributeValue("label")});
} else if ("major".equals(requestEl.getName())) {
student.getMajors().add(
new AcademicAreaCode(requestEl.attributeValue("area"), requestEl.attributeValue("code"), requestEl.attributeValue("label")));
major.add(new String[] {requestEl.attributeValue("area"), requestEl.attributeValue("code"), requestEl.attributeValue("label")});
} else if ("minor".equals(requestEl.getName())) {
student.getMinors().add(
new AcademicAreaCode(requestEl.attributeValue("area"), requestEl.attributeValue("code"), requestEl.attributeValue("label")));
if ("A".equals(requestEl.attributeValue("area")))
student.getAccommodations().add(requestEl.attributeValue("code"));
else
student.getGroups().add(new StudentGroup(requestEl.attributeValue("area"), requestEl.attributeValue("code"), requestEl.attributeValue("label")));
} else if ("unavailability".equals(requestEl.getName())) {
Offering offering = offeringTable.get(Long.parseLong(requestEl.attributeValue("offering")));
Section section = (offering == null ? null : offering.getSection(Long.parseLong(requestEl.attributeValue("section"))));
if (section != null)
new Unavailability(student, section, "true".equals(requestEl.attributeValue("allowOverlap")));
} else if ("acm".equals(requestEl.getName())) {
student.getAreaClassificationMajors().add(
new AreaClassificationMajor(requestEl.attributeValue("area"), requestEl.attributeValue("classification"), requestEl.attributeValue("major")));
if (requestEl.attributeValue("minor") != null)
student.getAreaClassificationMajors().add(new AreaClassificationMajor(requestEl.attributeValue("area"), requestEl.attributeValue("classification"), requestEl.attributeValue("minor")));
else
student.getAreaClassificationMajors().add(new AreaClassificationMajor(requestEl.attributeValue("area"), requestEl.attributeValue("classification"), requestEl.attributeValue("major")));
} else if ("group".equals(requestEl.getName())) {
student.getGroups().add(new StudentGroup(requestEl.attributeValue("type"), requestEl.attributeValue("reference"), requestEl.attributeValue("name")));
} else if ("accommodation".equals(requestEl.getName())) {
student.getAccommodations().add(requestEl.attributeValue("reference"));
} else if ("advisor".equals(requestEl.getName())) {
student.getAdvisors().add(new Instructor(0l, requestEl.attributeValue("externalId"), requestEl.attributeValue("name"), requestEl.attributeValue("email")));
}
}
for (int i = 0; i < Math.min(clasf.size(), major.size()); i++) {
student.getAreaClassificationMajors().add(new AreaClassificationMajor(clasf.get(i)[0],clasf.get(i)[1],major.get(i)[1]));
}
return student;
}

Expand Down
49 changes: 21 additions & 28 deletions src/org/cpsolver/studentsct/StudentSectioningXMLSaver.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import org.cpsolver.ifs.solver.Solver;
import org.cpsolver.ifs.util.Progress;
import org.cpsolver.studentsct.constraint.LinkedSections;
import org.cpsolver.studentsct.model.AcademicAreaCode;
import org.cpsolver.studentsct.model.AreaClassificationMajor;
import org.cpsolver.studentsct.model.Choice;
import org.cpsolver.studentsct.model.Config;
Expand All @@ -35,6 +34,7 @@
import org.cpsolver.studentsct.model.Section;
import org.cpsolver.studentsct.model.Student;
import org.cpsolver.studentsct.model.Student.StudentPriority;
import org.cpsolver.studentsct.model.StudentGroup;
import org.cpsolver.studentsct.model.Subpart;
import org.cpsolver.studentsct.model.Unavailability;
import org.cpsolver.studentsct.reservation.CourseReservation;
Expand Down Expand Up @@ -648,33 +648,6 @@ protected void saveStudent(Element studentEl, Student student) {
if (student.hasMaxCredit())
studentEl.addAttribute("maxCredit", String.valueOf(student.getMaxCredit()));
if (iSaveStudentInfo) {
for (AcademicAreaCode aac : student.getAcademicAreaClasiffications()) {
Element aacEl = studentEl.addElement("classification");
if (aac.getArea() != null)
aacEl.addAttribute("area", aac.getArea());
if (aac.getCode() != null)
aacEl.addAttribute("code", aac.getCode());
if (aac.getLabel() != null)
aacEl.addAttribute("label", aac.getLabel());
}
for (AcademicAreaCode aac : student.getMajors()) {
Element aacEl = studentEl.addElement("major");
if (aac.getArea() != null)
aacEl.addAttribute("area", aac.getArea());
if (aac.getCode() != null)
aacEl.addAttribute("code", aac.getCode());
if (aac.getLabel() != null)
aacEl.addAttribute("label", aac.getLabel());
}
for (AcademicAreaCode aac : student.getMinors()) {
Element aacEl = studentEl.addElement("minor");
if (aac.getArea() != null)
aacEl.addAttribute("area", aac.getArea());
if (aac.getCode() != null)
aacEl.addAttribute("code", aac.getCode());
if (aac.getLabel() != null)
aacEl.addAttribute("label", aac.getLabel());
}
for (AreaClassificationMajor acm : student.getAreaClassificationMajors()) {
Element acmEl = studentEl.addElement("acm");
if (acm.getArea() != null)
Expand All @@ -684,6 +657,26 @@ protected void saveStudent(Element studentEl, Student student) {
if (acm.getArea() != null)
acmEl.addAttribute("major", acm.getMajor());
}
for (AreaClassificationMajor acm : student.getAreaClassificationMinors()) {
Element acmEl = studentEl.addElement("acm");
if (acm.getArea() != null)
acmEl.addAttribute("area", acm.getArea());
if (acm.getArea() != null)
acmEl.addAttribute("classification", acm.getClassification());
if (acm.getArea() != null)
acmEl.addAttribute("minor", acm.getMajor());
}
for (StudentGroup g : student.getGroups()) {
Element grEl = studentEl.addElement("group");
if (g.getType() != null && !g.getType().isEmpty())
grEl.addAttribute("type", g.getType());
if (g.getReference() != null)
grEl.addAttribute("reference", g.getReference());
if (g.getName() != null)
grEl.addAttribute("name", g.getName());
}
for (String acc: student.getAccommodations())
studentEl.addElement("accommodation").addAttribute("reference", acc);
}
if (iShowNames && iSaveStudentInfo) {
for (Instructor adv: student.getAdvisors()) {
Expand Down
71 changes: 6 additions & 65 deletions src/org/cpsolver/studentsct/Test.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
import org.cpsolver.studentsct.heuristics.selection.BranchBoundSelection.BranchBoundNeighbour;
import org.cpsolver.studentsct.heuristics.studentord.StudentOrder;
import org.cpsolver.studentsct.heuristics.studentord.StudentRandomOrder;
import org.cpsolver.studentsct.model.AcademicAreaCode;
import org.cpsolver.studentsct.model.AreaClassificationMajor;
import org.cpsolver.studentsct.model.Course;
import org.cpsolver.studentsct.model.CourseRequest;
import org.cpsolver.studentsct.model.Enrollment;
Expand Down Expand Up @@ -261,8 +261,6 @@ public static Solution<Request, Enrollment> load(DataProperties cfg) {
}
if (cfg.getProperty("Test.LastLikeCourseDemands") != null)
loadLastLikeCourseDemandsXml(model, new File(cfg.getProperty("Test.LastLikeCourseDemands")));
if (cfg.getProperty("Test.StudentInfos") != null)
loadStudentInfoXml(model, new File(cfg.getProperty("Test.StudentInfos")));
if (cfg.getProperty("Test.CrsReq") != null)
loadCrsReqFiles(model, cfg.getProperty("Test.CrsReq"));
} catch (Exception e) {
Expand Down Expand Up @@ -981,14 +979,12 @@ public int compare(Student o1, Student o2) {
String clasf = line.substring(18, 20).trim();
String major = line.substring(21, 24).trim();
String minor = line.substring(24, 27).trim();
student.getAcademicAreaClasiffications().clear();
student.getMajors().clear();
student.getMinors().clear();
student.getAcademicAreaClasiffications().add(new AcademicAreaCode(area, clasf));
student.getAreaClassificationMajors().clear();
student.getAreaClassificationMinors().clear();
if (major.length() > 0)
student.getMajors().add(new AcademicAreaCode(area, major));
student.getAreaClassificationMajors().add(new AreaClassificationMajor(area, clasf, major));
if (minor.length() > 0)
student.getMinors().add(new AcademicAreaCode(area, minor));
student.getAreaClassificationMajors().add(new AreaClassificationMajor(area, clasf, minor));
}
} finally {
in.close();
Expand All @@ -997,7 +993,7 @@ public int compare(Student o1, Student o2) {
}
int without = 0;
for (Student student: students.values()) {
if (student.getAcademicAreaClasiffications().isEmpty())
if (student.getAreaClassificationMajors().isEmpty())
without++;
}
fixPriorities(model);
Expand Down Expand Up @@ -1028,61 +1024,6 @@ public int compare(Request r1, Request r2) {
}
}

/** Load student infos from a given XML file.
* @param model problem model
* @param xml an XML file
**/
public static void loadStudentInfoXml(StudentSectioningModel model, File xml) {
try {
sLog.info("Loading student infos from " + xml);
Document document = (new SAXReader()).read(xml);
Element root = document.getRootElement();
HashMap<Long, Student> studentTable = new HashMap<Long, Student>();
for (Student student : model.getStudents()) {
studentTable.put(new Long(student.getId()), student);
}
for (Iterator<?> i = root.elementIterator("student"); i.hasNext();) {
Element studentEl = (Element) i.next();
Student student = studentTable.get(Long.valueOf(studentEl.attributeValue("externalId")));
if (student == null) {
sLog.debug(" -- student " + studentEl.attributeValue("externalId") + " not found");
continue;
}
sLog.debug(" -- loading info for student " + student);
student.getAcademicAreaClasiffications().clear();
if (studentEl.element("studentAcadAreaClass") != null)
for (Iterator<?> j = studentEl.element("studentAcadAreaClass").elementIterator("acadAreaClass"); j
.hasNext();) {
Element studentAcadAreaClassElement = (Element) j.next();
student.getAcademicAreaClasiffications().add(
new AcademicAreaCode(studentAcadAreaClassElement.attributeValue("academicArea"),
studentAcadAreaClassElement.attributeValue("academicClass")));
}
sLog.debug(" -- acad areas classifs " + student.getAcademicAreaClasiffications());
student.getMajors().clear();
if (studentEl.element("studentMajors") != null)
for (Iterator<?> j = studentEl.element("studentMajors").elementIterator("major"); j.hasNext();) {
Element studentMajorElement = (Element) j.next();
student.getMajors().add(
new AcademicAreaCode(studentMajorElement.attributeValue("academicArea"),
studentMajorElement.attributeValue("code")));
}
sLog.debug(" -- majors " + student.getMajors());
student.getMinors().clear();
if (studentEl.element("studentMinors") != null)
for (Iterator<?> j = studentEl.element("studentMinors").elementIterator("minor"); j.hasNext();) {
Element studentMinorElement = (Element) j.next();
student.getMinors().add(
new AcademicAreaCode(studentMinorElement.attributeValue("academicArea", ""),
studentMinorElement.attributeValue("code", "")));
}
sLog.debug(" -- minors " + student.getMinors());
}
} catch (Exception e) {
sLog.error(e.getMessage(), e);
}
}

/** Save solution info as XML
* @param solution current solution
* @param extra solution extra info
Expand Down
10 changes: 5 additions & 5 deletions src/org/cpsolver/studentsct/filter/FreshmanStudentFilter.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.cpsolver.studentsct.filter;

import org.cpsolver.studentsct.model.AcademicAreaCode;
import org.cpsolver.studentsct.model.AreaClassificationMajor;
import org.cpsolver.studentsct.model.Student;

/**
Expand Down Expand Up @@ -37,12 +37,12 @@ public FreshmanStudentFilter() {
**/
@Override
public boolean accept(Student student) {
for (AcademicAreaCode aac : student.getAcademicAreaClasiffications()) {
if ("A".equals(aac.getCode()))
for (AreaClassificationMajor aac : student.getAreaClassificationMajors()) {
if ("A".equals(aac.getClassification()))
return true; // First Year
if ("01".equals(aac.getCode()))
if ("01".equals(aac.getClassification()))
return true; // First Semester Freshman
if ("02".equals(aac.getCode()))
if ("02".equals(aac.getClassification()))
return true; // Second Semester Freshman
}
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import java.util.List;

import org.cpsolver.ifs.util.DataProperties;
import org.cpsolver.studentsct.model.AcademicAreaCode;
import org.cpsolver.studentsct.model.AreaClassificationMajor;
import org.cpsolver.studentsct.model.Student;


Expand Down Expand Up @@ -49,24 +49,24 @@ public List<Student> order(List<Student> students) {

@Override
public int compare(Student s1, Student s2) {
int cmp = compareMajors(s1.getMajors(), s2.getMajors());
int cmp = compareMajors(s1.getAreaClassificationMajors(), s2.getAreaClassificationMajors());
if (cmp != 0)
return (iReverse ? -1 : 1) * cmp;
return (iReverse ? -1 : 1) * Double.compare(s1.getId(), s2.getId());
}

public int compareMajors(List<AcademicAreaCode> m1, List<AcademicAreaCode> m2) {
public int compareMajors(List<AreaClassificationMajor> m1, List<AreaClassificationMajor> m2) {
if (m1.isEmpty()) {
return m2.isEmpty() ? 0 : -1;
} else if (m2.isEmpty())
return 1;
return compareMajors(m1.get(0), m2.get(0));
}

public int compareMajors(AcademicAreaCode m1, AcademicAreaCode m2) {
public int compareMajors(AreaClassificationMajor m1, AreaClassificationMajor m2) {
int cmp = (m1.getArea() == null ? "" : m1.getArea()).compareTo(m2.getArea() == null ? "" : m2.getArea());
if (cmp != 0)
return cmp;
return (m1.getCode() == null ? "" : m1.getCode()).compareTo(m2.getCode() == null ? "" : m2.getCode());
return (m1.getMajor() == null ? "" : m1.getMajor()).compareTo(m2.getMajor() == null ? "" : m2.getMajor());
}
}
Loading

0 comments on commit f5fe357

Please sign in to comment.