Skip to content

Unit tests of NotAllEqual - #130

Merged
xcsp3team merged 7 commits into
masterfrom
tests-notallequal
Sep 29, 2026
Merged

xcsp3team merged 7 commits into
masterfrom
tests-notallequal

Conversation

@szczepanskiNicolas

@szczepanskiNicolas szczepanskiNicolas commented Sep 28, 2026 •

Copy link
Copy Markdown
Collaborator

Unit tests of the constraint NotAllEqual of the section Constraints (Global) of the API (https://pycsp.org/documentation/api/constraints-global/#NotAllEqual), written as for the previous global constraints (#66), with the same harness.

This PR adds tests (pycsp3/tests/test_constraints_global_notallequal.py). The bugs found are reported in issues, and the tests concerned are marked as strict expected failures with the numbers of these issues. It also contains the fixes of #131 (9327cec) and #132 (57e5479), which remove the marks of these issues, the removal of the tests with the option -mini (baeef7e), #133 not being a bug, and the tests of the terms given several times, expected to be kept once (41f5cdd), with the fix of #134 (55439f8).

Tests

NotAllEqual() posts NValues(...) > 1, that is to say an element <nValues> with the condition (gt,1). The tests cover:

  • the forms of the arguments (lists, tuples, generators, slices, nested lists), sizes, matrices, different domains, negative values, arrays with holes, and the example of the documentation;
  • repeated variables, and the degenerated cases (less than two terms: the constraint is trivially false);
  • expressions;
  • integers among the terms (replaced by auxiliary variables), and only integers;
  • groups of constraints (rows, sliding windows), and NotAllEqual() in logical expressions (~, |, &, imply(), either());
  • the XCSP3 files generated, and invalid arguments.

Each constraint is solved with ACE, CHOCO and cosoco, and all the solutions are compared with the ones computed by brute force.

File Commit Tests Passed Expected failures (known bugs) Skipped
test_constraints_global_notallequal.py 30b07b5 (tests only, before the fixes) 199 132 53 14
test_constraints_global_notallequal.py 55439f8 (last commit) 175 144 20 11

Whole suite at 55439f8 (run locally, master not having moved since the creation of the branch): 2703 passed, 125 skipped and 203 expected failures, no failure (master at 0f4ffd2 plus this file).

Known bugs

Each issue has the labels bug, unit-tests, Constraints (Global) and the label of the function (NotAllEqual for PyCSP3, nValues for ACE). Each issue of a solver shows the results of the three solvers on the same XCSP3 file, compared with brute force.

Expected failures at the last commit (20 tests):

Issue Solvers (tests) Tests
xcsp3team/ACE#18: nValues with (gt,1) or (ge,2) on two variables fails; fixed in ACE (3a6cd59) and closed, the marks being kept as long as PyCSP3 embeds ACE 2.6 (with ACE built from 3a6cd59, these 6 tests pass) ACE (6) 6
chocoteam/choco-solver#1248 (section 5): nValues on expressions, some solutions are found several times CHOCO (6) 6
table with an empty set of supports (the constraint false posted with less than two terms): the parser of ACE and CHOCO fails in buildCtrFalse() (Constraint with only conflicts, not reported, by decision, see #128) ACE (4), CHOCO (4) 8

Issues of PyCSP3 handled in this PR:

Issue Tests State
#131: NotAllEqual() with a single invalid term (None, a string, a range...) posts false instead of reporting an error 5 fixed in 9327cec (marks removed), closed
#132: NotAllEqual() given only integers is accepted, while AllDifferent() and AllEqual() report an error 3 fixed in 57e5479 (marks removed), closed
#133: with -mini, NValues() keeps the expressions in its list instead of replacing them by auxiliary variables 22 not a bug: nValues is not part of the mini-tracks (intension, extension, allDifferent, sum and element); closed as not planned, and the tests with -mini removed in baeef7e
#134: NotAllEqual() keeps the terms given several times, on which ACE fails (and that cosoco refuses); first reported as xcsp3team/ACE#19, closed because each term is to be kept once by PyCSP3 11 tests in 41f5cdd, fixed in 55439f8 (marks removed), closed

Cases not handled by the solvers

The following cases are not reported as bugs, because the solver says that it does not handle them (or, for the symbolic variables, because they are not part of XCSP3-core); the corresponding tests are skipped with this solver (11 tests). The other cells give the result of the solver: handled (✓), or a bug reported in the given issue.

Case (constraint) ACE CHOCO cosoco
nValues on expressions ✓ (except with two terms, xcsp3team/ACE#18) bug: solutions found several times (chocoteam/choco-solver#1248) not supported (s UNSUPPORTED)
nValues on symbolic variables (not part of XCSP3-core) RuntimeException RuntimeException: UNSUPPORTED no symbolic variables

The function NotAllEqual() of the section Constraints (Global) is tested as the
previous global constraints: forms of the arguments, sizes, domains, holes,
repeated variables, degenerated cases, expressions (with and without -mini),
integers among the terms, groups, logical contexts, XCSP3 files and invalid
cases, each constraint being solved with ACE, CHOCO and cosoco and compared
with brute force. The known bugs are marked as expected failures, to be
reported.
…Equal

The provisional marks '(to be reported)' now give the issues: #131, #132 and
#133 for PyCSP3, xcsp3team/ACE#18 and xcsp3team/ACE#19 for ACE, and section 5
of chocoteam/choco-solver#1248 for CHOCO. The mark of the empty tables of
supports (ACE and CHOCO) is kept as in the other test files.
@szczepanskiNicolas szczepanskiNicolas added run-tests Runs the unit tests (Linux and macOS) on this pull request and removed run-tests Runs the unit tests (Linux and macOS) on this pull request labels Sep 28, 2026
NValues() returned a constant for a single term before checking its type, so
that NotAllEqual() given None, a string, a float, a range or a dictionary
posted the constraint false (with a warning), and NValues('a') == 1 was
accepted without any message. None is now reported by NValues() and
NotAllEqual(), and the shortcut for a single term only applies to a variable,
an expression, a partial constraint or an integer: an invalid term is reported
by checkType(), as for AllEqual().

Fixes #131
…erent() and AllEqual()

NotAllEqual() given only integers replaced each one by an auxiliary variable
(NotAllEqual(1, 2) was always true, NotAllEqual(1, 1) always false), or posted
the constraint false (NotAllEqual(5)). As for AllDifferent() and AllEqual(), an
explicit error is now reported; integers among variables remain accepted.

The terms are flattened once: the body of NValues() is moved to _nvalues(),
which receives a flat list, and is called by NValues() and NotAllEqual(), so
that the check does not cost a second call to flatten() (+16% on the
generation of 23,490 constraints NotAllEqual, against +1.5% now).

Fixes #132
nValues is not part of the perimeter of the mini-tracks of the XCSP
competitions (intension, extension, allDifferent, sum and element), so that
the option -mini has nothing to change for NValues() (#133, not a bug): the
test expecting auxiliary variables in <nValues> with -mini was wrong, and the
test solving the constraints with -mini repeated the one without -mini, the
generated files being the same.
A term given several times does not change the number of distinct values;
ACE fails on a variable given several times in nValues and cosoco refuses it,
so that PyCSP3 is expected to keep each term once before posting the
constraint (#134; xcsp3team/ACE#19 closed for this reason). The constraints
with a repeated variable, or with two identical sums replaced by the same
auxiliary variable, are solved with at least three distinct terms (with two
terms, ACE fails because of xcsp3team/ACE#18), and the generated elements
<nValues> are checked; NotAllEqual(x[0], x[0]) is expected to be trivially
false.
…he constraint

A term given several times does not change the number of distinct values,
but ACE fails on a variable given several times in nValues and cosoco refuses
it. Before posting the constraint, _nvalues() now keeps each term once: the
variables are compared by identity (== being redefined for building
expressions), the expressions by their textual forms, identical partial
constraints being replaced by the same auxiliary variable, and an integer
given several times is replaced by a single auxiliary variable. When a single
term remains (NotAllEqual(x[0], x[0])), the constraint is trivially false, as
for NotAllEqual(x[0]).

On the generation of 23,490 constraints NotAllEqual, the time is unchanged on
variables (1.43 s) and 3.5% longer on expressions (3.60 s -> 3.73 s), with
identical files.

Fixes #134
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants