001    package net.sf.cpsolver.coursett.model;
002    
003    import java.util.Collection;
004    import java.util.Enumeration;
005    import java.util.HashSet;
006    import java.util.Hashtable;
007    import java.util.Iterator;
008    import java.util.Set;
009    
010    import net.sf.cpsolver.coursett.constraint.JenrlConstraint;
011    
012    /**
013     * Student.
014     * 
015     * @version
016     * CourseTT 1.1 (University Course Timetabling)<br>
017     * Copyright (C) 2006 Tomáš Müller<br>
018     * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
019     * Lazenska 391, 76314 Zlin, Czech Republic<br>
020     * <br>
021     * This library is free software; you can redistribute it and/or
022     * modify it under the terms of the GNU Lesser General Public
023     * License as published by the Free Software Foundation; either
024     * version 2.1 of the License, or (at your option) any later version.
025     * <br><br>
026     * This library is distributed in the hope that it will be useful,
027     * but WITHOUT ANY WARRANTY; without even the implied warranty of
028     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
029     * Lesser General Public License for more details.
030     * <br><br>
031     * You should have received a copy of the GNU Lesser General Public
032     * License along with this library; if not, write to the Free Software
033     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
034     */
035    public class Student implements Comparable {
036        private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger.getLogger(Student.class);
037            public static boolean USE_DISTANCE_CACHE = false;
038        Long iStudentId = null;
039        Hashtable iOfferings = new Hashtable();
040        Set iLectures = new HashSet();
041        Set iConfigurations = new HashSet();
042        Hashtable iCanNotEnrollSections = null;
043        Hashtable iDistanceCache = null;
044        HashSet iCommitedPlacements = null;
045        
046        public Student(Long studentId) {
047            iStudentId = studentId;
048        }
049        
050        public void addOffering(Long offeringId, double weight) {
051            iOfferings.put(offeringId, new Double(weight));
052        }
053        public Hashtable getOfferingsMap() {
054            return iOfferings;
055        }
056        public Set getOfferings() {
057            return iOfferings.keySet();
058        }
059        public boolean hasOffering(Long offeringId) {
060            return iOfferings.containsKey(offeringId);
061        }
062        public double getOfferingWeight(Configuration configuration) {
063            if (configuration==null) return 1.0;
064            return getOfferingWeight(configuration.getOfferingId());
065        }
066        
067        public double getOfferingWeight(Long offeringId) {
068            Double weight = (Double)iOfferings.get(offeringId);
069            return (weight==null?0.0:weight.doubleValue());
070        }
071        
072        public boolean canEnroll(Lecture lecture) {
073            if (iCanNotEnrollSections!=null) {
074                    HashSet canNotEnrollLectures = (HashSet)iCanNotEnrollSections.get(lecture.getConfiguration().getOfferingId());
075                    return canEnroll(canNotEnrollLectures, lecture, true);
076            }
077            return true;
078        }
079        
080        private boolean canEnroll(HashSet canNotEnrollLectures, Lecture lecture, boolean checkParents) {
081            if (canNotEnrollLectures==null) return true;
082            if (canNotEnrollLectures.contains(lecture)) return false;
083            if (checkParents) {
084                    Lecture parent = lecture.getParent();
085                    while (parent!=null) {
086                            if (canNotEnrollLectures.contains(parent)) return false;
087                            parent = parent.getParent();
088                    }
089            }
090            if (lecture.hasAnyChildren()) {
091                    for (Enumeration e=lecture.getChildrenSubpartIds();e.hasMoreElements();) {
092                            Long subpartId = (Long)e.nextElement();
093                            boolean canEnrollChild = false;
094                            for (Enumeration f=lecture.getChildren(subpartId).elements();f.hasMoreElements();) {
095                                    Lecture childLecture = (Lecture)f.nextElement();
096                                    if (canEnroll(canNotEnrollLectures, childLecture, false)) {
097                                            canEnrollChild = true; break;
098                                    }
099                            }
100                            if (!canEnrollChild) return false;
101                    }
102            }
103            return true;
104        }
105        
106        public void addCanNotEnroll(Lecture lecture) {
107            if (iCanNotEnrollSections==null)
108                    iCanNotEnrollSections = new Hashtable();
109            if (lecture.getConfiguration()==null) {
110                sLogger.warn("Student.addCanNotEnroll("+lecture+") -- given lecture has no configuration associated with.");
111                return;
112            }
113            HashSet canNotEnrollLectures = (HashSet)iCanNotEnrollSections.get(lecture.getConfiguration().getOfferingId());
114            if (canNotEnrollLectures==null) {
115                    canNotEnrollLectures = new HashSet();
116                    iCanNotEnrollSections.put(lecture.getConfiguration().getOfferingId(),canNotEnrollLectures); 
117            }
118            canNotEnrollLectures.add(lecture);
119        }
120        
121        public void addCanNotEnroll(Long offeringId, Collection lectures) {
122            if (lectures==null || lectures.isEmpty()) return;
123            if (iCanNotEnrollSections==null)
124                    iCanNotEnrollSections = new Hashtable();
125            HashSet canNotEnrollLectures = (HashSet)iCanNotEnrollSections.get(offeringId);
126            if (canNotEnrollLectures==null) {
127                    canNotEnrollLectures = new HashSet();
128                    iCanNotEnrollSections.put(offeringId,canNotEnrollLectures); 
129            }
130            canNotEnrollLectures.addAll(lectures);
131        }
132    
133        public Hashtable canNotEnrollSections() {
134            return iCanNotEnrollSections;
135        }
136    
137        public void addLecture(Lecture lecture) { iLectures.add(lecture); }
138        public void removeLecture(Lecture lecture) { iLectures.remove(lecture); }
139        public Set getLectures() { return iLectures; }
140        
141        public void addConfiguration(Configuration config) { iConfigurations.add(config); }
142        public void removeConfiguration(Configuration config) { iConfigurations.remove(config); }
143        public Set getConfigurations() { return iConfigurations; }
144    
145        public Long getId() { return iStudentId; }
146        
147        public double getDistance(Student student) {
148            Double dist = (USE_DISTANCE_CACHE && iDistanceCache!=null?(Double)iDistanceCache.get(student):null);
149            if (dist==null) {
150                int same = 0;
151                for (Iterator i=getOfferings().iterator();i.hasNext();) {
152                    if (student.getOfferings().contains(i.next())) same++;
153                }
154                double all = student.getOfferings().size() + getOfferings().size();
155                double dif = all - 2.0*same;
156                dist = new Double(dif/all);
157                if (USE_DISTANCE_CACHE) {
158                    if (iDistanceCache == null) iDistanceCache = new Hashtable();
159                    iDistanceCache.put(student,dist);
160                }
161            }
162            return dist.doubleValue();
163        }
164        
165        public void clearDistanceCache() {
166            if (USE_DISTANCE_CACHE && iDistanceCache!=null) iDistanceCache.clear();
167        }
168        
169        public String toString() { return String.valueOf(getId()); }//+"/"+getOfferings(); }
170        public int hashCode() { return getId().hashCode(); }
171        public int compareTo(Object o) {
172            return getId().compareTo(((Student)o).getId());
173        }
174        public boolean equals(Object o) {
175            if (o==null || !(o instanceof Student)) return false;
176            return getId().equals(((Student)o).getId());
177        }
178        
179        public void addCommitedPlacement(Placement placement) {
180            if (iCommitedPlacements==null)
181                    iCommitedPlacements = new HashSet();
182            iCommitedPlacements.add(placement);
183        }
184        
185        public Set getCommitedPlacements() { return iCommitedPlacements; }
186        
187        public Set conflictPlacements(Placement placement) {
188            if (iCommitedPlacements==null) return null;
189            Set ret = new HashSet();
190            Lecture lecture = (Lecture)placement.variable();
191            for (Iterator i=iCommitedPlacements.iterator();i.hasNext();) {
192                    Placement commitedPlacement = (Placement)i.next();
193                    Lecture commitedLecture = (Lecture)commitedPlacement.variable();
194                    if (lecture.getSchedulingSubpartId()!=null && lecture.getSchedulingSubpartId().equals(commitedLecture.getSchedulingSubpartId())) continue;
195                    if (JenrlConstraint.isInConflict(commitedPlacement, placement))
196                            ret.add(commitedPlacement);
197            }
198            return ret;
199        }
200        
201        public int countConflictPlacements(Placement placement) {
202            Set conflicts = conflictPlacements(placement);
203            double w = getOfferingWeight(((Lecture)placement.variable()).getConfiguration());
204            return (int)Math.round(conflicts==null?0:avg(w,1.0)*conflicts.size());
205        }
206        
207        public double getJenrlWeight(Lecture l1, Lecture l2) {
208            return avg(getOfferingWeight(l1.getConfiguration()),getOfferingWeight(l2.getConfiguration()));
209        }
210        
211        public double avg(double w1, double w2) {
212            return Math.sqrt(w1*w2);
213        }
214    }