001package org.cpsolver.studentsct.report; 002 003import java.text.DecimalFormat; 004import java.util.Comparator; 005import java.util.TreeSet; 006 007import org.cpsolver.ifs.assignment.Assignment; 008import org.cpsolver.ifs.util.CSVFile; 009import org.cpsolver.ifs.util.DataProperties; 010import org.cpsolver.studentsct.StudentSectioningModel; 011import org.cpsolver.studentsct.model.Config; 012import org.cpsolver.studentsct.model.Course; 013import org.cpsolver.studentsct.model.CourseRequest; 014import org.cpsolver.studentsct.model.Enrollment; 015import org.cpsolver.studentsct.model.Offering; 016import org.cpsolver.studentsct.model.Request; 017import org.cpsolver.studentsct.model.RequestGroup; 018import org.cpsolver.studentsct.model.Section; 019import org.cpsolver.studentsct.model.Subpart; 020 021/** 022 * This reports lists all request groups (including course name and group name) and the current spreads. 023 * For each group, the current average spread (see {@link RequestGroup#getAverageSpread(Assignment)}) 024 * is listed together with all the classes that the students of the group are enrolled into and their 025 * spreads (see {@link RequestGroup#getSectionSpread(Assignment, Section)}).<br> 026 * <br> 027 * The average spread corresponds with the probability of two students of the group to attend the same section. 028 * The section spread is a break down of the average spread by each section.<br> 029 * <br> 030 * 031 * 032 * @author Tomáš Müller 033 * @version StudentSct 1.3 (Student Sectioning)<br> 034 * Copyright (C) 2015 Tomáš Müller<br> 035 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 036 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 037 * <br> 038 * This library is free software; you can redistribute it and/or modify 039 * it under the terms of the GNU Lesser General Public License as 040 * published by the Free Software Foundation; either version 3 of the 041 * License, or (at your option) any later version. <br> 042 * <br> 043 * This library is distributed in the hope that it will be useful, but 044 * WITHOUT ANY WARRANTY; without even the implied warranty of 045 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 046 * Lesser General Public License for more details. <br> 047 * <br> 048 * You should have received a copy of the GNU Lesser General Public 049 * License along with this library; if not see 050 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 051 */ 052public class RequestGroupTable extends AbstractStudentSectioningReport { 053 private static DecimalFormat sDF = new DecimalFormat("0.000"); 054 055 /** 056 * Constructor 057 * 058 * @param model student sectioning model 059 */ 060 public RequestGroupTable(StudentSectioningModel model) { 061 super(model); 062 } 063 064 @Override 065 public CSVFile createTable(Assignment<Request, Enrollment> assignment, DataProperties properties) { 066 CSVFile csv = new CSVFile(); 067 csv.setHeader(new CSVFile.CSVField[] { 068 new CSVFile.CSVField("Group"), 069 new CSVFile.CSVField("Course"), 070 new CSVFile.CSVField("Total\nSpread"), 071 new CSVFile.CSVField("Group\nEnrollment"), 072 new CSVFile.CSVField("Class"), 073 new CSVFile.CSVField("Meeting Time"), 074 new CSVFile.CSVField("Class\nSpread"), 075 new CSVFile.CSVField("Class\nEnrollment"), 076 new CSVFile.CSVField("Class\nLimit") 077 }); 078 079 TreeSet<RequestGroup> groups = new TreeSet<RequestGroup>(new Comparator<RequestGroup>() { 080 @Override 081 public int compare(RequestGroup g1, RequestGroup g2) { 082 int cmp = g1.getName().compareTo(g2.getName()); 083 if (cmp != 0) return cmp; 084 cmp = g1.getCourse().getName().compareTo(g2.getCourse().getName()); 085 if (cmp != 0) return cmp; 086 if (g1.getId() < g2.getId()) return -1; 087 if (g1.getId() > g2.getId()) return 1; 088 return (g1.getCourse().getId() < g2.getCourse().getId() ? -1 : g1.getCourse().getId() > g2.getCourse().getId() ? 1 : 0); 089 } 090 }); 091 092 for (Offering offering: getModel().getOfferings()) { 093 if (offering.isDummy()) continue; 094 for (Course course: offering.getCourses()) 095 groups.addAll(course.getRequestGroups()); 096 } 097 098 for (RequestGroup group: groups) { 099 int nbrMatches = 0; 100 for (CourseRequest cr: group.getRequests()) { 101 if (matches(cr)) nbrMatches ++; 102 } 103 if (nbrMatches == 0) continue; 104 double groupEnrollment = group.getEnrollmentWeight(assignment, null); 105 double groupSpread = group.getAverageSpread(assignment); 106 for (Config config: group.getCourse().getOffering().getConfigs()) 107 for (Subpart subpart: config.getSubparts()) 108 for (Section section: subpart.getSections()) { 109 double s = group.getSectionWeight(assignment, section, null); 110 if (s > 0.00001) { 111 csv.addLine(new CSVFile.CSVField[] { 112 new CSVFile.CSVField(group.getName()), 113 new CSVFile.CSVField(group.getCourse().getName()), 114 new CSVFile.CSVField(sDF.format(100.0 * groupSpread)), 115 new CSVFile.CSVField(Math.round(groupEnrollment)), 116 new CSVFile.CSVField(section.getSubpart().getName() + " " + section.getName(group.getCourse().getId())), 117 new CSVFile.CSVField(section.getTime() == null ? "" : section.getTime().getDayHeader() + " " + section.getTime().getStartTimeHeader(isUseAmPm()) + " - " + section.getTime().getEndTimeHeader(isUseAmPm())), 118 new CSVFile.CSVField(sDF.format(100.0 * group.getSectionSpread(assignment, section))), 119 new CSVFile.CSVField(Math.round(group.getSectionWeight(assignment, section, null))), 120 new CSVFile.CSVField(section.getLimit()) 121 }); 122 } 123 } 124 } 125 126 return csv; 127 } 128 129}