Module tf.core.locality

Local navigation between nodes.

Expand source code Browse git
"""
# Local navigation between nodes.
"""


SET_TYPES = {set, frozenset}


class Locality:
    """Methods by which you can navigate from a node to its neighbourhood.

    Neighbours are: nodes that have slots in common, embedders and embeddees,
    previous and next siblings.

    !!! note "L"
        The Locality API is exposed as `L` or `Locality`.

    !!! note "`otype` parameter"
        In all of the following `L`-functions, if the `otype` parameter is passed,
        the result is filtered and only nodes with
        `otype=nodeType` or `otype in nodeTypes` are retained.

        `otype` can be a string (a single node type)  or a (frozen)set of node types.

    !!! caution "Results of the `L.` functions are tuples, not single nodes"
          Even if an `L`-function returns a single node, it is packed in a *tuple*.
          So to get the node itself, you have to index the tuple:

              L.u(node)[0]

    !!! caution "Locality and node types"
        When using `tf.core.nodes.Nodes.sortNodes` and the `L` methods,
        note the following.

        Suppose you have node types `verse` and `sentence`, and usually a
        verse has multiple sentences, but not vice versa. Then you expect that

        *   `L.d(verseNode)` will contain sentence nodes,
        *   `L.d(sentenceNode)` will **not** contain verse nodes.

        But if there is a verse with exactly one sentence, and both have exactly the
        same words, then that is a case where:

        *   `L.d(verseNode)` will contain `sentenceNode`,
        *   `L.d(sentenceNode)` will contain `verseNode`.
      """

    def __init__(self, api):
        self.api = api

    def i(self, n, otype=None):
        """Produces an ordered tuple of *intersecting* nodes

        Intersecting nodes of a node have slots in common with that node.

        Parameters
        ----------

        node: dict
            The node whose intersectors will be delivered.
        otype: string or set of strings
            See `Locality`.

        Returns
        -------
        tuple of integer
            The tuple nodes is sorted in the
            canonical order (`tf.core.nodes`).

            The result never includes `n` itself.
            But other nodes linked to the same set of slots as `n`
            may count as intersector nodes.

            Slots themselves can be intersectors.
        """

        api = self.api
        N = api.N
        Fotype = api.F.otype
        maxSlot = Fotype.maxSlot
        if n <= maxSlot:
            return tuple()
        maxNode = Fotype.maxNode
        if n > maxNode:
            return tuple()
        sortNodes = N.sortNodes
        if not otype:
            otype = set(Fotype.all)
        elif type(otype) is str:
            otype = {otype}
        elif type(otype) not in SET_TYPES:
            otype = set(otype)

        slotType = Fotype.slotType
        fOtype = Fotype.v
        levUp = api.C.levUp.data
        Eoslots = api.E.oslots

        slots = Eoslots.s(n)
        result = set()
        for slot in slots:
            result |= {m for m in levUp[slot - 1] if fOtype(m) in otype}
            if slotType in otype:
                result.add(slot)
        return sortNodes(result - {n})

    def u(self, n, otype=None):
        """Produces an ordered tuple of *upward* nodes.

        Upward nodes of a node are embedders of that node.
        One node embeds an other if all slots of the latter are contained in the slots
        of the former.

        Parameters
        ----------

        node: integer
            The node whose embedders will be delivered.
        otype: string or set of strings
            See `Locality`.

        Returns
        -------
        tuple of integer
            The tuple nodes is sorted in the canonical order (`tf.core.nodes`),
            but *reversed*: right and small embedders before left and big embedders.

            The result never includes `n` itself.
            But other nodes linked to the same set of slots as `n`
            may count as embedder nodes.

            Slots themselves are never embedders.
        """

        if n <= 0:
            return tuple()
        Fotype = self.api.F.otype
        maxNode = Fotype.maxNode
        if n > maxNode:
            return tuple()
        fOtype = Fotype.v
        levUp = self.api.C.levUp.data

        if otype is None:
            return tuple(levUp[n - 1])
        elif type(otype) is str:
            return tuple(m for m in levUp[n - 1] if fOtype(m) == otype)
        else:
            if type(otype) not in SET_TYPES:
                otype = set(otype)
            return tuple(m for m in levUp[n - 1] if fOtype(m) in otype)

    def d(self, n, otype=None):
        """Produces an ordered tuple of *downward* nodes.

        Downward nodes of a node are embedded nodes in that node.
        One node is embedded in an other if all slots of the former are contained
        in the slots of the latter.

        Parameters
        ----------

        node: integer
            The node whose embeddees will be delivered.
        otype: string or set of strings
            See `Locality`.

        Returns
        -------
        tuple of integer
            The tuple nodes is sorted in the canonical order (`tf.core.nodes`),
            left and big embeddees before right and small embeddees.

            The result never includes `n` itself.
            But other nodes linked to the same set of slots as `n`
            may count as embeddee nodes.
        """

        Fotype = self.api.F.otype
        fOtype = Fotype.v
        maxSlot = Fotype.maxSlot
        if n <= maxSlot:
            return tuple()
        maxNode = Fotype.maxNode
        if n > maxNode:
            return tuple()

        Eoslots = self.api.E.oslots
        Crank = self.api.C.rank.data
        levDown = self.api.C.levDown.data
        slotType = Fotype.slotType
        if otype is None:
            return tuple(
                sorted(
                    levDown[n - maxSlot - 1] + Eoslots.s(n), key=lambda m: Crank[m - 1],
                )
            )
        elif otype == slotType:
            return tuple(sorted(Eoslots.s(n), key=lambda m: Crank[m - 1]))
        elif type(otype) is str:
            return tuple(m for m in levDown[n - maxSlot - 1] if fOtype(m) == otype)
        else:
            if type(otype) not in SET_TYPES:
                otype = set(otype)
            return tuple(
                sorted(
                    (
                        k
                        for k in levDown[n - maxSlot - 1] + Eoslots.s(n)
                        if fOtype(k) in otype
                    ),
                    key=lambda m: Crank[m - 1],
                )
            )

    def p(self, n, otype=None):
        """Produces an ordered tuple of *previous* nodes.

        One node is previous to an other if the last slot of the former just precedes
        the first slots of the latter.

        Parameters
        ----------

        node: integer
            The node whose previous nodes will be delivered.
        otype: string or set of strings
            See `Locality`.

        Returns
        -------
        tuple of integer
            The tuple nodes is sorted in the canonical order (`tf.core.nodes`),
            but *reversed*: right and small embedders before left and big embedders.
        """

        if n <= 1:
            return tuple()
        Fotype = self.api.F.otype
        fOtype = Fotype.v
        maxNode = Fotype.maxNode
        if n > maxNode:
            return tuple()

        maxSlot = Fotype.maxSlot
        Eoslots = self.api.E.oslots.data
        (firstNode, lastNode) = self.api.C.boundary.data

        myPrev = n - 1 if n <= maxSlot else Eoslots[n - maxSlot - 1][0] - 1
        if myPrev <= 0:
            return ()

        result = tuple(lastNode[myPrev - 1]) + (myPrev,)

        if otype is None:
            return result
        elif type(otype) is str:
            return tuple(m for m in result if fOtype(m) == otype)
        else:
            if type(otype) not in SET_TYPES:
                otype = set(otype)
            return tuple(m for m in result if fOtype(m) in otype)

    def n(self, n, otype=None):
        """Produces an ordered tuple of *next* nodes.

        One node is next to an other if the first slot of the former just follows
        the last slot of the latter.

        Parameters
        ----------

        node: integer
            The node whose next nodes will be delivered.
        otype: string or set of strings
            See `Locality`.

        Returns
        -------
        tuple of integer
            The tuple nodes is sorted in the canonical order (`tf.core.nodes`),
            left and big embeddees before right and small embeddees.
        """

        if n <= 0:
            return tuple()
        Fotype = self.api.F.otype
        fOtype = Fotype.v
        maxNode = Fotype.maxNode
        maxSlot = Fotype.maxSlot
        if n == maxSlot:
            return tuple()
        if n > maxNode:
            return tuple()

        Eoslots = self.api.E.oslots.data
        (firstNode, lastNode) = self.api.C.boundary.data

        myNext = n + 1 if n < maxSlot else Eoslots[n - maxSlot - 1][-1] + 1
        if myNext > maxSlot:
            return ()

        result = (myNext,) + tuple(firstNode[myNext - 1])

        if otype is None:
            return result
        elif type(otype) is str:
            return tuple(m for m in result if fOtype(m) == otype)
        else:
            if type(otype) not in SET_TYPES:
                otype = set(otype)
            return tuple(m for m in result if fOtype(m) in otype)

