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