001 package net.sf.cpsolver.exam.reports; 002 003 import java.text.DecimalFormat; 004 import java.util.List; 005 006 import net.sf.cpsolver.exam.model.Exam; 007 import net.sf.cpsolver.exam.model.ExamModel; 008 import net.sf.cpsolver.exam.model.ExamPlacement; 009 import net.sf.cpsolver.exam.model.ExamStudent; 010 import net.sf.cpsolver.ifs.util.CSVFile; 011 import net.sf.cpsolver.ifs.util.CSVFile.CSVField; 012 013 /** 014 * Export student back-to-back conflicts between pairs of exams into a CSV file. <br> 015 * <br> 016 * Usage:<br> 017 * <code> 018 * new ExamStudentBackToBackConflicts(model).report().save(file); 019 * </code> <br> 020 * <br> 021 * 022 * @version ExamTT 1.2 (Examination Timetabling)<br> 023 * Copyright (C) 2008 - 2010 Tomas Muller<br> 024 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 025 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 026 * <br> 027 * This library is free software; you can redistribute it and/or modify 028 * it under the terms of the GNU Lesser General Public License as 029 * published by the Free Software Foundation; either version 3 of the 030 * License, or (at your option) any later version. <br> 031 * <br> 032 * This library is distributed in the hope that it will be useful, but 033 * WITHOUT ANY WARRANTY; without even the implied warranty of 034 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 035 * Lesser General Public License for more details. <br> 036 * <br> 037 * You should have received a copy of the GNU Lesser General Public 038 * License along with this library; if not see 039 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 040 */ 041 public class ExamStudentBackToBackConflicts { 042 private ExamModel iModel = null; 043 044 /** 045 * Constructor 046 * 047 * @param model 048 * examination timetabling model 049 */ 050 public ExamStudentBackToBackConflicts(ExamModel model) { 051 iModel = model; 052 } 053 054 /** 055 * generate report 056 */ 057 public CSVFile report() { 058 CSVFile csv = new CSVFile(); 059 csv.setHeader(new CSVField[] { new CSVField("Exam 1"), new CSVField("Enrl 1"), new CSVField("Period 1"), 060 new CSVField("Date 1"), new CSVField("Time 1"), new CSVField("Exam 2"), new CSVField("Enrl 2"), 061 new CSVField("Back-To-Back"), new CSVField("Back-To-Back [%]"), new CSVField("Distance") }); 062 DecimalFormat df = new DecimalFormat("0.0"); 063 for (Exam ex1 : iModel.variables()) { 064 ExamPlacement p1 = ex1.getAssignment(); 065 if (p1 == null || p1.getPeriod().next() == null) 066 continue; 067 if (!iModel.isDayBreakBackToBack() && p1.getPeriod().getDay() != p1.getPeriod().next().getDay()) 068 continue; 069 for (Exam ex2 : iModel.variables()) { 070 ExamPlacement p2 = ex2.getAssignment(); 071 if (p2 == null || !p2.getPeriod().equals(p1.getPeriod().next())) 072 continue; 073 List<ExamStudent> students = ex1.getJointEnrollments().get(ex2); 074 if (students == null || students.isEmpty()) 075 continue; 076 String distStr = ""; 077 if (iModel.getBackToBackDistance() >= 0) { 078 double dist = p1.getDistanceInMeters(p2); 079 if (dist > 0) 080 distStr = String.valueOf(dist); 081 } 082 csv 083 .addLine(new CSVField[] { 084 new CSVField(ex1.getName()), 085 new CSVField(ex1.getStudents().size()), 086 new CSVField(p1.getPeriod().getIndex() + 1), 087 new CSVField(p1.getPeriod().getDayStr()), 088 new CSVField(p1.getPeriod().getTimeStr()), 089 new CSVField(ex2.getName()), 090 new CSVField(ex2.getStudents().size()), 091 new CSVField(students.size()), 092 new CSVField(df.format(100.0 * students.size() 093 / Math.min(ex1.getStudents().size(), ex2.getStudents().size()))), 094 new CSVField(distStr) }); 095 } 096 } 097 return csv; 098 } 099 }