2012-05-23 14:56:01 +01:00
|
|
|
#include <limits>
|
|
|
|
|
|
|
|
#include <sstream>
|
|
|
|
#include <fstream>
|
|
|
|
|
|
|
|
#include "Util.h"
|
|
|
|
#include "Indexer.h"
|
|
|
|
#include "ElimGraph.h"
|
|
|
|
|
|
|
|
|
|
|
|
namespace Globals {
|
|
|
|
bool logDomain = false;
|
|
|
|
|
|
|
|
unsigned verbosity = 0;
|
|
|
|
|
|
|
|
InfAlgorithms infAlgorithm = InfAlgorithms::VE;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace BpOptions {
|
|
|
|
Schedule schedule = BpOptions::Schedule::SEQ_FIXED;
|
|
|
|
//Schedule schedule = BpOptions::Schedule::SEQ_RANDOM;
|
|
|
|
//Schedule schedule = BpOptions::Schedule::PARALLEL;
|
|
|
|
//Schedule schedule = BpOptions::Schedule::MAX_RESIDUAL;
|
|
|
|
double accuracy = 0.0001;
|
|
|
|
unsigned maxIter = 1000;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace Util {
|
|
|
|
|
|
|
|
|
|
|
|
template <> std::string
|
|
|
|
toString (const bool& b)
|
|
|
|
{
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << std::boolalpha << b;
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
unsigned
|
|
|
|
stringToUnsigned (string str)
|
|
|
|
{
|
|
|
|
int val;
|
|
|
|
stringstream ss;
|
|
|
|
ss << str;
|
|
|
|
ss >> val;
|
|
|
|
if (val < 0) {
|
|
|
|
cerr << "error: the readed number is negative" << endl;
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
return static_cast<unsigned> (val);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
double
|
|
|
|
stringToDouble (string str)
|
|
|
|
{
|
|
|
|
double val;
|
|
|
|
stringstream ss;
|
|
|
|
ss << str;
|
|
|
|
ss >> val;
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
double
|
|
|
|
factorial (unsigned num)
|
|
|
|
{
|
|
|
|
double result = 1.0;
|
|
|
|
for (unsigned i = 1; i <= num; i++) {
|
|
|
|
result *= i;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
double
|
|
|
|
logFactorial (unsigned num)
|
|
|
|
{
|
|
|
|
double result = 0.0;
|
|
|
|
if (num < 150) {
|
|
|
|
result = std::log (factorial (num));
|
|
|
|
} else {
|
|
|
|
for (unsigned i = 1; i <= num; i++) {
|
|
|
|
result += std::log (i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
unsigned
|
|
|
|
nrCombinations (unsigned n, unsigned k)
|
|
|
|
{
|
|
|
|
assert (n >= k);
|
|
|
|
int diff = n - k;
|
|
|
|
unsigned result = 0;
|
|
|
|
if (n < 150) {
|
|
|
|
unsigned prod = 1;
|
|
|
|
for (int i = n; i > diff; i--) {
|
|
|
|
prod *= i;
|
|
|
|
}
|
|
|
|
result = prod / factorial (k);
|
|
|
|
} else {
|
|
|
|
double prod = 0.0;
|
|
|
|
for (int i = n; i > diff; i--) {
|
|
|
|
prod += std::log (i);
|
|
|
|
}
|
|
|
|
prod -= logFactorial (k);
|
|
|
|
result = static_cast<unsigned> (std::exp (prod));
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-05-24 22:55:20 +01:00
|
|
|
size_t
|
2012-05-24 16:14:13 +01:00
|
|
|
sizeExpected (const Ranges& ranges)
|
2012-05-23 14:56:01 +01:00
|
|
|
{
|
2012-05-24 14:55:30 +01:00
|
|
|
return std::accumulate (
|
|
|
|
ranges.begin(), ranges.end(), 1, multiplies<unsigned>());
|
2012-05-23 14:56:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
unsigned
|
2012-05-24 16:14:13 +01:00
|
|
|
nrDigits (int num)
|
2012-05-23 14:56:01 +01:00
|
|
|
{
|
|
|
|
unsigned count = 1;
|
|
|
|
while (num >= 10) {
|
|
|
|
num /= 10;
|
|
|
|
count ++;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
isInteger (const string& s)
|
|
|
|
{
|
|
|
|
stringstream ss1 (s);
|
|
|
|
stringstream ss2;
|
|
|
|
int integer;
|
|
|
|
ss1 >> integer;
|
|
|
|
ss2 << integer;
|
|
|
|
return (ss1.str() == ss2.str());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
string
|
|
|
|
parametersToString (const Params& v, unsigned precision)
|
|
|
|
{
|
|
|
|
stringstream ss;
|
|
|
|
ss.precision (precision);
|
|
|
|
ss << "[" ;
|
2012-05-24 22:55:20 +01:00
|
|
|
for (size_t i = 0; i < v.size(); i++) {
|
2012-05-23 14:56:01 +01:00
|
|
|
if (i != 0) ss << ", " ;
|
|
|
|
ss << v[i];
|
|
|
|
}
|
|
|
|
ss << "]" ;
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vector<string>
|
|
|
|
getStateLines (const Vars& vars)
|
|
|
|
{
|
2012-05-24 22:55:20 +01:00
|
|
|
Ranges ranges;
|
|
|
|
for (size_t i = 0; i < vars.size(); i++) {
|
|
|
|
ranges.push_back (vars[i]->range());
|
|
|
|
}
|
2012-05-25 21:16:08 +01:00
|
|
|
Indexer indexer (ranges);
|
2012-05-23 14:56:01 +01:00
|
|
|
vector<string> jointStrings;
|
2012-05-24 22:55:20 +01:00
|
|
|
while (indexer.valid()) {
|
2012-05-23 14:56:01 +01:00
|
|
|
stringstream ss;
|
2012-05-24 22:55:20 +01:00
|
|
|
for (size_t i = 0; i < vars.size(); i++) {
|
2012-05-23 14:56:01 +01:00
|
|
|
if (i != 0) ss << ", " ;
|
2012-05-24 22:55:20 +01:00
|
|
|
ss << vars[i]->label() << "=" ;
|
|
|
|
ss << vars[i]->states()[(indexer[i])];
|
2012-05-23 14:56:01 +01:00
|
|
|
}
|
|
|
|
jointStrings.push_back (ss.str());
|
2012-05-24 22:55:20 +01:00
|
|
|
++ indexer;
|
2012-05-23 14:56:01 +01:00
|
|
|
}
|
|
|
|
return jointStrings;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
setHorusFlag (string key, string value)
|
|
|
|
{
|
|
|
|
bool returnVal = true;
|
|
|
|
if (key == "verbosity") {
|
|
|
|
stringstream ss;
|
|
|
|
ss << value;
|
|
|
|
ss >> Globals::verbosity;
|
|
|
|
} else if (key == "inf_alg") {
|
|
|
|
if ( value == "ve") {
|
|
|
|
Globals::infAlgorithm = InfAlgorithms::VE;
|
|
|
|
} else if (value == "bp") {
|
|
|
|
Globals::infAlgorithm = InfAlgorithms::BP;
|
|
|
|
} else if (value == "cbp") {
|
|
|
|
Globals::infAlgorithm = InfAlgorithms::CBP;
|
|
|
|
} else {
|
|
|
|
cerr << "warning: invalid value `" << value << "' " ;
|
|
|
|
cerr << "for `" << key << "'" << endl;
|
|
|
|
returnVal = false;
|
|
|
|
}
|
|
|
|
} else if (key == "elim_heuristic") {
|
|
|
|
if ( value == "min_neighbors") {
|
|
|
|
ElimGraph::elimHeuristic = ElimHeuristic::MIN_NEIGHBORS;
|
|
|
|
} else if (value == "min_weight") {
|
|
|
|
ElimGraph::elimHeuristic = ElimHeuristic::MIN_WEIGHT;
|
|
|
|
} else if (value == "min_fill") {
|
|
|
|
ElimGraph::elimHeuristic = ElimHeuristic::MIN_FILL;
|
|
|
|
} else if (value == "weighted_min_fill") {
|
|
|
|
ElimGraph::elimHeuristic = ElimHeuristic::WEIGHTED_MIN_FILL;
|
|
|
|
} else {
|
|
|
|
cerr << "warning: invalid value `" << value << "' " ;
|
|
|
|
cerr << "for `" << key << "'" << endl;
|
|
|
|
returnVal = false;
|
|
|
|
}
|
|
|
|
} else if (key == "schedule") {
|
|
|
|
if ( value == "seq_fixed") {
|
|
|
|
BpOptions::schedule = BpOptions::Schedule::SEQ_FIXED;
|
|
|
|
} else if (value == "seq_random") {
|
|
|
|
BpOptions::schedule = BpOptions::Schedule::SEQ_RANDOM;
|
|
|
|
} else if (value == "parallel") {
|
|
|
|
BpOptions::schedule = BpOptions::Schedule::PARALLEL;
|
|
|
|
} else if (value == "max_residual") {
|
|
|
|
BpOptions::schedule = BpOptions::Schedule::MAX_RESIDUAL;
|
|
|
|
} else {
|
|
|
|
cerr << "warning: invalid value `" << value << "' " ;
|
|
|
|
cerr << "for `" << key << "'" << endl;
|
|
|
|
returnVal = false;
|
|
|
|
}
|
|
|
|
} else if (key == "accuracy") {
|
|
|
|
stringstream ss;
|
|
|
|
ss << value;
|
|
|
|
ss >> BpOptions::accuracy;
|
|
|
|
} else if (key == "max_iter") {
|
|
|
|
stringstream ss;
|
|
|
|
ss << value;
|
|
|
|
ss >> BpOptions::maxIter;
|
|
|
|
} else if (key == "use_logarithms") {
|
|
|
|
if ( value == "true") {
|
|
|
|
Globals::logDomain = true;
|
|
|
|
} else if (value == "false") {
|
|
|
|
Globals::logDomain = false;
|
|
|
|
} else {
|
|
|
|
cerr << "warning: invalid value `" << value << "' " ;
|
|
|
|
cerr << "for `" << key << "'" << endl;
|
|
|
|
returnVal = false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
cerr << "warning: invalid key `" << key << "'" << endl;
|
|
|
|
returnVal = false;
|
|
|
|
}
|
|
|
|
return returnVal;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
printHeader (string header, std::ostream& os)
|
|
|
|
{
|
|
|
|
printAsteriskLine (os);
|
|
|
|
os << header << endl;
|
|
|
|
printAsteriskLine (os);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
printSubHeader (string header, std::ostream& os)
|
|
|
|
{
|
|
|
|
printDashedLine (os);
|
|
|
|
os << header << endl;
|
|
|
|
printDashedLine (os);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
printAsteriskLine (std::ostream& os)
|
|
|
|
{
|
|
|
|
os << "********************************" ;
|
|
|
|
os << "********************************" ;
|
|
|
|
os << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
printDashedLine (std::ostream& os)
|
|
|
|
{
|
|
|
|
os << "--------------------------------" ;
|
|
|
|
os << "--------------------------------" ;
|
|
|
|
os << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace LogAware {
|
|
|
|
|
|
|
|
void
|
|
|
|
normalize (Params& v)
|
|
|
|
{
|
|
|
|
double sum = LogAware::addIdenty();
|
|
|
|
if (Globals::logDomain) {
|
2012-05-24 22:55:20 +01:00
|
|
|
for (size_t i = 0; i < v.size(); i++) {
|
2012-05-23 14:56:01 +01:00
|
|
|
sum = Util::logSum (sum, v[i]);
|
|
|
|
}
|
|
|
|
assert (sum != -numeric_limits<double>::infinity());
|
2012-05-24 22:55:20 +01:00
|
|
|
for (size_t i = 0; i < v.size(); i++) {
|
2012-05-23 14:56:01 +01:00
|
|
|
v[i] -= sum;
|
|
|
|
}
|
|
|
|
} else {
|
2012-05-24 22:55:20 +01:00
|
|
|
for (size_t i = 0; i < v.size(); i++) {
|
2012-05-23 14:56:01 +01:00
|
|
|
sum += v[i];
|
|
|
|
}
|
|
|
|
assert (sum != 0.0);
|
2012-05-24 22:55:20 +01:00
|
|
|
for (size_t i = 0; i < v.size(); i++) {
|
2012-05-23 14:56:01 +01:00
|
|
|
v[i] /= sum;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
double
|
|
|
|
getL1Distance (const Params& v1, const Params& v2)
|
|
|
|
{
|
|
|
|
assert (v1.size() == v2.size());
|
|
|
|
double dist = 0.0;
|
|
|
|
if (Globals::logDomain) {
|
2012-05-24 22:55:20 +01:00
|
|
|
for (size_t i = 0; i < v1.size(); i++) {
|
2012-05-23 14:56:01 +01:00
|
|
|
dist += abs (exp(v1[i]) - exp(v2[i]));
|
|
|
|
}
|
|
|
|
} else {
|
2012-05-24 22:55:20 +01:00
|
|
|
for (size_t i = 0; i < v1.size(); i++) {
|
2012-05-23 14:56:01 +01:00
|
|
|
dist += abs (v1[i] - v2[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return dist;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
double
|
|
|
|
getMaxNorm (const Params& v1, const Params& v2)
|
|
|
|
{
|
|
|
|
assert (v1.size() == v2.size());
|
|
|
|
double max = 0.0;
|
|
|
|
if (Globals::logDomain) {
|
2012-05-24 22:55:20 +01:00
|
|
|
for (size_t i = 0; i < v1.size(); i++) {
|
2012-05-23 14:56:01 +01:00
|
|
|
double diff = abs (exp(v1[i]) - exp(v2[i]));
|
|
|
|
if (diff > max) {
|
|
|
|
max = diff;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2012-05-24 22:55:20 +01:00
|
|
|
for (size_t i = 0; i < v1.size(); i++) {
|
2012-05-23 14:56:01 +01:00
|
|
|
double diff = abs (v1[i] - v2[i]);
|
|
|
|
if (diff > max) {
|
|
|
|
max = diff;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return max;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-24 14:55:30 +01:00
|
|
|
|
2012-05-23 14:56:01 +01:00
|
|
|
double
|
2012-05-24 14:55:30 +01:00
|
|
|
pow (double base, unsigned iexp)
|
2012-05-23 14:56:01 +01:00
|
|
|
{
|
2012-05-24 14:55:30 +01:00
|
|
|
return Globals::logDomain ? base * iexp : std::pow (base, iexp);
|
2012-05-23 14:56:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
double
|
2012-05-24 14:55:30 +01:00
|
|
|
pow (double base, double exp)
|
2012-05-23 14:56:01 +01:00
|
|
|
{
|
|
|
|
// assumes that `expoent' is never in log domain
|
2012-05-24 14:55:30 +01:00
|
|
|
return Globals::logDomain ? base * exp : std::pow (base, exp);
|
2012-05-23 14:56:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2012-05-24 14:55:30 +01:00
|
|
|
pow (Params& v, unsigned iexp)
|
2012-05-23 14:56:01 +01:00
|
|
|
{
|
2012-05-24 14:55:30 +01:00
|
|
|
if (iexp == 1) {
|
2012-05-23 14:56:01 +01:00
|
|
|
return;
|
|
|
|
}
|
2012-05-24 14:55:30 +01:00
|
|
|
Globals::logDomain ? v *= iexp : v ^= (int)iexp;
|
2012-05-23 14:56:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2012-05-24 14:55:30 +01:00
|
|
|
pow (Params& v, double exp)
|
2012-05-23 14:56:01 +01:00
|
|
|
{
|
2012-05-24 14:55:30 +01:00
|
|
|
// `expoent' should not be in log domain
|
|
|
|
Globals::logDomain ? v *= exp : v ^= exp;
|
2012-05-23 14:56:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|