Commit d1f49a9d authored by Charles Fai-keung Siu's avatar Charles Fai-keung Siu
Browse files

A basic set solver enforcing ENC, ECC, EAC, and EHAC.

Added counter for number of solutions and timer.
parent 6b488533
/*
* **************** Abstract constraints of predefined arities **************
*/
#include "tb2abstractternconstr.hpp"
/*
* Constructors and misc.
*
*/
/** \file tb2abstractternconstr.hpp
* \brief Abstract constraints of predefined arities
*
*/
#ifndef TB2ABSTRACTTERNCONSTR_HPP_
#define TB2ABSTRACTTERNCONSTR_HPP_
#include "tb2constraint.hpp"
#include "tb2variable.hpp"
template<class T1, class T2, class T3>
class AbstractTernaryConstraint : public Constraint
{
protected:
T1 *x;
T2 *y;
T3 *z;
DLink<ConstraintLink> *linkX;
DLink<ConstraintLink> *linkY;
DLink<ConstraintLink> *linkZ;
public:
AbstractTernaryConstraint(WCSP *wcsp, T1 *xx, T2 *yy, T3 *zz) : Constraint(wcsp), x(xx), y(yy), z(zz), linkX(NULL), linkY(NULL), linkZ(NULL) {
assert(xx != yy);
assert(yy != zz);
assert(zz != xx);
linkX = xx->link(this,0);
linkY = yy->link(this,1);
linkZ = zz->link(this,2);
}
virtual ~AbstractTernaryConstraint() {delete linkX; delete linkY; delete linkZ;}
bool connected() {return !linkX->removed && !linkY->removed && !linkZ->removed;}
bool deconnected() {return linkX->removed || linkY->removed || linkZ->removed;}
void deconnect() {
if (connected()) {
if (ToulBar2::verbose >= 3) cout << "deconnect " << this << endl;
x->getConstrs()->erase(linkX, true);
y->getConstrs()->erase(linkY, true);
z->getConstrs()->erase(linkZ, true);
}
}
void reconnect() {
if (deconnected()) {
x->getConstrs()->push_back(linkX, true);
y->getConstrs()->push_back(linkY, true);
z->getConstrs()->push_back(linkZ, true);
}
}
int arity() const {return 3;}
Variable *getVar(int varIndex) const {return (varIndex == 0)?x:((varIndex == 1)?y:z);}
int getSmallestVarIndexInScope(int forbiddenScopeIndex) {
int idx = 0;
if (forbiddenScopeIndex == x->wcspIndex) {
idx = (y->wcspIndex < z->wcspIndex) ? y->wcspIndex : z->wcspIndex;
} else if (forbiddenScopeIndex == y->wcspIndex) {
idx = (x->wcspIndex < z->wcspIndex) ? x->wcspIndex : z->wcspIndex;
} else {
idx = (x->wcspIndex < y->wcspIndex) ? x->wcspIndex : y->wcspIndex;
}
return idx;
}
int getSecondSmallestVarIndexInScope(int forbiddenScopeIndex) {
int idx = 0;
if (forbiddenScopeIndex == x->wcspIndex) {
idx = (y->wcspIndex > z->wcspIndex) ? y->wcspIndex : z->wcspIndex;
} else if (forbiddenScopeIndex == y->wcspIndex) {
idx = (x->wcspIndex > z->wcspIndex) ? x->wcspIndex : z->wcspIndex;
} else {
idx = (x->wcspIndex > y->wcspIndex) ? x->wcspIndex : y->wcspIndex;
}
return idx;
}
};
#endif /*TB2ABSTRACTTERNCONSTR_HPP_*/
/*
* **************** Abstract set constraints **************
*/
#include "tb2setabstractconstr.hpp"
/*
* Constructors and misc.
*
*/
/** \file tb2setabstractconstr.hpp
* \brief Abstract set constraints
*
*/
#ifndef _TB2SETABSTRACTCONSTR_HPP_
#define _TB2SETABSTRACTCONSTR_HPP_
#include "toulbar2.hpp"
class AbstractSetConstraint
{
public:
AbstractSetConstraint() {}
virtual ~AbstractSetConstraint() {}
virtual void assign(int varIndex, int e) = 0;
virtual void propagate(int varIndex, int e) = 0;
};
#endif /*_TB2SETABSTRACTCONSTR_HPP_*/
#include "tb2setbinconstr.hpp"
#include "tb2wcsp.hpp"
#define GETCOST (this->*getBinaryCost)
BinarySetConstraint::BinarySetConstraint(WCSP *wcsp, SetVariable *xx,
SetVariable *yy, vector<Cost> &tab,
StoreStack<Cost, Cost> *storeCost) :
AbstractBinaryConstraint<SetVariable, SetVariable>(wcsp, xx, yy),
AbstractSetConstraint(),
sizeX(xx->getDomainInitSize()), sizeY(yy->getDomainInitSize()) {
for (unsigned int i = 0; i < tab.size(); i++) {
costs.push_back(StoreCost(tab[i], storeCost));
}
xx->queueAC();
xx->queueDAC();
yy->queueAC();
yy->queueDAC();
}
template <GetSetBinCostMember getBinaryCost>
void BinarySetConstraint::projection(int e, SetVariable *x, bool iny) {
for (int inx = 0; inx < 2; inx++) {
Cost cost = GETCOST(e, inx, iny);
if (cost > 0) {
if (ToulBar2::verbose >= 2) {
cout << "binary projection of " << cost << " on C("
<< x->getName() << "," << e << (inx ? "-in" : "-notin")
<< ")" << endl;
}
x->project(e, inx, cost);
}
}
}
void BinarySetConstraint::assign(int varIndex, int e) {
if (varIndex == 0) {
if (y->unassigned(e)) {
projectY(e);
}
} else {
if (x->unassigned(e)) {
projectX(e);
}
}
}
void BinarySetConstraint::propagate(int varIndex, int e) {
if (varIndex == 0) {
Cost minCost = min(getCost(e, true, true), getCost(e, true, false));
if (minCost > 0) {
x->project(e, true, minCost);
decreaseCost(e, true, true, minCost);
decreaseCost(e, true, false, minCost);
}
minCost = min(getCost(e, false, true), getCost(e, false, false));
if (minCost > 0) {
x->project(e, false, minCost);
decreaseCost(e, false, true, minCost);
decreaseCost(e, false, false, minCost);
}
} else {
Cost minCost = min(getCost(e, true, true), getCost(e, false, true));
if (minCost > 0) {
y->project(e, true, minCost);
decreaseCost(e, true, true, minCost);
decreaseCost(e, false, true, minCost);
}
minCost = min(getCost(e, true, false), getCost(e, false, false));
if (minCost > 0) {
y->project(e, false, minCost);
decreaseCost(e, true, false, minCost);
decreaseCost(e, false, false, minCost);
}
}
}
void BinarySetConstraint::print(ostream& os) {
os << this << " BinarySetConstraint(" << x->getName() << "," << y->getName() << ")" << endl;
if (ToulBar2::verbose >= 5) {
for (int e = 0; e < (int)(x->getDomainInitSize()); e++) {
cout << "[" << e << "]("
<< getCost(e, true, true) << ","
<< getCost(e, true, false) << ","
<< getCost(e, false, true) << ","
<< getCost(e, false, false) << ")" << endl;
}
}
}
bool BinarySetConstraint::verify() {
bool ok = true;
for (unsigned int e = 0; e < sizeX; e++) {
if (x->unassigned(e) && y->unassigned(e)) {
int cost = max(
max(
min(getCost(e, true, true), getCost(e, true, false)),
min(getCost(e, false, true), getCost(e, false, false))
),
max(
min(getCost(e, true, true), getCost(e, false, true)),
min(getCost(e, true, false), getCost(e, false, false))
)
);
if (cost > 0) {
ok = false;
}
}
}
return ok;
}
#ifndef _TB2SETBINCONSTR_HPP_
#define _TB2SETBINCONSTR_HPP_
#include "tb2abstractconstr.hpp"
#include "tb2setabstractconstr.hpp"
#include "tb2setvar.hpp"
class BinarySetConstraint;
typedef Cost (BinarySetConstraint::*GetSetBinCostMember)(int e, bool inx, bool iny);
class BinarySetConstraint :
public AbstractBinaryConstraint<SetVariable, SetVariable>,
public AbstractSetConstraint
{
unsigned int sizeX;
unsigned int sizeY;
vector<StoreCost> costs;
Cost getCost(int e, bool inx, bool iny) {
return costs[e * 4 + inx * 2 + iny];
}
Cost getCostReverse(int e, bool iny, bool inx) {
return costs[e * 4 + inx * 2 + iny];
}
void decreaseCost(int e, bool inx, bool iny, Cost dec) {
costs[e * 4 + inx * 2 + iny] -= dec;
}
template <GetSetBinCostMember getBinaryCost>
void projection(int e, SetVariable *x, bool iny);
void projectX(int e) {
projection<&BinarySetConstraint::getCost>(e, x, y->getValue(e));
}
void projectY(int e) {
projection<&BinarySetConstraint::getCostReverse>(e, y, x->getValue(e));
}
public:
BinarySetConstraint(WCSP *wcsp, SetVariable *xx, SetVariable *yy,
vector<Cost> &tab, StoreStack<Cost, Cost> *storeCost);
~BinarySetConstraint() {}
void propagate() {}
void assign(int varIndex) {
deconnect();
}
void assign(int varIndex, int e);
void propagate(int varIndex, int e);
bool verify();
void print(ostream &os);
};
#endif /*_TB2SETBINCONSTR_HPP_*/
#include "tb2setdomain.hpp"
SetDomain::SetDomain(int min, int max, StoreStack<int, int> *s) :
initSize(max - min + 1), distanceToZero(min),
cardPS(max - min + 1, s), cardRS(0, s),
cardUB(max - min + 1, s), cardLB(0, s) {
elements = new StoreValue[initSize](1, s);
}
SetDomain::SetDomain(int *e, int esize, StoreStack<int, int> *s) :
initSize(max(e, esize) - min(e, esize) + 1),
distanceToZero(min(e, esize)),
cardPS(esize, s), cardRS(0, s),
cardUB(esize, s), cardLB(0, s) {
elements = new StoreValue[initSize](0, s);
int size = 0;
for (int i = 0; i < esize; i++) {
elements[toIndex(e[i])] = 1;
size++;
}
cardPS = size;
cardUB = size;
}
SetDomain::~SetDomain() {
delete[] elements;
}
ostream& operator<<(ostream& os, SetDomain &domain) {
os << "{";
for (int i = 0; i < domain.initSize; i++) {
if (domain.elements[i] == 2) {
os << " " << i;
}
}
os << " |";
for (int i = 0; i < domain.initSize; i++) {
if (domain.elements[i] == 1) {
os << " " << i;
}
}
os << " } [" << domain.cardLB << "," << domain.cardUB << "]";
return os;
}
#ifndef _TB2SETDOMAIN_H_
#define _TB2SETDOMAIN_H_
#include "toulbar2.hpp"
#include "tb2store.hpp"
/*
* Main class
*
*/
class SetDomain
{
const int initSize; // cardinality of inital possible set
const Value distanceToZero;
StoreInt *elements; // 0 - not in PS, 1 - in PS, 2 - in PS & RS
StoreInt cardPS; // cardinality of PS
StoreInt cardRS; // cardinality of RS
StoreInt cardUB; // cardinality upper bound
StoreInt cardLB; // cardinality lower bound
SetDomain(const SetDomain &s);
SetDomain& operator=(const Domain &s);
public:
SetDomain(int min, int max, StoreStack<int, int> *s);
SetDomain(int *e, int esize, StoreStack<int, int> *s);
~SetDomain();
int getInitSize() const {
return initSize;
}
int getSize() const {
return cardPS - cardRS;
}
int toIndex(int e) const {
return e - distanceToZero;
}
int toValue(int idx) const {
return idx + distanceToZero;
}
bool isPossible(int e) const {
return (elements[toIndex(e)] >= 1);
}
bool isRequired(int e) const {
return (elements[toIndex(e)] >= 2);
}
void addRequired(int e) {
if (elements[e] == 1) {
elements[e] = 2;
cardRS = cardRS + 1;
if (cardLB < cardRS) {
cardLB = cardRS;
if (cardLB > cardUB) {
THROWCONTRADICTION;
}
}
} else if (elements[e] == 0) {
THROWCONTRADICTION;
}
}
void removePossible(int e) {
if (elements[e] == 1) {
elements[e] = 0;
cardPS = cardPS - 1;
if (cardUB > cardPS) {
cardUB = cardPS;
if (cardLB > cardUB) {
THROWCONTRADICTION;
}
}
} else if (elements[e] = 0) {
THROWCONTRADICTION;
}
}
int getPSSize() {
return cardPS;
}
int getRSSize() {
return cardRS;
}
int getCardLB() {
return cardLB;
}
int getCardUB() {
return cardUB;
}
void setCardLB(int lb) {
if (cardLB < lb) {
cardLB = lb;
if (cardLB > cardUB) {
THROWCONTRADICTION;
}
}
}
void setCardUB(int ub) {
if (cardUB > ub) {
cardUB = ub;
if (cardLB > cardUB) {
THROWCONTRADICTION;
}
}
}
Value getNextMinElement(int e) {
Value elem = -1;
for (int i = e + 1; i < initSize && elem == -1; i++) {
if (elements[i] == 1) {
elem = i;
}
}
return elem;
}
Value getNextMaxElement(int e) {
Value elem = -1;
for (int i = e - 1; i >= 0 && elem == -1; i--) {
if (elements[i] == 1) {
elem = i;
}
}
return elem;
}
bool bounded() {
return (cardPS == cardRS);
}
friend ostream& operator<<(ostream& os, SetDomain &domain);
};
#endif /*_TB2SETDOMAIN_H_*/
#include "tb2setternconstr.hpp"
#include "tb2wcsp.hpp"
#define GETCOST (this->*getTernaryCost)
TernarySetConstraint::TernarySetConstraint(WCSP *wcsp, SetVariable *xx,
SetVariable *yy, SetVariable *zz, vector<Cost> &tab,
StoreStack<Cost, Cost> *storeCost) :
AbstractTernaryConstraint<SetVariable, SetVariable, SetVariable>(wcsp, xx, yy, zz),
sizeX(xx->getDomainInitSize()), sizeY(yy->getDomainInitSize()),
sizeZ(zz->getDomainInitSize()) {
for (unsigned int i = 0; i < tab.size(); i++) {
costs.push_back(StoreCost(tab[i], storeCost));
}
connected = vector<StoreCost>(sizeX, StoreCost(3, storeCost));
}
template <GetSetTernCostMember getTernaryCost>
void TernarySetConstraint::projection(int e, SetVariable *x, bool iny, bool inz) {
for (int inx = 0; inx < 2; inx++) {
Cost cost = GETCOST(e, inx, iny, inz);
if (cost > 0) {
if (ToulBar2::verbose >= 2) {
cout << "ternary projection of " << cost << " on C("
<< x->getName() << "," << e << (inx ? "-in" : "-notin")
<< ")" << endl;
}
x->project(e, inx, cost);
}
}
}
void TernarySetConstraint::assign(int varIndex, int e) {
if (connected[e] == 3) {
if (varIndex == 0) {
propagateOnX(e);
} else if (varIndex == 1) {
propagateOnY(e);
} else {
propagateOnZ(e);
}
connected[e] = 2;
} else if (connected[e] == 2) {
if (x->unassigned(e)) {
projectX(e);
} else if (y->unassigned(e)) {
projectY(e);
} else {
projectZ(e);
}
connected[e] = 0;
}
}
void TernarySetConstraint::propagateOnX(int e) {
// (x, T, any)
bool xin = x->getValue(e);
Cost minCost = min(getCost(e, xin, true, true),
getCost(e, xin, true, false));
if (minCost > 0) {
y->project(e, true, minCost);
decreaseCost(e, xin, true, true, minCost);
decreaseCost(e, xin, true, true, minCost);
}
// (x, F, any)
minCost = min(getCost(e, xin, false, true),
getCost(e, xin, false, false));
if (minCost > 0) {
y->project(e, false, minCost);
decreaseCost(e, xin, false, true, minCost);
decreaseCost(e, xin, false, false, minCost);
}
// (x, any, T)
minCost = min(getCost(e, xin, true, true),
getCost(e, xin, false, true));
if (minCost > 0) {
z->project(e, true, minCost);
decreaseCost(e, xin, true, true, minCost);
decreaseCost(e, xin, false, true, minCost);
}
// (x, any, F)
minCost = min(getCost(e, xin, true, false),
getCost(e, xin, false, false));
if (minCost > 0) {
z->project(e, false, minCost);
decreaseCost(e, xin, true, false, minCost);
decreaseCost(e, xin, false, false, minCost);
}
}
void TernarySetConstraint::propagateOnY(int e) {
// (T, y, any)
bool yin = y->getValue(e);
Cost minCost = min(getCost(e, true, yin, true),
getCost(e, true, yin, false));
if (minCost > 0) {
x->project(e, true, minCost);
decreaseCost(e, true, yin, true, minCost);
decreaseCost