diff --git a/CHANGES.md b/CHANGES.md index 98f8da3392..483721ccf5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,8 @@ NEXT MILESTONE ### Major features: - Reduced integer overflows on large sum domain definition +- Fix declaring constraint for absolute constraint when the abs variable is already instantiated to 0 +- No more constraints are posted within factories (instead when LCG is activated) ### Deprecated API (to be removed in next release): @@ -18,6 +20,7 @@ See [milestone 6.0.2](https://github.com/chocoteam/choco-solver/milestone/xx) #### Contributors to this release: - Charles Prud'homme - Jean-Guillaume Fages +- Arthur Godet **Full Changelog**: https://github.com/chocoteam/choco-solver/compare/v6.0.1...v6.0.2 diff --git a/parsers/src/test/java/org/chocosolver/parser/flatzinc/parser/ConstraintTest.java b/parsers/src/test/java/org/chocosolver/parser/flatzinc/parser/ConstraintTest.java index d2da135ce8..94cb082686 100644 --- a/parsers/src/test/java/org/chocosolver/parser/flatzinc/parser/ConstraintTest.java +++ b/parsers/src/test/java/org/chocosolver/parser/flatzinc/parser/ConstraintTest.java @@ -11,6 +11,7 @@ import org.chocosolver.solver.Model; import org.chocosolver.solver.constraints.Arithmetic; import org.chocosolver.solver.constraints.Constraint; +import org.chocosolver.solver.constraints.unary.BooleanConstraint; import org.testng.Assert; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -35,9 +36,19 @@ public void before() { } @Test(groups = "1s") - public void test1() throws IOException { + public void test0() throws IOException { map.register("x", mSolver.intVar("x", 0, 2, true)); - Flatzinc4Parser fp = parser("constraint int_le(1,x); % 0<= x\n", mSolver, map); + Flatzinc4Parser fp = parser("constraint int_le(0,x); % 0<= x\n", mSolver, map); + fp.constraint(); + Assert.assertEquals(mSolver.getCstrs().length, 1); + Constraint c = mSolver.getCstrs()[0]; + Assert.assertTrue(c instanceof BooleanConstraint); + } + + @Test(groups = "1s") + public void test1() throws IOException { + map.register("x", mSolver.intVar("x", -1, 2, true)); + Flatzinc4Parser fp = parser("constraint int_le(0,x); % 0<= x\n", mSolver, map); fp.constraint(); Assert.assertEquals(mSolver.getCstrs().length, 1); Constraint c = mSolver.getCstrs()[0]; diff --git a/solver/src/main/java/org/chocosolver/solver/constraints/IIntConstraintFactory.java b/solver/src/main/java/org/chocosolver/solver/constraints/IIntConstraintFactory.java index 1d2b32bf35..9acfb97e91 100644 --- a/solver/src/main/java/org/chocosolver/solver/constraints/IIntConstraintFactory.java +++ b/solver/src/main/java/org/chocosolver/solver/constraints/IIntConstraintFactory.java @@ -262,7 +262,7 @@ default Constraint absolute(IntVar var1, IntVar var2) { } } else if (var1.isInstantiated()) { if (var1.getValue() == 0) { - var2.eq(0).post(); + return arithm(var2, "=", 0); } else if (var1.getValue() > 0) { return member(var2, new int[]{-var1.getValue(), var1.getValue()}); } else { @@ -270,9 +270,8 @@ default Constraint absolute(IntVar var1, IntVar var2) { } } return new Constraint(ConstraintsName.ABSOLUTE, - ref().getSolver().isLCG() ? - new PropAbsoluteLight(var1, var2) : - new PropAbsolute(var1, var2) + ref().getSolver().isLCG() ? new PropAbsoluteLight(var1, var2) + : new PropAbsolute(var1, var2) ); } @@ -351,8 +350,11 @@ default Constraint arithm(IntVar var1, String op1, IntVar var2, String op2, int } else { int[] bounds = VariableUtils.boundsForMultiplication(var1, var2); IntVar var4 = ref().intVar(bounds[0], bounds[1]); - ref().times(var1, var2, var4).post(); - return arithm(var4, op2, cste); + return Constraint.merge( + ConstraintsName.ARITHM, + ref().times(var1, var2, var4), + arithm(var4, op2, cste) + ); } case "/": // v1 / v2 OP cste @@ -361,8 +363,11 @@ default Constraint arithm(IntVar var1, String op1, IntVar var2, String op2, int } else { int[] bounds = VariableUtils.boundsForDivision(var1, var2); IntVar var4 = ref().intVar(bounds[0], bounds[1]); - ref().div(var1, var2, var4).post(); - return arithm(var4, op2, cste); + return Constraint.merge( + ConstraintsName.ARITHM, + ref().div(var1, var2, var4), + arithm(var4, op2, cste) + ); } default: switch (op2) { @@ -372,8 +377,11 @@ default Constraint arithm(IntVar var1, String op1, IntVar var2, String op2, int } else { int[] bounds = VariableUtils.boundsForMultiplication(var2, ref().intVar(cste)); IntVar var4 = ref().intVar(bounds[0], bounds[1]); - ref().times(var2, cste, var4).post(); - return arithm(var1, op1, var4); + return Constraint.merge( + ConstraintsName.ARITHM, + ref().times(var2, cste, var4), + arithm(var1, op1, var4) + ); } case "/": // v1 OP v2 / cste @@ -383,8 +391,11 @@ default Constraint arithm(IntVar var1, String op1, IntVar var2, String op2, int // v1 OP v2 / v3 int[] bounds = VariableUtils.boundsForDivision(var2, ref().intVar(cste)); IntVar var4 = ref().intVar(bounds[0], bounds[1]); - ref().div(var2, ref().intVar(cste), var4).post(); - return arithm(var1, op1, var4); + return Constraint.merge( + ConstraintsName.ARITHM, + ref().div(var2, ref().intVar(cste), var4), + arithm(var1, op1, var4) + ); } default: throw new SolverException("Unknown operators for arithm constraint"); @@ -493,7 +504,7 @@ default Constraint mod(IntVar X, int y, IntVar Z) { times(t1, y, t2).post(); return sum(new IntVar[]{Z, t2}, "=", X); } - return new Constraint((X.getName() + " MOD " + y + " = " + Z.getName()), new PropModXY(X, y, Z)); + return new Constraint(X.getName() + " MOD " + y + " = " + Z.getName(), new PropModXY(X, y, Z)); } } @@ -712,8 +723,11 @@ default Constraint arithm(IntVar var1, String op1, IntVar var2, String op2, IntV // v1 * v2 OP v3 int[] bounds = VariableUtils.boundsForMultiplication(var1, var2); IntVar var4 = ref().intVar(bounds[0], bounds[1]); - ref().times(var1, var2, var4).post(); - return arithm(var4, op2, var3); + return Constraint.merge( + ConstraintsName.ARITHM, + ref().times(var1, var2, var4), + arithm(var4, op2, var3) + ); } case "/": // v1 / v2 = v3 @@ -723,8 +737,11 @@ default Constraint arithm(IntVar var1, String op1, IntVar var2, String op2, IntV // v1 / v2 OP v3 int[] bounds = VariableUtils.boundsForDivision(var1, var2); IntVar var4 = ref().intVar(bounds[0], bounds[1]); - ref().div(var1, var2, var4).post(); - return arithm(var4, op2, var3); + return Constraint.merge( + ConstraintsName.ARITHM, + ref().div(var1, var2, var4), + arithm(var4, op2, var3) + ); } default: switch (op2) { @@ -736,8 +753,11 @@ default Constraint arithm(IntVar var1, String op1, IntVar var2, String op2, IntV // v1 OP v2 * v3 int[] bounds = VariableUtils.boundsForMultiplication(var2, var3); IntVar var4 = ref().intVar(bounds[0], bounds[1]); - ref().times(var2, var3, var4).post(); - return arithm(var1, op1, var4); + return Constraint.merge( + ConstraintsName.ARITHM, + ref().times(var2, var3, var4), + arithm(var1, op1, var4) + ); } case "/": // v1 = v2 / v3 @@ -747,8 +767,11 @@ default Constraint arithm(IntVar var1, String op1, IntVar var2, String op2, IntV // v1 OP v2 / v3 int[] bounds = VariableUtils.boundsForDivision(var2, var3); IntVar var4 = ref().intVar(bounds[0], bounds[1]); - ref().div(var2, var3, var4).post(); - return arithm(var1, op1, var4); + return Constraint.merge( + ConstraintsName.ARITHM, + ref().div(var2, var3, var4), + arithm(var1, op1, var4) + ); } case "+": return scalar(new IntVar[]{var1, var3}, new int[]{1, -1}, op1, var2); @@ -1176,8 +1199,7 @@ default Constraint among(IntVar nbVar, IntVar[] vars, int[] values) { Arrays.sort(vls); if (ref().getSolver().isLCG()) { if (ref().getSettings().warnUser()) { - ref().getSolver().log().white().println( - "Warning: among constraint is decomposed (due to LCG)."); + ref().getSolver().log().white().println("Warning: among constraint is decomposed (due to LCG)."); } IntVar[] cs = ref().intVarArray(vls.length, 0, vars.length); for (int i = 0; i < vls.length; i++) { @@ -1200,11 +1222,10 @@ default Constraint and(BoolVar... bools) { if (bools == null || bools.length == 0) { throw new IllegalArgumentException("The array of variables cannot be null or empty"); } - if (bools.length == 1) return ref().arithm(bools[0], "=", 1); - Model s = bools[0].getModel(); - IntVar sum = s.intVar(0, bools.length, true); - s.sum(bools, "=", sum).post(); - return s.arithm(sum, "=", bools.length); + if (bools.length == 1) { + return ref().arithm(bools[0], "=", 1); + } + return ref().sum(bools, "=", bools.length); } /** @@ -1237,8 +1258,7 @@ default Constraint and(Constraint... cstrs) { default Constraint atLeastNValues(IntVar[] vars, IntVar nValues, boolean AC) { if (ref().getSolver().isLCG()) { if (ref().getSettings().warnUser()) { - ref().getSolver().log().white().println( - "Warning: atMostNValues constraint is decomposed (due to LCG)."); + ref().getSolver().log().white().println("Warning: atMostNValues constraint is decomposed (due to LCG)."); } int[] vals = getDomainUnion(vars); BoolVar[] vs = ref().boolVarArray(vals.length); @@ -1279,8 +1299,7 @@ default Constraint atMostNValues(IntVar[] vars, IntVar nValues, boolean STRONG) int[] vals = getDomainUnion(vars); if (ref().getSolver().isLCG()) { if (ref().getSettings().warnUser()) { - ref().getSolver().log().white().println( - "Warning: atMostNValues constraint is decomposed (due to LCG)."); + ref().getSolver().log().white().println("Warning: atMostNValues constraint is decomposed (due to LCG)."); } BoolVar[] vs = ref().boolVarArray(vals.length); int k = 0; @@ -1339,8 +1358,7 @@ default Constraint binPacking(IntVar[] itemBin, int[] itemSize, IntVar[] binLoad } if (ref().getSolver().isLCG()) { if (ref().getSettings().warnUser()) { - ref().getSolver().log().white().println( - "Warning: binPacking constraint is decomposed (due to LCG)."); + ref().getSolver().log().white().println("Warning: binPacking constraint is decomposed (due to LCG)."); } for (int i = 0; i < itemBin.length; i++) { ref().member(itemBin[i], offset, binLoad.length - 1 + offset).post(); @@ -1353,7 +1371,9 @@ default Constraint binPacking(IntVar[] itemBin, int[] itemSize, IntVar[] binLoad ref().sum(loads, "=", binLoad[i]).post(); } ref().sum(binLoad, "=", sum).post(); - if (!list.isEmpty()) ref().allDifferent(list.toArray(new IntVar[0])).post(); + if (!list.isEmpty()) { + ref().allDifferent(list.toArray(new IntVar[0])).post(); + } return ref().voidConstraint(); } return Constraint.merge( @@ -1548,8 +1568,7 @@ default Constraint costRegular(IntVar[] vars, IntVar cost, ICostAutomaton costAu default Constraint count(int value, IntVar[] vars, IntVar limit) { if (ref().getSolver().isLCG()) { if (ref().getSettings().warnUser()) { - ref().getSolver().log().white().println( - "Warning: count constraint is decomposed (due to LCG)."); + ref().getSolver().log().white().println("Warning: count constraint is decomposed (due to LCG)."); } BoolVar[] bs = new BoolVar[vars.length]; for (int i = 0; i < vars.length; i++) { @@ -1576,8 +1595,7 @@ default Constraint count(IntVar value, IntVar[] vars, IntVar limit) { } if (ref().getSolver().isLCG()) { if (ref().getSettings().warnUser()) { - ref().getSolver().log().white().println( - "Warning: count constraint is decomposed (due to LCG)."); + ref().getSolver().log().white().println("Warning: count constraint is decomposed (due to LCG)."); } BoolVar[] bs = ref().boolVarArray(vars.length); for (int i = 0; i < vars.length; i++) { @@ -1632,8 +1650,7 @@ default Constraint diffN(IntVar[] X, IntVar[] Y, IntVar[] width, IntVar[] height ); if (ref().getSolver().isLCG()) { if (ref().getSettings().warnUser()) { - ref().getSolver().log().white().println( - "Warning: diffN constraint is simplified (due to LCG)."); + ref().getSolver().log().white().println("Warning: diffN constraint is simplified (due to LCG)."); } addCumulativeReasoning = false; } @@ -1728,8 +1745,7 @@ default Constraint element(IntVar value, IntVar[] table, IntVar index, int offse default Constraint globalCardinality(IntVar[] vars, int[] values, IntVar[] occurrences, boolean closed) { if (ref().getSolver().isLCG()) { if (ref().getSettings().warnUser()) { - ref().getSolver().log().white().println( - "Warning: globalCardinality constraint is decomposed (due to LCG)."); + ref().getSolver().log().white().println("Warning: globalCardinality constraint is decomposed (due to LCG)."); } for (int i = 0; i < values.length; i++) { ref().count(values[i], vars, occurrences[i]).post(); @@ -1749,13 +1765,11 @@ default Constraint globalCardinality(IntVar[] vars, int[] values, IntVar[] occur assert !givenValues.contains(i); givenValues.add(i); } - for (IntVar var : vars) { - int ub = var.getUB(); - for (int k = var.getLB(); k <= ub; k = var.nextValue(k)) { - if (!givenValues.contains(k)) { - if (!toAdd.contains(k)) { - toAdd.add(k); - } + for (IntVar variable : vars) { + int ub = variable.getUB(); + for (int k = variable.getLB(); k <= ub; k = variable.nextValue(k)) { + if (!givenValues.contains(k) && !toAdd.contains(k)) { + toAdd.add(k); } } } @@ -1789,8 +1803,7 @@ default Constraint globalCardinality(IntVar[] vars, int[] values, IntVar[] occur default Constraint increasing(IntVar[] vars, int delta) { if (ref().getSolver().isLCG()) { if (ref().getSettings().warnUser()) { - ref().getSolver().log().white().println( - "Warning: increasing constraint is decomposed (due to LCG)."); + ref().getSolver().log().white().println("Warning: increasing constraint is decomposed (due to LCG)."); } for (int i = 0; i < vars.length - 1; i++) { ref().arithm(vars[i], "<=", vars[i + 1], "-", delta).post(); @@ -1965,28 +1978,33 @@ default Constraint knapsack(IntVar[] occurrences, IntVar weightSum, IntVar energ es.add(energy[i]); ws.add(weight[i]); } - //ref().sum(doms, "=", occurrences[i]).post(); } } if (ref().getSolver().isLCG()) { if (ref().getSettings().warnUser()) { - ref().getSolver().log().white().println( - "Warning: weaker version of knapsack constraint (due to LCG)."); + ref().getSolver().log().white().println("Warning: weaker version of knapsack constraint (due to LCG)."); } - return new Constraint(ConstraintsName.KNAPSACK, ArrayUtils.append( + return new Constraint( + ConstraintsName.KNAPSACK, + ArrayUtils.append( scalar1.propagators, scalar2.propagators, - new Propagator[]{new PropKnapsack(occurrences, weightSum, energySum, weight, energy)})); + new Propagator[]{new PropKnapsack(occurrences, weightSum, energySum, weight, energy)} + ) + ); } - return new Constraint(ConstraintsName.KNAPSACK, ArrayUtils.append( - scalar1.propagators, - scalar2.propagators, - new Propagator[]{ + return new Constraint( + ConstraintsName.KNAPSACK, + ArrayUtils.append( + scalar1.propagators, + scalar2.propagators, + new Propagator[]{ new PropKnapsack(occurrences, weightSum, energySum, weight, energy), new PropKnapsackKatriel01(bs.toArray(new BoolVar[0]), weightSum, energySum, - ws.stream().mapToInt(k -> k).toArray(), es.stream().mapToInt(k -> k).toArray()) + ws.stream().mapToInt(k -> k).toArray(), es.stream().mapToInt(k -> k).toArray()) } - )); + ) + ); } /** @@ -2022,12 +2040,13 @@ default Constraint keySort(IntVar[][] vars, IntVar[] PERMvars, IntVar[][] SORTED } Constraint allDiff = ref().allDifferent(PERMvars); allDiff.ignore(); - return new Constraint(ConstraintsName.KEYSORT, - ArrayUtils.append( - allDiff.propagators, - - new Propagator[]{ - new PropKeysorting(vars, SORTEDvars, PERMvars, K)})); + return new Constraint( + ConstraintsName.KEYSORT, + ArrayUtils.append( + allDiff.propagators, + new Propagator[]{new PropKeysorting(vars, SORTEDvars, PERMvars, K)} + ) + ); } /** @@ -2042,7 +2061,9 @@ default Constraint lexChainLess(IntVar[]... vars) { if (vars == null || vars.length == 0) { throw new IllegalArgumentException("The array of variables cannot be null or empty"); } - if (vars.length == 1) return ref().trueConstraint(); + if (vars.length == 1) { + return ref().trueConstraint(); + } if (ref().getSolver().isLCG()) { if (ref().getSettings().warnUser()) { ref().getSolver().log().white().println( @@ -2053,7 +2074,7 @@ default Constraint lexChainLess(IntVar[]... vars) { } return ref().voidConstraint(); } - if(vars[0].length == 1){ + if (vars[0].length == 1) { // if the vectors are of size 1, then lexChainLess is equivalent to increasing IntVar[] rvars = new IntVar[vars.length]; for (int i = 0; i < vars.length; i++) { @@ -2087,7 +2108,7 @@ default Constraint lexChainLessEq(IntVar[]... vars) { } return ref().voidConstraint(); } - if(vars[0].length == 1){ + if (vars[0].length == 1) { // if the vectors are of size 1, then lexChainLessEq is equivalent to increasing IntVar[] rvars = new IntVar[vars.length]; for (int i = 0; i < vars.length; i++) { @@ -2315,8 +2336,7 @@ default Constraint nValues(IntVar[] vars, IntVar nValues) { nValues = ((IntVar[]) args[1])[0]; if (ref().getSolver().isLCG()) { if (ref().getSettings().warnUser()) { - ref().getSolver().log().white().println( - "Warning: nValues constraint is decomposed (due to LCG)."); + ref().getSolver().log().white().println("Warning: nValues constraint is decomposed (due to LCG)."); } /*return new Constraint( ConstraintsName.NVALUES, @@ -2355,10 +2375,7 @@ default Constraint nValues(IntVar[] vars, IntVar nValues) { * @return a constraint that is satisfied if at least one boolean variables in bools is true */ default Constraint or(BoolVar... bools) { - Model s = bools[0].getModel(); - IntVar sum = s.intVar(0, bools.length, true); - s.sum(bools, "=", sum).post(); - return s.arithm(sum, ">=", 1); + return ref().sum(bools, ">=", 1); } /** @@ -2558,33 +2575,31 @@ default Constraint sort(IntVar[] vars, IntVar[] sortedVars) { * @return a subCircuit constraint */ default Constraint subCircuit(IntVar[] vars, int offset, IntVar subCircuitLength) { - Constraint alldiff = allDifferent(vars, "AC"); - alldiff.ignore(); + final List constraints = new ArrayList<>(); + constraints.add(allDifferent(vars, "AC")); int n = vars.length; Model model = vars[0].getModel(); IntVar nbLoops = model.intVar("nLoops", 0, n, true); - nbLoops.add(subCircuitLength).eq(n).post(); + constraints.add(nbLoops.add(subCircuitLength).eq(n).decompose()); if (ref().getSolver().isLCG()) { if (ref().getSettings().warnUser()) { ref().getSolver().log().white().println( "Warning: subCircuit constraint restricted to lighter filtering options due to LCG."); } - return new Constraint(ConstraintsName.SUBCIRCUIT, ArrayUtils.append( - alldiff.getPropagators(), - ArrayUtils.toArray( - new PropKLoops(vars, offset, nbLoops), - new PropSubcircuit(vars, offset, subCircuitLength) - ) + constraints.add(new Constraint( + ConstraintsName.SUBCIRCUIT, + new PropKLoops(vars, offset, nbLoops), + new PropSubcircuit(vars, offset, subCircuitLength) + )); + } else { + constraints.add(new Constraint( + ConstraintsName.SUBCIRCUIT, + new PropKLoops(vars, offset, nbLoops), + new PropSubcircuit(vars, offset, subCircuitLength), + new PropSubcircuitDominatorFilter(vars, offset, true) )); } - return new Constraint(ConstraintsName.SUBCIRCUIT, ArrayUtils.append( - alldiff.getPropagators(), - ArrayUtils.toArray( - new PropKLoops(vars, offset, nbLoops), - new PropSubcircuit(vars, offset, subCircuitLength), - new PropSubcircuitDominatorFilter(vars, offset, true) - ) - )); + return Constraint.merge(ConstraintsName.SUBCIRCUIT, constraints.toArray(Constraint[]::new)); } /** @@ -2739,8 +2754,11 @@ default Constraint sum(BoolVar[] vars, String operator, IntVar sum, int minCardF if (sum.getModel().getSettings().enableDecompositionOfBooleanSum()) { int[] bounds = VariableUtils.boundsForAddition(vars); IntVar p = sum.getModel().intVar(sum.getModel().generateName("RSLT_"), bounds[0], bounds[1], true); - IntLinCombFactory.reduce(vars, Operator.EQ, p, minCardForDecomp).post(); - return arithm(p, operator, sum); + return Constraint.merge( + ConstraintsName.SUM, + IntLinCombFactory.reduce(vars, Operator.EQ, p, minCardForDecomp), + arithm(p, operator, sum) + ); } else { return IntLinCombFactory.reduce(vars, Operator.get(operator), sum, minCardForDecomp); } diff --git a/solver/src/main/java/org/chocosolver/solver/constraints/ISchedulingFactory.java b/solver/src/main/java/org/chocosolver/solver/constraints/ISchedulingFactory.java index ed0bc68d05..3d4e0403e6 100644 --- a/solver/src/main/java/org/chocosolver/solver/constraints/ISchedulingFactory.java +++ b/solver/src/main/java/org/chocosolver/solver/constraints/ISchedulingFactory.java @@ -6,9 +6,6 @@ */ package org.chocosolver.solver.constraints; -import java.util.*; -import java.util.function.Function; - import org.chocosolver.solver.ISelf; import org.chocosolver.solver.Model; import org.chocosolver.solver.constraints.nary.cumulative.PropagatorCumulative; @@ -19,6 +16,12 @@ import org.chocosolver.solver.search.strategy.strategy.SetTimes; import org.chocosolver.solver.variables.IntVar; import org.chocosolver.solver.variables.Task; +import org.chocosolver.util.tools.ArrayUtils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.Function; /** * Interface to make and declare everything useful for scheduling problems (Task objects, constraints, search heuristics, etc.) @@ -117,9 +120,14 @@ default Constraint cumulative( keptTasks[i] = tasksToKeep.get(i); keptHeights[i] = heightsToKeep.get(i); } + Propagator prop = + new PropagatorCumulative(keptTasks, keptHeights, capacity, energyNaive, disjunctiveEnergyNaive); return new Constraint( - ConstraintsName.CUMULATIVE, - new PropagatorCumulative(keptTasks, keptHeights, capacity, energyNaive, disjunctiveEnergyNaive) + ConstraintsName.CUMULATIVE, + ArrayUtils.append( + Arrays.stream(tasks).filter(p -> !p.isPassive()).toArray(Propagator[]::new), + new Propagator[]{prop} + ) ); } diff --git a/solver/src/main/java/org/chocosolver/solver/variables/Task.java b/solver/src/main/java/org/chocosolver/solver/variables/Task.java index 6df79aaaae..3f85ec41b2 100644 --- a/solver/src/main/java/org/chocosolver/solver/variables/Task.java +++ b/solver/src/main/java/org/chocosolver/solver/variables/Task.java @@ -6,8 +6,8 @@ */ package org.chocosolver.solver.variables; -import org.chocosolver.solver.ICause; import org.chocosolver.sat.Reason; +import org.chocosolver.solver.ICause; import org.chocosolver.solver.Model; import org.chocosolver.solver.constraints.Constraint; import org.chocosolver.solver.constraints.Explained; @@ -22,7 +22,7 @@ /** * Container representing a task: - * It ensures that: start + duration = end + * It ensures, when posted, that: start + duration = end * * @author Arthur Godet * @since 25/11/2023 @@ -123,11 +123,13 @@ public Task(IntVar s, IntVar d, IntVar e) { if (shouldPassivate(s, d, e)) { setActive(); setPassive(); - } else { - this.getModel().post(new Constraint("Task relation", this)); } } + public void post() { + this.getModel().post(new Constraint("Task relation", this)); + } + private Task(IntVar[] vars) { this(vars[0], vars[1], vars[2]); } diff --git a/solver/src/test/java/org/chocosolver/solver/variables/TaskTest.java b/solver/src/test/java/org/chocosolver/solver/variables/TaskTest.java index b80db7ee64..f652a5efc3 100644 --- a/solver/src/test/java/org/chocosolver/solver/variables/TaskTest.java +++ b/solver/src/test/java/org/chocosolver/solver/variables/TaskTest.java @@ -363,7 +363,7 @@ public void testMonitor1() { IntVar last = model.intVar("last", 5, 6); IntVar IV390 = model.intVar("IV390", 6); model.arithm(first, "+", dur, "=", last).post(); - new Task(first, dur, IV390); + new Task(first, dur, IV390).post(); Solver s = model.getSolver(); s.setSearch(Search.inputOrderLBSearch(last)); // <- for the issue Assert.assertTrue(s.solve()); @@ -377,7 +377,7 @@ public void testMonitor2() { IntVar last = model.intVar("last", 5, 6); IntVar IV390 = model.intVar("IV390", 6); model.arithm(first, "+", dur, "=", last).post(); - new Task(first, dur, IV390); + new Task(first, dur, IV390).post(); Solver s = model.getSolver(); s.setSearch(Search.inputOrderLBSearch(last)); // <- for the issue Assert.assertTrue(s.solve()); @@ -391,7 +391,7 @@ public void testMonitorAndView() { IntVar last = model.offset(model.intVar("last", 5, 6), 2); IntVar IV390 = model.offset(model.intVar("IV390", 6), 2); model.arithm(first, "+", dur, "=", last).post(); - new Task(first, dur, IV390); + new Task(first, dur, IV390).post(); Solver s = model.getSolver(); s.setSearch(Search.inputOrderLBSearch(last)); // <- for the issue Assert.assertTrue(s.solve()); @@ -407,7 +407,11 @@ public void testScalarAndTaskBug1() { vars[3] = model.intVar(3, 5); model.scalar(vars, coeffs, "<=", 1).post(); IntVar ee = model.intVar(4, 9); - new Task(vars[3], vars[2], ee); + Task task = new Task(vars[3], vars[2], ee); + model.getSolver().solve(); + Assert.assertEquals(model.getSolver().getSolutionCount(), 1); + model.getSolver().reset(); + task.post(); model.getSolver().solve(); Assert.assertEquals(model.getSolver().getSolutionCount(), 0); }