Skip to content
Merged
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
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1363,6 +1363,8 @@ if(BUILD_TESTING)
Int::Arithmetic::Max::Nary
Int::Cumulative::Man::Fix::0::4
Int::Distinct::Random
Int::Extensional::TupleSet::Sparse::IncrementalDelta
Int::Extensional::TupleSet::Auto::DefaultDispatch
Int::Linear::Bool::Int::Lq
Int::MiniModel::LinExpr::Bool::352
NoGoods::Queens
Expand Down
2 changes: 2 additions & 0 deletions Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -1312,6 +1312,8 @@ CHECKTESTS = Branch::Int::Dense::3 \
Int::Arithmetic::Max::Nary \
Int::Cumulative::Man::Fix::0::4 \
Int::Distinct::Random \
Int::Extensional::TupleSet::Sparse::IncrementalDelta \
Int::Extensional::TupleSet::Auto::DefaultDispatch \
Int::Linear::Bool::Int::Lq \
Int::MiniModel::LinExpr::Bool::352 \
NoGoods::Queens \
Expand Down
26 changes: 26 additions & 0 deletions changelog.in
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,32 @@ Strengthen bin-packing propagation with lower bounds based on
dual-feasible functions, improving early detection of infeasible
packing states.

[ENTRY]
Module: int
What: new
Rank: major
[DESCRIPTION]
Add selectable TupleSet support representations for extensional integer
constraints.
[MORE]
Tuple sets can use dense, sparse, compressed-dense, or automatic support
selection. Extensional posting selects the matching propagator. DFA-derived
tuple sets accept the same selector, while FlatZinc tables and examples that
materialize larger tuple sets use automatic selection.

A failed finalization leaves the tuple set in a terminal failed state,
reported by failed(); it cannot be finalized again.

[ENTRY]
Module: int
What: bug
Rank: minor
[DESCRIPTION]
Avoid reading past TupleSet range data when a negative compact-table
propagator receives an assignment outside every table range. Positive
compact-table propagators also preserve pending updates when a disabled
space is cloned and later enabled.

[ENTRY]
Module: other
What: change
Expand Down
2 changes: 1 addition & 1 deletion examples/black-hole.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ class BlackHole : public Script {
for (int s2 = 4; s2--; )
for (int i = -1; i <= 1; i+=2)
ts.add({r+13*s1, (r+i+52+13*s2)%52});
ts.finalize();
ts.finalize(EPK_AUTO);

for (int i = 51; i--; )
extensional(*this, IntVarArgs({x[i],x[i+1]}), ts);
Expand Down
2 changes: 1 addition & 1 deletion examples/colored-matrix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -624,7 +624,7 @@ namespace {
}
}
}
result.finalize();
result.finalize(EPK_AUTO);
return result;
}

Expand Down
2 changes: 1 addition & 1 deletion examples/crossword.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ class Crossword : public Script {
ts.add(w);
}
}
ts.finalize();
ts.finalize(EPK_AUTO);

// Array of all words of length w_l
IntVarArgs words(*this,n,0,n_w-1);
Expand Down
2 changes: 1 addition & 1 deletion examples/crowded-chess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ namespace {
delete s;
}

