Source code for curry.backends.py.eval.rts_fingerprint

'''
Implements RuntimeState methods related to the fingerprint.  This module is not
intended to be imported except by rts.py.
'''

from copy import copy
from ....common import T_FREE, T_CHOICE, LEFT, RIGHT, UNDETERMINED, ChoiceState
from .. import graph
from .... import inspect

__all__ = ['equate_fp', 'grp_id', 'obj_id', 'read_fp', 'update_fp']

[docs] def grp_id(rts, arg=None, config=None): ''' Returns the group ID. The argument must be a choice or variable node, or ID. Every distinct group of free variables constrained equal with (=:=) belong to a group with a unique group ID. The group ID is the object ID of one arbitrary, distinguished member, called the representative. Two variables are constrained equal if and only if they share the same group ID (reflexivity permitted). ''' config = config or rts.C return config.strict_constraints.read.root(rts.obj_id(arg, config))
[docs] def obj_id(rts, arg=None, config=None): ''' Returns the choice or variable ID of a node. The node argument must be a choice or free variable node. For convenience, ``arg`` may be an ID, in which case it is simply returned. ''' arg = (config or rts.C).root if arg is None else arg if isinstance(arg, int): return arg else: if arg.info.tag == T_CHOICE: cid, _, _ = arg.successors return cid elif arg.info.tag == T_FREE: vid, _ = arg.successors return vid
[docs] def read_fp(rts, arg=None, config=None): ''' Read the fingerprint for the given argument. The argument must be a choice or variable node, ID, or ChoiceState. The group ID is always used to read a fingerprint. For convenience, if a ChoiceState is provided, it is simply returned. ''' if isinstance(arg, ChoiceState): return arg else: config = config or rts.C cid = rts.grp_id(arg, config=config) for cfg in rts.walk_qstack(firstconfig=config): if cid in cfg.fingerprint: return cfg.fingerprint[cid] else: return UNDETERMINED
def fork(rts, config=None): ''' Fork a choice-rooted configuration. Yields each consistent configuration arising from fixing the choice to the LEFT or RIGHT. ''' rts.telemetry._forks += 1 config = config or rts.C checker = rts.checker clones = None if checker is None else [] for idx, choicestate in [(1, LEFT), (2, RIGHT)]: clone = config.clone(config.root.successors[idx]) if rts.update_fp(choicestate, config.root, config=clone): cid = rts.obj_id(config=config) gid = rts.grp_id(cid, config=clone) if cid in rts.vtable: rts.apply_binding(cid, config=clone) rts.apply_binding(gid, config=clone) if not rts.constrain_equal(*map(rts.get_freevar, [cid,gid]), config=clone): continue if any(config.fingerprint.get(i, choicestate) != choicestate for config in rts.walk_qstack() for i in [cid, gid] ): continue if clones is not None: clones.append(clone) yield clone if checker is not None: checker.fork(config, clones)
[docs] def equate_fp(rts, arg0, arg1, config=None): ''' Equate two IDs in a fingerprint. Set both to the same value and return True, if that is consistent, or return False otherwise. ''' return rts.update_fp(arg0, arg1, config=config) \ and rts.update_fp(arg1, arg0, config=config)
def pull_tab(rts, root, target, realpath, rewrite=None): ''' Make a choice node with ID ``cid`` whose alternatives are derived by replacing ``node[path]`` with the alternatives of choice-rooted expression``alternatives``. If ``alternatives`` is not specified, then ``node[path]`` is used. If ``rewrite`` is supplied, the specified node is overwritten. Otherwise a new node is created. ''' rts.telemetry._pulltabs += 1 cid,l,r = target.successors lhs = graph.utility.copy_spine(root, realpath, end=l) rhs = graph.utility.copy_spine(root, realpath, end=r) checker = rts.checker if checker is None: return graph.Node(rts.Choice, cid, lhs, rhs, target=rewrite) # The copies are checked against the spine before the rewrite, and the # identifier of the created choice after it. checker.pulltab(root, target, realpath, lhs, rhs) node = graph.Node(rts.Choice, cid, lhs, rhs, target=rewrite) checker.pulltab_done(node, target) return node
[docs] def update_fp(rts, choicestate, arg=None, config=None): ''' Update the fingerprint to reflect the ID associated with ``arg``` being set to ``choicestate.`` If ``choicestate`` is ``UNDETERMINED``, this does nothing. Otherwise, the current value of ``arg`` is determined, consulting the fingerprint, if necessary. If it is consistent with ``choicestate`` then it is updated and True is returned. Otherwise, False is returned. Args: choicestate: The choice state to set. Must be a ChoiceState, choice or free variable node, or ID. arg: The ID to update in the fingerprint. Must be a choice or free variable node, or ID. config: The Configuration to use as context. Returns: A Boolean indicating whether the change is consistent. ''' config = config or rts.C choicestate = rts.read_fp(choicestate, config=config) if choicestate == UNDETERMINED: return True current = rts.read_fp(arg, config=config) if current == UNDETERMINED: config.fingerprint = copy(config.fingerprint) config.fingerprint[rts.obj_id(arg, config)] = choicestate config.fingerprint[rts.grp_id(arg, config)] = choicestate return True else: return current == choicestate