From ec4d9875ae5d4fc3a25cb51f258db59d168faa81 Mon Sep 17 00:00:00 2001 From: Arthur Godet Date: Sat, 22 Aug 2026 19:53:49 +0200 Subject: [PATCH 1/7] fix failing test in T_constraint --- .../parser/flatzinc/parser/T_constraint.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/parsers/src/test/java/org/chocosolver/parser/flatzinc/parser/T_constraint.java b/parsers/src/test/java/org/chocosolver/parser/flatzinc/parser/T_constraint.java index 0d89327e63..6c483058b7 100644 --- a/parsers/src/test/java/org/chocosolver/parser/flatzinc/parser/T_constraint.java +++ b/parsers/src/test/java/org/chocosolver/parser/flatzinc/parser/T_constraint.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,12 +36,22 @@ 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(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]; Assert.assertTrue(c instanceof Arithmetic); } From 7919af5bd4a2d3b7f0b36998be99cd034582bd8d Mon Sep 17 00:00:00 2001 From: Arthur Godet Date: Sat, 22 Aug 2026 20:01:12 +0200 Subject: [PATCH 2/7] Fix #1231 and #1235 and remove posted constraints within factories --- CHANGES.md | 3 + .../constraints/IIntConstraintFactory.java | 257 ++++++++++-------- .../constraints/ISchedulingFactory.java | 18 +- .../nary/knapsack/PropKnapsackKatriel01.java | 7 +- .../chocosolver/solver/variables/Task.java | 5 +- .../solver/constraints/nary/KnapsackTest.java | 60 ++++ 6 files changed, 229 insertions(+), 121 deletions(-) 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/solver/src/main/java/org/chocosolver/solver/constraints/IIntConstraintFactory.java b/solver/src/main/java/org/chocosolver/solver/constraints/IIntConstraintFactory.java index 1d2b32bf35..aa4c519221 100644 --- a/solver/src/main/java/org/chocosolver/solver/constraints/IIntConstraintFactory.java +++ b/solver/src/main/java/org/chocosolver/solver/constraints/IIntConstraintFactory.java @@ -44,7 +44,6 @@ import org.chocosolver.solver.constraints.nary.element.PropElementV_fast; import org.chocosolver.solver.constraints.nary.globalcardinality.GlobalCardinality; import org.chocosolver.solver.constraints.nary.knapsack.PropKnapsack; -import org.chocosolver.solver.constraints.nary.knapsack.PropKnapsackKatriel01; import org.chocosolver.solver.constraints.nary.lex.PropIncreasing; import org.chocosolver.solver.constraints.nary.lex.PropLex; import org.chocosolver.solver.constraints.nary.lex.PropLexChain; @@ -262,7 +261,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 +269,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 +349,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 +362,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 +376,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 +390,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"); @@ -489,11 +499,14 @@ default Constraint mod(IntVar X, int y, IntVar Z) { int b = Math.max(xl, xu); IntVar t1 = ref().intVar(ref().generateName("T1_"), -b, b, true); IntVar t2 = ref().intVar(ref().generateName("T2_"), -b, b, true); - div(X, ref().intVar(y), t1).post(); - times(t1, y, t2).post(); - return sum(new IntVar[]{Z, t2}, "=", X); + return Constraint.merge( + X.getName() + " MOD " + y + " = " + Z.getName(), + div(X, ref().intVar(y), t1), + times(t1, y, t2), + 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 +725,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 +739,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 +755,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 +769,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); @@ -873,17 +898,20 @@ default Constraint mod(IntVar X, IntVar Y, IntVar Z) { Model model = X.getModel(); IntVar t1 = model.intVar(model.generateName("T1_"), -b, b, true); IntVar t2 = model.intVar(model.generateName("T2_"), -b, b, true); - div(X, Y, t1).post(); - times(t1, Y, t2).post(); // compute real modulo int maxMod = Math.max(abs(Y.getLB()), abs(Y.getUB())) - 1; IntVar modulo = model.intVar(model.generateName("mod_"), -maxMod, maxMod); - arithm(X, "-", t2, "=", modulo).post(); // The modulo has the same sign as X (except when modulo = 0) ref().ifThen(arithm(X, ">=", 0), arithm(modulo, ">=", 0)); ref().ifThen(arithm(X, "<", 0), arithm(modulo, "<=", 0)); // returns equality constraint - return arithm(Z, "=", modulo); + return Constraint.merge( + X.getName() + " MOD " + Y.getName() + " = " + Z.getName(), + div(X, Y, t1), + times(t1, Y, t2), + arithm(X, "-", t2, "=", modulo), + arithm(Z, "=", modulo) + ); } else { return new Constraint(X.getName() + " MOD " + Y.getName() + " = " + Z.getName(), new PropModXYZ(X, Y, Z)); } @@ -1174,6 +1202,7 @@ default Constraint notAllEqual(IntVar... vars) { default Constraint among(IntVar nbVar, IntVar[] vars, int[] values) { int[] vls = new TIntHashSet(values).toArray(); // remove double occurrences Arrays.sort(vls); + final List> propagators = new ArrayList<>(); if (ref().getSolver().isLCG()) { if (ref().getSettings().warnUser()) { ref().getSolver().log().white().println( @@ -1181,12 +1210,13 @@ default Constraint among(IntVar nbVar, IntVar[] vars, int[] values) { } IntVar[] cs = ref().intVarArray(vls.length, 0, vars.length); for (int i = 0; i < vls.length; i++) { - ref().count(vls[i], vars, cs[i]).post(); + Arrays.stream(ref().count(vls[i], vars, cs[i]).getPropagators()).forEach(propagators::add); } - return ref().sum(cs, "=", nbVar); + Arrays.stream(ref().sum(cs, "=", nbVar).getPropagators()).forEach(propagators::add); } // sort - return new Constraint(ConstraintsName.AMONG, new PropAmongGAC(ArrayUtils.concat(vars, nbVar), vls)); + propagators.add(new PropAmongGAC(ArrayUtils.concat(vars, nbVar), vls)); + return new Constraint(ConstraintsName.AMONG, propagators.toArray(Propagator[]::new)); } /** @@ -1203,8 +1233,11 @@ default Constraint and(BoolVar... bools) { 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); + return Constraint.merge( + "AND", + s.sum(bools, "=", sum), + s.arithm(sum, "=", bools.length) + ); } /** @@ -1237,8 +1270,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 +1311,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 +1370,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 +1383,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( @@ -1379,9 +1411,10 @@ default Constraint boolsIntChanneling(BoolVar[] bVars, IntVar var, int offset) { return new Constraint(ConstraintsName.BOOLCHANNELING, new PropEnumDomainChanneling(bVars, var, offset)); } else { IntVar enumV = var.getModel().intVar(var.getName() + "_enumImage", var.getLB(), var.getUB(), false); - enumV.eq(var).post(); - return new Constraint(ConstraintsName.BOOLCHANNELING, - new PropEnumDomainChanneling(bVars, enumV, offset) + return Constraint.merge( + ConstraintsName.BOOLCHANNELING, + new Constraint(ConstraintsName.BOOLCHANNELING, new PropEnumDomainChanneling(bVars, enumV, offset)), + enumV.eq(var).decompose() ); } } @@ -1548,8 +1581,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 +1608,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++) { @@ -1589,10 +1620,12 @@ default Constraint count(IntVar value, IntVar[] vars, IntVar limit) { return new Constraint(ConstraintsName.COUNT, new PropCountVar(vars, value, limit)); } else { Model model = value.getModel(); - IntVar Evalue = model.intVar(model.generateName("COUNT_"), value.getLB(), value.getUB(), false); - Evalue.eq(value).post(); - return new Constraint(ConstraintsName.COUNT, - new PropCountVar(vars, Evalue, limit)); + IntVar evalue = model.intVar(model.generateName("COUNT_"), value.getLB(), value.getUB(), false); + return Constraint.merge( + ConstraintsName.COUNT, + new Constraint(ConstraintsName.COUNT, new PropCountVar(vars, evalue, limit)), + arithm(evalue, "=", value) + ); } } @@ -1632,8 +1665,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 +1760,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 +1780,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 +1818,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 +1993,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()) +// new PropKnapsackKatriel01(bs.toArray(new BoolVar[0]), weightSum, energySum, +// ws.stream().mapToInt(k -> k).toArray(), es.stream().mapToInt(k -> k).toArray()) } - )); + ) + ); } /** @@ -2022,12 +2055,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 +2076,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 +2089,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 +2123,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 +2351,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, @@ -2357,8 +2392,11 @@ default Constraint nValues(IntVar[] vars, IntVar nValues) { 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 Constraint.merge( + "OR", + s.sum(bools, "=", sum), + s.arithm(sum, ">=", 1) + ); } /** @@ -2558,33 +2596,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 +2775,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/constraints/nary/knapsack/PropKnapsackKatriel01.java b/solver/src/main/java/org/chocosolver/solver/constraints/nary/knapsack/PropKnapsackKatriel01.java index aaa1fc8b85..cc345199c4 100644 --- a/solver/src/main/java/org/chocosolver/solver/constraints/nary/knapsack/PropKnapsackKatriel01.java +++ b/solver/src/main/java/org/chocosolver/solver/constraints/nary/knapsack/PropKnapsackKatriel01.java @@ -25,9 +25,10 @@ import java.util.Arrays; /** - * Propagator for the 0/1-Knapsack constraint - * based on Dantzig-Wolfe relaxation trying - * to find forbidden and mandatory items + * Propagator for the 0/1-Knapsack constraint based on Dantzig-Wolfe relaxation trying to find forbidden and mandatory + * items + * + * TODO : needs to be debugged * * @author Nicolas PIERRE */ 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..362f8d6de1 100644 --- a/solver/src/main/java/org/chocosolver/solver/variables/Task.java +++ b/solver/src/main/java/org/chocosolver/solver/variables/Task.java @@ -6,10 +6,9 @@ */ 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; import org.chocosolver.solver.constraints.Propagator; import org.chocosolver.solver.constraints.PropagatorPriority; @@ -123,8 +122,6 @@ public Task(IntVar s, IntVar d, IntVar e) { if (shouldPassivate(s, d, e)) { setActive(); setPassive(); - } else { - this.getModel().post(new Constraint("Task relation", this)); } } diff --git a/solver/src/test/java/org/chocosolver/solver/constraints/nary/KnapsackTest.java b/solver/src/test/java/org/chocosolver/solver/constraints/nary/KnapsackTest.java index 04767ce1b1..2f3eff4856 100644 --- a/solver/src/test/java/org/chocosolver/solver/constraints/nary/KnapsackTest.java +++ b/solver/src/test/java/org/chocosolver/solver/constraints/nary/KnapsackTest.java @@ -35,6 +35,66 @@ public class KnapsackTest { {38, 52, 30, 42, 170, 9, 7, 20, 0, 3, 21, 4, 1, 2, 14, 310, 8, 4, 6, 1, 18, 15, 38, 10, 4, 8, 6, 0, 0, 3, 0, 10, 6, 1, 3, 0, 3, 5, 4, 0, 30, 12, 16, 18, 3, 16, 22, 30, 4, 0} }; + @Test(groups = "1s", timeOut = 60000) + public void test() { + Model model = new Model(); + + IntVar[] occurrences = model.intVarArray("item", 3, 0, 1); + IntVar weight = model.intVar("weight", 0, 2); + IntVar profit = model.intVar("profit", 0, 6); + + model.knapsack(occurrences, weight, profit, new int[]{1, 1, 3}, new int[]{1, 2, 3}).post(); + model.arithm(profit, ">=", 2).post(); + + Solver solver = model.getSolver(); + + while (solver.solve()) { + } + Assert.assertEquals(solver.getSolutionCount(), 2); + } + + @Test(groups = "1s", timeOut = 60000) + public void test2() { + Model model = new Model(); + IntVar[] occurrences = model.intVarArray("item", 3, 0, 1); + IntVar weight = model.intVar("weight", 0, 2); + IntVar profit = model.intVar("profit", 0, 6); + + model.knapsack(occurrences, weight, profit, new int[]{1, 1, 3}, new int[]{1, 2, 3}).post(); + model.arithm(profit, ">=", 2).post(); + + Solver solver = model.getSolver(); + model.setObjective(Model.MAXIMIZE, profit); + + int best = Integer.MIN_VALUE; + while (solver.solve()) { + best = profit.getValue(); + } + Assert.assertEquals(best, 3); + } + + @Test(groups = "1s", timeOut = 60000) + public void test3() { + Model model = new Model(); + + IntVar[] occurrences = model.intVarArray("item", 3, 0, 1); + IntVar weight = model.intVar("weight", 0, 17); + IntVar profit = model.intVar("profit", 0, 29); + + model.knapsack(occurrences, weight, profit, new int[]{16, 1, 25}, new int[]{6, 3, 20}).post(); + model.arithm(profit, ">=", 9).post(); + + Solver solver = model.getSolver(); + boolean solutionFound = false; + while (solver.solve()) { + solutionFound = true; + } + + if (!solutionFound) { + Assert.fail(); + } + } + @Test(groups = "10s", timeOut = 60000) public void knapsackTest() { Model m = new Model(); From 5e60f981fa231aa3351d45abd9331aa8b99ff8f5 Mon Sep 17 00:00:00 2001 From: Arthur Godet Date: Sat, 22 Aug 2026 20:11:58 +0200 Subject: [PATCH 3/7] undo change to among() constraint when LCG is activated --- .../solver/constraints/IIntConstraintFactory.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) 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 aa4c519221..a71ea1e0d7 100644 --- a/solver/src/main/java/org/chocosolver/solver/constraints/IIntConstraintFactory.java +++ b/solver/src/main/java/org/chocosolver/solver/constraints/IIntConstraintFactory.java @@ -1202,21 +1202,18 @@ default Constraint notAllEqual(IntVar... vars) { default Constraint among(IntVar nbVar, IntVar[] vars, int[] values) { int[] vls = new TIntHashSet(values).toArray(); // remove double occurrences Arrays.sort(vls); - final List> propagators = new ArrayList<>(); 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++) { - Arrays.stream(ref().count(vls[i], vars, cs[i]).getPropagators()).forEach(propagators::add); + ref().count(vls[i], vars, cs[i]).post(); } - Arrays.stream(ref().sum(cs, "=", nbVar).getPropagators()).forEach(propagators::add); + return ref().sum(cs, "=", nbVar); } // sort - propagators.add(new PropAmongGAC(ArrayUtils.concat(vars, nbVar), vls)); - return new Constraint(ConstraintsName.AMONG, propagators.toArray(Propagator[]::new)); + return new Constraint(ConstraintsName.AMONG, new PropAmongGAC(ArrayUtils.concat(vars, nbVar), vls)); } /** From ebad6b9b934dc830856c9e8f496bcab22ef670e1 Mon Sep 17 00:00:00 2001 From: Arthur Godet Date: Sat, 22 Aug 2026 21:02:01 +0200 Subject: [PATCH 4/7] fix changes in and(), or() constraints + add a post() method for Task --- .../constraints/IIntConstraintFactory.java | 57 +++++++------------ .../chocosolver/solver/variables/Task.java | 7 ++- .../solver/variables/TaskTest.java | 12 ++-- 3 files changed, 33 insertions(+), 43 deletions(-) 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 a71ea1e0d7..d9653e6aa0 100644 --- a/solver/src/main/java/org/chocosolver/solver/constraints/IIntConstraintFactory.java +++ b/solver/src/main/java/org/chocosolver/solver/constraints/IIntConstraintFactory.java @@ -499,12 +499,9 @@ default Constraint mod(IntVar X, int y, IntVar Z) { int b = Math.max(xl, xu); IntVar t1 = ref().intVar(ref().generateName("T1_"), -b, b, true); IntVar t2 = ref().intVar(ref().generateName("T2_"), -b, b, true); - return Constraint.merge( - X.getName() + " MOD " + y + " = " + Z.getName(), - div(X, ref().intVar(y), t1), - times(t1, y, t2), - sum(new IntVar[]{Z, t2}, "=", X) - ); + div(X, ref().intVar(y), t1).post(); + 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)); } @@ -898,20 +895,17 @@ default Constraint mod(IntVar X, IntVar Y, IntVar Z) { Model model = X.getModel(); IntVar t1 = model.intVar(model.generateName("T1_"), -b, b, true); IntVar t2 = model.intVar(model.generateName("T2_"), -b, b, true); + div(X, Y, t1).post(); + times(t1, Y, t2).post(); // compute real modulo int maxMod = Math.max(abs(Y.getLB()), abs(Y.getUB())) - 1; IntVar modulo = model.intVar(model.generateName("mod_"), -maxMod, maxMod); + arithm(X, "-", t2, "=", modulo).post(); // The modulo has the same sign as X (except when modulo = 0) ref().ifThen(arithm(X, ">=", 0), arithm(modulo, ">=", 0)); ref().ifThen(arithm(X, "<", 0), arithm(modulo, "<=", 0)); // returns equality constraint - return Constraint.merge( - X.getName() + " MOD " + Y.getName() + " = " + Z.getName(), - div(X, Y, t1), - times(t1, Y, t2), - arithm(X, "-", t2, "=", modulo), - arithm(Z, "=", modulo) - ); + return arithm(Z, "=", modulo); } else { return new Constraint(X.getName() + " MOD " + Y.getName() + " = " + Z.getName(), new PropModXYZ(X, Y, Z)); } @@ -1227,14 +1221,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); - return Constraint.merge( - "AND", - s.sum(bools, "=", sum), - s.arithm(sum, "=", bools.length) - ); + if (bools.length == 1) { + return ref().arithm(bools[0], "=", 1); + } + return ref().sum(bools, "=", bools.length); } /** @@ -1408,10 +1398,9 @@ default Constraint boolsIntChanneling(BoolVar[] bVars, IntVar var, int offset) { return new Constraint(ConstraintsName.BOOLCHANNELING, new PropEnumDomainChanneling(bVars, var, offset)); } else { IntVar enumV = var.getModel().intVar(var.getName() + "_enumImage", var.getLB(), var.getUB(), false); - return Constraint.merge( - ConstraintsName.BOOLCHANNELING, - new Constraint(ConstraintsName.BOOLCHANNELING, new PropEnumDomainChanneling(bVars, enumV, offset)), - enumV.eq(var).decompose() + enumV.eq(var).post(); + return new Constraint(ConstraintsName.BOOLCHANNELING, + new PropEnumDomainChanneling(bVars, enumV, offset) ); } } @@ -1617,12 +1606,10 @@ default Constraint count(IntVar value, IntVar[] vars, IntVar limit) { return new Constraint(ConstraintsName.COUNT, new PropCountVar(vars, value, limit)); } else { Model model = value.getModel(); - IntVar evalue = model.intVar(model.generateName("COUNT_"), value.getLB(), value.getUB(), false); - return Constraint.merge( - ConstraintsName.COUNT, - new Constraint(ConstraintsName.COUNT, new PropCountVar(vars, evalue, limit)), - arithm(evalue, "=", value) - ); + IntVar Evalue = model.intVar(model.generateName("COUNT_"), value.getLB(), value.getUB(), false); + Evalue.eq(value).post(); + return new Constraint(ConstraintsName.COUNT, + new PropCountVar(vars, Evalue, limit)); } } @@ -2387,13 +2374,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); - return Constraint.merge( - "OR", - s.sum(bools, "=", sum), - s.arithm(sum, ">=", 1) - ); + return ref().sum(bools, ">=", 1); } /** 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 362f8d6de1..3f85ec41b2 100644 --- a/solver/src/main/java/org/chocosolver/solver/variables/Task.java +++ b/solver/src/main/java/org/chocosolver/solver/variables/Task.java @@ -9,6 +9,7 @@ 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; import org.chocosolver.solver.constraints.Propagator; import org.chocosolver.solver.constraints.PropagatorPriority; @@ -21,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 @@ -125,6 +126,10 @@ public Task(IntVar s, IntVar d, IntVar e) { } } + 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); } From 2d7de30efc012928aea6e7bc5ca23945dd6d6b81 Mon Sep 17 00:00:00 2001 From: Arthur Godet Date: Sat, 22 Aug 2026 21:11:30 +0200 Subject: [PATCH 5/7] fix parsers' ConstraintTest --- .../org/chocosolver/parser/flatzinc/parser/ConstraintTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 4aaa8d7ac6..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 @@ -38,7 +38,7 @@ public void before() { @Test(groups = "1s") 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]; From 0cf61317fb932dfae9df780e08b9f0d33d57726d Mon Sep 17 00:00:00 2001 From: Arthur Godet Date: Sun, 23 Aug 2026 00:18:50 +0200 Subject: [PATCH 6/7] change number of nodes and fails for mknapsack_global+mknap2-1.fzn instance in PerfomanceTest (until PropKnapsackKatriel01 is debugged) --- parsers/src/test/resources/flatzinc/instances.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parsers/src/test/resources/flatzinc/instances.csv b/parsers/src/test/resources/flatzinc/instances.csv index a2ce021225..5ca898a71a 100644 --- a/parsers/src/test/resources/flatzinc/instances.csv +++ b/parsers/src/test/resources/flatzinc/instances.csv @@ -20,7 +20,7 @@ 2019,fm3_3.fzn,89,165922,575372,575195 2019,group+u6g1pref1.fzn,14,120,284,257 2019,median_string_dp+p2_10_8-0.fzn,4,34,6207,6200 -2019,mknapsack_global+mknap2-1.fzn,1,7772,5808,5807 +2019,mknapsack_global+mknap2-1.fzn,1,7772,212114,212113 2019,vrp-s4-v2-c3_svrp-v2-c3_det.fzn,8,117,926,911 2019,zephyrus+12_6_6_3.fzn,1,780,62559,62558 2018,oocsp_racks+050_r1.fzn,1,_,9,4 From 3840af0bc9fce72d2bb42d9ac12ab78fd83c537b Mon Sep 17 00:00:00 2001 From: Arthur Godet Date: Fri, 28 Aug 2026 17:29:40 +0200 Subject: [PATCH 7/7] undo changes du to issue #1231 --- .../src/test/resources/flatzinc/instances.csv | 2 +- .../constraints/IIntConstraintFactory.java | 5 +- .../nary/knapsack/PropKnapsackKatriel01.java | 7 +-- .../solver/constraints/nary/KnapsackTest.java | 60 ------------------- 4 files changed, 7 insertions(+), 67 deletions(-) diff --git a/parsers/src/test/resources/flatzinc/instances.csv b/parsers/src/test/resources/flatzinc/instances.csv index 5ca898a71a..a2ce021225 100644 --- a/parsers/src/test/resources/flatzinc/instances.csv +++ b/parsers/src/test/resources/flatzinc/instances.csv @@ -20,7 +20,7 @@ 2019,fm3_3.fzn,89,165922,575372,575195 2019,group+u6g1pref1.fzn,14,120,284,257 2019,median_string_dp+p2_10_8-0.fzn,4,34,6207,6200 -2019,mknapsack_global+mknap2-1.fzn,1,7772,212114,212113 +2019,mknapsack_global+mknap2-1.fzn,1,7772,5808,5807 2019,vrp-s4-v2-c3_svrp-v2-c3_det.fzn,8,117,926,911 2019,zephyrus+12_6_6_3.fzn,1,780,62559,62558 2018,oocsp_racks+050_r1.fzn,1,_,9,4 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 d9653e6aa0..9acfb97e91 100644 --- a/solver/src/main/java/org/chocosolver/solver/constraints/IIntConstraintFactory.java +++ b/solver/src/main/java/org/chocosolver/solver/constraints/IIntConstraintFactory.java @@ -44,6 +44,7 @@ import org.chocosolver.solver.constraints.nary.element.PropElementV_fast; import org.chocosolver.solver.constraints.nary.globalcardinality.GlobalCardinality; import org.chocosolver.solver.constraints.nary.knapsack.PropKnapsack; +import org.chocosolver.solver.constraints.nary.knapsack.PropKnapsackKatriel01; import org.chocosolver.solver.constraints.nary.lex.PropIncreasing; import org.chocosolver.solver.constraints.nary.lex.PropLex; import org.chocosolver.solver.constraints.nary.lex.PropLexChain; @@ -1999,8 +2000,8 @@ default Constraint knapsack(IntVar[] occurrences, IntVar weightSum, IntVar energ 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()) + new PropKnapsackKatriel01(bs.toArray(new BoolVar[0]), weightSum, energySum, + ws.stream().mapToInt(k -> k).toArray(), es.stream().mapToInt(k -> k).toArray()) } ) ); diff --git a/solver/src/main/java/org/chocosolver/solver/constraints/nary/knapsack/PropKnapsackKatriel01.java b/solver/src/main/java/org/chocosolver/solver/constraints/nary/knapsack/PropKnapsackKatriel01.java index cc345199c4..aaa1fc8b85 100644 --- a/solver/src/main/java/org/chocosolver/solver/constraints/nary/knapsack/PropKnapsackKatriel01.java +++ b/solver/src/main/java/org/chocosolver/solver/constraints/nary/knapsack/PropKnapsackKatriel01.java @@ -25,10 +25,9 @@ import java.util.Arrays; /** - * Propagator for the 0/1-Knapsack constraint based on Dantzig-Wolfe relaxation trying to find forbidden and mandatory - * items - * - * TODO : needs to be debugged + * Propagator for the 0/1-Knapsack constraint + * based on Dantzig-Wolfe relaxation trying + * to find forbidden and mandatory items * * @author Nicolas PIERRE */ diff --git a/solver/src/test/java/org/chocosolver/solver/constraints/nary/KnapsackTest.java b/solver/src/test/java/org/chocosolver/solver/constraints/nary/KnapsackTest.java index 2f3eff4856..04767ce1b1 100644 --- a/solver/src/test/java/org/chocosolver/solver/constraints/nary/KnapsackTest.java +++ b/solver/src/test/java/org/chocosolver/solver/constraints/nary/KnapsackTest.java @@ -35,66 +35,6 @@ public class KnapsackTest { {38, 52, 30, 42, 170, 9, 7, 20, 0, 3, 21, 4, 1, 2, 14, 310, 8, 4, 6, 1, 18, 15, 38, 10, 4, 8, 6, 0, 0, 3, 0, 10, 6, 1, 3, 0, 3, 5, 4, 0, 30, 12, 16, 18, 3, 16, 22, 30, 4, 0} }; - @Test(groups = "1s", timeOut = 60000) - public void test() { - Model model = new Model(); - - IntVar[] occurrences = model.intVarArray("item", 3, 0, 1); - IntVar weight = model.intVar("weight", 0, 2); - IntVar profit = model.intVar("profit", 0, 6); - - model.knapsack(occurrences, weight, profit, new int[]{1, 1, 3}, new int[]{1, 2, 3}).post(); - model.arithm(profit, ">=", 2).post(); - - Solver solver = model.getSolver(); - - while (solver.solve()) { - } - Assert.assertEquals(solver.getSolutionCount(), 2); - } - - @Test(groups = "1s", timeOut = 60000) - public void test2() { - Model model = new Model(); - IntVar[] occurrences = model.intVarArray("item", 3, 0, 1); - IntVar weight = model.intVar("weight", 0, 2); - IntVar profit = model.intVar("profit", 0, 6); - - model.knapsack(occurrences, weight, profit, new int[]{1, 1, 3}, new int[]{1, 2, 3}).post(); - model.arithm(profit, ">=", 2).post(); - - Solver solver = model.getSolver(); - model.setObjective(Model.MAXIMIZE, profit); - - int best = Integer.MIN_VALUE; - while (solver.solve()) { - best = profit.getValue(); - } - Assert.assertEquals(best, 3); - } - - @Test(groups = "1s", timeOut = 60000) - public void test3() { - Model model = new Model(); - - IntVar[] occurrences = model.intVarArray("item", 3, 0, 1); - IntVar weight = model.intVar("weight", 0, 17); - IntVar profit = model.intVar("profit", 0, 29); - - model.knapsack(occurrences, weight, profit, new int[]{16, 1, 25}, new int[]{6, 3, 20}).post(); - model.arithm(profit, ">=", 9).post(); - - Solver solver = model.getSolver(); - boolean solutionFound = false; - while (solver.solve()) { - solutionFound = true; - } - - if (!solutionFound) { - Assert.fail(); - } - } - @Test(groups = "10s", timeOut = 60000) public void knapsackTest() { Model m = new Model();