Hugin C++ API 6.1

Contents

Introduction

The Hugin C++ API 6.1 consists of the header file and the static library. The names under the supported platforms can be found in the table blow.
Platform Header Library
Solaris/Linux hugin hugincpp.a
Win32 hugin hugincpp.lib

Solaris/Linux users please note, that the Hugin C++ API is not compatible with gcc3.

These pages are meant as a help for developers programming against the Hugin C++ API 6.1. Short descriptions can be found for all classes and their members. However, additional information might be relevant for different tasks. In such cases, the Hugin API 6.0 reference manual will be a good place to look. It contains detailed documentation of the Hugin C API 6.1 which is currently the basis of the C++ API 6.1. The Hugin API 6.1 reference manual can be downloaded from Hugin Expert A/S - Documentation.

General Information

The Hugin C++ API 6.1 contains a high performance inference engine that can be used as the core of knowledge based systems built using Bayesian belief networks or influence diagrams. A knowledge engineer can build knowledge bases that model the application domain, using probabilistic descriptions of causal relationships in the domain. Given this description, the Hugin inference engine can perform fast and accurate reasoning.
The Hugin C++ API 6.1 is organized as an ordinary C++ static library. Classes and member methods are provided for tasks such as construction of networks, performing inference, etc. The Hugin C++ API 6.1 also provides an exception based mechanism for handling errors. As something new, the Hugin C++ API 6.1 contains facilities for constructing and working with Object Oriented Bayesian Networks.

Classes and Constants

The Hugin C++ API uses various classes for representing domains, nodes, tables, cliques, junction trees, and exceptions. A set of enumeration types is used to represent triangulation methods, node categories, etc. A summary of classes and enumeration types is given below. The classes and types are (sorted by category):

ClassCollection Classes

ClassCollection

NetworkModel Classes

NetworkModel
Class
Domain

Node Classes

BooleanDCNode
BooleanDDNode
ContinuousChanceNode
DiscreteChanceNode
DiscreteDecisionNode
InstanceNode
IntervalDCNode
IntervalDDNode
LabelledDCNode
LabelledDDNode
Node
NumberedDCNode
NumberedDDNode
UtilityNode

Junction Tree Classes

Clique
JunctionTree

Table Classes

Table

Model Classes

Model

Expression Classes

AbsExpression
AddExpression
AndExpression
BooleanExpression
CeilExpression
CompositeExpression
ConstantExpression
DivideExpression
EqualsExpression
ExpExpression
Expression
FloorExpression
GreaterThanExpression
GreaterThanOrEqualsExpression
IfExpression
LabelExpression
LessThanExpression
LessThanOrEqualsExpression
LogExpression
Log2Expression
Log10Expression
MaxExpression
MinExpression
ModExpression
MultiplyExpression
SubtractExpression
NegateExpression
NodeExpression
NotEqualsExpression
NotExpression
NumberExpression
OrExpression
PowerExpression
SqrtExpression
SinExpression
SinhExpression
CosExpression
CoshExpression
TanExpression
TanhExpression

Distribution Classes

BetaDistribution
BinomialDistribution
NegativeBinomialDistribution
DistributionDistribution
ExponentialDistribution
GammaDistribution
GeometricDistribution
NormalDistribution
PoissonDistribution
UniformDistribution
WeibullDistribution

List Classes

CliqueList
ExpressionList
JunctionTreeList
NodeList
ClassList

Parser Classes

ParseListener
NetParseListener
ClassParseListener
DefaultParseListener

Attribute Classes

Attribute

Enumeration Types

Category
Constraint
Endian
Equilibrium
EvidenceMode
Kind
TriangulationMethod

Errors

Several types of errors can occur when using a class or member method from the Hugin C++ API. These errors can be the result of error in the application program, of running out of memory, of corrupted data files, etc.
As a general principle, the Hugin C++ API will try to recover from any error as well as possible. The API will then inform the application program of the problem and take no further action. It is then up to the application program to take the appropriate action.
When a member method fails, the data structures will always be left in a consistent state. Moreover, unless otherwise stated explicitly for a particular method, this state can be assumed identical to the state before the failed API call.
To communicate errors to the user of the Hugin C++ API, the API defines a set of exception classes. All exception classes are subclasses of ExceptionHugin.

Examples

The following examples describe how the Hugin C++ API can be used to manipulate Bayesian networks and influence diagrams, and to perform the two different kind of learning in the networks.

Example 1: Load And Propagate