Classes

class Locality (api)

Methods by which you can navigate from a node to its neighbourhood.

Neighbours are: nodes that have slots in common, embedders and embeddees, previous and next siblings.

L

The Locality API is exposed as L or Locality.

otype parameter

In all of the following L-functions, if the otype parameter is passed, the result is filtered and only nodes with otype=nodeType or otype in nodeTypes are retained.

otype can be a string (a single node type) or a (frozen)set of node types.

Results of the L. functions are tuples, not single nodes

Even if an L-function returns a single node, it is packed in a tuple. So to get the node itself, you have to index the tuple:

  L.u(node)[0]

Locality and node types

When using Nodes.sortNodes() and the L methods, note the following.

Suppose you have node types verse and sentence, and usually a verse has multiple sentences, but not vice versa. Then you expect that

  • L.d(verseNode) will contain sentence nodes,
  • L.d(sentenceNode) will not contain verse nodes.

But if there is a verse with exactly one sentence, and both have exactly the same words, then that is a case where:

  • L.d(verseNode) will contain sentenceNode,
  • L.d(sentenceNode) will contain verseNode.
Expand source code Browse git
class Locality:
    """Methods by which you can navigate from a node to its neighbourhood.

    Neighbours are: nodes that have slots in common, embedders and embeddees,
    previous and next siblings.

    !!! note "L"
        The Locality API is exposed as `L` or `Locality`.

    !!! note "`otype` parameter"
        In all of the following `L`-functions, if the `otype` parameter is passed,
        the result is filtered and only nodes with
        `otype=nodeType` or `otype in nodeTypes` are retained.

        `otype` can be a string (a single node type)  or a (frozen)set of node types.

    !!! caution "Results of the `L.` functions are tuples, not single nodes"
          Even if an `L`-function returns a single node, it is packed in a *tuple*.
          So to get the node itself, you have to index the tuple:

              L.u(node)[0]

    !!! caution "Locality and node types"
        When using `tf.core.nodes.Nodes.sortNodes` and the `L` methods,
        note the following.

        Suppose you have node types `verse` and `sentence`, and usually a
        verse has multiple sentences, but not vice versa. Then you expect that

        *   `L.d(verseNode)` will contain sentence nodes,
        *   `L.d(sentenceNode)` will **not** contain verse nodes.

        But if there is a verse with exactly one sentence, and both have exactly the
        same words, then that is a case where:

        *   `L.d(verseNode)` will contain `sentenceNode`,
        *   `L.d(sentenceNode)` will contain `verseNode`.
      """

    def __init__(self, api):
        self.api = api

    def i(self, n, otype=None):
        """Produces an ordered tuple of *intersecting* nodes

        Intersecting nodes of a node have slots in common with that node.

        Parameters
        ----------

        node: dict
            The node whose intersectors will be delivered.
        otype: string or set of strings
            See `Locality`.

        Returns
        -------
        tuple of integer
            The tuple nodes is sorted in the
            canonical order (`tf.core.nodes`).

            The result never includes `n` itself.
            But other nodes linked to the same set of slots as `n`
            may count as intersector nodes.

            Slots themselves can be intersectors.
        """

        api = self.api
        N = api.N
        Fotype = api.F.otype
        maxSlot = Fotype.maxSlot
        if n <= maxSlot:
            return tuple()
        maxNode = Fotype.maxNode
        if n > maxNode:
            return tuple()
        sortNodes = N.sortNodes
        if not otype:
            otype = set(Fotype.all)
        elif type(otype) is str:
            otype = {otype}
        elif type(otype) not in SET_TYPES:
            otype = set(otype)

        slotType = Fotype.slotType
        fOtype = Fotype.v
        levUp = api.C.levUp.data
        Eoslots = api.E.oslots

        slots = Eoslots.s(n)
        result = set()
        for slot in slots:
            result |= {m for m in levUp[slot - 1] if fOtype(m) in otype}
            if slotType in otype:
                result.add(slot)
        return sortNodes(result - {n})

    def u(self, n, otype=None):
        """Produces an ordered tuple of *upward* nodes.

        Upward nodes of a node are embedders of that node.
        One node embeds an other if all slots of the latter are contained in the slots
        of the former.

        Parameters
        ----------

        node: integer
            The node whose embedders will be delivered.
        otype: string or set of strings
            See `Locality`.

        Returns
        -------
        tuple of integer
            The tuple nodes is sorted in the canonical order (`tf.core.nodes`),
            but *reversed*: right and small embedders before left and big embedders.

            The result never includes `n` itself.
            But other nodes linked to the same set of slots as `n`
            may count as embedder nodes.

            Slots themselves are never embedders.
        """

        if n <= 0:
            return tuple()
        Fotype = self.api.F.otype
        maxNode = Fotype.maxNode
        if n > maxNode:
            return tuple()
        fOtype = Fotype.v
        levUp = self.api.C.levUp.data

        if otype is None:
            return tuple(levUp[n - 1])
        elif type(otype) is str:
            return tuple(m for m in levUp[n - 1] if fOtype(m) == otype)
        else:
            if type(otype) not in SET_TYPES:
                otype = set(otype)
            return tuple(m for m in levUp[n - 1] if fOtype(m) in otype)

    def d(self, n, otype=None):
        """Produces an ordered tuple of *downward* nodes.

        Downward nodes of a node are embedded nodes in that node.
        One node is embedded in an other if all slots of the former are contained
        in the slots of the latter.

        Parameters
        ----------

        node: integer
            The node whose embeddees will be delivered.
        otype: string or set of strings
            See `Locality`.

        Returns
        -------
        tuple of integer
            The tuple nodes is sorted in the canonical order (`tf.core.nodes`),
            left and big embeddees before right and small embeddees.

            The result never includes `n` itself.
            But other nodes linked to the same set of slots as `n`
            may count as embeddee nodes.
        """

        Fotype = self.api.F.otype
        fOtype = Fotype.v
        maxSlot = Fotype.maxSlot
        if n <= maxSlot:
            return tuple()
        maxNode = Fotype.maxNode
        if n > maxNode:
            return tuple()

        Eoslots = self.api.E.oslots
        Crank = self.api.C.rank.data
        levDown = self.api.C.levDown.data
        slotType = Fotype.slotType
        if otype is None:
            return tuple(
                sorted(
                    levDown[n - maxSlot - 1] + Eoslots.s(n), key=lambda m: Crank[m - 1],
                )
            )
        elif otype == slotType:
            return tuple(sorted(Eoslots.s(n), key=lambda m: Crank[m - 1]))
        elif type(otype) is str:
            return tuple(m for m in levDown[n - maxSlot - 1] if fOtype(m) == otype)
        else:
            if type(otype) not in SET_TYPES:
                otype = set(otype)
            return tuple(
                sorted(
                    (
                        k
                        for k in levDown[n - maxSlot - 1] + Eoslots.s(n)
                        if fOtype(k) in otype
                    ),
                    key=lambda m: Crank[m - 1],
                )
            )

    def p(self, n, otype=None):
        """Produces an ordered tuple of *previous* nodes.

        One node is previous to an other if the last slot of the former just precedes
        the first slots of the latter.

        Parameters
        ----------

        node: integer
            The node whose previous nodes will be delivered.
        otype: string or set of strings
            See `Locality`.

        Returns
        -------
        tuple of integer
            The tuple nodes is sorted in the canonical order (`tf.core.nodes`),
            but *reversed*: right and small embedders before left and big embedders.
        """

        if n <= 1:
            return tuple()
        Fotype = self.api.F.otype
        fOtype = Fotype.v
        maxNode = Fotype.maxNode
        if n > maxNode:
            return tuple()

        maxSlot = Fotype.maxSlot
        Eoslots = self.api.E.oslots.data
        (firstNode, lastNode) = self.api.C.boundary.data

        myPrev = n - 1 if n <= maxSlot else Eoslots[n - maxSlot - 1][0] - 1
        if myPrev <= 0:
            return ()

        result = tuple(lastNode[myPrev - 1]) + (myPrev,)

        if otype is None:
            return result
        elif type(otype) is str:
            return tuple(m for m in result if fOtype(m) == otype)
        else:
            if type(otype) not in SET_TYPES:
                otype = set(otype)
            return tuple(m for m in result if fOtype(m) in otype)

    def n(self, n, otype=None):
        """Produces an ordered tuple of *next* nodes.

        One node is next to an other if the first slot of the former just follows
        the last slot of the latter.

        Parameters
        ----------

        node: integer
            The node whose next nodes will be delivered.
        otype: string or set of strings
            See `Locality`.

        Returns
        -------
        tuple of integer
            The tuple nodes is sorted in the canonical order (`tf.core.nodes`),
            left and big embeddees before right and small embeddees.
        """

        if n <= 0:
            return tuple()
        Fotype = self.api.F.otype
        fOtype = Fotype.v
        maxNode = Fotype.maxNode
        maxSlot = Fotype.maxSlot
        if n == maxSlot:
            return tuple()
        if n > maxNode:
            return tuple()

        Eoslots = self.api.E.oslots.data
        (firstNode, lastNode) = self.api.C.boundary.data

        myNext = n + 1 if n < maxSlot else Eoslots[n - maxSlot - 1][-1] + 1
        if myNext > maxSlot:
            return ()

        result = (myNext,) + tuple(firstNode[myNext - 1])

        if otype is None:
            return result
        elif type(otype) is str:
            return tuple(m for m in result if fOtype(m) == otype)
        else:
            if type(otype) not in SET_TYPES:
                otype = set(otype)
            return tuple(m for m in result if fOtype(m) in otype)

