Source code for openalea.core.dataflow_evaluation
# -*- python -*-
#
# OpenAlea.Core
#
# Copyright 2006-2009 INRIA - CIRAD - INRA
#
# File author(): Jerome Chopard <revesansparole@gmail.com>
#
# Distributed under the Cecill-C License.
# See accompanying file LICENSE.txt or copy at
# http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html
#
# OpenAlea WebSite: http://openalea.gforge.inria.fr
#
###############################################################################
""" This module provide algorithms to evaluate a dataflow
"""
__license__ = "Cecill-C"
__revision__ = " $Id$ "
# class EvaluationException(Exception):
#
# def __init__(self, vid, node, exception, exc_info):
# Exception.__init__(self)
# self.vid = vid
# self.node = node
# self.exception = exception
# self.exc_info = exc_info
[docs]
class AbstractEvaluation(object):
""" Abstract evaluation algorithm
"""
def __init__(self, dataflow):
""" Constructor
args:
- dataflow (Dataflow): the dataflow to evaluate
"""
self._dataflow = dataflow
[docs]
def eval(self, env, state, vid=None):
""" Evaluate associated dataflow.
Produce a valid state from a ready_to_evaluate one.
args:
- env (EvaluationEnvironment): environment in which to perform
the evaluation
- state (DataflowState): must be a ready_not_evaluate state
- vid (vid): id of vertex to start the evaluation
if None starts from the leaves of the dataflow
"""
raise NotImplementedError()
[docs]
def clear(self):
""" Clear algorithm, ready to reevaluate.
"""
pass
[docs]
class BruteEvaluation(AbstractEvaluation):
""" For each evaluation reevaluate each node of the dataflow.
"""
def __init__(self, dataflow):
AbstractEvaluation.__init__(self, dataflow)
self._evaluated = set()
[docs]
def clear(self):
AbstractEvaluation.clear(self)
self._evaluated.clear()
[docs]
def eval(self, env, state, vid=None):
if not state.is_ready_for_evaluation():
raise UserWarning("state not ready for evaluation")
if vid is None: # start evaluation from leaves in the dataflow
df = self._dataflow
leaves = [vid for vid in df.vertices() if df.nb_out_edges(vid) == 0]
# TODO: sort leaves
for vid in leaves:
self.eval_from_node(env, state, vid)
else:
self.eval_from_node(env, state, vid)
[docs]
def eval_from_node(self, env, state, vid):
""" Evaluate dataflow from a given node.
function provided for convenience to simplify
derivation from this algo
"""
# add node to evaluated list to prevent
# multiple evaluation of the same node
self._evaluated.add(vid)
# ensure that all nodes upstream of this node have been evaluated
for nid in self._dataflow.in_neighbors(vid):
if nid not in self._evaluated:
self.eval_from_node(env, state, nid)
# evaluate the node
self.eval_node(env, state, vid)
[docs]
def eval_node(self, env, state, vid):
""" Evaluate a single node
Store result in state.
Doesn't test if state is valid or if the node
actually need to be evaluated
"""
df = self._dataflow
# find input values
inputs = [state.get_data(pid) for pid in df.in_ports(vid)]
# perform computation
vals = df.actor(vid)(inputs)
# affect return values to output ports
pids = tuple(df.out_ports(vid))
if len(pids) == 0:
if vals is not None:
msg = "mismatch nb out port vs. function result"
raise UserWarning(msg)
elif len(pids) == 1:
pid, = pids
state.set_data(pid, vals)
elif len(pids) == len(vals):
for pid, val in zip(pids, vals):
state.set_data(pid, val)
else:
raise UserWarning("mismatch nb out port vs. function result")
# class LazyEvaluation(BruteEvaluation):
# """ For each evaluation reevaluate a node of the dataflow
# only if its inputs have changed or if it is tagged
# as not lazy.
# """
# def __init__(self, dataflow):
# BruteEvaluation.__init__(self, dataflow)
#
# self._modified = {}
#
# def clear(self):
# BruteEvaluation.clear(self)
# self._modified.clear()