From 96f7b5e10d770631ee35e076f7ff3fc762e73ad4 Mon Sep 17 00:00:00 2001 From: gadaavid Date: Tue, 22 Oct 2024 00:38:05 -0300 Subject: [PATCH 1/5] Add SetExpression and related classes for improved SetVar operations --- .../set/expression/SetVarExpressionTest.java | 372 ++++++++++++++++++ .../discrete/set/BiArSetExpression.java | 58 +++ .../discrete/set/BiReSetExpression.java | 104 +++++ .../discrete/set/SetExpression.java | 70 ++++ .../expression/discrete/set/SetOperator.java | 11 + .../discrete/set/UnReSetExpression.java | 104 +++++ .../variables/impl/SetVarExpression.java | 36 ++ 7 files changed, 755 insertions(+) create mode 100644 examples/src/test/java/org/chocosolver/examples/set/expression/SetVarExpressionTest.java create mode 100644 solver/src/main/java/org/chocosolver/solver/expression/discrete/set/BiArSetExpression.java create mode 100644 solver/src/main/java/org/chocosolver/solver/expression/discrete/set/BiReSetExpression.java create mode 100644 solver/src/main/java/org/chocosolver/solver/expression/discrete/set/SetExpression.java create mode 100644 solver/src/main/java/org/chocosolver/solver/expression/discrete/set/SetOperator.java create mode 100644 solver/src/main/java/org/chocosolver/solver/expression/discrete/set/UnReSetExpression.java create mode 100644 solver/src/main/java/org/chocosolver/solver/variables/impl/SetVarExpression.java diff --git a/examples/src/test/java/org/chocosolver/examples/set/expression/SetVarExpressionTest.java b/examples/src/test/java/org/chocosolver/examples/set/expression/SetVarExpressionTest.java new file mode 100644 index 0000000000..44890de7a6 --- /dev/null +++ b/examples/src/test/java/org/chocosolver/examples/set/expression/SetVarExpressionTest.java @@ -0,0 +1,372 @@ +package org.chocosolver.examples.set.expression; + +import org.chocosolver.solver.Model; +import org.chocosolver.solver.exception.ContradictionException; +import org.chocosolver.solver.variables.impl.SetVarExpression; +import org.junit.Test; + +import java.util.Arrays; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class SetVarExpressionTest { + + /** Basic + * ============= Relacional ============= values and sets + * EQ (Equals) -> set = n value | setA = setB + * NE (not equals) -> set != n values | setA != setB + * Contains -> set contains n values | setA contains setB + * NC (Not Contains) -> set notContains n values | setA notContains setB + * SUBSET -> set = is a subset of a SuperSet (values or set) + * + * Basic relacionals => and, imp, or... + * + * ============= Basic Arithmetic ============= + * UNION + * INTERSECT + * + * Simple and Compound -> a.eq((b.intersection(c.union(d)).union(e.intersection(f))).intersection(g) + * + * Another functions + * setCard - set Cardinality + * notEmpty - a set can't empty + * Empty + */ + + @Test + public void notEmptyTest() throws ContradictionException{ + Model model = new Model(); + SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{0, 1, 2, 3}); + +// model.notEmpty(setA).post(); Choco + setA.notEmpty().post(); + + model.getSolver().propagate(); + + model.notMember(0, setA).post(); + model.notMember(1, setA).post(); + model.notMember(3, setA).post(); + + model.getSolver().propagate(); + + assertTrue(setA.getValue().toArray()[0] == 2); + } + + @Test() + public void setCardTest() throws ContradictionException { + Model model = new Model(); + SetVarExpression setA = new SetVarExpression(model,"setA",new int[]{}, new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9}); + +// setA.setCard(model.intVar(4)); Choco + setA.setCard(4).post(); + + int nbSol = 0; + while(model.getSolver().solve()) { + nbSol++; + assertEquals(setA.getValue().size(), 4); + } + + model.getSolver().propagate(); + + assertEquals(nbSol, 126); // binomial coefficient, 4 in 9 + } + + @Test() + public void simpleEQTest01() throws ContradictionException { + Model model = new Model(); + SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{1,2}); + setA.eq(1).post(); + + model.getSolver().propagate(); + + assertTrue(Arrays.equals(setA.getValue().toArray(), new int[] {1})); + } + + @Test() + public void simpleEQTest02() throws ContradictionException { + Model model = new Model(); + SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{1,2}); + SetVarExpression setB = new SetVarExpression(model,"setB", new int[]{}, new int[]{1,2}); + setA.eq(1).imp(setB.eq(2)).post(); + setA.eq(1).post(); + + model.getSolver().propagate(); + + assertTrue(Arrays.equals(setA.getValue().toArray(), new int[] {1})); + assertTrue(Arrays.equals(setB.getValue().toArray(), new int[] {2})); + } + + @Test() + public void simpleEQTest03() throws ContradictionException { + Model model = new Model(); + SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{0,1,2,3,4,5,6,7,8,9}); + setA.eq(1,2,3).post(); + + model.getSolver().propagate(); + + assertTrue(Arrays.equals(setA.getValue().toArray(), new int[] {1,2,3})); + } + + @Test() + public void simpleNETest01() throws ContradictionException { + Model model = new Model(); + SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{1,2}); + SetVarExpression setB = new SetVarExpression(model,"setB", new int[]{}, new int[]{1,2}); + setA.eq(2).post(); + setA.ne(1).imp(setB.eq(2)).post(); + + model.getSolver().propagate(); + + assertTrue(Arrays.equals(setA.getValue().toArray(), new int[] {2})); + assertTrue(Arrays.equals(setB.getValue().toArray(), new int[] {2})); + } + + @Test() + public void simpleContainsTest01() throws ContradictionException { + Model model = new Model(); + SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{0,1,2,3,4,5,6,7,8,9}); + setA.contains(1,2,3).post(); + + model.getSolver().propagate(); + + assertTrue(Arrays.equals(setA.getLB().toArray(), new int[] {1,2,3})); + } + + @Test() + public void simpleNotContainsTest01() throws ContradictionException { + Model model = new Model(); + SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{0,1,2,3,4,5,6,7,8,9}); + setA.notContains(1,2,3).post(); + + model.getSolver().propagate(); + + assertTrue(Arrays.equals(setA.getUB().toArray(), new int[] {0,4,5,6,7,8,9})); + } + + + @Test() + public void simpleSubSetTest01() throws ContradictionException { + Model model = new Model(); + SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{0,1,2,3,4,5,6,7,8,9}); + setA.subSet(1,2,3,4,5).post(); + + model.getSolver().propagate(); + + assertTrue(Arrays.equals(setA.getUB().toArray(), new int[] {1,2,3,4,5})); + + setA.notEmpty().post(); + setA.notContains(4,5).post(); + model.getSolver().propagate(); + + assertTrue(Arrays.equals(setA.getUB().toArray(), new int[] {1,2,3})); + } + + @Test() + public void biEqTest01() throws ContradictionException { + Model model = new Model(); + SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{1,2,3,4,5}); + SetVarExpression setB = new SetVarExpression(model,"setB", new int[]{}, new int[]{1,2,3,4,5}); + setA.eq(setB).post(); + + setA.eq(1,2).post(); + + model.getSolver().propagate(); + + assertTrue(Arrays.equals(setA.getValue().toArray(), new int[] {1,2})); + assertTrue(Arrays.equals(setB.getValue().toArray(), new int[] {1,2})); + } + + @Test() + public void biEQTest02() throws ContradictionException { + Model model = new Model(); + SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{1,2,3,4,5}); + SetVarExpression setB = new SetVarExpression(model,"setB", new int[]{}, new int[]{1,2,3,4,5}); + SetVarExpression setC = new SetVarExpression(model,"setC", new int[]{}, new int[]{1,2,3,4,5}); + SetVarExpression setD = new SetVarExpression(model,"setD", new int[]{}, new int[]{1,2,3,4,5}); + setA.eq(setB).imp(setC.eq(setD)).post(); + setA.eq(1,2,3).post(); + setB.eq(1,2,3).post(); + setC.eq(4,5).post(); + + model.getSolver().propagate(); + + assertTrue(Arrays.equals(setA.getValue().toArray(), new int[] {1,2,3})); + assertTrue(Arrays.equals(setB.getValue().toArray(), new int[] {1,2,3})); + assertTrue(Arrays.equals(setC.getValue().toArray(), new int[] {4,5})); + assertTrue(Arrays.equals(setD.getValue().toArray(), new int[] {4,5})); + } + + @Test() + public void biEQTest03() throws ContradictionException { + Model model = new Model(); + SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{0,1,2,3,4,5,6,7,8,9}); + SetVarExpression setB = new SetVarExpression(model,"setB", 1,2,3); + setA.eq(setB).post(); + + model.getSolver().propagate(); + + assertTrue(Arrays.equals(setA.getValue().toArray(), setB.getValue().toArray())); + } + + @Test() + public void biNETest01() throws ContradictionException { + Model model = new Model(); + SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{1,2,3,4,5}); + SetVarExpression setB = new SetVarExpression(model,"setB", new int[]{}, new int[]{1,2,3,4,5}); + SetVarExpression setC = new SetVarExpression(model,"setC", 3,4); + SetVarExpression setD = new SetVarExpression(model,"setD", 1,2); + + setA.eq(setC).post(); + setA.ne(setD).imp(setB.eq(setD)).post(); + + model.getSolver().propagate(); + + assertTrue(Arrays.equals(setA.getValue().toArray(), new int[] {3,4})); + assertTrue(Arrays.equals(setB.getValue().toArray(), new int[] {1,2})); + } + + @Test() + public void biContainsTest01() throws ContradictionException { + Model model = new Model(); + SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{0,1,2,3,4,5,6,7,8,9}); + SetVarExpression setB = new SetVarExpression(model,"setB", new int[]{}, new int[]{0,1,2,3,4,5,6,7,8,9}); + setA.contains(setB).post(); + setB.eq(1,2,3).post(); + + model.getSolver().propagate(); + + assertTrue(Arrays.equals(setB.getValue().toArray(), new int[] {1,2,3})); + assertTrue(Arrays.equals(setA.getLB().toArray(), new int[] {1,2,3})); + assertTrue(Arrays.equals(setA.getUB().toArray(), new int[] {0,1,2,3,4,5,6,7,8,9})); + } + + + @Test() + public void biNotContainsTest01() throws ContradictionException { + Model model = new Model(); + SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{0,1,2,3,4,5,6,7,8,9}); + SetVarExpression setB = new SetVarExpression(model,"setB", new int[]{}, new int[]{0,1,2,3,4,5,6,7,8,9}); + setA.notContains(setB).post(); + setB.eq(1,2,3).post(); + + model.getSolver().propagate(); + + assertTrue(Arrays.equals(setA.getUB().toArray(), new int[] {0,4,5,6,7,8,9})); + } + + @Test() + public void biSubSetTest01() throws ContradictionException { + Model model = new Model(); + SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{0,1,2,3,4,5,6,7,8,9}); + SetVarExpression setB = new SetVarExpression(model,"setB", new int[]{}, new int[]{1,2,3,4,5}); + setA.subSet(setB).post(); + + model.getSolver().propagate(); + + assertTrue(Arrays.equals(setA.getUB().toArray(), new int[] {1,2,3,4,5})); + assertTrue(Arrays.equals(setB.getUB().toArray(), new int[] {1,2,3,4,5})); + + setA.notEmpty().post(); + setA.notContains(4,5).post(); + model.getSolver().propagate(); + + assertTrue(Arrays.equals(setA.getUB().toArray(), new int[] {1,2,3})); + assertTrue(Arrays.equals(setB.getUB().toArray(), new int[] {1,2,3,4,5})); + } + + @Test() + public void unionTest01() throws ContradictionException { + Model model = new Model(); + SetVarExpression setC = new SetVarExpression(model,"setC", new int[]{}, new int[]{1,3,5,7,9,11,13}); + SetVarExpression setD = new SetVarExpression(model,"setD", new int[]{}, new int[]{4,5,6,7,10,12,14}); + SetVarExpression setCD = new SetVarExpression(model,"setCD", new int[]{}, new int[]{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}); + + setCD.eq(setC.union(setD)).post(); + model.getSolver().propagate(); + + assertTrue(Arrays.equals(setCD.getUB().toArray(), new int[] {1, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14})); + } + + @Test() + public void intersectTest01() throws ContradictionException { + Model model = new Model(); + SetVarExpression setCD = new SetVarExpression(model,"CD", new int[]{}, new int[]{1, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14}); + SetVarExpression setB = new SetVarExpression(model,"setB", new int[]{}, new int[]{2,4,6,8,10,12,14}); + SetVarExpression setBCD = new SetVarExpression(model,"setBCD", new int[]{}, new int[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14}); + + setBCD.eq(setB.intersection(setCD)).post(); + model.getSolver().propagate(); + + assertTrue(Arrays.equals(setBCD.getUB().toArray(), new int[] {4,6,10,12,14})); + } + + @Test() + public void intersectAndUnionTest01() throws ContradictionException { + Model model = new Model(); + SetVarExpression setC = new SetVarExpression(model,"setC", new int[]{}, new int[]{1,3,5,7,9,11,13}); + SetVarExpression setD = new SetVarExpression(model,"setD", new int[]{}, new int[]{4,5,6,7,10,12,14}); + SetVarExpression setB = new SetVarExpression(model,"setB", new int[]{}, new int[]{2,4,6,8,10,12,14}); + SetVarExpression setBCD = new SetVarExpression(model,"setBCD", new int[]{}, new int[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14}); + + setBCD.eq(setB.intersection(setC.union(setD))).post(); + model.getSolver().propagate(); + + assertTrue(Arrays.equals(setBCD.getUB().toArray(), new int[] {4,6,10,12,14})); + } + + @Test() + public void intersectTest02() throws ContradictionException { + Model model = new Model(); + SetVarExpression setE = new SetVarExpression(model,"setE", new int[]{}, new int[]{3,5,9,11,15,17,19}); + SetVarExpression setF = new SetVarExpression(model,"setF", new int[]{}, new int[]{4,8,12,16,20}); + SetVarExpression setEF = new SetVarExpression(model,"setEF", new int[]{}, new int[]{3,4,5,8,9,11,12,15,16,17,19,20}); + + setEF.eq(setE.intersection(setF)).post(); + model.getSolver().propagate(); + + assertTrue(Arrays.equals(setEF.getUB().toArray(), new int[] {})); + } + + + @Test() + public void intersectAndUnionTest02() throws ContradictionException { + Model model = new Model(); + SetVarExpression setE = new SetVarExpression(model,"setE", new int[]{}, new int[]{3,5,9,11,15,17,19}); + SetVarExpression setF = new SetVarExpression(model,"setF", new int[]{}, new int[]{4,8,12,16,20}); + SetVarExpression setC = new SetVarExpression(model,"setC", new int[]{}, new int[]{1,3,5,7,9,11,13}); + SetVarExpression setD = new SetVarExpression(model,"setD", new int[]{}, new int[]{4,5,6,7,10,12,14}); + SetVarExpression setB = new SetVarExpression(model,"setB", new int[]{}, new int[]{2,4,6,8,10,12,14}); + + SetVarExpression setBCDEF = new SetVarExpression(model,"setBCDEF", new int[]{}, new int[]{ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 20}); + + setBCDEF.eq((setB.intersection(setC.union(setD)).union(setE.intersection(setF)))).post(); + model.getSolver().propagate(); + + assertTrue(Arrays.equals(setBCDEF.getUB().toArray(), new int[] {4,6,10,12,14})); + } + + @Test() + public void setExpressionTest01() throws ContradictionException { + Model model = new Model(); + SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{1,2,3,4,5,6,7}); + SetVarExpression setB = new SetVarExpression(model,"setB", new int[]{}, new int[]{2,4,6,8,10,12,14}); + SetVarExpression setC = new SetVarExpression(model,"setC", new int[]{}, new int[]{1,3,5,7,9,11,13}); + SetVarExpression setD = new SetVarExpression(model,"setD", new int[]{}, new int[]{4,5,6,7,10,12,14}); + SetVarExpression setE = new SetVarExpression(model,"setE", new int[]{}, new int[]{3,5,9,11,15,17,19}); + SetVarExpression setF = new SetVarExpression(model,"setF", new int[]{}, new int[]{4,8,12,16,20}); + SetVarExpression setG = new SetVarExpression(model,"setG", new int[]{}, new int[]{2,6,10,14,18}); + + setA.eq((setB.intersection(setC.union(setD)).union(setE.intersection(setF))).intersection(setG)).post(); + model.getSolver().propagate(); + + assertTrue(Arrays.equals(setA.getUB().toArray(), new int[] {6})); + assertTrue(Arrays.equals(setB.getUB().toArray(), new int[] {2, 4, 6, 8, 10, 12, 14})); + assertTrue(Arrays.equals(setC.getUB().toArray(), new int[] {1, 3, 5, 7, 9, 11, 13})); + assertTrue(Arrays.equals(setD.getUB().toArray(), new int[] {4, 5, 6, 7, 10, 12, 14})); + assertTrue(Arrays.equals(setE.getUB().toArray(), new int[] {3, 5, 9, 11, 15, 17, 19})); + assertTrue(Arrays.equals(setF.getUB().toArray(), new int[] {4, 8, 12, 16, 20})); + assertTrue(Arrays.equals(setG.getUB().toArray(), new int[] {2, 6, 10, 14, 18})); + } +} diff --git a/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/BiArSetExpression.java b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/BiArSetExpression.java new file mode 100644 index 0000000000..a4b3e949c7 --- /dev/null +++ b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/BiArSetExpression.java @@ -0,0 +1,58 @@ +package org.chocosolver.solver.expression.discrete.set; + +import org.chocosolver.solver.Model; +import org.chocosolver.solver.variables.SetVar; + +import java.util.Arrays; +import java.util.stream.IntStream; + +/** + * BiArSetExpression - Binary Arithmetic Set Expression + * + * This class represents a binary arithmetic expression between two SetVarExpression instances. + * It supports set operations such as union (UNION) and intersection (INTERSECTION), + * returning a new SetVar as the result of the operation. + * + * Example: + * setA.eq(setB.union(setC)).post(); + * setA.eq(setB.intersection(setC)).post(); + */ + +public class BiArSetExpression implements SetExpression { + + private SetOperator op; + private SetExpression x; + private SetExpression y; + private Model model; + private SetVar xSet, ySet, resultSet; + + public BiArSetExpression(SetOperator operator, SetExpression x, SetExpression y) { + this.op = operator; + this.x = x; + this.y = y; + this.xSet = x.getSetVar(); + this.ySet = y.getSetVar(); + + this.model = xSet.getModel(); + } + + @Override + public SetVar getSetVar() { + if (resultSet == null) { + int[] setDomain = IntStream.concat(Arrays.stream(xSet.getUB().toArray()), Arrays.stream(ySet.getUB().toArray())).toArray(); + resultSet = model.setVar(model.generateName("aux_setvar_"), new int[]{}, setDomain); + + switch (op) { + case UNION: + model.union(new SetVar[]{xSet, ySet}, resultSet).post(); + break; + case INTERSECTION: + model.intersection(new SetVar[]{xSet, ySet}, resultSet).post(); + break; + default: + throw new UnsupportedOperationException("Unsupported SetOperator: " + op); + } + } + return resultSet; + } +} diff --git a/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/BiReSetExpression.java b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/BiReSetExpression.java new file mode 100644 index 0000000000..4bf3e50e45 --- /dev/null +++ b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/BiReSetExpression.java @@ -0,0 +1,104 @@ +package org.chocosolver.solver.expression.discrete.set; + + +import org.chocosolver.solver.Model; +import org.chocosolver.solver.constraints.Constraint; +import org.chocosolver.solver.expression.discrete.relational.ReExpression; +import org.chocosolver.solver.variables.BoolVar; +import org.chocosolver.solver.variables.IntVar; +import org.chocosolver.solver.variables.SetVar; + +import java.util.HashSet; + +import static org.chocosolver.solver.constraints.real.Ibex.TRUE; + +/** + * BiReSetExpression - Binary Relational Set Expression + * + * This class represents a binary relational expression between two SetVarExpression instances. + * It supports relational operations such as equality (EQ), inequality (NE), subset (SUBSET), + * and containment (CONTAINS). The operations can be composed and posted as constraints. + * + * Example: + * setA.eq(setB).post(); + * setA.ne(setB).post(); + */ +public class BiReSetExpression implements ReExpression { + + private SetOperator op; + private SetExpression x; + private SetExpression y; + private Model model; + private SetVar xSet, ySet; + + private Constraint constraint; + + private BoolVar result; + + public BiReSetExpression(SetOperator operator, SetExpression x, SetExpression y) { + this.op = operator; + this.model = x.getModel(); + this.x = x; + this.y = y; + this.xSet = x.getSetVar(); + this.ySet = y.getSetVar(); + } + + public Model getModel() { + return this.model; + } + + @Override + public BoolVar boolVar() { + if (result == null) { + switch (op) { + case SUBSET: + result = model.subsetEq(xSet, ySet).reify().eq(TRUE).boolVar(); + break; + case EQ: + result = model.allEqual(xSet, ySet).reify().eq(TRUE).boolVar(); + break; + case NE: + result = model.allDifferent(xSet, ySet).reify().eq(TRUE).boolVar(); + break; + case CONTAINS: + result = model.subsetEq(ySet, xSet).reify().eq(TRUE).boolVar(); + break; + case NC: + result = model.disjoint(ySet, xSet).reify().eq(TRUE).boolVar(); + break; + default: + throw new UnsupportedOperationException("Unsupported SetOperator: " + op); + } + } + return result; + } + + @Override + public void extractVar(HashSet variables) { + } + + @Override + public Constraint decompose() { + switch (op) { + case SUBSET: + constraint = model.subsetEq(xSet, ySet); + break; + case EQ: + constraint = model.allEqual(xSet, ySet); + break; + case NE: + constraint = model.allDifferent(xSet, ySet); + break; + case CONTAINS: + constraint = model.subsetEq(ySet, xSet); + break; + case NC: + constraint = model.disjoint(xSet,ySet); + break; + default: + throw new UnsupportedOperationException("Unsupported SetOperator: " + op); + } + return constraint; + } +} \ No newline at end of file diff --git a/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/SetExpression.java b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/SetExpression.java new file mode 100644 index 0000000000..9c15acae3e --- /dev/null +++ b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/SetExpression.java @@ -0,0 +1,70 @@ +package org.chocosolver.solver.expression.discrete.set; + +import org.chocosolver.solver.Model; +import org.chocosolver.solver.constraints.Constraint; +import org.chocosolver.solver.expression.discrete.relational.ReExpression; +import org.chocosolver.solver.expression.discrete.relational.UnCReExpression; +import org.chocosolver.solver.variables.SetVar; + +public interface SetExpression { + default SetExpression union(SetExpression y){ + return new BiArSetExpression(SetOperator.UNION, this, y); + } + + default SetExpression intersection(SetExpression y){ + return new BiArSetExpression(SetOperator.INTERSECTION, this, y); + } + default ReExpression subSet(SetExpression y) { + return new BiReSetExpression(SetOperator.SUBSET, this, y); + } + default ReExpression eq(SetExpression y) { + return new BiReSetExpression(SetOperator.EQ, this, y); + } + default ReExpression ne(SetExpression y) { + return new BiReSetExpression(SetOperator.NE, this, y); + } + default ReExpression contains(SetExpression y) { + return new BiReSetExpression(SetOperator.CONTAINS, this, y); + } + + default ReExpression notContains(SetExpression y) { + return new BiReSetExpression(SetOperator.NC, this, y); + } + + + default ReExpression subSet(int...y) { + return new UnReSetExpression(SetOperator.SUBSET, this, y); + } + default ReExpression eq(int...y) { + return new UnReSetExpression(SetOperator.EQ, this, y); + } + + default ReExpression notContains(int...y) { + return new UnReSetExpression(SetOperator.NC, this, y); + } + + default ReExpression contains(int...y) { + return new UnReSetExpression(SetOperator.CONTAINS, this, y); + } + + default ReExpression ne(int...y) { + return new UnReSetExpression(SetOperator.NE, this, y); + } + + default Constraint notEmpty(){ + SetVar set = this.getSetVar(); + return getModel().notEmpty(set); + } + + default UnCReExpression setCard(int valueCard){ + SetVar set = this.getSetVar(); + return set.getCard().eq(valueCard); + } + + SetVar getSetVar(); + + default Model getModel() { + throw new UnsupportedOperationException("getModel() is not supported in this context"); + } + +} \ No newline at end of file diff --git a/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/SetOperator.java b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/SetOperator.java new file mode 100644 index 0000000000..741fbfe93e --- /dev/null +++ b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/SetOperator.java @@ -0,0 +1,11 @@ +package org.chocosolver.solver.expression.discrete.set; + +public enum SetOperator { + SUBSET, + EQ, + NE, + CONTAINS, + NC, + UNION, + INTERSECTION +} \ No newline at end of file diff --git a/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/UnReSetExpression.java b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/UnReSetExpression.java new file mode 100644 index 0000000000..3aad6eb364 --- /dev/null +++ b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/UnReSetExpression.java @@ -0,0 +1,104 @@ +package org.chocosolver.solver.expression.discrete.set; + +import org.chocosolver.solver.Model; +import org.chocosolver.solver.constraints.Constraint; +import org.chocosolver.solver.expression.discrete.relational.ReExpression; +import org.chocosolver.solver.variables.BoolVar; +import org.chocosolver.solver.variables.IntVar; +import org.chocosolver.solver.variables.SetVar; + +import java.util.Arrays; +import java.util.HashSet; + +import static org.chocosolver.solver.constraints.real.Ibex.TRUE; + +/** + * UnReSetExpression - Unary Relational Set Expression + * + * This class represents a unary relational expression for a SetVar and a set of values. + * It handles operations like equality (EQ), inequality (NE), subset (SUBSET), and containment (CONTAINS) + * with respect to a fixed set of integers. + * + * Example: + * setA.eq(1,2,3).post(); + * setA.contains(1,2).post(); + */ +public class UnReSetExpression implements ReExpression { + private SetOperator op; + private SetExpression x; + private int[] y; + private Model model; + private SetVar xSet, ySet; + + private Constraint constraint; + + private BoolVar result; + + public UnReSetExpression(SetOperator operator, SetExpression x, int... y) { + this.op = operator; + this.model = x.getModel(); + this.x = x; + this.y = y; + this.xSet = x.getSetVar(); + this.ySet = model.setVar(Arrays.stream(y).toArray()); + } + + public Model getModel() { + return this.model; + } + + @Override + public BoolVar boolVar() { + if (result == null) { + switch (op) { + case SUBSET: + result = model.subsetEq(xSet, ySet).reify().eq(TRUE).boolVar(); + break; + case EQ: + result = model.allEqual(xSet, ySet).reify().eq(TRUE).boolVar(); + break; + case NE: + result = model.allDifferent(xSet, ySet).reify().eq(TRUE).boolVar(); + break; + case CONTAINS: + result = model.subsetEq(ySet, xSet).reify().eq(TRUE).boolVar(); + break; + case NC: + result = model.disjoint(ySet, xSet).reify().eq(TRUE).boolVar(); + break; + default: + throw new UnsupportedOperationException("Unsupported SetOperator: " + op); + } + } + return result; + } + + @Override + public void extractVar(HashSet variables) { + + } + + @Override + public Constraint decompose() { + switch (op) { + case SUBSET: + constraint = model.subsetEq(xSet, ySet); + break; + case EQ: + constraint = model.allEqual(xSet, ySet); + break; + case NE: + constraint = model.allDifferent(xSet, ySet); + break; + case CONTAINS: + constraint = model.subsetEq(ySet, xSet); + break; + case NC: + constraint = model.disjoint(xSet,ySet); + break; + default: + throw new UnsupportedOperationException("Unsupported SetOperator: " + op); + } + return constraint; + } +} \ No newline at end of file diff --git a/solver/src/main/java/org/chocosolver/solver/variables/impl/SetVarExpression.java b/solver/src/main/java/org/chocosolver/solver/variables/impl/SetVarExpression.java new file mode 100644 index 0000000000..39039df455 --- /dev/null +++ b/solver/src/main/java/org/chocosolver/solver/variables/impl/SetVarExpression.java @@ -0,0 +1,36 @@ +package org.chocosolver.solver.variables.impl; + +import org.chocosolver.solver.Model; +import org.chocosolver.solver.expression.discrete.set.SetExpression; +import org.chocosolver.util.objects.setDataStructures.SetType; + + +/** + * SetVarExpression - SetVar Implementation with Expression Support + * + * This class extends SetVar to allow arithmetic and relational operations to be performed + * directly on set variables, facilitating composition of constraints and complex expressions + * such as union, intersection, equality, and subset relations. + * + * Example: + * setA.eq(1,2,3).post(); + * setA.union(setB).post(); + */ + +public class SetVarExpression extends SetVarImpl implements SetExpression { + /** + This class is a copy of SetVarImpl that implements the SetExpression functions. + */ + + public SetVarExpression(Model model, String name, int[] valuesLB, int[] valuesUB){ + super(name, valuesLB, SetType.BITSET, valuesUB, SetType.BITSET, model.ref()); + } + + public SetVarExpression(Model model, String name, int...domain){ + super(name, domain, model.ref()); + } + @Override + public SetVarImpl getSetVar(){ + return this; + } +} \ No newline at end of file From 067b8e9381f8ca3b176b4f56072b7725d407e81f Mon Sep 17 00:00:00 2001 From: gadavidd Date: Thu, 20 Mar 2025 15:42:49 -0300 Subject: [PATCH 2/5] improvements in BiReSetExpression --- .../discrete/set/BiReSetExpression.java | 14 +- .../discrete/set/SetExpression.java | 125 ++++++++++++++++-- .../discrete/set/UnReSetExpression.java | 2 +- 3 files changed, 121 insertions(+), 20 deletions(-) diff --git a/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/BiReSetExpression.java b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/BiReSetExpression.java index 4bf3e50e45..80db64b6fe 100644 --- a/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/BiReSetExpression.java +++ b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/BiReSetExpression.java @@ -1,6 +1,5 @@ package org.chocosolver.solver.expression.discrete.set; - import org.chocosolver.solver.Model; import org.chocosolver.solver.constraints.Constraint; import org.chocosolver.solver.expression.discrete.relational.ReExpression; @@ -10,8 +9,6 @@ import java.util.HashSet; -import static org.chocosolver.solver.constraints.real.Ibex.TRUE; - /** * BiReSetExpression - Binary Relational Set Expression * @@ -53,19 +50,19 @@ public BoolVar boolVar() { if (result == null) { switch (op) { case SUBSET: - result = model.subsetEq(xSet, ySet).reify().eq(TRUE).boolVar(); + result = model.subsetEq(xSet, ySet).reify(); break; case EQ: - result = model.allEqual(xSet, ySet).reify().eq(TRUE).boolVar(); + result = model.allEqual(xSet, ySet).reify(); break; case NE: - result = model.allDifferent(xSet, ySet).reify().eq(TRUE).boolVar(); + result = model.allDifferent(xSet, ySet).reify(); break; case CONTAINS: - result = model.subsetEq(ySet, xSet).reify().eq(TRUE).boolVar(); + result = model.subsetEq(ySet, xSet).reify(); break; case NC: - result = model.disjoint(ySet, xSet).reify().eq(TRUE).boolVar(); + result = model.disjoint(ySet, xSet).reify(); break; default: throw new UnsupportedOperationException("Unsupported SetOperator: " + op); @@ -76,6 +73,7 @@ public BoolVar boolVar() { @Override public void extractVar(HashSet variables) { + throw new UnsupportedOperationException("extractVar() is not supported for BiReSetExpression."); } @Override diff --git a/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/SetExpression.java b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/SetExpression.java index 9c15acae3e..a18a8b1dc3 100644 --- a/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/SetExpression.java +++ b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/SetExpression.java @@ -6,63 +6,166 @@ import org.chocosolver.solver.expression.discrete.relational.UnCReExpression; import org.chocosolver.solver.variables.SetVar; +/** + * Interface for set variable (*SetVar*) expressions. + * This interface enables the construction of relational and arithmetic expressions + * over sets, allowing operations such as union, intersection, and membership checks. + */ + public interface SetExpression { - default SetExpression union(SetExpression y){ + /** + * Returns the union of this set with another set. + * + * @param y the other set expression. + * @return a new expression representing the union. + */ + default SetExpression union(SetExpression y) { return new BiArSetExpression(SetOperator.UNION, this, y); } - default SetExpression intersection(SetExpression y){ + /** + * Returns the intersection of this set with another set. + * + * @param y the other set expression. + * @return a new expression representing the intersection. + */ + default SetExpression intersection(SetExpression y) { return new BiArSetExpression(SetOperator.INTERSECTION, this, y); } + /** + * Checks if this set is a subset of another set. + * + * @param y the other set expression. + * @return a boolean expression representing the subset relationship. + */ default ReExpression subSet(SetExpression y) { return new BiReSetExpression(SetOperator.SUBSET, this, y); } + + /** + * Checks if two sets are equal. + * + * @param y the other set expression. + * @return a boolean expression representing equality. + */ default ReExpression eq(SetExpression y) { return new BiReSetExpression(SetOperator.EQ, this, y); } + + /** + * Checks if two sets are different. + * + * @param y the other set expression. + * @return a boolean expression representing inequality. + */ default ReExpression ne(SetExpression y) { return new BiReSetExpression(SetOperator.NE, this, y); } + + /** + * Checks if this set contains another set. + * + * @param y the other set expression. + * @return a boolean expression representing the containment relation. + */ default ReExpression contains(SetExpression y) { return new BiReSetExpression(SetOperator.CONTAINS, this, y); } - + /** + * Checks if this set does not contain another set. + * + * @param y the other set expression. + * @return a boolean expression representing the non-membership relation. + */ default ReExpression notContains(SetExpression y) { return new BiReSetExpression(SetOperator.NC, this, y); } - - default ReExpression subSet(int...y) { + /** + * Checks if this set is a subset of a given set of integers. + * + * @param y the integer values to check. + * @return a boolean expression representing the subset relationship. + */ + default ReExpression subSet(int... y) { return new UnReSetExpression(SetOperator.SUBSET, this, y); } - default ReExpression eq(int...y) { + + /** + * Checks if this set is equal to a given set of integers. + * + * @param y the integer values to compare. + * @return a boolean expression representing equality. + */ + default ReExpression eq(int... y) { return new UnReSetExpression(SetOperator.EQ, this, y); } - default ReExpression notContains(int...y) { + /** + * Checks if this set does not contain a given set of integers. + * + * @param y the integer values to check. + * @return a boolean expression representing non-membership. + */ + default ReExpression notContains(int... y) { return new UnReSetExpression(SetOperator.NC, this, y); } - default ReExpression contains(int...y) { + /** + * Checks if this set contains a given set of integers. + * + * @param y the integer values to check. + * @return a boolean expression representing membership. + */ + default ReExpression contains(int... y) { return new UnReSetExpression(SetOperator.CONTAINS, this, y); } - default ReExpression ne(int...y) { + /** + * Checks if this set is different from a given set of integers. + * + * @param y the integer values to compare. + * @return a boolean expression representing inequality. + */ + default ReExpression ne(int... y) { return new UnReSetExpression(SetOperator.NE, this, y); } - default Constraint notEmpty(){ + /** + * Returns a constraint ensuring that the set is not empty. + * + * @return a constraint enforcing the non-emptiness of the set. + */ + default Constraint notEmpty() { SetVar set = this.getSetVar(); return getModel().notEmpty(set); } - default UnCReExpression setCard(int valueCard){ + /** + * Constrains the cardinality of the set to be equal to a specific value. + * + * @param valueCard the desired cardinality value. + * @return a unary relational expression enforcing the set cardinality. + */ + default UnCReExpression setCard(int valueCard) { SetVar set = this.getSetVar(); return set.getCard().eq(valueCard); } + /** + * Returns the set variable associated with this expression. + * + * @return the corresponding set variable. + */ SetVar getSetVar(); + /** + * Returns the model associated with this expression. + * + * @return the model of the expression. + * @throws UnsupportedOperationException if this method is not supported. + */ + default Model getModel() { throw new UnsupportedOperationException("getModel() is not supported in this context"); } diff --git a/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/UnReSetExpression.java b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/UnReSetExpression.java index 3aad6eb364..0496d90898 100644 --- a/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/UnReSetExpression.java +++ b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/UnReSetExpression.java @@ -75,7 +75,7 @@ public BoolVar boolVar() { @Override public void extractVar(HashSet variables) { - + throw new UnsupportedOperationException("extractVar() is not supported for UnReSetExpression."); } @Override From 21a83e9367ca57eae474b82db975a7dee248287e Mon Sep 17 00:00:00 2001 From: cprudhom Date: Thu, 28 Aug 2025 18:51:50 +0200 Subject: [PATCH 3/5] SetExpression: alignment of the structure of set expressions with the existing structure for integer expressions. + update headers Suggestion of improvements: detect constraints like `partition(SetVar[] sets, SetVar universe)` --- CONTRIBUTORS | 1 + .../set/expression/SetVarExpressionTest.java | 248 +++++++++--------- ...etExpression.java => ArSetExpression.java} | 87 +++--- .../discrete/set/BiArSetExpression.java | 50 ++-- .../discrete/set/BiReSetExpression.java | 75 +++--- .../expression/discrete/set/SetOperator.java | 18 +- .../discrete/set/UnReSetExpression.java | 104 -------- .../chocosolver/solver/variables/SetVar.java | 10 +- .../variables/impl/SetVarExpression.java | 36 --- 9 files changed, 268 insertions(+), 361 deletions(-) rename solver/src/main/java/org/chocosolver/solver/expression/discrete/set/{SetExpression.java => ArSetExpression.java} (69%) delete mode 100644 solver/src/main/java/org/chocosolver/solver/expression/discrete/set/UnReSetExpression.java delete mode 100644 solver/src/main/java/org/chocosolver/solver/variables/impl/SetVarExpression.java diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 13a5d6b23c..73b4bbda04 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -25,4 +25,5 @@ Mathieu Vavrille, Charles Vernerey, Mohamed Wahbi , Dmitrij Zherebyatev , +Gabriel Augusto David , diff --git a/examples/src/test/java/org/chocosolver/examples/set/expression/SetVarExpressionTest.java b/examples/src/test/java/org/chocosolver/examples/set/expression/SetVarExpressionTest.java index 44890de7a6..13e964d93d 100644 --- a/examples/src/test/java/org/chocosolver/examples/set/expression/SetVarExpressionTest.java +++ b/examples/src/test/java/org/chocosolver/examples/set/expression/SetVarExpressionTest.java @@ -1,33 +1,41 @@ +/* + * This file is part of examples, http://choco-solver.org/ + * + * Copyright (c) 2025, IMT Atlantique. All rights reserved. + * + * Licensed under the BSD 4-clause license. + * + * See LICENSE file in the project root for full license information. + */ package org.chocosolver.examples.set.expression; import org.chocosolver.solver.Model; import org.chocosolver.solver.exception.ContradictionException; -import org.chocosolver.solver.variables.impl.SetVarExpression; +import org.chocosolver.solver.variables.SetVar; import org.junit.Test; -import java.util.Arrays; - +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; public class SetVarExpressionTest { - /** Basic + /** + * Basic * ============= Relacional ============= values and sets * EQ (Equals) -> set = n value | setA = setB * NE (not equals) -> set != n values | setA != setB * Contains -> set contains n values | setA contains setB * NC (Not Contains) -> set notContains n values | setA notContains setB * SUBSET -> set = is a subset of a SuperSet (values or set) - * + *

* Basic relacionals => and, imp, or... - * + *

* ============= Basic Arithmetic ============= * UNION * INTERSECT - * + *

* Simple and Compound -> a.eq((b.intersection(c.union(d)).union(e.intersection(f))).intersection(g) - * + *

* Another functions * setCard - set Cardinality * notEmpty - a set can't empty @@ -35,9 +43,9 @@ public class SetVarExpressionTest { */ @Test - public void notEmptyTest() throws ContradictionException{ + public void notEmptyTest() throws ContradictionException { Model model = new Model(); - SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{0, 1, 2, 3}); + SetVar setA = model.setVar("setA", new int[]{}, new int[]{0, 1, 2, 3}); // model.notEmpty(setA).post(); Choco setA.notEmpty().post(); @@ -50,323 +58,323 @@ public void notEmptyTest() throws ContradictionException{ model.getSolver().propagate(); - assertTrue(setA.getValue().toArray()[0] == 2); + assertEquals(2, setA.getValue().toArray()[0]); } @Test() public void setCardTest() throws ContradictionException { Model model = new Model(); - SetVarExpression setA = new SetVarExpression(model,"setA",new int[]{}, new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9}); + SetVar setA = model.setVar("setA", new int[]{}, new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9}); // setA.setCard(model.intVar(4)); Choco setA.setCard(4).post(); int nbSol = 0; - while(model.getSolver().solve()) { + while (model.getSolver().solve()) { nbSol++; - assertEquals(setA.getValue().size(), 4); + assertEquals(4, setA.getValue().size()); } model.getSolver().propagate(); - assertEquals(nbSol, 126); // binomial coefficient, 4 in 9 + assertEquals(126, nbSol); // binomial coefficient, 4 in 9 } @Test() public void simpleEQTest01() throws ContradictionException { Model model = new Model(); - SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{1,2}); + SetVar setA = model.setVar("setA", new int[]{}, new int[]{1, 2}); setA.eq(1).post(); model.getSolver().propagate(); - assertTrue(Arrays.equals(setA.getValue().toArray(), new int[] {1})); + assertArrayEquals(new int[]{1}, setA.getValue().toArray()); } @Test() public void simpleEQTest02() throws ContradictionException { Model model = new Model(); - SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{1,2}); - SetVarExpression setB = new SetVarExpression(model,"setB", new int[]{}, new int[]{1,2}); + SetVar setA = model.setVar("setA", new int[]{}, new int[]{1, 2}); + SetVar setB = model.setVar("setB", new int[]{}, new int[]{1, 2}); setA.eq(1).imp(setB.eq(2)).post(); setA.eq(1).post(); model.getSolver().propagate(); - assertTrue(Arrays.equals(setA.getValue().toArray(), new int[] {1})); - assertTrue(Arrays.equals(setB.getValue().toArray(), new int[] {2})); + assertArrayEquals(new int[]{1}, setA.getValue().toArray()); + assertArrayEquals(new int[]{2}, setB.getValue().toArray()); } @Test() public void simpleEQTest03() throws ContradictionException { Model model = new Model(); - SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{0,1,2,3,4,5,6,7,8,9}); - setA.eq(1,2,3).post(); + SetVar setA = model.setVar("setA", new int[]{}, new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); + setA.eq(1, 2, 3).post(); model.getSolver().propagate(); - assertTrue(Arrays.equals(setA.getValue().toArray(), new int[] {1,2,3})); + assertArrayEquals(new int[]{1, 2, 3}, setA.getValue().toArray()); } @Test() public void simpleNETest01() throws ContradictionException { Model model = new Model(); - SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{1,2}); - SetVarExpression setB = new SetVarExpression(model,"setB", new int[]{}, new int[]{1,2}); + SetVar setA = model.setVar("setA", new int[]{}, new int[]{1, 2}); + SetVar setB = model.setVar("setB", new int[]{}, new int[]{1, 2}); setA.eq(2).post(); setA.ne(1).imp(setB.eq(2)).post(); model.getSolver().propagate(); - assertTrue(Arrays.equals(setA.getValue().toArray(), new int[] {2})); - assertTrue(Arrays.equals(setB.getValue().toArray(), new int[] {2})); + assertArrayEquals(new int[]{2}, setA.getValue().toArray()); + assertArrayEquals(new int[]{2}, setB.getValue().toArray()); } @Test() public void simpleContainsTest01() throws ContradictionException { Model model = new Model(); - SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{0,1,2,3,4,5,6,7,8,9}); - setA.contains(1,2,3).post(); + SetVar setA = model.setVar("setA", new int[]{}, new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); + setA.contains(1, 2, 3).post(); model.getSolver().propagate(); - assertTrue(Arrays.equals(setA.getLB().toArray(), new int[] {1,2,3})); + assertArrayEquals(new int[]{1, 2, 3}, setA.getLB().toArray()); } @Test() public void simpleNotContainsTest01() throws ContradictionException { Model model = new Model(); - SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{0,1,2,3,4,5,6,7,8,9}); - setA.notContains(1,2,3).post(); + SetVar setA = model.setVar("setA", new int[]{}, new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); + setA.notContains(1, 2, 3).post(); model.getSolver().propagate(); - assertTrue(Arrays.equals(setA.getUB().toArray(), new int[] {0,4,5,6,7,8,9})); + assertArrayEquals(new int[]{0, 4, 5, 6, 7, 8, 9}, setA.getUB().toArray()); } @Test() public void simpleSubSetTest01() throws ContradictionException { Model model = new Model(); - SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{0,1,2,3,4,5,6,7,8,9}); - setA.subSet(1,2,3,4,5).post(); + SetVar setA = model.setVar("setA", new int[]{}, new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); + setA.subSet(1, 2, 3, 4, 5).post(); model.getSolver().propagate(); - assertTrue(Arrays.equals(setA.getUB().toArray(), new int[] {1,2,3,4,5})); + assertArrayEquals(new int[]{1, 2, 3, 4, 5}, setA.getUB().toArray()); setA.notEmpty().post(); - setA.notContains(4,5).post(); + setA.notContains(4, 5).post(); model.getSolver().propagate(); - assertTrue(Arrays.equals(setA.getUB().toArray(), new int[] {1,2,3})); + assertArrayEquals(new int[]{1, 2, 3}, setA.getUB().toArray()); } @Test() public void biEqTest01() throws ContradictionException { Model model = new Model(); - SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{1,2,3,4,5}); - SetVarExpression setB = new SetVarExpression(model,"setB", new int[]{}, new int[]{1,2,3,4,5}); + SetVar setA = model.setVar("setA", new int[]{}, new int[]{1, 2, 3, 4, 5}); + SetVar setB = model.setVar("setB", new int[]{}, new int[]{1, 2, 3, 4, 5}); setA.eq(setB).post(); - setA.eq(1,2).post(); + setA.eq(1, 2).post(); model.getSolver().propagate(); - assertTrue(Arrays.equals(setA.getValue().toArray(), new int[] {1,2})); - assertTrue(Arrays.equals(setB.getValue().toArray(), new int[] {1,2})); + assertArrayEquals(new int[]{1, 2}, setA.getValue().toArray()); + assertArrayEquals(new int[]{1, 2}, setB.getValue().toArray()); } @Test() public void biEQTest02() throws ContradictionException { Model model = new Model(); - SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{1,2,3,4,5}); - SetVarExpression setB = new SetVarExpression(model,"setB", new int[]{}, new int[]{1,2,3,4,5}); - SetVarExpression setC = new SetVarExpression(model,"setC", new int[]{}, new int[]{1,2,3,4,5}); - SetVarExpression setD = new SetVarExpression(model,"setD", new int[]{}, new int[]{1,2,3,4,5}); + SetVar setA = model.setVar("setA", new int[]{}, new int[]{1, 2, 3, 4, 5}); + SetVar setB = model.setVar("setB", new int[]{}, new int[]{1, 2, 3, 4, 5}); + SetVar setC = model.setVar("setC", new int[]{}, new int[]{1, 2, 3, 4, 5}); + SetVar setD = model.setVar("setD", new int[]{}, new int[]{1, 2, 3, 4, 5}); setA.eq(setB).imp(setC.eq(setD)).post(); - setA.eq(1,2,3).post(); - setB.eq(1,2,3).post(); - setC.eq(4,5).post(); + setA.eq(1, 2, 3).post(); + setB.eq(1, 2, 3).post(); + setC.eq(4, 5).post(); model.getSolver().propagate(); - assertTrue(Arrays.equals(setA.getValue().toArray(), new int[] {1,2,3})); - assertTrue(Arrays.equals(setB.getValue().toArray(), new int[] {1,2,3})); - assertTrue(Arrays.equals(setC.getValue().toArray(), new int[] {4,5})); - assertTrue(Arrays.equals(setD.getValue().toArray(), new int[] {4,5})); + assertArrayEquals(new int[]{1, 2, 3}, setA.getValue().toArray()); + assertArrayEquals(new int[]{1, 2, 3}, setB.getValue().toArray()); + assertArrayEquals(new int[]{4, 5}, setC.getValue().toArray()); + assertArrayEquals(new int[]{4, 5}, setD.getValue().toArray()); } @Test() public void biEQTest03() throws ContradictionException { Model model = new Model(); - SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{0,1,2,3,4,5,6,7,8,9}); - SetVarExpression setB = new SetVarExpression(model,"setB", 1,2,3); + SetVar setA = model.setVar("setA", new int[]{}, new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); + SetVar setB = model.setVar("setB", 1, 2, 3); setA.eq(setB).post(); model.getSolver().propagate(); - assertTrue(Arrays.equals(setA.getValue().toArray(), setB.getValue().toArray())); + assertArrayEquals(setA.getValue().toArray(), setB.getValue().toArray()); } @Test() public void biNETest01() throws ContradictionException { Model model = new Model(); - SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{1,2,3,4,5}); - SetVarExpression setB = new SetVarExpression(model,"setB", new int[]{}, new int[]{1,2,3,4,5}); - SetVarExpression setC = new SetVarExpression(model,"setC", 3,4); - SetVarExpression setD = new SetVarExpression(model,"setD", 1,2); + SetVar setA = model.setVar("setA", new int[]{}, new int[]{1, 2, 3, 4, 5}); + SetVar setB = model.setVar("setB", new int[]{}, new int[]{1, 2, 3, 4, 5}); + SetVar setC = model.setVar("setC", 3, 4); + SetVar setD = model.setVar("setD", 1, 2); setA.eq(setC).post(); setA.ne(setD).imp(setB.eq(setD)).post(); model.getSolver().propagate(); - assertTrue(Arrays.equals(setA.getValue().toArray(), new int[] {3,4})); - assertTrue(Arrays.equals(setB.getValue().toArray(), new int[] {1,2})); + assertArrayEquals(new int[]{3, 4}, setA.getValue().toArray()); + assertArrayEquals(new int[]{1, 2}, setB.getValue().toArray()); } @Test() public void biContainsTest01() throws ContradictionException { Model model = new Model(); - SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{0,1,2,3,4,5,6,7,8,9}); - SetVarExpression setB = new SetVarExpression(model,"setB", new int[]{}, new int[]{0,1,2,3,4,5,6,7,8,9}); + SetVar setA = model.setVar("setA", new int[]{}, new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); + SetVar setB = model.setVar("setB", new int[]{}, new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); setA.contains(setB).post(); - setB.eq(1,2,3).post(); + setB.eq(1, 2, 3).post(); model.getSolver().propagate(); - assertTrue(Arrays.equals(setB.getValue().toArray(), new int[] {1,2,3})); - assertTrue(Arrays.equals(setA.getLB().toArray(), new int[] {1,2,3})); - assertTrue(Arrays.equals(setA.getUB().toArray(), new int[] {0,1,2,3,4,5,6,7,8,9})); + assertArrayEquals(new int[]{1, 2, 3}, setB.getValue().toArray()); + assertArrayEquals(new int[]{1, 2, 3}, setA.getLB().toArray()); + assertArrayEquals(new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, setA.getUB().toArray()); } @Test() public void biNotContainsTest01() throws ContradictionException { Model model = new Model(); - SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{0,1,2,3,4,5,6,7,8,9}); - SetVarExpression setB = new SetVarExpression(model,"setB", new int[]{}, new int[]{0,1,2,3,4,5,6,7,8,9}); + SetVar setA = model.setVar("setA", new int[]{}, new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); + SetVar setB = model.setVar("setB", new int[]{}, new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); setA.notContains(setB).post(); - setB.eq(1,2,3).post(); + setB.eq(1, 2, 3).post(); model.getSolver().propagate(); - assertTrue(Arrays.equals(setA.getUB().toArray(), new int[] {0,4,5,6,7,8,9})); + assertArrayEquals(new int[]{0, 4, 5, 6, 7, 8, 9}, setA.getUB().toArray()); } @Test() public void biSubSetTest01() throws ContradictionException { Model model = new Model(); - SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{0,1,2,3,4,5,6,7,8,9}); - SetVarExpression setB = new SetVarExpression(model,"setB", new int[]{}, new int[]{1,2,3,4,5}); + SetVar setA = model.setVar("setA", new int[]{}, new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); + SetVar setB = model.setVar("setB", new int[]{}, new int[]{1, 2, 3, 4, 5}); setA.subSet(setB).post(); model.getSolver().propagate(); - assertTrue(Arrays.equals(setA.getUB().toArray(), new int[] {1,2,3,4,5})); - assertTrue(Arrays.equals(setB.getUB().toArray(), new int[] {1,2,3,4,5})); + assertArrayEquals(new int[]{1, 2, 3, 4, 5}, setA.getUB().toArray()); + assertArrayEquals(new int[]{1, 2, 3, 4, 5}, setB.getUB().toArray()); setA.notEmpty().post(); - setA.notContains(4,5).post(); + setA.notContains(4, 5).post(); model.getSolver().propagate(); - assertTrue(Arrays.equals(setA.getUB().toArray(), new int[] {1,2,3})); - assertTrue(Arrays.equals(setB.getUB().toArray(), new int[] {1,2,3,4,5})); + assertArrayEquals(new int[]{1, 2, 3}, setA.getUB().toArray()); + assertArrayEquals(new int[]{1, 2, 3, 4, 5}, setB.getUB().toArray()); } @Test() public void unionTest01() throws ContradictionException { Model model = new Model(); - SetVarExpression setC = new SetVarExpression(model,"setC", new int[]{}, new int[]{1,3,5,7,9,11,13}); - SetVarExpression setD = new SetVarExpression(model,"setD", new int[]{}, new int[]{4,5,6,7,10,12,14}); - SetVarExpression setCD = new SetVarExpression(model,"setCD", new int[]{}, new int[]{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}); + SetVar setC = model.setVar("setC", new int[]{}, new int[]{1, 3, 5, 7, 9, 11, 13}); + SetVar setD = model.setVar("setD", new int[]{}, new int[]{4, 5, 6, 7, 10, 12, 14}); + SetVar setCD = model.setVar("setCD", new int[]{}, new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}); setCD.eq(setC.union(setD)).post(); model.getSolver().propagate(); - assertTrue(Arrays.equals(setCD.getUB().toArray(), new int[] {1, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14})); + assertArrayEquals(new int[]{1, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14}, setCD.getUB().toArray()); } @Test() public void intersectTest01() throws ContradictionException { Model model = new Model(); - SetVarExpression setCD = new SetVarExpression(model,"CD", new int[]{}, new int[]{1, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14}); - SetVarExpression setB = new SetVarExpression(model,"setB", new int[]{}, new int[]{2,4,6,8,10,12,14}); - SetVarExpression setBCD = new SetVarExpression(model,"setBCD", new int[]{}, new int[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14}); + SetVar setCD = model.setVar("CD", new int[]{}, new int[]{1, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14}); + SetVar setB = model.setVar("setB", new int[]{}, new int[]{2, 4, 6, 8, 10, 12, 14}); + SetVar setBCD = model.setVar("setBCD", new int[]{}, new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}); setBCD.eq(setB.intersection(setCD)).post(); model.getSolver().propagate(); - assertTrue(Arrays.equals(setBCD.getUB().toArray(), new int[] {4,6,10,12,14})); + assertArrayEquals(new int[]{4, 6, 10, 12, 14}, setBCD.getUB().toArray()); } @Test() public void intersectAndUnionTest01() throws ContradictionException { Model model = new Model(); - SetVarExpression setC = new SetVarExpression(model,"setC", new int[]{}, new int[]{1,3,5,7,9,11,13}); - SetVarExpression setD = new SetVarExpression(model,"setD", new int[]{}, new int[]{4,5,6,7,10,12,14}); - SetVarExpression setB = new SetVarExpression(model,"setB", new int[]{}, new int[]{2,4,6,8,10,12,14}); - SetVarExpression setBCD = new SetVarExpression(model,"setBCD", new int[]{}, new int[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14}); + SetVar setC = model.setVar("setC", new int[]{}, new int[]{1, 3, 5, 7, 9, 11, 13}); + SetVar setD = model.setVar("setD", new int[]{}, new int[]{4, 5, 6, 7, 10, 12, 14}); + SetVar setB = model.setVar("setB", new int[]{}, new int[]{2, 4, 6, 8, 10, 12, 14}); + SetVar setBCD = model.setVar("setBCD", new int[]{}, new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}); setBCD.eq(setB.intersection(setC.union(setD))).post(); model.getSolver().propagate(); - assertTrue(Arrays.equals(setBCD.getUB().toArray(), new int[] {4,6,10,12,14})); + assertArrayEquals(new int[]{4, 6, 10, 12, 14}, setBCD.getUB().toArray()); } @Test() public void intersectTest02() throws ContradictionException { Model model = new Model(); - SetVarExpression setE = new SetVarExpression(model,"setE", new int[]{}, new int[]{3,5,9,11,15,17,19}); - SetVarExpression setF = new SetVarExpression(model,"setF", new int[]{}, new int[]{4,8,12,16,20}); - SetVarExpression setEF = new SetVarExpression(model,"setEF", new int[]{}, new int[]{3,4,5,8,9,11,12,15,16,17,19,20}); + SetVar setE = model.setVar("setE", new int[]{}, new int[]{3, 5, 9, 11, 15, 17, 19}); + SetVar setF = model.setVar("setF", new int[]{}, new int[]{4, 8, 12, 16, 20}); + SetVar setEF = model.setVar("setEF", new int[]{}, new int[]{3, 4, 5, 8, 9, 11, 12, 15, 16, 17, 19, 20}); setEF.eq(setE.intersection(setF)).post(); model.getSolver().propagate(); - assertTrue(Arrays.equals(setEF.getUB().toArray(), new int[] {})); + assertArrayEquals(new int[]{}, setEF.getUB().toArray()); } @Test() public void intersectAndUnionTest02() throws ContradictionException { Model model = new Model(); - SetVarExpression setE = new SetVarExpression(model,"setE", new int[]{}, new int[]{3,5,9,11,15,17,19}); - SetVarExpression setF = new SetVarExpression(model,"setF", new int[]{}, new int[]{4,8,12,16,20}); - SetVarExpression setC = new SetVarExpression(model,"setC", new int[]{}, new int[]{1,3,5,7,9,11,13}); - SetVarExpression setD = new SetVarExpression(model,"setD", new int[]{}, new int[]{4,5,6,7,10,12,14}); - SetVarExpression setB = new SetVarExpression(model,"setB", new int[]{}, new int[]{2,4,6,8,10,12,14}); + SetVar setE = model.setVar("setE", new int[]{}, new int[]{3, 5, 9, 11, 15, 17, 19}); + SetVar setF = model.setVar("setF", new int[]{}, new int[]{4, 8, 12, 16, 20}); + SetVar setC = model.setVar("setC", new int[]{}, new int[]{1, 3, 5, 7, 9, 11, 13}); + SetVar setD = model.setVar("setD", new int[]{}, new int[]{4, 5, 6, 7, 10, 12, 14}); + SetVar setB = model.setVar("setB", new int[]{}, new int[]{2, 4, 6, 8, 10, 12, 14}); - SetVarExpression setBCDEF = new SetVarExpression(model,"setBCDEF", new int[]{}, new int[]{ + SetVar setBCDEF = model.setVar("setBCDEF", new int[]{}, new int[]{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 20}); setBCDEF.eq((setB.intersection(setC.union(setD)).union(setE.intersection(setF)))).post(); model.getSolver().propagate(); - assertTrue(Arrays.equals(setBCDEF.getUB().toArray(), new int[] {4,6,10,12,14})); + assertArrayEquals(new int[]{4, 6, 10, 12, 14}, setBCDEF.getUB().toArray()); } @Test() public void setExpressionTest01() throws ContradictionException { Model model = new Model(); - SetVarExpression setA = new SetVarExpression(model,"setA", new int[]{}, new int[]{1,2,3,4,5,6,7}); - SetVarExpression setB = new SetVarExpression(model,"setB", new int[]{}, new int[]{2,4,6,8,10,12,14}); - SetVarExpression setC = new SetVarExpression(model,"setC", new int[]{}, new int[]{1,3,5,7,9,11,13}); - SetVarExpression setD = new SetVarExpression(model,"setD", new int[]{}, new int[]{4,5,6,7,10,12,14}); - SetVarExpression setE = new SetVarExpression(model,"setE", new int[]{}, new int[]{3,5,9,11,15,17,19}); - SetVarExpression setF = new SetVarExpression(model,"setF", new int[]{}, new int[]{4,8,12,16,20}); - SetVarExpression setG = new SetVarExpression(model,"setG", new int[]{}, new int[]{2,6,10,14,18}); + SetVar setA = model.setVar("setA", new int[]{}, new int[]{1, 2, 3, 4, 5, 6, 7}); + SetVar setB = model.setVar("setB", new int[]{}, new int[]{2, 4, 6, 8, 10, 12, 14}); + SetVar setC = model.setVar("setC", new int[]{}, new int[]{1, 3, 5, 7, 9, 11, 13}); + SetVar setD = model.setVar("setD", new int[]{}, new int[]{4, 5, 6, 7, 10, 12, 14}); + SetVar setE = model.setVar("setE", new int[]{}, new int[]{3, 5, 9, 11, 15, 17, 19}); + SetVar setF = model.setVar("setF", new int[]{}, new int[]{4, 8, 12, 16, 20}); + SetVar setG = model.setVar("setG", new int[]{}, new int[]{2, 6, 10, 14, 18}); setA.eq((setB.intersection(setC.union(setD)).union(setE.intersection(setF))).intersection(setG)).post(); model.getSolver().propagate(); - assertTrue(Arrays.equals(setA.getUB().toArray(), new int[] {6})); - assertTrue(Arrays.equals(setB.getUB().toArray(), new int[] {2, 4, 6, 8, 10, 12, 14})); - assertTrue(Arrays.equals(setC.getUB().toArray(), new int[] {1, 3, 5, 7, 9, 11, 13})); - assertTrue(Arrays.equals(setD.getUB().toArray(), new int[] {4, 5, 6, 7, 10, 12, 14})); - assertTrue(Arrays.equals(setE.getUB().toArray(), new int[] {3, 5, 9, 11, 15, 17, 19})); - assertTrue(Arrays.equals(setF.getUB().toArray(), new int[] {4, 8, 12, 16, 20})); - assertTrue(Arrays.equals(setG.getUB().toArray(), new int[] {2, 6, 10, 14, 18})); + assertArrayEquals(new int[]{6}, setA.getUB().toArray()); + assertArrayEquals(new int[]{2, 4, 6, 8, 10, 12, 14}, setB.getUB().toArray()); + assertArrayEquals(new int[]{1, 3, 5, 7, 9, 11, 13}, setC.getUB().toArray()); + assertArrayEquals(new int[]{4, 5, 6, 7, 10, 12, 14}, setD.getUB().toArray()); + assertArrayEquals(new int[]{3, 5, 9, 11, 15, 17, 19}, setE.getUB().toArray()); + assertArrayEquals(new int[]{4, 8, 12, 16, 20}, setF.getUB().toArray()); + assertArrayEquals(new int[]{2, 6, 10, 14, 18}, setG.getUB().toArray()); } } diff --git a/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/SetExpression.java b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/ArSetExpression.java similarity index 69% rename from solver/src/main/java/org/chocosolver/solver/expression/discrete/set/SetExpression.java rename to solver/src/main/java/org/chocosolver/solver/expression/discrete/set/ArSetExpression.java index a18a8b1dc3..105f247413 100644 --- a/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/SetExpression.java +++ b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/ArSetExpression.java @@ -1,25 +1,53 @@ +/* + * This file is part of choco-solver, http://choco-solver.org/ + * + * Copyright (c) 2025, IMT Atlantique. All rights reserved. + * + * Licensed under the BSD 4-clause license. + * + * See LICENSE file in the project root for full license information. + */ package org.chocosolver.solver.expression.discrete.set; import org.chocosolver.solver.Model; -import org.chocosolver.solver.constraints.Constraint; import org.chocosolver.solver.expression.discrete.relational.ReExpression; import org.chocosolver.solver.expression.discrete.relational.UnCReExpression; import org.chocosolver.solver.variables.SetVar; +import java.util.Arrays; + /** - * Interface for set variable (*SetVar*) expressions. + * Interface for set variable (*SetVar*) arithmetical expressions. * This interface enables the construction of relational and arithmetic expressions * over sets, allowing operations such as union, intersection, and membership checks. + * + * @author Gabriel Augusto David + * @author Charles Prud'homme */ -public interface SetExpression { +public interface ArSetExpression { + + /** + * Return the associated model + * + * @return a Model object + */ + Model getModel(); + + /** + * Returns the set variable associated with this expression. + * + * @return the corresponding set variable. + */ + SetVar setVar(); + /** * Returns the union of this set with another set. * * @param y the other set expression. * @return a new expression representing the union. */ - default SetExpression union(SetExpression y) { + default ArSetExpression union(ArSetExpression y) { return new BiArSetExpression(SetOperator.UNION, this, y); } @@ -29,16 +57,17 @@ default SetExpression union(SetExpression y) { * @param y the other set expression. * @return a new expression representing the intersection. */ - default SetExpression intersection(SetExpression y) { + default ArSetExpression intersection(ArSetExpression y) { return new BiArSetExpression(SetOperator.INTERSECTION, this, y); } + /** * Checks if this set is a subset of another set. * * @param y the other set expression. * @return a boolean expression representing the subset relationship. */ - default ReExpression subSet(SetExpression y) { + default ReExpression subSet(ArSetExpression y) { return new BiReSetExpression(SetOperator.SUBSET, this, y); } @@ -48,7 +77,7 @@ default ReExpression subSet(SetExpression y) { * @param y the other set expression. * @return a boolean expression representing equality. */ - default ReExpression eq(SetExpression y) { + default ReExpression eq(ArSetExpression y) { return new BiReSetExpression(SetOperator.EQ, this, y); } @@ -58,7 +87,7 @@ default ReExpression eq(SetExpression y) { * @param y the other set expression. * @return a boolean expression representing inequality. */ - default ReExpression ne(SetExpression y) { + default ReExpression ne(ArSetExpression y) { return new BiReSetExpression(SetOperator.NE, this, y); } @@ -68,17 +97,18 @@ default ReExpression ne(SetExpression y) { * @param y the other set expression. * @return a boolean expression representing the containment relation. */ - default ReExpression contains(SetExpression y) { + default ReExpression contains(ArSetExpression y) { return new BiReSetExpression(SetOperator.CONTAINS, this, y); } + /** * Checks if this set does not contain another set. * * @param y the other set expression. * @return a boolean expression representing the non-membership relation. */ - default ReExpression notContains(SetExpression y) { - return new BiReSetExpression(SetOperator.NC, this, y); + default ReExpression notContains(ArSetExpression y) { + return new BiReSetExpression(SetOperator.NOT_CONTAINS, this, y); } /** @@ -88,7 +118,7 @@ default ReExpression notContains(SetExpression y) { * @return a boolean expression representing the subset relationship. */ default ReExpression subSet(int... y) { - return new UnReSetExpression(SetOperator.SUBSET, this, y); + return new BiReSetExpression(SetOperator.SUBSET, this, this.getModel().setVar(Arrays.stream(y).toArray())); } /** @@ -98,7 +128,7 @@ default ReExpression subSet(int... y) { * @return a boolean expression representing equality. */ default ReExpression eq(int... y) { - return new UnReSetExpression(SetOperator.EQ, this, y); + return new BiReSetExpression(SetOperator.EQ, this, this.getModel().setVar(Arrays.stream(y).toArray())); } /** @@ -108,7 +138,7 @@ default ReExpression eq(int... y) { * @return a boolean expression representing non-membership. */ default ReExpression notContains(int... y) { - return new UnReSetExpression(SetOperator.NC, this, y); + return new BiReSetExpression(SetOperator.NOT_CONTAINS, this, this.getModel().setVar(Arrays.stream(y).toArray())); } /** @@ -118,7 +148,7 @@ default ReExpression notContains(int... y) { * @return a boolean expression representing membership. */ default ReExpression contains(int... y) { - return new UnReSetExpression(SetOperator.CONTAINS, this, y); + return new BiReSetExpression(SetOperator.CONTAINS, this, this.getModel().setVar(Arrays.stream(y).toArray())); } /** @@ -128,7 +158,7 @@ default ReExpression contains(int... y) { * @return a boolean expression representing inequality. */ default ReExpression ne(int... y) { - return new UnReSetExpression(SetOperator.NE, this, y); + return new BiReSetExpression(SetOperator.NE, this, this.getModel().setVar(Arrays.stream(y).toArray())); } /** @@ -136,9 +166,8 @@ default ReExpression ne(int... y) { * * @return a constraint enforcing the non-emptiness of the set. */ - default Constraint notEmpty() { - SetVar set = this.getSetVar(); - return getModel().notEmpty(set); + default ReExpression notEmpty() { + return new BiReSetExpression(SetOperator.NOT_EMPTY, this, this.getModel().setVar()); } /** @@ -148,26 +177,8 @@ default Constraint notEmpty() { * @return a unary relational expression enforcing the set cardinality. */ default UnCReExpression setCard(int valueCard) { - SetVar set = this.getSetVar(); + SetVar set = this.setVar(); return set.getCard().eq(valueCard); } - /** - * Returns the set variable associated with this expression. - * - * @return the corresponding set variable. - */ - SetVar getSetVar(); - - /** - * Returns the model associated with this expression. - * - * @return the model of the expression. - * @throws UnsupportedOperationException if this method is not supported. - */ - - default Model getModel() { - throw new UnsupportedOperationException("getModel() is not supported in this context"); - } - } \ No newline at end of file diff --git a/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/BiArSetExpression.java b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/BiArSetExpression.java index a4b3e949c7..cd9736b161 100644 --- a/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/BiArSetExpression.java +++ b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/BiArSetExpression.java @@ -1,3 +1,12 @@ +/* + * This file is part of choco-solver, http://choco-solver.org/ + * + * Copyright (c) 2025, IMT Atlantique. All rights reserved. + * + * Licensed under the BSD 4-clause license. + * + * See LICENSE file in the project root for full license information. + */ package org.chocosolver.solver.expression.discrete.set; import org.chocosolver.solver.Model; @@ -8,46 +17,55 @@ /** * BiArSetExpression - Binary Arithmetic Set Expression - * + *

* This class represents a binary arithmetic expression between two SetVarExpression instances. * It supports set operations such as union (UNION) and intersection (INTERSECTION), * returning a new SetVar as the result of the operation. - * + *

* Example: * setA.eq(setB.union(setC)).post(); * setA.eq(setB.intersection(setC)).post(); + * + * @author Gabriel Augusto David + * @author Charles Prud'homme */ -public class BiArSetExpression implements SetExpression { +public class BiArSetExpression implements ArSetExpression { - private SetOperator op; - private SetExpression x; - private SetExpression y; - private Model model; - private SetVar xSet, ySet, resultSet; + private final SetOperator op; + private final ArSetExpression x; + private final ArSetExpression y; + private final Model model; + private SetVar resultSet; - public BiArSetExpression(SetOperator operator, SetExpression x, SetExpression y) { + public BiArSetExpression(SetOperator operator, ArSetExpression x, ArSetExpression y) { this.op = operator; this.x = x; this.y = y; - this.xSet = x.getSetVar(); - this.ySet = y.getSetVar(); + this.model = x.getModel(); + } - this.model = xSet.getModel(); + @Override + public Model getModel() { + return model; } @Override - public SetVar getSetVar() { + public SetVar setVar() { if (resultSet == null) { - int[] setDomain = IntStream.concat(Arrays.stream(xSet.getUB().toArray()), Arrays.stream(ySet.getUB().toArray())).toArray(); + SetVar v1 = x.setVar(); + SetVar v2 = y.setVar(); + int[] setDomain = IntStream.concat(Arrays.stream(v1.getUB().toArray()), + Arrays.stream(v2.getUB().toArray())). + toArray(); resultSet = model.setVar(model.generateName("aux_setvar_"), new int[]{}, setDomain); switch (op) { case UNION: - model.union(new SetVar[]{xSet, ySet}, resultSet).post(); + model.union(new SetVar[]{v1, v2}, resultSet).post(); break; case INTERSECTION: - model.intersection(new SetVar[]{xSet, ySet}, resultSet).post(); + model.intersection(new SetVar[]{v1, v2}, resultSet).post(); break; default: throw new UnsupportedOperationException("Unsupported SetOperator: " + op); diff --git a/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/BiReSetExpression.java b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/BiReSetExpression.java index 80db64b6fe..bdf47724e0 100644 --- a/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/BiReSetExpression.java +++ b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/BiReSetExpression.java @@ -1,3 +1,12 @@ +/* + * This file is part of choco-solver, http://choco-solver.org/ + * + * Copyright (c) 2025, IMT Atlantique. All rights reserved. + * + * Licensed under the BSD 4-clause license. + * + * See LICENSE file in the project root for full license information. + */ package org.chocosolver.solver.expression.discrete.set; import org.chocosolver.solver.Model; @@ -11,34 +20,32 @@ /** * BiReSetExpression - Binary Relational Set Expression - * + *

* This class represents a binary relational expression between two SetVarExpression instances. * It supports relational operations such as equality (EQ), inequality (NE), subset (SUBSET), * and containment (CONTAINS). The operations can be composed and posted as constraints. - * + *

* Example: * setA.eq(setB).post(); * setA.ne(setB).post(); + *

+ * + * @author Gabriel Augusto David + * @author Charles Prud'homme */ public class BiReSetExpression implements ReExpression { - private SetOperator op; - private SetExpression x; - private SetExpression y; - private Model model; - private SetVar xSet, ySet; - - private Constraint constraint; - + private final SetOperator op; + private final ArSetExpression x; + private final ArSetExpression y; + private final Model model; private BoolVar result; - public BiReSetExpression(SetOperator operator, SetExpression x, SetExpression y) { + public BiReSetExpression(SetOperator operator, ArSetExpression x, ArSetExpression y) { this.op = operator; this.model = x.getModel(); this.x = x; this.y = y; - this.xSet = x.getSetVar(); - this.ySet = y.getSetVar(); } public Model getModel() { @@ -48,25 +55,7 @@ public Model getModel() { @Override public BoolVar boolVar() { if (result == null) { - switch (op) { - case SUBSET: - result = model.subsetEq(xSet, ySet).reify(); - break; - case EQ: - result = model.allEqual(xSet, ySet).reify(); - break; - case NE: - result = model.allDifferent(xSet, ySet).reify(); - break; - case CONTAINS: - result = model.subsetEq(ySet, xSet).reify(); - break; - case NC: - result = model.disjoint(ySet, xSet).reify(); - break; - default: - throw new UnsupportedOperationException("Unsupported SetOperator: " + op); - } + result = decompose().reify(); } return result; } @@ -78,25 +67,23 @@ public void extractVar(HashSet variables) { @Override public Constraint decompose() { + SetVar xSet = x.setVar(); + SetVar ySet = y.setVar(); switch (op) { case SUBSET: - constraint = model.subsetEq(xSet, ySet); - break; + return model.subsetEq(xSet, ySet); case EQ: - constraint = model.allEqual(xSet, ySet); - break; + return model.allEqual(xSet, ySet); case NE: - constraint = model.allDifferent(xSet, ySet); - break; + return model.allDifferent(xSet, ySet); case CONTAINS: - constraint = model.subsetEq(ySet, xSet); - break; - case NC: - constraint = model.disjoint(xSet,ySet); - break; + return model.subsetEq(ySet, xSet); + case NOT_CONTAINS: + return model.disjoint(xSet, ySet); + case NOT_EMPTY: + return model.notEmpty(xSet); default: throw new UnsupportedOperationException("Unsupported SetOperator: " + op); } - return constraint; } } \ No newline at end of file diff --git a/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/SetOperator.java b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/SetOperator.java index 741fbfe93e..e0d91fcd33 100644 --- a/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/SetOperator.java +++ b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/SetOperator.java @@ -1,11 +1,27 @@ +/* + * This file is part of choco-solver, http://choco-solver.org/ + * + * Copyright (c) 2025, IMT Atlantique. All rights reserved. + * + * Licensed under the BSD 4-clause license. + * + * See LICENSE file in the project root for full license information. + */ package org.chocosolver.solver.expression.discrete.set; +/** + * Set operators for set expressions. + * Relational and arithmetical operators are defined here. + * + * @author Gabriel Augusto David + */ public enum SetOperator { SUBSET, EQ, NE, CONTAINS, - NC, + NOT_EMPTY, + NOT_CONTAINS, UNION, INTERSECTION } \ No newline at end of file diff --git a/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/UnReSetExpression.java b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/UnReSetExpression.java deleted file mode 100644 index 0496d90898..0000000000 --- a/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/UnReSetExpression.java +++ /dev/null @@ -1,104 +0,0 @@ -package org.chocosolver.solver.expression.discrete.set; - -import org.chocosolver.solver.Model; -import org.chocosolver.solver.constraints.Constraint; -import org.chocosolver.solver.expression.discrete.relational.ReExpression; -import org.chocosolver.solver.variables.BoolVar; -import org.chocosolver.solver.variables.IntVar; -import org.chocosolver.solver.variables.SetVar; - -import java.util.Arrays; -import java.util.HashSet; - -import static org.chocosolver.solver.constraints.real.Ibex.TRUE; - -/** - * UnReSetExpression - Unary Relational Set Expression - * - * This class represents a unary relational expression for a SetVar and a set of values. - * It handles operations like equality (EQ), inequality (NE), subset (SUBSET), and containment (CONTAINS) - * with respect to a fixed set of integers. - * - * Example: - * setA.eq(1,2,3).post(); - * setA.contains(1,2).post(); - */ -public class UnReSetExpression implements ReExpression { - private SetOperator op; - private SetExpression x; - private int[] y; - private Model model; - private SetVar xSet, ySet; - - private Constraint constraint; - - private BoolVar result; - - public UnReSetExpression(SetOperator operator, SetExpression x, int... y) { - this.op = operator; - this.model = x.getModel(); - this.x = x; - this.y = y; - this.xSet = x.getSetVar(); - this.ySet = model.setVar(Arrays.stream(y).toArray()); - } - - public Model getModel() { - return this.model; - } - - @Override - public BoolVar boolVar() { - if (result == null) { - switch (op) { - case SUBSET: - result = model.subsetEq(xSet, ySet).reify().eq(TRUE).boolVar(); - break; - case EQ: - result = model.allEqual(xSet, ySet).reify().eq(TRUE).boolVar(); - break; - case NE: - result = model.allDifferent(xSet, ySet).reify().eq(TRUE).boolVar(); - break; - case CONTAINS: - result = model.subsetEq(ySet, xSet).reify().eq(TRUE).boolVar(); - break; - case NC: - result = model.disjoint(ySet, xSet).reify().eq(TRUE).boolVar(); - break; - default: - throw new UnsupportedOperationException("Unsupported SetOperator: " + op); - } - } - return result; - } - - @Override - public void extractVar(HashSet variables) { - throw new UnsupportedOperationException("extractVar() is not supported for UnReSetExpression."); - } - - @Override - public Constraint decompose() { - switch (op) { - case SUBSET: - constraint = model.subsetEq(xSet, ySet); - break; - case EQ: - constraint = model.allEqual(xSet, ySet); - break; - case NE: - constraint = model.allDifferent(xSet, ySet); - break; - case CONTAINS: - constraint = model.subsetEq(ySet, xSet); - break; - case NC: - constraint = model.disjoint(xSet,ySet); - break; - default: - throw new UnsupportedOperationException("Unsupported SetOperator: " + op); - } - return constraint; - } -} \ No newline at end of file diff --git a/solver/src/main/java/org/chocosolver/solver/variables/SetVar.java b/solver/src/main/java/org/chocosolver/solver/variables/SetVar.java index 06a051c331..8054a8b118 100644 --- a/solver/src/main/java/org/chocosolver/solver/variables/SetVar.java +++ b/solver/src/main/java/org/chocosolver/solver/variables/SetVar.java @@ -11,6 +11,7 @@ import org.chocosolver.solver.ICause; import org.chocosolver.solver.exception.ContradictionException; +import org.chocosolver.solver.expression.discrete.set.ArSetExpression; import org.chocosolver.solver.variables.delta.ISetDelta; import org.chocosolver.solver.variables.delta.ISetDeltaMonitor; import org.chocosolver.util.objects.setDataStructures.ISet; @@ -25,10 +26,10 @@ * @author Charles Prud'homme, Jean-Guillaume Fages * @since 15 nov. 2012 Major update 2016 */ -public interface SetVar extends Variable { +public interface SetVar extends Variable, ArSetExpression { /** - * Get SetVar Lower Bound : the set of integers that must belong to every solution (i.e. a subset of all solutions) + * Get SetVar Lower Bound: the set of integers that must belong to every solution (i.e. a subset of all solutions) * To iterate over this set, use the following loop: *

* ISet lbSet = getLB(); @@ -147,4 +148,9 @@ default int getDomainSize() { } return dom; } + + @Override + default SetVar setVar() { + return this; + } } diff --git a/solver/src/main/java/org/chocosolver/solver/variables/impl/SetVarExpression.java b/solver/src/main/java/org/chocosolver/solver/variables/impl/SetVarExpression.java deleted file mode 100644 index 39039df455..0000000000 --- a/solver/src/main/java/org/chocosolver/solver/variables/impl/SetVarExpression.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.chocosolver.solver.variables.impl; - -import org.chocosolver.solver.Model; -import org.chocosolver.solver.expression.discrete.set.SetExpression; -import org.chocosolver.util.objects.setDataStructures.SetType; - - -/** - * SetVarExpression - SetVar Implementation with Expression Support - * - * This class extends SetVar to allow arithmetic and relational operations to be performed - * directly on set variables, facilitating composition of constraints and complex expressions - * such as union, intersection, equality, and subset relations. - * - * Example: - * setA.eq(1,2,3).post(); - * setA.union(setB).post(); - */ - -public class SetVarExpression extends SetVarImpl implements SetExpression { - /** - This class is a copy of SetVarImpl that implements the SetExpression functions. - */ - - public SetVarExpression(Model model, String name, int[] valuesLB, int[] valuesUB){ - super(name, valuesLB, SetType.BITSET, valuesUB, SetType.BITSET, model.ref()); - } - - public SetVarExpression(Model model, String name, int...domain){ - super(name, domain, model.ref()); - } - @Override - public SetVarImpl getSetVar(){ - return this; - } -} \ No newline at end of file From 2cda4d84daba8c8097bbbb16f9255192df7729cd Mon Sep 17 00:00:00 2001 From: cprudhom Date: Thu, 28 Aug 2025 19:06:16 +0200 Subject: [PATCH 4/5] SetExpression: update module-info.java --- solver/src/main/java/module-info.java | 1 + 1 file changed, 1 insertion(+) diff --git a/solver/src/main/java/module-info.java b/solver/src/main/java/module-info.java index 3961577d0c..b6aaf793bd 100644 --- a/solver/src/main/java/module-info.java +++ b/solver/src/main/java/module-info.java @@ -73,6 +73,7 @@ exports org.chocosolver.solver.expression.discrete.arithmetic; exports org.chocosolver.solver.expression.discrete.logical; exports org.chocosolver.solver.expression.discrete.relational; + exports org.chocosolver.solver.expression.discrete.set; exports org.chocosolver.solver.objective; exports org.chocosolver.solver.propagation; exports org.chocosolver.solver.search; From 81331c155719558d5aded0172911e7badc6521a7 Mon Sep 17 00:00:00 2001 From: Gabriel Augusto David Date: Thu, 30 Apr 2026 21:23:14 -0300 Subject: [PATCH 5/5] Refactor set expressions API --- .../set/expression/SetVarExpressionTest.java | 99 ++++++++++--------- .../discrete/set/ArSetExpression.java | 14 +-- .../discrete/set/BiReSetExpression.java | 4 +- .../expression/discrete/set/SetOperator.java | 3 +- 4 files changed, 60 insertions(+), 60 deletions(-) diff --git a/examples/src/test/java/org/chocosolver/examples/set/expression/SetVarExpressionTest.java b/examples/src/test/java/org/chocosolver/examples/set/expression/SetVarExpressionTest.java index 13e964d93d..83d26026c2 100644 --- a/examples/src/test/java/org/chocosolver/examples/set/expression/SetVarExpressionTest.java +++ b/examples/src/test/java/org/chocosolver/examples/set/expression/SetVarExpressionTest.java @@ -12,23 +12,26 @@ import org.chocosolver.solver.Model; import org.chocosolver.solver.exception.ContradictionException; import org.chocosolver.solver.variables.SetVar; -import org.junit.Test; +import org.testng.annotations.Test; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; +import java.util.Arrays; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +@Test(groups = "1s") public class SetVarExpressionTest { /** * Basic - * ============= Relacional ============= values and sets + * ============= Relational ============= values and sets * EQ (Equals) -> set = n value | setA = setB * NE (not equals) -> set != n values | setA != setB * Contains -> set contains n values | setA contains setB * NC (Not Contains) -> set notContains n values | setA notContains setB * SUBSET -> set = is a subset of a SuperSet (values or set) *

- * Basic relacionals => and, imp, or... + * Basic relationals => and, imp, or... *

* ============= Basic Arithmetic ============= * UNION @@ -42,12 +45,11 @@ public class SetVarExpressionTest { * Empty */ - @Test + @Test(expectedExceptions = ContradictionException.class) public void notEmptyTest() throws ContradictionException { Model model = new Model(); SetVar setA = model.setVar("setA", new int[]{}, new int[]{0, 1, 2, 3}); -// model.notEmpty(setA).post(); Choco setA.notEmpty().post(); model.getSolver().propagate(); @@ -59,6 +61,9 @@ public void notEmptyTest() throws ContradictionException { model.getSolver().propagate(); assertEquals(2, setA.getValue().toArray()[0]); + + model.notMember(2, setA).post(); + model.getSolver().propagate(); } @Test() @@ -88,7 +93,7 @@ public void simpleEQTest01() throws ContradictionException { model.getSolver().propagate(); - assertArrayEquals(new int[]{1}, setA.getValue().toArray()); + assertTrue(Arrays.equals(new int[]{1}, setA.getValue().toArray())); } @Test() @@ -101,8 +106,8 @@ public void simpleEQTest02() throws ContradictionException { model.getSolver().propagate(); - assertArrayEquals(new int[]{1}, setA.getValue().toArray()); - assertArrayEquals(new int[]{2}, setB.getValue().toArray()); + assertTrue(Arrays.equals(new int[]{1}, setA.getValue().toArray())); + assertTrue(Arrays.equals(new int[]{2}, setB.getValue().toArray())); } @Test() @@ -113,7 +118,7 @@ public void simpleEQTest03() throws ContradictionException { model.getSolver().propagate(); - assertArrayEquals(new int[]{1, 2, 3}, setA.getValue().toArray()); + assertTrue(Arrays.equals(new int[]{1, 2, 3}, setA.getValue().toArray())); } @Test() @@ -126,8 +131,8 @@ public void simpleNETest01() throws ContradictionException { model.getSolver().propagate(); - assertArrayEquals(new int[]{2}, setA.getValue().toArray()); - assertArrayEquals(new int[]{2}, setB.getValue().toArray()); + assertTrue(Arrays.equals(new int[]{2}, setA.getValue().toArray())); + assertTrue(Arrays.equals(new int[]{2}, setB.getValue().toArray())); } @Test() @@ -138,7 +143,7 @@ public void simpleContainsTest01() throws ContradictionException { model.getSolver().propagate(); - assertArrayEquals(new int[]{1, 2, 3}, setA.getLB().toArray()); + assertTrue(Arrays.equals(new int[]{1, 2, 3}, setA.getLB().toArray())); } @Test() @@ -149,7 +154,7 @@ public void simpleNotContainsTest01() throws ContradictionException { model.getSolver().propagate(); - assertArrayEquals(new int[]{0, 4, 5, 6, 7, 8, 9}, setA.getUB().toArray()); + assertTrue(Arrays.equals(new int[]{0, 4, 5, 6, 7, 8, 9}, setA.getUB().toArray())); } @@ -161,13 +166,12 @@ public void simpleSubSetTest01() throws ContradictionException { model.getSolver().propagate(); - assertArrayEquals(new int[]{1, 2, 3, 4, 5}, setA.getUB().toArray()); + assertTrue(Arrays.equals(new int[]{1, 2, 3, 4, 5}, setA.getUB().toArray())); - setA.notEmpty().post(); setA.notContains(4, 5).post(); model.getSolver().propagate(); - assertArrayEquals(new int[]{1, 2, 3}, setA.getUB().toArray()); + assertTrue(Arrays.equals(new int[]{1, 2, 3}, setA.getUB().toArray())); } @Test() @@ -181,8 +185,8 @@ public void biEqTest01() throws ContradictionException { model.getSolver().propagate(); - assertArrayEquals(new int[]{1, 2}, setA.getValue().toArray()); - assertArrayEquals(new int[]{1, 2}, setB.getValue().toArray()); + assertTrue(Arrays.equals(new int[]{1, 2}, setA.getValue().toArray())); + assertTrue(Arrays.equals(new int[]{1, 2}, setB.getValue().toArray())); } @Test() @@ -199,10 +203,10 @@ public void biEQTest02() throws ContradictionException { model.getSolver().propagate(); - assertArrayEquals(new int[]{1, 2, 3}, setA.getValue().toArray()); - assertArrayEquals(new int[]{1, 2, 3}, setB.getValue().toArray()); - assertArrayEquals(new int[]{4, 5}, setC.getValue().toArray()); - assertArrayEquals(new int[]{4, 5}, setD.getValue().toArray()); + assertTrue(Arrays.equals(new int[]{1, 2, 3}, setA.getValue().toArray())); + assertTrue(Arrays.equals(new int[]{1, 2, 3}, setB.getValue().toArray())); + assertTrue(Arrays.equals(new int[]{4, 5}, setC.getValue().toArray())); + assertTrue(Arrays.equals(new int[]{4, 5}, setD.getValue().toArray())); } @Test() @@ -214,7 +218,7 @@ public void biEQTest03() throws ContradictionException { model.getSolver().propagate(); - assertArrayEquals(setA.getValue().toArray(), setB.getValue().toArray()); + assertTrue(Arrays.equals(setA.getValue().toArray(), setB.getValue().toArray())); } @Test() @@ -230,8 +234,8 @@ public void biNETest01() throws ContradictionException { model.getSolver().propagate(); - assertArrayEquals(new int[]{3, 4}, setA.getValue().toArray()); - assertArrayEquals(new int[]{1, 2}, setB.getValue().toArray()); + assertTrue(Arrays.equals(new int[]{3, 4}, setA.getValue().toArray())); + assertTrue(Arrays.equals(new int[]{1, 2}, setB.getValue().toArray())); } @Test() @@ -244,9 +248,9 @@ public void biContainsTest01() throws ContradictionException { model.getSolver().propagate(); - assertArrayEquals(new int[]{1, 2, 3}, setB.getValue().toArray()); - assertArrayEquals(new int[]{1, 2, 3}, setA.getLB().toArray()); - assertArrayEquals(new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, setA.getUB().toArray()); + assertTrue(Arrays.equals(new int[]{1, 2, 3}, setB.getValue().toArray())); + assertTrue(Arrays.equals(new int[]{1, 2, 3}, setA.getLB().toArray())); + assertTrue(Arrays.equals(new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, setA.getUB().toArray())); } @@ -260,7 +264,7 @@ public void biNotContainsTest01() throws ContradictionException { model.getSolver().propagate(); - assertArrayEquals(new int[]{0, 4, 5, 6, 7, 8, 9}, setA.getUB().toArray()); + assertTrue(Arrays.equals(new int[]{0, 4, 5, 6, 7, 8, 9}, setA.getUB().toArray())); } @Test() @@ -272,15 +276,14 @@ public void biSubSetTest01() throws ContradictionException { model.getSolver().propagate(); - assertArrayEquals(new int[]{1, 2, 3, 4, 5}, setA.getUB().toArray()); - assertArrayEquals(new int[]{1, 2, 3, 4, 5}, setB.getUB().toArray()); + assertTrue(Arrays.equals(new int[]{1, 2, 3, 4, 5}, setA.getUB().toArray())); + assertTrue(Arrays.equals(new int[]{1, 2, 3, 4, 5}, setB.getUB().toArray())); - setA.notEmpty().post(); setA.notContains(4, 5).post(); model.getSolver().propagate(); - assertArrayEquals(new int[]{1, 2, 3}, setA.getUB().toArray()); - assertArrayEquals(new int[]{1, 2, 3, 4, 5}, setB.getUB().toArray()); + assertTrue(Arrays.equals(new int[]{1, 2, 3}, setA.getUB().toArray())); + assertTrue(Arrays.equals(new int[]{1, 2, 3, 4, 5}, setB.getUB().toArray())); } @Test() @@ -293,7 +296,7 @@ public void unionTest01() throws ContradictionException { setCD.eq(setC.union(setD)).post(); model.getSolver().propagate(); - assertArrayEquals(new int[]{1, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14}, setCD.getUB().toArray()); + assertTrue(Arrays.equals(new int[]{1, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14}, setCD.getUB().toArray())); } @Test() @@ -306,7 +309,7 @@ public void intersectTest01() throws ContradictionException { setBCD.eq(setB.intersection(setCD)).post(); model.getSolver().propagate(); - assertArrayEquals(new int[]{4, 6, 10, 12, 14}, setBCD.getUB().toArray()); + assertTrue(Arrays.equals(new int[]{4, 6, 10, 12, 14}, setBCD.getUB().toArray())); } @Test() @@ -320,7 +323,7 @@ public void intersectAndUnionTest01() throws ContradictionException { setBCD.eq(setB.intersection(setC.union(setD))).post(); model.getSolver().propagate(); - assertArrayEquals(new int[]{4, 6, 10, 12, 14}, setBCD.getUB().toArray()); + assertTrue(Arrays.equals(new int[]{4, 6, 10, 12, 14}, setBCD.getUB().toArray())); } @Test() @@ -333,7 +336,7 @@ public void intersectTest02() throws ContradictionException { setEF.eq(setE.intersection(setF)).post(); model.getSolver().propagate(); - assertArrayEquals(new int[]{}, setEF.getUB().toArray()); + assertTrue(Arrays.equals(new int[]{}, setEF.getUB().toArray())); } @@ -352,7 +355,7 @@ public void intersectAndUnionTest02() throws ContradictionException { setBCDEF.eq((setB.intersection(setC.union(setD)).union(setE.intersection(setF)))).post(); model.getSolver().propagate(); - assertArrayEquals(new int[]{4, 6, 10, 12, 14}, setBCDEF.getUB().toArray()); + assertTrue(Arrays.equals(new int[]{4, 6, 10, 12, 14}, setBCDEF.getUB().toArray())); } @Test() @@ -369,12 +372,12 @@ public void setExpressionTest01() throws ContradictionException { setA.eq((setB.intersection(setC.union(setD)).union(setE.intersection(setF))).intersection(setG)).post(); model.getSolver().propagate(); - assertArrayEquals(new int[]{6}, setA.getUB().toArray()); - assertArrayEquals(new int[]{2, 4, 6, 8, 10, 12, 14}, setB.getUB().toArray()); - assertArrayEquals(new int[]{1, 3, 5, 7, 9, 11, 13}, setC.getUB().toArray()); - assertArrayEquals(new int[]{4, 5, 6, 7, 10, 12, 14}, setD.getUB().toArray()); - assertArrayEquals(new int[]{3, 5, 9, 11, 15, 17, 19}, setE.getUB().toArray()); - assertArrayEquals(new int[]{4, 8, 12, 16, 20}, setF.getUB().toArray()); - assertArrayEquals(new int[]{2, 6, 10, 14, 18}, setG.getUB().toArray()); + assertTrue(Arrays.equals(new int[]{6}, setA.getUB().toArray())); + assertTrue(Arrays.equals(new int[]{2, 4, 6, 8, 10, 12, 14}, setB.getUB().toArray())); + assertTrue(Arrays.equals(new int[]{1, 3, 5, 7, 9, 11, 13}, setC.getUB().toArray())); + assertTrue(Arrays.equals(new int[]{4, 5, 6, 7, 10, 12, 14}, setD.getUB().toArray())); + assertTrue(Arrays.equals(new int[]{3, 5, 9, 11, 15, 17, 19}, setE.getUB().toArray())); + assertTrue(Arrays.equals(new int[]{4, 8, 12, 16, 20}, setF.getUB().toArray())); + assertTrue(Arrays.equals(new int[]{2, 6, 10, 14, 18}, setG.getUB().toArray())); } } diff --git a/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/ArSetExpression.java b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/ArSetExpression.java index 105f247413..0b6d385bf8 100644 --- a/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/ArSetExpression.java +++ b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/ArSetExpression.java @@ -98,7 +98,7 @@ default ReExpression ne(ArSetExpression y) { * @return a boolean expression representing the containment relation. */ default ReExpression contains(ArSetExpression y) { - return new BiReSetExpression(SetOperator.CONTAINS, this, y); + return y.subSet(this); } /** @@ -108,7 +108,7 @@ default ReExpression contains(ArSetExpression y) { * @return a boolean expression representing the non-membership relation. */ default ReExpression notContains(ArSetExpression y) { - return new BiReSetExpression(SetOperator.NOT_CONTAINS, this, y); + return new BiReSetExpression(SetOperator.DISJOINT, this, y); } /** @@ -118,7 +118,7 @@ default ReExpression notContains(ArSetExpression y) { * @return a boolean expression representing the subset relationship. */ default ReExpression subSet(int... y) { - return new BiReSetExpression(SetOperator.SUBSET, this, this.getModel().setVar(Arrays.stream(y).toArray())); + return subSet(this.getModel().setVar(y)); } /** @@ -128,7 +128,7 @@ default ReExpression subSet(int... y) { * @return a boolean expression representing equality. */ default ReExpression eq(int... y) { - return new BiReSetExpression(SetOperator.EQ, this, this.getModel().setVar(Arrays.stream(y).toArray())); + return eq(this.getModel().setVar(y)); } /** @@ -138,7 +138,7 @@ default ReExpression eq(int... y) { * @return a boolean expression representing non-membership. */ default ReExpression notContains(int... y) { - return new BiReSetExpression(SetOperator.NOT_CONTAINS, this, this.getModel().setVar(Arrays.stream(y).toArray())); + return notContains(this.getModel().setVar(y)); } /** @@ -148,7 +148,7 @@ default ReExpression notContains(int... y) { * @return a boolean expression representing membership. */ default ReExpression contains(int... y) { - return new BiReSetExpression(SetOperator.CONTAINS, this, this.getModel().setVar(Arrays.stream(y).toArray())); + return contains(this.getModel().setVar(y)); } /** @@ -158,7 +158,7 @@ default ReExpression contains(int... y) { * @return a boolean expression representing inequality. */ default ReExpression ne(int... y) { - return new BiReSetExpression(SetOperator.NE, this, this.getModel().setVar(Arrays.stream(y).toArray())); + return ne(this.getModel().setVar(y)); } /** diff --git a/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/BiReSetExpression.java b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/BiReSetExpression.java index bdf47724e0..da6959e1c0 100644 --- a/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/BiReSetExpression.java +++ b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/BiReSetExpression.java @@ -76,9 +76,7 @@ public Constraint decompose() { return model.allEqual(xSet, ySet); case NE: return model.allDifferent(xSet, ySet); - case CONTAINS: - return model.subsetEq(ySet, xSet); - case NOT_CONTAINS: + case DISJOINT: return model.disjoint(xSet, ySet); case NOT_EMPTY: return model.notEmpty(xSet); diff --git a/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/SetOperator.java b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/SetOperator.java index e0d91fcd33..c0cfae2d64 100644 --- a/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/SetOperator.java +++ b/solver/src/main/java/org/chocosolver/solver/expression/discrete/set/SetOperator.java @@ -19,9 +19,8 @@ public enum SetOperator { SUBSET, EQ, NE, - CONTAINS, NOT_EMPTY, - NOT_CONTAINS, + DISJOINT, UNION, INTERSECTION } \ No newline at end of file