#ifndef HORUS_FACTOR_H #define HORUS_FACTOR_H #include #include "Indexer.h" #include "Util.h" using namespace std; template class TFactor { public: const vector& arguments (void) const { return args_; } vector& arguments (void) { return args_; } const Ranges& ranges (void) const { return ranges_; } const Params& params (void) const { return params_; } Params& params (void) { return params_; } size_t nrArguments (void) const { return args_.size(); } size_t size (void) const { return params_.size(); } unsigned distId (void) const { return distId_; } void setDistId (unsigned id) { distId_ = id; } void normalize (void) { LogAware::normalize (params_); } void randomize (void) { for (size_t i = 0; i < params_.size(); ++i) { params_[i] = (double) std::rand() / RAND_MAX; } } void setParams (const Params& newParams) { params_ = newParams; assert (params_.size() == Util::sizeExpected (ranges_)); } size_t indexOf (const T& t) const { return Util::indexOf (args_, t); } const T& argument (size_t idx) const { assert (idx < args_.size()); return args_[idx]; } T& argument (size_t idx) { assert (idx < args_.size()); return args_[idx]; } unsigned range (size_t idx) const { assert (idx < ranges_.size()); return ranges_[idx]; } void multiply (TFactor& g) { if (args_ == g.arguments()) { // optimization Globals::logDomain ? params_ += g.params() : params_ *= g.params(); return; } unsigned range_prod = 1; bool share_arguments = false; const vector& g_args = g.arguments(); const Ranges& g_ranges = g.ranges(); const Params& g_params = g.params(); for (size_t i = 0; i < g_args.size(); i++) { size_t idx = indexOf (g_args[i]); if (idx == args_.size()) { range_prod *= g_ranges[i]; args_.push_back (g_args[i]); ranges_.push_back (g_ranges[i]); } else { share_arguments = true; } } if (share_arguments == false) { // optimization cartesianProduct (g_params.begin(), g_params.end()); } else { extend (range_prod); Params::iterator it = params_.begin(); MapIndexer indexer (args_, ranges_, g_args, g_ranges); if (Globals::logDomain) { for (; indexer.valid(); ++it, ++indexer) { *it += g_params[indexer]; } } else { for (; indexer.valid(); ++it, ++indexer) { *it *= g_params[indexer]; } } } } void sumOutIndex (size_t idx) { assert (idx < args_.size()); assert (args_.size() > 1); size_t new_size = params_.size() / ranges_[idx]; Params newps (new_size, LogAware::addIdenty()); Params::const_iterator first = params_.begin(); Params::const_iterator last = params_.end(); MapIndexer indexer (ranges_, idx); if (Globals::logDomain) { for (; first != last; ++indexer) { newps[indexer] = Util::logSum (newps[indexer], *first++); } } else { for (; first != last; ++indexer) { newps[indexer] += *first++; } } params_ = newps; args_.erase (args_.begin() + idx); ranges_.erase (ranges_.begin() + idx); } void absorveEvidence (const T& arg, unsigned obsIdx) { size_t idx = indexOf (arg); assert (idx != args_.size()); assert (obsIdx < ranges_[idx]); Params newps; newps.reserve (params_.size() / ranges_[idx]); Indexer indexer (ranges_); for (unsigned i = 0; i < obsIdx; ++i) { indexer.incrementDimension (idx); } while (indexer.valid()) { newps.push_back (params_[indexer]); indexer.incrementExceptDimension (idx); } params_ = newps; args_.erase (args_.begin() + idx); ranges_.erase (ranges_.begin() + idx); } void reorderArguments (const vector new_args) { assert (new_args.size() == args_.size()); if (new_args == args_) { return; // already on the desired order } Ranges new_ranges; for (size_t i = 0; i < new_args.size(); i++) { size_t idx = indexOf (new_args[i]); assert (idx != args_.size()); new_ranges.push_back (ranges_[idx]); } Params newps; newps.reserve (params_.size()); MapIndexer indexer (new_args, new_ranges, args_, ranges_); for (; indexer.valid(); ++indexer) { newps.push_back (params_[indexer]); } params_ = newps; args_ = new_args; ranges_ = new_ranges; } bool contains (const T& arg) const { return Util::contains (args_, arg); } bool contains (const vector& args) const { for (size_t i = 0; i < args.size(); i++) { if (contains (args[i]) == false) { return false; } } return true; } double& operator[] (size_t idx) { assert (idx < params_.size()); return params_[idx]; } protected: vector args_; Ranges ranges_; Params params_; unsigned distId_; private: void extend (unsigned range_prod) { Params backup = params_; params_.clear(); params_.reserve (backup.size() * range_prod); Params::const_iterator first = backup.begin(); Params::const_iterator last = backup.end(); for (; first != last; ++first) { for (unsigned reps = 0; reps < range_prod; ++reps) { params_.push_back (*first); } } } void cartesianProduct ( Params::const_iterator first2, Params::const_iterator last2) { Params backup = params_; params_.clear(); params_.reserve (params_.size() * (last2 - first2)); Params::const_iterator first1 = backup.begin(); Params::const_iterator last1 = backup.end(); Params::const_iterator tmp; if (Globals::logDomain) { for (; first1 != last1; ++first1) { for (tmp = first2; tmp != last2; ++tmp) { params_.push_back ((*first1) + (*tmp)); } } } else { for (; first1 != last1; ++first1) { for (tmp = first2; tmp != last2; ++tmp) { params_.push_back ((*first1) * (*tmp)); } } } } }; class Factor : public TFactor { public: Factor (void) { } Factor (const Factor&); Factor (const VarIds&, const Ranges&, const Params&, unsigned = Util::maxUnsigned()); Factor (const Vars&, const Params&, unsigned = Util::maxUnsigned()); void sumOut (VarId); void sumOutAllExcept (VarId); void sumOutAllExcept (const VarIds&); void sumOutAllExceptIndex (size_t idx); void multiply (Factor&); string getLabel (void) const; void print (void) const; private: void sumOutFirstVariable (void); void sumOutLastVariable (void); void sumOutArgs (const vector& mask); void clone (const Factor& f); DISALLOW_ASSIGN (Factor); }; #endif // HORUS_FACTOR_H