bishops.finalize();
bishops.finalize(EPK_AUTO);
}
}
/**
Expand Down
2 changes: 1 addition & 1 deletion examples/golf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ class Golf : public Script {
for (int p1=0; p1<playerCount-1; p1++)
for (int p2=p1+1; p2<playerCount; p2++)
ts.add({p1, p2, pairCount++});
ts.finalize();
ts.finalize(EPK_AUTO);

// Collect pairs of golfers into pairs
IntVarArgs pairs;
Expand Down
2 changes: 1 addition & 1 deletion examples/kakuro.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ namespace {
while (DistinctLinear* s = d.next()) {
ts.add(s->solution()); delete s;
}
ts.finalize();
ts.finalize(EPK_AUTO);
return ts;
}

Expand Down
2 changes: 1 addition & 1 deletion gecode/flatzinc/flatzinc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2338,7 +2338,7 @@ namespace Gecode { namespace FlatZinc {
}
ts.add(t);
}
ts.finalize();
ts.finalize(EPK_AUTO);

if (_initData) {
FlatZincSpaceInitData::TupleSetSet::iterator it = _initData->tupleSetSet.find(ts);
Expand Down
171 changes: 167 additions & 4 deletions gecode/int.hh
Original file line number Diff line number Diff line change
Expand Up @@ -2332,8 +2332,45 @@ namespace Gecode {

#include <gecode/int/extensional/dfa.hpp>

namespace Gecode { namespace Int { namespace Extensional {

class TupleSetAccess;

}}}

namespace Gecode {

/**
* \brief Support representation selection for extensional tuple sets
*
* The selector controls which support representation is materialized by
* TupleSet::finalize(ExtensionalPropKind). Tuple-set posting dispatches to
* the propagator for the concrete representation stored in the tuple set.
* During finalization, EPK_AUTO selects dense or compressed support
* according to the normal size and density policy; it never selects sparse
* support.
*
* \ingroup TaskModelIntExt
*/
enum class ExtensionalPropKind {
EPK_AUTO, ///< Select dense or compressed representation automatically
EPK_DENSE, ///< Use dense support representation
EPK_SPARSE, ///< Use sparse support representation
EPK_DENSE_COMPRESSED ///< Use compressed dense support representation
};
/// Select dense or compressed representation automatically
static constexpr ExtensionalPropKind EPK_AUTO =
ExtensionalPropKind::EPK_AUTO;
/// Use dense support representation
static constexpr ExtensionalPropKind EPK_DENSE =
ExtensionalPropKind::EPK_DENSE;
/// Use sparse support representation
static constexpr ExtensionalPropKind EPK_SPARSE =
ExtensionalPropKind::EPK_SPARSE;
/// Use compressed dense support representation
static constexpr ExtensionalPropKind EPK_DENSE_COMPRESSED =
ExtensionalPropKind::EPK_DENSE_COMPRESSED;

