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

386 lines
13 KiB
C++
Executable File

/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
* Main authors:
* Mikael Lagerkvist <lagerkvist@gecode.org>
*
* Copyright:
* Mikael Lagerkvist, 2005
*
* 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 <algorithm>
/*
* This is the propagation algorithm of the cumulatives constraint as
* presented in:
* Nicolas Beldiceanu and Mats Carlsson, A New Multi-resource cumulatives
* Constraint with Negative Heights. CP 2002, pages 63-79, Springer-Verlag.
*/
namespace Gecode { namespace Int { namespace Cumulatives {
template<class ViewM, class ViewP, class ViewU, class View>
forceinline
Val<ViewM,ViewP,ViewU,View>::Val(Home home,
const ViewArray<ViewM>& _m,
const ViewArray<View>& _s,
const ViewArray<ViewP>& _p,
const ViewArray<View>& _e,
const ViewArray<ViewU>& _u,
const SharedArray<int>& _c,
bool _at_most) :
Propagator(home),
m(_m), s(_s), p(_p), e(_e), u(_u), c(_c), at_most(_at_most) {
home.notice(*this,AP_DISPOSE);
m.subscribe(home,*this,Int::PC_INT_DOM);
s.subscribe(home,*this,Int::PC_INT_BND);
p.subscribe(home,*this,Int::PC_INT_BND);
e.subscribe(home,*this,Int::PC_INT_BND);
u.subscribe(home,*this,Int::PC_INT_BND);
}
template<class ViewM, class ViewP, class ViewU, class View>
ExecStatus
Val<ViewM,ViewP,ViewU,View>
::post(Home home, const ViewArray<ViewM>& m,
const ViewArray<View>& s, const ViewArray<ViewP>& p,
const ViewArray<View>& e, const ViewArray<ViewU>& u,
const SharedArray<int>& c, bool at_most) {
(void) new (home) Val(home, m,s,p,e,u,c,at_most);
return ES_OK;
}
template<class ViewM, class ViewP, class ViewU, class View>
forceinline
Val<ViewM,ViewP,ViewU,View>::Val(Space& home,
Val<ViewM,ViewP,ViewU,View>& vp)
: Propagator(home,vp), c(vp.c), at_most(vp.at_most) {
m.update(home,vp.m);
s.update(home, vp.s);
p.update(home, vp.p);
e.update(home, vp.e);
u.update(home, vp.u);
}
template<class ViewM, class ViewP, class ViewU, class View>
size_t
Val<ViewM,ViewP,ViewU,View>::dispose(Space& home) {
home.ignore(*this,AP_DISPOSE);
if (!home.failed()) {
m.cancel(home,*this,Int::PC_INT_DOM);
s.cancel(home,*this,Int::PC_INT_BND);
p.cancel(home,*this,Int::PC_INT_BND);
e.cancel(home,*this,Int::PC_INT_BND);
u.cancel(home,*this,Int::PC_INT_BND);
}
c.~SharedArray();
(void) Propagator::dispose(home);
return sizeof(*this);
}
template<class ViewM, class ViewP, class ViewU, class View>
PropCost
Val<ViewM,ViewP,ViewU,View>::cost(const Space&, const ModEventDelta&) const {
return PropCost::quadratic(PropCost::LO, s.size());
}
template<class ViewM, class ViewP, class ViewU, class View>
void
Val<ViewM,ViewP,ViewU,View>::reschedule(Space& home) {
m.reschedule(home,*this,Int::PC_INT_DOM);
s.reschedule(home,*this,Int::PC_INT_BND);
p.reschedule(home,*this,Int::PC_INT_BND);
e.reschedule(home,*this,Int::PC_INT_BND);
u.reschedule(home,*this,Int::PC_INT_BND);
}
template<class ViewM, class ViewP, class ViewU, class View>
Actor*
Val<ViewM,ViewP,ViewU,View>::copy(Space& home) {
return new (home) Val<ViewM,ViewP,ViewU,View>(home,*this);
}
/// Types of events for the sweep-line
typedef enum {EVENT_CHCK, EVENT_PROF, EVENT_PRUN} ev_t;
/// An event collects the information for one evnet for the sweep-line
class Event
{
public:
/// The type of the event
ev_t e;
/// The task this event refers to
int task;
/// The date of this event
int date;
/// The quantity changed by this event (if any)
int inc;
/** If the type is EVENT_PROF and it is the first of the pair,
* this value is true. Added to handle contribution-values
* correctly for both at_most and at_least.
*/
bool first_prof;
/// Simple constructor
Event(ev_t _e, int _task, int _date, int _inc = 0, bool _first_prof = false)
: e(_e), task(_task), date(_date), inc(_inc), first_prof(_first_prof)
{}
// Default constructor for region-allocated memory
Event(void) {}
/// Order events based on date.
bool operator <(const Event& ev) const {
if (date == ev.date) {
if (e == EVENT_PROF && ev.e != EVENT_PROF) return true;
if (e == EVENT_CHCK && ev.e == EVENT_PRUN) return true;
return false;
}
return date < ev.date;
}
};
template<class ViewM, class ViewP, class ViewU, class View>
ExecStatus
Val<ViewM,ViewP,ViewU,View>::prune(Space& home, int low, int up, int r,
int ntask, int su,
int* contribution,
int* prune_tasks, int& prune_tasks_size) {
if (ntask > 0 && (at_most ? su > c[r] : su < c[r])) {
return ES_FAILED;
}
int pti = 0;
while (pti != prune_tasks_size) {
int t = prune_tasks[pti];
// Algorithm 2.
// Prune the machine, start, and end for required
// tasks for machine r that have heights possibly greater than 0.
if (ntask != 0 &&
(at_most ? u[t].min() < 0
: u[t].max() > 0) &&
(at_most ? su-contribution[t] > c[r]
: su-contribution[t] < c[r])) {
if (me_failed(m[t].eq(home, r))||
me_failed(s[t].gq(home, up-p[t].max()+1))||
me_failed(s[t].lq(home, low))||
me_failed(e[t].lq(home,low+p[t].max()))||
me_failed(e[t].gq(home, up+1))||
me_failed(p[t].gq(home,std::min(up-s[t].max()+1,e[t].min()-low)))
) {
return ES_FAILED;
}
}
// Algorithm 3.
// Remove values that prevent us from reaching the limit
if (at_most ? u[t].min() > std::min(0, c[r])
: u[t].max() < std::max(0, c[r])) {
if (at_most ? su-contribution[t]+u[t].min() > c[r]
: su-contribution[t]+u[t].max() < c[r]) {
if (e[t].min() > low &&
s[t].max() <= up &&
p[t].min() > 0) {
if (me_failed(m[t].nq(home, r))) {
return ES_FAILED;
}
} else if (m[t].assigned()) {
int ptmin = p[t].min();
if (ptmin > 0) {
Iter::Ranges::Singleton
a(low-ptmin+1, up), b(low+1, up+ptmin);
if (me_failed(s[t].minus_r(home,a,false)) ||
me_failed(e[t].minus_r(home, b,false)))
return ES_FAILED;
}
if (me_failed(p[t].lq(home,std::max(std::max(low-s[t].min(),
e[t].max()-up-1),
0)))) {
return ES_FAILED;
}
}
}
}
// Algorithm 4.
// Remove bad negative values from for-sure heights.
/* \note "It is not sufficient to only test for assignment of machine[t]
* since Algorithm 3 can remove the value." Check this against
* the conditions for Alg3.
*/
if (m[t].assigned() &&
m[t].val() == r &&
e[t].min() > low &&
s[t].max() <= up &&
p[t].min() > 0 ) {
if (me_failed(at_most
? u[t].lq(home, c[r]-su+contribution[t])
: u[t].gq(home, c[r]-su+contribution[t]))) {
return ES_FAILED;
}
}
// Remove tasks that are no longer relevant.
if (!m[t].in(r) || (e[t].max() <= up+1)) {
prune_tasks[pti] = prune_tasks[--prune_tasks_size];
} else {
++pti;
}
}
return ES_OK;
}
namespace {
template<class C>
class Less {
public:
bool operator ()(const C& lhs, const C& rhs) {
return lhs < rhs;
}
};
}
template<class ViewM, class ViewP, class ViewU, class View>
ExecStatus
Val<ViewM,ViewP,ViewU,View>::propagate(Space& home, const ModEventDelta&) {
// Check for subsumption
bool subsumed = true;
for (int t=0; t<s.size(); t++)
if (!(p[t].assigned() && e[t].assigned() &&
m[t].assigned() && s[t].assigned() &&
u[t].assigned())) {
subsumed = false;
break;
}
// Propagate information for machine r
Region region;
Event *events = region.alloc<Event>(s.size()*8);
int events_size;
int *prune_tasks = region.alloc<int>(s.size());
int prune_tasks_size;
int *contribution = region.alloc<int>(s.size());
for (int r = c.size(); r--; ) {
events_size = 0;
#define GECODE_PUSH_EVENTS(E) assert(events_size < s.size()*8); \
events[events_size++] = E
// Find events for sweep-line
for (int t = s.size(); t--; ) {
if (m[t].assigned() &&
m[t].val() == r &&
s[t].max() < e[t].min()) {
if (at_most
? u[t].min() > std::min(0, c[r])
: u[t].max() < std::max(0, c[r])) {
GECODE_PUSH_EVENTS(Event(EVENT_CHCK, t, s[t].max(), 1));
GECODE_PUSH_EVENTS(Event(EVENT_CHCK, t, e[t].min(), -1));
}
if (at_most
? u[t].min() > 0
: u[t].max() < 0) {
GECODE_PUSH_EVENTS(Event(EVENT_PROF, t, s[t].max(),
at_most ? u[t].min() : u[t].max(), true));
GECODE_PUSH_EVENTS(Event(EVENT_PROF, t, e[t].min(),
at_most ? -u[t].min() : -u[t].max()));
}
}
if (m[t].in(r)) {
if (at_most
? u[t].min() < 0
: u[t].max() > 0) {
GECODE_PUSH_EVENTS(Event(EVENT_PROF, t, s[t].min(),
at_most ? u[t].min() : u[t].max(), true));
GECODE_PUSH_EVENTS(Event(EVENT_PROF, t, e[t].max(),
at_most ? -u[t].min() : -u[t].max()));
}
if (!(m[t].assigned() &&
u[t].assigned() &&
s[t].assigned() &&
e[t].assigned())) {
GECODE_PUSH_EVENTS(Event(EVENT_PRUN, t, s[t].min()));
}
}
}
#undef GECODE_PUSH_EVENTS
// If there are no events, continue with next machine
if (events_size == 0) {
continue;
}
// Sort the events according to date
Less<Event> less;
Support::insertion(&events[0], events_size, less);
// Sweep line along d, starting at 0
int d = 0;
int ntask = 0;
int su = 0;
int ei = 0;
prune_tasks_size = 0;
for (int i = s.size(); i--; ) contribution[i] = 0;
d = events[ei].date;
while (ei < events_size) {
if (events[ei].e != EVENT_PRUN) {
if (d != events[ei].date) {
GECODE_ES_CHECK(prune(home, d, events[ei].date-1, r,
ntask, su,
contribution, prune_tasks, prune_tasks_size));
d = events[ei].date;
}
if (events[ei].e == EVENT_CHCK) {
ntask += events[ei].inc;
} else /* if (events[ei].e == EVENT_PROF) */ {
su += events[ei].inc;
if(events[ei].first_prof)
contribution[events[ei].task] = at_most
? std::max(contribution[events[ei].task], events[ei].inc)
: std::min(contribution[events[ei].task], events[ei].inc);
}
} else /* if (events[ei].e == EVENT_PRUN) */ {
assert(prune_tasks_size<s.size());
prune_tasks[prune_tasks_size++] = events[ei].task;
}
ei++;
}
GECODE_ES_CHECK(prune(home, d, d, r,
ntask, su,
contribution, prune_tasks, prune_tasks_size));
}
return subsumed ? home.ES_SUBSUMED(*this): ES_NOFIX;
}
}}}
// STATISTICS: int-prop