Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Construct scope trees and fragments #241

Open
goodmami opened this issue Jul 25, 2019 · 0 comments
Open

Construct scope trees and fragments #241

goodmami opened this issue Jul 25, 2019 · 0 comments

Comments

@goodmami
Copy link
Member

In the new delphin.scope module I had a function tree_fragments() which constructed the partial scope trees and allowed inspection of immediately lower scopes (lheqs) and indirectly lower scopes (qeqs) for each scope label. In the end I needed per-predicate granularity when looking at scopal descendants (rather than the descendants of the whole scope) for representative node selection, so I started finding other ways of doing this. With scope.descendants() I no longer need the UnderspecifiedScope class or the tree_fragments() function. They may still be useful in the future for enumerating scope readings (see #221) so I copy those bits of code here. Re-adding the same functionality to PyDelphin might not use the code directly; they are just copied for reference.

class UnderspecifiedScope(tuple):
    """
    Quantifier scope with underspecified constraints.

    This class serves as the nodes in the scope tree fragments used by
    MRS (and transformations of DMRS). It combines three data
    structures:

    * the ids of predications in the immediate scope

    * a mapping of labels to :class:`UnderspecifiedScope` objects for
      scopes directly under the current scope

    * a mapping of labels to :class:`UnderspecifiedScope` objects for
      scopes qeq from the current scope

    This class is not meant to be instantiated directly, but rather is
    used in the return value of functions such as
    :func:`tree_fragments`.

    Attributes:
        ids: ids of predications in the immediate scope
        lheqs: mapping of labels to underspecified scopes directly
            under the current scope
        qeqs: mapping of labels to underspecified scopes qeq from
            the current scope
    """

    __slots__ = ()

    def __new__(cls,
                ids: Container[Identifier],
                lheqs: UnderspecifiedFragments = None,
                qeqs: UnderspecifiedFragments = None):
        if lheqs is None:
            lheqs = {}
        if qeqs is None:
            qeqs = {}
        return super().__new__(cls, (set(ids), dict(lheqs), dict(qeqs)))

    ids = property(
        itemgetter(0), doc='set of ids of predicates in the immediate scope')
    lheqs = property(
        itemgetter(1), doc='directly lower scopes')
    qeqs = property(
        itemgetter(2), doc='indirectly lower scopes')

    def __repr__(self):
        return 'UnderspecifiedScope({!r}, {!r}, {!r})'.format(*self)

    def __contains__(self, id):
        return (id in self.ids
                or any(id in lower for lower in self.lheqs.values())
                or any(id in lower for lower in self.qeqs.values()))
def tree_fragments(x: ScopingSemanticStructure,
                   prune=True) -> UnderspecifiedFragments:
    """
    Return a mapping of scope labels to underspecified tree fragments.

    Each fragment is an :class:`UnderspecifiedScope` object.

    By default the top-level mapping only includes the fragments that
    are not specified as being under another scope. By setting the
    *prune* parameter to `False` all scope labels are included in the
    mapping, which may be helpful for applications needing direct
    access to lower scopes.

    Args:
        x: an MRS or DMRS
        prune: if `True` only include top-level scopes in the mapping
    """
    scopes = x.scopes()
    fragments = {x.top: UnderspecifiedScope([])}
    for label, ps in scopes.items():
        fragments[label] = UnderspecifiedScope(ps)

    nested = set()
    for src, sc_roleargs in x.scopal_arguments(scopes).items():
        for _, rel, label in sc_roleargs:
            if rel == LHEQ:
                fragments[src].lheqs[tgt] = fragments[tgt]
                nested.add(tgt)
            elif rel == QEQ:
                fragments[src].qeqs[tgt] = fragments[tgt]
                nested.add(tgt)

    if prune:
        for label in nested:
            del fragments[label]

    return fragments
goodmami added a commit that referenced this issue Jul 25, 2019
This removes scope.tree_fragments() and scope.UnderspecifiedScope in
favor of updates to the ScopeMap type and adding
scope.descendants(). The reason is so scope.representatives() can get
predicate-granularity scope descendants, which was useful for
excluding representative candidates. The other stuff is removed
because it is no longer used, although it may still be useful.

See #241

This update also tweaks the representative sorting algorithm to
include TENSE information. Diffs on the EDS task with the LKB are now
minimal.
@goodmami goodmami added this to the v1.1.0 milestone Jul 25, 2019
@goodmami goodmami modified the milestones: v1.1.0, v1.2.0 Jan 7, 2020
@goodmami goodmami removed this from the v1.2.0 milestone Jan 16, 2020
@goodmami goodmami mentioned this issue Aug 28, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant