<< Click to Display Table of Contents >> Navigation: Using SMILE Wrappers > Continuous models > Equation-based nodes |
To create an equation node, specify EQUATION when calling Network.add_node. By default, the node equation is set to x=0 (where x is the node identifier). You can replace this default equation using Network.set_node_equation. For instance, the following code sets the node x to a standard Gaussian probability distribution:
Python
hx = net.add_node(pysmile.NodeType.EQUATION, "x")
net.set_node_equation(hx, "x=Normal(0,1)")
Java
int hx = net.addNode(Network.NodeType.EQUATION, "x");
net.setNodeEquation(hx, "x=Normal(0,1)");
C#
int hx = net.AddNode(Network.NodeType.Equation, "x");
net.SetNodeEquation(hx, "x=Normal(0,1)");
R
hx <- net$addNode(net$NodeType$EQUATION, "x")
net$setNodeEquation(hx, "x=Normal(0,1)")
SMILE defines many functions for use in node equations. The complete list of functions is available in the Equations reference section. Among these functions, there are random generators, which generate a single sample based on the passed parameters. In the example above, the Normal is the name of SMILE's random generator function.
Node equations can reference other nodes by using their identifiers. Continuing with our code snippet:
Python
hy = net.add_node(pysmile.NodeType.EQUATION, "y")
net.set_node_equation(hy, "y=2*x")
Java
int hy = net.addNode(Network.NodeType.EQUATION, "y");
net.setNodeEquation(hx, "y=2*x");
C#
int hy = net.AddNode(Network.NodeType.Equation, "y");
net.SetNodeEquation(hx, "y=2*x");
R
hy <- net$addNode(net$NodeType$EQUATION, "y");
net$setNodeEquation(hx, "y=2*x");
A second node is added, and its equation is set to y=2*x, where x references the previously defined node. SMILE automatically adds an arc from x to y; it is not necessary to call Network.add_arc before setting an equation that references other nodes. Note that calling addArc explicitly will modify the child node’s equation by appending a term for the new parent at the end of the equation. For example, in a network with equation nodes a, b, c, and d, if d's equation is set to d=Normal(a, 1)+Normal(b, 2), calling addArc with the handles of nodes c and d would rewrite d’s equation as d=Normal(a, 1)+Normal(b, 2)+c.
If an arc is removed—either via Network.delete_arc or Network.delete_node on one of the parents—the node equation is automatically rewritten to sum over the remaining parents. This ensures that equations and arcs remain synchronized. For instance, if node b is deleted or an arc from b to d is removed, d’s equation would update to d=a+c.
Changes to node identifiers are also propagated into equations. If the identifier of the first node in the previous example were changed from x to x_prime, the equation of node y would automatically update to y=2*x_prime.
In SMILE, calling Network.set_node_equation is sufficient to define both the mathematical relationship and the network structure for continuous (equation) nodes. Unlike discrete nodes, where the conditional probability distribution is specified with Network.set_node_definition, equation nodes automatically create or update arcs and dependencies based on the expression passed to set_node_equation. In this sense, set_node_equation can be seen as a generalization of set_node_definition, combining parameter specification and structural updates in a single operation.
In addition to set_node_equation, there are functions that provide information about the type of an equation defining the node. Network.get_node_equation_constant returns the numeric value of a constant equation, if the node represents a constant. The corresponding Network.is_node_equation_constant function returns true if the node’s equation is a fixed constant, and false otherwise. Similarly, Network.is_node_equation_deterministic indicates whether the node’s equation is deterministic—that is, whether it produces a single, predictable value given its parent nodes, rather than generating random samples.
Python
get_node_equation(node: int | str) -> str
set_node_equation(node: int | str, equation: str) -> None
get_node_equation_constant(node: int | str) -> float
is_node_equation_constant(node: int | str) -> bool
is_node_equation_deterministic(node: int | str) -> bool
Java
String getNodeEquation(int nodeHandle);
String getNodeEquation(String nodeId);
void setNodeEquation(int nodeHandle, String equation);
void setNodeEquation(String nodeId, String equation);
double getNodeEquationConstant(int nodeHandle);
double getNodeEquationConstant(String nodeId);
boolean isNodeEquationConstant(int nodeHandle);
boolean isNodeEquationConstant(String nodeId);
boolean isNodeEquationDeterministic(int nodeHandle);
boolean isNodeEquationDeterministic(String nodeId);
C#
string GetNodeEquation(int nodeHandle);
string GetNodeEquation(string nodeId);
void SetNodeEquation(int nodeHandle, string equation);
void SetNodeEquation(string nodeId, string equation);
double GetNodeEquationConstant(int nodeHandle);
double GetNodeEquationConstant(string nodeId);
bool IsNodeEquationConstant(int nodeHandle);
bool IsNodeEquationConstant(string nodeId);
bool IsNodeEquationDeterministic(int nodeHandle);
bool IsNodeEquationDeterministic(string nodeId);
R
nodeEquation <- getNodeEquation(nodeIdOrHandle)
setNodeEquation(nodeIdOrHandle, equation)
nodeConstant <- getNodeEquationConstant(nodeIdOrHandle)
isConstant <- isNodeEquationConstant(nodeIdOrHandle)
isDeterministic <- isNodeEquationDeterministic(nodeIdOrHandle)