    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.StudentSectioningModel;
    018import org.cpsolver.studentsct.extension.DistanceConflict;
    019import org.cpsolver.studentsct.extension.TimeOverlapsCounter;
    020import org.cpsolver.studentsct.model.Choice;
    021import org.cpsolver.studentsct.model.Config;
    022import org.cpsolver.studentsct.model.Course;
    023import org.cpsolver.studentsct.model.CourseRequest;
    024import org.cpsolver.studentsct.model.Enrollment;
    025import org.cpsolver.studentsct.model.Instructor;
    026import org.cpsolver.studentsct.model.Offering;
    027import org.cpsolver.studentsct.model.Request;
    028import org.cpsolver.studentsct.model.SctAssignment;
    029import org.cpsolver.studentsct.model.Section;
    030import org.cpsolver.studentsct.model.Student;
    031import org.cpsolver.studentsct.model.Subpart;
    032
    033
    034/**
    035 * Student weight is spread equally among student's course requests. Only alternatives have lower weight.
    036 * The rest is inherited from {@link PriorityStudentWeights}.
    037 *
    038 * @version StudentSct 1.3 (Student Sectioning)<br>
    039 *          Copyright (C) 2007 - 2014 Tomáš Müller<br>
    040 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
    041 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
    042 * <br>
    043 *          This library is free software; you can redistribute it and/or modify
    044 *          it under the terms of the GNU Lesser General Public License as
    045 *          published by the Free Software Foundation; either version 3 of the
    046 *          License, or (at your option) any later version. <br>
    047 * <br>
    048 *          This library is distributed in the hope that it will be useful, but
    049 *          WITHOUT ANY WARRANTY; without even the implied warranty of
    050 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    051 *          Lesser General Public License for more details. <br>
    052 * <br>
    053 *          You should have received a copy of the GNU Lesser General Public
    054 *          License along with this library; if not see
    055 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
    056 */
    057
    058public class EqualStudentWeights extends PriorityStudentWeights {
    059
    060    public EqualStudentWeights(DataProperties config) {
    061        super(config);
    062    }
    063
    064    @Override
    065    public double getWeight(Request request) {
    066        if (request.getStudent().isDummy() && iProjectedStudentWeight >= 0.0) {
    067            double weight = iProjectedStudentWeight;
    068            if (request.isAlternative())
    069                weight *= iAlternativeRequestFactor;
    070            return weight;
    071        }
    072        double weight = 1.0 / request.getStudent().nrRequests();
    073        if (request.isAlternative())
    074            weight *= iAlternativeRequestFactor;
    075        return round(weight);
    076    }
    077
    078    @Override
    079    public boolean isBetterThanBestSolution(Solution<Request, Enrollment> currentSolution) {
    080        if (currentSolution.getBestInfo() == null) return true;
    081        if (iMPP) return super.isBetterThanBestSolution(currentSolution);
    082        int unassigned = currentSolution.getModel().nrUnassignedVariables(currentSolution.getAssignment());
    083        if (currentSolution.getModel().getBestUnassignedVariables() != unassigned)
    084            return currentSolution.getModel().getBestUnassignedVariables() > unassigned;
    085        return ((StudentSectioningModel)currentSolution.getModel()).getTotalValue(currentSolution.getAssignment(), iPreciseComparison) < currentSolution.getBestValue();
    086    }
    087
    088    @Override
    089    public boolean isFreeTimeAllowOverlaps() {
    090        return true;
    091    }
    092
    093    /**
    094     * Test case -- run to see the weights for a few courses
    095     * @param args program arguments
    096     */
    097    public static void main(String[] args) {
    098        EqualStudentWeights pw = new EqualStudentWeights(new DataProperties());
    099        DecimalFormat df = new DecimalFormat("0.0000");
    100        Student s = new Student(0l);
    101        new CourseRequest(1l, 0, false, s, ToolBox.toList(
    102                new Course(1, "A", "1", new Offering(0, "A")),
    103                new Course(1, "A", "2", new Offering(0, "A")),
    104                new Course(1, "A", "3", new Offering(0, "A"))), false, null);
    105        new CourseRequest(2l, 1, false, s, ToolBox.toList(
    106                new Course(1, "B", "1", new Offering(0, "B")),
    107                new Course(1, "B", "2", new Offering(0, "B")),
    108                new Course(1, "B", "3", new Offering(0, "B"))), false, null);
    109        new CourseRequest(3l, 2, false, s, ToolBox.toList(
    110                new Course(1, "C", "1", new Offering(0, "C")),
    111                new Course(1, "C", "2", new Offering(0, "C")),
    112                new Course(1, "C", "3", new Offering(0, "C"))), false, null);
    113        new CourseRequest(5l, 4, false, s, ToolBox.toList(
    114                new Course(1, "E", "1", new Offering(0, "E")),
    115                new Course(1, "E", "2", new Offering(0, "E")),
    116                new Course(1, "E", "3", new Offering(0, "E"))), false, null);
    117        new CourseRequest(6l, 5, true, s, ToolBox.toList(
    118                new Course(1, "F", "1", new Offering(0, "F")),
    119                new Course(1, "F", "2", new Offering(0, "F")),
    120                new Course(1, "F", "3", new Offering(0, "F"))), false, null);
    121        new CourseRequest(7l, 6, true, s, ToolBox.toList(
    122                new Course(1, "G", "1", new Offering(0, "G")),
    123                new Course(1, "G", "2", new Offering(0, "G")),
    124                new Course(1, "G", "3", new Offering(0, "G"))), false, null);
    125
    126        Assignment<Request, Enrollment> assignment = new DefaultSingleAssignment<Request, Enrollment>();
    127        Placement p = new Placement(null, new TimeLocation(1, 90, 12, 0, 0, null, null, new BitSet(), 10), new ArrayList<RoomLocation>());
    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<SctAssignment> sections = new HashSet<SctAssignment>();
    134                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
    135                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
    136                w[i] = pw.getWeight(assignment, e, null, null);
    137            }
    138            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
    139        }
    140
    141        System.out.println("With one distance conflict:");
    142        for (Request r: s.getRequests()) {
    143            CourseRequest cr = (CourseRequest)r;
    144            double[] w = new double[] {0.0, 0.0, 0.0};
    145            for (int i = 0; i < cr.getCourses().size(); i++) {
    146                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
    147                Set<SctAssignment> sections = new HashSet<SctAssignment>();
    148                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
    149                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
    150                Set<DistanceConflict.Conflict> dc = new HashSet<DistanceConflict.Conflict>();
    151                dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, (Section)sections.iterator().next()));
    152                w[i] = pw.getWeight(assignment, e, dc, null);
    153            }
    154            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
    155        }
    156
    157        System.out.println("With two distance conflicts:");
    158        for (Request r: s.getRequests()) {
    159            CourseRequest cr = (CourseRequest)r;
    160            double[] w = new double[] {0.0, 0.0, 0.0};
    161            for (int i = 0; i < cr.getCourses().size(); i++) {
    162                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
    163                Set<SctAssignment> sections = new HashSet<SctAssignment>();
    164                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
    165                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
    166                Set<DistanceConflict.Conflict> dc = new HashSet<DistanceConflict.Conflict>();
    167                dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, (Section)sections.iterator().next()));
    168                dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e,
    169                        new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)));
    170                w[i] = pw.getWeight(assignment, e, dc, null);
    171            }
    172            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
    173        }
    174
    175        System.out.println("With 25% time overlapping conflict:");
    176        for (Request r: s.getRequests()) {
    177            CourseRequest cr = (CourseRequest)r;
    178            double[] w = new double[] {0.0, 0.0, 0.0};
    179            for (int i = 0; i < cr.getCourses().size(); i++) {
    180                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
    181                Set<SctAssignment> sections = new HashSet<SctAssignment>();
    182                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
    183                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
    184                Set<TimeOverlapsCounter.Conflict> toc = new HashSet<TimeOverlapsCounter.Conflict>();
    185                toc.add(new TimeOverlapsCounter.Conflict(s, 3, e, sections.iterator().next(), e, sections.iterator().next()));
    186                w[i] = pw.getWeight(assignment, e, null, toc);
    187            }
    188            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
    189        }
    190
    191        System.out.println("Disbalanced sections (by 2 / 10 students):");
    192        for (Request r: s.getRequests()) {
    193            CourseRequest cr = (CourseRequest)r;
    194            double[] w = new double[] {0.0, 0.0, 0.0};
    195            for (int i = 0; i < cr.getCourses().size(); i++) {
    196                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
    197                Set<SctAssignment> sections = new HashSet<SctAssignment>();
    198                Subpart x = new Subpart(0, "Lec", "Lec", cfg, null);
    199                Section a = new Section(0, 10, "x", x, p, null);
    200                new Section(1, 10, "y", x, p, null);
    201                sections.add(a);
    202                a.assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment));
    203                a.assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment));
    204                cfg.getContext(assignment).assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment));
    205                cfg.getContext(assignment).assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment));
    206                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
    207                w[i] = pw.getWeight(assignment, e, null, null);
    208            }
    209            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
    210        }
    211
    212        System.out.println("Same sections:");
    213        pw.iMPP = true;
    214        for (Request r: s.getRequests()) {
    215            CourseRequest cr = (CourseRequest)r;
    216            double[] w = new double[] {0.0, 0.0, 0.0};
    217            double dif = 0;
    218            for (int i = 0; i < cr.getCourses().size(); i++) {
    219                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
    220                Set<SctAssignment> sections = new HashSet<SctAssignment>();
    221                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
    222                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
    223                cr.setInitialAssignment(new Enrollment(cr, i, cfg, sections, assignment));
    224                w[i] = pw.getWeight(assignment, e, null, null);
    225                dif = pw.getDifference(e);
    226            }
    227            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]) + " (" + df.format(dif) + ")");
    228        }
    229
    230        System.out.println("Same choice sections:");
    231        pw.iMPP = true;
    232        for (Request r: s.getRequests()) {
    233            CourseRequest cr = (CourseRequest)r;
    234            double[] w = new double[] {0.0, 0.0, 0.0};
    235            double dif = 0;
    236            for (int i = 0; i < cr.getCourses().size(); i++) {
    237                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
    238                Set<SctAssignment> sections = new HashSet<SctAssignment>();
    239                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
    240                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
    241                Set<SctAssignment> other = new HashSet<SctAssignment>();
    242                other.add(new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
    243                cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment));
    244                w[i] = pw.getWeight(assignment, e, null, null);
    245                dif = pw.getDifference(e);
    246            }
    247            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]) + " (" + df.format(dif) + ")");
    248        }
    249
    250        System.out.println("Same time sections:");
    251        for (Request r: s.getRequests()) {
    252            CourseRequest cr = (CourseRequest)r;
    253            double dif = 0;
    254            double[] w = new double[] {0.0, 0.0, 0.0};
    255            for (int i = 0; i < cr.getCourses().size(); i++) {
    256                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
    257                Set<SctAssignment> sections = new HashSet<SctAssignment>();
    258                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
    259                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
    260                Set<SctAssignment> other = new HashSet<SctAssignment>();
    261                other.add(new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, new Instructor(1, null, "Josef Novak", null)));
    262                cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment));
    263                w[i] = pw.getWeight(assignment, e, null, null);
    264                dif = pw.getDifference(e);
    265            }
    266            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]) + " (" + df.format(dif) + ")");
    267        }
    268
    269        System.out.println("Same configuration sections:");
    270        for (Request r: s.getRequests()) {
    271            CourseRequest cr = (CourseRequest)r;
    272            double[] w = new double[] {0.0, 0.0, 0.0};
    273            double dif = 0;
    274            for (int i = 0; i < cr.getCourses().size(); i++) {
    275                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
    276                Set<SctAssignment> sections = new HashSet<SctAssignment>();
    277                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
    278                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
    279                cr.getSelectedChoices().add(new Choice(cfg));
    280                cr.setInitialAssignment(null);
    281                w[i] = pw.getWeight(assignment, e, null, null);
    282                dif = pw.getDifference(e);
    283            }
    284            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]) + " (" + df.format(dif) + ")");
    285        }
    286
    287        System.out.println("Different time sections:");
    288        Placement q = new Placement(null, new TimeLocation(1, 102, 12, 0, 0, null, null, new BitSet(), 10), new ArrayList<RoomLocation>());
    289        for (Request r: s.getRequests()) {
    290            CourseRequest cr = (CourseRequest)r;
    291            double[] w = new double[] {0.0, 0.0, 0.0};
    292            double dif = 0;
    293            for (int i = 0; i < cr.getCourses().size(); i++) {
    294                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
    295                Set<SctAssignment> sections = new HashSet<SctAssignment>();
    296                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
    297                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
    298                Set<SctAssignment> other = new HashSet<SctAssignment>();
    299                other.add(new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), q, null));
    300                cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment));
    301                w[i] = pw.getWeight(assignment, e, null, null);
    302                dif = pw.getDifference(e);
    303            }
    304            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]) + " (" + df.format(dif) + ")");
    305        }
    306
    307        System.out.println("Two sections, one same choice, one same time:");
    308        for (Request r: s.getRequests()) {
    309            CourseRequest cr = (CourseRequest)r;
    310            double[] w = new double[] {0.0, 0.0, 0.0};
    311            double dif = 0;
    312            for (int i = 0; i < cr.getCourses().size(); i++) {
    313                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
    314                Set<SctAssignment> sections = new HashSet<SctAssignment>();
    315                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
    316                sections.add(new Section(1, 1, "y", new Subpart(1, "Rec", "Rec", cfg, null), p, null));
    317                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
    318                Set<SctAssignment> other = new HashSet<SctAssignment>();
    319                other.add(new Section(2, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
    320                other.add(new Section(3, 1, "y", new Subpart(1, "Rec", "Rec", cfg, null), p, null, new Instructor(1, null, "Josef Novak", null)));
    321                cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment));
    322                w[i] = pw.getWeight(assignment, e, null, null);
    323                dif = pw.getDifference(e);
    324            }
    325            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]) + " (" + df.format(dif) + ")");
    326        }
    327    }
    328}