Search in sources :

Example 16 with Offering

use of org.cpsolver.studentsct.model.Offering in project cpsolver by UniTime.

the class RequestGroupTable method create.

@Override
public CSVFile create(Assignment<Request, Enrollment> assignment, DataProperties properties) {
    boolean useAmPm = properties.getPropertyBoolean("useAmPm", true);
    CSVFile csv = new CSVFile();
    csv.setHeader(new CSVFile.CSVField[] { new CSVFile.CSVField("Group"), new CSVFile.CSVField("Course"), new CSVFile.CSVField("Total\nSpread"), new CSVFile.CSVField("Group\nEnrollment"), new CSVFile.CSVField("Class"), new CSVFile.CSVField("Meeting Time"), new CSVFile.CSVField("Class\nSpread"), new CSVFile.CSVField("Class\nEnrollment"), new CSVFile.CSVField("Class\nLimit") });
    TreeSet<RequestGroup> groups = new TreeSet<RequestGroup>(new Comparator<RequestGroup>() {

        @Override
        public int compare(RequestGroup g1, RequestGroup g2) {
            int cmp = g1.getName().compareTo(g2.getName());
            if (cmp != 0)
                return cmp;
            cmp = g1.getCourse().getName().compareTo(g2.getCourse().getName());
            if (cmp != 0)
                return cmp;
            if (g1.getId() < g2.getId())
                return -1;
            if (g1.getId() > g2.getId())
                return 1;
            return (g1.getCourse().getId() < g2.getCourse().getId() ? -1 : g1.getCourse().getId() > g2.getCourse().getId() ? 1 : 0);
        }
    });
    for (Offering offering : iModel.getOfferings()) for (Course course : offering.getCourses()) groups.addAll(course.getRequestGroups());
    for (RequestGroup group : groups) {
        double groupEnrollment = group.getEnrollmentWeight(assignment, null);
        double groupSpread = group.getAverageSpread(assignment);
        for (Config config : group.getCourse().getOffering().getConfigs()) for (Subpart subpart : config.getSubparts()) for (Section section : subpart.getSections()) {
            double s = group.getSectionWeight(assignment, section, null);
            if (s > 0.00001) {
                csv.addLine(new CSVFile.CSVField[] { new CSVFile.CSVField(group.getName()), new CSVFile.CSVField(group.getCourse().getName()), new CSVFile.CSVField(sDF.format(100.0 * groupSpread)), new CSVFile.CSVField(Math.round(groupEnrollment)), new CSVFile.CSVField(section.getSubpart().getName() + " " + section.getName(group.getCourse().getId())), new CSVFile.CSVField(section.getTime() == null ? "" : section.getTime().getDayHeader() + " " + section.getTime().getStartTimeHeader(useAmPm) + " - " + section.getTime().getEndTimeHeader(useAmPm)), new CSVFile.CSVField(sDF.format(100.0 * group.getSectionSpread(assignment, section))), new CSVFile.CSVField(Math.round(group.getSectionWeight(assignment, section, null))), new CSVFile.CSVField(section.getLimit()) });
            }
        }
    }
    return csv;
}
Also used : CSVFile(org.cpsolver.ifs.util.CSVFile) Config(org.cpsolver.studentsct.model.Config) Offering(org.cpsolver.studentsct.model.Offering) Section(org.cpsolver.studentsct.model.Section) RequestGroup(org.cpsolver.studentsct.model.RequestGroup) TreeSet(java.util.TreeSet) Subpart(org.cpsolver.studentsct.model.Subpart) Course(org.cpsolver.studentsct.model.Course)

Example 17 with Offering

use of org.cpsolver.studentsct.model.Offering in project cpsolver by UniTime.

the class OriginalStudentWeights method main.

/**
 * Test case -- run to see the weights for a few courses
 * @param args program arguments
 */
