def _encode_penman(self, g, top=None):
        """
        Walk graph g and find a spanning dag, then serialize the result.

        First, depth-first traversal of preferred orientations (whether
        true or inverted) to create graph p.

        If any triples remain, select the first remaining triple whose
        source in the dispreferred orientation exists in p, where
        'first' is determined by the order of inserted nodes (i.e. a
        topological sort). Add this triple, then repeat the depth-first
        traversal of preferred orientations from its target. Repeat
        until no triples remain, or raise an error if there are no
        candidates in the dispreferred orientation (which likely means
        the graph is disconnected).
        """
        if top is None:
            top = g.top
        remaining = set(g.triples())
        variables = g.variables()
        store = defaultdict(lambda: ([], []))  # (preferred, dispreferred)
        for t in g.triples():
            if t.inverted:
                store[t.target][0].append(t)
                store[t.source][1].append(Triple(*t, inverted=False))
            else:
                store[t.source][0].append(t)
                store[t.target][1].append(Triple(*t, inverted=True))

        p = defaultdict(list)
        topolist = [top]

        def _update(t):
            src, tgt = (t[2], t[0]) if t.inverted else (t[0], t[2])
            p[src].append(t)
            remaining.remove(t)
            if tgt in variables and t.relation != self.TYPE_REL:
                topolist.append(tgt)
                return tgt
            return None

        def _explore_preferred(src):
            ts = store.get(src, ([], []))[0]
            for t in ts:
                if t in remaining:
                    tgt = _update(t)
                    if tgt is not None:
                        _explore_preferred(tgt)
            ts[:] = []  # clear explored list

        _explore_preferred(top)

        while remaining:
            flip_candidates = [store.get(v, ([],[]))[1] for v in topolist]
            for fc in flip_candidates:
                fc[:] = [c for c in fc if c in remaining]  # clear superfluous
            if not any(len(fc) > 0 for fc in flip_candidates):
                raise EncodeError('Invalid graph; possibly disconnected.')
            c = next(c for fc in flip_candidates for c in fc)
            tgt = _update(c)
            if tgt is not None:
                _explore_preferred(tgt)

        return self._layout(p, top, 0, set())
Walk graph g and find a spanning dag, then serialize the result.

        First, depth-first traversal of preferred orientations (whether
        true or inverted) to create graph p.

        If any triples remain, select the first remaining triple whose
        source in the dispreferred orientation exists in p, where
        'first' is determined by the order of inserted nodes (i.e. a
        topological sort). Add this triple, then repeat the depth-first
        traversal of preferred orientations from its target. Repeat
        until no triples remain, or raise an error if there are no
        candidates in the dispreferred orientation (which likely means
        the graph is disconnected).