001 package net.sf.cpsolver.studentsct.heuristics.studentord;
002
003 import java.util.Collections;
004 import java.util.Comparator;
005 import java.util.Enumeration;
006 import java.util.HashSet;
007 import java.util.Hashtable;
008 import java.util.Vector;
009
010 import net.sf.cpsolver.ifs.util.DataProperties;
011 import net.sf.cpsolver.studentsct.model.Config;
012 import net.sf.cpsolver.studentsct.model.Course;
013 import net.sf.cpsolver.studentsct.model.CourseRequest;
014 import net.sf.cpsolver.studentsct.model.Request;
015 import net.sf.cpsolver.studentsct.model.Section;
016 import net.sf.cpsolver.studentsct.model.Student;
017 import net.sf.cpsolver.studentsct.model.Subpart;
018
019 /**
020 * Return the given set of students in an order of average number
021 * of choices of each student (students with more choices first).
022 *
023 * @version
024 * StudentSct 1.1 (Student Sectioning)<br>
025 * Copyright (C) 2007 Tomáš Müller<br>
026 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
027 * Lazenska 391, 76314 Zlin, Czech Republic<br>
028 * <br>
029 * This library is free software; you can redistribute it and/or
030 * modify it under the terms of the GNU Lesser General Public
031 * License as published by the Free Software Foundation; either
032 * version 2.1 of the License, or (at your option) any later version.
033 * <br><br>
034 * This library is distributed in the hope that it will be useful,
035 * but WITHOUT ANY WARRANTY; without even the implied warranty of
036 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
037 * Lesser General Public License for more details.
038 * <br><br>
039 * You should have received a copy of the GNU Lesser General Public
040 * License along with this library; if not, write to the Free Software
041 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
042 */
043 public class StudentChoiceOrder implements StudentOrder, Comparator {
044 private boolean iReverse = false;
045 private Hashtable iCache = new Hashtable();
046
047 public StudentChoiceOrder(DataProperties config) {
048 iReverse = config.getPropertyBoolean("StudentChoiceOrder.Reverse", iReverse);
049 }
050
051 /** Is order reversed */
052 public boolean isReverse() {
053 return iReverse;
054 }
055
056 /** Set reverse order */
057 public void setReverse(boolean reverse) {
058 iReverse = reverse;
059 }
060
061 /** Order the given list of students */
062 public Vector order(Vector students) {
063 Vector ret = new Vector(students);
064 Collections.sort(ret, this);
065 return ret;
066 }
067
068 public int compare(Object o1, Object o2) {
069 Student s1 = (Student)o1;
070 Student s2 = (Student)o2;
071 try {
072 int cmp = -Double.compare(avgNrChoices(s1),avgNrChoices(s2));
073 if (cmp!=0) return (iReverse?-1:1)*cmp;
074 } catch (Exception e) {
075 e.printStackTrace();
076 }
077 return (iReverse?-1:1)*Double.compare(s1.getId(), s2.getId());
078 }
079
080 private int nrChoices(Config config, int idx, HashSet sections) {
081 if (config.getSubparts().size()==idx) {
082 return 1;
083 } else {
084 Subpart subpart = (Subpart)config.getSubparts().elementAt(idx);
085 int choicesThisSubpart = 0;
086 for (Enumeration e=subpart.getSections().elements();e.hasMoreElements();) {
087 Section section = (Section)e.nextElement();
088 if (section.getParent()!=null && !sections.contains(section.getParent())) continue;
089 if (section.isOverlapping(sections)) continue;
090 sections.add(section);
091 choicesThisSubpart += nrChoices(config, idx+1, sections);
092 sections.remove(section);
093 }
094 return choicesThisSubpart;
095 }
096 }
097
098 /** Average number of choices for each student */
099 public double avgNrChoices(Student student) {
100 int nrRequests = 0;
101 int nrChoices = 0;
102 for (Enumeration e=student.getRequests().elements();e.hasMoreElements();) {
103 Request request = (Request)e.nextElement();
104 if (request instanceof CourseRequest) {
105 CourseRequest cr = (CourseRequest)request;
106 for (Enumeration f=cr.getCourses().elements();f.hasMoreElements();) {
107 Course course = (Course)f.nextElement();
108 for (Enumeration g=course.getOffering().getConfigs().elements();g.hasMoreElements();) {
109 Config config = (Config)g.nextElement();
110 Integer nrChoicesThisCfg = (Integer)iCache.get(config);
111 if (nrChoicesThisCfg==null) {
112 nrChoicesThisCfg = new Integer(nrChoices(config, 0, new HashSet()));
113 iCache.put(config, nrChoicesThisCfg);
114 }
115 nrChoices += nrChoicesThisCfg.intValue();
116 }
117 }
118 nrRequests ++;
119 }
120 }
121 return (nrRequests==0?0.0:((double)nrChoices)/nrRequests);
122 }
123 }