/** \brief Class representing a set of tuples.
*
* A TupleSet is used for storing an extensional representation of a
Expand All @@ -2343,6 +2380,7 @@ namespace Gecode {
* \ingroup TaskModelIntExt
*/
class TupleSet : public SharedHandle {
friend class Int::Extensional::TupleSetAccess;
public:
/** \brief Type of a tuple
*
Expand All @@ -2351,6 +2389,12 @@ namespace Gecode {
typedef int* Tuple;
/// Import bit set data type
typedef Gecode::Support::BitSetData BitSetData;
/// Compressed support data for one tuple-word block
class CSupportWord {
public:
unsigned int widx; ///< Word index in tuple-word array
BitSetData bits; ///< Support bits in that word
};
/// Range information
class Range {
public:
Expand All @@ -2362,7 +2406,12 @@ namespace Gecode {
BitSetData* s;
/// Return the width
unsigned int width(void) const;
/// Return the supports for value \a n
/**
* \brief Return the dense supports for value \a n
*
* Returns \c nullptr if the tuple set does not use the dense
* representation.
*/
const BitSetData* supports(unsigned int n_words, int n) const;
};
protected:
Expand All @@ -2373,6 +2422,8 @@ namespace Gecode {
unsigned int n;
/// Ranges
Range* r;
/// Base support id for each range (sparse and compressed only)
unsigned int* base;
/// Find start range for value \a n
unsigned int start(int n) const;
};
Expand All @@ -2384,6 +2435,15 @@ namespace Gecode {
protected:
/// Initial number of free tuples
static const int n_initial_free = 1024;
public:
/// Tuple set lifecycle state and finalized representation
enum State {
TS_BUILDING,
TS_FAILED,
TS_DENSE,
TS_SPARSE,
TS_DENSE_COMPRESSED
};
public:
/// Arity
int arity;
Expand All @@ -2405,8 +2465,26 @@ namespace Gecode {
ValueData* vd;
/// Pointer to all ranges
Range* range;
/// Pointer to all range support ids
unsigned int* range_base;
/// Pointer to all support data
BitSetData* support;
/// Tuple set lifecycle state and finalized representation
State state;
/// Number of sparse support values
unsigned int sparse_n_vals;
/// Sparse support offsets (size sparse_n_vals+1)
unsigned int* sparse_offsets;
/// Sparse support tuple ids (size arity*n_tuples)
unsigned int* sparse_tuples;
/// Tuple cell to sparse support id map (size arity*n_tuples)
unsigned int* sparse_tv;
/// Compressed support offsets (size n_vals+1)
unsigned int* compressed_offsets;
/// Compressed support words (size compressed_n_entries)
CSupportWord* compressed_words;
/// Number of compressed support entries
unsigned int compressed_n_entries;

/// Return newly added tuple
Tuple add(void);
Expand All @@ -2425,11 +2503,28 @@ namespace Gecode {
/// Finalize datastructure (disallows additions of more Tuples)
GECODE_INT_EXPORT
void finalize(void);
/// Finalize datastructure (disallows additions of more Tuples)
GECODE_INT_EXPORT
void finalize(ExtensionalPropKind epk);
/// Resize tuple data
GECODE_INT_EXPORT
void resize(void);
/// Release partially or fully constructed support data
void clear_support(void);
/// Select the state for an empty finalized tuple set
State empty_state(ExtensionalPropKind epk) const;
/// Select the finalized state for the computed table layout
State select_state(
ExtensionalPropKind epk, bool dense_possible,
bool sparse_possible, bool compressed_possible,
bool support_bits_sparse, unsigned long long dense_bytes) const;
/// Is datastructure finalized
bool finalized(void) const;
/// Has finalization failed
bool failed(void) const;
/// Is datastructure no longer mutable
bool terminal(void) const;

/// Initialize as empty tuple set with arity \a a
Data(int a);
/// Delete implementation
Expand Down Expand Up @@ -2464,9 +2559,12 @@ namespace Gecode {
/// Assignment operator
GECODE_INT_EXPORT
TupleSet& operator =(const TupleSet& t);
/// Initialize with DFA \a dfa for arity \a a
/// Initialize with DFA \a dfa for arity \a a using dense supports
GECODE_INT_EXPORT
TupleSet(int a, const DFA& dfa);
/// Initialize with DFA \a dfa for arity \a a and representation \a epk
GECODE_INT_EXPORT
TupleSet(int a, const DFA& dfa, ExtensionalPropKind epk);
/// Test whether tuple set has been initialized
operator bool(void) const;
/// Test whether tuple set is equal to \a t
Expand All @@ -2479,10 +2577,27 @@ namespace Gecode {
//@{
/// Add tuple \a t to tuple set
TupleSet& add(const IntArgs& t);
/// Is tuple set finalized
/// Is tuple set successfully finalized
bool finalized(void) const;
/// Finalize tuple set
/**
* \brief Has tuple-set finalization failed
*
* A failed tuple set is terminal: no tuples can be added and
* finalization cannot be attempted again.
*/
bool failed(void) const;
/// Finalize tuple set with dense support data
void finalize(void);
/// Finalize tuple set with representation \a epk
/**
* Explicit representation selection materializes only the selected
* support representation. EPK_AUTO selects dense or compressed support
* according to the normal size and density policy and never selects
* sparse support. Tuple-set posting uses the selected concrete
* representation.
* If finalization throws, the tuple set is terminal and failed().
*/
void finalize(ExtensionalPropKind epk);
//@}

/// \name Tuple access
Expand All @@ -2501,6 +2616,27 @@ namespace Gecode {
int max(void) const;
/// Return hash key
std::size_t hash(void) const;
/// Return materialized tuple-set representation
ExtensionalPropKind representation(void) const;
private:
/// Return number of sparse support values
unsigned int sparse_values(void) const;
/// Return tuple-value sparse ids (size tuples()*arity())
const unsigned int* sparse_tuple_value_ids(void) const;
/// Return sparse support offsets (size sparse_values()+1)
const unsigned int* sparse_support_offsets(void) const;
/// Return support id for position/value, false if absent
bool support_id(int p, int n, unsigned int& gid) const;
/// Return sparse support tuple id range for position/value, false if absent
bool sparse_support(int p, int n,
const unsigned int*& b,
const unsigned int*& e,
unsigned int& gid) const;
/// Return compressed support words for position/value, false if absent
bool dense_compressed_support(int p, int n,
const CSupportWord*& b,
const CSupportWord*& e) const;
public:
//@}

/// \name Range access and iteration
Expand Down Expand Up @@ -2544,6 +2680,33 @@ namespace Gecode {
//@}
};

namespace Int { namespace Extensional {

/// Internal access to finalized tuple-set support representations
class TupleSetAccess {
public:
/// Return number of sparse support values
static unsigned int sparse_values(const TupleSet& ts);
/// Return tuple-value sparse ids
static const unsigned int* sparse_tuple_value_ids(const TupleSet& ts);
/// Return sparse support offsets
static const unsigned int* sparse_support_offsets(const TupleSet& ts);
/// Return support id for position/value
static bool support_id(const TupleSet& ts, int p, int n,
unsigned int& gid);
/// Return sparse support tuple id range for position/value
static bool sparse_support(const TupleSet& ts, int p, int n,
const unsigned int*& b,
const unsigned int*& e,
unsigned int& gid);
/// Return compressed support words for position/value
static bool dense_compressed_support(const TupleSet& ts, int p, int n,
const TupleSet::CSupportWord*& b,
const TupleSet::CSupportWord*& e);
};

}}

}

#include <gecode/int/extensional/tuple-set.hpp>
Expand Down
Loading
Loading