Skip to content

Commit 5bc62fb

Browse files
author
Mikael Zayenz Lagerkvist
committed
Fix GCC solution loss during recomputation
1 parent 545fa33 commit 5bc62fb

6 files changed

Lines changed: 308 additions & 2 deletions

File tree

Makefile.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,6 +1141,7 @@ FLATZINCTESTSRC0 = \
11411141
test/flatzinc/empty_domain_2.cpp \
11421142
test/flatzinc/int_set_as_type1.cpp \
11431143
test/flatzinc/int_set_as_type2.cpp \
1144+
test/flatzinc/issue166.cpp \
11441145
test/flatzinc/jobshop.cpp \
11451146
test/flatzinc/no_warn_empty_domain.cpp \
11461147
test/flatzinc/output_test.cpp \

changelog.in

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,15 @@ This release modernizes the Gecode build infrastructure, adds a
7575
first-class CMake package for downstream consumers, refreshes the
7676
autoconf build path, and updates CI coverage for current platforms.
7777

78+
[ENTRY]
79+
Module: int
80+
What: bug
81+
Rank: major
82+
Issue: 166
83+
[DESCRIPTION]
84+
Fix domain-level global cardinality propagation losing solutions when search
85+
recomputation applies several branch choices before propagation.
86+
7887
[ENTRY]
7988
Module: flatzinc
8089
What: new