This first example is concerned with loading a Bayesian network or an influence diagram. Once the Bayesian network or influence diagram has been loaded the corresponding domain is triangulated using the minimum fill-in-weight heuristic and the compilation process is completed. Next, the members of each clique of the junction tree(s) are printed on standard output. Finally, a propagation of evidence is performed and the resulting posterior marginals are printed on standard output.
#include < vector >
#include < iostream >
#include < cstdio >
#include "hugin"

using namespace HAPI;
using namespace std;

class LAP {
public:
  LAP(const string& fileName);
  void printJunctionTrees(JunctionTreeList& list);
  void printNodeMarginals(Domain *domain);
  void printNodes(NodeList& list);
};

LAP::LAP(const string& fileName)
{
  try
  {
    string netFileName = fileName + ".net";
    Domain *domain = new Domain(netFileName, NULL);
    string logFileName = fileName + ".log";
    FILE *logFile = fopen(logFileName.c_str(), "w");

    domain->setLogFile(logFile);
    domain->triangulate(H_TM_FILL_IN_WEIGHT);
    domain->compile();
    printJunctionTrees(domain->getJunctionTrees());
    domain->propagate(H_EQUILIBRIUM_SUM,
          H_EVIDENCE_MODE_NORMAL);
    printNodeMarginals(domain);
    fclose(logFile);

    string hkbFileName = fileName + ".hkb";
    domain->save(hkbFileName, H_ENDIAN_BIG);      
  } 
  catch (ExceptionHugin *e) {
    cerr << e->what() << endl;
  }
}

/**
   * Print the cliques of the junction tree(s).
   */
void LAP::printJunctionTrees(JunctionTreeList& list)
{
  try 
  {
    JunctionTreeList::iterator jtit = list.begin();
    CliqueList clist;
    CliqueList::iterator cliqueit = NULL;
    cerr << "Cliques : ";
    while (list.end() != jtit) 
    {
      clist = (*jtit)->getCliques();
      cliqueit = clist.begin();
      while (clist.end() != cliqueit) 
      {
        printNodes((*cliqueit)->getMembers());
        cliqueit++;
      }
      jtit++;
    }
    cout << endl;
  } 
  catch (ExceptionHugin *e) {
    cerr << e->what() << endl;
  }
}

/**
   * Print the marginal distribution of each variable in the domain.
   */
void LAP::printNodeMarginals(Domain *domain)
{
  try 
  {
    Node *node;
    NodeList nlist = domain->getNodes();
    NodeList::iterator nit = nlist.begin();
    while(nlist.end() != nit) 
    {
      node = *nit;
      cout << node->getLabel() << "(" 
           << node->getName() << ")" << endl;
      if (node->getCategory()==H_CATEGORY_CHANCE)
      {
        if (node->getKind()==H_KIND_CONTINUOUS)
        {
          cout << "-Mean     : " 
               << ((ContinuousChanceNode*)node)->getMean() << endl;
          cout << "-Variance : " 
               <<  ((ContinuousChanceNode*)node)->getVariance() 
               << endl;
        }
  else
          if (node->getKind()==H_KIND_DISCRETE)
          {
            for (int i=0;i<((DiscreteChanceNode*)node)->getNumberOfStates();i++)
            {
              cout << "-" 
                   << ((DiscreteChanceNode*)node)->getStateLabel(i)
                   << " " 
                   << ((DiscreteChanceNode*)node)->getBelief(i) << endl;
            }
          }
      }
      else
        if (node->getCategory()==H_CATEGORY_DECISION)
        {
          for (int i=0;i<((DiscreteDecisionNode*)node)->getNumberOfStates();i++)
          {
            cout << "-" 
                 << ((DiscreteDecisionNode*)node)->getStateLabel(i) 
                 << " " 
                 << ((DiscreteDecisionNode*)node)->getExpectedUtility(i) << endl;
          }
        }
      nit++;
    }
  } 
  catch (ExceptionHugin *e) {
    cout << e->what() << endl;
  }
}
 
/**
   * Print the name of each node in the list.
   */
void LAP::printNodes(NodeList& list)
{
  try 
  {
    NodeList::iterator nit = list.begin();
 
    while (list.end() != nit) 
    {
      cout << (*nit)->getName() + " ";
      nit++;
    }
    cout << endl;
  } 
  catch (ExceptionHugin *e) 
  {
    cout << e->what() << endl;
  }
}
 
 
/**
 * Load a Hugin net file and perform a single propagation of
 * evidence. Print the results.
 */
int main (int argc, char *argv[])
{
  new LAP(string(argv[1]));
  return 0;
}

Example 2: Build And Propagate

