001package org.cpsolver.studentsct.online.expectations; 002 003import org.cpsolver.ifs.assignment.Assignment; 004import org.cpsolver.ifs.util.DataProperties; 005import org.cpsolver.studentsct.model.Enrollment; 006import org.cpsolver.studentsct.model.Request; 007import org.cpsolver.studentsct.model.Section; 008import org.cpsolver.studentsct.model.Subpart; 009 010/** 011 * Avoid unbalanced sections when there are no expectations. When there are 012 * expectations, the {@link PercentageOverExpected} is used. If there are no 013 * expectations, sections that would have more students than given by the balance 014 * are marked as over-expected. The target fill ratio is proportional to the section 015 * size, a section is considered unbalanced, when the target fill is exceeded by 016 * more than OverExpected.Disbalance percentage (defaults to 0.1). Unlimited 017 * sections are also balanced, when General.BalanceUnlimited parameter is set 018 * to true (defaults to false).<br><br> 019 * A class of an offering with no expectations is over-expected when the number 020 * of enrolled students (including the student in question) minus the target 021 * fill is over the OverExpected.Disbalance portion of the section limit. 022 * 023 * @version StudentSct 1.3 (Student Sectioning)<br> 024 * Copyright (C) 2014 Tomáš Müller<br> 025 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 026 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 027 * <br> 028 * This library is free software; you can redistribute it and/or modify 029 * it under the terms of the GNU Lesser General Public License as 030 * published by the Free Software Foundation; either version 3 of the 031 * License, or (at your option) any later version. <br> 032 * <br> 033 * This library is distributed in the hope that it will be useful, but 034 * WITHOUT ANY WARRANTY; without even the implied warranty of 035 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 036 * Lesser General Public License for more details. <br> 037 * <br> 038 * You should have received a copy of the GNU Lesser General Public 039 * License along with this library; if not see <a 040 * href='http://www.gnu.org/licenses'>http://www.gnu.org/licenses</a>. 041 * 042 */ 043public class AvoidUnbalancedWhenNoExpectations extends PercentageOverExpected { 044 private Double iDisbalance = 0.1; 045 private boolean iBalanceUnlimited = false; 046 047 public AvoidUnbalancedWhenNoExpectations(DataProperties config) { 048 super(config); 049 iDisbalance = config.getPropertyDouble("OverExpected.Disbalance", iDisbalance); 050 iBalanceUnlimited = config.getPropertyBoolean("General.BalanceUnlimited", iBalanceUnlimited); 051 } 052 053 public AvoidUnbalancedWhenNoExpectations(Double percentage, Double disbalance) { 054 super(percentage); 055 iDisbalance = disbalance; 056 } 057 058 public AvoidUnbalancedWhenNoExpectations(Double percentage) { 059 this(percentage, null); 060 } 061 062 public AvoidUnbalancedWhenNoExpectations() { 063 this(null, null); 064 } 065 066 /** 067 * Return allowed disbalance, defaults to 0.1 (parameter OverExpected.Disbalance) 068 * @return allowed disbalance 069 */ 070 public Double getDisbalance() { 071 return iDisbalance; 072 } 073 074 /** 075 * Is balancing of unlimited sections enabled (parameter General.BalanceUnlimited) 076 * @return true if balancing of unlimited sections is enabled 077 */ 078 public boolean isBalanceUnlimited() { 079 return iBalanceUnlimited; 080 } 081 082 @Override 083 public double getOverExpected(Assignment<Request, Enrollment> assignment, Section section, Request request) { 084 Subpart subpart = section.getSubpart(); 085 086 if (hasExpectations(subpart) && section.getLimit() > 0) 087 return super.getOverExpected(assignment, section, request); 088 089 if (getDisbalance() == null || getDisbalance() < 0.0) 090 return 0.0; 091 092 double enrlConfig = request.getWeight() + getEnrollment(assignment, subpart.getConfig(), request); 093 int subparts = section.getSubpart().getConfig().getSubparts().size(); 094 int limit = getLimit(section); 095 double enrl = request.getWeight() + getEnrollment(assignment, section, request); 096 097 if (limit > 0) { 098 // sections have limits -> desired size is section limit x (total 099 // enrollment / total limit) 100 double desired = (enrlConfig / getLimit(subpart)) * limit; 101 if (enrl - desired >= Math.max(1.0, getDisbalance() * limit)) 102 return 1.0 / subparts; 103 } else if (isBalanceUnlimited()) { 104 // unlimited sections -> desired size is total enrollment / number 105 // of sections 106 double desired = enrlConfig / subpart.getSections().size(); 107 if (enrl - desired >= Math.max(1.0, getDisbalance() * desired)) 108 return 1.0 / subparts; 109 } 110 111 return 0.0; 112 } 113 114 @Override 115 public String toString() { 116 return "bal(" + getPercentage() + "," + getDisbalance() + ")"; 117 } 118 119}