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.
yap-6.3/packages/CLPBN/clpbn/bp/Factor.cpp

518 lines
11 KiB
C++
Raw Normal View History

#include <cstdlib>
#include <cassert>
2011-12-12 15:29:51 +00:00
#include <algorithm>
#include <iostream>
#include <sstream>
#include "Factor.h"
2012-03-22 11:33:24 +00:00
#include "Indexer.h"
#include "Util.h"
Factor::Factor (const Factor& g)
{
2011-12-12 15:29:51 +00:00
copyFromFactor (g);
}
2011-12-12 15:29:51 +00:00
Factor::Factor (VarId vid, unsigned nStates)
{
2011-12-12 15:29:51 +00:00
varids_.push_back (vid);
ranges_.push_back (nStates);
2012-03-22 11:33:24 +00:00
dist_ = new Distribution (Params (nStates, 1.0));
}
2011-12-12 15:29:51 +00:00
Factor::Factor (const VarNodes& vars)
{
int nParams = 1;
2011-12-12 15:29:51 +00:00
for (unsigned i = 0; i < vars.size(); i++) {
varids_.push_back (vars[i]->varId());
ranges_.push_back (vars[i]->nrStates());
nParams *= vars[i]->nrStates();
}
// create a uniform distribution
double val = 1.0 / nParams;
2012-03-22 11:33:24 +00:00
dist_ = new Distribution (Params (nParams, val));
}
2012-03-22 11:33:24 +00:00
Factor::Factor (VarId vid, unsigned nStates, const Params& params)
{
2011-12-12 15:29:51 +00:00
varids_.push_back (vid);
ranges_.push_back (nStates);
dist_ = new Distribution (params);
}
2011-12-12 15:29:51 +00:00
Factor::Factor (VarNodes& vars, Distribution* dist)
{
2011-12-12 15:29:51 +00:00
for (unsigned i = 0; i < vars.size(); i++) {
varids_.push_back (vars[i]->varId());
ranges_.push_back (vars[i]->nrStates());
}
dist_ = dist;
}
2012-03-22 11:33:24 +00:00
Factor::Factor (const VarNodes& vars, const Params& params)
{
2011-12-12 15:29:51 +00:00
for (unsigned i = 0; i < vars.size(); i++) {
varids_.push_back (vars[i]->varId());
ranges_.push_back (vars[i]->nrStates());
}
dist_ = new Distribution (params);
}
2012-03-22 11:33:24 +00:00
Factor::Factor (const VarIds& vids,
2011-12-12 15:29:51 +00:00
const Ranges& ranges,
2012-03-22 11:33:24 +00:00
const Params& params)
2011-12-12 15:29:51 +00:00
{
varids_ = vids;
ranges_ = ranges;
dist_ = new Distribution (params);
}
2012-03-22 11:33:24 +00:00
Factor::~Factor (void)
{
if (dist_->shared() == false) {
delete dist_;
}
}
void
2012-03-22 11:33:24 +00:00
Factor::setParameters (const Params& params)
{
assert (dist_->params.size() == params.size());
2012-03-22 11:33:24 +00:00
dist_->params = params;
}
void
2011-12-12 15:29:51 +00:00
Factor::copyFromFactor (const Factor& g)
{
2011-12-12 15:29:51 +00:00
varids_ = g.getVarIds();
ranges_ = g.getRanges();
2012-03-22 11:33:24 +00:00
dist_ = new Distribution (g.getParameters());
}
void
2012-03-22 11:33:24 +00:00
Factor::multiply (const Factor& g)
{
2011-12-12 15:29:51 +00:00
if (varids_.size() == 0) {
copyFromFactor (g);
return;
}
2012-03-22 11:33:24 +00:00
const VarIds& g_varids = g.getVarIds();
const Ranges& g_ranges = g.getRanges();
const Params& g_params = g.getParameters();
2012-03-22 11:33:24 +00:00
if (varids_ == g_varids) {
// optimization: if the factors contain the same set of variables,
2011-12-12 15:29:51 +00:00
// we can do a 1 to 1 operation on the parameters
2012-03-22 11:33:24 +00:00
if (Globals::logDomain) {
Util::add (dist_->params, g_params);
} else {
Util::multiply (dist_->params, g_params);
}
} else {
2012-03-22 11:33:24 +00:00
bool sharedVars = false;
2011-12-12 15:29:51 +00:00
vector<unsigned> gvarpos;
2012-03-22 11:33:24 +00:00
for (unsigned i = 0; i < g_varids.size(); i++) {
int idx = indexOf (g_varids[i]);
if (idx == -1) {
insertVariable (g_varids[i], g_ranges[i]);
2011-12-12 15:29:51 +00:00
gvarpos.push_back (varids_.size() - 1);
} else {
2012-03-22 11:33:24 +00:00
sharedVars = true;
gvarpos.push_back (idx);
}
}
2012-03-22 11:33:24 +00:00
if (sharedVars == false) {
// optimization: if the original factors doesn't have common variables,
// we don't need to marry the states of the common variables
unsigned count = 0;
for (unsigned i = 0; i < dist_->params.size(); i++) {
2012-03-22 11:33:24 +00:00
if (Globals::logDomain) {
dist_->params[i] += g_params[count];
} else {
dist_->params[i] *= g_params[count];
2011-12-12 15:29:51 +00:00
}
count ++;
2012-03-22 11:33:24 +00:00
if (count >= g_params.size()) {
count = 0;
}
}
2012-03-22 11:33:24 +00:00
} else {
StatesIndexer indexer (ranges_, false);
while (indexer.valid()) {
unsigned g_li = 0;
unsigned prod = 1;
for (int j = gvarpos.size() - 1; j >= 0; j--) {
g_li += indexer[gvarpos[j]] * prod;
prod *= g_ranges[j];
}
if (Globals::logDomain) {
dist_->params[indexer] += g_params[g_li];
} else {
dist_->params[indexer] *= g_params[g_li];
}
++ indexer;
}
}
}
}
void
2012-03-22 11:33:24 +00:00
Factor::insertVariable (VarId varId, unsigned nrStates)
{
2012-03-22 11:33:24 +00:00
assert (indexOf (varId) == -1);
Params oldParams = dist_->params;
dist_->params.clear();
dist_->params.reserve (oldParams.size() * nrStates);
for (unsigned i = 0; i < oldParams.size(); i++) {
for (unsigned reps = 0; reps < nrStates; reps++) {
dist_->params.push_back (oldParams[i]);
}
}
varids_.push_back (varId);
ranges_.push_back (nrStates);
}
void
Factor::insertVariables (const VarIds& varIds, const Ranges& ranges)
{
Params oldParams = dist_->params;
unsigned nrStates = 1;
for (unsigned i = 0; i < varIds.size(); i++) {
assert (indexOf (varIds[i]) == -1);
varids_.push_back (varIds[i]);
ranges_.push_back (ranges[i]);
nrStates *= ranges[i];
}
dist_->params.clear();
dist_->params.reserve (oldParams.size() * nrStates);
for (unsigned i = 0; i < oldParams.size(); i++) {
for (unsigned reps = 0; reps < nrStates; reps++) {
dist_->params.push_back (oldParams[i]);
}
}
}
void
2012-03-22 11:33:24 +00:00
Factor::sumOutAllExcept (VarId vid)
{
2012-03-22 11:33:24 +00:00
assert (indexOf (vid) != -1);
2011-12-12 15:29:51 +00:00
while (varids_.back() != vid) {
2012-03-22 11:33:24 +00:00
sumOutLastVariable();
2011-12-12 15:29:51 +00:00
}
while (varids_.front() != vid) {
2012-03-22 11:33:24 +00:00
sumOutFirstVariable();
2011-12-12 15:29:51 +00:00
}
}
void
2012-03-22 11:33:24 +00:00
Factor::sumOutAllExcept (const VarIds& vids)
{
for (unsigned i = 0; i < varids_.size(); i++) {
if (std::find (vids.begin(), vids.end(), varids_[i]) == vids.end()) {
sumOut (varids_[i]);
}
}
}
void
Factor::sumOut (VarId vid)
2011-12-12 15:29:51 +00:00
{
2012-03-22 11:33:24 +00:00
int idx = indexOf (vid);
assert (idx != -1);
2011-12-12 15:29:51 +00:00
if (vid == varids_.back()) {
2012-03-22 11:33:24 +00:00
sumOutLastVariable(); // optimization
2011-12-12 15:29:51 +00:00
return;
}
if (vid == varids_.front()) {
2012-03-22 11:33:24 +00:00
sumOutFirstVariable(); // optimization
2011-12-12 15:29:51 +00:00
return;
}
// number of parameters separating a different state of `var',
// with the states of the remaining variables fixed
unsigned varOffset = 1;
// number of parameters separating a different state of the variable
// on the left of `var', with the states of the remaining vars fixed
unsigned leftVarOffset = 1;
2012-03-22 11:33:24 +00:00
for (int i = varids_.size() - 1; i > idx; i--) {
2011-12-12 15:29:51 +00:00
varOffset *= ranges_[i];
leftVarOffset *= ranges_[i];
}
2012-03-22 11:33:24 +00:00
leftVarOffset *= ranges_[idx];
unsigned offset = 0;
unsigned count1 = 0;
unsigned count2 = 0;
2012-03-22 11:33:24 +00:00
unsigned newpsSize = dist_->params.size() / ranges_[idx];
2012-03-22 11:33:24 +00:00
Params newps;
newps.reserve (newpsSize);
Params& params = dist_->params;
2012-03-22 11:33:24 +00:00
while (newps.size() < newpsSize) {
2011-12-12 15:29:51 +00:00
double sum = Util::addIdenty();
2012-03-22 11:33:24 +00:00
for (unsigned i = 0; i < ranges_[idx]; i++) {
if (Globals::logDomain) {
Util::logSum (sum, params[offset]);
} else {
sum += params[offset];
2011-12-12 15:29:51 +00:00
}
offset += varOffset;
}
2012-03-22 11:33:24 +00:00
newps.push_back (sum);
count1 ++;
2012-03-22 11:33:24 +00:00
if (idx == (int)varids_.size() - 1) {
offset = count1 * ranges_[idx];
} else {
if (((offset - varOffset + 1) % leftVarOffset) == 0) {
count1 = 0;
count2 ++;
}
offset = (leftVarOffset * count2) + count1;
}
}
2012-03-22 11:33:24 +00:00
varids_.erase (varids_.begin() + idx);
ranges_.erase (ranges_.begin() + idx);
dist_->params = newps;
}
2011-12-12 15:29:51 +00:00
void
2012-03-22 11:33:24 +00:00
Factor::sumOutFirstVariable (void)
{
2012-03-22 11:33:24 +00:00
Params& params = dist_->params;
2011-12-12 15:29:51 +00:00
unsigned nStates = ranges_.front();
unsigned sep = params.size() / nStates;
2012-03-22 11:33:24 +00:00
if (Globals::logDomain) {
for (unsigned i = sep; i < params.size(); i++) {
Util::logSum (params[i % sep], params[i]);
}
} else {
for (unsigned i = sep; i < params.size(); i++) {
params[i % sep] += params[i];
}
2011-12-12 15:29:51 +00:00
}
params.resize (sep);
varids_.erase (varids_.begin());
ranges_.erase (ranges_.begin());
}
2011-12-12 15:29:51 +00:00
void
2012-03-22 11:33:24 +00:00
Factor::sumOutLastVariable (void)
2011-12-12 15:29:51 +00:00
{
2012-03-22 11:33:24 +00:00
Params& params = dist_->params;
2011-12-12 15:29:51 +00:00
unsigned nStates = ranges_.back();
unsigned idx1 = 0;
unsigned idx2 = 0;
2012-03-22 11:33:24 +00:00
if (Globals::logDomain) {
while (idx1 < params.size()) {
params[idx2] = params[idx1];
idx1 ++;
for (unsigned j = 1; j < nStates; j++) {
Util::logSum (params[idx2], params[idx1]);
2011-12-12 15:29:51 +00:00
idx1 ++;
}
2012-03-22 11:33:24 +00:00
idx2 ++;
}
} else {
while (idx1 < params.size()) {
params[idx2] = params[idx1];
idx1 ++;
for (unsigned j = 1; j < nStates; j++) {
params[idx2] += params[idx1];
2011-12-12 15:29:51 +00:00
idx1 ++;
}
2012-03-22 11:33:24 +00:00
idx2 ++;
}
2011-12-12 15:29:51 +00:00
}
params.resize (idx2);
varids_.pop_back();
ranges_.pop_back();
}
void
Factor::orderVariables (void)
{
2012-03-22 11:33:24 +00:00
VarIds sortedVarIds = varids_;
2011-12-12 15:29:51 +00:00
sort (sortedVarIds.begin(), sortedVarIds.end());
2012-03-22 11:33:24 +00:00
reorderVariables (sortedVarIds);
2011-12-12 15:29:51 +00:00
}
void
2012-03-22 11:33:24 +00:00
Factor::reorderVariables (const VarIds& newVarIds)
2011-12-12 15:29:51 +00:00
{
2012-03-22 11:33:24 +00:00
assert (newVarIds.size() == varids_.size());
if (newVarIds == varids_) {
2011-12-12 15:29:51 +00:00
return;
}
2012-03-22 11:33:24 +00:00
Ranges newRanges;
2011-12-12 15:29:51 +00:00
vector<unsigned> positions;
2012-03-22 11:33:24 +00:00
for (unsigned i = 0; i < newVarIds.size(); i++) {
unsigned idx = indexOf (newVarIds[i]);
newRanges.push_back (ranges_[idx]);
positions.push_back (idx);
2011-12-12 15:29:51 +00:00
}
2012-03-22 11:33:24 +00:00
2011-12-12 15:29:51 +00:00
unsigned N = ranges_.size();
2012-03-22 11:33:24 +00:00
Params newParams (dist_->params.size());
2011-12-12 15:29:51 +00:00
for (unsigned i = 0; i < dist_->params.size(); i++) {
unsigned li = i;
// calculate vector index corresponding to linear index
vector<unsigned> vi (N);
for (int k = N-1; k >= 0; k--) {
vi[k] = li % ranges_[k];
li /= ranges_[k];
}
2011-12-12 15:29:51 +00:00
// convert permuted vector index to corresponding linear index
unsigned prod = 1;
unsigned new_li = 0;
for (int k = N-1; k >= 0; k--) {
new_li += vi[positions[k]] * prod;
prod *= ranges_[positions[k]];
}
2012-03-22 11:33:24 +00:00
newParams[new_li] = dist_->params[i];
}
2012-03-22 11:33:24 +00:00
varids_ = newVarIds;
ranges_ = newRanges;
dist_->params = newParams;
2011-12-12 15:29:51 +00:00
}
void
2012-03-22 11:33:24 +00:00
Factor::absorveEvidence (VarId vid, unsigned evidence)
2011-12-12 15:29:51 +00:00
{
2012-03-22 11:33:24 +00:00
int idx = indexOf (vid);
assert (idx != -1);
Params oldParams = dist_->params;
dist_->params.clear();
dist_->params.reserve (oldParams.size() / ranges_[idx]);
StatesIndexer indexer (ranges_);
2011-12-12 15:29:51 +00:00
for (unsigned i = 0; i < evidence; i++) {
2012-03-22 11:33:24 +00:00
indexer.increment (idx);
}
while (indexer.valid()) {
dist_->params.push_back (oldParams[indexer]);
indexer.incrementExcluding (idx);
2011-12-12 15:29:51 +00:00
}
2012-03-22 11:33:24 +00:00
varids_.erase (varids_.begin() + idx);
ranges_.erase (ranges_.begin() + idx);
}
void
Factor::normalize (void)
{
Util::normalize (dist_->params);
}
bool
Factor::contains (const VarIds& vars) const
{
for (unsigned i = 0; i < vars.size(); i++) {
if (indexOf (vars[i]) == -1) {
return false;
}
2011-12-12 15:29:51 +00:00
}
2012-03-22 11:33:24 +00:00
return true;
}
int
Factor::indexOf (VarId vid) const
{
for (unsigned i = 0; i < varids_.size(); i++) {
if (varids_[i] == vid) {
return i;
}
}
return -1;
}
string
Factor::getLabel (void) const
{
stringstream ss;
2011-12-12 15:29:51 +00:00
ss << "f(" ;
for (unsigned i = 0; i < varids_.size(); i++) {
if (i != 0) ss << "," ;
2011-12-12 15:29:51 +00:00
ss << VarNode (varids_[i], ranges_[i]).label();
}
ss << ")" ;
return ss.str();
}
void
2012-03-22 11:33:24 +00:00
Factor::print (void) const
{
2011-12-12 15:29:51 +00:00
VarNodes vars;
for (unsigned i = 0; i < varids_.size(); i++) {
vars.push_back (new VarNode (varids_[i], ranges_[i]));
}
vector<string> jointStrings = Util::getJointStateStrings (vars);
for (unsigned i = 0; i < dist_->params.size(); i++) {
cout << "f(" << jointStrings[i] << ")" ;
cout << " = " << dist_->params[i] << endl;
}
2012-03-22 11:33:24 +00:00
cout << endl;
2011-12-12 15:29:51 +00:00
for (unsigned i = 0; i < vars.size(); i++) {
delete vars[i];
}
}