This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
Tiago Gomes 532654baba Use enum class instead of old enum.
As we are relying on c++11x for other stuff too.
2013-03-09 15:39:39 +00:00

248 lines
5.9 KiB
C++

#include <iostream>
#include <fstream>
#include "ElimGraph.h"
namespace Horus {
ElimGraph::ElimHeuristic ElimGraph::elimHeuristic_ =
ElimHeuristic::minNeighborsEh;
ElimGraph::ElimGraph (const std::vector<Factor*>& factors)
{
for (size_t i = 0; i < factors.size(); i++) {
if (factors[i]) {
const VarIds& args = factors[i]->arguments();
for (size_t j = 0; j < args.size() - 1; j++) {
EGNode* n1 = getEGNode (args[j]);
if (!n1) {
n1 = new EGNode (args[j], factors[i]->range (j));
addNode (n1);
}
for (size_t k = j + 1; k < args.size(); k++) {
EGNode* n2 = getEGNode (args[k]);
if (!n2) {
n2 = new EGNode (args[k], factors[i]->range (k));
addNode (n2);
}
if (!neighbors (n1, n2)) {
addEdge (n1, n2);
}
}
}
if (args.size() == 1 && !getEGNode (args[0])) {
addNode (new EGNode (args[0], factors[i]->range (0)));
}
}
}
}
ElimGraph::~ElimGraph()
{
for (size_t i = 0; i < nodes_.size(); i++) {
delete nodes_[i];
}
}
VarIds
ElimGraph::getEliminatingOrder (const VarIds& excludedVids)
{
VarIds elimOrder;
unmarked_.reserve (nodes_.size());
for (size_t i = 0; i < nodes_.size(); i++) {
if (Util::contains (excludedVids, nodes_[i]->varId()) == false) {
unmarked_.insert (nodes_[i]);
}
}
size_t nrVarsToEliminate = nodes_.size() - excludedVids.size();
for (size_t i = 0; i < nrVarsToEliminate; i++) {
EGNode* node = getLowestCostNode();
unmarked_.remove (node);
const EGNeighs& neighs = node->neighbors();
for (size_t j = 0; j < neighs.size(); j++) {
neighs[j]->removeNeighbor (node);
}
elimOrder.push_back (node->varId());
connectAllNeighbors (node);
}
return elimOrder;
}
void
ElimGraph::print() const
{
for (size_t i = 0; i < nodes_.size(); i++) {
std::cout << "node " << nodes_[i]->label() << " neighs:" ;
EGNeighs neighs = nodes_[i]->neighbors();
for (size_t j = 0; j < neighs.size(); j++) {
std::cout << " " << neighs[j]->label();
}
std::cout << std::endl;
}
}
void
ElimGraph::exportToGraphViz (
const char* fileName,
bool showNeighborless,
const VarIds& highlightVarIds) const
{
std::ofstream out (fileName);
if (!out.is_open()) {
std::cerr << "Error: couldn't open file '" << fileName << "'." ;
std::cerr << std::endl;
return;
}
out << "strict graph {" << std::endl;
for (size_t i = 0; i < nodes_.size(); i++) {
if (showNeighborless || nodes_[i]->neighbors().empty() == false) {
out << '"' << nodes_[i]->label() << '"' << std::endl;
}
}
for (size_t i = 0; i < highlightVarIds.size(); i++) {
EGNode* node =getEGNode (highlightVarIds[i]);
if (node) {
out << '"' << node->label() << '"' ;
out << " [shape=box3d]" << std::endl;
} else {
std::cerr << "Error: invalid variable id: " ;
std::cerr << highlightVarIds[i] << "." ;
std::cerr << std::endl;
exit (EXIT_FAILURE);
}
}
for (size_t i = 0; i < nodes_.size(); i++) {
EGNeighs neighs = nodes_[i]->neighbors();
for (size_t j = 0; j < neighs.size(); j++) {
out << '"' << nodes_[i]->label() << '"' << " -- " ;
out << '"' << neighs[j]->label() << '"' << std::endl;
}
}
out << "}" << std::endl;
out.close();
}
VarIds
ElimGraph::getEliminationOrder (
const Factors& factors,
VarIds excludedVids)
{
if (elimHeuristic_ == ElimHeuristic::sequentialEh) {
VarIds allVids;
Factors::const_iterator first = factors.begin();
Factors::const_iterator end = factors.end();
for (; first != end; ++first) {
Util::addToVector (allVids, (*first)->arguments());
}
TinySet<VarId> elimOrder (allVids);
elimOrder -= TinySet<VarId> (excludedVids);
return elimOrder.elements();
}
ElimGraph graph (factors);
return graph.getEliminatingOrder (excludedVids);
}
void
ElimGraph::addNode (EGNode* n)
{
nodes_.push_back (n);
n->setIndex (nodes_.size() - 1);
varMap_.insert (std::make_pair (n->varId(), n));
}
ElimGraph::EGNode*
ElimGraph::getEGNode (VarId vid) const
{
std::unordered_map<VarId, EGNode*>::const_iterator it;
it = varMap_.find (vid);
return (it != varMap_.end()) ? it->second : 0;
}
ElimGraph::EGNode*
ElimGraph::getLowestCostNode() const
{
EGNode* bestNode = 0;
unsigned minCost = Util::maxUnsigned();
EGNeighs::const_iterator it;
switch (elimHeuristic_) {
case ElimHeuristic::minNeighborsEh: {
for (it = unmarked_.begin(); it != unmarked_.end(); ++ it) {
unsigned cost = getNeighborsCost (*it);
if (cost < minCost) {
bestNode = *it;
minCost = cost;
}
}}
break;
case ElimHeuristic::minWeightEh: {
for (it = unmarked_.begin(); it != unmarked_.end(); ++ it) {
unsigned cost = getWeightCost (*it);
if (cost < minCost) {
bestNode = *it;
minCost = cost;
}
}}
break;
case ElimHeuristic::minFillEh: {
for (it = unmarked_.begin(); it != unmarked_.end(); ++ it) {
unsigned cost = getFillCost (*it);
if (cost < minCost) {
bestNode = *it;
minCost = cost;
}
}}
break;
case ElimHeuristic::weightedMinFillEh: {
for (it = unmarked_.begin(); it != unmarked_.end(); ++ it) {
unsigned cost = getWeightedFillCost (*it);
if (cost < minCost) {
bestNode = *it;
minCost = cost;
}
}}
break;
default:
assert (false);
}
assert (bestNode);
return bestNode;
}
void
ElimGraph::connectAllNeighbors (const EGNode* n)
{
const EGNeighs& neighs = n->neighbors();
if (neighs.size() > 0) {
for (size_t i = 0; i < neighs.size() - 1; i++) {
for (size_t j = i + 1; j < neighs.size(); j++) {
if (!neighbors (neighs[i], neighs[j])) {
addEdge (neighs[i], neighs[j]);
}
}
}
}
}
} // namespace Horus