private void showCC() { for (int i = 0; i < setCC.size(); i++) { IStateBitSet contain = setCC.elementAt(i); LOGGER.info("cc(" + i + ") = " + contain.toString()); } LOGGER.info("*-*-*-*-*-*-*-*-*-*-*-*-*"); }
private void updateSpecialNodes() { for (int i = 0; i < nbNodes; i++) { if (graph[i].cardinality() == 0) sinkNodes.set(i, true); else sinkNodes.set(i, false); if (revGraph[i].cardinality() == 0) srcNodes.set(i, true); else srcNodes.set(i, false); } }
@Override public boolean removeValue(int value, ICause cause, boolean informCause) throws ContradictionException { ICause antipromo = cause; if (informCause) { cause = Cause.Null; } boolean change = false; int inf = getLB(); int sup = getUB(); if (value == inf && value == sup) { this.contradiction(cause, MSG_REMOVE); } else { if (inf <= value && value <= sup) { EventType e = EventType.REMOVE; int aValue = value - OFFSET; change = VALUES.get(aValue); this.VALUES.clear(aValue); if (change) { SIZE.add(-1); // todo delta } if (value == inf) { inf = VALUES.nextSetBit(aValue) + OFFSET; LB.set(inf); e = EventType.INCLOW; filterOnGeq(cause, inf); if (cause.reactOnPromotion()) { cause = Cause.Null; } } else if (value == sup) { sup = VALUES.prevSetBit(aValue) + OFFSET; UB.set(sup); e = EventType.DECUPP; filterOnLeq(cause, sup); if (cause.reactOnPromotion()) { cause = Cause.Null; } } if (change && !VALUES.isEmpty()) { if (this.instantiated()) { e = EventType.INSTANTIATE; if (cause.reactOnPromotion()) { cause = Cause.Null; } } this.notifyPropagators(e, cause); } else { if (VALUES.isEmpty()) { this.contradiction(cause, MSG_EMPTY); } } } } return change; }
@Override public void backPropagate(int mask) throws ContradictionException { // one of the variable as changed externally, this involves a complete update of this if (!EventType.isRemove(mask)) { int elb = A.getLB() + B.getLB(); int eub = A.getUB() + B.getUB(); int ilb = LB.get(); int iub = UB.get(); int old_size = iub - ilb; // is == 0, then the view is already instantiated boolean up = false, down = false; EventType e = EventType.VOID; if (elb > ilb) { if (elb > iub) { this.contradiction(this, MSG_LOW); } VALUES.clear(ilb - OFFSET, elb - OFFSET); ilb = VALUES.nextSetBit(ilb - OFFSET) + OFFSET; LB.set(ilb); e = EventType.INCLOW; down = true; } if (eub < iub) { if (eub < ilb) { this.contradiction(this, MSG_LOW); } VALUES.clear(eub - OFFSET + 1, iub - OFFSET + 1); iub = VALUES.prevSetBit(iub - OFFSET + 1) + OFFSET; UB.set(iub); if (e != EventType.VOID) { e = EventType.BOUND; } else { e = EventType.DECUPP; } up = true; } int size = VALUES.cardinality(); SIZE.set(size); if (ilb > iub) { this.contradiction(this, MSG_EMPTY); } if (down || size == 1) { filterOnGeq(this, ilb); } if (up || size == 1) { // size == 1 means instantiation, then force filtering algo filterOnLeq(this, iub); } if (ilb == iub) { // size == 1 means instantiation, then force filtering algo if (old_size > 0) { notifyPropagators(EventType.INSTANTIATE, this); } } else { notifyPropagators(e, this); } } }
private void computeCCfromScratch() { this.cc.getConnectedComponents(affiche); if (affiche) showCC(); // record the connected components of the graph for (int i = 0; i < nbNodes; i++) this.numFromVertCC[i].clear(); for (int i = 0; i < this.setCC.size(); i++) { IStateBitSet contain = this.setCC.elementAt(i); this.vertFromNumCC[i].clear(); for (int j = contain.nextSetBit(0); j >= 0; j = contain.nextSetBit(j + 1)) { this.vertFromNumCC[i].set(j, true); this.numFromVertCC[j].set(i, true); } } this.nbCC.set(this.cc.getNbCC()); }
public int nextValue(int aValue) { aValue -= OFFSET; int lb = LB.get(); if (aValue < 0 || aValue < lb) return lb + OFFSET; aValue = VALUES.nextSetBit(aValue + 1); if (aValue > -1) return aValue + OFFSET; return Integer.MAX_VALUE; }
/** * add a value. * * @param x value to add * @return true wether the value has been added */ public boolean add(int x) { int i = x - offset; if (!contents.get(i)) { addIndex(i); return true; } else { return false; } }
@Override public int previousValue(int aValue) { aValue -= OFFSET; int ub = UB.get(); if (aValue > ub) return ub + OFFSET; aValue = VALUES.prevSetBit(aValue - 1); if (aValue > -1) return aValue + OFFSET; return Integer.MIN_VALUE; }
/** Removes a value. */ public boolean remove(int x) { int i = x - offset; if (contents.get(i)) { removeIndex(i); return true; } else { return false; } }
/** * Instantiates the domain of <code>this</code> to <code>value</code>. The instruction comes from * <code>propagator</code>. * * <ul> * <li>If the domain of <code>this</code> is already instantiated to <code>value</code>, nothing * is done and the return value is <code>false</code>, * <li>If the domain of <code>this</code> is already instantiated to another value, then a * <code>ContradictionException</code> is thrown, * <li>Otherwise, the domain of <code>this</code> is restricted to <code>value</code> and the * observers are notified and the return value is <code>true</code>. * </ul> * * @param value instantiation value (int) * @param cause instantiation releaser * @param informCause * @return true if the instantiation is done, false otherwise * @throws solver.exception.ContradictionException if the domain become empty due to this action */ public boolean instantiateTo(int value, ICause cause, boolean informCause) throws ContradictionException { // BEWARE: THIS CODE SHOULD NOT BE MOVED TO THE DOMAIN TO NOT DECREASE PERFORMANCES! solver .getExplainer() .instantiateTo( this, value, cause); // the explainer is informed before the actual instantiation is performed if (informCause) { cause = Cause.Null; } if (this.instantiated()) { if (value != this.getValue()) { this.contradiction(cause, MSG_INST); } return false; } else if (contains(value)) { int aValue = value - OFFSET; if (reactOnRemoval) { int i = VALUES.nextSetBit(this.LB.get()); for (; i < aValue; i = VALUES.nextSetBit(i + 1)) { delta.add(i + OFFSET); } i = VALUES.nextSetBit(aValue + 1); for (; i >= 0; i = VALUES.nextSetBit(i + 1)) { delta.add(i + OFFSET); } } this.VALUES.clear(); this.VALUES.set(aValue); this.LB.set(aValue); this.UB.set(aValue); this.SIZE.set(1); if (VALUES.isEmpty()) { this.contradiction(cause, MSG_EMPTY); } this.notifyPropagators(EventType.INSTANTIATE, cause); return true; } else { this.contradiction(cause, MSG_UNKNOWN); return false; } }
/** * Updates the lower bound of the domain of <code>this</code> to <code>value</code>. The * instruction comes from <code>propagator</code>. * * <ul> * <li>If <code>value</code> is smaller than the lower bound of the domain, nothing is done and * the return value is <code>false</code>, * <li>if updating the lower bound to <code>value</code> leads to a dead-end (domain wipe-out), * a <code>ContradictionException</code> is thrown, * <li>otherwise, if updating the lower bound to <code>value</code> can be done safely, the * event type is created (the original event can be promoted) and observers are notified and * the return value is <code>true</code> * </ul> * * @param value new lower bound (included) * @param cause updating releaser * @param informCause * @return true if the lower bound has been updated, false otherwise * @throws solver.exception.ContradictionException if the domain become empty due to this action */ public boolean updateLowerBound(int value, ICause cause, boolean informCause) throws ContradictionException { boolean change; ICause antipromo = cause; if (informCause) { cause = Cause.Null; } int old = this.getLB(); if (old < value) { if (this.getUB() < value) { solver.getExplainer().updateLowerBound(this, old, value, antipromo); this.contradiction(cause, MSG_LOW); } else { EventType e = EventType.INCLOW; int aValue = value - OFFSET; if (reactOnRemoval) { // BEWARE: this loop significantly decreases performances for (int i = old - OFFSET; i < aValue; i = VALUES.nextSetBit(i + 1)) { delta.add(i + OFFSET); } } VALUES.clear(old - OFFSET, aValue); LB.set(VALUES.nextSetBit(aValue)); int _size = SIZE.get(); int card = VALUES.cardinality(); SIZE.set(card); change = _size - card > 0; if (instantiated()) { e = EventType.INSTANTIATE; if (cause.reactOnPromotion()) { cause = Cause.Null; } } assert (change); this.notifyPropagators(e, cause); solver.getExplainer().updateLowerBound(this, old, value, antipromo); return change; } } return false; }
/** * Constructs a new domain for the specified variable and bounds. * * @param v The involved variable. * @param a Minimal value. * @param b Maximal value. * @param full indicate if the initial bitSetDomain is full or empty (env or ker) * @param environment */ public BitSetEnumeratedDomain(SetVar v, int a, int b, boolean full, IEnvironment environment) { capacity = b - a + 1; // number of entries this.offset = a; if (full) size = environment.makeInt(capacity); else size = environment.makeInt(0); contents = environment.makeBitSet(capacity); if (full) { for (int i = 0; i < capacity; i++) contents.set(i); } delatDom = new BitSetDeltaDomain(capacity, offset); }
private IStateBitSet getDesc(int i, int j, IStateBitSet[] graph) { // retrieve the set of reachable nodes from i in the graph needUpdate = true; Stack<Integer> stack = new Stack<Integer>(); IStateBitSet reached = solver.getEnvironment().makeBitSet(nbNodes); stack.push(i); while (!stack.isEmpty()) { int a = stack.pop(); for (int b = graph[a].nextSetBit(0); b >= 0; b = graph[a].nextSetBit(b + 1)) { if (!stack.contains(b) && !reached.get(b)) { reached.set(b, true); if (b == j) { needUpdate = false; return reached; } else stack.push(b); } } } return reached; }
@Override public boolean updateLowerBound(int value, ICause cause, boolean informCause) throws ContradictionException { ICause antipromo = cause; if (informCause) { cause = Cause.Null; } boolean change; int lb = this.getLB(); if (lb < value) { if (this.getUB() < value) { this.contradiction(cause, MSG_LOW); } else { EventType e = EventType.INCLOW; int aValue = value - OFFSET; // todo delta VALUES.clear(lb - OFFSET, aValue); lb = VALUES.nextSetBit(aValue) + OFFSET; LB.set(lb); int _size = SIZE.get(); int card = VALUES.cardinality(); SIZE.set(card); change = _size - card > 0; filterOnGeq(cause, lb); if (instantiated()) { e = EventType.INSTANTIATE; if (cause.reactOnPromotion()) { cause = Cause.Null; } } this.notifyPropagators(e, cause); return change; } } return false; }
private void remIncreTC(int i, int j) { if (i != j) { // reachable nodes from node i in the graph IStateBitSet tempDesc = getDesc(i, j, graph); if (needUpdate) { tcGraph[i] = tempDesc; // compute all the reachble nodes from each ancestor of i in graph IStateBitSet updateAnc = solver.getEnvironment().makeBitSet(nbNodes); for (int k = revTcGraph[i].nextSetBit(0); k >= 0; k = revTcGraph[i].nextSetBit(k + 1)) { if (!updateAnc.get(k)) { tempDesc = getDesc(k, j, graph); if (!needUpdate) updateAnc.or(revTcGraph[k]); else tcGraph[k] = tempDesc; } } // compute the nodes reachable from j in the reverse graph revTcGraph[j] = getDesc(j, i, revGraph); // compute all the nodes reachable from each descendant of j in the reverse graph IStateBitSet updateDesc = solver.getEnvironment().makeBitSet(nbNodes); for (int k = tcGraph[j].nextSetBit(0); k >= 0; k = tcGraph[j].nextSetBit(k + 1)) { if (!updateDesc.get(k)) { tempDesc = getDesc(k, i, revGraph); if (!needUpdate) updateDesc.or(tcGraph[k]); else revTcGraph[k] = tempDesc; } } } } }
@Override public boolean updateUpperBound(int value, ICause cause, boolean informCause) throws ContradictionException { ICause antipromo = cause; if (informCause) { cause = Cause.Null; } boolean change; int ub = this.getUB(); if (ub > value) { if (this.getLB() > value) { this.contradiction(cause, MSG_UPP); } else { EventType e = EventType.DECUPP; int aValue = value - OFFSET; // todo delta VALUES.clear(aValue + 1, ub - OFFSET + 1); ub = VALUES.prevSetBit(aValue) + OFFSET; UB.set(ub); int _size = SIZE.get(); int card = VALUES.cardinality(); SIZE.set(card); change = _size - card > 0; filterOnLeq(cause, ub); if (card == 1) { e = EventType.INSTANTIATE; if (cause.reactOnPromotion()) { cause = Cause.Null; } } this.notifyPropagators(e, cause); return change; } } return false; }
public BitsetXYSumView(IntVar a, IntVar b, Solver solver) { super(a, b, solver); int lbA = A.getLB(); int ubA = A.getUB(); int lbB = B.getLB(); int ubB = B.getUB(); OFFSET = lbA + lbB; VALUES = solver.getEnvironment().makeBitSet((ubA + ubB) - (lbA + lbB) + 1); DisposableRangeIterator itA = A.getRangeIterator(true); DisposableRangeIterator itB = B.getRangeIterator(true); while (itA.hasNext()) { itB.bottomUpInit(); while (itB.hasNext()) { VALUES.set(itA.min() + itB.min() - OFFSET, itA.max() + itB.max() - OFFSET + 1); itB.next(); } itB.dispose(); itA.next(); } itA.dispose(); SIZE.set(VALUES.cardinality()); }
@Override public int nextValue(int aValue) { // based on "Bounds Consistency Techniques for Long Linear Constraint" // we only check bounds of A and B, and consider VALUES inside as bounds as existing ones // what if lb > Integer.MAX_VALUE... int lb = getLB(); if (aValue < lb) { return lb; } else if (aValue < getUB()) { return VALUES.nextSetBit(aValue - OFFSET + 1) + OFFSET; } else { return Integer.MAX_VALUE; } }
@Override public int previousValue(int aValue) { // based on "Bounds Consistency Techniques for Long Linear Constraint" // we only check bounds of A and B, and consider VALUES inside as bounds as existing ones // what if ub > Integer.MAX_VALUE... int ub = getUB(); if (aValue > ub) { return ub; } else if (aValue > getLB()) { return VALUES.prevSetBit(aValue - OFFSET - 1) + OFFSET; } else { return Integer.MIN_VALUE; } }
public BitSetEnumeratedDomain( SetVar v, int[] sortedValues, boolean full, IEnvironment environment) { int a = sortedValues[0]; int b = sortedValues[sortedValues.length - 1]; capacity = b - a + 1; // number of entries this.offset = a; if (full) { size = environment.makeInt(sortedValues.length); } else { size = environment.makeInt(0); } contents = environment.makeBitSet(capacity); if (full) { // TODO : could be improved... for (int sortedValue : sortedValues) { contents.set(sortedValue - a); } } delatDom = new BitSetDeltaDomain(capacity, offset); }
@Override public boolean instantiateTo(int value, ICause cause, boolean informCause) throws ContradictionException { if (informCause) { cause = Cause.Null; } int lb = LB.get(); if (this.instantiated()) { if (value != lb) { this.contradiction(cause, MSG_EMPTY); } return false; } else if (contains(value)) { int aValue = value - OFFSET; // todo delta this.VALUES.clear(); this.VALUES.set(aValue); this.LB.set(value); this.UB.set(value); this.SIZE.set(1); if (VALUES.isEmpty()) { this.contradiction(cause, MSG_EMPTY); } filterOnLeq(cause, value); filterOnGeq(cause, value); this.notifyPropagators(EventType.INSTANTIATE, cause); return true; } else { this.contradiction(cause, MSG_UNKNOWN); return false; } }
private void addIndex(int i) { contents.set(i); delatDom.remove(i + offset); if (!contents.get(i)) LOGGER.severe("etrange etrange"); size.add(1); }
@Override public boolean contains(int aValue) { // based on "Bounds Consistency Techniques for Long Linear Constraint" aValue -= OFFSET; return aValue >= 0 && VALUES.get(aValue); }
private void removeIndex(int i) { contents.clear(i); delatDom.remove(i + offset); if (contents.get(i)) LOGGER.severe("etrange etrange"); size.add(-1); }
/** * Removes <code>value</code>from the domain of <code>this</code>. The instruction comes from * <code>propagator</code>. * * <ul> * <li>If <code>value</code> is out of the domain, nothing is done and the return value is * <code>false</code>, * <li>if removing <code>value</code> leads to a dead-end (domain wipe-out), a <code> * ContradictionException</code> is thrown, * <li>otherwise, if removing <code>value</code> from the domain can be done safely, the event * type is created (the original event can be promoted) and observers are notified and the * return value is <code>true</code> * </ul> * * @param value value to remove from the domain (int) * @param cause removal releaser * @param informCause * @return true if the value has been removed, false otherwise * @throws solver.exception.ContradictionException if the domain become empty due to this action */ public boolean removeValue(int value, ICause cause, boolean informCause) throws ContradictionException { // BEWARE: THIS CODE SHOULD NOT BE MOVED TO THE DOMAIN TO NOT DECREASE PERFORMANCES! boolean change = false; ICause antipromo = cause; if (informCause) { cause = Cause.Null; } int inf = getLB(); int sup = getUB(); if (value == inf && value == sup) { solver.getExplainer().removeValue(this, value, antipromo); this.contradiction(cause, MSG_REMOVE); } else { if (inf <= value && value <= sup) { EventType e = EventType.REMOVE; int aValue = value - OFFSET; change = VALUES.get(aValue); this.VALUES.set(aValue, false); if (change) { this.SIZE.add(-1); if (reactOnRemoval) { delta.add(aValue + OFFSET); } } if (value == inf) { LB.set(VALUES.nextSetBit(aValue)); e = EventType.INCLOW; if (cause.reactOnPromotion()) { cause = Cause.Null; } } else if (value == sup) { UB.set(VALUES.prevSetBit(aValue)); e = EventType.DECUPP; if (cause.reactOnPromotion()) { cause = Cause.Null; } } if (change && !VALUES.isEmpty()) { if (this.instantiated()) { e = EventType.INSTANTIATE; if (cause.reactOnPromotion()) { cause = Cause.Null; } } this.notifyPropagators(e, cause); } else { if (VALUES.isEmpty()) { solver.getExplainer().removeValue(this, value, antipromo); this.contradiction(cause, MSG_EMPTY); } } } } if (change) { solver.getExplainer().removeValue(this, value, antipromo); } return change; }
/** * Returns the value following <code>x</code> if non exist return -1 * * @param x starting value * @return value following x */ public int getNextValue(int x) { int i = x - offset; int val = contents.nextSetBit(i + 1); if (val > 0) return val + offset; else return -1; }
private void updateSpecialNodes(int u, int v) { if (graph[u].cardinality() == 0) sinkNodes.set(u, true); else sinkNodes.set(u, false); if (revGraph[v].cardinality() == 0) srcNodes.set(v, true); else srcNodes.set(v, false); }
/** * Returns the value preceding <code>x</code> if non exist return -1 * * @param x starting value * @return value preceding x */ public int getPrevValue(int x) { int i = x - offset; int val = contents.prevSetBit(i - 1); if (val >= 0) return val + offset; else return -1; }
/** * Checks if the value has a following value. * * @param x starting value * @return true whether there is a following value */ public boolean hasNextValue(int x) { int i = x - offset; return (contents.nextSetBit(i + 1) != -1); }
/** * Checks if the value has a preceding value. * * @param x starting value * @return true if there is a preceding value */ public boolean hasPrevValue(int x) { int i = x - offset; return (contents.prevSetBit(i - 1) != -1); }