public static void main(String[] args) {
    OriginalStudentWeights pw = new OriginalStudentWeights(new DataProperties());
    DecimalFormat df = new DecimalFormat("0.000");
    Student s = new Student(0l);
    new CourseRequest(1l, 0, false, s, ToolBox.toList(new Course(1, "A", "1", new Offering(0, "A")), new Course(1, "A", "2", new Offering(0, "A")), new Course(1, "A", "3", new Offering(0, "A"))), false, null);
    new CourseRequest(2l, 1, false, s, ToolBox.toList(new Course(1, "B", "1", new Offering(0, "B")), new Course(1, "B", "2", new Offering(0, "B")), new Course(1, "B", "3", new Offering(0, "B"))), false, null);
    new CourseRequest(3l, 2, false, s, ToolBox.toList(new Course(1, "C", "1", new Offering(0, "C")), new Course(1, "C", "2", new Offering(0, "C")), new Course(1, "C", "3", new Offering(0, "C"))), false, null);
    new CourseRequest(4l, 3, false, s, ToolBox.toList(new Course(1, "D", "1", new Offering(0, "D")), new Course(1, "D", "2", new Offering(0, "D")), new Course(1, "D", "3", new Offering(0, "D"))), false, null);
    new CourseRequest(5l, 4, false, s, ToolBox.toList(new Course(1, "E", "1", new Offering(0, "E")), new Course(1, "E", "2", new Offering(0, "E")), new Course(1, "E", "3", new Offering(0, "E"))), false, null);
    new CourseRequest(6l, 5, true, s, ToolBox.toList(new Course(1, "F", "1", new Offering(0, "F")), new Course(1, "F", "2", new Offering(0, "F")), new Course(1, "F", "3", new Offering(0, "F"))), false, null);
    new CourseRequest(7l, 6, true, s, ToolBox.toList(new Course(1, "G", "1", new Offering(0, "G")), new Course(1, "G", "2", new Offering(0, "G")), new Course(1, "G", "3", new Offering(0, "G"))), false, null);
    Assignment<Request, Enrollment> assignment = new DefaultSingleAssignment<Request, Enrollment>();
    Placement p = new Placement(null, new TimeLocation(1, 90, 12, 0, 0, null, null, new BitSet(), 10), new ArrayList<RoomLocation>());
    for (Request r : s.getRequests()) {
        CourseRequest cr = (CourseRequest) r;
        double[] w = new double[] { 0.0, 0.0, 0.0 };
        for (int i = 0; i < cr.getCourses().size(); i++) {
            Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
            Set<SctAssignment> sections = new HashSet<SctAssignment>();
            sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
            Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
            w[i] = pw.getWeight(assignment, e, null, null);
        }
        System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
    }
    System.out.println("With one distance conflict:");
    for (Request r : s.getRequests()) {
        CourseRequest cr = (CourseRequest) r;
        double[] w = new double[] { 0.0, 0.0, 0.0 };
        for (int i = 0; i < cr.getCourses().size(); i++) {
            Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
            Set<SctAssignment> sections = new HashSet<SctAssignment>();
            sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
            Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
            Set<DistanceConflict.Conflict> dc = new HashSet<DistanceConflict.Conflict>();
            dc.add(new DistanceConflict.Conflict(s, e, (Section) sections.iterator().next(), e, (Section) sections.iterator().next()));
            w[i] = pw.getWeight(assignment, e, dc, null);
        }
        System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
    }
    System.out.println("With two distance conflicts:");
    for (Request r : s.getRequests()) {
        CourseRequest cr = (CourseRequest) r;
        double[] w = new double[] { 0.0, 0.0, 0.0 };
        for (int i = 0; i < cr.getCourses().size(); i++) {
            Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
            Set<SctAssignment> sections = new HashSet<SctAssignment>();
            sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
            Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
            Set<DistanceConflict.Conflict> dc = new HashSet<DistanceConflict.Conflict>();
            dc.add(new DistanceConflict.Conflict(s, e, (Section) sections.iterator().next(), e, (Section) sections.iterator().next()));
            dc.add(new DistanceConflict.Conflict(s, e, (Section) sections.iterator().next(), e, new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)));
            w[i] = pw.getWeight(assignment, e, dc, null);
        }
        System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
    }
    System.out.println("With 25% time overlapping conflicts:");
    for (Request r : s.getRequests()) {
        CourseRequest cr = (CourseRequest) r;
        double[] w = new double[] { 0.0, 0.0, 0.0 };
        for (int i = 0; i < cr.getCourses().size(); i++) {
            Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
            Set<SctAssignment> sections = new HashSet<SctAssignment>();
            sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
            Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
            Set<TimeOverlapsCounter.Conflict> toc = new HashSet<TimeOverlapsCounter.Conflict>();
            toc.add(new TimeOverlapsCounter.Conflict(s, 3, e, sections.iterator().next(), e, sections.iterator().next()));
            w[i] = pw.getWeight(assignment, e, null, toc);
        }
        System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
    }
}
Also used : TimeLocation(org.cpsolver.coursett.model.TimeLocation) Config(org.cpsolver.studentsct.model.Config) DecimalFormat(java.text.DecimalFormat) DistanceConflict(org.cpsolver.studentsct.extension.DistanceConflict) DataProperties(org.cpsolver.ifs.util.DataProperties) Placement(org.cpsolver.coursett.model.Placement) Enrollment(org.cpsolver.studentsct.model.Enrollment) Course(org.cpsolver.studentsct.model.Course) HashSet(java.util.HashSet) RoomLocation(org.cpsolver.coursett.model.RoomLocation) Request(org.cpsolver.studentsct.model.Request) CourseRequest(org.cpsolver.studentsct.model.CourseRequest) BitSet(java.util.BitSet) Student(org.cpsolver.studentsct.model.Student) Offering(org.cpsolver.studentsct.model.Offering) Section(org.cpsolver.studentsct.model.Section) TimeOverlapsCounter(org.cpsolver.studentsct.extension.TimeOverlapsCounter) CourseRequest(org.cpsolver.studentsct.model.CourseRequest) DistanceConflict(org.cpsolver.studentsct.extension.DistanceConflict) Subpart(org.cpsolver.studentsct.model.Subpart) DefaultSingleAssignment(org.cpsolver.ifs.assignment.DefaultSingleAssignment) SctAssignment(org.cpsolver.studentsct.model.SctAssignment)

Example 18 with Offering

use of org.cpsolver.studentsct.model.Offering in project cpsolver by UniTime.

the class UnbalancedSectionsTable method createTable.

/**
 * Create report
 *
 * @param assignment current assignment
 * @param includeLastLikeStudents
 *            true, if last-like students should be included (i.e.,
 *            {@link Student#isDummy()} is true)
 * @param includeRealStudents
 *            true, if real students should be included (i.e.,
 *            {@link Student#isDummy()} is false)
 * @param useAmPm use 12-hour format
 * @return report as comma separated text file
 */
