compositional_graph_models/data.py
def _deserialize_binary_recurse(
    func: List[str],
    vars: List[str],
    function_vocab: Dict[str, int],
    token_vocab: Dict[str, int],
) -> dgl.DGLGraph:
    """
    Recursive helper function for `deserialize_binary`.

    Do not use this function directly; call `deserialize_binary` instead.

    Parameters
    ----------
    func
        Function symbols in the tree's preorder traversal. Modified in place.
    vars
        Variable symbols in the tree's preorder traversal. Modified in place.
    function_vocab
        Mapping from function names to indices.
    token_vocab
        Mapping from token names to indices.

    Returns
    -------
    DGLGraph
        A homogeneous graph representing the parseable prefix of the serialized tree.
    """
    if not func:
        raise ValueError(
            "Cannot deserialize an empty structure. Empty trees are serialized as '#'."
        )
    if len(func) != len(vars):
        raise ValueError("`func` and `vars` must have the same length.")

    node_function = func.pop(0)
    node_token = vars.pop(0)

    if node_function == "#":  # Base case: empty graph
        return dgl.graph(([], []))

    if node_token:
        node_function = LEAF_FUNCTION
    else:
        node_token = NONLEAF_TOKEN

    function_id = function_vocab[node_function]
    token_id = token_vocab[node_token]

    # Recursively collect left and right children
    left_subgraph = _deserialize_binary_recurse(func, vars, function_vocab, token_vocab)
    right_subgraph = _deserialize_binary_recurse(
        func, vars, function_vocab, token_vocab
    )

    right_root_idx = right_subgraph.num_nodes() - 1
    left_root_idx = right_root_idx + left_subgraph.num_nodes()
    root_idx = left_root_idx + 1

    if SIDE_FIELD in left_subgraph.ndata.keys():
        left_subgraph.ndata[SIDE_FIELD][:] = SIDE_LEFT
    if SIDE_FIELD in right_subgraph.ndata.keys():
        right_subgraph.ndata[SIDE_FIELD][:] = SIDE_RIGHT

    # Batch right child then left child. 
    # This enforces the node_ids to be labeled in reverse preorder traversal.
    graph = dgl.batch([right_subgraph, left_subgraph])
    graph.add_nodes(1)

    if root_idx == 0:  # Leaf node
        graph.ndata[FUNCTION_FIELD] = torch.tensor([function_id], dtype=torch.int64)
        graph.ndata[TOKEN_FIELD] = torch.tensor([token_id], dtype=torch.int64)
        graph.ndata[SIDE_FIELD] = torch.tensor([SIDE_ROOT], dtype=torch.int64)
    else:
        if left_subgraph.num_nodes() == 0:  # Right-unary
            graph.add_edges(right_root_idx, root_idx)
        elif right_subgraph.num_nodes() == 0:  # Left-unary
            graph.add_edges(left_root_idx, root_idx)
        else:  # Binary
            graph.add_edges([right_root_idx, left_root_idx], root_idx)

        graph.ndata[FUNCTION_FIELD][-1] = function_id
        graph.ndata[TOKEN_FIELD][-1] = token_id
        graph.ndata[SIDE_FIELD][-1] = SIDE_ROOT

    return graph

    Recursive helper function for `deserialize_binary`.

    Do not use this function directly; call `deserialize_binary` instead.

    Parameters
    ----------
    func
        Function symbols in the tree's preorder traversal. Modified in place.
    vars
        Variable symbols in the tree's preorder traversal. Modified in place.
    function_vocab
        Mapping from function names to indices.
    token_vocab
        Mapping from token names to indices.

    Returns
    -------
    DGLGraph
        A homogeneous graph representing the parseable prefix of the serialized tree.
    
Recursive helper function for `deserialize_binary`.
Do not use this function directly; call `deserialize_binary` instead.

Parameters

func
Function symbols in the tree's preorder traversal. Modified in place.
vars
Variable symbols in the tree's preorder traversal. Modified in place.
function_vocab
Mapping from function names to indices.
token_vocab
Mapping from token names to indices.

Returns

