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 35a3110598 Squashed 'software/chuffed/' content from commit 2ed0c015
git-subtree-dir: software/chuffed
git-subtree-split: 2ed0c01558d2a5c49c1ce57e048d32c17adf92d3
2021-06-18 09:36:35 +10:00

561 lines
15 KiB
C++

#include <chuffed/core/propagator.h>
#define DISJ_DEBUG 0
using namespace std;
// propagates bounds given precedences
class DisjunctiveBP : public Propagator {
// structure to store propagation info for lazy explanation
struct Pinfo {
int var; // which var's bound changed
int est; // est of set which forced the bound
Pinfo(int v, int e) : var(v), est(e) {}
};
bool trailed_pinfo_sz;
public:
// constant data
vec<IntVar*>& x; // start times
vec<int>& dur; // durations of tasks
BoolView **pred; // precedence literals
// Persistent non-trailed state
int *ests; // task no. sorted according to est in ascending order
int *lets; // task no. sorted according to let in descending order
// Persistent trailed state
Tchar *old_est; // est's before any propagations are made
vec<Pinfo> p_info; // memory for propagation info
int est(int i) { return x[i]->getMin(); }
int let(int i) { return x[i]->getMax() + dur[i]; }
DisjunctiveBP(vec<IntVar*>& _x, vec<int>& _dur, BoolView **_pred, int *_ests, int *_lets)
: x(_x), dur(_dur), pred(_pred), ests(_ests), lets(_lets) {
priority = 3;
old_est = (Tchar*) malloc(x.size() * sizeof(Tchar));
}
Reason createReason(int var, int est) {
if (!trailed_pinfo_sz) {
engine.trail.push(TrailElem(&p_info._size(), 4));
trailed_pinfo_sz = true;
}
p_info.push(Pinfo(var, est));
return Reason(prop_id, p_info.size()-1);
}
bool propagate() {
trailed_pinfo_sz = false;
for (int i = 0; i < x.size(); i++) old_est[i] = est(i);
for (int i = 0; i < x.size(); i++) {
int b = INT_MIN, e = INT_MIN;
for (int ests_i = 0; ests_i < x.size(); ests_i++) {
int j = ests[ests_i];
if (!pred[j][i].isTrue()) continue;
if (old_est[j] >= b) {
e = b = old_est[j];
}
b += dur[j];
}
if (x[i]->setMinNotR(b)) {
if (engine.decisionLevel() == 0) {
fprintf(stderr, "%% prop_id = %d, var_id = %d, i = %d, b = %d\n", prop_id, x[i]->var_id, i, b);
}
if (!x[i]->setMin(b, createReason(i, e))) return false;
}
}
return true;
}
Clause* explain(Lit p, int inf_id) {
Pinfo& pi = p_info[inf_id];
/*
fprintf(stderr, "var = %d, est = %d\n", pi.var, pi.est);
for (int i = 0; i < x.size(); i++) {
fprintf(stderr, "x[%d]: est = %d, let = %d, dur = %d\n", i, est(i), let(i), dur[i]);
}
fprintf(stderr, "Old est: ");
for (int i = 0; i < x.size(); i++) {
fprintf(stderr, "%d ", old_est[i]);
}
fprintf(stderr, "\n");
fprintf(stderr, "Preds: ");
for (int i = 0; i < x.size(); i++) {
fprintf(stderr, "%d ", pred[i][pi.var].isTrue());
}
fprintf(stderr, "\n");
fprintf(stderr, "in: ");
*/
vec<Lit> ps(1);
// can lift!
int lb = pi.est;
for (int i = 0; i < x.size(); i++) {
BoolView& p = pred[i][pi.var];
if (p.isTrue() && old_est[i] >= pi.est) {
ps.push(p.getValLit());
ps.push(x[i]->getMinLit());
lb += dur[i];
// fprintf(stderr, "%d ", i);
}
}
// fprintf(stderr, "\n");
// fprintf(stderr, "lb = %d, inf_lb = %d\n", lb, (sat.c_info[var(p)].v>>2)+1);
assert(lb > sat.c_info[var(p)].val);
/*
for (int i = 0; i < x.size(); i++) {
BoolView& p = pred[i][pi.var];
if (p.isTrue() && est(i) >= pi.est) {
ps.push(p.getValLit());
ps.push(x[i]->getLit(pi.est-1, 3));
}
}
*/
Clause *expl = Clause_new(ps);
expl->temp_expl = 1;
sat.rtrail.last().push(expl);
if (DISJ_DEBUG) fprintf(stderr, "BP explain: length %d\n", expl->size());
return expl;
}
};
// Finds precedences only
class DisjunctiveEF : public Propagator {
// structure to store propagation info for lazy explanation
struct Pinfo {
int ps_i; // point in pre-emptive schedule that inference was made
int var; // task which has to be after set of other tasks
int let; // let of set used to make inference
Clause *expl; // explanation for inference
Pinfo(int _ps_i, int _var, int _let) : ps_i(_ps_i), var(_var),
let(_let), expl(NULL) {}
};
bool trailed_pinfo_sz;
public:
// constant data
vec<IntVar*> x; // start times
vec<int> dur; // durations of tasks
BoolView **pred; // precedence literals
DisjunctiveBP *bp; // bounds propagation part of propagator
// Persistent trailed state
Tint *ps_times; // times in pre-emptive schedule
Tint *ps_tasks; // tasks in pre-emptive schedule
Tint *residual; // residual of task i in current pre-emptive schedule
vec<Pinfo> p_info; // memory for propagation info
// Persistent non-trailed state
int *ests; // task no. sorted according to est in ascending order
int *lets; // task no. sorted according to let in descending order
// Inline functions
int est(int i) { return x[i]->getMin(); }
int let(int i) { return x[i]->getMax() + dur[i]; }
struct SortEstAsc {
DisjunctiveEF *p;
bool operator() (int i, int j) { return p->est(i) < p->est(j); }
SortEstAsc(DisjunctiveEF *_p) : p(_p) {}
} sort_est_asc;
struct SortEstDsc {
DisjunctiveEF *p;
bool operator() (int i, int j) { return p->est(i) > p->est(j); }
SortEstDsc(DisjunctiveEF *_p) : p(_p) {}
} sort_est_dsc;
struct SortLetAsc {
DisjunctiveEF *p;
bool operator() (int i, int j) { return p->let(i) < p->let(j); }
SortLetAsc(DisjunctiveEF *_p) : p(_p) {}
} sort_let_asc;
struct SortLetDsc {
DisjunctiveEF *p;
bool operator() (int i, int j) { return p->let(i) > p->let(j); }
SortLetDsc(DisjunctiveEF *_p) : p(_p) {}
} sort_let_dsc;
DisjunctiveEF(vec<IntVar*>& _x, vec<int>& _dur) : x(_x), dur(_dur),
sort_est_asc(this), sort_est_dsc(this), sort_let_asc(this), sort_let_dsc(this) {
// set priority
priority = 3;
// create all intermediate precedence literals
pred = (BoolView **) malloc(x.size() * sizeof (BoolView *));
for (int i = 0; i < x.size(); i++) pred[i] = (BoolView *) malloc(x.size() * sizeof(BoolView));
for (int i = 0; i < x.size(); i++) {
for (int j = i+1; j < x.size(); j++) {
BoolView r = newBoolVar();
pred[i][j] = r;
pred[j][i] = ~r;
int_rel_half_reif(x[j], IRT_GE, x[i], r, dur[i]);
int_rel_half_reif(x[i], IRT_GE, x[j], ~r, dur[j]);
}
pred[i][i] = bv_false;
}
// initialise data structures
ps_times = (Tint*) malloc(4 * x.size() * sizeof(Tint));
ps_tasks = (Tint*) malloc(4 * x.size() * sizeof(Tint));
residual = (Tint*) malloc(x.size() * sizeof(Tint));
ests = (int*) malloc(x.size() * sizeof(int));
lets = (int*) malloc(x.size() * sizeof(int));
for (int i = 0; i < x.size(); i++) ests[i] = lets[i] = i;
// attach to var events
for (int i = 0; i < x.size(); i++) x[i]->attach(this, i, EVENT_LU);
bp = new DisjunctiveBP(x, dur, pred, ests, lets);
}
bool findBasicPrecedences() {
int* eet = new int[x.size()];
int* lst = new int[x.size()];
// int eet[x.size()];
// int lst[x.size()];
for (int i = 0; i < x.size(); i++) {
eet[i] = x[i]->getMin() + dur[i];
lst[i] = x[i]->getMax();
}
for (int i = 0; i < x.size(); i++) {
for (int j = i+1; j < x.size(); j++) {
// Can lift these explanations
// if (prop_id == 1 && i == 0 && j == 2) {
// fprintf(stderr, "lst(0) = %d, eet(0) = %d, lst(2) = %d, eet(2) = %d\n", lst[0], eet[0], lst[2], eet[2]);
// }
if (lst[i] < eet[j]) {
setDom(pred[i][j], setVal, 1, x[i]->getMaxLit(), x[j]->getMinLit());
}
if (lst[j] < eet[i]) {
setDom(pred[j][i], setVal, 1, x[j]->getMaxLit(), x[i]->getMinLit());
}
}
}
delete[] eet;
delete[] lst;
return true;
}
Reason createReason(int ps_i, int var, int let) {
if (!trailed_pinfo_sz) {
engine.trail.push(TrailElem(&p_info._size(), 4));
trailed_pinfo_sz = true;
}
p_info.push(Pinfo(ps_i, var, let));
return Reason(prop_id, p_info.size()-1);
}
bool doEdgeFinding() {
for (int i = 0; i < x.size(); i++) residual[i] = dur[i];
// create pre-emptive schedule
int ests_i = 0;
int ps_i = 0;
int cur_time = est(ests[0]);
int next_lb = 0;
int lets_comp = x.size();
Heap<SortLetAsc> pqueue(sort_let_asc);
// fprintf(stderr, "Forming schedule\n");
while (true) {
ps_times[ps_i] = cur_time;
if (let(lets[lets_comp-1]) <= cur_time) {
explainFailure(lets[lets_comp-1], ps_i);
return false;
}
// process newly available tasks
for ( ; ests_i < x.size(); ests_i++) {
int task = ests[ests_i];
if (x[task]->getMin() > cur_time) break;
assert(x[task]->getMin() == cur_time);
// add task to priority queue
pqueue.insert(task);
// infer precedences by looking for bound b s.t.
// cur_time + dur[task] + sum_{t | let(t) <= b} residual[t] > b
int lets_i;
int eet = cur_time + dur[task];
for (lets_i = lets_comp; let(lets[--lets_i]) < let(task); ) {
eet += residual[lets[lets_i]];
if (eet > let(lets[lets_i])) break;
}
// no precedences can be inferred
if (let(lets[lets_i]) == let(task)) continue;
// precedences can be inferred
Reason r = createReason(ps_i, task, let(lets[lets_i]));
for (int i = lets_i; i < lets_comp; i++) {
if (residual[lets[i]] == 0) continue;
BoolView& v = pred[lets[i]][task];
if (v.setValNotR(1)) {
if (!v.setVal(1, r)) return false;
}
}
}
// move to next time point
next_lb = (ests_i == x.size() ? INT_MAX : est(ests[ests_i]));
ps_tasks[ps_i] = pqueue.empty() ? -1 : pqueue[0];
ps_i++;
if (pqueue.empty()) {
// do nothing until next available task
assert(next_lb != INT_MAX);
// fprintf("w%d, ", next_lb - cur_time);
cur_time = next_lb;
} else {
Tint& res = residual[pqueue[0]];
if (cur_time + res <= next_lb) {
// fprintf("f%d, ", res);
// can finish off highest priority task
cur_time += res;
res = 0;
pqueue.removeMin();
while (lets_comp && residual[lets[lets_comp-1]] == 0) lets_comp--;
// fprintf(stderr, "lets_comp = %d\n", lets_comp);
if (lets_comp == 0) break;
} else {
// do some of highest priority task
// fprintf("f%d, ", next_lb - cur_time);
res = res - next_lb + cur_time;
cur_time = next_lb;
}
}
}
return true;
}
void explainFailure(int task, int ps_i) {
// find set which forced the precedence
// bool in[x.size()];
bool* in = new bool[x.size()];
int set_est = est(task);
/*
for (int i = 0; i < x.size(); i++) {
fprintf(stderr, "x[%d]: est = %d, let = %d, dur = %d\n", i, est(i), let(i), dur[i]);
}
fprintf(stderr, "ests: ");
for (int i = 0; i < x.size(); i++) fprintf(stderr, "%d ", ests[i]);
fprintf(stderr, "\n");
fprintf(stderr, "lets: ");
for (int i = 0; i < x.size(); i++) fprintf(stderr, "%d ", lets[i]);
fprintf(stderr, "\n");
fprintf(stderr, "Schedule:\n");
for (int i = 0; i < ps_i; i++) {
fprintf(stderr, "%d: %d, ", ps_times[i], ps_tasks[i]);
}
fprintf(stderr, "\n");
fprintf(stderr, "task = %d, cur_time = %d, in: \n", task, ps_times[ps_i]);
*/
for (int i = 0; i < x.size(); i++) in[i] = false;
in[task] = true;
while (ps_times[ps_i--] > set_est) {
if (!in[ps_tasks[ps_i]]) {
in[ps_tasks[ps_i]] = true;
if (est(ps_tasks[ps_i]) < set_est) set_est = est(ps_tasks[ps_i]);
}
}
/*
for (int i = 0; i < x.size(); i++) {
if (in[i]) fprintf(stderr, "%d ", i);
}
fprintf(stderr, "\n");
*/
// create explanation
vec<Lit> ps;
// can lift!
for (int i = 0; i < x.size(); i++) {
if (!in[i]) continue;
ps.push(x[i]->getMinLit());
ps.push(x[i]->getMaxLit());
}
/*
ps.push(x[pi.var]->getLit(set_est, 2));
for (int i = 0; i < x.size(); i++) {
if (!in[i]) continue;
ps.push(x[i]->getLit(set_est, 2));
ps.push(x[i]->getLit(set_let - dur[i], 3));
}
*/
Clause *expl = Clause_new(ps);
expl->temp_expl = 1;
sat.rtrail.last().push(expl);
sat.confl = expl;
if (DISJ_DEBUG) fprintf(stderr, "EF fail: length %d\n", expl->size());
delete[] in;
}
bool propagate() {
trailed_pinfo_sz = false;
// sort vars based on est and let
sort(ests, ests + x.size(), sort_est_asc);
sort(lets, lets + x.size(), sort_let_dsc);
// if (!findBasicPrecedences()) return false;
if (so.disj_edge_find && !doEdgeFinding()) return false;
if (so.disj_set_bp && !bp->propagate()) return false;
return true;
}
Clause* explain(Lit p, int inf_id) {
Pinfo& pi = p_info[inf_id];
if (pi.expl != NULL) return pi.expl;
// find set which forced the precedence
// bool in[x.size()];
bool* in = new bool[x.size()];
int ps_i = pi.ps_i;
int set_est = ps_times[ps_i];
for (int i = 0; i < x.size(); i++) {
if (let(i) <= pi.let && residual[i] > 0) {
in[i] = true;
if (est(i) < set_est) set_est = est(i);
} else {
in[i] = false;
}
}
// fprintf(stderr, "task = %d, cur_time = %d, let = %d, in: \n", pi.var, ps_times[pi.ps_i], pi.let);
while (ps_times[ps_i--] > set_est) {
if (!in[ps_tasks[ps_i]]) {
in[ps_tasks[ps_i]] = true;
if (est(ps_tasks[ps_i]) < set_est) set_est = est(ps_tasks[ps_i]);
}
}
/*
for (int i = 0; i < x.size(); i++) {
fprintf(stderr, "x[%d]: est = %d, let = %d, dur = %d\n", i, est(i), let(i), dur[i]);
}
fprintf(stderr, "ests: ");
for (int i = 0; i < x.size(); i++) fprintf(stderr, "%d ", ests[i]);
fprintf(stderr, "\n");
fprintf(stderr, "lets: ");
for (int i = 0; i < x.size(); i++) fprintf(stderr, "%d ", lets[i]);
fprintf(stderr, "\n");
fprintf(stderr, "Schedule:\n");
for (int i = 0; i < pi.ps_i; i++) {
fprintf(stderr, "%d: %d, ", ps_times[i], ps_tasks[i]);
}
fprintf(stderr, "\n");
fprintf(stderr, "residual: ");
for (int i = 0; i < x.size(); i++) fprintf(stderr, "%d ", residual[i]);
fprintf(stderr, "\n");
for (int i = 0; i < x.size(); i++) {
if (in[i]) fprintf(stderr, "%d ", i);
}
fprintf(stderr, "\n");
*/
// create explanation
vec<Lit> ps(1);
// can lift!
ps.push(x[pi.var]->getMinLit());
for (int i = 0; i < x.size(); i++) {
if (!in[i]) continue;
ps.push(x[i]->getMinLit());
ps.push(x[i]->getMaxLit());
}
/*
ps.push(x[pi.var]->getLit(set_est, 2));
for (int i = 0; i < x.size(); i++) {
if (!in[i]) continue;
ps.push(x[i]->getLit(set_est, 2));
ps.push(x[i]->getLit(pi.let - dur[i], 3));
}
*/
Clause *expl = Clause_new(ps);
expl->temp_expl = 1;
sat.rtrail.last().push(expl);
pi.expl = expl;
if (DISJ_DEBUG) fprintf(stderr, "EF explain: length %d\n", expl->size());
delete[] in;
return expl;
}
};
void disjunctive(vec<IntVar*>& x, vec<int>& dur) {
new DisjunctiveEF(x, dur);
}