Source code for pynfg.classes.deternode

# -*- coding: utf-8 -*-
"""
Implements the DeterNode class

Part of: PyNFG - a Python package for modeling and solving Network Form Games

Created on Mon Feb 18 10:34:13 2013

Copyright (C) 2013 James Bono (jwbono@gmail.com)

GNU Affero General Public License

"""

import numpy as np
from node import *

[docs]class DeterNode(Node): """Implements a deterministic node for the semi-NFG formalism created by D. Wolpert :arg name: the name of the DeterNode, usually descriptive, e.g. F5 for the fifth deterministic node (F for fixed), or F21 for the second deterministic node in the first time step, etc. :type name: str :arg func: a deterministic function - defined with defaults for each of its inputs. :type func: function :arg params: keys are input keywords for func, values are parents or fixed values if something other than defaults for non-parent inputs is desired. :type params: dict :arg continuous: True if function takes on continuous values. False if discrete. :type continuous: bool :arg space: The list of elements in space if discrete. Empty list if continuous :type space: list :arg description: a description of the DeterNode, usually including a summary description of the function, space, parents and children. :type description: str. :arg time: the timestep to which the node belongs. This is generally only used for :class:`seminfg.iterSemiNFG` objects. :type time: integer :arg basename: a reference to a theoretical node in the base or kernel. :type basename: str. Formally, a deterministic node has the following properties: * belongs to the *nature* player * has deterministic function from the values of its parents - given by :py:meth:`classes.DecisionNode.prob()` or :py:meth:`classes.ChanceNode.prob()`. .. note:: Deterministic nodes are not a part of the Semi-NFG formalism. Their functionality is implicit in the relationship between stochastic parent nodes and their stochastic children, as is the convention in Bayesian Networks. They can be seen as deterministically *transforming* the values of parents into the parameters that are used by their children. Example:: import scipy.stats.distributions as randvars dist1 = randvars.norm params1 = [0.5, 1] distip1 = (dist1, params1) C1 = ChanceNode('C1', distip=distip1, description='CN given by norm loc=0.5, scale=1') def func2(var1=1, var2=0): r = np.sign(var1+var2) return r params2 = {'var1': C1} continuous2 = False space2 = [-1, 0, 1] F2 = DeterNode('F2', func2, params2, continuous2, space=space2, description='a disc. DeterNode child of C1') Upon initialization, the following private method is called: :py:meth:`classes.DeterNode._set_parent_dict()` Some useful methods are: * :py:meth:`classes.DeterNode.draw_value()` * :py:meth:`classes.DeterNode.prob()` * :py:meth:`classes.DeterNode.logprob()` """ def __init__(self, name, func, params, continuous, space=None, \ description='no description', time=None, basename=None, \ verbose=False): if verbose: try: print 'Name: '+ name + '\nDescription: '+ description except TypeError: print('name and description should be strings') self.name = name self.player = 'nature' self.dfunction = func self.params = params if space is None: space = [] if isinstance(space, list): self.space = space else: raise TypeError('The space must be a list') self.parents = self._set_parent_dict(params.values()) self.continuous = continuous # self.value = None # self.draw_value() self.description = description self.time = time self.basename = basename def __str__(self): return self.name
[docs] def draw_value(self, parentinput=None, setvalue=True): """Draw a value from the :class:`classes.DeterNode` object This function computes the value of the deterministic node given the current values of the parents or with the values provided in pareninput :arg parentinput: Optional. Specify values of the parents at which to compute values from the function governing the DeterNode. 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 no parent values are specified, then the current values of the parents are used. :type parentinput: dict :arg setvalue: (Optional) determines if the random draw replaces :py:attr:`classes.DeterNode.value`. True by default. :type setvalue: bool :returns: the value of the deterministic node that corresponds to the parent values. .. note:: If parent values are specified in parentinput, those values must be legitimate values of the parent. For discrete parents, the values must correspond to an item in the parent's space attribute. """ if parentinput is None: parentinput = {} funinput = {} for par in self.params: if isinstance(self.params[par],Node): if par in parentinput: funinput[par] = parentinput[par] else: funinput[par] = self.params[par].get_value() else: funinput[par] = self.params[par] r = self.dfunction(**funinput) if setvalue: self.set_value(r) return self.value else: return r
[docs] def prob(self, parentinput=None, valueinput=None): """Compute the probability of the current or specified value Note that since this is a deterministic node, the probability is always either zero or one. :arg parentinput: Optional. Specify values of the parents at which to compute the probability of the value of the DeterNode function. 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 no parent values are specified, then the current values of the parents are used. :type parentinput: dict :arg valueinput: Optional. A legitimate value of the DeterNode object. If no valueinput is specified, then the current value of the node is used. :returns: the conditional probability of valueinput or the current value conditioned on parentinput or the current values of the parents. .. note:: If parent values are specified in parentinput, those values must be legitimate values of the parent. For discrete parents, the values must correspond to an item in the parent's space attribute. """ if parentinput is None: parentinput = {} funinput = {} for par in self.params: if isinstance(self.params[par], Node): if par in parentinput: funinput[par] = parentinput[par] else: funinput[par] = self.params[par].get_value() else: funinput[par] = self.params[par] if valueinput is None: valueinput = self.get_value() try: r = 1*(self.dfunction(**funinput) == valueinput).all() except AttributeError: r = 1*(self.dfunction(**funinput) == valueinput) return r
[docs] def logprob(self, parentinput=None, valueinput=None): """Compute the conditional logprob of the current or specified value :arg parentinput: Optional. Specify values of the parents at which to compute the logprob of the value of the DeterNode. 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 no parent values are specified, then the current values of the parents are used. :type parentinput: dict :arg valueinput: Optional. A legitimate value of the DeterNode object. If no valueinput is specified, then the current value of the node is used. :returns: the log conditional probability of valueinput or the current value conditioned on parentinput or the current values of the parents. .. note:: If parent values are specified in parentinput, those values must be legitimate values of the parent. For discrete parents, the values must correspond to an item in the parent's space attribute. .. note:: Since this is a deterministic node, the logprob is alwayseither zero or -inf. This is equivalent to ``np.log(DeterNode.prob())`` """ if parentinput is None: parentinput = {} r = self.prob(parentinput, valueinput) return np.log(r)

Mailing List

Join the Google Group: