001package net.sf.cpsolver.studentsct.weights;
002
003import java.text.DecimalFormat;
004import java.util.ArrayList;
005import java.util.BitSet;
006import java.util.HashSet;
007import java.util.Set;
008
009import net.sf.cpsolver.coursett.model.Placement;
010import net.sf.cpsolver.coursett.model.RoomLocation;
011import net.sf.cpsolver.coursett.model.TimeLocation;
012import net.sf.cpsolver.ifs.solution.Solution;
013import net.sf.cpsolver.ifs.util.DataProperties;
014import net.sf.cpsolver.ifs.util.ToolBox;
015import net.sf.cpsolver.studentsct.extension.DistanceConflict;
016import net.sf.cpsolver.studentsct.extension.TimeOverlapsCounter;
017import net.sf.cpsolver.studentsct.model.Assignment;
018import net.sf.cpsolver.studentsct.model.Config;
019import net.sf.cpsolver.studentsct.model.Course;
020import net.sf.cpsolver.studentsct.model.CourseRequest;
021import net.sf.cpsolver.studentsct.model.Enrollment;
022import net.sf.cpsolver.studentsct.model.Offering;
023import net.sf.cpsolver.studentsct.model.Request;
024import net.sf.cpsolver.studentsct.model.Section;
025import net.sf.cpsolver.studentsct.model.Student;
026import 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 Tomáš Müller<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
052public 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}