DGLGraph
A homogeneous graph representing the parseable prefix of the serialized tree.
Recursive helper function for ` deserialize_binary ` . Do not use this function directly ; call ` deserialize_binary ` instead . Parameters func Function symbols in the tree ' s preorder traversal . Modified in place . vars Variable symbols in the tree ' s preorder traversal . Modified in place . function_vocab Mapping from function names to indices . token_vocab Mapping from token names to indices . Returns DGLGraph A homogeneous graph representing the parseable prefix of the serialized tree .
def _deserialize_binary_recurse(
    func: List[str],
    vars: List[str],
    function_vocab: Dict[str, int],
    token_vocab: Dict[str, int],
) -> dgl.DGLGraph:
    if not func:
        raise ValueError(
            "Cannot deserialize an empty structure. Empty trees are serialized as '#'."
        )
    if len(func) != len(vars):
        raise ValueError("`func` and `vars` must have the same length.")
    node_function = func.pop(0)
    node_token = vars.pop(0)
    if node_function == "#":  
        return dgl.graph(([], []))
    if node_token:
        node_function = LEAF_FUNCTION
    else:
        node_token = NONLEAF_TOKEN
    function_id = function_vocab[node_function]
    token_id = token_vocab[node_token]
    left_subgraph = _deserialize_binary_recurse(func, vars, function_vocab, token_vocab)
    right_subgraph = _deserialize_binary_recurse(
        func, vars, function_vocab, token_vocab
    )
    right_root_idx = right_subgraph.num_nodes() - 1
    left_root_idx = right_root_idx + left_subgraph.num_nodes()
    root_idx = left_root_idx + 1
    if SIDE_FIELD in left_subgraph.ndata.keys():
        left_subgraph.ndata[SIDE_FIELD][:] = SIDE_LEFT
    if SIDE_FIELD in right_subgraph.ndata.keys():
        right_subgraph.ndata[SIDE_FIELD][:] = SIDE_RIGHT
    graph = dgl.batch([right_subgraph, left_subgraph])
    graph.add_nodes(1)
    if root_idx == 0:  
        graph.ndata[FUNCTION_FIELD] = torch.tensor([function_id], dtype=torch.int64)
        graph.ndata[TOKEN_FIELD] = torch.tensor([token_id], dtype=torch.int64)
        graph.ndata[SIDE_FIELD] = torch.tensor([SIDE_ROOT], dtype=torch.int64)
    else:
        if left_subgraph.num_nodes() == 0:  
            graph.add_edges(right_root_idx, root_idx)
        elif right_subgraph.num_nodes() == 0:  
            graph.add_edges(left_root_idx, root_idx)
        else:  
            graph.add_edges([right_root_idx, left_root_idx], root_idx)
        graph.ndata[FUNCTION_FIELD][-1] = function_id
        graph.ndata[TOKEN_FIELD][-1] = token_id
        graph.ndata[SIDE_FIELD][-1] = SIDE_ROOT
    return graph
def _deserialize_binary_recurse ( func : List [ str ] , vars : List [ str ] , function_vocab : Dict [ str , int ] , token_vocab : Dict [ str , int ] , ) -> dgl . DGLGraph : if not func : raise ValueError ( "Cannot deserialize an empty structure. Empty trees are serialized as '#'." ) if len ( func ) != len ( vars ) : raise ValueError ( "`func` and `vars` must have the same length." ) node_function = func . pop ( 0 ) node_token = vars . pop ( 0 ) if node_function == "#" : return dgl . graph ( ( [ ] , [ ] ) ) if node_token : node_function = LEAF_FUNCTION else : node_token = NONLEAF_TOKEN function_id = function_vocab [ node_function ] token_id = token_vocab [ node_token ] left_subgraph = _deserialize_binary_recurse ( func , vars , function_vocab , token_vocab ) right_subgraph = _deserialize_binary_recurse ( func , vars , function_vocab , token_vocab ) right_root_idx = right_subgraph . num_nodes ( ) - 1 left_root_idx = right_root_idx + left_subgraph . num_nodes ( ) root_idx = left_root_idx + 1 if SIDE_FIELD in left_subgraph . ndata . keys ( ) : left_subgraph . ndata [ SIDE_FIELD ] [ : ] = SIDE_LEFT if SIDE_FIELD in right_subgraph . ndata . keys ( ) : right_subgraph . ndata [ SIDE_FIELD ] [ : ] = SIDE_RIGHT graph = dgl . batch ( [ right_subgraph , left_subgraph ] ) graph . add_nodes ( 1 ) if root_idx == 0 : graph . ndata [ FUNCTION_FIELD ] = torch . tensor ( [ function_id ] , dtype = torch . int64 ) graph . ndata [ TOKEN_FIELD ] = torch . tensor ( [ token_id ] , dtype = torch . int64 ) graph . ndata [ SIDE_FIELD ] = torch . tensor ( [ SIDE_ROOT ] , dtype = torch . int64 ) else : if left_subgraph . num_nodes ( ) == 0 : graph . add_edges ( right_root_idx , root_idx ) elif right_subgraph . num_nodes ( ) == 0 : graph . add_edges ( left_root_idx , root_idx ) else : graph . add_edges ( [ right_root_idx , left_root_idx ] , root_idx ) graph . ndata [ FUNCTION_FIELD ] [ - 1 ] = function_id graph . ndata [ TOKEN_FIELD ] [ - 1 ] = token_id graph . ndata [ SIDE_FIELD ] [ - 1 ] = SIDE_ROOT return graph
Recursive helper function for `deserialize_binary`.
Recursive helper function for ` deserialize_binary ` .
"""
    Recursive helper function for `deserialize_binary`.

    Do not use this function directly; call `deserialize_binary` instead.

    Parameters
    ----------
    func
        Function symbols in the tree's preorder traversal. Modified in place.
    vars
        Variable symbols in the tree's preorder traversal. Modified in place.
    function_vocab
        Mapping from function names to indices.
    token_vocab
        Mapping from token names to indices.

    Returns
    -------
    DGLGraph
        A homogeneous graph representing the parseable prefix of the serialized tree.
    """ # Base case: empty graph # Recursively collect left and right children # Batch right child then left child.  # This enforces the node_ids to be labeled in reverse preorder traversal. # Leaf node # Right-unary # Left-unary # Binary
func
List[str]
vars
List[str]
function_vocab
Dict[str, int]
token_vocab
Dict[str, int]