Appendices: Converting NoisyOR/AND Nodes to NoisyMAX
From DSL
Introduction
This document is intended as guide to lead a user though the process of replacing DSL_noisyOR and DSL_noisyAND classes, which are no more present in SMILE:, by the new class called DSL_noisyMAX, which is supposed to provide old functionality of both DSL_noisyOR and DSL_noisyAND augmented with new features. It is important to note, that DSL_noisyMAX is not compatible with DSL_noisyOR/AND.
The new class DSL_noisyMAX is capable of expressing relationships modeled earlier by DSL_noisyAND, because by providing the mechanism for manipulating the order of outcomes in the node as well as assigning the strengths of parents' outcomes, noisy-AND/MIN can be expressed as OR/MAX only by means of changing orders of states and assigning causal strengths.
Why DSL_noisyMAX?
The C++ classes DSL_noisyOR and DSL_noisyMAX are both implementing noisy-OR and noisy-MAX gates, for Bayesian networks. Formally, both classes implement noisy-MAX, since noisy-OR is a special case of noisy-MAX, where all the parents nodes and the child node are binary. So one can say that noisy-MAX is a generalization of noisy-OR.
The original implementation of class DSL_noisyOR, suffered from multiple problems. First of all, the design disallowed implementation of switching the order of states, which was introduced in SMILE 1.1. The other reason was relatively poor quality of the code, compared to the rest of SMILE. These both reasons lead to the decision of abandoning the old code and re-implementing noisy-OR/MAX gates.
Conceptual Differences Between Two Implementations
There are several important conceptual differences between DSL_noisyOR and DSL_noisyMAX. The most important are:
- Different meaning of parameters in the two implementations ("native" vs. "loaded" parameters).
- Different shape of DSL_Dmatrix, which contains parameters.
- Introduced the possibility of assigning the ordering of parent's outcomes in the noisy-MAX gate, that is different to order of outcomes in the parent node.
- By default, DSL_noisyMAX does not expand CPT.
Different Parameters Interpretations
DSL_noisyOR was using as noisy-OR parameters probabilities in form:P(Y|~X1,...,Xi,...,~Xn,XL) . It was possible to use the other version of noisy-OR parameters, which are of form:P(Y|Xi) , by using methods Get/SetHenrionProbabilities(). Sadly, the selection of the name of the parameters was very unfortunate, because Henrion was using both versions of parameters, which can be misleading. Actually, DSL_noisyMAX is using as native parameterization, which was called "Henrion" in DSL_noisyOR, and "native" DSL_noisyOR parameters are "Henrion" parameters for DSL_noisyMAX, and can be accessed by DSL_noisyMAX methods: Get/SetHenrionProbabilities(). We decided to do in such way, to correct mistakes made during DSL_noisyOR implementation, and we selected as a native implementation the one, which leads to simpler calculations. The table should be used as reference:
| Native Parameters | Get/SetHenrionProbabilities() | |
| DSL_noisyOR | P(Y|~X1,...,Xi,...,~Xn,XL) | P(Y|Xi) |
| DSL_noisyMAX | P(Y|Xi) | P(Y|~X1,...,Xi,...,~Xn,XL) |
Different Shapes of DSL_Dmatrix for Noisy-OR Parameters
The DSL_noisyMAX implementation differs from DSL_noisyOR with the shape of DSL_Dmatrx, which stores parameters. Basically, for DSL_noisyOR, DSL_Dmatrix had two dimensions, first was indexed by parents' outcomes, second by noisy-OR node's outcomes. The same holds for DSL_noisyMAX. The difference is in size of the first dimension. For DSL_noisyOR if the parent node had n outcomes, it had assigned n-1 slots. DSL_noisyMAX has assigned in this situation n slots. The graph below explains the difference.
The gray fields in DSL_Dmatrix of DSL_noisyMAX indicate the constraint values. For details see SMILE: Programmer documentation.
Outcome order and strengths of influence'
The class DSL_noisyMAX introduces the concept of outcome strengths. In previous implementation of noisy-OR, SMILE: had inconvenient assumption, that order of outcomes in the parent node reflects the order of causal influence on child node. For example, it was impossible to model interaction when one parent node had two noisy-OR children, but the "absent" state for both of those relationships was different - previous implementation assumed that always the last outcome in parent's node is "absent," while in fact it should be defined in child node and should be possible to set for every node separately.
In DSL_noisyMAX class, user has possibility of control, in what is parent's outcomes order in causal relation. For each parent's outcome there is assigned outcome strength, which defines this order. The value of strength 0 indicates the strongest influence and the greatest value is assigned to distinguished state. The DSL_matrix containing parameters always follows order of strengths - this means, that the first column is aligned to the outcome of the greatest strength, the second column to the outcome of the second strength end so on. The distinguished state is always assigned to the last column.
It is important to note, that when obtaining fully expanded CPT, the order of outcomes is preserved as was original in parents, and outcome strengths do not play any role. In other words, DSL_Dmatrix should be treated exactly in the same way as for DSL_cpt.
Expanding Noisy-MAX to the full CPT
The implementation of noisy-MAX does not keep expanded full CPT by default. DSL_noisyMAX can work in two modes - KeepExpanded or DontKeepExpanded (by default).
KeepExpanded means, that DSL_noisyMAX will keep DSL_Dmatrix containing full CPT expanded and updated all the time. This produces extra overhead in calculations and memory allocations, but access to expanded CPT is immediate and without cost.
In the mode DontKeepExpanded, the full CPT is calculated only on explicit user request (like method GetCpt()). However each call to this method will be costly since, SMILE: will update DSL_Dmatrix containing full CPT every time the method was called. In this mode there is an alternative method of accessing single probability distribution without expanding whole CPT - CalculateCptColumn(). This can be suggested, when noisy-MAX has multiple parents and storing whole CPT is too expensive or even impossible.
To switch between the modes there are two methods provided: SetKeepSynchronized() and SetDontKeepSynchronized().
Access methods for different parameters
The class DSL_noisyMAX provides programming interface for different parameters. Below there is a list of available methods and description of their functionality:
- DSL_Dmatrix &GetCiWeights()
Returns noisy-MAX parameters in form native for DSL_noisyMAX.
- DSL_Dmatrix &GetCpt()
Returns a full CPT parameters in form native for DSL_cpt. This method, when necessary, automatically updates CPT.
- int GetHenrionProbabilities(DSL_Dmatrix &here)
Fills here with DSL_noisyMAX "Henrion" parameters, note that the shape of DSL_Dmatrix is the same as for "native" parameters.
- int SetHenrionProbabilities(DSL_Dmatrix &withThese)
Sets parameters using DSL_noisyMAX "Henrion" parameters stored in withThese, note that the shape of DSL_Dmatrix is the same as for "native" parameters.
- int SetDefinition(DSL_Dmatrix &ciWeights)
Allows to set DSL_noisyMAX "native" weights.
- int SetDefinition(DSL_doubleArray &ciWeights)
Allows to set DSL_noisyMAX "native" weights.
- int SetLegacyNoisyOrProbabilities(DSL_doubleArray &old)
Allows to fill DSL_noisyMAX ciWeights with parameters used in DSL_noisyOR. The old should contain valid data from DSL_Dmatrix taken directly from DSL_noisyOR.
- int GetLegacyNoisyOrProbabilities(DSL_doubleArray &new)
Allows to get parameters used in DSL_noisyOR. The new follows data format from DSL_Dmatrix taken directly from DSL_noisyOR.
- int CalculateCptColumn (const DSL_intArray &coordinates, DSL_doubleArray &here)
Allows to calculate (without actual expanding) one distribution (column) in CPT. Input parameters coordinates are coordinates of requested distribution (indexed by order of outcomes in parents) and the output is a distribution provided in here.
The following functions are available, however the user is strongly discouraged to use them. We reserve the right to change or remove them in later versions.
- DSL_object *GetDefinition()
Returns pointer to DSL_Dmatrix that holds CPT.
- int GetDefinition(DSL_Dmatrix **cptHere)
Fills DSL_Dmatrix with parameters of full CPT.
- int GetDefinition(DSL_doubleArray **cptHere)
Fills DSL_doubleArray with parameters of full CPT.


