359 lines
10 KiB
C++
359 lines
10 KiB
C++
// -*- c++ -*-
|
|
//=============================================================================
|
|
// Copyright (C) 2011 by Denys Duchier
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify it
|
|
// under the terms of the GNU Lesser General Public License as published by the
|
|
// Free Software Foundation, either version 3 of the License, or (at your
|
|
// option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
// more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
//=============================================================================
|
|
|
|
#ifndef GECODE_COMMON
|
|
#define GECODE_COMMON
|
|
|
|
#include "gecode/int.hh"
|
|
#include "gecode/set.hh"
|
|
#include "gecode/search.hh"
|
|
#include <vector>
|
|
|
|
namespace generic_gecode
|
|
{
|
|
using namespace std;
|
|
using namespace Gecode;
|
|
|
|
// description of the optimization criterion
|
|
struct Optimizing
|
|
{
|
|
enum What { OPT_NONE, OPT_INT, OPT_RATIO };
|
|
enum How { OPT_MIN, OPT_MAX };
|
|
int num;
|
|
int den;
|
|
What what;
|
|
How how;
|
|
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)
|
|
{ check_ok(); what = OPT_INT; how = OPT_MAX; num = i; };
|
|
void maximize(int i,int j)
|
|
{ check_ok(); what = OPT_RATIO; how = OPT_MAX; num = i; den = j; };
|
|
void minimize(int i)
|
|
{ check_ok(); what = OPT_INT; how = OPT_MIN; num = i; };
|
|
void minimize(int i,int j)
|
|
{ check_ok(); what = OPT_RATIO; how = OPT_MIN; num = i; den = j; };
|
|
};
|
|
|
|
struct GenericSpace;
|
|
|
|
struct GenericEngine
|
|
{
|
|
virtual GenericSpace* next(void)=0;
|
|
virtual ~GenericEngine() {};
|
|
};
|
|
|
|
struct GenericDFS: GenericEngine
|
|
{
|
|
DFS<GenericSpace> engine;
|
|
GenericDFS(GenericSpace* s,Search::Options& opt) : engine(s,opt) {}
|
|
virtual GenericSpace* next(void) { return engine.next(); }
|
|
};
|
|
|
|
struct GenericBAB: GenericEngine
|
|
{
|
|
BAB<GenericSpace> engine;
|
|
GenericBAB(GenericSpace* s,Search::Options& opt) : engine(s,opt) {}
|
|
virtual GenericSpace* next(void) { return engine.next(); }
|
|
};
|
|
|
|
struct GenericRestart: GenericEngine
|
|
{
|
|
Restart<GenericSpace> engine;
|
|
GenericRestart(GenericSpace* s,Search::Options& opt): engine(s,opt) {}
|
|
virtual GenericSpace* next(void) { return engine.next(); }
|
|
};
|
|
|
|
struct LoadingDock
|
|
{
|
|
vector<IntVar> ivars;
|
|
vector<BoolVar> bvars;
|
|
vector<SetVar> svars;
|
|
vector<int> ikeep;
|
|
vector<int> bkeep;
|
|
vector<int> 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<int>(ivars.size()-1); }
|
|
|
|
int enter_bvar(const BoolVar& v)
|
|
{ bvars.push_back(v); return static_cast<int>(bvars.size()-1); }
|
|
|
|
int enter_svar(const SetVar& v)
|
|
{ svars.push_back(v); return static_cast<int>(svars.size()-1); }
|
|
|
|
int keep_ivar(int i) { ikeep.push_back(i); return static_cast<int>(ikeep.size()-1); }
|
|
int keep_bvar(int i) { bkeep.push_back(i); return static_cast<int>(bkeep.size()-1); }
|
|
int keep_svar(int i) { skeep.push_back(i); return static_cast<int>(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<int>(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<int>(ikeep.size()-1); }
|
|
if (_den != -1 && !den_found)
|
|
{ ikeep.push_back(_den);
|
|
den=static_cast<int>(ikeep.size()-1); }
|
|
}
|
|
{ int n = static_cast<int>(ikeep.size());
|
|
iarr = IntVarArray(home, n);
|
|
for (;n--;) iarr[n]=ivars[ikeep[n]]; }
|
|
{ int n = static_cast<int>(bkeep.size());
|
|
barr = BoolVarArray(home, n);
|
|
for (;n--;) barr[n]=bvars[bkeep[n]]; }
|
|
{ int n = static_cast<int>(skeep.size());
|
|
sarr = SetVarArray(home, n);
|
|
for (;n--;) sarr[n]=svars[skeep[n]]; }
|
|
}
|
|
else
|
|
{
|
|
{ int n = static_cast<int>(ivars.size());
|
|
iarr = IntVarArray(home, n);
|
|
for (;n--;) iarr[n]=ivars[n]; }
|
|
{ int n = static_cast<int>(bvars.size());
|
|
barr = BoolVarArray(home, n);
|
|
for (;n--;) barr[n]=bvars[n]; }
|
|
{ int n = static_cast<int>(svars.size());
|
|
sarr = SetVarArray(home, n);
|
|
for (;n--;) sarr[n]=svars[n]; }
|
|
}
|
|
}
|
|
};
|
|
|
|
struct GenericSpace: Space
|
|
{
|
|
Optimizing optim;
|
|
IntVarArray ivars;
|
|
BoolVarArray bvars;
|
|
SetVarArray 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), dock(NULL), keeping_some(s.keeping_some)
|
|
{
|
|
ivars.update(*this, share, s.ivars);
|
|
bvars.update(*this, share, s.bvars);
|
|
svars.update(*this, share, s.svars);
|
|
}
|
|
|
|
Space* copy(bool share)
|
|
{ freeze(); return new GenericSpace(share, *this); }
|
|
|
|
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 (dock)
|
|
{
|
|
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 (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)
|
|
{
|
|
freeze();
|
|
return (optim.what == Optimizing::OPT_NONE)
|
|
? static_cast<GenericEngine*>(new GenericDFS(this,opt))
|
|
: (restart
|
|
? static_cast<GenericEngine*>(new GenericRestart(this,opt))
|
|
: static_cast<GenericEngine*>(new GenericBAB(this,opt)));
|
|
}
|
|
|
|
int _new_ivar(IntVar& v)
|
|
{
|
|
if (dock) return dock->enter_ivar(v);
|
|
else return ikaboom("too late to create vars");
|
|
}
|
|
|
|
int new_ivar(int lo, int hi)
|
|
{
|
|
IntVar v(*this, lo, hi);
|
|
return _new_ivar(v);
|
|
}
|
|
|
|
int new_ivar(IntSet& s)
|
|
{
|
|
IntVar v(*this, s);
|
|
return _new_ivar(v);
|
|
}
|
|
|
|
int _new_bvar(BoolVar& v)
|
|
{
|
|
if (dock) return dock->enter_bvar(v);
|
|
else return ikaboom("too late to create vars");
|
|
}
|
|
|
|
int new_bvar()
|
|
{
|
|
BoolVar v(*this, 0, 1);
|
|
return _new_bvar(v);
|
|
}
|
|
|
|
int _new_svar(SetVar& v)
|
|
{
|
|
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,
|
|
unsigned int cardMin=0,
|
|
unsigned int cardMax=Set::Limits::card)
|
|
{
|
|
SetVar v(*this, glbMin, glbMax, lubMin, lubMax, cardMin, cardMax);
|
|
return _new_svar(v);
|
|
}
|
|
|
|
int new_svar(IntSet glb, int lubMin, int lubMax,
|
|
unsigned int cardMin=0,
|
|
unsigned int cardMax=Set::Limits::card)
|
|
{
|
|
SetVar v(*this, glb, lubMin, lubMax, cardMin, cardMax);
|
|
return _new_svar(v);
|
|
}
|
|
|
|
int new_svar(int glbMin, int glbMax, IntSet lub,
|
|
unsigned int cardMin=0,
|
|
unsigned int cardMax=Set::Limits::card)
|
|
{
|
|
SetVar v(*this, glbMin, glbMax, lub, cardMin, cardMax);
|
|
return _new_svar(v);
|
|
}
|
|
|
|
int new_svar(IntSet glb, IntSet lub,
|
|
unsigned int cardMin=0,
|
|
unsigned int cardMax=Set::Limits::card)
|
|
{
|
|
SetVar v(*this, glb, lub, cardMin, cardMax);
|
|
return _new_svar(v);
|
|
}
|
|
|
|
void minimize(int i) { optim.minimize(i); }
|
|
void minimize(int i, int j) { optim.minimize(i,j); }
|
|
void maximize(int i) { optim.maximize(i); }
|
|
void maximize(int i, int j) { optim.maximize(i,j); }
|
|
|
|
virtual void constrain(const Space& s)
|
|
{
|
|
const GenericSpace& sol = static_cast<const GenericSpace&>(s);
|
|
switch (optim.what)
|
|
{
|
|
case Optimizing::OPT_NONE:
|
|
break;
|
|
case Optimizing::OPT_INT:
|
|
rel(*this, ivars[optim.num],
|
|
((optim.how==Optimizing::OPT_MIN) ? IRT_LE : IRT_GR),
|
|
sol.ivars[optim.num].val());
|
|
break;
|
|
case Optimizing::OPT_RATIO:
|
|
{
|
|
IntArgs c(2, sol.ivars[optim.den].val(),
|
|
- sol.ivars[optim.num].val());
|
|
IntVarArgs v(2);
|
|
v[0] = ivars[optim.num];
|
|
v[1] = ivars[optim.den];
|
|
linear(*this, c, v,
|
|
((optim.how==Optimizing::OPT_MIN) ? IRT_LE : IRT_GR), 0);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
#ifdef DISJUNCTOR
|
|
#include "disjunctor.icc"
|
|
#endif
|
|
|
|
#endif
|