The second example describes how a Bayesian network can be constructed using the Hugin C++ API. The Bayesian network constructed consists of three numbered nodes. Two of the nodes take on values 0, 1, and 2. The third node is the sum of the two other nodes. Once the Bayesian network is constructed the network is saved to a net specification file and an initial propagation is performed. Finally, the marginals of the nodes are printed on standard output.
#include < vector >
#include < iostream >
 
#include "hugin"
 
using namespace HAPI;
using namespace std;
 
class BAP {
public:
  BAP::BAP();
protected:
  void propagateEvidenceInNetwork();
 
  void printNodeMarginals(Domain *d);
 
  NumberedDCNode* constructNDC(char *label, char *name, int n);
 
  void buildStructure(NumberedDCNode *A, NumberedDCNode *B,
          NumberedDCNode *C);
 
  void buildExpressionForC(NumberedDCNode *A,
         NumberedDCNode *B,
         NumberedDCNode *C);
 
  void specifyDistributions(NumberedDCNode *A,
          NumberedDCNode *B);
 
  void buildNetwork();
  
  Domain *domain;
};
 
/**
   * Build a Bayesian network and propagate evidence.
   */
BAP::BAP() 
{
  try 
  {
    domain = new Domain();
      
    buildNetwork();
      
    domain->writeNet("builddomain.net");
    domain->compile();
      
    propagateEvidenceInNetwork();
  } catch(ExceptionHugin *e) {
    cout << e->what() << endl;
  }
}
 
/**
   * Propagate evidence in domain.
   */
void BAP::propagateEvidenceInNetwork()
{
  try 
  {
    domain->propagate(H_EQUILIBRIUM_SUM,
          H_EVIDENCE_MODE_NORMAL);
      
    printNodeMarginals(domain);
  } catch (ExceptionHugin *e) {
    cout << e->what() << endl;
  }
}
  
/**
   * print node marginals.
   */
void BAP::printNodeMarginals(Domain *d)
{
  try 
  {
    NodeList nlist = domain->getNodes();
    NodeList::iterator nit = nlist.begin();
    DiscreteChanceNode *node;
      
    while(nlist.end() != nit) 
    {
      node = (DiscreteChanceNode*) *nit;
      cout << node->getLabel() << endl;
        
      for (int i=0;i<((DiscreteChanceNode*)node)->getNumberOfStates(); i++)
        cout << "-" << node->getStateLabel(i) 
             << " " << node->getBelief(i) << endl;
      nit++;
    }
  } catch (ExceptionHugin *e) {
    cout << e->what() << endl;
  }
}
 
/**
   * Construct numbered discrete chance node.
   */
