Add XSpode submodel

This commit is contained in:
2025-03-07 18:34:16 +01:00
parent b2002d341c
commit 7a23782b05
3 changed files with 473 additions and 72 deletions

View File

@@ -9,6 +9,7 @@
#include <limits.h>
#include <tuple>
#include "XBAODE.h"
#include "XSpode.hpp"
#include "TensorUtils.hpp"
#include <loguru.hpp>
@@ -86,7 +87,8 @@ namespace platform {
while (counter++ < k && featureSelection.size() > 0) {
auto feature = featureSelection[0];
featureSelection.erase(featureSelection.begin());
add_active_parent(feature);
auto model = XSpode(feature);
model.fit(X_train_, y_train_, weights_);
alpha_t = 0.0;
std::vector<int> ypred;
if (alpha_block) {
@@ -104,7 +106,7 @@ namespace platform {
aode_.remove_last_parent();
n_models--;
} else {
ypred = predict_spode(X_train_, feature);
ypred = model.predict(X_train_);
}
// Step 3.1: Compute the classifier amout of say
auto ypred_t = torch::tensor(ypred);

View File

@@ -0,0 +1,394 @@
#ifndef XSPODE_H
#define XSPODE_H
#include <vector>
#include <map>
#include <stdexcept>
#include <algorithm>
#include <numeric>
#include <string>
#include <cmath>
#include <limits>
#include <sstream>
#include <iostream>
namespace platform {
class XSpode {
public:
// --------------------------------------
// The SPODE can be EMPTY (just created),
// in COUNTS mode (accumulating raw counts),
// or in PROBS mode (storing conditional probabilities).
// --------------------------------------
enum class MatrixState {
EMPTY,
COUNTS,
PROBS
};
// --------------------------------------
// Constructor
//
// Supply which feature index is the single super-parent (“spIndex”).
// --------------------------------------
XSpode(int spIndex)
: superParent_{ spIndex },
nFeatures_{ 0 },
statesClass_{ 0 },
matrixState_{ MatrixState::EMPTY },
alpha_{ 1.0 }
{
}
// --------------------------------------
// fit
// --------------------------------------
//
// Trains the SPODE given data:
// X: X[f][n] is the f-th feature value for instance n
// y: y[n] is the class value for instance n
// states: a map or array that tells how many distinct states each feature and the class can take
//
// For example, states_.back() is the number of class states,
// and states_[f] is the number of distinct values for feature f.
//
// We only store conditional probabilities for:
// p(x_sp| c) (the super-parent feature)
// p(x_child| c, x_sp) for all child ≠ sp
//
// The “weights” can be a vector of per-instance weights; if not used, pass them as 1.0.
// --------------------------------------
void fit(const std::vector<std::vector<int>>& X,
const std::vector<int>& y,
const torch::Tensor& weights)
{
int numInstances = static_cast<int>(y.size());
nFeatures_ = static_cast<int>(X.size());
// Derive the number of states for each feature and for the class.
// (This is just one approach; adapt to match your environment.)
// Here, we assume the user also gave us the total #states per feature in e.g. statesMap.
// We'll simply reconstruct the integer states_ array. The last entry is statesClass_.
states_.resize(nFeatures_);
for (int f = 0; f < nFeatures_; f++) {
// Suppose you look up in “statesMap” by the feature name, or read directly from X.
// We'll assume states_[f] = max value in X[f] + 1.
auto maxIt = std::max_element(X[f].begin(), X[f].end());
states_[f] = (*maxIt) + 1;
}
// For the class: states_.back() = max(y)+1
statesClass_ = (*std::max_element(y.begin(), y.end())) + 1;
// Initialize counts
classCounts_.resize(statesClass_, 0.0);
// p(x_sp = spVal | c)
// We'll store these counts in spFeatureCounts_[spVal * statesClass_ + c].
spFeatureCounts_.resize(states_[superParent_] * statesClass_, 0.0);
// For each child ≠ sp, we store p(childVal| c, spVal) in a separate block of childCounts_.
// childCounts_ will be sized as sum_{child≠sp} (states_[child] * statesClass_ * states_[sp]).
// We also need an offset for each child to index into childCounts_.
childOffsets_.resize(nFeatures_, -1);
int totalSize = 0;
for (int f = 0; f < nFeatures_; f++) {
if (f == superParent_) continue; // skip sp
childOffsets_[f] = totalSize;
// block size for this child's counts: states_[f] * statesClass_ * states_[superParent_]
totalSize += (states_[f] * statesClass_ * states_[superParent_]);
}
childCounts_.resize(totalSize, 0.0);
// Switch to COUNTS mode
matrixState_ = MatrixState::COUNTS;
// Accumulate raw counts
for (int n = 0; n < numInstances; n++) {
std::vector<int> instance(nFeatures_ + 1);
for (int f = 0; f < nFeatures_; f++) {
instance[f] = X[f][n];
}
instance[nFeatures_] = y[n];
addSample(instance, weights[n].item<double>());
}
// Laplace smoothing scaled to #instances
alpha_ = 1.0 / static_cast<double>(numInstances);
initializer_ = initializer_ = std::numeric_limits<double>::max() / (nFeatures_ * nFeatures_);
// Convert raw counts to probabilities
computeProbabilities();
}
// --------------------------------------
// addSample (only valid in COUNTS mode)
// --------------------------------------
//
// instance has size nFeatures_ + 1, with the class at the end.
// We add 1 to the appropriate counters for each (c, superParentVal, childVal).
//
void addSample(const std::vector<int>& instance, double weight)
{
if (matrixState_ != MatrixState::COUNTS) {
throw std::logic_error("addSample: Not in COUNTS mode!");
}
if (weight <= 0.0) return;
int c = instance.back();
// (A) increment classCounts
classCounts_[c] += weight;
// (B) increment super-parent counts => p(x_sp | c)
int spVal = instance[superParent_];
spFeatureCounts_[spVal * statesClass_ + c] += weight;
// (C) increment child counts => p(childVal | c, x_sp)
for (int f = 0; f < nFeatures_; f++) {
if (f == superParent_) continue;
int childVal = instance[f];
int offset = childOffsets_[f];
// Compute index in childCounts_.
// Layout: [ offset + (spVal * states_[f] + childVal) * statesClass_ + c ]
int blockSize = states_[f] * statesClass_;
int idx = offset + spVal * blockSize + childVal * statesClass_ + c;
childCounts_[idx] += weight;
}
}
// --------------------------------------
// computeProbabilities
// --------------------------------------
//
// Once all samples are added in COUNTS mode, call this to:
// p(c)
// p(x_sp = spVal | c)
// p(x_child = v | c, x_sp = s_sp)
//
// We store them in the corresponding *Probs_ arrays for inference.
// --------------------------------------
void computeProbabilities()
{
if (matrixState_ != MatrixState::COUNTS) {
throw std::logic_error("computeProbabilities: must be in COUNTS mode.");
}
double totalCount = std::accumulate(classCounts_.begin(), classCounts_.end(), 0.0);
// p(c) => classPriors_
classPriors_.resize(statesClass_, 0.0);
if (totalCount <= 0.0) {
// fallback => uniform
double unif = 1.0 / static_cast<double>(statesClass_);
for (int c = 0; c < statesClass_; c++) {
classPriors_[c] = unif;
}
} else {
for (int c = 0; c < statesClass_; c++) {
classPriors_[c] = (classCounts_[c] + alpha_)
/ (totalCount + alpha_ * statesClass_);
}
}
// p(x_sp | c)
spFeatureProbs_.resize(spFeatureCounts_.size());
// denominator for spVal * statesClass_ + c is just classCounts_[c] + alpha_ * (#states of sp)
int spCard = states_[superParent_];
for (int spVal = 0; spVal < spCard; spVal++) {
for (int c = 0; c < statesClass_; c++) {
double denom = classCounts_[c] + alpha_ * spCard;
double num = spFeatureCounts_[spVal * statesClass_ + c] + alpha_;
spFeatureProbs_[spVal * statesClass_ + c] = (denom <= 0.0 ? 0.0 : num / denom);
}
}
// p(x_child | c, x_sp)
childProbs_.resize(childCounts_.size());
for (int f = 0; f < nFeatures_; f++) {
if (f == superParent_) continue;
int offset = childOffsets_[f];
int childCard = states_[f];
// For each spVal, c, childVal in childCounts_:
for (int spVal = 0; spVal < spCard; spVal++) {
for (int childVal = 0; childVal < childCard; childVal++) {
for (int c = 0; c < statesClass_; c++) {
int idx = offset + spVal * (childCard * statesClass_)
+ childVal * statesClass_
+ c;
double num = childCounts_[idx] + alpha_;
// denominator = spFeatureCounts_[spVal * statesClass_ + c] + alpha_ * (#states of child)
double denom = spFeatureCounts_[spVal * statesClass_ + c]
+ alpha_ * childCard;
childProbs_[idx] = (denom <= 0.0 ? 0.0 : num / denom);
}
}
}
}
matrixState_ = MatrixState::PROBS;
}
// --------------------------------------
// predict_proba
// --------------------------------------
//
// For a single instance x of dimension nFeatures_:
// P(c | x) ∝ p(c) × p(x_sp | c) × ∏(child ≠ sp) p(x_child | c, x_sp).
//
// Then we normalize the result.
// --------------------------------------
std::vector<double> predict_proba(const std::vector<int>& instance) const
{
if (matrixState_ != MatrixState::PROBS) {
throw std::logic_error("predict_proba: the model is not in PROBS mode.");
}
std::vector<double> probs(statesClass_, 0.0);
// Multiply p(c) × p(x_sp | c)
int spVal = instance[superParent_];
for (int c = 0; c < statesClass_; c++) {
double pc = classPriors_[c];
double pSpC = spFeatureProbs_[spVal * statesClass_ + c];
probs[c] = pc * pSpC * initializer_;
}
// Multiply by each childs probability p(x_child | c, x_sp)
for (int feature = 0; feature < nFeatures_; feature++) {
if (feature == superParent_) continue; // skip sp
int sf = instance[feature];
int offset = childOffsets_[feature];
int childCard = states_[feature]; // not used directly, but for clarity
// Index into childProbs_ = offset + spVal*(childCard*statesClass_) + childVal*statesClass_ + c
int base = offset + spVal * (childCard * statesClass_) + sf * statesClass_;
for (int c = 0; c < statesClass_; c++) {
probs[c] *= childProbs_[base + c];
}
}
// Normalize
normalize(probs);
return probs;
}
// --------------------------------------
// predict
// --------------------------------------
//
// Return the class argmax( P(c|x) ).
// --------------------------------------
int predict(const std::vector<int>& instance) const
{
auto p = predict_proba(instance);
return static_cast<int>(std::distance(p.begin(),
std::max_element(p.begin(), p.end())));
}
std::vector<int> predict(const std::vector<std::vector<int>>& X) const
{
std::vector<int> preds;
for (const auto& instance : X) {
preds.push_back(predict(instance));
}
return preds;
}
// --------------------------------------
// Utility: normalize
// --------------------------------------
void normalize(std::vector<double>& v) const
{
double sum = 0.0;
for (auto val : v) { sum += val; }
if (sum <= 0.0) {
return;
}
for (auto& val : v) {
val /= sum;
}
}
// --------------------------------------
// debug printing, if desired
// --------------------------------------
std::string to_string() const
{
std::ostringstream oss;
oss << "---- SPODE Model ----\n"
<< "nFeatures_ = " << nFeatures_ << "\n"
<< "superParent_ = " << superParent_ << "\n"
<< "statesClass_ = " << statesClass_ << "\n"
<< "matrixState_ = "
<< (matrixState_ == MatrixState::EMPTY ? "EMPTY"
: (matrixState_ == MatrixState::COUNTS ? "COUNTS" : "PROBS"))
<< "\n";
oss << "States: [";
for (int s : states_) oss << s << " ";
oss << "]\n";
oss << "classCounts_: [";
for (double c : classCounts_) oss << c << " ";
oss << "]\n";
oss << "classPriors_: [";
for (double c : classPriors_) oss << c << " ";
oss << "]\n";
oss << "spFeatureCounts_: size = " << spFeatureCounts_.size() << "\n[";
for (double c : spFeatureCounts_) oss << c << " ";
oss << "]\n";
oss << "spFeatureProbs_: size = " << spFeatureProbs_.size() << "\n[";
for (double c : spFeatureProbs_) oss << c << " ";
oss << "]\n";
oss << "childCounts_: size = " << childCounts_.size() << "\n[";
for (double cc : childCounts_) oss << cc << " ";
oss << "]\n";
oss << "childProbs_: size = " << childProbs_.size() << "\n[";
for (double cp : childProbs_) oss << cp << " ";
oss << "]\n";
oss << "childOffsets_: [";
for (int co : childOffsets_) oss << co << " ";
oss << "]\n";
oss << "---------------------\n";
return oss.str();
}
private:
// --------------------------------------
// MEMBERS
// --------------------------------------
int superParent_; // which feature is the single super-parent
int nFeatures_;
int statesClass_;
std::vector<int> states_; // [states_feat0, ..., states_feat(N-1)] (class not included in this array)
// Class counts
std::vector<double> classCounts_; // [c], accumulative
std::vector<double> classPriors_; // [c], after normalization
// For p(x_sp = spVal | c)
std::vector<double> spFeatureCounts_; // [spVal * statesClass_ + c]
std::vector<double> spFeatureProbs_; // same shape, after normalization
// For p(x_child = childVal | x_sp = spVal, c)
// childCounts_ is big enough to hold all child features except sp:
// For each child f, we store childOffsets_[f] as the start index, then
// childVal, spVal, c => the data.
std::vector<double> childCounts_;
std::vector<double> childProbs_;
std::vector<int> childOffsets_;
MatrixState matrixState_;
double alpha_ = 1.0;
double initializer_; // for numerical stability
};
} // namespace platform
#endif // XSPODE_H

View File

@@ -9,14 +9,16 @@
#ifndef XAODE2_H
#define XAODE2_H
#include <vector>
#include <map>
#include <stdexcept>
#include <algorithm>
#include <numeric>
#include <iostream>
#include <string>
#include <cmath>
#include <limits>
#include <torch/torch.h>
#include <sstream>
#include <iostream>
namespace platform {
class Xaode2 {
@@ -108,32 +110,39 @@ namespace platform {
instance[nFeatures_] = y[n_instance];
addSample(instance, weights[n_instance].item<double>());
}
//alpha_ = 1 / num_instances;
// alpha_ Laplace smoothing adapted to the number of instances
alpha_ = 1.0 / static_cast<double>(num_instances);
initializer_ = std::numeric_limits<double>::max() / (nFeatures_ * nFeatures_);
computeProbabilities();
}
// Optional: print a quick summary
void show() const
std::string to_string() const
{
std::cout << "-------- Xaode.show() --------" << std::endl
std::ostringstream ostream;
ostream << "-------- Xaode.status --------" << std::endl
<< "- nFeatures = " << nFeatures_ << std::endl
<< "- statesClass = " << statesClass_ << std::endl
<< "- matrixState = " << (matrixState_ == MatrixState::COUNTS ? "COUNTS" : "PROBS") << std::endl;
std::cout << "- states: size: " << states_.size() << std::endl;
for (int s : states_) std::cout << s << " "; std::cout << std::endl;
std::cout << "- classCounts: size: " << classCounts_.size() << std::endl;
for (double cc : classCounts_) std::cout << cc << " "; std::cout << std::endl;
std::cout << "- classFeatureCounts: size: " << classFeatureCounts_.size() << std::endl;
for (double cfc : classFeatureCounts_) std::cout << cfc << " "; std::cout << std::endl;
std::cout << "- classFeatureProbs: size: " << classFeatureProbs_.size() << std::endl;
for (double cfp : classFeatureProbs_) std::cout << cfp << " "; std::cout << std::endl;
std::cout << "- featureClassOffset: size: " << featureClassOffset_.size() << std::endl;
for (int f : featureClassOffset_) std::cout << f << " "; std::cout << std::endl;
std::cout << "- pairOffset_: size: " << pairOffset_.size() << std::endl;
for (int p : pairOffset_) std::cout << p << " "; std::cout << std::endl;
std::cout << "- data: size: " << data_.size() << std::endl;
for (double d : data_) std::cout << d << " "; std::cout << std::endl;
std::cout << "--------------------------------" << std::endl;
ostream << "- states: size: " << states_.size() << std::endl;
for (int s : states_) ostream << s << " "; ostream << std::endl;
ostream << "- classCounts: size: " << classCounts_.size() << std::endl;
for (double cc : classCounts_) ostream << cc << " "; ostream << std::endl;
ostream << "- classPriors: size: " << classPriors_.size() << std::endl;
for (double cp : classPriors_) ostream << cp << " "; ostream << std::endl;
ostream << "- classFeatureCounts: size: " << classFeatureCounts_.size() << std::endl;
for (double cfc : classFeatureCounts_) ostream << cfc << " "; ostream << std::endl;
ostream << "- classFeatureProbs: size: " << classFeatureProbs_.size() << std::endl;
for (double cfp : classFeatureProbs_) ostream << cfp << " "; ostream << std::endl;
ostream << "- featureClassOffset: size: " << featureClassOffset_.size() << std::endl;
for (int f : featureClassOffset_) ostream << f << " "; ostream << std::endl;
ostream << "- pairOffset_: size: " << pairOffset_.size() << std::endl;
for (int p : pairOffset_) ostream << p << " "; ostream << std::endl;
ostream << "- data: size: " << data_.size() << std::endl;
for (double d : data_) ostream << d << " "; ostream << std::endl;
ostream << "- dataOpp: size: " << dataOpp_.size() << std::endl;
for (double d : dataOpp_) ostream << d << " "; ostream << std::endl;
ostream << "--------------------------------" << std::endl;
std::string output = ostream.str();
return output;
}
// -------------------------------------------------------
// addSample (only in COUNTS mode)
@@ -148,18 +157,7 @@ namespace platform {
// (B) increment featureclass counts => for p(x_i|c)
// (C) increment pair (superparent= i, child= j) counts => data_
//
// if (matrixState_ != MatrixState::COUNTS) {
// throw std::logic_error("addSample: not in COUNTS mode.");
// }
// if (static_cast<int>(instance.size()) != nFeatures_ + 1) {
// throw std::invalid_argument("addSample: instance.size() must be nFeatures_ + 1.");
// }
int c = instance.back();
// if (c < 0 || c >= statesClass_) {
// throw std::out_of_range("addSample: class index out of range.");
// }
if (weight <= 0.0) {
return;
}
@@ -168,17 +166,17 @@ namespace platform {
// (B,C)
// We'll store raw counts now and turn them into p(child| c, superparent) later.
int idx, fcIndex, si, sj, i_offset;
for (int i = 0; i < nFeatures_; ++i) {
si = instance[i];
int idx, fcIndex, sp, sc, i_offset;
for (int parent = 0; parent < nFeatures_; ++parent) {
sp = instance[parent];
// (B) increment featureclass counts => for p(x_i|c)
fcIndex = (featureClassOffset_[i] + si) * statesClass_ + c;
fcIndex = (featureClassOffset_[parent] + sp) * statesClass_ + c;
classFeatureCounts_[fcIndex] += weight;
// (C) increment pair (superparent= i, child= j) counts => data_
i_offset = pairOffset_[featureClassOffset_[i] + si];
for (int j = 0; j < i; ++j) {
sj = instance[j];
idx = (i_offset + featureClassOffset_[j] + sj) * statesClass_ + c;
i_offset = pairOffset_[featureClassOffset_[parent] + sp];
for (int child = 0; child < parent; ++child) {
sc = instance[child];
idx = (i_offset + featureClassOffset_[child] + sc) * statesClass_ + c;
data_[idx] += weight;
}
}
@@ -207,36 +205,26 @@ namespace platform {
}
} else {
for (int c = 0; c < statesClass_; ++c) {
classPriors_[c] = classCounts_[c] / totalCount;
classPriors_[c] = (classCounts_[c] + alpha_) / (totalCount + alpha_ * statesClass_);
}
}
// (2) p(x_i=si | c) => classFeatureProbs_
int idx, sf;
double denom, countVal, p;
double denom;
for (int feature = 0; feature < nFeatures_; ++feature) {
sf = states_[feature];
for (int c = 0; c < statesClass_; ++c) {
denom = classCounts_[c] * sf;
if (denom <= 0.0) {
// fallback => uniform
for (int sf_value = 0; sf_value < sf; ++sf_value) {
idx = (featureClassOffset_[feature] + sf_value) * statesClass_ + c;
classFeatureProbs_[idx] = 1.0 / sf;
}
} else {
for (int sf_value = 0; sf_value < sf; ++sf_value) {
idx = (featureClassOffset_[feature] + sf_value) * statesClass_ + c;
countVal = classFeatureCounts_[idx];
p = ((countVal + alpha_ / (statesClass_ * states_[feature])) / (totalCount + alpha_));
classFeatureProbs_[idx] = p;
}
denom = classCounts_[c] + alpha_ * sf;
for (int sf_value = 0; sf_value < sf; ++sf_value) {
idx = (featureClassOffset_[feature] + sf_value) * statesClass_ + c;
classFeatureProbs_[idx] = (classFeatureCounts_[idx] + alpha_) / denom;
}
}
}
// getCountFromTable(int classVal, int pIndex, int childIndex)
// (3) p(x_c=sc | c, x_p=sp) => data_(parent,sp,child,sc,c)
// (3) p(x_p=sp | c, x_c=sc) => dataOpp_(child,sc,parent,sp,c)
// C(x_c, x_p, c) + alpha_/Card(xp)
// C(x_c, x_p, c) + alpha_
// P(x_p | x_c, c) = -----------------------------------
// C(x_c, c) + alpha_
double pcc_count, pc_count, cc_count;
@@ -260,10 +248,10 @@ namespace platform {
// Child, Class count
cc_count = classFeatureCounts_[part2_class + c];
// p(x_c=sc | c, x_p=sp)
conditionalProb = (pcc_count + alpha_ / states_[parent]) / (cc_count + alpha_);
conditionalProb = (pcc_count + alpha_) / (pc_count + alpha_ * states_[child]);
data_[idx] = conditionalProb;
// p(x_p=sp | c, x_c=sc)
oppositeCondProb = (pcc_count + alpha_ / states_[child]) / (pc_count + alpha_);
oppositeCondProb = (pcc_count + alpha_) / (cc_count + alpha_ * states_[parent]);
dataOpp_[idx] = oppositeCondProb;
}
}
@@ -288,7 +276,10 @@ namespace platform {
{
// accumulates posterior probabilities for each class
auto probs = std::vector<double>(statesClass_);
auto spodeProbs = std::vector<double>(statesClass_);
auto spodeProbs = std::vector<double>(statesClass_, 0.0);
if (std::find(active_parents.begin(), active_parents.end(), parent) == active_parents.end()) {
return spodeProbs;
}
// Initialize the probabilities with the feature|class probabilities x class priors
int localOffset;
int sp = instance[parent];
@@ -297,21 +288,27 @@ namespace platform {
spodeProbs[c] = classFeatureProbs_[localOffset + c] * classPriors_[c] * initializer_;
}
int idx, base, sc, parent_offset;
sp = instance[parent];
parent_offset = pairOffset_[featureClassOffset_[parent] + sp];
for (int child = 0; child < nFeatures_; ++child) {
if (child == parent) {
continue;
}
sc = instance[child];
base = (parent_offset + featureClassOffset_[child] + sc) * statesClass_;
if (child > parent) {
parent_offset = pairOffset_[featureClassOffset_[child] + sc];
base = (parent_offset + featureClassOffset_[parent] + sp) * statesClass_;
} else {
parent_offset = pairOffset_[featureClassOffset_[parent] + sp];
base = (parent_offset + featureClassOffset_[child] + sc) * statesClass_;
}
for (int c = 0; c < statesClass_; ++c) {
/*
* The probability P(xc|xp,c) is stored in dataOpp_, and
* the probability P(xp|xc,c) is stored in data_
*/
idx = base + c;
spodeProbs[c] *= child < parent ? dataOpp_[idx] : data_[idx];
double factor = child > parent ? dataOpp_[idx] : data_[idx];
// double factor = data_[idx];
spodeProbs[c] *= factor;
}
}
// Normalize the probabilities
@@ -347,7 +344,7 @@ namespace platform {
}
localOffset = (featureClassOffset_[feature] + instance[feature]) * statesClass_;
for (int c = 0; c < statesClass_; ++c) {
spodeProbs[feature][c] = classFeatureProbs_[localOffset + c] * classPriors_[c];
spodeProbs[feature][c] = classFeatureProbs_[localOffset + c] * classPriors_[c] * initializer_;
}
}
int idx, base, sp, sc, parent_offset;
@@ -360,15 +357,23 @@ namespace platform {
parent_offset = pairOffset_[featureClassOffset_[parent] + sp];
for (int child = 0; child < parent; ++child) {
sc = instance[child];
base = (parent_offset + featureClassOffset_[child] + sc) * statesClass_;
if (child > parent) {
parent_offset = pairOffset_[featureClassOffset_[child] + sc];
base = (parent_offset + featureClassOffset_[parent] + sp) * statesClass_;
} else {
parent_offset = pairOffset_[featureClassOffset_[parent] + sp];
base = (parent_offset + featureClassOffset_[child] + sc) * statesClass_;
}
for (int c = 0; c < statesClass_; ++c) {
/*
* The probability P(xc|xp,c) is stored in dataOpp_, and
* the probability P(xp|xc,c) is stored in data_
*/
idx = base + c;
spodeProbs[child][c] *= data_[idx];
spodeProbs[parent][c] *= dataOpp_[idx];
double factor_child = child > parent ? data_[idx] : dataOpp_[idx];
double factor_parent = child > parent ? dataOpp_[idx] : data_[idx];
spodeProbs[child][c] *= factor_child;
spodeProbs[parent][c] *= factor_parent;
}
}
}
@@ -456,8 +461,8 @@ namespace platform {
MatrixState matrixState_;
double alpha_ = 1.0;
double initializer_ = std::numeric_limits<double>::max();
double alpha_ = 1.0; // Laplace smoothing
double initializer_ = 1.0;
std::vector<int> active_parents;
};
}