cmake/GecodeSources.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ set(GECODE_TEST_SOURCES
293293
test/flatzinc/golomb.cpp
294294
test/flatzinc/int_set_as_type1.cpp
295295
test/flatzinc/int_set_as_type2.cpp
296+
test/flatzinc/issue166.cpp
296297
test/flatzinc/jobshop.cpp
297298
test/flatzinc/jobshop2x2.cpp
298299
test/flatzinc/knights.cpp

docs/open-issues-plan.md

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
# Open issue work plan
2+
3+
This plan covers the 29 issues that were open on 13 July 2026. The ordering is
4+
based on the current `main` branch. Old reports are not automatically low
5+
priority, but work that can produce wrong answers ranks above usability changes
6+
and reports against build code that has since been replaced.
7+
8+
The first implementation target is [#166](https://github.com/Gecode/gecode/issues/166).
9+
It reports missing solutions and includes a small reproducer, so it provides a
10+
good starting point for the remaining correctness work.
11+
12+
## Immediate correctness and release work
13+
14+
### #166: global cardinality misses solutions
15+
16+
**Priority:** urgent. **Status:** fix and regression implemented.
17+
18+
The minimized model fails only with domain propagation when several branch
19+
choices are replayed before propagation. The upper- and lower-bound matching
20+
passes both increment the same occurrence counter, which can make a value look
21+
full and remove a valid edge. Count assigned variable nodes only during the
22+
upper-bound pass, and retain the original randomized search as a FlatZinc
23+
regression. A solver that omits valid solutions is unsound, so this issue comes
24+
first.
25+
26+
### #168: `sort` and `element` model hangs
27+
28+
**Priority:** urgent after #166.
29+
30+
The minimized model contains repeated variables. Reproduce it with a time limit,
31+
then determine whether the loop is in propagation, search, or FlatZinc posting.
32+
Recent fixes for other FlatZinc constraints established a useful pattern:
33+
explicitly handle shared variables before posting propagators that assume
34+
distinct views.
35+
36+
### #199: MiniZinc float test exhausts memory
37+
38+
**Priority:** urgent release investigation.
39+
40+
Run `test-globals-float.mzn` against `main` with strict time and memory limits.
41+
Record nodes, failures, depth, and resident memory to distinguish a leak from an
42+
unbounded search tree. Treat the separate request for an `fzn-gecode` memory
43+
limit as a follow-up unless bounded reproduction shows that it is required for
44+
safe operation.
45+
46+
### #142: zero-sized `nooverlap` rectangles
47+
48+
**Priority:** high.
49+
50+
Decide whether the documented semantics or the current propagator behavior is
51+
the intended contract. Add direct tests for zero width, zero height, and both
52+
dimensions zero before changing either implementation or documentation.
53+
54+
### #107 and #108: Autotools installation cleanup
55+
56+
**Priority:** high before release; small scope.
57+
58+
Use staged installations to verify both reports. Example data headers should not
59+
be installed when examples are disabled, and disabling FlatZinc should not
60+
create empty MiniZinc directories. Test the positive installation paths as well
61+
as the disabled configurations.
62+
63+
### #126: dead website link
64+
65+
**Priority:** high before release; trivial scope.
66+
67+
Replace the dead Global Constraint Catalog URL with
68+
<https://sofdem.github.io/gccat/> in the website source. Verify the deployed
69+
page rather than closing the issue from a source-only change.
70+
71+
### #151: wrong TSP example result
72+
73+
**Priority:** medium-high; good contained correctness task.
74+
75+
The `br17` instance contains valid zero-cost edges, while the example treats a
76+
zero cost as an absent edge. Separate edge existence from edge cost and verify
77+
all bundled instances, including the known optimum of 39 for `br17`.
78+
79+
## Float behavior and embedding contracts
80+
81+
### #175: unexpected `OutOfLimits`
82+
83+
**Priority:** medium-high.
84+
85+
Port the C++ reproducer to `main` and inspect the interval assigned to each
86+
subexpression. The likely failure boundary is conservative nonlinear interval
87+
construction rather than search. Preserve the exception until sound, tighter
88+
bounds can be demonstrated.
89+
90+
### #155: rounding-mode side effects
91+
92+
**Priority:** medium; technically interesting.
93+
94+
Document the rounding-mode contract first. Evaluate a public RAII guard that
95+
saves and restores the caller's mode, with tests on supported platforms. Avoid
96+
an implicit per-operation guard unless measurements show that its cost and
97+
interaction with user propagators are acceptable.
98+
99+
### #164: unbounded float search
100+
101+
**Priority:** low.
102+
103+
The example asks the default search to choose an unbounded float satisfying a
104+
strict inequality. Confirm current behavior, then prefer a diagnostic or
105+
documentation change unless the same problem occurs with a bounded variable.
106+
107+
## Scheduling and MiniZinc integration
108+
109+
### #80, #81, and #82: scheduling lowering
110+
111+
**Priority:** medium as a single project, low as isolated old tickets.
112+
113+
Re-audit these issues against current `cumulatives` and optional-task support.
114+
List the remaining start/duration/end variants, identify decompositions that
115+
still live in the C++ registry, and benchmark native posting against
116+
MiniZinc-level rewriting. Decide zero-duration semantics explicitly. Replace the
117+
three historical issues with one current design issue if their original
118+
dependency structure no longer describes the code.
119+
120+
### #99: statistics and Gist mode
121+
122+
**Priority:** low.
123+
124+
Confirm that `-s` still overrides `-mode gist`. If it does, keep Gist selection
125+
authoritative and arrange statistics output around that mode. This is a suitable
126+
small task if Gist remains an actively supported interface.
127+
128+
## Propagation strength and search behavior
129+
130+
### #143: infeasible `nooverlap` model searches for too long
131+
132+
**Priority:** medium-low.
133+
134+
Measure the search rather than treating elapsed time alone as a hang. The model
135+
looks like a pigeonhole inconsistency that pairwise non-overlap propagation may
136+
not prove at the root. Consider redundant capacity reasoning only after the
137+
baseline confirms that propagation, rather than an actual loop, is the problem.
138+
139+
## API and command-line usability
140+
141+
### #145: construct `BoolExpr` from `bool`
142+
143+
**Priority:** low-medium.
144+
145+
Define Boolean constants separately from the empty accumulator semantics added
146+
for default-constructed `BoolExpr`. Cover composition, posting, copying, and
147+
materialization of both `true` and `false`.
148+
149+
### #144: reject unsupported options and print help
150+
151+
**Priority:** low-medium.
152+
153+
Specify whether `Options::parse()` owns unknown-option handling or reports it to
154+
the caller. Add tests for unknown options, help, missing values, and applications
155+
that register custom options before changing the public behavior.
156+
157+
### #141: successful test-run summary
158+
159+
**Priority:** low; good first issue.
160+
161+
Print a short success summary after a complete test run. Keep filtered runs and
162+
early failures unambiguous, and make the CMake and Autotools entry points agree.
163+
164+
## Release administration
165+
166+
### #148, #177, and #215: publish and identify 6.3.0
167+
168+
**Priority:** release completion.
169+
170+
Keep these open until the release is published. Close them together after the
171+
release artifacts, website version, and downstream-facing stability statement
172+
are available.
173+
174+
## Verify and close
175+
176+
These issues describe code paths that have been replaced or behavior that is
177+
intentional. They should receive a focused verification and an explanatory
178+
closure rather than new implementation work.
179+
180+
### #83: CMake examples ignored optional features
181+
182+
Configure without MPFR and verify that the two MPFR-only examples are skipped.
183+
Current CMake code already contains this selection.
184+
185+
### #92: malformed Qt version detection
186+
187+
Run configuration with a failing or unusable `qmake`. Current Autoconf code
188+
validates the parsed major version before numeric comparison.
189+
190+
### #65: adopt `AX_PTHREAD`
191+
192+
Close as obsolete. `main` uses standard C++ threads and no longer depends on the
193+
old pthread feature-detection design.
194+
195+
### #52: shared-library versions
196+
197+
Perform a staged shared build and check the installed library names and
198+
symlinks. Current CMake targets set both `VERSION` and `SOVERSION`.
199+
200+
### #117: `-fPIC` in static libraries
201+
202+
Close as intentional unless the project wants to support a second explicitly
203+
non-PIC archive configuration. PIC archives can be linked into shared libraries
204+
and position-independent executables.
205+
206+
### #146 and #172: Qt build support questions
207+
208+
Close as answered or stale after one current Qt-enabled build check. Both reports
209+
appear to concern local Qt discovery or mixed Qt installations rather than
210+
reproducible defects in `main`.
211+
212+
## Suggested execution order
213+
214+
1. Fix #166, then #168.
215+
2. Bound and reproduce #199 before publishing the release.
216+
3. Resolve #142 and the small release-facing items #107, #108, #126, and #151.
217+
4. Verify and close #83, #92, #65, #52, #117, #146, and #172.
218+
5. Investigate #175 and define a practical contract for #155.
219+
6. Reframe #80#82 as one current scheduling project.
220+
7. Work through the remaining search and usability issues as capacity permits.

gecode/int/gcc/dom-sup.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1417,7 +1417,8 @@ namespace Gecode { namespace Int { namespace GCC {
14171417
ValNode* v = vars[i]->first()->getVal();
14181418
vars[i]->first()->free(bc);
14191419
GECODE_ME_CHECK(x[i].eq(home, v->val));
1420-
v->inc();
1420+
if (bc == UBC)
1421+
v->inc();
14211422
}
14221423

14231424
for (int i = n_val; i--; ) {
@@ -1766,4 +1767,3 @@ namespace Gecode { namespace Int { namespace GCC {
17661767

17671768
// STATISTICS: int-prop
17681769

1769-

test/flatzinc/issue166.cpp

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2+
/*
3+
* Main authors:
4+
* Mikael Zayenz Lagerkvist <lagerkvist@gecode.dev>
5+
*
6+
* Copyright:
7+
* Mikael Zayenz Lagerkvist, 2026
8+
*
9+
* This file is part of Gecode, the generic constraint
10+
* development environment:
11+
* http://www.gecode.dev
12+
*
13+
* Permission is hereby granted, free of charge, to any person obtaining
14+
* a copy of this software and associated documentation files (the
15+
* "Software"), to deal in the Software without restriction, including
16+
* without limitation the rights to use, copy, modify, merge, publish,
17+
* distribute, sublicense, and/or sell copies of the Software, and to
18+
* permit persons to whom the Software is furnished to do so, subject to
19+
* the following conditions:
20+
*
21+
* The above copyright notice and this permission notice shall be
22+
* included in all copies or substantial portions of the Software.
23+
*
24+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28+
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29+
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30+
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31+
*/
32+
33+
#include "test/flatzinc.hh"
34+
35+
namespace Test { namespace FlatZinc {
36+
37+
namespace {
38+
/// Check that recomputation does not lose a solution
39+
bool check(const std::string& output) {
40+
const std::string separator = "----------\n";
41+
int solutions = 0;
42+
for (std::string::size_type p = 0;
43+
(p = output.find(separator,p)) != std::string::npos;
44+
p += separator.size())
45+
solutions++;
46+
return (solutions == 11) &&
47+
(output.find("A = 3;\nB = 1;\nC = 3;\nD = 1;\nE = 2;\nG = 3;\n")
48+
!= std::string::npos);
49+
}
50+
51+
/// Helper class to create and register test
52+
class Create {
53+
public:
54+
/// Perform creation and registration
55+
Create(void) {
56+
(void) new FlatZincTest("Issue166",
57+
"predicate gecode_global_cardinality(array [int] of var int: x, array [int] of int: cover, array [int] of var int: counts);\n\
58+
var 1..3: A :: output_var;\n\
59+
var 1..3: B :: output_var;\n\
60+
var 1..3: C :: output_var;\n\
61+
var 1..2: D :: output_var;\n\
62+
var 2..3: E :: output_var;\n\
63+
var 2..3: G :: output_var;\n\
64+
constraint gecode_global_cardinality([3,A,D,G,E],[1,2,3],[1,B,C]) :: domain;\n\
65+
solve :: int_search([D,A,E,B],input_order,indomain_random,complete) satisfy;\n",
66+
"", true, {"-a", "-r", "0", "-c-d", "8"}, check);
67+
}
68+
};
69+
70+
Create c;
71+
}
72+
73+
}}
74+
75+
// STATISTICS: test-flatzinc

0 commit comments

Comments
 (0)