public CSVFile createTable(Assignment<Request, Enrollment> assignment, boolean includeLastLikeStudents, boolean includeRealStudents, boolean useAmPm) {
    CSVFile csv = new CSVFile();
    csv.setHeader(new CSVFile.CSVField[] { new CSVFile.CSVField("Course"), new CSVFile.CSVField("Class"), new CSVFile.CSVField("Meeting Time"), new CSVFile.CSVField("Enrollment"), new CSVFile.CSVField("Target"), new CSVFile.CSVField("Limit"), new CSVFile.CSVField("Disbalance [%]") });
    TreeSet<Offering> offerings = new TreeSet<Offering>(new Comparator<Offering>() {

        @Override
        public int compare(Offering o1, Offering o2) {
            int cmp = o1.getName().compareToIgnoreCase(o2.getName());
            if (cmp != 0)
                return cmp;
            return o1.getId() < o2.getId() ? -1 : o2.getId() == o2.getId() ? 0 : 1;
        }
    });
    offerings.addAll(getModel().getOfferings());
    Offering last = null;
    for (Offering offering : offerings) {
        for (Config config : offering.getConfigs()) {
            double configEnrl = 0;
            for (Enrollment e : config.getEnrollments(assignment)) {
                if (e.getStudent().isDummy() && !includeLastLikeStudents)
                    continue;
                if (!e.getStudent().isDummy() && !includeRealStudents)
                    continue;
                configEnrl += e.getRequest().getWeight();
            }
            for (Subpart subpart : config.getSubparts()) {
                if (subpart.getSections().size() <= 1)
                    continue;
                if (subpart.getLimit() > 0) {
                    // sections have limits -> desired size is section limit x (total enrollment / total limit)
                    double ratio = configEnrl / subpart.getLimit();
                    for (Section section : subpart.getSections()) {
                        double enrl = 0.0;
                        for (Enrollment e : section.getEnrollments(assignment)) {
                            if (e.getStudent().isDummy() && !includeLastLikeStudents)
                                continue;
                            if (!e.getStudent().isDummy() && !includeRealStudents)
                                continue;
                            enrl += e.getRequest().getWeight();
                        }
                        double desired = ratio * section.getLimit();
                        if (Math.abs(desired - enrl) >= Math.max(1.0, 0.1 * section.getLimit())) {
                            if (last != null && !offering.equals(last))
                                csv.addLine();
                            csv.addLine(new CSVFile.CSVField[] { new CSVFile.CSVField(offering.equals(last) ? "" : offering.getName()), new CSVFile.CSVField(section.getSubpart().getName() + " " + section.getName()), new CSVFile.CSVField(section.getTime() == null ? "" : section.getTime().getDayHeader() + " " + section.getTime().getStartTimeHeader(useAmPm) + " - " + section.getTime().getEndTimeHeader(useAmPm)), new CSVFile.CSVField(sDF1.format(enrl)), new CSVFile.CSVField(sDF2.format(desired)), new CSVFile.CSVField(sDF1.format(section.getLimit())), new CSVFile.CSVField(sDF2.format(Math.min(1.0, Math.max(-1.0, (enrl - desired) / section.getLimit())))) });
                            last = offering;
                        }
                    }
                } else {
                    // unlimited sections -> desired size is total enrollment / number of sections
                    for (Section section : subpart.getSections()) {
                        double enrl = 0.0;
                        for (Enrollment e : section.getEnrollments(assignment)) {
                            if (e.getStudent().isDummy() && !includeLastLikeStudents)
                                continue;
                            if (!e.getStudent().isDummy() && !includeRealStudents)
                                continue;
                            enrl += e.getRequest().getWeight();
                        }
                        double desired = configEnrl / subpart.getSections().size();
                        if (Math.abs(desired - enrl) >= Math.max(1.0, 0.1 * desired)) {
                            if (last != null && !offering.equals(last))
                                csv.addLine();
                            csv.addLine(new CSVFile.CSVField[] { new CSVFile.CSVField(offering.equals(last) ? "" : offering.getName()), new CSVFile.CSVField(section.getSubpart().getName() + " " + section.getName()), new CSVFile.CSVField(section.getTime() == null ? "" : section.getTime().getDayHeader() + " " + section.getTime().getStartTimeHeader(useAmPm) + " - " + section.getTime().getEndTimeHeader(useAmPm)), new CSVFile.CSVField(sDF1.format(enrl)), new CSVFile.CSVField(sDF2.format(desired)), new CSVFile.CSVField(""), new CSVFile.CSVField(sDF2.format(Math.min(1.0, Math.max(-1.0, (enrl - desired) / desired)))) });
                            last = offering;
                        }
                    }
                }
            }
        }
    }
    return csv;
}
Also used : CSVFile(org.cpsolver.ifs.util.CSVFile) TreeSet(java.util.TreeSet) Config(org.cpsolver.studentsct.model.Config) Subpart(org.cpsolver.studentsct.model.Subpart) Enrollment(org.cpsolver.studentsct.model.Enrollment) Offering(org.cpsolver.studentsct.model.Offering) Section(org.cpsolver.studentsct.model.Section)

Example 19 with Offering

use of org.cpsolver.studentsct.model.Offering in project cpsolver by UniTime.

the class Test method loadCrsReqFiles.

/**
 * Load course request from the given files (in the format being used by the
 * old MSF system)
 *
 * @param model
 *            student sectioning model (with offerings loaded)
 * @param files
 *            semi-colon separated list of files to be loaded
 */