Methods

def d(self, n, otype=None)

Produces an ordered tuple of downward nodes.

Downward nodes of a node are embedded nodes in that node. One node is embedded in an other if all slots of the former are contained in the slots of the latter.

Parameters

node : integer
The node whose embeddees will be delivered.
otype : string or set of strings
See Locality.

Returns

tuple of integer

The tuple nodes is sorted in the canonical order (tf.core.nodes), left and big embeddees before right and small embeddees.

The result never includes n itself. But other nodes linked to the same set of slots as n may count as embeddee nodes.

def i(self, n, otype=None)

Produces an ordered tuple of intersecting nodes

Intersecting nodes of a node have slots in common with that node.

Parameters

node : dict
The node whose intersectors will be delivered.
otype : string or set of strings
See Locality.

Returns

tuple of integer

The tuple nodes is sorted in the canonical order (tf.core.nodes).

The result never includes n itself. But other nodes linked to the same set of slots as n may count as intersector nodes.

Slots themselves can be intersectors.

def n(self, n, otype=None)

Produces an ordered tuple of next nodes.

One node is next to an other if the first slot of the former just follows the last slot of the latter.

Parameters

node : integer
The node whose next nodes will be delivered.
otype : string or set of strings
See Locality.

Returns

tuple of integer
The tuple nodes is sorted in the canonical order (tf.core.nodes), left and big embeddees before right and small embeddees.
def p(self, n, otype=None)

Produces an ordered tuple of previous nodes.

One node is previous to an other if the last slot of the former just precedes the first slots of the latter.

Parameters

node : integer
The node whose previous nodes will be delivered.
otype : string or set of strings
See Locality.

Returns

tuple of integer
The tuple nodes is sorted in the canonical order (tf.core.nodes), but reversed: right and small embedders before left and big embedders.
def u(self, n, otype=None)

Produces an ordered tuple of upward nodes.

Upward nodes of a node are embedders of that node. One node embeds an other if all slots of the latter are contained in the slots of the former.

Parameters

node : integer
The node whose embedders will be delivered.
otype : string or set of strings
See Locality.

Returns

tuple of integer

The tuple nodes is sorted in the canonical order (tf.core.nodes), but reversed: right and small embedders before left and big embedders.

The result never includes n itself. But other nodes linked to the same set of slots as n may count as embedder nodes.

Slots themselves are never embedders.