Source code for pynfg.classes.node
# -*- coding: utf-8 -*-
"""
Created on Mon Feb 18 10:42:34 2013
Copyright (C) 2013 James Bono (jwbono@gmail.com)
GNU Affero General Public License
"""
from collections import OrderedDict
[docs]class Node(object):
"""Implements a generic node of the semi-NFG formalism created by D. Wolpert
.. note::
This is the superclass. Nodes are generally instantiated in one of the
subclasses, ChanceNode, DecisionNode or DeterNode.
:arg name: the name of the Node, usually descriptive, e.g. C5 for
the fifth chance node (C for chance), or C21 for the second chance node
in the first time step, etc.
:type name: str
:arg parents: a list of the Node's parents
:type parents: list
:arg continuous: True if Node takes on continuous values. False if
discrete.
:type continuous: bool
Upon initialization, the following private method is called:
:py:meth:`nodes.DeterNode._set_parent_dict()`
Some useful methods are:
* :py:meth:`classes.Nodes.dict2list_vals()`
* :py:meth:`classes.Nodes.get_CPTindex()`
"""
def __init__(self, name, parents, continuous):
self.name = name
self.parents = self._set_parent_dict(parents)
self.continuous = continuous
def _set_parent_dict(self, parents):
"""Set the parent OrderedDict based on the params entered by user
:arg parents: list of parameter values for the Node. For ChanceNode and
DecisionNode objects, this is just a list of parent nodes. For
DeterNode objects this list may also contain non-node objects, such
as fixed parameters of the DeterNode function.
:type parents: list
:returns: OrderedDict. Keys are node names. Values are node objects.
"""
r = OrderedDict()
for par in parents:
if isinstance(par, Node):
r[par.name] = par
return r
def _check_disc_parents(self):
"""Check that parents entered by user are discrete
:arg parent: a dictionary with keys as parent names and values as parent
nodes
:type parent: dict
"""
for par in self.parents.values():
if par.continuous is True:
raise RuntimeError("The parent named %s is continuous!" %par.name)
[docs] def dict2list_vals(self, parentinput={}, valueinput=None):
"""Convert parent/value dict entered by user to a list of values
:arg parentdict: the parents OrderedDict attribute for the node, e.g.
`:py:attr:DecisionNode.parents` or `:py:attr:ChanceNode.parents`
:type parentdict: dict
:arg parentinput: Optional. Specify values of the parents. Keys are
parent names. Values are parent values. To specify values for only a
subset of the parents, only enter those parents in the dictionary.
If only a subset of parent values are specified, then the current
values are used for the remaining parents.
:type parentinput: dict
:arg valueinput: Optional. A legitimate value of the decision node
object. If no valueinput is specified, then the output does not include a
value for the node itself.
:returns: a list of the values for the parents and the decision node
itself in the order determine by the :py:attr:DecisionNode.parents`
OrderedDict.
"""
valuelist = []
for par in self.parents.values():
if par.name in parentinput:
valuelist.append(parentinput[par.name])
else:
valuelist.append(par.value)
if valueinput is not None:
valuelist.append(valueinput)
return valuelist
[docs] def get_CPTindex(self, values, onlyparents=False):
"""Get the CPT index that corresponds to the (parent, node) values
:arg parentdict: the parents OrderedDict attribute for the node, e.g.
`:py:attr:DecisionNode.parents` or `:py:attr:ChanceNode.parents`
:type parentdict: dict
:arg onlyparents: set to true if
:type onlyparents: bool
:arg values: a list whose members are values for the parents of the
decision node and the decision node itself, in the order given by
the `:py:attr:DecisionNode.parents` OrderedDict
"""
if self.continuous:
raise AttributeError('cont. nodes do not have CPTs')
ind = []
i = 0
for par in self.parents.values():
if type(par.space[0]==values[i]) is bool:
ind.append(par.space.index(values[i]))
else:
truth = [(x==values[i]).all() for x in par.space]
ind.append(truth.index(True))
i += 1
if not onlyparents:
if type(self.space[0]==values[-1]) is bool:
ind.append(self.space.index(values[-1]))
else:
truth = [(x==values[-1]).all() for x in self.space]
ind.append(truth.index(True))
indo = tuple(ind)
return indo