public static void loadCrsReqFiles(StudentSectioningModel model, String files) {
    try {
        boolean lastLike = model.getProperties().getPropertyBoolean("Test.CrsReqIsLastLike", true);
        boolean shuffleIds = model.getProperties().getPropertyBoolean("Test.CrsReqShuffleStudentIds", true);
        boolean tryWithoutSuffix = model.getProperties().getPropertyBoolean("Test.CrsReqTryWithoutSuffix", false);
        HashMap<Long, Student> students = new HashMap<Long, Student>();
        long reqId = 0;
        for (StringTokenizer stk = new StringTokenizer(files, ";"); stk.hasMoreTokens(); ) {
            String file = stk.nextToken();
            sLog.debug("Loading " + file + " ...");
            BufferedReader in = new BufferedReader(new FileReader(file));
            String line;
            int lineIndex = 0;
            while ((line = in.readLine()) != null) {
                lineIndex++;
                if (line.length() <= 150)
                    continue;
                char code = line.charAt(13);
                if (code == 'H' || code == 'T')
                    // skip header and tail
                    continue;
                long studentId = Long.parseLong(line.substring(14, 23));
                Student student = students.get(Long.valueOf(studentId));
                if (student == null) {
                    student = new Student(studentId);
                    if (lastLike)
                        student.setDummy(true);
                    students.put(Long.valueOf(studentId), student);
                    sLog.debug("  -- loading student " + studentId + " ...");
                } else
                    sLog.debug("  -- updating student " + studentId + " ...");
                line = line.substring(150);
                while (line.length() >= 20) {
                    String subjectArea = line.substring(0, 4).trim();
                    String courseNbr = line.substring(4, 8).trim();
                    if (subjectArea.length() == 0 || courseNbr.length() == 0) {
                        line = line.substring(20);
                        continue;
                    }
                    /*
                         * // UNUSED String instrSel = line.substring(8,10);
                         * //ZZ - Remove previous instructor selection char
                         * reqPDiv = line.charAt(10); //P - Personal preference;
                         * C - Conflict resolution; //0 - (Zero) used by program
                         * only, for change requests to reschedule division //
                         * (used to reschedule canceled division) String reqDiv
                         * = line.substring(11,13); //00 - Reschedule division
                         * String reqSect = line.substring(13,15); //Contains
                         * designator for designator-required courses String
                         * credit = line.substring(15,19); char nameRaise =
                         * line.charAt(19); //N - Name raise
                         */
                    // A - Add; D - Drop; C -
                    char action = line.charAt(19);
                    // Change
                    sLog.debug("    -- requesting " + subjectArea + " " + courseNbr + " (action:" + action + ") ...");
                    Course course = null;
                    offerings: for (Offering offering : model.getOfferings()) {
                        for (Course c : offering.getCourses()) {
                            if (c.getSubjectArea().equals(subjectArea) && c.getCourseNumber().equals(courseNbr)) {
                                course = c;
                                break offerings;
                            }
                        }
                    }
                    if (course == null && tryWithoutSuffix && courseNbr.charAt(courseNbr.length() - 1) >= 'A' && courseNbr.charAt(courseNbr.length() - 1) <= 'Z') {
                        String courseNbrNoSfx = courseNbr.substring(0, courseNbr.length() - 1);
                        offerings: for (Offering offering : model.getOfferings()) {
                            for (Course c : offering.getCourses()) {
                                if (c.getSubjectArea().equals(subjectArea) && c.getCourseNumber().equals(courseNbrNoSfx)) {
                                    course = c;
                                    break offerings;
                                }
                            }
                        }
                    }
                    if (course == null) {
                        if (courseNbr.charAt(courseNbr.length() - 1) >= 'A' && courseNbr.charAt(courseNbr.length() - 1) <= 'Z') {
                        } else {
                            sLog.warn("      -- course " + subjectArea + " " + courseNbr + " not found (file " + file + ", line " + lineIndex + ")");
                        }
                    } else {
                        CourseRequest courseRequest = null;
                        for (Request request : student.getRequests()) {
                            if (request instanceof CourseRequest && ((CourseRequest) request).getCourses().contains(course)) {
                                courseRequest = (CourseRequest) request;
                                break;
                            }
                        }
                        if (action == 'A') {
                            if (courseRequest == null) {
                                List<Course> courses = new ArrayList<Course>(1);
                                courses.add(course);
                                courseRequest = new CourseRequest(reqId++, student.getRequests().size(), false, student, courses, false, null);
                            } else {
                                sLog.warn("      -- request for course " + course + " is already present");
                            }
                        } else if (action == 'D') {
                            if (courseRequest == null) {
                                sLog.warn("      -- request for course " + course + " is not present -- cannot be dropped");
                            } else {
                                student.getRequests().remove(courseRequest);
                            }
                        } else if (action == 'C') {
                            if (courseRequest == null) {
                                sLog.warn("      -- request for course " + course + " is not present -- cannot be changed");
                            } else {
                            // ?
                            }
                        } else {
                            sLog.warn("      -- unknown action " + action);
                        }
                    }
                    line = line.substring(20);
                }
            }
            in.close();
        }
        HashMap<Course, List<Request>> requests = new HashMap<Course, List<Request>>();
        Set<Long> studentIds = new HashSet<Long>();
        for (Student student : students.values()) {
            if (!student.getRequests().isEmpty())
                model.addStudent(student);
            if (shuffleIds) {
                long newId = -1;
                while (true) {
                    newId = 1 + (long) (999999999L * Math.random());
                    if (studentIds.add(Long.valueOf(newId)))
                        break;
                }
                student.setId(newId);
            }
            if (student.isDummy()) {
                for (Request request : student.getRequests()) {
                    if (request instanceof CourseRequest) {
                        Course course = ((CourseRequest) request).getCourses().get(0);
                        List<Request> requestsThisCourse = requests.get(course);
                        if (requestsThisCourse == null) {
                            requestsThisCourse = new ArrayList<Request>();
                            requests.put(course, requestsThisCourse);
                        }
                        requestsThisCourse.add(request);
                    }
                }
            }
        }
        Collections.sort(model.getStudents(), new Comparator<Student>() {

            @Override
            public int compare(Student o1, Student o2) {
                return Double.compare(o1.getId(), o2.getId());
            }
        });
        for (Map.Entry<Course, List<Request>> entry : requests.entrySet()) {
            Course course = entry.getKey();
            List<Request> requestsThisCourse = entry.getValue();
            double weight = getLastLikeStudentWeight(course, 0, requestsThisCourse.size());
            for (Request request : requestsThisCourse) {
                request.setWeight(weight);
            }
        }
        if (model.getProperties().getProperty("Test.EtrChk") != null) {
            for (StringTokenizer stk = new StringTokenizer(model.getProperties().getProperty("Test.EtrChk"), ";"); stk.hasMoreTokens(); ) {
                String file = stk.nextToken();
                sLog.debug("Loading " + file + " ...");
                BufferedReader in = new BufferedReader(new FileReader(file));
                try {
                    String line;
                    while ((line = in.readLine()) != null) {
                        if (line.length() < 55)
                            continue;
                        char code = line.charAt(12);
                        if (code == 'H' || code == 'T')
                            // skip header and tail
                            continue;
                        if (code == 'D' || code == 'K')
                            // skip delete nad cancel
                            continue;
                        long studentId = Long.parseLong(line.substring(2, 11));
                        Student student = students.get(Long.valueOf(studentId));
                        if (student == null) {
                            sLog.info("  -- student " + studentId + " not found");
                            continue;
                        }
                        sLog.info("  -- reading student " + studentId);
                        String area = line.substring(15, 18).trim();
                        if (area.length() == 0)
                            continue;
                        String clasf = line.substring(18, 20).trim();
                        String major = line.substring(21, 24).trim();
                        String minor = line.substring(24, 27).trim();
                        student.getAreaClassificationMajors().clear();
                        student.getAreaClassificationMinors().clear();
                        if (major.length() > 0)
                            student.getAreaClassificationMajors().add(new AreaClassificationMajor(area, clasf, major));
                        if (minor.length() > 0)
                            student.getAreaClassificationMajors().add(new AreaClassificationMajor(area, clasf, minor));
                    }
                } finally {
                    in.close();
                }
            }
        }
        int without = 0;
        for (Student student : students.values()) {
            if (student.getAreaClassificationMajors().isEmpty())
                without++;
        }
        fixPriorities(model);
        sLog.info("Students without academic area: " + without);
    } catch (Exception e) {
        sLog.error(e.getMessage(), e);
    }
}
Also used : AreaClassificationMajor(org.cpsolver.studentsct.model.AreaClassificationMajor) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) FileReader(java.io.FileReader) List(java.util.List) ArrayList(java.util.ArrayList) Course(org.cpsolver.studentsct.model.Course) HashSet(java.util.HashSet) Request(org.cpsolver.studentsct.model.Request) CourseRequest(org.cpsolver.studentsct.model.CourseRequest) Student(org.cpsolver.studentsct.model.Student) Offering(org.cpsolver.studentsct.model.Offering) IOException(java.io.IOException) StringTokenizer(java.util.StringTokenizer) CourseRequest(org.cpsolver.studentsct.model.CourseRequest) BufferedReader(java.io.BufferedReader) Map(java.util.Map) HashMap(java.util.HashMap)

