001package org.cpsolver.studentsct.online;
002
003import java.util.Set;
004
005import org.apache.logging.log4j.Logger;
006import org.cpsolver.ifs.assignment.Assignment;
007import org.cpsolver.ifs.model.Constraint;
008import org.cpsolver.ifs.model.GlobalConstraint;
009import org.cpsolver.ifs.model.Value;
010import org.cpsolver.ifs.util.DataProperties;
011import org.cpsolver.studentsct.StudentSectioningModel;
012import org.cpsolver.studentsct.constraint.FixInitialAssignments;
013import org.cpsolver.studentsct.model.Enrollment;
014import org.cpsolver.studentsct.model.Request;
015import org.cpsolver.studentsct.model.Section;
016import org.cpsolver.studentsct.online.expectations.AvoidUnbalancedWhenNoExpectations;
017import org.cpsolver.studentsct.online.expectations.OverExpectedCriterion;
018import org.cpsolver.studentsct.online.expectations.PercentageOverExpected;
019
020/**
021 * An online model. A simple extension of the {@link OnlineSectioningModel} class that allows to set the over-expected
022 * criterion (see {@link OverExpectedCriterion}). This class is particularly useful in passing the over-expected criterion to the 
023 * online sectioning algorithms and heuristics.<br><br>
024 * The over-expected criterion can be passed as a constructor parameter, or given using the OverExpectedCriterion.Class parameter.
025 * It defaults to {@link AvoidUnbalancedWhenNoExpectations}.
026 * 
027 * @author  Tomáš Müller
028 * @version StudentSct 1.3 (Student Sectioning)<br>
029 *          Copyright (C) 2014 Tomáš Müller<br>
030 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
031 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
032 * <br>
033 *          This library is free software; you can redistribute it and/or modify
034 *          it under the terms of the GNU Lesser General Public License as
035 *          published by the Free Software Foundation; either version 3 of the
036 *          License, or (at your option) any later version. <br>
037 * <br>
038 *          This library is distributed in the hope that it will be useful, but
039 *          WITHOUT ANY WARRANTY; without even the implied warranty of
040 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
041 *          Lesser General Public License for more details. <br>
042 * <br>
043 *          You should have received a copy of the GNU Lesser General Public
044 *          License along with this library; if not see <a href='http://www.gnu.org/licenses'>http://www.gnu.org/licenses</a>.
045 * 
046 */
047public class OnlineSectioningModel extends StudentSectioningModel {
048    private static Logger sLog = org.apache.logging.log4j.LogManager.getLogger(OnlineSectioningModel.class);
049    private OverExpectedCriterion iOverExpectedCriterion;
050
051    public OnlineSectioningModel(DataProperties properties) {
052        this(properties, null);
053        try {
054            @SuppressWarnings("unchecked")
055            Class<OverExpectedCriterion> overExpectedCriterionClass = (Class<OverExpectedCriterion>)
056                Class.forName(properties.getProperty("OverExpectedCriterion.Class", AvoidUnbalancedWhenNoExpectations.class.getName()));
057            iOverExpectedCriterion = overExpectedCriterionClass.getConstructor(DataProperties.class).newInstance(properties);
058        } catch (Exception e) {
059                sLog.error("Unable to create custom over-expected criterion (" + e.getMessage() + "), using default.", e);
060                iOverExpectedCriterion = new PercentageOverExpected(properties);
061        }
062    }
063
064    public OnlineSectioningModel(DataProperties config, OverExpectedCriterion criterion) {
065        super(config);
066        iOverExpectedCriterion = criterion;
067        if (isMPP() && super.getKeepInitialAssignments()) {
068            for (GlobalConstraint<Request, Enrollment> c: globalConstraints()) {
069                if (c instanceof FixInitialAssignments) {
070                    removeGlobalConstraint(c); break;
071                }
072            }
073        }
074    }
075    
076    @Override
077    public boolean getKeepInitialAssignments() {
078        return false;
079    }
080    
081    /**
082     * Get over-expected criterion
083     * @return over-expected criterion
084     */
085    public OverExpectedCriterion getOverExpectedCriterion() { return iOverExpectedCriterion; }
086    
087    /**
088     * Set over-expected criterion
089     * @param overExpectedCriterion over-expected criterion
090     */
091    public void setOverExpectedCriterion(OverExpectedCriterion overExpectedCriterion) { iOverExpectedCriterion = overExpectedCriterion; }
092    
093    /**
094     * Expectation penalty, to be minimized (computed using {@link OverExpectedCriterion#getOverExpected(Assignment, Section, Request)})
095     * @param assignment current assignment
096     * @param section section in question
097     * @param request student course request
098     * @return expectation penalty (typically 1.0 / number of subparts when over-expected, 0.0 otherwise)
099     */
100    public double getOverExpected(Assignment<Request, Enrollment> assignment, Section section, Request request) {
101        return getOverExpectedCriterion().getOverExpected(assignment, section, request);
102    }
103    
104    /**
105     * Expectation penalty, to be minimized
106     * @param assignment current assignment
107     * @param enrollment current enrollment of the student
108     * @param index only use enrollments 0 .. index - 1 from the assignment array
109     * @param section section in question
110     * @param request student course request
111     * @return expectation penalty (typically 1.0 / number of subparts when over-expected, 0.0 otherwise)
112     */
113    public double getOverExpected(Assignment<Request, Enrollment> assignment, Enrollment[] enrollment, int index, Section section, Request request) {
114        if (getOverExpectedCriterion() instanceof OverExpectedCriterion.HasContext)
115            return ((OverExpectedCriterion.HasContext)getOverExpectedCriterion()).getOverExpected(assignment, enrollment, index, section, request);
116        else
117            return getOverExpectedCriterion().getOverExpected(assignment, section, request);
118    }
119    
120    /**
121     * Expectation penalty, to be minimized.
122     * A variant of the {@link OverExpectedCriterion#getOverExpected(Assignment, Section, Request)} method that can be called from {@link Constraint#computeConflicts(Assignment, Value, Set)}.
123     * @param assignment current assignment
124     * @param selection selected enrollment question
125     * @param value an enrollment to be assigned
126     * @param conflicts enrollments that have been already identified as conflicting
127     * @return expectation penalty (typically 1.0 / number of subparts when over-expected, 0.0 otherwise)
128     */
129    public double getOverExpected(Assignment<Request, Enrollment> assignment, Enrollment selection, Enrollment value, Set<Enrollment> conflicts) {
130        if (getOverExpectedCriterion() instanceof OverExpectedCriterion.HasContext)
131            return ((OverExpectedCriterion.HasContext)getOverExpectedCriterion()).getOverExpected(assignment, selection, value, conflicts);
132        else {
133            if (selection == null || !selection.isCourseRequest()) return 0.0;
134            double penalty = 0.0;
135            for (Section section: selection.getSections())
136                penalty += getOverExpectedCriterion().getOverExpected(assignment, section, selection.getRequest());
137            return penalty;
138        }
139    }
140
141}