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}