51class BlackBoxHandle :
public SharedHandle {
53 explicit BlackBoxHandle(BlackBoxBackend* backend) : SharedHandle() {
56 explicit BlackBoxHandle(
const SharedHandle& handle) : SharedHandle(handle) {}
57 BlackBoxHandle(
const BlackBoxHandle& handle) : SharedHandle(handle) {}
58 BlackBoxHandle& operator=(
const BlackBoxHandle& handle) {
61 BlackBoxBackend* operator()(
void)
const {
62 return static_cast<BlackBoxBackend*
>(object());
73 std::vector<std::string>
args;
75 ExecEntry(
const std::string &program0,
const std::vector<std::string> &args0,
76 const BlackBoxHandle &handle0)
80 std::vector<ExecEntry>
exec;
87 const std::string& target,
88 const std::vector<std::string>& args);
89 void fail(std::exception_ptr e);
103 const std::string& mode,
const std::string& target,
104 const std::vector<std::string>& args)
const {
116 return static_cast<bool>(*this) &&
129 const std::string& target,
130 const std::vector<std::string>& args) {
131 if (mode ==
"exec") {
134 if ((e.program == target) && (e.args == args)) {
145 throw Error(
"Blackbox",
"Unknown blackbox protocol `" + mode +
"'");
167 std::exception_ptr e;
173 std::rethrow_exception(e);
183#ifdef GECODE_HAS_FLOAT_VARS
187 BlackBoxHandle backend;
190 BlackBox(
Space& home, BlackBox& p)
191 :
Propagator(home, p), backend(p.backend), context(p.context) {
192 int_input.
update(home, p.int_input);
193 int_output.
update(home, p.int_output);
195 float_input.
update(home, p.float_input);
196 float_output.
update(home, p.float_output);
207 const BlackBoxHandle& backend0,
208 const BlackBoxContextHandle& context0)
209 :
Propagator(home), int_input(int_in), int_output(int_out),
211 float_input(float_in), float_output(float_out),
213 backend(backend0), context(context0) {
215#ifdef GECODE_HAS_FLOAT_VARS
221 PropCost cost(
const Space&,
const ModEventDelta&)
const override {
231#ifdef GECODE_HAS_FLOAT_VARS
236 size_t dispose(Space& home)
override {
238#ifdef GECODE_HAS_FLOAT_VARS
242 backend.~BlackBoxHandle();
243 context.~BlackBoxContextHandle();
245 return sizeof(*this);
250 Propagator* copy(Space& home)
override {
251 return new (home) BlackBox(home, *
this);
254 static ExecStatus post(Home home, ViewArray<Int::IntView>& int_input,
255 ViewArray<Int::IntView>& int_output,
257 ViewArray<Float::FloatView>& float_input,
258 ViewArray<Float::FloatView>& float_output,
260 const BlackBoxContextHandle& context,
261 const std::string& mode,
const std::string& target,
262 const std::vector<std::string>& args);
265class BlackBoxBounds :
public Propagator {
267 ViewArray<Int::IntView> ivar;
268#ifdef GECODE_HAS_FLOAT_VARS
269 ViewArray<Float::FloatView> fvar;
271 SharedArray<bool> sub_int;
272#ifdef GECODE_HAS_FLOAT_VARS
273 SharedArray<bool> sub_float;
275 BlackBoxHandle backend;
276 BlackBoxContextHandle context;
278 BlackBoxBounds(Space& home, BlackBoxBounds& p)
279 : Propagator(home, p), sub_int(p.sub_int),
281 sub_float(p.sub_float),
283 backend(p.backend), context(p.context) {
284 ivar.update(home, p.ivar);
286 fvar.update(home, p.fvar);
291 BlackBoxBounds(Home home, ViewArray<Int::IntView>& ivar0,
293 ViewArray<Float::FloatView>& fvar0,
295 SharedArray<bool> sub_int0,
297 SharedArray<bool> sub_float0,
299 const BlackBoxHandle& backend0,
300 const BlackBoxContextHandle& context0)
301 : Propagator(home), ivar(ivar0),
307 sub_float(sub_float0),
309 backend(backend0), context(context0) {
310 for (
int i = 0;
i < ivar.
size();
i++)
313#ifdef GECODE_HAS_FLOAT_VARS
314 for (
int i = 0;
i < fvar.
size();
i++)
322 PropCost cost(
const Space&,
const ModEventDelta&)
const override {
331 for (
int i = 0;
i < ivar.
size();
i++)
334#ifdef GECODE_HAS_FLOAT_VARS
335 for (
int i = 0;
i < fvar.
size();
i++)
341 size_t dispose(Space& home)
override {
342 for (
int i = 0;
i < ivar.
size();
i++)
345#ifdef GECODE_HAS_FLOAT_VARS
346 for (
int i = 0;
i < fvar.
size();
i++)
352 backend.~BlackBoxHandle();
353 context.~BlackBoxContextHandle();
354 sub_int.~SharedArray<
bool>();
355#ifdef GECODE_HAS_FLOAT_VARS
356 sub_float.~SharedArray<
bool>();
359 return sizeof(*this);
363 Propagator* copy(Space& home)
override {
364 return new (home) BlackBoxBounds(home, *
this);
367 static ExecStatus evaluate(Home home, ViewArray<Int::IntView>& ivar,
369 ViewArray<Float::FloatView>& fvar,
371 BlackBoxHandle& backend,
372 const BlackBoxContextHandle& context);
375 ViewArray<Float::FloatView>& fvar,
377 SharedArray<bool> sub_int,
379 SharedArray<bool> sub_float,
381 const BlackBoxContextHandle& context,
382 const std::string& mode,
const std::string& target,
383 const std::vector<std::string>& args);
389BlackBox::post(Home home, ViewArray<Int::IntView>& int_input,
390 ViewArray<Int::IntView>& int_output,
392 ViewArray<Float::FloatView>& float_input,
393 ViewArray<Float::FloatView>& float_output,
396 const std::string& mode,
const std::string& target,
397 const std::vector<std::string>& args) {
398 BlackBoxHandle backend(context.backendForConstraint(mode, target, args));
399 if ((int_input.size() == 0)
401 && (float_input.size() == 0)
404 std::vector<int64_t> int_in;
405 std::vector<int64_t> int_out(int_output.size());
406 std::vector<double> float_in;
407 std::vector<double> float_out;
408#ifdef GECODE_HAS_FLOAT_VARS
409 float_out.resize(float_output.size());
411 BlackBoxCall call = {int_in, float_in, int_out, float_out};
412 backend()->run(call);
413 for (
int i = 0;
i < int_output.
size();
i++)
414 if (
me_failed(int_output[i].eq(home,
static_cast<int>(int_out[i]))))
416#ifdef GECODE_HAS_FLOAT_VARS
417 for (
int i = 0;
i < float_output.
size();
i++)
418 if (
me_failed(float_output[i].eq(home, float_out[i])))
424 new (home) BlackBox(home, int_input, int_output,
426 float_input, float_output,
433BlackBoxBounds::post(Home home, ViewArray<Int::IntView>& ivar,
435 ViewArray<Float::FloatView>& fvar,
437 SharedArray<bool> sub_int,
439 SharedArray<bool> sub_float,
441 const BlackBoxContextHandle& context,
442 const std::string& mode,
const std::string& target,
443 const std::vector<std::string>& args) {
444 BlackBoxHandle backend(context.backendForConstraint(mode, target, args));
445 bool has_subscription =
false;
446 for (
int i = 0;
i < ivar.
size();
i++)
447 has_subscription = has_subscription || sub_int[i];
448#ifdef GECODE_HAS_FLOAT_VARS
449 for (
int i = 0;
i < fvar.
size();
i++)
450 has_subscription = has_subscription || sub_float[i];
452 if (!has_subscription)
453 return evaluate(home, ivar,
459 new (home) BlackBoxBounds(home, ivar,
472 if (int_input.assigned()
474 && float_input.assigned()
477 std::vector<int64_t> int_in(int_input.size());
478 std::vector<int64_t> int_out(int_output.size());
479 for (
size_t i = 0;
i < int_in.
size();
i++) {
480 int_in[
i] =
static_cast<int64_t
>(int_input[
i].val());
482 std::vector<double> float_in;
483 std::vector<double> float_out;
484#ifdef GECODE_HAS_FLOAT_VARS
485 float_in.resize(float_input.size());
486 float_out.resize(float_output.size());
487 for (
size_t i = 0;
i < float_in.
size();
i++) {
488 float_in[
i] = float_input[
i].val().med();
493 BlackBoxCall call = {int_in, float_in, int_out, float_out};
494 backend()->run(call);
496 context.fail(std::current_exception());
500 for (
size_t i = 0;
i < int_out.
size();
i++) {
503#ifdef GECODE_HAS_FLOAT_VARS
504 for (
size_t i = 0;
i < float_out.
size();
i++) {
509 return home.ES_SUBSUMED(*
this);
515BlackBoxBounds::evaluate(Home home, ViewArray<Int::IntView> &ivar,
517 ViewArray<Float::FloatView> &fvar,
519 BlackBoxHandle& backend,
520 const BlackBoxContextHandle& context) {
521 std::vector<int64_t> int_in(ivar.size() * 2);
522 std::vector<int64_t> int_out(ivar.size() * 2);
523 for (
int i = 0;
i < ivar.
size();
i++) {
524 int_in[
i*2] =
static_cast<int64_t
>(ivar[
i].min());
525 int_in[
i*2+1] =
static_cast<int64_t
>(ivar[
i].max());
527 std::vector<double> float_in;
528 std::vector<double> float_out;
529#ifdef GECODE_HAS_FLOAT_VARS
530 float_in.resize(fvar.size() * 2);
531 float_out.resize(fvar.size() * 2);
532 for (
int i = 0;
i < fvar.
size();
i++) {
533 float_in[
i*2] = fvar[
i].min();
534 float_in[
i*2+1] = fvar[
i].max();
539 BlackBoxCall call = {int_in, float_in, int_out, float_out};
540 backend()->run(call);
542 context.fail(std::current_exception());
546 for (
int i = 0;
i < ivar.
size();
i++) {
547 if (
me_failed(ivar[i].gq(home,
static_cast<int>(int_out[i*2]))) ||
548 me_failed(ivar[i].lq(home,
static_cast<int>(int_out[i*2+1])))) {
552#ifdef GECODE_HAS_FLOAT_VARS
553 for (
int i = 0;
i < fvar.
size();
i++) {
554 if (
me_failed(fvar[i].gq(home, float_out[i*2])) ||
555 me_failed(fvar[i].lq(home, float_out[i*2+1]))) {
570 return (es == ES_OK) ?
ES_NOFIX : es;
578 const std::string &mode,
const std::string &target,
579 const std::vector<std::string> &args) {
582#ifdef GECODE_HAS_FLOAT_VARS
591 ExecStatus es = BlackBox::post(home, int_input, int_output,
593 float_input, float_output,
595 context, mode, target, args);
607static void reason_subscriptions(
const std::vector<int> &reason,
int n_int,
610 for (
int i = 0; i < n_int; i++) {
613 for (
int i = 0; i < n_float; i++) {
614 sub_float[i] =
false;
617 const int n_total = n_int + n_float;
618 std::vector<bool> explained(n_total,
false);
620 auto require = [&](
size_t n,
const char *what) {
621 if (reason.size() - pos < n) {
622 throw Error(
"Blackbox", std::string(
"Malformed blackbox bounds reason: ") +
626 while (pos < reason.size()) {
627 require(1,
"missing explained variable index");
628 int idx = reason[
pos++];
629 if ((idx < 1) || (idx > n_total)) {
630 throw Error(
"Blackbox",
631 "Malformed blackbox bounds reason: explained variable index "
634 if (explained[idx - 1]) {
635 throw Error(
"Blackbox",
636 "Malformed blackbox bounds reason: duplicate explained "
639 explained[idx - 1] =
true;
640 for (
int side = 0; side < 2; side++) {
641 require(1,
"missing reason literal count");
644 throw Error(
"Blackbox",
645 "Malformed blackbox bounds reason: negative literal count.");
647 if (
static_cast<size_t>(
count) > (reason.size() - pos) / 2) {
648 throw Error(
"Blackbox",
649 "Malformed blackbox bounds reason: truncated reason "
652 for (
int k = 0; k <
count; k++) {
653 int var = reason[
pos++];
654 int bnd = reason[
pos++];
655 if (var >= 1 && var <= n_int) {
656 sub_int[var - 1] =
true;
657 }
else if (var > n_int && var <= n_int + n_float) {
658 sub_float[var - 1 - n_int] =
true;
660 throw Error(
"Blackbox",
661 "Malformed blackbox bounds reason: dependency variable "
662 "index is out of range.");
664 if (bnd != 1 && bnd != 2) {
665 throw Error(
"Blackbox",
666 "Malformed blackbox bounds reason: dependency bound "
667 "code is out of range.");
672 for (
int i = 0;
i < n_total;
i++) {
674 throw Error(
"Blackbox",
675 "Malformed blackbox bounds reason: missing explained "
686 const std::string &mode,
const std::string &target,
687 const std::vector<std::string> &args,
688 const std::vector<int> &reason) {
690#ifdef GECODE_HAS_FLOAT_VARS
692 int n_float = fvar.size();
702 reason_subscriptions(reason, ivar.
size(), n_float, sub_int, sub_float);
708 ExecStatus es = BlackBoxBounds::post(home, int_var,
716 context, mode, target, args);
virtual size_t dispose(Space &home)
Delete actor and return its size.
int size(void) const
Return size of array (number of elements).
Model-local context shared by blackbox propagators and search support.
void rethrow(void) const
Rethrow the first recorded propagation exception.
SharedHandle backendForConstraint(const std::string &mode, const std::string &target, const std::vector< std::string > &args) const
Return the backend selected for one constraint as an opaque handle.
void fail(std::exception_ptr e) const
Record the first exception raised during blackbox propagation.
bool failed(void) const
Whether blackbox propagation raised an exception.
void init(void)
Initialize this context if it is empty.
ExecEntry(const std::string &program0, const std::vector< std::string > &args0, const BlackBoxHandle &handle0)
std::vector< std::string > args
std::exception_ptr exception
void fail(std::exception_ptr e)
BlackBoxHandle backendForConstraint(const std::string &mode, const std::string &target, const std::vector< std::string > &args)
std::vector< ExecEntry > exec
std::atomic< bool > error_recorded
Persistent-process backend shared by equal executable configurations.
Dynamic-library backend owned by one blackbox constraint.
Exception class for FlatZinc errors
Home class for posting propagators
void notice(Actor &a, ActorProperty p, bool duplicate=false)
Notice actor property.
bool failed(void) const
Check whether corresponding space is failed.
Passing integer variables.
Class to set group information when a post function is executed.
static PropCost crazy(PropCost::Mod m, unsigned int n)
Exponential complexity for modifier m and size measure n.
Base-class for propagators.
Shared array with arbitrary number of elements.
SharedHandle & operator=(const SharedHandle &sh)
Assignment operator maintaining reference count.
SharedHandle::Object * object(void) const
Access to the shared object.
A lock as a scoped frontend for a mutex.
A mutex for mutual exclausion among several threads.
void update(Space &home, ViewArray< View > &a)
Update array to be a clone of array a.
void subscribe(Space &home, Propagator &p, PropCond pc, bool schedule=true)
Subscribe propagator p with propagation condition pc to variable.
int size(void) const
Return size of array (number of elements).
int ModEventDelta
Modification event deltas.
#define GECODE_ME_CHECK(me)
Check whether modification event me is failed, and forward failure.
#define GECODE_ES_FAIL(es)
Check whether execution status es is failed, and fail space home.
bool me_failed(ModEvent me)
Check whether modification event me is failed.
@ AP_DISPOSE
Actor must always be disposed.
Interpreter for the FlatZinc language.
void blackbox_bounds(Home home, BlackBoxContextHandle &context, const IntVarArgs &ivar, const FloatVarArgs &fvar, const std::string &mode, const std::string &target, const std::vector< std::string > &args, const std::vector< int > &reason)
void blackbox(Home home, BlackBoxContextHandle &context, const IntVarArgs &int_in, const IntVarArgs &int_out, const FloatVarArgs &float_in, const FloatVarArgs &float_out, const std::string &mode, const std::string &target, const std::vector< std::string > &args)
bool pos(const View &x)
Test whether x is positive.
const Gecode::PropCond PC_FLOAT_VAL
Propagate when a view becomes assigned (single value).
const Gecode::PropCond PC_FLOAT_BND
Propagate when minimum or maximum of a view changes.
void subscribe(Space &home, Propagator &p, VY y)
Subscribe propagator p to view y.
void reschedule(Space &home, Propagator &p, VY y)
Schedule propagator p for view y.
const Gecode::PropCond PC_INT_VAL
Propagate when a view becomes assigned (single value).
const Gecode::PropCond PC_INT_BND
Propagate when minimum or maximum of a view changes.
Gecode toplevel namespace
void count(Home home, const IntVarArgs &x, int n, IntRelType irt, int m, IntPropLevel ipl=IPL_DEF)
Post propagator for .
TFE post(PropagatorGroup g)
Only post functions (but not propagators) from g are considered.
@ ES_OK
Execution is okay.
@ ES_FIX
Propagation has computed fixpoint.
@ ES_FAILED
Execution has resulted in failure.
@ ES_NOFIX
Propagation has not computed fixpoint.
Gecode::IntArgs i({1, 2, 3, 4})
#define GECODE_HAS_FLOAT_VARS