NumberedDCNode* BAP::constructNDC(char *label,
         char *name,
         int n)
{
  try 
  {
    NumberedDCNode *node = new NumberedDCNode(domain);
 
    node->setNumberOfStates(n);
 
    for (int i=0;isetStateValue(i, i);
 
    char s[10];
    for (i=0;isetStateLabel(i, s);
    }
 
    node->setLabel(label);
    node->setName(name);
 
    return node;
  } 
  catch (ExceptionHugin *e) {
    cout << e->what() << endl;
  }
  return NULL;
}
 
/**
   * Build the structure.
   */
void BAP::buildStructure(NumberedDCNode *A,
       NumberedDCNode *B,
       NumberedDCNode *C)
{
  try 
  {
    C->addParent(A);
    C->addParent(B);
 
    A->setPosition(100, 200);
    B->setPosition(200, 200);
    C->setPosition(150, 50);
  } 
  catch (ExceptionHugin *e) {
    cout << e->what() << endl;
  }
}
 
/**
   * Expression for C
   */
void BAP::buildExpressionForC(NumberedDCNode *A,
            NumberedDCNode *B,
            NumberedDCNode *C)
{
  try 
  {
    NodeList modelNodes;
      
    Model *model = new Model(C, modelNodes);
 
    NodeExpression *exprA = new NodeExpression(A);
    NodeExpression *exprB = new NodeExpression(B);
    
    AddExpression *exprC = new AddExpression(exprA, exprB);
 
    model->setExpression(0, exprC);
  } 
  catch (ExceptionHugin *e) {
    cout << e->what() << endl;
  }
}
 
/**
   * Specify the prior distribution of A and B.
   */
void BAP::specifyDistributions(NumberedDCNode *A,
             NumberedDCNode *B)
{
  try 
  {
    Table *table;
 
    table = A->getTable();
 
    std::vector *data = new std::vector(3);
 
    (*data)[0] = 0.1;
    (*data)[1] = 0.2;
    (*data)[2] = 0.7;
 
    for (int i=0; i<3; i++)
      table->getData()[i] = (*data)[i];
 
    table = B->getTable();
    table->getData()[0] = 0.2;
    table->getData()[1] = 0.2;
    table->getData()[2] = 0.6;
  } 
  catch (ExceptionHugin *e) {
    cout << e->what() << endl;
  }
}
 
/**
   * Build the Bayesian network.
   */
void BAP::buildNetwork() 
{
  try 
  {
    domain->setNodeSize(50,30);
 
    NumberedDCNode *A = constructNDC("A", "A", 3);
    NumberedDCNode *B = constructNDC("B", "B", 3);
 
    NumberedDCNode *C = constructNDC("C", "C", 5);
 
    buildStructure(A,B,C);
 
    buildExpressionForC(A,B,C);
 
    specifyDistributions(A, B);
  } 
  catch (ExceptionHugin *e) {
    cout << e->what() << endl;
  }
}
 
/**
 * Build a Bayesian network and perform a propagation of
 * evidence. Print the results.
 */
int main(int argc, char *argv[])
{
  new BAP();
  return 0;
}

Example 3: Sequential Learning

Example three presents a skeleton for sequential learning. Sequential learning, or adaptation, is an update process applied to the conditional probability tables. After a network has been built, sequential learning can be applied during operation in order to maintain the correspondence between the model (conditional probability tables) and the real-world domain. After the network is loaded in Hugin, the learning parameters are specified. Then follows the build-up and entering of cases, and finally, the tables are updated and node marginals are printed.
#include < vector >
#include < string >
#include < cstdio >
#include < iostream >
#include < exception >
 
#include "hugin"
 
using namespace HAPI;
using namespace std;
 
class Adapt {
public:
  Adapt(const string &fileName);
 
private:
  void specifyLearningParameters(Domain *d);
  void printLearningParameters(Domain *d);
  void enterCase(Domain *d);
  void printCase(Domain *d);
  void printNodeMarginals(Domain *d);
};
 
 
int main (int argc, char *argv[]) {
 
  try {
    new Adapt(string(argv[1]));
  }
  catch (exception e) {
    cerr << e.what() << endl;
    return -1;
  }
  catch (...) {
    cerr << "caught something..." << endl;
    return -2;
  }
 
  return 0;
}
 
 
 
Adapt::Adapt(const string &fileName) {
  Domain *d;
 
  try {
    string netFileName = fileName + ".net";
    d = new Domain(netFileName, NULL);
 
    string logFileName = fileName + ".log";
    FILE *logFile = fopen(logFileName.c_str(), "w");
    d->setLogFile(logFile);
 
    d->compile();
 
    specifyLearningParameters(d);
    printLearningParameters(d);
 
    enterCase(d);
 
    printCase(d);
 
    d->adapt();
 
    d->initialize();
 
    d->propagate();
 
    printNodeMarginals(d);
 
    d->writeNet("q.net");
  }
  catch (ExceptionHugin eh) {
    cerr << "Caught ExceptionHugin in Adapt::Adapt()." << endl;
    cerr << eh.what() << endl;
    return;
  }
  catch (exception e) {
    cerr << "Caught general exception in Adapt::Adapt()." << endl;
    cerr << e.what() << endl;
    return;
  }
}
 
 
void Adapt::specifyLearningParameters(Domain *d) {
  NodeList nl;
  NodeList::iterator nlIter, nlEnd;
  DiscreteChanceNode *node;
  Table *table;
 
  vector data;
 
  try {
    nl = d->getNodes();
    nlIter = nl.begin();
    nlEnd = nl.end();
 
    while (nlIter != nlEnd) {
      node = dynamic_cast (*nlIter);
      table = node->getExperienceTable();
 
      data.clear();
      data.insert(data.end(), table->getSize(), 1);
 
      table->setData(data);
 
      nlIter++;
    }
  }
  catch (ExceptionHugin eh) {
    cerr << "Caught ExceptionHugin" << endl;
    cerr << "Filling experience tables in Adapt::specifyLearningParameters()" 
         << endl;
    cerr << eh.what() << endl;
    throw eh;
  }
  catch (exception e) {
    cerr << "Caught general exception" << endl;
    cerr << "Filling experience tables in Adapt::specifyLearningParameters()" 
         << endl;
    cerr << e.what() << endl;
    throw e;
  }
 
  try {
    nlIter = nl.begin();
    nlEnd = nl.end();
 
    while (nlIter != nlEnd) {
      node = dynamic_cast (*nlIter);
      table = node->getFadingTable();
 
      data.clear();
      data.insert(data.end(), table->getSize(), 1);
 
      table->setData(data);
 
      nlIter++;
    }
  }
  catch (ExceptionHugin eh) {
    cerr << "Caught ExceptionHugin in Adapt::specifyLearningParameters()" 
         << endl;
    cerr << "Filling fading tables in Adapt::specifyLearningParameters()" 
         << endl;
    cerr << eh.what() << endl;
    throw eh;
 }

 catch (exception e) {
    cerr << "General exception in Adapt::specifyLearningParameters()" 
         << endl;
    cerr << "Filling fading tables in Adapt::specifyLearningParameters()" 
         << endl;
    cerr << e.what() << endl;
    throw e;
  }
 
}
 
 
void Adapt::printLearningParameters(Domain *d) {
 
  NodeList nl;
  NodeList::iterator nlIter, nlEnd;
  DiscreteChanceNode *dcNode;
  Table *table;
 
  try {
    nl = d->getNodes();
    nlIter = nl.begin();
    nlEnd = nl.end();
 
    while (nlIter != nlEnd) {
      dcNode = dynamic_cast (*nlIter);
      cout << dcNode->getLabel() << " (" << dcNode->getName() << "): " << endl;
 
      cout << "   ";
      if (dcNode->hasExperienceTable()) {
        table = dcNode->getExperienceTable();
        
        int i, tblSize;
        tblSize = table->getSize();
        for (i = 0; i < tblSize; i++) {
          cout << table->getData()[i] << " ";
        }
        cout << endl;
      }
      else {
        cout << "No experience table" << endl;
      }
 
      cout << "   ";
      if (dcNode->hasFadingTable()) {
        table = dcNode->getFadingTable();
        
        int i, tblSize;
        tblSize = table->getSize();
        for (i = 0; i < tblSize; i++) {
          cout << table->getData()[i] << " ";
        }
        cout << endl;
      }
      else {
        cout << "No fading table" << endl;
      }
 
      nlIter++;
    }
  }
  catch (ExceptionHugin eh) {
    cerr << "Caught ExceptionHugin in Adapt::printLearningParameters()." << endl;
    cerr << eh.what() << endl;
  }
  catch (exception e) {
    cerr << "Caught general exception in Adapt::printLearningParameters()." 
         << endl;
    cerr << e.what() << endl;
  }
}
 
 
void Adapt::enterCase(Domain *d) {
  DiscreteChanceNode *dcNode;
 
  NodeList::iterator nlIter;
  NodeList::iterator nlEnd;
  NodeList nl;
  try {
    nl = d->getNodes();
    nlIter = nl.begin();
    nlEnd = nl.end();
 
    while (nlIter != nlEnd) {
      dcNode = dynamic_cast (*nlIter);
      dcNode->selectState(0);
 
      nlIter++;
    }
 
    dcNode = dynamic_cast (nl[1]));
    dcNode->retractFindings();
  }
  catch (ExceptionHugin eh) {
    cerr << "Caught ExceptionHugin in Adapt::enterCase()" << endl;
    cerr << eh.what() << endl;
    throw eh;
  }
  catch (exception e) {
    cerr << "Caught general exception in Adapt::enterCase()" << endl;
    cerr << e.what() << endl;
    throw e;
  }
}

