Skip to content

Commit

Permalink
Fix defines_var annotation for cyclic definitions. Fixes #863.
Browse files Browse the repository at this point in the history
  • Loading branch information
guidotack committed Nov 8, 2024
1 parent 23a91c2 commit 1c2edcb
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 3 deletions.
1 change: 1 addition & 0 deletions changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Bug fixes:
- Fix compilation of empty arrays with empty domains (:bugref:`860`).
- Fix evaluation of ``dom_array`` on par arrays (:bugref:`851`).
- Fix flattening of array slices inside tuples and records (:bugref:`859`).
- Fix defines_var annotation for cyclic definitions (:bugref:`863`).

.. _v2.8.7:

Expand Down
22 changes: 19 additions & 3 deletions lib/flatten.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5527,10 +5527,10 @@ void oldflatzinc(Env& e) {
}
auto it = definition_map.find(ident->decl());
if (it != definition_map.end()) {
if (it->second.second == 0) {
if (it->second.second == DFS_UNKNOWN) {
// not yet visited, push
definesStack.push_back(it->first);
} else if (it->second.second == 1) {
} else if (it->second.second == DFS_SEEN) {
// Found a cycle through variable ident
// Break cycle by removing annotations
Expression::ann(ident->decl()).remove(Constants::constants().ann.is_defined_var);
Expand All @@ -5540,7 +5540,7 @@ void oldflatzinc(Env& e) {
}
};
for (auto* it : definitions) {
if (definition_map[it].second == 0) {
if (definition_map[it].second == DFS_UNKNOWN) {
// not yet visited
definesStack.push_back(it);
while (!definesStack.empty()) {
Expand All @@ -5555,6 +5555,7 @@ void oldflatzinc(Env& e) {
if (Call* c = Expression::dynamicCast<Call>(
(*m)[definition_map[cur].first]->cast<ConstraintI>()->e())) {
// Variable is defined by a call, push all arguments
unsigned int count_cur = 0;
for (unsigned int i = 0; i < c->argCount(); i++) {
if (Expression::type(c->arg(i)).isPar()) {
continue;
Expand All @@ -5564,21 +5565,36 @@ void oldflatzinc(Env& e) {
if (auto* al = Expression::dynamicCast<ArrayLit>(ident->decl()->e())) {
for (auto* e : al->getVec()) {
if (auto* ident = Expression::dynamicCast<Id>(e)) {
if (cur == ident->decl()) {
count_cur++;
}
checkId(cur, ident);
}
}
}
} else if (ident->type().isvar()) {
if (cur == ident->decl()) {
count_cur++;
}
checkId(cur, ident);
}
} else if (auto* al = Expression::dynamicCast<ArrayLit>(c->arg(i))) {
for (auto* e : al->getVec()) {
if (auto* ident = Expression::dynamicCast<Id>(e)) {
if (cur == ident->decl()) {
count_cur++;
}
checkId(cur, ident);
}
}
}
}
if (count_cur != 1) {
// We've seen the defined variable 0 times or more than once,
// so this call cannot define the variable
Expression::ann(cur).remove(Constants::constants().ann.is_defined_var);
Expression::ann(c).removeCall(Constants::constants().ann.defines_var);
}
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions tests/spec/unit/compilation/test_bug_863.fzn
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
predicate gecode_int_element(var int: idx,int: idxoffset,array [int] of var int: x,var int: c);
var 1..2: X_INTRODUCED_0_;
var 1..2: y:: output_var;
array [1..2] of var int: x:: output_array([1..2]) = [X_INTRODUCED_0_,y];
constraint gecode_int_element(y,1,x,y);
solve satisfy;
11 changes: 11 additions & 0 deletions tests/spec/unit/compilation/test_bug_863.mzn
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/***
!Test
type: compile
solvers: [gecode]
expected: !FlatZinc test_bug_863.fzn
***/

array[1..2] of var 1..2: x;
var 1..2: y;
constraint x[y] = x[2];
constraint y == x[2];

0 comments on commit 1c2edcb

Please sign in to comment.