コード例 #1
0
def configure(g: Graph, top: Variable = None, model: Model = None) -> Tree:
    """
    Create a tree from a graph by making as few decisions as possible.

    A graph interpreted from a valid tree using :func:`interpret` will
    contain epigraphical markers that describe how the triples of a
    graph are to be expressed in a tree, and thus configuring this
    tree requires only a single pass through the list of triples. If
    the markers are missing or out of order, or if the graph has been
    modified, then the configuration process will have to make
    decisions about where to insert tree branches. These decisions are
    deterministic, but may result in a tree different than the one
    expected.

    Args:
        g: the :class:`~penman.graph.Graph` to configure
        top: the variable to use as the top of the graph; if ``None``,
            the top of *g* will be used
        model: the :class:`~penman.model.Model` used to configure the
            tree
    Returns:
        The configured :class:`~penman.tree.Tree`.
    Example:

        >>> from penman.graph import Graph
        >>> from penman import layout
        >>> g = Graph([('b', ':instance', 'bark-01'),
        ...            ('b', ':ARG0', 'd'),
        ...            ('d', ':instance', 'dog')])
        >>> t = layout.configure(g)
        >>> print(t)
        Tree(
          ('b', [
            ('/', 'bark-01'),
            (':ARG0', ('d', [
              ('/', 'dog')]))]))
    """
    if model is None:
        model = _default_model
    node, data, nodemap = _configure(g, top, model)
    # remove any superfluous POPs at the end (maybe from dereification)
    while data and data[-1] is POP:
        data.pop()
    # if any data remain, the graph was not properly annotated for a tree
    while data:
        skipped, var, data = _find_next(data, nodemap)
        data_count = len(data)
        if var is None or data_count == 0:
            raise LayoutError('possibly disconnected graph')
        _configure_node(var, data, nodemap, model)
        if len(data) >= data_count:
            raise LayoutError('possible cycle in configuration')
        data = skipped + data
        # remove any superfluous POPs
        while data and data[-1] is POP:
            data.pop()
    tree = Tree(node, metadata=g.metadata)
    logger.debug('Configured: %s', tree)
    return tree
コード例 #2
0
def _preconfigure(g, strict):
    """
    Arrange the triples and epidata for ordered traversal.

    Also perform some basic validation.
    """
    data = []
    epidata = g.epidata
    pushed = set()
    for triple in g.triples:
        var, role, target = triple
        push, pops = None, []
        for epi in epidata.get(triple, []):
            if isinstance(epi, Push):
                if push is not None or epi.variable in pushed:
                    if strict:
                        raise LayoutError(
                            f"multiple node contexts for '{epi.variable}'")
                    pass  # change to 'continue' to disallow multiple contexts
                if epi.variable not in (triple[0], triple[2]):
                    if strict:
                        raise LayoutError(
                            f"node context '{epi.variable}' "
                            f"invalid for triple: {triple!r}")
                    continue
                pushed.add(epi.variable)
                push = epi
            elif epi is POP:
                pops.append(epi)
            elif epi.mode == 1:  # role epidata
                role = f'{role!s}{epi!s}'
            elif target and epi.mode == 2:  # target epidata
                target = f'{target!s}{epi!s}'
            else:
                logging.warning('epigraphical marker lost: %r', epi)

        if strict and push and pops:
            raise LayoutError(
                f'incompatible node context changes on triple: {triple!r}')

        data.append(((var, role, target), push))
        data.extend(pops)

    return data
コード例 #3
0
def _configure(g, top, model, strict):
    """
    Create the tree that can be created without any improvising.
    """
    if len(g.triples) == 0:
        return (g.top, []), [], {}

    nodemap: _Nodemap = {var: None for var in g.variables()}
    if top is None:
        top = g.top
    if top not in nodemap:
        raise LayoutError(f'top is not a variable: {top!r}')
    nodemap[top] = (top, [])

    data = list(reversed(_preconfigure(g, strict)))
    node = _configure_node(top, data, nodemap, model)

    return node, data, nodemap