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
21 changes: 21 additions & 0 deletions changelog.in
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,27 @@ Date: unreleased
[DESCRIPTION]
This is the development changelog for the next Gecode release.

[ENTRY]
Module: kernel
What: new
Rank: minor
[DESCRIPTION]
Add Space::NoGPI for scoped posting without globally retained propagator
information. Scoped propagators keep their identifiers and groups in the
space, have zero AFC, and copy their information when cloned. Rewriting
preserves the original propagator information. Space::UseGPI enables global
information for selected posting calls inside a NoGPI scope. Both contexts
restore the previous setting when they leave scope.

[ENTRY]
Module: int
What: bug
Rank: minor
[DESCRIPTION]
Fix iterator invalidation when counting-based search removes expired
propagator cache entries. The invalid iterator could skip remaining entries
and leave the brancher without a choice.

[ENTRY]

Module: int
Expand Down
16 changes: 9 additions & 7 deletions gecode/int/branch/cbs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,13 +191,15 @@ namespace Gecode { namespace Int { namespace Branch {

// We delete unvisited propagators from the log and look for the highest
// solution density across all propagators.
for (const auto& kv : logProp) {
unsigned int prop_id = kv.first;
const PropInfo& info = kv.second;
if (!info.visited)
logProp.erase(prop_id);
else if (info.dens > maxSD.dens)
maxSD = {info.var_id, info.val, info.dens};
for (auto i = logProp.begin(); i != logProp.end(); ) {
if (!i->second.visited) {
i = logProp.erase(i);
} else {
const PropInfo& info = i->second;
if (info.dens > maxSD.dens)
maxSD = {info.var_id, info.val, info.dens};
++i;
}
}

assert(maxSD.dens != -1);
Expand Down
19 changes: 16 additions & 3 deletions gecode/kernel/core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ namespace Gecode {
VarImpDisposerBase* Space::vd[AllVarConf::idx_d];
#endif

Space::Space(void) : mm(ssd.data().sm) {
Space::Space(void) : mm(ssd.data().sm), no_gpi(false) {
#ifdef GECODE_HAS_CBS
var_id_counter = 0;
#endif
Expand Down Expand Up @@ -540,7 +540,8 @@ namespace Gecode {
// Process failure
failed:
// Count failure
ssd.data().gpi.fail(p->gpi());
if (!p->local_info())
ssd.data().gpi.fail(p->gpi());
// Mark as failed
fail();
// Propagate top priority propagators
Expand Down Expand Up @@ -727,7 +728,7 @@ namespace Gecode {
#ifdef GECODE_HAS_CBS
var_id_counter(s.var_id_counter),
#endif
d_fst(&Actor::sentinel),d_cur(nullptr),d_lst(nullptr) {
no_gpi(false), d_fst(&Actor::sentinel),d_cur(nullptr),d_lst(nullptr) {
#ifdef GECODE_HAS_VAR_DISPOSE
for (int i=0; i<AllVarConf::idx_d; i++)
_vars_d[i] = nullptr;
Expand Down Expand Up @@ -920,11 +921,23 @@ namespace Gecode {
}


void*
Space::local_info(unsigned int gid) {
static_assert(alignof(Kernel::GPI::Info) >= 4,
"Propagator information needs two tag bits");
Kernel::GPI::Info* i = alloc<Kernel::GPI::Info>(1);
i->init(ssd.data().gpi.next_pid(),gid);
i->afc = 0.0;
return Support::ptrjoin(i,2);
}

void
Space::afc_unshare(void) {
if (ssd.data().gpi.unshare()) {
for (Propagators ps(*this); ps(); ++ps) {
Propagator& p = ps.propagator();
if (p.local_info())
continue;
Kernel::GPI::Info* gpi
= ssd.data().gpi.allocate(p.gpi().pid,p.gpi().gid);
if (p.disabled())
Expand Down
117 changes: 113 additions & 4 deletions gecode/kernel/core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1087,12 +1087,19 @@ namespace Gecode {
/// A list of advisors (used during cloning)
Gecode::ActorLink* advisors;
} u;
/// A tagged pointer combining a pointer to global propagator information and whether the propagator is disabled
/**
* \brief Tagged pointer to propagator information
*
* Bit zero marks disabled propagators; bit one marks space-local
* information, which has no accumulated failure count.
*/
void* gpi_disabled;
/// Static cast for a non-null pointer (to give a hint to optimizer)
static Propagator* cast(ActorLink* al);
/// Static cast for a non-null pointer (to give a hint to optimizer)
static const Propagator* cast(const ActorLink* al);
/// Whether propagator information is local to the space
bool local_info(void) const;
/// Disable propagator
void disable(Space& home);
/// Enable propagator
Expand All @@ -1104,7 +1111,7 @@ namespace Gecode {
Propagator(Space& home, Propagator& p);
/// Return forwarding pointer during copying
Propagator* fwd(void) const;
/// Provide access to global propagator information
/// Provide access to propagator information
Kernel::GPI::Info& gpi(void);

public:
Expand Down Expand Up @@ -1791,6 +1798,8 @@ namespace Gecode {
friend GECODE_KERNEL_EXPORT
void trace(Home home, TraceFilter tf, int te, Tracer& t);
private:
/// Allocate tagged space-local propagator information
GECODE_KERNEL_EXPORT void* local_info(unsigned int gid);
/// Shared data for space
Kernel::SharedSpaceData ssd;
/// Performs memory management for space
Expand All @@ -1799,6 +1808,8 @@ namespace Gecode {
/// Global counter for variable ids
unsigned int var_id_counter;
#endif
/// Whether new propagator information is local to this space
bool no_gpi;
/// Doubly linked list of all propagators
ActorLink pl;
/// Doubly linked list of all branchers
Expand Down Expand Up @@ -2037,6 +2048,68 @@ namespace Gecode {
GECODE_KERNEL_EXPORT
void ap_ignore_dispose(Actor* a, bool d);
public:
/**
* \brief Suppress global propagator information during scoped posting
* \ingroup TaskModelScript
*
* New propagators posted into this space use space-local information
* instead of records retained by all spaces in a search. Their AFC is
* always zero, including after AFC initialization or unsharing. They
* retain normal identifiers and groups, so tracing and counting-based
* search remain supported. Group changes for these propagators are
* local to the space; clones copy the current group. Local records are
* reclaimed with the space, even if their propagators subsume earlier.
* AFC-based branching therefore only counts ordinary propagators.
*
* Rewriting inherits the original propagator's information, regardless
* of this context. Existing propagators are unaffected. Clones retain
* local information but start with ordinary posting enabled.
*
* A nested UseGPI context enables global information for selected
* posting calls. Both contexts restore the previous setting on destruction,
* including exception unwinding. The space must outlive the context,
* and contexts for the same space must be destroyed in reverse order.
*/
class NoGPI {
private:
/// Space in which to suppress global information
Space& home;
/// Previous setting
bool previous;
NoGPI(const NoGPI&) = delete;
NoGPI& operator =(const NoGPI&) = delete;
public:
/// Suppress global information for new propagators in \a home
explicit NoGPI(Space& home);
/// Restore the previous setting
~NoGPI(void);
};

/**
* \brief Enable global propagator information during scoped posting
* \ingroup TaskModelScript
*
* Overrides an enclosing NoGPI context for new propagators posted into
* this space. Rewriting still inherits the original information.
* Destruction restores the previous setting, including exception
* unwinding. The space must outlive the context, and NoGPI and UseGPI
* contexts for the same space must be destroyed in reverse order.
*/
class UseGPI {
private:
/// Space in which to enable global information
Space& home;
/// Previous setting
bool previous;
UseGPI(const UseGPI&) = delete;
UseGPI& operator =(const UseGPI&) = delete;
public:
/// Enable global information for new propagators in \a home
explicit UseGPI(Space& home);
/// Restore the previous setting
~UseGPI(void);
};

/**
* \brief Default constructor
* \ingroup TaskModelScript
Expand Down Expand Up @@ -3556,6 +3629,28 @@ namespace Gecode {
}


forceinline
Space::NoGPI::NoGPI(Space& h) : home(h), previous(h.no_gpi) {
home.no_gpi = true;
}

forceinline
Space::NoGPI::~NoGPI(void) {
home.no_gpi = previous;
}


forceinline
Space::UseGPI::UseGPI(Space& h) : home(h), previous(h.no_gpi) {
home.no_gpi = false;
}

forceinline
Space::UseGPI::~UseGPI(void) {
home.no_gpi = previous;
}


/*
* Propagator
*
Expand All @@ -3581,6 +3676,11 @@ namespace Gecode {
return static_cast<Propagator*>(prev());
}

forceinline bool
Propagator::local_info(void) const {
return (reinterpret_cast<ptrdiff_t>(gpi_disabled) & 2) != 0;
}

forceinline bool
Propagator::disabled(void) const {
return Support::marked(gpi_disabled);
Expand All @@ -3600,14 +3700,18 @@ namespace Gecode {

forceinline Kernel::GPI::Info&
Propagator::gpi(void) {
return *static_cast<Kernel::GPI::Info*>(Support::funmark(gpi_disabled));
return *reinterpret_cast<Kernel::GPI::Info*>
(reinterpret_cast<ptrdiff_t>(gpi_disabled) & ~static_cast<ptrdiff_t>(3));
}

forceinline
Propagator::Propagator(Home home)
: gpi_disabled((home.propagator() != nullptr) ?
// Inherit propagator information
home.propagator()->gpi_disabled :
static_cast<Space&>(home).no_gpi ?
static_cast<Space&>(home).local_info
(home.propagatorgroup().gid) :
// New propagator information
static_cast<Space&>(home).ssd.data().gpi.allocate
(home.propagatorgroup().gid)) {
Expand All @@ -3617,8 +3721,13 @@ namespace Gecode {
}

forceinline
Propagator::Propagator(Space&, Propagator& p)
Propagator::Propagator(Space& home, Propagator& p)
: gpi_disabled(p.gpi_disabled) {
if (p.local_info()) {
Kernel::GPI::Info* i = home.alloc<Kernel::GPI::Info>(1);
*i = p.gpi();
gpi_disabled = Support::ptrjoin(i, p.disabled() ? 3 : 2);
}
u.advisors = nullptr;
assert((u.med == 0) && (u.size == 0));
// Set forwarding pointer
Expand Down
9 changes: 8 additions & 1 deletion gecode/kernel/gpi.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ namespace Gecode { namespace Kernel {
Info* allocate(unsigned int p, unsigned int gid);
/// Allocate new actor info
Info* allocate(unsigned int gid);
/// Allocate a new propagator id without allocating information
unsigned int next_pid(void);
/// Return next free propagator id
unsigned int pid(void) const;
/// Provide access to unshare info and set to true
Expand Down Expand Up @@ -141,6 +143,11 @@ namespace Gecode { namespace Kernel {
return d;
}

forceinline unsigned int
GPI::next_pid(void) {
return npid.fetch_add(1, std::memory_order_seq_cst);
}

forceinline unsigned int
GPI::pid(void) const {
return npid.load(std::memory_order_acquire);
Expand Down Expand Up @@ -186,7 +193,7 @@ namespace Gecode { namespace Kernel {
}
c = &b->info[--b->free];
m.release();
c->init(npid.fetch_add(1, std::memory_order_seq_cst),gid);
c->init(next_pid(),gid);
return c;
}

Expand Down
Loading
Loading