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