001    package net.sf.cpsolver.studentsct.weights;
002    
003    import java.text.DecimalFormat;
004    import java.util.ArrayList;
005    import java.util.BitSet;
006    import java.util.HashSet;
007    import java.util.Set;
008    
009    import net.sf.cpsolver.coursett.model.Placement;
010    import net.sf.cpsolver.coursett.model.RoomLocation;
011    import net.sf.cpsolver.coursett.model.TimeLocation;
012    import net.sf.cpsolver.ifs.solution.Solution;
013    import net.sf.cpsolver.ifs.util.DataProperties;
014    import net.sf.cpsolver.ifs.util.ToolBox;
015    import net.sf.cpsolver.studentsct.extension.DistanceConflict;
016    import net.sf.cpsolver.studentsct.extension.TimeOverlapsCounter;
017    import net.sf.cpsolver.studentsct.model.Assignment;
018    import net.sf.cpsolver.studentsct.model.Config;
019    import net.sf.cpsolver.studentsct.model.Course;
020    import net.sf.cpsolver.studentsct.model.CourseRequest;
021    import net.sf.cpsolver.studentsct.model.Enrollment;
022    import net.sf.cpsolver.studentsct.model.Offering;
023    import net.sf.cpsolver.studentsct.model.Request;
024    import net.sf.cpsolver.studentsct.model.Section;
025    import net.sf.cpsolver.studentsct.model.Student;
026    import net.sf.cpsolver.studentsct.model.Subpart;
027    
028    /**
029     * Student weight is spread equally among student's course requests. Only alternatives have lower weight.
030     * The rest is inherited from {@link PriorityStudentWeights}.
031     * 
032     * @version StudentSct 1.2 (Student Sectioning)<br>
033     *          Copyright (C) 2007 - 2010 Tomas Muller<br>
034     *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
035     *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
036     * <br>
037     *          This library is free software; you can redistribute it and/or modify
038     *          it under the terms of the GNU Lesser General Public License as
039     *          published by the Free Software Foundation; either version 3 of the
040     *          License, or (at your option) any later version. <br>
041     * <br>
042     *          This library is distributed in the hope that it will be useful, but
043     *          WITHOUT ANY WARRANTY; without even the implied warranty of
044     *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
045     *          Lesser General Public License for more details. <br>
046     * <br>
047     *          You should have received a copy of the GNU Lesser General Public
048     *          License along with this library; if not see
049     *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
050     */
051    
052    public class EqualStudentWeights extends PriorityStudentWeights {
053    
054        public EqualStudentWeights(DataProperties config) {
055            super(config);
056        }
057    
058        @Override
059        public double getWeight(Request request) {
060            if (request.getStudent().isDummy() && iProjectedStudentWeight >= 0.0) {
061                double weight = iProjectedStudentWeight;
062                if (request.isAlternative())
063                    weight *= iAlternativeRequestFactor;
064                return weight;
065            }
066            double weight = 1.0 / request.getStudent().nrRequests();
067            if (request.isAlternative())
068                weight *= iAlternativeRequestFactor;
069            return round(weight);
070        }
071        
072        @Override
073        public boolean isBetterThanBestSolution(Solution<Request, Enrollment> currentSolution) {
074            if (currentSolution.getBestInfo() == null) return true;
075            int unassigned = currentSolution.getModel().nrUnassignedVariables();
076            if (currentSolution.getModel().getBestUnassignedVariables() != unassigned)
077                return currentSolution.getModel().getBestUnassignedVariables() > unassigned;
078            return currentSolution.getModel().getTotalValue() < currentSolution.getBestValue();
079        }
080        
081        @Override
082        public boolean isFreeTimeAllowOverlaps() {
083            return true;
084        }
085        
086        /**
087         * Test case -- run to see the weights for a few courses
088         */
089        public static void main(String[] args) {
090            EqualStudentWeights pw = new EqualStudentWeights(new DataProperties());
091            DecimalFormat df = new DecimalFormat("0.0000");
092            Student s = new Student(0l);
093            new CourseRequest(1l, 0, false, s, ToolBox.toList(
094                    new Course(1, "A", "1", new Offering(0, "A")),
095                    new Course(1, "A", "2", new Offering(0, "A")),
096                    new Course(1, "A", "3", new Offering(0, "A"))), false, null);
097            new CourseRequest(2l, 1, false, s, ToolBox.toList(
098                    new Course(1, "B", "1", new Offering(0, "B")),
099                    new Course(1, "B", "2", new Offering(0, "B")),
100                    new Course(1, "B", "3", new Offering(0, "B"))), false, null);
101            new CourseRequest(3l, 2, false, s, ToolBox.toList(
102                    new Course(1, "C", "1", new Offering(0, "C")),
103                    new Course(1, "C", "2", new Offering(0, "C")),
104                    new Course(1, "C", "3", new Offering(0, "C"))), false, null);
105            new CourseRequest(5l, 4, false, s, ToolBox.toList(
106                    new Course(1, "E", "1", new Offering(0, "E")),
107                    new Course(1, "E", "2", new Offering(0, "E")),
108                    new Course(1, "E", "3", new Offering(0, "E"))), false, null);
109            new CourseRequest(6l, 5, true, s, ToolBox.toList(
110                    new Course(1, "F", "1", new Offering(0, "F")),
111                    new Course(1, "F", "2", new Offering(0, "F")),
112                    new Course(1, "F", "3", new Offering(0, "F"))), false, null);
113            new CourseRequest(7l, 6, true, s, ToolBox.toList(
114                    new Course(1, "G", "1", new Offering(0, "G")),
115                    new Course(1, "G", "2", new Offering(0, "G")),
116                    new Course(1, "G", "3", new Offering(0, "G"))), false, null);
117            
118            Placement p = new Placement(null, new TimeLocation(1, 90, 12, 0, 0, null, null, new BitSet(), 10), new ArrayList<RoomLocation>());
119            for (Request r: s.getRequests()) {
120                CourseRequest cr = (CourseRequest)r;
121                double[] w = new double[] {0.0, 0.0, 0.0};
122                for (int i = 0; i < cr.getCourses().size(); i++) {
123                    Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
124                    Set<Assignment> sections = new HashSet<Assignment>();
125                    sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null));
126                    Enrollment e = new Enrollment(cr, i, cfg, sections);
127                    w[i] = pw.getWeight(e, null, null);
128                }
129                System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
130            }
131    
132            System.out.println("With one distance conflict:");
133            for (Request r: s.getRequests()) {
134                CourseRequest cr = (CourseRequest)r;
135                double[] w = new double[] {0.0, 0.0, 0.0};
136                for (int i = 0; i < cr.getCourses().size(); i++) {
137                    Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
138                    Set<Assignment> sections = new HashSet<Assignment>();
139                    sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null));
140                    Enrollment e = new Enrollment(cr, i, cfg, sections);
141                    Set<DistanceConflict.Conflict> dc = new HashSet<DistanceConflict.Conflict>();
142                    dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, (Section)sections.iterator().next()));
143                    w[i] = pw.getWeight(e, dc, null);
144                }
145                System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
146            }
147    
148            System.out.println("With two distance conflicts:");
149            for (Request r: s.getRequests()) {
150                CourseRequest cr = (CourseRequest)r;
151                double[] w = new double[] {0.0, 0.0, 0.0};
152                for (int i = 0; i < cr.getCourses().size(); i++) {
153                    Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
154                    Set<Assignment> sections = new HashSet<Assignment>();
155                    sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null));
156                    Enrollment e = new Enrollment(cr, i, cfg, sections);
157                    Set<DistanceConflict.Conflict> dc = new HashSet<DistanceConflict.Conflict>();
158                    dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, (Section)sections.iterator().next()));
159                    dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e,
160                            new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null)));
161                    w[i] = pw.getWeight(e, dc, null);
162                }
163                System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
164            }
165    
166            System.out.println("With 25% time overlapping conflict:");
167            for (Request r: s.getRequests()) {
168                CourseRequest cr = (CourseRequest)r;
169                double[] w = new double[] {0.0, 0.0, 0.0};
170                for (int i = 0; i < cr.getCourses().size(); i++) {
171                    Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
172                    Set<Assignment> sections = new HashSet<Assignment>();
173                    sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null));
174                    Enrollment e = new Enrollment(cr, i, cfg, sections);
175                    Set<TimeOverlapsCounter.Conflict> toc = new HashSet<TimeOverlapsCounter.Conflict>();
176                    toc.add(new TimeOverlapsCounter.Conflict(s, 3, e, sections.iterator().next(), e, sections.iterator().next()));
177                    w[i] = pw.getWeight(e, null, toc);
178                }
179                System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
180            }
181    
182            System.out.println("Disbalanced sections (by 2 / 10 students):");
183            for (Request r: s.getRequests()) {
184                CourseRequest cr = (CourseRequest)r;
185                double[] w = new double[] {0.0, 0.0, 0.0};
186                for (int i = 0; i < cr.getCourses().size(); i++) {
187                    Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
188                    Set<Assignment> sections = new HashSet<Assignment>();
189                    Subpart x = new Subpart(0, "Lec", "Lec", cfg, null);
190                    Section a = new Section(0, 10, "x", x, p, null, null, null);
191                    new Section(1, 10, "y", x, p, null, null, null);
192                    sections.add(a);
193                    a.assigned(new Enrollment(s.getRequests().get(0), i, cfg, sections));
194                    a.assigned(new Enrollment(s.getRequests().get(0), i, cfg, sections));
195                    cfg.assigned(new Enrollment(s.getRequests().get(0), i, cfg, sections));
196                    cfg.assigned(new Enrollment(s.getRequests().get(0), i, cfg, sections));
197                    Enrollment e = new Enrollment(cr, i, cfg, sections);
198                    w[i] = pw.getWeight(e, null, null);
199                }
200                System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
201            }
202        }
203    }