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