# Path: penman/exceptions.py
# class GraphError(PenmanError):
#     """Raised on invalid graph structures or operations."""
# 
# Path: penman/types.py

# 
# Path: penman/epigraph.py
# class Epidatum(object):


from typing import (Union, Optional, Mapping, List, Dict, Set, NamedTuple)
from collections import defaultdict
from penman.exceptions import GraphError
from penman.types import (
    Variable,
    Constant,
    Role,
    Target,
    BasicTriple,
    Triples,
)
from penman.epigraph import Epidata
import copy
        """
        top = self._top
        if top is None and len(self.triples) > 0:
            top = self.triples[0][0]  # implicit top
        return top

    @top.setter
    def top(self, top: Union[Variable, None]):
        if top is not None and top not in self.variables():
            raise GraphError('top must be a valid node')
        self._top = top  # check if top is valid variable?

    def variables(self) -> Set[Variable]:
        """
        Return the set of variables (nonterminal node identifiers).
        """
        vs = set(src for src, _, _ in self.triples)
        if self._top is not None:
            vs.add(self._top)
        return vs

    def instances(self) -> List[Instance]:
        """
        Return instances (concept triples).
        """
        return [Instance(*t)
                for t in self._filter_triples(None, CONCEPT_ROLE, None)]

    def edges(self,
              source: Optional[Variable] = None,

# Path: penman/exceptions.py
# class GraphError(PenmanError):
#     """Raised on invalid graph structures or operations."""
# 
# Path: penman/types.py

# 
# Path: penman/epigraph.py
# class Epidatum(object):


# Path: penman/graph.py
from typing import (Union, Optional, Mapping, List, Dict, Set, NamedTuple)
from collections import defaultdict
from penman.exceptions import GraphError
from penman.types import (
    Variable,
    Constant,
    Role,
    Target,
    BasicTriple,
    Triples,
)
from penman.epigraph import Epidata
import copy

        """
        top = self._top
        if top is None and len(self.triples) > 0:
            top = self.triples[0][0]  # implicit top
        return top

    @top.setter
    def top(self, top: Union[Variable, None]):
        if top is not None and top not in self.variables():
            raise GraphError('top must be a valid node')
        self._top = top  # check if top is valid variable?

    def variables(self) -> Set[Variable]:
        """
        Return the set of variables (nonterminal node identifiers).
        """
        vs = set(src for src, _, _ in self.triples)
        if self._top is not None:
            vs.add(self._top)
        return vs

    def instances(self) -> List[Instance]:
        """
        Return instances (concept triples).
        """
        return [Instance(*t)
                for t in self._filter_triples(None, CONCEPT_ROLE, None)]

    def edges(self,
              source: Optional[Variable] = None,

              role: Role = None,