void Adapt::printCase(Domain *d) {
  DiscreteChanceNode *dcNode;
  NodeList::iterator nlIter;
  NodeList::iterator nlEnd;
  NodeList nl;
  try {
    nl = d->getNodes();
    nlIter = nl.begin();
    nlEnd = nl.end();
 
    while (nlIter != nlEnd) {
      dcNode = dynamic_cast (*nlIter);
      cout << "(" + dcNode->getName() + ",";
      if (dcNode->isEvidenceEntered())
        cout << " evidence entered) ";
      else
        cout << " evidence not entered) ";
 
      nlIter++;
    }
    cout << endl;
 
  }
  catch (ExceptionHugin eh) {
    cerr << "Caught ExceptionHugin in Adapt::printCase()" << endl;
    cerr << eh.what() << endl;
    throw eh;
  }
  catch (exception e) {
    cerr << "Caught general exception in Adapt::printCase()" << endl;
    cerr << e.what() << endl;
    throw e;
  }
}
 
 
void Adapt::printNodeMarginals(Domain *d) {
  
  DiscreteChanceNode *dcNode;
  NodeList::iterator nlIter;
  NodeList::iterator nlEnd;
  NodeList nl;
  int i, nStates;
 
  try {
    nl = d->getNodes();
    nlIter = nl.begin();
    nlEnd = nl.end();
 
    while (nlIter != nlEnd) {
      dcNode = dynamic_cast (*nlIter);
      nStates = dcNode->getNumberOfStates();
 
      cout << dcNode->getLabel() + " (" + dcNode->getName() + ")" << endl;
 
      string res;
      for (i = 0; i < nStates; i++) {
        cout << " - " << dcNode->getStateLabel(i) 
           << ": " << dcNode->getBelief(i) << endl;
      }
 
      nlIter++;
    }
  }
  catch (ExceptionHugin eh) {
    cerr << "Caught ExceptionHugin in Adapt::printNodeMarginals()" << endl;
    cerr << eh.what() << endl;
    throw eh;
  }
  catch (exception e) {
    cerr << "Caught general exception in Adapt::printNodeMarginals()" << endl;
    cerr << e.what() << endl;
    throw e;
  }
}

