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        /**
082         * Test case -- run to see the weights for a few courses
083         */
084        public static void main(String[] args) {
085            EqualStudentWeights pw = new EqualStudentWeights(new DataProperties());
086            DecimalFormat df = new DecimalFormat("0.0000");
087            Student s = new Student(0l);
088            new CourseRequest(1l, 0, false, s, ToolBox.toList(
089                    new Course(1, "A", "1", new Offering(0, "A")),
090                    new Course(1, "A", "2", new Offering(0, "A")),
091                    new Course(1, "A", "3", new Offering(0, "A"))), false, null);
092            new CourseRequest(2l, 1, false, s, ToolBox.toList(
093                    new Course(1, "B", "1", new Offering(0, "B")),
094                    new Course(1, "B", "2", new Offering(0, "B")),
095                    new Course(1, "B", "3", new Offering(0, "B"))), false, null);
096            new CourseRequest(3l, 2, false, s, ToolBox.toList(
097                    new Course(1, "C", "1", new Offering(0, "C")),
098                    new Course(1, "C", "2", new Offering(0, "C")),
099                    new Course(1, "C", "3", new Offering(0, "C"))), false, null);
100            new CourseRequest(5l, 4, false, s, ToolBox.toList(
101                    new Course(1, "E", "1", new Offering(0, "E")),
102                    new Course(1, "E", "2", new Offering(0, "E")),
103                    new Course(1, "E", "3", new Offering(0, "E"))), false, null);
104            new CourseRequest(6l, 5, true, s, ToolBox.toList(
105                    new Course(1, "F", "1", new Offering(0, "F")),
106                    new Course(1, "F", "2", new Offering(0, "F")),
107                    new Course(1, "F", "3", new Offering(0, "F"))), false, null);
108            new CourseRequest(7l, 6, true, s, ToolBox.toList(
109                    new Course(1, "G", "1", new Offering(0, "G")),
110                    new Course(1, "G", "2", new Offering(0, "G")),
111                    new Course(1, "G", "3", new Offering(0, "G"))), false, null);
112            
113            Placement p = new Placement(null, new TimeLocation(1, 90, 12, 0, 0, null, null, new BitSet(), 10), new ArrayList<RoomLocation>());
114            for (Request r: s.getRequests()) {
115                CourseRequest cr = (CourseRequest)r;
116                double[] w = new double[] {0.0, 0.0, 0.0};
117                for (int i = 0; i < cr.getCourses().size(); i++) {
118                    Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
119                    Set<Assignment> sections = new HashSet<Assignment>();
120                    sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null));
121                    Enrollment e = new Enrollment(cr, i, cfg, sections);
122                    w[i] = pw.getWeight(e, null, null);
123                }
124                System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
125            }
126    
127            System.out.println("With one distance conflict:");
128            for (Request r: s.getRequests()) {
129                CourseRequest cr = (CourseRequest)r;
130                double[] w = new double[] {0.0, 0.0, 0.0};
131                for (int i = 0; i < cr.getCourses().size(); i++) {
132                    Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
133                    Set<Assignment> sections = new HashSet<Assignment>();
134                    sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null));
135                    Enrollment e = new Enrollment(cr, i, cfg, sections);
136                    Set<DistanceConflict.Conflict> dc = new HashSet<DistanceConflict.Conflict>();
137                    dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, (Section)sections.iterator().next()));
138                    w[i] = pw.getWeight(e, dc, null);
139                }
140                System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
141            }
142    
143            System.out.println("With two distance conflicts:");
144            for (Request r: s.getRequests()) {
145                CourseRequest cr = (CourseRequest)r;
146                double[] w = new double[] {0.0, 0.0, 0.0};
147                for (int i = 0; i < cr.getCourses().size(); i++) {
148                    Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
149                    Set<Assignment> sections = new HashSet<Assignment>();
150                    sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null));
151                    Enrollment e = new Enrollment(cr, i, cfg, sections);
152                    Set<DistanceConflict.Conflict> dc = new HashSet<DistanceConflict.Conflict>();
153                    dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, (Section)sections.iterator().next()));
154                    dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e,
155                            new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null)));
156                    w[i] = pw.getWeight(e, dc, null);
157                }
158                System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
159            }
160    
161            System.out.println("With 25% time overlapping conflict:");
162            for (Request r: s.getRequests()) {
163                CourseRequest cr = (CourseRequest)r;
164                double[] w = new double[] {0.0, 0.0, 0.0};
165                for (int i = 0; i < cr.getCourses().size(); i++) {
166                    Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
167                    Set<Assignment> sections = new HashSet<Assignment>();
168                    sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null));
169                    Enrollment e = new Enrollment(cr, i, cfg, sections);
170                    Set<TimeOverlapsCounter.Conflict> toc = new HashSet<TimeOverlapsCounter.Conflict>();
171                    toc.add(new TimeOverlapsCounter.Conflict(s, 3, e, sections.iterator().next(), e, sections.iterator().next()));
172                    w[i] = pw.getWeight(e, null, toc);
173                }
174                System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
175            }
176    
177            System.out.println("Disbalanced sections (by 2 / 10 students):");
178            for (Request r: s.getRequests()) {
179                CourseRequest cr = (CourseRequest)r;
180                double[] w = new double[] {0.0, 0.0, 0.0};
181                for (int i = 0; i < cr.getCourses().size(); i++) {
182                    Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
183                    Set<Assignment> sections = new HashSet<Assignment>();
184                    Subpart x = new Subpart(0, "Lec", "Lec", cfg, null);
185                    Section a = new Section(0, 10, "x", x, p, null, null, null);
186                    new Section(1, 10, "y", x, p, null, null, null);
187                    sections.add(a);
188                    a.assigned(new Enrollment(s.getRequests().get(0), i, cfg, sections));
189                    a.assigned(new Enrollment(s.getRequests().get(0), i, cfg, sections));
190                    cfg.assigned(new Enrollment(s.getRequests().get(0), i, cfg, sections));
191                    cfg.assigned(new Enrollment(s.getRequests().get(0), i, cfg, sections));
192                    Enrollment e = new Enrollment(cr, i, cfg, sections);
193                    w[i] = pw.getWeight(e, null, null);
194                }
195                System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
196            }
197        }
198    }