1
0
This repository has been archived on 2025-03-06. You can view files and clone it, but cannot push or open issues or pull requests.
Jip J. Dekker 981be2067e Squashed 'software/gecode_on_replay/' content from commit 8051d92b9
git-subtree-dir: software/gecode_on_replay
git-subtree-split: 8051d92b9c89e49cccfbd1c201371580d7703ab4
2021-06-16 14:04:29 +10:00

325 lines
9.6 KiB
C++

/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
* Main authors:
* Christian Schulte <schulte@gecode.org>
*
* Copyright:
* Christian Schulte, 2011
*
* This file is part of Gecode, the generic constraint
* development environment:
* http://www.gecode.org
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include <gecode/int/distinct.hh>
namespace Gecode { namespace Int { namespace NValues {
template<class VY>
forceinline
IntBase<VY>::IntBase(Home home, ValSet& vs0, ViewArray<IntView>& x, VY y)
: MixNaryOnePropagator<IntView,PC_INT_DOM,VY,PC_INT_BND>(home,x,y),
vs(vs0) {}
template<class VY>
forceinline
IntBase<VY>::IntBase(Space& home, IntBase<VY>& p)
: MixNaryOnePropagator<IntView,PC_INT_DOM,VY,PC_INT_BND>(home, p) {
vs.update(home, p.vs);
}
template<class VY>
forceinline size_t
IntBase<VY>::dispose(Space& home) {
vs.dispose(home);
(void) MixNaryOnePropagator<IntView,PC_INT_DOM,VY,PC_INT_BND>
::dispose(home);
return sizeof(*this);
}
template<class VY>
PropCost
IntBase<VY>::cost(const Space&, const ModEventDelta&) const {
return PropCost::quadratic(PropCost::HI, x.size());
}
template<class VY>
void
IntBase<VY>::add(Space& home) {
int n=x.size();
for (int i=n; i--; )
if (x[i].assigned()) {
vs.add(home, x[i].val());
x[i] = x[--n];
}
x.size(n);
}
template<class VY>
void
IntBase<VY>::disjoint(Space& home, Region& r, int*& dis, int& n_dis) {
// Compute positions of disjoint views
int n=x.size();
dis = r.alloc<int>(n); n_dis = 0;
int i=0;
while (i < n)
switch (vs.compare(x[i])) {
case Iter::Ranges::CS_SUBSET:
// All values are already contained in vs, eliminate x[i]
x[i].cancel(home, *this, PC_INT_DOM);
x[i] = x[--n];
break;
case Iter::Ranges::CS_DISJOINT:
dis[n_dis++] = i++;
break;
case Iter::Ranges::CS_NONE:
i++;
break;
default:
GECODE_NEVER;
}
x.size(n);
}
template<class VY>
void
IntBase<VY>::eliminate(Space& home) {
int n=x.size();
for (int i=n; i--; )
if (vs.subset(x[i])) {
// All values are already contained in vs, eliminate x[i]
x[i].cancel(home, *this, PC_INT_DOM);
x[i] = x[--n];
}
x.size(n);
}
template<class VY>
ExecStatus
IntBase<VY>::all_in_valset(Space& home) {
for (int i=x.size(); i--; ) {
ValSet::Ranges vsr(vs);
GECODE_ME_CHECK(x[i].inter_r(home, vsr, false));
}
return home.ES_SUBSUMED(*this);
}
template<class VY>
ExecStatus
IntBase<VY>::prune_lower(Space& home, int* dis, int n_dis) {
assert(n_dis > 0);
// At least one more value will be needed
GECODE_ME_CHECK(y.gq(home,vs.size() + 1));
Region r;
// Only one additional value is allowed
if (y.max() == vs.size() + 1) {
// Compute possible values
ViewRanges<IntView>* r_dis = r.alloc<ViewRanges<IntView> >(n_dis);
for (int i=n_dis; i--; )
r_dis[i] = ViewRanges<IntView>(x[dis[i]]);
Iter::Ranges::NaryInter iv(r, r_dis, n_dis);
// Is there a common value at all?
if (!iv())
return ES_FAILED;
ValSet::Ranges vsr(vs);
Iter::Ranges::NaryUnion pv(r,iv,vsr);
// Enforce common values
for (int i=x.size(); i--; ) {
pv.reset();
GECODE_ME_CHECK(x[i].inter_r(home, pv, false));
}
return ES_OK;
}
// Compute independent set for lower bound
// ovl is a bit-matrix defining whether two views overlap
SymBitMatrix ovl(r,x.size());
// deg[i] is the degree of x[i]
int* deg = r.alloc<int>(x.size());
// ovl_i[i] is an array of indices j such that x[j] overlaps with x[i]
int** ovl_i = r.alloc<int*>(x.size());
// n_ovl_i[i] defines how many integers are stored for ovl_i[i]
int* n_ovl_i = r.alloc<int>(x.size());
{
#ifndef NDEBUG
// Initialize all to null pointers so that things crash ;-)
for (int i=x.size(); i--; )
ovl_i[i] = nullptr;
#endif
// For each i there can be at most n_dis-1 entries in ovl_i[i]
int* m = r.alloc<int>(n_dis*(n_dis-1));
for (int i=n_dis; i--; ) {
deg[dis[i]] = 0;
ovl_i[dis[i]] = m; m += n_dis-1;
}
}
// Initialize overlap matrix by analyzing the view ranges
{
// Compute how many events are needed
// One event for the end marker
int n_re = 1;
// Two events for each range
for (int i=n_dis; i--; )
for (ViewRanges<IntView> rx(x[dis[i]]); rx(); ++rx)
n_re += 2;
// Allocate and initialize events
RangeEvent* re = r.alloc<RangeEvent>(n_re);
{
int j=0;
for (int i=n_dis; i--; )
for (ViewRanges<IntView> rx(x[dis[i]]); rx(); ++rx) {
// Event when a range starts
re[j].ret=RET_FST; re[j].val=rx.min(); re[j].view=dis[i]; j++;
// Event when a range ends
re[j].ret=RET_LST; re[j].val=rx.max(); re[j].view=dis[i]; j++;
}
// Make this the last event
re[j].ret=RET_END; re[j].val=Int::Limits::infinity;
assert(j+1 == n_re);
}
// Sort and process events
Support::quicksort(re,n_re);
// Current views with a range being active
Support::BitSet<Region> cur(r,static_cast<unsigned int>(x.size()));
// Process all events
for (int i=0; true; i++)
switch (re[i].ret) {
case RET_FST:
// Process all overlapping views
for (Iter::Values::BitSet<Support::BitSet<Region> > j(cur);
j(); ++j) {
int di = re[i].view, dj = j.val();
if (!ovl.get(di,dj)) {
ovl.set(di,dj);
ovl_i[di][deg[di]++] = dj;
ovl_i[dj][deg[dj]++] = di;
}
}
cur.set(static_cast<unsigned int>(re[i].view));
break;
case RET_LST:
cur.clear(static_cast<unsigned int>(re[i].view));
break;
case RET_END:
goto done;
default:
GECODE_NEVER;
}
done:
r.free<RangeEvent>(re,n_re);
}
// While deg changes, n_ovl_i remains unchanged and is needed, so copy it
for (int i=n_dis; i--; ) {
assert(deg[dis[i]] < n_dis);
n_ovl_i[dis[i]] = deg[dis[i]];
}
// Views in the independent set
int* ind = r.alloc<int>(n_dis);
int n_ind = 0;
while (n_dis > 0) {
int i_min = n_dis-1;
int d_min = deg[dis[i_min]];
unsigned int s_min = x[dis[i_min]].size();
// Find view with smallest (degree,size)
for (int i=n_dis-1; i--; )
if ((d_min > deg[dis[i]]) ||
((d_min == deg[dis[i]]) && (s_min > x[dis[i]].size()))) {
i_min = i;
d_min = deg[dis[i]];
s_min = x[dis[i]].size();
}
// i_min refers to view with smallest (degree,size)
ind[n_ind++] = dis[i_min]; dis[i_min] = dis[--n_dis];
// Filter out non disjoint views
for (int i=n_dis; i--; )
if (ovl.get(dis[i],ind[n_ind-1])) {
// Update degree information
for (int j=n_ovl_i[dis[i]]; j--; )
deg[ovl_i[dis[i]][j]]--;
// Eliminate view
dis[i] = dis[--n_dis];
}
}
// Enforce lower bound
GECODE_ME_CHECK(y.gq(home,vs.size() + n_ind));
// Prune, if possible
if (vs.size() + n_ind == y.max()) {
// Only values from the indepent set a can be taken
ViewRanges<IntView>* r_ind = r.alloc<ViewRanges<IntView> >(n_ind);
for (int i=n_ind; i--; )
r_ind[i] = ViewRanges<IntView>(x[ind[i]]);
Iter::Ranges::NaryUnion v_ind(r, r_ind, n_ind);
ValSet::Ranges vsr(vs);
v_ind |= vsr;
for (int i=x.size(); i--; ) {
v_ind.reset();
GECODE_ME_CHECK(x[i].inter_r(home,v_ind,false));
}
}
return ES_OK;
}
template<class VY>
forceinline ExecStatus
IntBase<VY>::prune_upper(Space& home, Graph& g) {
if (!g) {
g.init(home,vs,x);
} else {
g.purge();
g.sync();
}
GECODE_ME_CHECK(y.lq(home, g.size()));
if (y.min() == g.size()) {
// All values must be taken on
if (vs.size() + x.size() == g.size()) {
// This is in fact a distinct, simplify and rewrite
for (int i=x.size(); i--; ) {
ValSet::Ranges vsr(vs);
GECODE_ME_CHECK(x[i].minus_r(home, vsr, false));
}
GECODE_REWRITE(*this,Distinct::Dom<IntView>::post(home(*this),x));
}
if (g.mark())
GECODE_ES_CHECK(g.prune(home));
}
return ES_OK;
}
}}}
// STATISTICS: int-prop