/* * Copyright (c) Fabien Hermenier * * This file is part of Entropy. * * Entropy is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Entropy is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Entropy. If not, see <http://www.gnu.org/licenses/>. */ package entropy.plan.choco.constraint.pack; import choco.kernel.common.logging.ChocoLogging; import choco.kernel.common.util.iterators.DisposableIntIterator; import choco.kernel.memory.IStateIntVector; import choco.kernel.solver.ContradictionException; import choco.kernel.solver.SolverException; import choco.kernel.solver.variables.integer.IntDomainVar; import choco.kernel.solver.variables.set.SetVar; /** * Simplified version of {@link choco.cp.solver.constraints.global.pack.PackFiltering}. * An assertion checks the consistency of the loads with the set model. So take care of disabling assertions * when benching * * @author Fabien Hermenier * @see choco.cp.solver.constraints.global.pack.PackFiltering */ public final class SimpleBinPackingFiltering { private final SimpleBinPacking cstr; /** * The constant size of each item. */ protected final int[] iSizes; /** * The loads of the bins. */ protected final IntDomainVar[] loads; private SetVar setBin; /** * The no fix point. */ private boolean noFixPoint; protected final SumDataStruct loadSum; /** * Instantiates a new 1BP constraint. * * @param pack the packing constraint */ public SimpleBinPackingFiltering(SimpleBinPacking pack) { this.cstr = pack; this.loads = cstr.getLoads(); this.iSizes = this.cstr.getISizes(); loadSum = new SumDataStruct(loads, computeTotalSize()); } /** * Compute the total size and check that sizes are constant. */ private int computeTotalSize() { int l = 0; int last = Integer.MAX_VALUE; int len = iSizes.length; for (int i = 0; i < len; i++) { int s = iSizes[i]; if (s > last) { throw new SolverException("size must be sorted according to non increasing order"); } else { l += s; last = s; } } return l; } /** * Update the minimal load of a given bin. * * @param bin the index of bin * @param load the new load * @throws ContradictionException the contradiction exception */ protected void updateInfLoad(final int bin, final int load) throws ContradictionException { noFixPoint |= cstr.updateInfLoad(bin, load); } /** * Update the maximal load of a given bin. * * @param bin the index of bin * @param load the new load * @throws ContradictionException the contradiction exception */ protected void updateSupLoad(final int bin, final int load) throws ContradictionException { noFixPoint |= cstr.updateSupLoad(bin, load); } /** * Do not update status */ protected void pack(final int item, final int bin) throws ContradictionException { //ChocoLogging.getBranchingLogger().finest("filtering pack(" + item + ", " + bin + ")"); noFixPoint |= cstr.pack(item, bin); } /** * Do not update status */ protected void remove(final int item, final int bin) throws ContradictionException { //ChocoLogging.getBranchingLogger().finest("filtering remove(" + item + ", " + bin + ")"); noFixPoint |= cstr.remove(item, bin); } // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%// // %%%%%%%%%%%%%%%%%%%%%%%%%% TYPICAL MODEL %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%// // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%// /** * The minimum and maximum load of each bin {@link SimpleBinPacking#loads } is maintained according to the domains of the bin assignment variables. * * @param bin the index of the bin * @throws ContradictionException the contradiction exception */ protected void loadMaintenance(final int bin) throws ContradictionException { //sumEnvelop(bin); //Bad for performance!! assert checkLoadConsistency(bin); updateInfLoad(bin, cstr.getRLoad(bin).get()); updateSupLoad(bin, cstr.getCLoad(bin).get() + cstr.getRLoad(bin).get()); } /** * Check the consistency of the rloads and the cloads with regards ot the set variable denoting the hosting * capability of a bin. * * @param bin the bin to analyse * @return {@code false} if the consistency is not viable. * @throws ContradictionException if an error occurred */ public boolean checkLoadConsistency(int bin) throws ContradictionException { DisposableIntIterator ite = cstr.getSetBin(bin).getDomain().getKernelIterator(); int r = 0; while (ite.hasNext()) { r += iSizes[ite.next()]; } ite.dispose(); ite = cstr.getSetBin(bin).getDomain().getOpenDomainIterator(); int c = 0; while (ite.hasNext()) { c += iSizes[ite.next()]; } ite.dispose(); if (r != cstr.getRLoad(bin).get()) { //ChocoLogging.getSearchLogger().finest(loads[bin].pretty() + " env" + cstr.prettyEnvelop(bin) + "=" + cstr.getCLoad(bin).get() + " ker=" + cstr.prettyKernel(bin) + "=" + cstr.getRLoad(bin).get()); ChocoLogging.getBranchingLogger().warning(loads[bin].pretty() + " current r=" + cstr.getRLoad(bin).get() + " expected=" + r); ChocoLogging.flushLogs(); return false; } if (c != cstr.getCLoad(bin).get()) { //ChocoLogging.getSearchLogger().finest(loads[bin].pretty() + " env" + cstr.prettyEnvelop(bin) + "=" + cstr.getCLoad(bin).get() + " ker=" + cstr.prettyKernel(bin) + "=" + cstr.getRLoad(bin).get()); ChocoLogging.getBranchingLogger().warning(loads[bin].pretty() + " (r=" + r + ") current c=" + cstr.getCLoad(bin).get() + " expected=" + c); ChocoLogging.flushLogs(); return false; } return true; } /** * The minimum and maximum load of each bin {@link SimpleBinPacking#loads } is maintained according to the domains of the bin assignment variables. * * @param bin the bin * @throws ContradictionException the contradiction exception */ protected void loadSizeAndCoherence(final int bin) throws ContradictionException { loadSum.updateBounds(bin); updateInfLoad(bin, loadSum.boundInf); updateSupLoad(bin, loadSum.boundSup); } /** * Single item elimination and commitment. * * @param bin the bin * @throws ContradictionException the contradiction exception */ protected void singleItemEliminationAndCommitment(final int bin) throws ContradictionException { DisposableIntIterator iter = setBin.getDomain().getOpenDomainIterator(); final int lInf = loads[bin].getInf(); final int lSup = loads[bin].getSup(); try { while (iter.hasNext()) { final int iIdx = iter.next(); final int iSize = iSizes[iIdx]; final int rLoad = cstr.getRLoad(bin).get(); if (iSize + rLoad > lSup) { remove(iIdx, bin); } else if (rLoad + cstr.getCLoad(bin).get() - iSize < lInf) { pack(iIdx, bin); } else { break; } } } finally { iter.dispose(); } } // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%// // %%%%%%%%%%%%%%%%%%%%%%%%%% ADDITIONAL RULES %%%%%%%%%%%%%%%%%%%%%%%%%%%%// // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%// // ****************************************************************// // ********* PROPAGATION LOOP *************************************// // ****************************************************************// public void propagate() throws ContradictionException { final IStateIntVector abins = cstr.getAvailableBins(); final int n = abins.size(); noFixPoint = true; while (noFixPoint) { noFixPoint = false; loadSum.update(); for (int i = 0; i < n; i++) { propagate(abins.quickGet(i)); } } cstr.fireAvailableBins(); } /** * @throws ContradictionException the contradiction exception */ private void propagate(final int bin) throws ContradictionException { setBin = cstr.getSetBin(bin); loadSizeAndCoherence(bin); loadMaintenance(bin); singleItemEliminationAndCommitment(bin); } static final class SumDataStruct { /** * variables to sum */ protected final IntDomainVar[] vars; /** * the constant sum. */ public final int sum; protected int sumMinusInfs; protected int sumMinusSups; public int boundInf; public int boundSup; private int size; public SumDataStruct(IntDomainVar[] vars, int sum) { super(); this.vars = vars; this.sum = sum; this.size = vars.length; } public void update() { sumMinusInfs = sum; sumMinusSups = sum; for (int i = 0; i < size; i++) { sumMinusInfs -= vars[i].getInf(); sumMinusSups -= vars[i].getSup(); } } public void updateBounds(int idx) { boundInf = sumMinusSups + vars[idx].getSup(); boundSup = sumMinusInfs + vars[idx].getInf(); } } }