A FactorGraph and a RegionGraph are often equipped with additional properties for nodes and edges. The code to initialize those is often quite similar. Maybe one could abstract this, e.g.:
template <typename Node1Properties, typename Node2Properties, typename EdgeProperties>
class ExtFactorGraph : public FactorGraph {
public:
std::vector<Node1Properties> node1Props;
std::vector<Node2Properties> node2Props;
std::vector<std::vector<EdgeProperties> > edgeProps;
}
Advantages:
- Less code duplication.
- Easier maintainability.
- Easier to write new inference algorithms.
Disadvantages:
- Cachability may be worse.
- A problem is the case where there are no properties for either type of nodes or for edges. Maybe this can be solved using specializations, or using variadac template arguments? Another possible solution would be to define a "class Empty {}", and add some code that checks for the typeid, comparing it with Empty, and doing something special in that case (e.g., not allocating memory).
- The main disadvantage of this approach seems to be that it leads to even more entanglement. Therefore this is probably a bad idea.
Instead of polymorphism by inheritance, use polymorphism by template parameterization. For example, the real reason for introducing the complicated inheritance scheme of
dai::InfAlg was for functions like
dai::calcMarginal. Instead, one could use a template function:
template<typename InfAlg>
Factor calcMarginal( const InfAlg &obj, const VarSet &ns, bool reInit );
This would assume that the type InfAlg supports certain methods. Ideally, one would use concepts to define different classes of inference algorithms with different capabilities, for example the ability to calculate logZ, the ability to calculate marginals, the ability to calculate bounds, the ability to calculate MAP states, etc. Then, one would use traits classes in order to be able to query the capabilities of the model. For example, one would be able to query whether the inference algorithm supports calculation of logZ. Unfortunately, this is compile-time polymorphism, whereas tests/testdai needs runtime polymorphism. Therefore this is probably a bad idea.