func (g *GreedyGraphMem) ToString() (string, error) {
	var sb strings.Builder
	var expanded = make(map[string]bool)
	todo := newStringList()
	tips, err := g.Tips()
	if err != nil {
		return "", err
	}
	for _, tip := range tips {
		todo.push(tip)
	}
	for todo.size() > 0 {
		node, ok := todo.shift()
		if !ok {
			return "", fmt.Errorf("No element removed from front of list")
		}
		if !expanded[node] {
			parents, err := g.Parents(node)
			if err != nil {
				return "", err
			}
			size := len(parents)
			if size > 0 {
				sort.Strings(parents)
				for _, p := range parents {
					todo.push(p)
					sb.WriteString(node + "->" + p + "\n")
				}
			} else {
				sb.WriteString(node + "\n")
			}
		}
		expanded[node] = true
	}
	return sb.String(), nil
}
ToString returns a string representation of the graph
package phantom
import (
	"fmt"
	"sort"
	"strings"
)
type kChain struct {
	chain *OrderedStringSet
	minHeight int
}
type GreedyGraphMem struct {
	k int
	children map[string]*OrderedStringSet
	parents map[string]*OrderedStringSet
	height map[string]int
	coloringTip string
	coloringChain *OrderedStringSet
	mainKChain *kChain
	bluePastOrder *ChainMap
	redPastOrder *ChainMap
	blueAntiPastOrder *OrderMap
	redAntiPastOrder *OrderMap
	uncoloredUnorderedAntiPast *OrderMap
	pastOrder *ChainMap
	antiPastOrder *ChainMap
	antiPast *ChainMap
	coloringOrder *ChainMap
	order *ChainMap
	blueCount map[string]int
	coloringParents map[string]string
	blueDiffPastOrder map[string]OrderMap
	redDiffPastOrder map[string]OrderMap
	selfOrder map[string]int
}
func (g *GreedyGraphMem) Add(id string, parents []string) (bool, error) {
	ok, err := g.AddNode(id)
	if err != nil {
		return ok, err
	}
	if len(parents) > 0 {
		ok, err := g.AddMultiEdge(id, parents)
		if err != nil {
			return ok, err
		}
	}
	_, err = g.Height(id)
	if err != nil {
		return ok, err
	}
	g.updateColoringIncrementally(id, parents)
	g.updateTopologicalOrderIncrementally(id)
	return ok, nil
}
func (g *GreedyGraphMem) AddNode(id string) (bool, error) {
	_, ok := g.parents[id]
	if ok {
		return false, nil
	}
	g.parents[id] = NewOrderedStringSet()
	g.children[id] = NewOrderedStringSet()
	return true, nil
}
func (g *GreedyGraphMem) AddEdge(a, b string) (bool, error) {
	_, err := g.AddNode(a)
	if err != nil {
		return false, err
	}
	_, err = g.AddNode(b)
	if err != nil {
		return false, err
	}
	parentsOfA, ok := g.parents[a]
	if !ok {
		return false, fmt.Errorf("failed to add edge from %s to %s; no node entry for %s", a, b, a)
	}
	childrenOfB, ok := g.children[b]
	if !ok {
		return false, fmt.Errorf("failed to add edge from %s to %s; no node entry for %s", a, b, b)
	}
	if parentsOfA.Contains(b) {
		return false, nil
	}
	parentsOfA.Add(b)
	childrenOfB.Add(a)
	return true, nil
}
func (g *GreedyGraphMem) AddMultiEdge(a string, parents []string) (bool, error) {
	added := 0
	for _, p := range parents {
		ok, err := g.AddEdge(a, p)
		if err != nil {
			return false, err
		}
		if ok {
			added += 1
		}
	}
	return added == len(parents), nil
}
func (g *GreedyGraphMem) RemoveEdge(a, b string) bool {
	var inParent, inChild bool
	parents, ok := g.parents[a]
	if ok {
		inParent = parents.Contains(b)
		parents.Remove(b)
	}
	children, ok := g.children[b]
	if ok {
		inChild = children.Contains(a)
		children.Remove(a)
	}
	return inParent && inChild
}
func (g *GreedyGraphMem) RemoveTip(id string) error {
	children, ok := g.children[id]
	if !ok {
		return nil
	}
	if children.Size() > 0 {
		return nil
	}
	if g.coloringTip != "" && id == g.coloringTip {
		tips, err := g.Tips()
		if err != nil {
			return fmt.Errorf("failed to remove node %s: %s", id, err)
		}
		otherTips := make([]string, 0)
		for _, t := range tips {
			if t != id {
				otherTips = append(otherTips, t)
			}
		}
		if len(otherTips) > 0 {
			bluest := g.getBluest(otherTips...)
			g.coloringTip = bluest
			g.mainKChain = g.getKChain(bluest)
		} else {
			parents, ok := g.parents[id]
			if !ok {
				return fmt.Errorf("failed to remove node %s; missing entry for node in g.parents", id)
			}
			if parents.Size() > 0 {
				bluest := g.getBluest(parents.Elements()...)
				g.coloringTip = bluest
				g.mainKChain = g.getKChain(bluest)
			}
		}
	}
	delete(g.children, id)
	delete(g.parents, id)
	for _, children := range g.children {
		if children.Contains(id) {
			children.Remove(id)
		}
	}
	for _, parents := range g.parents {
		if parents.Contains(id) {
			parents.Remove(id)
		}
	}
	delete(g.height, id)
	g.uncoloredUnorderedAntiPast.Remove(id)
	delete(g.selfOrder, id)
	delete(g.coloringParents, id)
	delete(g.blueCount, id)
	g.redPastOrder.Remove(id)
	g.bluePastOrder.Remove(id)
	g.redAntiPastOrder.Remove(id)
	g.blueAntiPastOrder.Remove(id)
	delete(g.redDiffPastOrder, id)
	delete(g.blueDiffPastOrder, id)
	return nil
}
func (g *GreedyGraphMem) NodeExists(id string) (bool, error) {
	_, ok := g.parents[id]
	return ok, nil
}
func (g *GreedyGraphMem) Nodes() []string {
	nodes := make([]string, len(g.parents))
	index := 0
	for n := range g.parents {
		nodes[index] = n
		index += 1
	}
	return nodes
}
func (g *GreedyGraphMem) Tips() ([]string, error) {
	tips := make([]string, 0)
	for node, children := range g.children {
		if children.Size() == 0 {
			tips = append(tips, node)
		}
	}
	sort.Strings(tips)
	return tips, nil
}
func (g *GreedyGraphMem) TipDiff(subTips []string) ([]string, error) {
	subTipPast := make(map[string]struct{})
	for _, tip := range subTips {
		subTipPast[tip] = keyExists
		past, err := g.Past(tip)
		if err != nil {
			return nil, err
		}
		for _, id := range past {
			_, ok := subTipPast[id]
			if !ok {
				subTipPast[id] = keyExists
			}
		}
	}
	diff := make([]string, 0)
	for _, n := range g.Nodes() {
		_, ok := subTipPast[n]
		if !ok {
			diff = append(diff, n)
		}
	}
	return diff, nil
}
func (g *GreedyGraphMem) Parents(id string) ([]string, error) {
	parents, ok := g.parents[id]
	if !ok {
		return nil, fmt.Errorf("missing node %s", id)
	}
	return parents.Elements(), nil
}
func (g *GreedyGraphMem) Past(id string) ([]string, error) {
	parents, ok := g.parents[id]
	if !ok {
		return nil, fmt.Errorf("missing node %s", id)
	}
	if parents.Size() == 0 {
		return []string{}, nil
	}
	var past = parents.Clone()
	todo := newStringList()
	for _, p := range parents.Elements() {
		todo.push(p)
	}
	for todo.size() > 0 {
		node, ok := todo.shift()
		if !ok {
			return nil, fmt.Errorf("todo size > 0 but nothing shifted")
		}
		past.Add(node)
		parents, ok := g.parents[node]
		if !ok {
			continue
		}
		for _, p := range parents.Elements() {
			todo.push(p)
		}
	}
	return past.Elements(), nil
}
func (g *GreedyGraphMem) Height(id string) (int, error) {
	height, ok := g.height[id]
	if ok {
		return height, nil
	}
	parents, ok := g.parents[id]
	if !ok {
		return -1, fmt.Errorf("missing node %s", id)
	}
	if parents.Size() == 0 {
		return 0, nil
	}
	var maxHeight int
	for _, p := range parents.Elements() {
		pHeight, err := g.Height(p)
		if err != nil {
			return -1, fmt.Errorf("failed to get height of %s when evaluating parent %s: %s", id, p, err)
		}
		if pHeight > maxHeight {
			maxHeight = pHeight
		}
	}
	var nodeHeight = maxHeight + 1
	g.height[id] = nodeHeight
	return nodeHeight, nil
}
func (g *GreedyGraphMem) Order() ([]string, error) {
	var ordered = NewOrderedStringSet()
	var coloring = g.getColoring()
	var getTopologicalOrder func([]string, string) ([]string, error)
	getTopologicalOrder = func(leaves []string, coloringParent string) ([]string, error) {
		var leafSet = NewOrderedStringSet(leaves...)
		leafSet = leafSet.Difference(ordered)
		if leafSet.Size() == 0 {
			return nil, nil
		}
		blueLeafSet := leafSet.Intersection(coloring)
		var blueLeaves = blueLeafSet.Elements()
		sort.Strings(blueLeaves)
		redLeafSet := leafSet.Difference(blueLeafSet)
		var redLeaves = redLeafSet.Elements()
		sort.Strings(redLeaves)
		toSort := make([]string, 0)
		if coloringParent != "" {
			toSort = append(toSort, coloringParent)
		}
		toSort = append(toSort, blueLeaves...)
		toSort = append(toSort, redLeaves...)
		var topologicalOrder = NewOrderedStringSet()
		for _, leaf := range toSort {
			ordered.Add(leaf)
			parents, err := g.Parents(leaf)
			if err != nil {
				return nil, err
			}
			var leafOrder []string
			leafColoringParent, ok := g.coloringParents[leaf]
			if ok {
				leafOrder, err = getTopologicalOrder(parents, leafColoringParent)
			} else {
				leafOrder, err = getTopologicalOrder(parents, "")
			}
			leafOrder = append(leafOrder, leaf)
			for _, n := range leafOrder {
				topologicalOrder.Add(n)
			}
		}
		return topologicalOrder.Elements(), nil
	}
	tips, err := g.Tips()
	if err != nil {
		return nil, err
	}
	var order []string
	if g.coloringTip != "" {
		order, err = getTopologicalOrder(tips, g.coloringTip)
	} else {
		order, err = getTopologicalOrder(tips, "")
	}
	if err != nil {
		return nil, err
	}
	return order, nil
}
func (g *GreedyGraphMem) ColoringOrder() (*OrderedStringSet, error) {
	return g.coloringOrder.Keys(), nil
}