Example 4: Parametric Learning

The fourth example shows how the Hugin C++ API can be used for parametric learning in a Bayesian network. The network is loaded from disk, and the parameters controlling the learning process are loaded. Then, the conditional probability tables are computed from data using the EM algorithm. Finally, the node marginals are printed.
#include < vector >
#include < string >
#include < cstdio >
#include < iostream >
#include < exception >
 
#include "hugin"
 
using namespace HAPI;
using namespace std;
 
class EM {
public:
  EM(const string &fileName);
 
private:
  void specifyLearningParameters(Domain *d);
  void printLearningParameters(Domain *d);
  void loadCases(Domain *d);
  void printCases(Domain *d);
  void printNodeMarginals(Domain *d);
};
 
int main (int argc, char *argv[]) {
  try {
    new EM(string(argv[1]));
  }
  catch (exception e) {
    cerr << e.what() << endl;
    return -1;
  }
  catch (...) {
    cerr << "caught something..." << endl;
    return -2;
  }
  return 0;
}
 
 
EM::EM(const string &fileName) {
  Domain *d;
  try {
    string netFileName = fileName + ".net";
    d = new Domain(netFileName, NULL);
 
    string logFileName = fileName + ".log";
    FILE *logFile = fopen(logFileName.c_str(), "w");
    d->setLogFile(logFile);
 
    d->compile();
 
    specifyLearningParameters(d);
    printLearningParameters(d);
 
    loadCases(d);
    printCases(d);
 
    d->learnTables();
    d->setNumberOfCases(0); // ??
    cout << "Log likelihood: " << d->getLogLikelihood() << endl;
 
    d->initialize();
 
    d->propagate();
 
    printNodeMarginals(d);
 
    d->writeNet("q.net");
  }
  catch (ExceptionHugin eh) {
    cerr << "Caught ExceptionHugin in EM::EM()." << endl;
    cerr << eh.what() << endl;
    return;
  }
  catch (exception e) {
    cerr << "Caught general exception in EM::EM()." << endl;
    cerr << e.what() << endl;
    return;
  }
}
 
 
void EM::specifyLearningParameters(Domain *d) {
  NodeList nl;
  NodeList::iterator nlIter, nlEnd;
  DiscreteChanceNode *node;
  Table *table;
 
  vector data;
 
  try {
    nl = d->getNodes();
    nlIter = nl.begin();
    nlEnd = nl.end();
 
    while (nlIter != nlEnd) {
      node = dynamic_cast (*nlIter);
      table = node->getExperienceTable();
 
      data.clear();
      data.insert(data.end(), table->getSize(), 1);
 
      table->setData(data);
 
      nlIter++;
    }
 
    d->setLogLikelihoodTolerance(0.000001);
    d->setMaxNumberOfEMIterations(1000);
  }
  catch (ExceptionHugin eh) {
    cerr << "Caught ExceptionHugin" << endl;
    cerr << "Filling experience tables in EM::specifyLearningParameters(Domain *d)" 
         << endl;
    cerr << eh.what() << endl;
    throw eh;
  }
  catch (exception e) {
    cerr << "Caught general exception" << endl;
    cerr << "Filling experience tables in EM::specifyLearningParameters(Domain *d)"
         << endl;
    cerr << e.what() << endl;
    throw e;
  }
}
 
 
 
