    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}