Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions changelog.in
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,17 @@ This release modernizes the Gecode build infrastructure, adds a
first-class CMake package for downstream consumers, refreshes the
autoconf build path, and updates CI coverage for current platforms.

[ENTRY]
Module: minimodel
What: bug
Rank: minor
Issue: 139
Thanks: yuri@FreeBSD
[DESCRIPTION]
Fix default-constructed Boolean expressions so they can be used as
empty accumulators for conjunction and disjunction without reading
uninitialized node state.

[ENTRY]
Module: float
What: bug
Expand Down
23 changes: 19 additions & 4 deletions gecode/minimodel/bool-expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ namespace Gecode {
*
*/
BoolExpr::Node::Node(void)
: use(1), l(nullptr), r(nullptr), m(nullptr) {}
: use(1), same(0), t(NT_AND), l(nullptr), r(nullptr), m(nullptr) {}

BoolExpr::Node::~Node(void) {
delete m;
Expand Down Expand Up @@ -125,8 +125,18 @@ namespace Gecode {
n->x = x;
}

BoolExpr::BoolExpr(const BoolExpr& l, NodeType t, const BoolExpr& r)
: n(new Node) {
BoolExpr::BoolExpr(const BoolExpr& l, NodeType t, const BoolExpr& r) {
if (((t == NT_AND) || (t == NT_OR)) && (l.n->same == 0)) {
n = r.n;
n->use++;
return;
}
if (((t == NT_AND) || (t == NT_OR)) && (r.n->same == 0)) {
n = l.n;
n->use++;
return;
}
n = new Node;
int ls = ((l.n->t == t) || (l.n->t == NT_VAR)) ? l.n->same : 1;
int rs = ((r.n->t == t) || (r.n->t == NT_VAR)) ? r.n->same : 1;
n->same = ls+rs;
Expand All @@ -140,7 +150,10 @@ namespace Gecode {
BoolExpr::BoolExpr(const BoolExpr& l, NodeType t) {
(void) t;
assert(t == NT_NOT);
if (l.n->t == NT_NOT) {
if (l.n->same == 0) {
n = l.n;
n->use++;
} else if (l.n->t == NT_NOT) {
n = l.n->l;
n->use++;
} else {
Expand Down Expand Up @@ -505,6 +518,8 @@ namespace Gecode {

NNF*
NNF::nnf(Region& r, Node* n, bool neg) {
if (n->same == 0)
throw MiniModel::TooFewArguments("BoolExpr");
switch (n->t) {
case BoolExpr::NT_VAR:
case BoolExpr::NT_RLIN:
Expand Down
39 changes: 39 additions & 0 deletions test/int/mm-bool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,41 @@ namespace Test { namespace Int {
}
};

/// %Test Boolean expressions with default-constructed accumulators
class BoolExprDefaultAccumulator : public Test {
protected:
/// Boolean operation to accumulate
BoolOpcode o;
/// Whether the default expression starts on the right hand side
bool rhs;
public:
/// Create and register test
BoolExprDefaultAccumulator(BoolOpcode o0, bool rhs0)
: Test("MiniModel::BoolExpr::Default::"+
std::string(o0 == BO_AND ? "And" : "Or")+
(rhs0 ? "::Rhs" : "::Lhs"),3,0,1), o(o0), rhs(rhs0) {}
/// %Test whether \a x is solution
virtual bool solution(const Assignment& x) const {
int r = (o == BO_AND) ? (x[0] & x[1]) : (x[0] | x[1]);
return r == x[2];
}
/// Post constraint on \a x
virtual void post(Gecode::Space& home, Gecode::IntVarArray& x) {
using namespace Gecode;
Gecode::BoolExpr e;
Gecode::BoolExpr x0(channel(home,x[0]));
Gecode::BoolExpr x1(channel(home,x[1]));
if (o == BO_AND) {
e = rhs ? (x0 && e) : (e && x0);
e = e && x1;
} else {
e = rhs ? (x0 || e) : (e || x0);
e = e || x1;
}
rel(home, expr(home,e), IRT_EQ, channel(home,x[2]));
}
};

const BoolInstr bi000[] = {
{BO_AND,0,1,0},{BO_AND,2,3,1},{BO_AND,0,1,0},
{BO_HLT,0,0,0}
Expand Down Expand Up @@ -4382,6 +4417,10 @@ namespace Test { namespace Int {
(void) new BoolElement("Expr::A",0);
(void) new BoolElement("Expr::B",1);
(void) new BoolElement("Rel",2);
(void) new BoolExprDefaultAccumulator(BO_AND,false);
(void) new BoolExprDefaultAccumulator(BO_AND,true);
(void) new BoolExprDefaultAccumulator(BO_OR,false);
(void) new BoolExprDefaultAccumulator(BO_OR,true);
}
};

Expand Down
Loading