diff --git a/library/gecode/gecode-common.icc b/library/gecode/gecode-common.icc index 80cb69ab5..a0ce80175 100644 --- a/library/gecode/gecode-common.icc +++ b/library/gecode/gecode-common.icc @@ -41,14 +41,17 @@ namespace generic_gecode Optimizing(): num(-1), den(-1), what(OPT_NONE), how(OPT_MAX) {} Optimizing(Optimizing& o) : num(o.num), den(o.den), what(o.what), how(o.how) {} + void check_ok() const + { if (what!=OPT_NONE) + throw Exception("gecode-python","too many optimization criteria"); } void maximize(int i) - { what = OPT_INT; how = OPT_MAX; num = i; }; + { check_ok(); what = OPT_INT; how = OPT_MAX; num = i; }; void maximize(int i,int j) - { what = OPT_RATIO; how = OPT_MAX; num = i; den = j; }; + { check_ok(); what = OPT_RATIO; how = OPT_MAX; num = i; den = j; }; void minimize(int i) - { what = OPT_INT; how = OPT_MIN; num = i; }; + { check_ok(); what = OPT_INT; how = OPT_MIN; num = i; }; void minimize(int i,int j) - { what = OPT_RATIO; how = OPT_MIN; num = i; den = j; }; + { check_ok(); what = OPT_RATIO; how = OPT_MIN; num = i; den = j; }; }; struct GenericSpace; @@ -80,21 +83,106 @@ namespace generic_gecode virtual GenericSpace* next(void) { return engine.next(); } }; + struct LoadingDock + { + vector ivars; + vector bvars; + vector svars; + vector ikeep; + vector bkeep; + vector skeep; + + bool keeping_some() const + { + return (ikeep.size() != 0) + || (bkeep.size() != 0) + || (skeep.size() != 0); + } + + IntVar get_ivar(int i) const { return ivars[i]; } + BoolVar get_bvar(int i) const { return bvars[i]; } + SetVar get_svar(int i) const { return svars[i]; } + + int enter_ivar(const IntVar& v) + { ivars.push_back(v); return static_cast(ivars.size()-1); } + + int enter_bvar(const BoolVar& v) + { bvars.push_back(v); return static_cast(bvars.size()-1); } + + int enter_svar(const SetVar& v) + { svars.push_back(v); return static_cast(svars.size()-1); } + + int keep_ivar(int i) { ikeep.push_back(i); return static_cast(ikeep.size()-1); } + int keep_bvar(int i) { bkeep.push_back(i); return static_cast(bkeep.size()-1); } + int keep_svar(int i) { skeep.push_back(i); return static_cast(skeep.size()-1); } + + void freeze(Space& home, + IntVarArray& iarr, BoolVarArray& barr, SetVarArray& sarr, + int& num, int& den) + { + if (keeping_some()) + { + // make sure that optimization vars (if any) are kept + if (num != -1) + { + const int _num(num); + const int _den(den); + int n = static_cast(ikeep.size()); + bool num_found(false); + bool den_found(false); + for (;n--;) + { + const int idx(ikeep[n]); + if (idx==_num) + { num_found=true; if (den_found) break; } + if (idx==_den) + { den_found=true; if (num_found) break; } + } + if (!num_found) + { ikeep.push_back(_num); + num=static_cast(ikeep.size()-1); } + if (_den != -1 && !den_found) + { ikeep.push_back(_den); + den=static_cast(ikeep.size()-1); } + } + { int n = static_cast(ikeep.size()); + iarr = IntVarArray(home, n); + for (;n--;) iarr[n]=ivars[ikeep[n]]; } + { int n = static_cast(bkeep.size()); + barr = BoolVarArray(home, n); + for (;n--;) barr[n]=bvars[bkeep[n]]; } + { int n = static_cast(skeep.size()); + sarr = SetVarArray(home, n); + for (;n--;) sarr[n]=svars[skeep[n]]; } + } + else + { + { int n = static_cast(ivars.size()); + iarr = IntVarArray(home, n); + for (;n--;) iarr[n]=ivars[n]; } + { int n = static_cast(bvars.size()); + barr = BoolVarArray(home, n); + for (;n--;) barr[n]=bvars[n]; } + { int n = static_cast(svars.size()); + sarr = SetVarArray(home, n); + for (;n--;) sarr[n]=svars[n]; } + } + } + }; + struct GenericSpace: Space { Optimizing optim; IntVarArray ivars; BoolVarArray bvars; SetVarArray svars; - vector* _ivars; - vector* _bvars; - vector* _svars; + LoadingDock* dock; + bool keeping_some; // iff only SOME of the vars are kept Space* space() { return this; } GenericSpace(bool share, GenericSpace& s) - : Space(share, s), optim(s.optim), - _ivars(NULL), _bvars(NULL), _svars(NULL) + : Space(share, s), optim(s.optim), dock(NULL), keeping_some(s.keeping_some) { ivars.update(*this, share, s.ivars); bvars.update(*this, share, s.bvars); @@ -104,45 +192,53 @@ namespace generic_gecode Space* copy(bool share) { freeze(); return new GenericSpace(share, *this); } - GenericSpace() : _ivars(NULL), _bvars(NULL), _svars(NULL) {} + GenericSpace() : dock(new LoadingDock()), keeping_some(false) {} + ~GenericSpace() { delete dock; } + + // throw some C++ exception on behalf of glue code + void kaboom(const char* s) + { throw Exception("gecode-python", s); } + int ikaboom(const char* s) + { kaboom(s); return 0; } // freeze the space before handing it off to a search engine void freeze() { - if (_ivars) + if (dock) { - int n = _ivars->size(); - ivars = IntVarArray(*this, n); - vector& v(*_ivars); - for (; n--;) ivars[n] = v[n]; - delete _ivars; - _ivars = NULL; - } - - if (_bvars) - { - int n = _bvars->size(); - bvars = BoolVarArray(*this, n); - vector& v(*_bvars); - for (; n--;) bvars[n] = v[n]; - delete _bvars; - _bvars = NULL; - } - - if (_svars) - { - int n = _svars->size(); - svars = SetVarArray(*this, n); - vector& v(*_svars); - for (; n--;) svars[n] = v[n]; - delete _svars; - _svars = NULL; + keeping_some = dock->keeping_some(); + dock->freeze(*this, ivars, bvars, svars, optim.num, optim.den); + delete dock; + dock = NULL; } } - IntVar get_ivar(int i) const { return (_ivars) ? (*_ivars)[i] : ivars[i]; } - BoolVar get_bvar(int i) const { return (_bvars) ? (*_bvars)[i] : bvars[i]; } - SetVar get_svar(int i) const { return (_svars) ? (*_svars)[i] : svars[i]; } + IntVar get_ivar(int i) const { return (dock)?dock->get_ivar(i):ivars[i]; } + BoolVar get_bvar(int i) const { return (dock)?dock->get_bvar(i):bvars[i]; } + SetVar get_svar(int i) const { return (dock)?dock->get_svar(i):svars[i]; } + + int keep_ivar(int i) + { + if (dock) return dock->keep_ivar(i); + else return ikaboom("too late to keep"); + } + + int keep_bvar(int i) + { + if (dock) return dock->keep_bvar(i); + else return ikaboom("too late to keep"); + } + + int keep_svar(int i) + { + if (dock) return dock->keep_svar(i); + else return ikaboom("too late to keep"); + } + + bool frozen() const { return dock==NULL; } + bool has_keepers() const { return keeping_some; } + // when frozen and has_keepers: which is just has_keepers actually + bool use_keep_index() const { return has_keepers(); } GenericEngine* new_engine(bool restart, Search::Options& opt) { @@ -156,10 +252,8 @@ namespace generic_gecode int _new_ivar(IntVar& v) { - if (!_ivars) _ivars = new vector; - int i = _ivars->size(); - _ivars->push_back(v); - return i; + if (dock) return dock->enter_ivar(v); + else return ikaboom("too late to create vars"); } int new_ivar(int lo, int hi) @@ -176,10 +270,8 @@ namespace generic_gecode int _new_bvar(BoolVar& v) { - if (!_bvars) _bvars = new vector; - int i = _bvars->size(); - _bvars->push_back(v); - return i; + if (dock) return dock->enter_bvar(v); + else return ikaboom("too late to create vars"); } int new_bvar() @@ -190,10 +282,8 @@ namespace generic_gecode int _new_svar(SetVar& v) { - if (!_svars) _svars = new vector; - int i = _svars->size(); - _svars->push_back(v); - return i; + if (dock) return dock->enter_svar(v); + else return ikaboom("too late to create vars"); } int new_svar(int glbMin, int glbMax, int lubMin, int lubMax, diff --git a/library/gecode/gecode_yap.cc b/library/gecode/gecode_yap.cc index 416867189..385635bbe 100644 --- a/library/gecode/gecode_yap.cc +++ b/library/gecode/gecode_yap.cc @@ -651,6 +651,48 @@ extern "C" cerr << "this should never happen" << endl; exit(1); } + static int gecode_space_use_keep_index(void) + { + YAP_Term arg1 = YAP_ARG1; + YAP_Term arg2 = YAP_ARG2; + GenericSpace* space = gecode_Space_from_term(arg1); + return YAP_Unify(arg2,(space->use_keep_index() + ?gecode_TRUE:gecode_FALSE)); + } + + static int gecode_intvar_keep(void) + { + YAP_Term arg1 = YAP_ARG1; + YAP_Term arg2 = YAP_ARG2; + YAP_Term arg3 = YAP_ARG3; + GenericSpace* space = gecode_Space_from_term(arg1); + int idx = YAP_IntOfTerm(arg2); + int kidx = space->keep_ivar(idx); + return YAP_Unify(arg3,YAP_MkIntTerm(kidx)); + } + + static int gecode_boolvar_keep(void) + { + YAP_Term arg1 = YAP_ARG1; + YAP_Term arg2 = YAP_ARG2; + YAP_Term arg3 = YAP_ARG3; + GenericSpace* space = gecode_Space_from_term(arg1); + int idx = YAP_IntOfTerm(arg2); + int kidx = space->keep_bvar(idx); + return YAP_Unify(arg3,YAP_MkIntTerm(kidx)); + } + + static int gecode_setvar_keep(void) + { + YAP_Term arg1 = YAP_ARG1; + YAP_Term arg2 = YAP_ARG2; + YAP_Term arg3 = YAP_ARG3; + GenericSpace* space = gecode_Space_from_term(arg1); + int idx = YAP_IntOfTerm(arg2); + int kidx = space->keep_svar(idx); + return YAP_Unify(arg3,YAP_MkIntTerm(kidx)); + } + // INFO ON INTVARS static int gecode_intvar_assigned(void) { @@ -1133,5 +1175,9 @@ extern "C" YAP_UserCPredicate("gecode_setvar_glb_values", gecode_setvar_glb_values, 3); YAP_UserCPredicate("gecode_setvar_lub_values", gecode_setvar_lub_values, 3); YAP_UserCPredicate("gecode_setvar_unknown_values", gecode_setvar_unknown_values, 3); + YAP_UserCPredicate("gecode_space_use_keep_index", gecode_space_use_keep_index, 2); + YAP_UserCPredicate("gecode_intvar_keep", gecode_intvar_keep, 3); + YAP_UserCPredicate("gecode_boolvar_keep", gecode_boolvar_keep, 3); + YAP_UserCPredicate("gecode_setvar_keep", gecode_setvar_keep, 3); } } diff --git a/library/gecode/gecode_yap_hand_written.yap b/library/gecode/gecode_yap_hand_written.yap index e5b89be4d..e1755cca3 100644 --- a/library/gecode/gecode_yap_hand_written.yap +++ b/library/gecode/gecode_yap_hand_written.yap @@ -31,9 +31,21 @@ is_bool_(false,false). is_bool(X,Y) :- nonvar(X), Y=X. is_bool(X) :- is_bool(X,_). -is_IntVar_('IntVar'(I),I) :- integer(I). -is_BoolVar_('BoolVar'(I),I) :- integer(I). -is_SetVar_('SetVar'(I),I) :- integer(I). +is_IntVar_('IntVar'(I,K),N) :- + integer(I), + integer(K), + nb_getval(gecode_space_use_keep_index,B), + (B=true -> N=K ; N=I). +is_BoolVar_('BoolVar'(I,K),N) :- + integer(I), + integer(K), + nb_getval(gecode_space_use_keep_index,B), + (B=true -> N=K ; N=I). +is_SetVar_('SetVar'(I,K),N) :- + integer(I), + integer(K), + nb_getval(gecode_space_use_keep_index,B), + (B=true -> N=K ; N=I). is_IntVar(X,I) :- nonvar(X), is_IntVar_(X,I). is_BoolVar(X,I) :- nonvar(X), is_BoolVar_(X,I). @@ -142,7 +154,18 @@ new_space(Space) :- gecode_new_space(Space_), Space='Space'(Space_). -is_Space_('Space'(X),X). +%% checking that an argument is a space sets a global variable +%% indicating whether variables need to be translated to their +%% original index or to their "keep" index. +%% +%% these bindings are going to take advantage of the fact that, +%% when a space is involved, it is checked first, thus setting +%% this global variable. subsequent accesses to variables are +%% then correctly translated. + +is_Space_('Space'(X),X) :- + gecode_space_use_keep_index(X,B), + nb_setval(gecode_space_use_keep_index,B). is_Space(X,Y) :- nonvar(X), is_Space_(X,Y). is_Space(X) :- is_Space(X,_). @@ -198,19 +221,19 @@ new_intvar(IVar, Space, Lo, Hi) :- !, assert_integer(Lo), assert_integer(Hi), gecode_new_intvar_from_bounds(Idx,Space_,Lo,Hi), - IVar='IntVar'(Idx). + IVar='IntVar'(Idx,-1). new_intvar(IVar, Space, IntSet) :- !, assert_var(IVar), assert_is_Space_or_Clause(Space,Space_), assert_is_IntSet(IntSet, L), gecode_new_intvar_from_intset(Idx,Space_,L), - IVar='IntVar'(Idx). + IVar='IntVar'(Idx,-1). new_boolvar(BVar, Space) :- !, assert_var(BVar), assert_is_Space_or_Clause(Space,Space_), gecode_new_boolvar(Idx,Space_), - BVar='BoolVar'(Idx). + BVar='BoolVar'(Idx,-1). %% (GlbMin,GlbMax,LubMin,LubMax,CardMin,CardMax) 6 new_setvar_1 %% (GlbMin,GlbMax,LubMin,LubMax,CardMin) 5 new_setvar_2 @@ -237,7 +260,7 @@ new_setvar(SVar, Space, GlbMin, GlbMax, LubMin, LubMax, CardMin, CardMax) :- assert_integer(CardMin), assert_integer(CardMax), gecode_new_setvar(Idx, Space_, GlbMin, GlbMax, LubMib, LubMax, CardMin, CardMax), - SVar='SetVar'(Idx). + SVar='SetVar'(Idx,-1). %% 5 arguments %% (GlbMin,GlbMax,LubMin,LubMax,CardMin) 5 new_setvar_2 @@ -593,7 +616,9 @@ new_clause(X, Disj) :- gecode_new_clause(C, Disj_), X='Clause'(C). -is_Clause_('Clause'(C),C). +is_Clause_('Clause'(C),C) :- + gecode_space_use_keep_index(C,B), + nb_setval(gecode_space_use_keep_index,B). is_Clause(X,Y) :- nonvar(X), is_Clause_(X,Y). is_Clause(X) :- is_Clause(X,_). @@ -636,6 +661,24 @@ new_setvars_(L,Space,N,X1,X2,X3,X4) :- length(L,N), new_setvars(L,Space,X1,X2,X3 new_setvars_(L,Space,N,X1,X2,X3) :- length(L,N), new_setvars(L,Space,X1,X2,X3). new_setvars_(L,Space,N,X1,X2) :- length(L,N), new_setvars(L,Space,X1,X2). +keep_(Space, Var) :- + (Var = 'IntVar'(I,J) + -> (J = -1 -> (gecode_intvar_keep(Space,I,K),setarg(2,Var,K)) + ; throw(gecode_error(variable_already_kept(Var)))) + ; (Var = 'BoolVar'(I,J) + -> (J = -1 -> (gecode_boolvar_keep(Space,I,K),setarg(2,Var,K)) + ; throw(gecode_error(variable_already_kept(Var)))) + ; (Var = 'SetVar'(I,J) + -> (J = -1 -> (gecode_setvar_keep(Space,I,K),setarg(2,Var,K)) + ; throw(gecode_error(variable_already_kept(Var)))) + ; keep_list_(Space,Var)))). + +keep_list_(Space, []) :- !. +keep_list_(Space, [H|T]) :- !, + keep_(Space,H), keep_list_(Space,T). +keep_list_(_, X) :- + throw(gecode_error(not_a_variable(X))). + %% more concise interface: (X := Y) :- var(Y), !, throw(gecode_error((X := Y))). (X := intset(I,J)) :- !, new_intset(X,I,J). @@ -801,3 +844,5 @@ new_setvars_(L,Space,N,X1,X2) :- length(L,N), new_setvars(L,Space,X1,X2). (Space += maximize(X)) :- !, maximize(Space,X). (Space += minimize(X,Y)) :- !, minimize(Space,X,Y). (Space += maximize(X,Y)) :- !, maximize(Space,X,Y). + +(Space += keep(X)) :- !, keep_(Space,X).