@Override public void propagate(int evtmask) throws ContradictionException { updateBounds(); // ensure that, in case of enumerated domains, holes are also propagated if (bothEnumerated) { int ub = x.getUB(); for (int val = x.getLB(); val <= ub; val = x.nextValue(val)) { if (!y.contains(val - cste)) { x.removeValue(val, aCause); } } ub = y.getUB(); for (int val = y.getLB(); val <= ub; val = y.nextValue(val)) { if (!x.contains(val + cste)) { y.removeValue(val, aCause); } } idms[0].unfreeze(); idms[1].unfreeze(); } if (x.isInstantiated()) { assert (y.isInstantiated()); setPassive(); } }
@SuppressWarnings("StatementWithEmptyBody") private void updateBounds() throws ContradictionException { while (x.updateLowerBound(y.getLB() + cste, aCause) | y.updateLowerBound(x.getLB() - cste, aCause)) ; while (x.updateUpperBound(y.getUB() + cste, aCause) | y.updateUpperBound(x.getUB() - cste, aCause)) ; }
private void backPropRemPoss() throws ContradictionException { ISetIterator iter = poss.iterator(); while (iter.hasNext()) { int i = iter.nextInt(); IntVar v = vars[i]; if (v.hasEnumeratedDomain()) { for (int value : values) { v.removeValue(value, this); } poss.remove(i); } else { int newLB = v.getLB(); int newUB = v.getUB(); for (int val = v.getLB(); val <= newUB; val = v.nextValue(val)) { if (setValues.contains(val)) { newLB = val + 1; } else { break; } } for (int val = newUB; val >= newLB; val = v.previousValue(val)) { if (setValues.contains(val)) { newUB = val - 1; } else { break; } } v.updateBounds(newLB, newUB, this); if (newLB > values[values.length - 1] || newUB < values[0]) { poss.remove(i); } } } }
@Override public ESat isEntailed() { if ((x.getUB() < y.getLB() + cste) || (x.getLB() > y.getUB() + cste) || x.hasEnumeratedDomain() && y.hasEnumeratedDomain() && !match()) return ESat.FALSE; else if (x.isInstantiated() && y.isInstantiated() && (x.getValue() == y.getValue() + cste)) return ESat.TRUE; else return ESat.UNDEFINED; }
/** In case of a EQ, due to a modification of the lower bound of v0 */ public void filterOnInf(IntVar v0, IntVar v1) throws ContradictionException { if (v1.hasEnumeratedDomain()) { int end = v0.getLB() + cste; for (int val = v0.getLB(); val <= end; val = v1.nextValue(val)) { if (!v0.contains(val - cste) && !v0.contains(val + cste)) { v1.removeValue(val, this); } } } else { v1.updateLowerBound(v0.getLB() - cste, this); } }
@Override public void propagate(int evtmask) throws ContradictionException { for (int i = 0; i < n; i++) { IntVar intVar = intVars[i]; RealVar realVar = realVars[i]; realVar.updateBounds( (double) intVar.getLB() - epsilon, (double) intVar.getUB() + epsilon, aCause); intVar.updateLowerBound((int) Math.ceil(realVar.getLB() - epsilon), aCause); intVar.updateUpperBound((int) Math.floor(realVar.getUB() + epsilon), aCause); if (intVar.hasEnumeratedDomain()) { realVar.updateBounds( (double) intVar.getLB() - epsilon, (double) intVar.getUB() + epsilon, aCause); } } }
@Override public ESat isEntailed() { if (set.getEnvelopeSize() == 0) { if (notEmpty) { return ESat.FALSE; } else { return ESat.TRUE; } } int lb = min.getLB(); int ub = min.getUB(); for (int j = set.getKernelFirst(); j != SetVar.END; j = set.getKernelNext()) { if (get(j) < lb) { return ESat.FALSE; } } int minVal = Integer.MAX_VALUE; for (int j = set.getEnvelopeFirst(); j != SetVar.END; j = set.getEnvelopeNext()) { if (minVal > get(j)) { minVal = get(j); } } if (minVal > ub && (notEmpty || set.getKernelSize() > 0)) { return ESat.FALSE; } if (isCompletelyInstantiated()) { return ESat.TRUE; } return ESat.UNDEFINED; }
/** * AtLeastNValues Propagator (similar to SoftAllDiff) The number of distinct values in vars is at * least nValues Performs Generalized Arc Consistency based on Maximum Bipartite Matching The * worst case time complexity is O(nm) but this is very pessimistic In practice it is more like * O(m) where m is the number of variable-value pairs * * @param variables array of integer variables * @param nValues integer variable */ public PropAtLeastNValues_AC(IntVar[] variables, IntVar nValues) { super(ArrayUtils.append(variables, new IntVar[] {nValues}), PropagatorPriority.QUADRATIC, true); this.idms = new IIntDeltaMonitor[this.vars.length]; for (int i = 0; i < this.vars.length; i++) { idms[i] = this.vars[i].monitorDelta(this); } n = variables.length; map = new TIntIntHashMap(); IntVar v; int ub; int idx = n; for (int i = 0; i < n; i++) { v = vars[i]; ub = v.getUB(); for (int j = v.getLB(); j <= ub; j = v.nextValue(j)) { if (!map.containsKey(j)) { map.put(j, idx); idx++; } } } n2 = idx; fifo = new int[n2]; digraph = new DirectedGraph(model, n2 + 2, SetType.LINKED_LIST, false); free = new BitSet(n2); remProc = new DirectedRemProc(); father = new int[n2]; in = new BitSet(n2); SCCfinder = new StrongConnectivityFinder(digraph); }
private boolean match() { int lb = x.getLB(); int ub = x.getUB(); for (; lb <= ub; lb = x.nextValue(lb)) { if (y.contains(lb - cste)) return true; } return false; }
/** In case of a GT, due to a modification on v0 domain */ public void filterGTonVar(IntVar v0, IntVar v1) throws ContradictionException { if (cste >= 0) { int lbv0 = v0.getUB() - cste; int ubv0 = v0.getLB() + cste; // remove interval [lbv0, ubv0] from domain of vars[0] v1.removeInterval(lbv0, ubv0, this); } else { this.setPassive(); } }
/** In case of a EQ, due to a modification of the upper bound of v0 */ public void filterOnSup(IntVar v0, IntVar v1) throws ContradictionException { if (v1.hasEnumeratedDomain()) { int initval; if (v0.getUB() - cste > v1.getLB()) { initval = v1.nextValue(v0.getUB() - cste - 1); } else { initval = v1.getLB(); } int val = initval; do { if (!v0.contains(val - cste) && !v0.contains(val + cste)) { v1.removeValue(val, this); } val = v1.nextValue(val); } while (val <= v1.getUB() && val > initval); // todo : pourquoi besoin du deuxieme currentElement ? } else { v1.updateUpperBound(v0.getUB() + cste, this); } }
private void filter() throws ContradictionException { buildSCC(); int j, ub; IntVar v; for (int i = 0; i < n; i++) { v = vars[i]; ub = v.getUB(); for (int k = v.getLB(); k <= ub; k = v.nextValue(k)) { j = map.get(k); if (nodeSCC[i] != nodeSCC[j]) { if (digraph.getPredOf(i).contains(j)) { v.instantiateTo(k, this); } else { v.removeValue(k, this); digraph.removeArc(i, j); } } } if (!v.hasEnumeratedDomain()) { ub = v.getUB(); for (int k = v.getLB(); k <= ub; k = v.nextValue(k)) { j = map.get(k); if (digraph.arcExists(i, j) || digraph.arcExists(j, i)) { break; } else { v.removeValue(k, this); } } int lb = v.getLB(); for (int k = ub; k >= lb; k = v.previousValue(k)) { j = map.get(k); if (digraph.arcExists(i, j) || digraph.arcExists(j, i)) { break; } else { v.removeValue(k, this); } } } } }
@Override public ESat isEntailed() { assert intVars.length == realVars.length; boolean allInst = true; for (int i = 0; i < n; i++) { IntVar intVar = intVars[i]; RealVar realVar = realVars[i]; if ((realVar.getLB() < (double) intVar.getLB() - epsilon) || (realVar.getUB() > (double) intVar.getUB() + epsilon)) { return ESat.FALSE; } if (!(intVar.isInstantiated() && realVar.isInstantiated())) { allInst = false; } } return allInst ? ESat.TRUE : ESat.UNDEFINED; }
private void buildDigraph() { for (int i = 0; i < n2; i++) { digraph.getSuccOf(i).clear(); digraph.getPredOf(i).clear(); } free.set(0, n2); int j, k, ub; IntVar v; for (int i = 0; i < n2 + 2; i++) { digraph.removeNode(i); } for (int i = 0; i < n; i++) { v = vars[i]; ub = v.getUB(); for (k = v.getLB(); k <= ub; k = v.nextValue(k)) { j = map.get(k); digraph.addArc(i, j); } } }
@Override public ESat isEntailed() { int min = 0; int max = 0; ISet env = g.getPotentialNodes(); for (int i = env.getFirstElement(); i >= 0; i = env.getNextElement()) { if (g.getMandSuccOrNeighOf(i).contain(i)) { min++; max++; } else if (g.getPotSuccOrNeighOf(i).contain(i)) { max++; } } if (k.getLB() > max || k.getUB() < min) { return ESat.FALSE; } if (min == max) { return ESat.TRUE; } return ESat.UNDEFINED; }
@Override public void propagate(int evtmask) throws ContradictionException { for (int j = set.getKernelFirst(); j != SetVar.END; j = set.getKernelNext()) { min.updateUpperBound(get(j), this); } int minVal = Integer.MAX_VALUE; int lb = min.getLB(); for (int j = set.getEnvelopeFirst(); j != SetVar.END; j = set.getEnvelopeNext()) { int k = get(j); if (k < lb) { set.removeFromEnvelope(j, this); } else { if (minVal > k) { minVal = k; } } } if (notEmpty || set.getKernelSize() > 0) { min.updateLowerBound(minVal, this); } }
@Override public void propagate(int evtmask) throws ContradictionException { IntVar union = vars[0]; for (int v = union.getLB(); v <= union.getUB(); v = union.nextValue(v)) { int i; for (i = 1; i < vars.length; i++) { if (vars[i].contains(v)) { break; } } if (i == vars.length) { union.removeValue(v, aCause); } } for (int i = 1; i < vars.length; i++) { for (int v = vars[i].getLB(); v <= vars[i].getUB(); v = vars[i].nextValue(v)) { if (!union.contains(v)) { vars[i].removeValue(v, aCause); } } } }
@Override public ESat isEntailed() { BitSet values = new BitSet(n2); BitSet mandatoryValues = new BitSet(n2); IntVar v; int ub; for (int i = 0; i < n; i++) { v = vars[i]; ub = v.getUB(); if (v.isInstantiated()) { mandatoryValues.set(map.get(ub)); } for (int j = v.getLB(); j <= ub; j++) { values.set(map.get(j)); } } if (mandatoryValues.cardinality() >= vars[n].getUB()) { return ESat.TRUE; } if (values.cardinality() < vars[n].getLB()) { return ESat.FALSE; } return ESat.UNDEFINED; }
/** In case of a LT, due to a modification on v0 domain */ public void filterLTonVar(IntVar v0, IntVar v1) throws ContradictionException { v1.updateBounds(v0.getLB() - cste + 1, v0.getUB() + cste - 1, this); }
@Override public double maxGHat(double lambda, IntVar var) { return -lambda * ((lambda < 0) ? var.getUB() : var.getLB()); }
/** * Make a new model. * * @param p the RP to use as a basis. * @param e the VM managed by the action * @throws org.btrplace.scheduler.SchedulerException if an error occurred */ public RelocatableVM(ReconfigurationProblem p, VM e) throws SchedulerException { // Get vars vm = e; rp = p; src = rp.getSourceModel().getMapping().getVMLocation(e); org.chocosolver.solver.Model csp = rp.getModel(); Model mo = rp.getSourceModel(); // Default values start = rp.getStart(); end = rp.getStart(); duration = csp.intVar(0); state = csp.boolVar(true); // If not manageable, the VM stays on the current host if (!p.getManageableVMs().contains(e)) { stay = csp.boolVar(true); doReinstantiation = csp.boolVar(false); manageable = false; IntVar host = rp.makeCurrentHost(vm, PREFIX_STAY, vm, ").host"); cSlice = new SliceBuilder(rp, vm, PREFIX_STAY, vm.toString(), ").cSlice") .setHoster(host) .setEnd(rp.makeUnboundedDuration(PREFIX_STAY, vm, ").cSlice_end")) .build(); dSlice = new SliceBuilder(rp, vm, PREFIX_STAY, vm, ").dSlice") .setHoster(host) .setStart(cSlice.getEnd()) .build(); return; } // The VM can move (to re-instantiate or migrate) OR STAY to the same host stay = csp.boolVar(rp.makeVarLabel(vm, "stay")); cSlice = new SliceBuilder(rp, vm, PREFIX, vm, ").cSlice") .setHoster(rp.getNode(rp.getSourceModel().getMapping().getVMLocation(vm))) .setEnd(rp.makeUnboundedDuration(PREFIX, vm, ").cSlice_end")) .build(); dSlice = new SliceBuilder(rp, vm, PREFIX, vm, ").dSlice") .setStart(rp.makeUnboundedDuration(PREFIX, vm, ").dSlice_start")) .build(); // Update start and end vars of the action start = dSlice.getStart(); end = cSlice.getEnd(); csp.post(new Arithmetic(end, Operator.LE, rp.getEnd())); // Get some static durations from evaluators DurationEvaluators dev = rp.getDurationEvaluators(); int migrateDuration = dev.evaluate(rp.getSourceModel(), MigrateVM.class, vm); int bootDuration = dev.evaluate(rp.getSourceModel(), org.btrplace.plan.event.BootVM.class, vm); int forgeD = p.getDurationEvaluators() .evaluate(p.getSourceModel(), org.btrplace.plan.event.ForgeVM.class, vm); // Compute the re-instantiation duration int reInstantiateDuration = bootDuration + forgeD; reInstantiateDuration = forgeD; // Compliant with CMaxOnlineTest and others // Get the networking view if attached Network network = Network.get(mo); IntVar migrationDuration; if (network != null) { // Set the migration algorithm postCopy = mo.getAttributes().get(vm, "postCopy", false); // Create unbounded/large domain vars for migration duration and bandwidth migrationDuration = p.makeUnboundedDuration("migration(", vm, ").duration"); bandwidth = csp.intVar(PREFIX + vm + ").bandwidth", 0, Integer.MAX_VALUE / 100, true); } // No networking view, set the duration from the evaluator else { // The duration can still be 0 => the VM STAY ! migrationDuration = csp.intVar( rp.makeVarLabel("migration(", vm, ").duration"), new int[] {0, migrateDuration}); bandwidth = null; } // Possibly re-instantiate (if some attributes are defined) if (mo.getAttributes().get(vm, "clone", false) && mo.getAttributes().isSet(vm, "template")) { doReinstantiation = csp.boolVar(rp.makeVarLabel("relocation_method(", vm, ")")); duration = csp.intVar( rp.makeVarLabel(PREFIX, vm, ").duration"), Math.min(migrationDuration.getLB(), reInstantiateDuration), Math.max(migrationDuration.getUB(), reInstantiateDuration), true); // Re-instantiate or migrate // (Prefer the re-instantiation if the duration are the same, otherwise choose the min) rp.getModel() .ifThenElse( rp.getModel() .or( new Arithmetic( doReinstantiation, Operator.EQ, 0), // can be instantiated externally ! new Arithmetic(migrationDuration, Operator.LT, reInstantiateDuration)), new Arithmetic(duration, Operator.EQ, migrationDuration), new Arithmetic(duration, Operator.EQ, reInstantiateDuration)); // If it is a re-instantiation then specify that the dSlice must start AFTER the Forge delay IntVar time = csp.intVar(rp.makeVarLabel(doReinstantiation.getName(), " * ", forgeD), 0, forgeD, false); csp.post(csp.times(doReinstantiation, forgeD, time)); csp.post(new Arithmetic(start, Operator.GE, time)); // Be sure that doReinstantiation will be instantiated csp.post(new FastIFFEq(doReinstantiation, duration, reInstantiateDuration)); } // The VM either migrate or stay but won't be re-instantiated for sure else { doReinstantiation = csp.boolVar(false); duration = migrationDuration; } // If the VM stay (src host == dst host), then duration = 0 csp.post(new FastIFFEq(stay, dSlice.getHoster(), cSlice.getHoster().getValue())); csp.post(new FastIFFEq(stay, duration, 0)); // We have to force the migration duration equals to 0 if it stays // otherwise, the variable will be free csp.post(new FastIFFEq(stay, migrationDuration, 0)); // Create the task ('default' cumulative constraint with a height of 1) migrationTask = new Task(start, duration, end); }
@Override public double evaluate(IntVar variable) { int lower = variable.getLB(); return -(variable.nextValue(lower) - lower); }