void EM::printLearningParameters(Domain *d) {
  NodeList nl;
  NodeList::iterator nlIter, nlEnd;
  DiscreteChanceNode *dcNode;
  Table *table;
 
  try {
    nl = d->getNodes();
    nlIter = nl.begin();
    nlEnd = nl.end();
 
    while (nlIter != nlEnd) {
      dcNode = dynamic_cast (*nlIter);
 
      cout << dcNode->getLabel() << " (" << dcNode->getName() << "): " << endl;
 
      cout << "   ";
      if (dcNode->hasExperienceTable()) {
        table = dcNode->getExperienceTable();
        
        int i, tblSize;
        tblSize = table->getSize();
        for (i = 0; i < tblSize; i++) {
          cout << table->getData()[i] << " ";
        }
        cout << endl;
      }
      else {
        cout << "No experience table" << endl;
      }
 
      cout << "   ";
      if (dcNode->hasFadingTable()) {
        table = dcNode->getFadingTable();
      
        int i, tblSize;
        tblSize = table->getSize();
        for (i = 0; i < tblSize; i++) {
          cout << table->getData()[i] << " ";
        }
  cout << endl;
      }
      else {
        cout << "No fading table" << endl;
      }
 
      nlIter++;
    }
 
    cout << "Log likelihood tolerance: " << d->getLogLikelihoodTolerance() << endl;
    cout << "Max EM iterations: " << d->getMaxNumberOfEMIterations() << endl;
  }
  catch (ExceptionHugin eh) {
    cerr << "Caught ExceptionHugin." << endl;
    cerr << eh.what() << endl;
  }
  catch (exception e) {
    cerr << "Caught general exception." << endl;
    cerr << e.what() << endl;
  }
}
 
 
void EM::loadCases(Domain *d) {
  DiscreteChanceNode *dcNode;
  int iCase;
 
  NodeList::iterator nlIter;
  NodeList::iterator nlEnd;
  NodeList nl;
  try {
    nl = d->getNodes();
    nlIter = nl.begin();
    nlEnd = nl.end();
 
    d->setNumberOfCases(0);
    iCase = d->newCase();
    cout << "Case index: " << iCase << endl;
 
    d->setCaseCount(iCase, 2.5);
 
    while (nlIter != nlEnd) {
      dcNode = dynamic_cast (*nlIter);
      dcNode->setCaseState(iCase, 0);
 
      nlIter++;
    }
 
    dcNode = dynamic_cast (nl[1]);
    dcNode->unsetCase(iCase);
  }
  catch (ExceptionHugin eh) {
    cerr << "Caught ExceptionHugin in EM::enterCase(Domain *d)" << endl;
    cerr << eh.what() << endl;
    throw eh;
  }
  catch (exception e) {
    cerr << "Caught general exception in EM::enterCase(Domain *d)" << endl;
    cerr << e.what() << endl;
    throw e;
  }
}
 
 
 
void EM::printCases(Domain *d) {
  DiscreteChanceNode *dcNode;
  NodeList::iterator nlIter;
  NodeList::iterator nlEnd;
  NodeList nl;
  try {
    nl = d->getNodes();
    nlIter = nl.begin();
    nlEnd = nl.end();
 
    int nCases = d->getNumberOfCases();
    int i;
 
    cout << "Number of cases: " << nCases << endl;
    for (i = 0; i < nCases; i++) {
      cout << "case " << i << " " << d->getCaseCount(i) << " " << endl;
 
      while (nlIter != nlEnd) {
        dcNode = dynamic_cast (*nlIter);
        cout << "(" + dcNode->getName() + ",";
        if (dcNode->caseIsSet(i))
            cout << dcNode->getCaseState(i) << ") ";
        else
            cout << "N/A) ";
 
        nlIter++;
      }
    }
    cout << endl;
  }
  catch (ExceptionHugin eh) {
    cerr << "Caught ExceptionHugin in EM::printCase(Domain *d)" << endl;
    cerr << eh.what() << endl;
    throw eh;
  }
  catch (exception e) {
    cerr << "Caught general exception in EM::printCase(Domain *d)" << endl;
    cerr << e.what() << endl;
    throw e;
  }
}
 
 
void EM::printNodeMarginals(Domain *d) {
  DiscreteChanceNode *dcNode;
  NodeList::iterator nlIter;
  NodeList::iterator nlEnd;
  NodeList nl;
  int i, nStates;
 
  try {
    nl = d->getNodes();
    nlIter = nl.begin();
    nlEnd = nl.end();
 
    while (nlIter != nlEnd) {
      dcNode = dynamic_cast (*nlIter);
      nStates = dcNode->getNumberOfStates();
 
      cout << dcNode->getLabel() + " (" + dcNode->getName() + ")" << endl;
 
      string res;
      for (i = 0; i < nStates; i++) {
        cout << " - " << dcNode->getStateLabel(i) 
             << ": " << dcNode->getBelief(i) << endl;
      }
 
      nlIter++;
    }
  }
  catch (ExceptionHugin eh) {
    cerr << "Caught ExceptionHugin in EM::printNodeMarginals(Domain *d)" << endl;
    cerr << eh.what() << endl;
    throw eh;
  }
  catch (exception e) {
    cerr << "Caught general exception in EM::printNodeMarginals(Domain *d)" 
         << endl;
    cerr << e.what() << endl;
    throw e;
  }
}