Example 20 with Offering

use of org.cpsolver.studentsct.model.Offering in project cpsolver by UniTime.

the class StudentSectioningModel method getExtendedInfo.

/**
 * Model extended info. Some more information (that is more expensive to
 * compute) is added to an ordinary {@link Model#getInfo(Assignment)}.
 */
@Override
public Map<String, String> getExtendedInfo(Assignment<Request, Enrollment> assignment) {
    Map<String, String> info = getInfo(assignment);
    /*
        double dc = 0;
        if (getDistanceConflict() != null && getDistanceConflict().getTotalNrConflicts(assignment) != 0) {
            Set<DistanceConflict.Conflict> conf = getDistanceConflict().getAllConflicts(assignment);
            int sdc = 0;
            for (DistanceConflict.Conflict c: conf) {
                dc += avg(c.getR1().getWeight(), c.getR2().getWeight()) * iStudentWeights.getDistanceConflictWeight(assignment, c);
                if (c.getStudent().isNeedShortDistances()) sdc ++;
            }
            if (!conf.isEmpty())
                info.put("Student distance conflicts", conf.size() + (sdc > 0 ? " (" + getDistanceConflict().getDistanceMetric().getShortDistanceAccommodationReference() + ": " + sdc + ", weighted: " : " (weighted: ") + sDecimalFormat.format(dc) + ")");
        }
        */
    if (getStudentQuality() == null && getTimeOverlaps() != null && getTimeOverlaps().getTotalNrConflicts(assignment) != 0) {
        Set<TimeOverlapsCounter.Conflict> conf = getTimeOverlaps().getContext(assignment).computeAllConflicts(assignment);
        int share = 0, crShare = 0;
        for (TimeOverlapsCounter.Conflict c : conf) {
            share += c.getShare();
            if (c.getR1() instanceof CourseRequest && c.getR2() instanceof CourseRequest)
                crShare += c.getShare();
        }
        if (share > 0)
            info.put("Time overlapping conflicts", sDoubleFormat.format(5.0 * share / iStudents.size()) + " mins per student\n(" + sDoubleFormat.format(5.0 * crShare / iStudents.size()) + " between courses; " + sDoubleFormat.format(getTimeOverlaps().getTotalNrConflicts(assignment) / 12.0) + " hours total)");
    }
    /*
        info.put("Overall solution value", sDecimalFormat.format(total - dc - toc) + (dc == 0.0 && toc == 0.0 ? "" :
            " (" + (dc != 0.0 ? "distance: " + sDecimalFormat.format(dc): "") + (dc != 0.0 && toc != 0.0 ? ", " : "") + 
            (toc != 0.0 ? "overlap: " + sDecimalFormat.format(toc) : "") + ")")
            );
        */
    double disbWeight = 0;
    int disbSections = 0;
    int disb10Sections = 0;
    int disb10Limit = getProperties().getPropertyInt("Info.ListDisbalancedSections", 0);
    Set<String> disb10SectionList = (disb10Limit == 0 ? null : new TreeSet<String>());
    for (Offering offering : getOfferings()) {
        for (Config config : offering.getConfigs()) {
            double enrl = config.getEnrollmentTotalWeight(assignment, null);
            for (Subpart subpart : config.getSubparts()) {
                if (subpart.getSections().size() <= 1)
                    continue;
                if (subpart.getLimit() > 0) {
                    // sections have limits -> desired size is section limit x (total enrollment / total limit)
                    double ratio = enrl / subpart.getLimit();
                    for (Section section : subpart.getSections()) {
                        double desired = ratio * section.getLimit();
                        disbWeight += Math.abs(section.getEnrollmentTotalWeight(assignment, null) - desired);
                        disbSections++;
                        if (Math.abs(desired - section.getEnrollmentTotalWeight(assignment, null)) >= Math.max(1.0, 0.1 * section.getLimit())) {
                            disb10Sections++;
                            if (disb10SectionList != null)
                                disb10SectionList.add(section.getSubpart().getConfig().getOffering().getName() + " " + section.getSubpart().getName() + " " + section.getName());
                        }
                    }
                } else {
                    // unlimited sections -> desired size is total enrollment / number of sections
                    for (Section section : subpart.getSections()) {
                        double desired = enrl / subpart.getSections().size();
                        disbWeight += Math.abs(section.getEnrollmentTotalWeight(assignment, null) - desired);
                        disbSections++;
                        if (Math.abs(desired - section.getEnrollmentTotalWeight(assignment, null)) >= Math.max(1.0, 0.1 * desired)) {
                            disb10Sections++;
                            if (disb10SectionList != null)
                                disb10SectionList.add(section.getSubpart().getConfig().getOffering().getName() + " " + section.getSubpart().getName() + " " + section.getName());
                        }
                    }
                }
            }
        }
    }
    if (disbSections != 0) {
        double assignedCRWeight = getContext(assignment).getAssignedCourseRequestWeight();
        info.put("Average disbalance", sDecimalFormat.format(assignedCRWeight == 0 ? 0.0 : 100.0 * disbWeight / assignedCRWeight) + "% (" + sDecimalFormat.format(disbWeight / disbSections) + ")");
        String list = "";
        if (disb10SectionList != null) {
            int i = 0;
            for (String section : disb10SectionList) {
                if (i == disb10Limit) {
                    list += "\n...";
                    break;
                }
                list += "\n" + section;
                i++;
            }
        }
        info.put("Sections disbalanced by 10% or more", sDecimalFormat.format(disbSections == 0 ? 0.0 : 100.0 * disb10Sections / disbSections) + "% (" + disb10Sections + ")" + (list.isEmpty() ? "" : "\n" + list));
    }
    int assCR = 0, priCR = 0;
    for (Request r : variables()) {
        if (r instanceof CourseRequest && !r.getStudent().isDummy()) {
            CourseRequest cr = (CourseRequest) r;
            Enrollment e = assignment.getValue(cr);
            if (e != null) {
                assCR++;
                if (!cr.isAlternative() && cr.getCourses().get(0).equals(e.getCourse()))
                    priCR++;
            }
        }
    }
    if (assCR > 0)
        info.put("Assigned priority course requests", sDoubleFormat.format(100.0 * priCR / assCR) + "% (" + priCR + "/" + assCR + ")");
    int[] missing = new int[] { 0, 0, 0, 0, 0 };
    int incomplete = 0;
    for (Student student : getStudents()) {
        if (student.isDummy())
            continue;
        int nrRequests = 0;
        int nrAssignedRequests = 0;
        for (Request r : student.getRequests()) {
            // ignore free times
            if (!(r instanceof CourseRequest))
                continue;
            if (!r.isAlternative())
                nrRequests++;
            if (r.isAssigned(assignment))
                nrAssignedRequests++;
        }
        if (nrAssignedRequests < nrRequests) {
            missing[Math.min(nrRequests - nrAssignedRequests, missing.length) - 1]++;
            incomplete++;
        }
    }
    for (int i = 0; i < missing.length; i++) if (missing[i] > 0)
        info.put("Students missing " + (i == 0 ? "1 course" : i + 1 == missing.length ? (i + 1) + " or more courses" : (i + 1) + " courses"), sDecimalFormat.format(100.0 * missing[i] / incomplete) + "% (" + missing[i] + ")");
    // + " [precise: " + sDoubleFormat.format(getTotalValue(assignment, true)) + "]");
    info.put("Overall solution value", sDoubleFormat.format(getTotalValue(assignment)));
    int nrStudentsBelowMinCredit = 0, nrStudents = 0;
    for (Student student : getStudents()) {
        if (student.isDummy())
            continue;
        if (student.hasMinCredit()) {
            nrStudents++;
            float credit = student.getAssignedCredit(assignment);
            if (credit < student.getMinCredit() && !student.isComplete(assignment))
                nrStudentsBelowMinCredit++;
        }
    }
    if (nrStudentsBelowMinCredit > 0)
        info.put("Students below min credit", sDoubleFormat.format(100.0 * nrStudentsBelowMinCredit / nrStudents) + "% (" + nrStudentsBelowMinCredit + "/" + nrStudents + ")");
    int[] notAssignedPriority = new int[] { 0, 0, 0, 0, 0, 0, 0 };
    int[] assignedChoice = new int[] { 0, 0, 0, 0, 0 };
    int notAssignedTotal = 0, assignedChoiceTotal = 0;
    int avgPriority = 0, avgChoice = 0;
    for (Student student : getStudents()) {
        if (student.isDummy())
            continue;
        for (Request r : student.getRequests()) {
            // ignore free times
            if (!(r instanceof CourseRequest))
                continue;
            Enrollment e = r.getAssignment(assignment);
            if (e == null) {
                if (!r.isAlternative()) {
                    notAssignedPriority[Math.min(r.getPriority(), notAssignedPriority.length - 1)]++;
                    notAssignedTotal++;
                    avgPriority += r.getPriority();
                }
            } else {
                assignedChoice[Math.min(e.getTruePriority(), assignedChoice.length - 1)]++;
                assignedChoiceTotal++;
                avgChoice += e.getTruePriority();
            }
        }
    }
    for (int i = 0; i < notAssignedPriority.length; i++) if (notAssignedPriority[i] > 0)
        info.put("Priority: Not-assigned priority " + (i + 1 == notAssignedPriority.length ? (i + 1) + "+" : (i + 1)) + " course requests", sDecimalFormat.format(100.0 * notAssignedPriority[i] / notAssignedTotal) + "% (" + notAssignedPriority[i] + ")");
    if (notAssignedTotal > 0)
        info.put("Priority: Average not-assigned priority", sDecimalFormat.format(1.0 + ((double) avgPriority) / notAssignedTotal));
    for (int i = 0; i < assignedChoice.length; i++) if (assignedChoice[i] > 0)
        info.put("Choice: assigned " + (i == 0 ? "1st" : i == 1 ? "2nd" : i == 2 ? "3rd" : i + 1 == assignedChoice.length ? (i + 1) + "th+" : (i + 1) + "th") + " course choice", sDecimalFormat.format(100.0 * assignedChoice[i] / assignedChoiceTotal) + "% (" + assignedChoice[i] + ")");
    if (assignedChoiceTotal > 0)
        info.put("Choice: Average assigned choice", sDecimalFormat.format(1.0 + ((double) avgChoice) / assignedChoiceTotal));
    int nbrSections = 0, nbrFullSections = 0, nbrSections98 = 0, nbrSections95 = 0, nbrSections90 = 0, nbrSectionsDis = 0;
    int enrlSections = 0, enrlFullSections = 0, enrlSections98 = 0, enrlSections95 = 0, enrlSections90 = 0, enrlSectionsDis = 0;
    int nbrOfferings = 0, nbrFullOfferings = 0, nbrOfferings98 = 0, nbrOfferings95 = 0, nbrOfferings90 = 0;
    int enrlOfferings = 0, enrlOfferingsFull = 0, enrlOfferings98 = 0, enrlOfferings95 = 0, enrlOfferings90 = 0;
    for (Offering offering : getOfferings()) {
        int offeringLimit = 0, offeringEnrollment = 0;
        for (Config config : offering.getConfigs()) {
            int configLimit = config.getLimit();
            for (Subpart subpart : config.getSubparts()) {
                int subpartLimit = 0;
                for (Section section : subpart.getSections()) {
                    if (section.isCancelled())
                        continue;
                    int enrl = section.getEnrollments(assignment).size();
                    if (section.getLimit() < 0 || subpartLimit < 0)
                        subpartLimit = -1;
                    else
                        subpartLimit += (section.isEnabled() ? section.getLimit() : enrl);
                    nbrSections++;
                    enrlSections += enrl;
                    if (section.getLimit() >= 0 && section.getLimit() <= enrl) {
                        nbrFullSections++;
                        enrlFullSections += enrl;
                    }
                    if (!section.isEnabled() && (enrl > 0 || section.getLimit() >= 0)) {
                        nbrSectionsDis++;
                        enrlSectionsDis += enrl;
                    }
                    if (section.getLimit() >= 0 && (section.getLimit() - enrl) <= Math.round(0.02 * section.getLimit())) {
                        nbrSections98++;
                        enrlSections98 += enrl;
                    }
                    if (section.getLimit() >= 0 && (section.getLimit() - enrl) <= Math.round(0.05 * section.getLimit())) {
                        nbrSections95++;
                        enrlSections95 += enrl;
                    }
                    if (section.getLimit() >= 0 && (section.getLimit() - enrl) <= Math.round(0.10 * section.getLimit())) {
                        nbrSections90++;
                        enrlSections90 += enrl;
                    }
                }
                if (configLimit < 0 || subpartLimit < 0)
                    configLimit = -1;
                else
                    configLimit = Math.min(configLimit, subpartLimit);
            }
            if (offeringLimit < 0 || configLimit < 0)
                offeringLimit = -1;
            else
                offeringLimit += configLimit;
            offeringEnrollment += config.getEnrollments(assignment).size();
        }
        nbrOfferings++;
        enrlOfferings += offeringEnrollment;
        if (offeringLimit >= 0 && offeringEnrollment >= offeringLimit) {
            nbrFullOfferings++;
            enrlOfferingsFull += offeringEnrollment;
        }
        if (offeringLimit >= 0 && (offeringLimit - offeringEnrollment) <= Math.round(0.02 * offeringLimit)) {
            nbrOfferings98++;
            enrlOfferings98 += offeringEnrollment;
        }
        if (offeringLimit >= 0 && (offeringLimit - offeringEnrollment) <= Math.round(0.05 * offeringLimit)) {
            nbrOfferings95++;
            enrlOfferings95 += offeringEnrollment;
        }
        if (offeringLimit >= 0 && (offeringLimit - offeringEnrollment) <= Math.round(0.10 * offeringLimit)) {
            nbrOfferings90++;
            enrlOfferings90 += offeringEnrollment;
        }
    }
    if (enrlOfferings90 > 0 && enrlOfferings > 0)
        info.put("Full Offerings", (nbrFullOfferings > 0 ? nbrFullOfferings + " with no space (" + sDecimalFormat.format(100.0 * nbrFullOfferings / nbrOfferings) + "% of all offerings, " + sDecimalFormat.format(100.0 * enrlOfferingsFull / enrlOfferings) + "% assignments)\n" : "") + (nbrOfferings98 > nbrFullOfferings ? nbrOfferings98 + " with &leq; 2% available (" + sDecimalFormat.format(100.0 * nbrOfferings98 / nbrOfferings) + "% of all offerings, " + sDecimalFormat.format(100.0 * enrlOfferings98 / enrlOfferings) + "% assignments)\n" : "") + (nbrOfferings95 > nbrOfferings98 ? nbrOfferings95 + " with &leq; 5% available (" + sDecimalFormat.format(100.0 * nbrOfferings95 / nbrOfferings) + "% of all offerings, " + sDecimalFormat.format(100.0 * enrlOfferings95 / enrlOfferings) + "% assignments)\n" : "") + (nbrOfferings90 > nbrOfferings95 ? nbrOfferings90 + " with &leq; 10% available (" + sDecimalFormat.format(100.0 * nbrOfferings90 / nbrOfferings) + "% of all offerings, " + sDecimalFormat.format(100.0 * enrlOfferings90 / enrlOfferings) + "% assignments)" : ""));
    if ((enrlSections90 > 0 || nbrSectionsDis > 0) && enrlSections > 0)
        info.put("Full Sections", (nbrFullSections > 0 ? nbrFullSections + " with no space (" + sDecimalFormat.format(100.0 * nbrFullSections / nbrSections) + "% of all sections, " + sDecimalFormat.format(100.0 * enrlFullSections / enrlSections) + "% assignments)\n" : "") + (nbrSectionsDis > 0 ? nbrSectionsDis + " disabled (" + sDecimalFormat.format(100.0 * nbrSectionsDis / nbrSections) + "% of all sections, " + sDecimalFormat.format(100.0 * enrlSectionsDis / enrlSections) + "% assignments)\n" : "") + (enrlSections98 > nbrFullSections ? nbrSections98 + " with &leq; 2% available (" + sDecimalFormat.format(100.0 * nbrSections98 / nbrSections) + "% of all sections, " + sDecimalFormat.format(100.0 * enrlSections98 / enrlSections) + "% assignments)\n" : "") + (nbrSections95 > enrlSections98 ? nbrSections95 + " with &leq; 5% available (" + sDecimalFormat.format(100.0 * nbrSections95 / nbrSections) + "% of all sections, " + sDecimalFormat.format(100.0 * enrlSections95 / enrlSections) + "% assignments)\n" : "") + (nbrSections90 > nbrSections95 ? nbrSections90 + " with &leq; 10% available (" + sDecimalFormat.format(100.0 * nbrSections90 / nbrSections) + "% of all sections, " + sDecimalFormat.format(100.0 * enrlSections90 / enrlSections) + "% assignments)" : ""));
    if (getStudentQuality() != null) {
        int shareCR = getStudentQuality().getContext(assignment).countTotalPenalty(StudentQuality.Type.CourseTimeOverlap, assignment);
        int shareFT = getStudentQuality().getContext(assignment).countTotalPenalty(StudentQuality.Type.FreeTimeOverlap, assignment);
        int shareUN = getStudentQuality().getContext(assignment).countTotalPenalty(StudentQuality.Type.Unavailability, assignment);
        if (shareCR > 0) {
            Set<Student> students = new HashSet<Student>();
            for (StudentQuality.Conflict c : getStudentQuality().getContext(assignment).computeAllConflicts(StudentQuality.Type.CourseTimeOverlap, assignment)) {
                students.add(c.getStudent());
            }
            info.put("Time overlaps: courses", students.size() + " students (avg " + sDoubleFormat.format(5.0 * shareCR / students.size()) + " mins)");
        }
        if (shareFT > 0) {
            Set<Student> students = new HashSet<Student>();
            for (StudentQuality.Conflict c : getStudentQuality().getContext(assignment).computeAllConflicts(StudentQuality.Type.FreeTimeOverlap, assignment)) {
                students.add(c.getStudent());
            }
            info.put("Time overlaps: free times", students.size() + " students (avg " + sDoubleFormat.format(5.0 * shareFT / students.size()) + " mins)");
        }
        if (shareUN > 0) {
            Set<Student> students = new HashSet<Student>();
            for (StudentQuality.Conflict c : getStudentQuality().getContext(assignment).computeAllConflicts(StudentQuality.Type.Unavailability, assignment)) {
                students.add(c.getStudent());
            }
            info.put("Time overlaps: teaching assignments", students.size() + " students (avg " + sDoubleFormat.format(5.0 * shareUN / students.size()) + " mins)");
        }
    } else if (getTimeOverlaps() != null && getTimeOverlaps().getTotalNrConflicts(assignment) != 0) {
        Set<TimeOverlapsCounter.Conflict> conf = getTimeOverlaps().getContext(assignment).computeAllConflicts(assignment);
        int shareCR = 0, shareFT = 0, shareUN = 0;
        Set<Student> studentsCR = new HashSet<Student>();
        Set<Student> studentsFT = new HashSet<Student>();
        Set<Student> studentsUN = new HashSet<Student>();
        for (TimeOverlapsCounter.Conflict c : conf) {
            if (c.getR1() instanceof CourseRequest && c.getR2() instanceof CourseRequest) {
                shareCR += c.getShare();
                studentsCR.add(c.getStudent());
            } else if (c.getS2() instanceof Unavailability) {
                shareUN += c.getShare();
                studentsUN.add(c.getStudent());
            } else {
                shareFT += c.getShare();
                studentsFT.add(c.getStudent());
            }
        }
        if (shareCR > 0)
            info.put("Time overlaps: courses", studentsCR.size() + " students (avg " + sDoubleFormat.format(5.0 * shareCR / studentsCR.size()) + " mins)");
        if (shareFT > 0)
            info.put("Time overlaps: free times", studentsFT.size() + " students (avg " + sDoubleFormat.format(5.0 * shareFT / studentsFT.size()) + " mins)");
        if (shareUN > 0)
            info.put("Time overlaps: teaching assignments", studentsUN.size() + " students (avg " + sDoubleFormat.format(5.0 * shareUN / studentsUN.size()) + " mins)");
    }
    return info;
}
Also used : Set(java.util.Set) TreeSet(java.util.TreeSet) HashSet(java.util.HashSet) Config(org.cpsolver.studentsct.model.Config) Unavailability(org.cpsolver.studentsct.model.Unavailability) TreeSet(java.util.TreeSet) Enrollment(org.cpsolver.studentsct.model.Enrollment) HashSet(java.util.HashSet) StudentQuality(org.cpsolver.studentsct.extension.StudentQuality) Request(org.cpsolver.studentsct.model.Request) CourseRequest(org.cpsolver.studentsct.model.CourseRequest) Student(org.cpsolver.studentsct.model.Student) Offering(org.cpsolver.studentsct.model.Offering) Section(org.cpsolver.studentsct.model.Section) Constraint(org.cpsolver.ifs.model.Constraint) TimeOverlapsCounter(org.cpsolver.studentsct.extension.TimeOverlapsCounter) CourseRequest(org.cpsolver.studentsct.model.CourseRequest) DistanceConflict(org.cpsolver.studentsct.extension.DistanceConflict) StudentConflict(org.cpsolver.studentsct.constraint.StudentConflict) Subpart(org.cpsolver.studentsct.model.Subpart)

Aggregations

Offering (org.cpsolver.studentsct.model.Offering)25 Section (org.cpsolver.studentsct.model.Section)18 Subpart (org.cpsolver.studentsct.model.Subpart)16 Course (org.cpsolver.studentsct.model.Course)15 Config (org.cpsolver.studentsct.model.Config)13 HashSet (java.util.HashSet)10 CourseRequest (org.cpsolver.studentsct.model.CourseRequest)10 Enrollment (org.cpsolver.studentsct.model.Enrollment)10 Request (org.cpsolver.studentsct.model.Request)10 HashMap (java.util.HashMap)8 Student (org.cpsolver.studentsct.model.Student)8 Element (org.dom4j.Element)8 ArrayList (java.util.ArrayList)7 TreeSet (java.util.TreeSet)6 DistanceConflict (org.cpsolver.studentsct.extension.DistanceConflict)5 TimeOverlapsCounter (org.cpsolver.studentsct.extension.TimeOverlapsCounter)5 DecimalFormat (java.text.DecimalFormat)4 Map (java.util.Map)4 Set (java.util.Set)4 Placement (org.cpsolver.coursett.model.Placement)4