...
 
Commits (6)
#ifndef CARTESIAN_H_
#define CARTESIAN_H_
#include <algorithm>
#include <vector>
/**
* A small class to iterate over the Cartesian products of a few sequences with number ranges, such
* as 0, 1, 2 and 0, 1 and 0, 1, 2, 3. All the sequences start from 0.
*/
template <typename IntegerType = int>
class Cartesian
{
private:
std::vector<IntegerType> upperBounds; // The largest integers we should never touch.
public:
inline const decltype(upperBounds)& getUpperBounds() const noexcept
{
return upperBounds;
}
// The iterator
class Iterator
{
private:
std::vector<IntegerType> cur; // Current iterated product.
bool overflown;
const Cartesian * c;
public:
Iterator() noexcept
: overflown(false)
, c(nullptr)
{}
Iterator(const Cartesian& c, bool of = false) noexcept
: overflown(of)
{
this->c = &c;
cur.assign(c.getUpperBounds().size(), 0);
}
inline bool isOverflown() const noexcept
{
return overflown;
}
inline const Cartesian * getCartesian() const noexcept
{
return c;
}
inline Iterator& operator ++ () noexcept
{
typename decltype(cur)::size_type i = 0;
while (true)
{
++ cur[i];
if (cur[i] < getCartesian()->getUpperBounds().at(i))
break;
cur[i] = 0;
++ i;
// We've done with the last one. We now overflow.
if (i >= cur.size())
{
overflown = true;
break;
}
}
return *this;
}
inline Iterator operator ++ (int) noexcept
{
Iterator it(*this);
operator ++ ();
return it;
}
inline const decltype(cur)& operator * () const noexcept
{
return cur;
}
inline const decltype(cur)* operator -> () const noexcept
{
return &cur;
}
inline bool operator == (const Iterator& other) const noexcept
{
return **this == *other &&
isOverflown() == other.isOverflown() &&
getCartesian() == other.getCartesian();
}
inline bool operator != (const Iterator& other) const noexcept
{
return !(*this == other);
}
};
const Iterator begin() const noexcept
{
return Iterator(*this);
}
const Iterator end() const noexcept
{
return Iterator(*this, true);
}
template <class Iter>
Cartesian(Iter beg, Iter end) noexcept // Beg and end contains the max integer of each sequence plus 1.
{
std::copy(beg, end, std::back_inserter(upperBounds));
}
};
#endif // CARTESIAN_H_
......@@ -50,7 +50,9 @@ private:
private:
graph_t g;
std::map<variable_id_t, vertex_t> id_to_v; // map from variable id to vertex_t
std::map<variable_id_t, std::set<vertex_t> > id_to_v; // map from variable id to vertex_t
const WCSPInstance<> * wcspInstance;
typename boost::property_map<graph_t, boost::vertex_name_t>::type vertex_id_map;
typename boost::property_map<graph_t, boost::vertex_weight_t>::type vertex_weight_map;
......@@ -100,9 +102,9 @@ public:
private:
/**
* Add a vertex corresponding to v or get the vertex if exists.
* Add a vertex corresponding to v or get the vertices if exists.
*/
vertex_t addOrGetVertex(variable_id_t v) noexcept
const std::set<vertex_t>& addOrGetVertices(variable_id_t v) noexcept
{
using namespace boost;
......@@ -110,24 +112,34 @@ private:
if (v_pos == id_to_v.end()) // the variable has never been added to the CCG
{
auto ver = add_vertex(g);
vertex_id_map[ver] = v;
v_pos = id_to_v.insert(std::make_pair(v, ver)).first;
auto ds = wcspInstance->getDomainSize(v);
std::set<vertex_t> vs;
for (auto i = ds; i > 0; -- i)
{
auto ver = add_vertex(g);
vertex_id_map[ver] = v;
vs.insert(ver);
}
v_pos = id_to_v.insert(std::make_pair(v, std::move(vs))).first;
}
return v_pos->second;
}
public:
ConstraintCompositeGraph()
ConstraintCompositeGraph(const WCSPInstance<>& w)
{
using namespace boost;
vertex_id_map = get(vertex_name, g);
vertex_weight_map = get(vertex_weight, g);
wcspInstance = &w;
}
/**
* Add a polynomial into the CCG. Note @p will be modified in this function.
* TODO: rewrite this part.
*/
weight_t addPolynomial(typename Constraint::Polynomial& p) noexcept
{
......@@ -152,16 +164,20 @@ public:
variable_id_t v = *k.begin();
// add the weight
auto vertex = addOrGetVertex(v);
auto vertices = addOrGetVertices(v);
if (w >= 0)
vertex_weight_map[vertex] += w;
for (const auto& ver : vertices)
vertex_weight_map[ver] += w;
else
{
// add the auxiliary vertex with a weight of -w and connect them
auto vertex_a = add_vertex(g);
vertex_id_map[vertex_a] = -1; // no corresponding variable
vertex_weight_map[vertex_a] = -w;
add_edge(vertex, vertex_a, g);
for (const auto& ver : vertices)
{
auto vertex_a = add_vertex(g);
vertex_id_map[vertex_a] = -1; // the ID of no corresponding variable
vertex_weight_map[vertex_a] = -w;
add_edge(ver, vertex_a, g);
}
}
continue;
......@@ -169,45 +185,74 @@ public:
// non-linear term
std::vector<vertex_t> vers;
std::vector<std::vector<vertex_t> > vers;
vers.reserve(k.size());
for (auto va : k)
vers.push_back(addOrGetVertex(va));
{
const auto& vertices_set = addOrGetVertices(va);
std::vector<vertex_t> vertices(vertices_set.begin(), vertices_set.end());
vers.push_back(std::move(vertices));
}
std::vector<size_t> num_variable_vertices;
num_variable_vertices.reserve(vers.size());
for (auto ve : vers)
num_variable_vertices.push_back(ve.size());
Cartesian<size_t> cartesian(num_variable_vertices.begin(), num_variable_vertices.end());
if (w < 0) // negative weight
{
w = -w;
p[PolynomialKey()] -= w;
// auxiliary vertex
auto vertex_a = add_vertex(g);
vertex_weight_map[vertex_a] = w;
vertex_id_map[vertex_a] = -1;
for (auto v : vers)
add_edge(v, vertex_a, g);
for (auto it = cartesian.begin(); it != cartesian.end(); ++ it)
{
// auxiliary vertex
auto vertex_a = add_vertex(g);
vertex_weight_map[vertex_a] = w;
vertex_id_map[vertex_a] = -1;
// Connect to one vertex from each variable.
for (size_t i = 0; i < vers.size(); ++ i)
add_edge(vers[i][it->at(i)], vertex_a, g);
}
}
else // non negative weight
{
// Always attach L to the first variable. Update lower order coefficients.
double l = w + 1;
p[PolynomialKey()] -= l + w;
double l = w * num_variable_vertices.at(0) + 1;
p[PolynomialKey()] -= l * num_variable_vertices.at(0) +
w * std::accumulate(num_variable_vertices.begin(),
num_variable_vertices.end(),
1, std::multiplies<size_t>());
p[PolynomialKey{*k.begin()}] += l;
p[PolynomialKey(std::next(k.begin()), k.end())] += w;
p[PolynomialKey(std::next(k.begin()), k.end())] += w * num_variable_vertices.at(0);
auto vertex_a = add_vertex(g);
vertex_weight_map[vertex_a] = w;
vertex_id_map[vertex_a] = -1;
auto vertex_a1 = add_vertex(g);
vertex_weight_map[vertex_a1] = l;
vertex_id_map[vertex_a1] = -2;
add_edge(vertex_a, vertex_a1, g);
add_edge(vertex_a1, vers.at(0), g);
// the L vertices
std::vector<vertex_t> vertices_a1;
vertices_a1.reserve(vers[0].size());
for (const auto& v : vers[0])
{
auto vertex_a1 = add_vertex(g);
vertex_weight_map[vertex_a1] = l;
vertex_id_map[vertex_a1] = -2;
add_edge(vertex_a1, v, g);
vertices_a1.push_back(vertex_a1);
}
// connect the auxiliary vertex to all other variable vertices
for (auto it = std::next(vers.begin()); it != vers.end(); ++ it)
add_edge(vertex_a, *it, g);
for (auto it = cartesian.begin(); it != cartesian.end(); ++ it)
{
// auxiliary vertex
auto vertex_a = add_vertex(g);
vertex_weight_map[vertex_a] = w;
vertex_id_map[vertex_a] = -1;
// Connect the auxiliary vertex to one of the L vertices.
add_edge(vertices_a1.at(it->at(0)), vertex_a, g);
// Connect the auxiliary vertex to all other variable vertices.
for (size_t i = 1; i < vers.size(); ++ i)
add_edge(vers[i][it->at(i)], vertex_a, g);
}
}
}
......
This diff is collapsed.