Example 5: Object Oriented Networks

The last example demonstrates the Object Oriented network facilities of the Hugin C++ API. It starts out be creating two very simple networks. Creates an instance of one network in the other. Then it uses the input and output nodes in the instance to connect the two networks, and creates a runtime domain from the class. It ends by printing the origin of all the nodes in the domain.
#include < stdio.h >

#include "hugin"

using namespace HAPI;

class ClassBuildInstance{
public:
  int test();
};

/* Build the first network. This will contain an 
   instance of the second network
*/
void buildFirst(Class* cls){
  LabelledDCNode *node1, *node2, *node3;
  
  node1=new LabelledDCNode(cls);
  node1->setName("c1_n1");
  node1->setNumberOfStates(3);
  node2=new LabelledDCNode(cls);
  node2->setName("c1_n2");
  node2->setNumberOfStates(2);
  node3=new LabelledDCNode(cls);
  node3->setName("c1_n3");
  node3->setNumberOfStates(3);

  node2->addParent(node1);
  node3->addParent(node2);
}

/* Build the second network to be instantiated in
   the first network
*/
void buildSecond(Class* cls){
  LabelledDCNode *node1, *node2, *node3;
  
  node1=new LabelledDCNode(cls);
  node1->setName("c2_n1");
  node1->setNumberOfStates(3);
  node2=new LabelledDCNode(cls);
  node2->setName("c2_n2");
  node2->setNumberOfStates(2);
  node3=new LabelledDCNode(cls);
  node3->setName("c2_n3");
  node3->setNumberOfStates(3);

  node3->addParent(node1);
  node3->addParent(node2);
  
  // make node3 output node
  node3->addToOutputs();
  // make node2 input node
  // note that only nodes with no parents can be input node
  node2->addToInputs();
}


int ClassBuildInstance::test(){
  try{
    ClassCollection* coll;
    Class* cls1, *cls2;
    ClassList *clsList;
    LabelledDCNode *node, *node2;
    InstanceNode *instance;

    // create the class collection to contain the classes
    coll=new ClassCollection();
    // create the first class in the collection
    cls1=new Class(coll);
    cls1->setName("c1");
    buildFirst(cls1);

    // create the second class in the collection
    cls2=new Class(coll);
    cls2->setName("c2");
    buildSecond(cls2);

    cerr<<"----------------------------------------\n";
    cerr<<"Testing instances\n";
    cerr<<"----------------------------------------\n";
    // create an instance of cls2 in cls1
    instance=new InstanceNode(cls1, cls2);
    cerr<<"Instance derived from "<getClass()->getName()<getNodeByName("c2_n3");
    
    // we will add the clone of the output as parent to c1_n2
    node2=(LabelledDCNode*)cls1->getNodeByName("c1_n2");
    // instance->getOutput retrieves the output clone for the given node
    node2->addParent((DiscreteChanceNode*)instance->getOutput(node));
    
    cerr<<"Removing output \n";
    // removing the c2_n3 from the output list. This will
    // delete the output clone, so that c1_n2 no longer has that as parent
    node->removeFromOutputs();
    cerr<<"Done \n";

    cerr<<"\n----------------------------------------\n";
    cerr<<"Testing inputs and bindings\n";
    cerr<<"----------------------------------------\n";
    // get the first (and only) input node from cls2
    node=((LabelledDCNode*)cls2->getInputs().front());
    node2=(LabelledDCNode*)cls1->getNodeByName("c1_n2");
    // bind c1_n2 to the input node. This effectively replaces
    // the table of the input node with that of the bound node
    instance->setInput(node, node2);
    cerr<<"Bound "<getName()<<" to "<getInput(node)->getName()<createDomain();

    // print out the origin of all nodes in the domain
    NodeList nodes=dom->getNodes();
    NodeList list;
    for(int j=0; jgetSource();
      cerr<getName()<<" comes from ";
      for(int i=0; igetName()<<(i+1==list.size() ? "\n":".");
      }
    }
    
    dom->writeNet("cbap.net");
    coll->saveAsNet("cbColl.net");
  }
  catch(ExceptionHugin e){
    cerr<<"Caught exception\n";
    cerr<test();
}