diff --git a/go/pov/cmd/cmd b/go/pov/cmd/cmd index 3e1583d..e755c54 100755 Binary files a/go/pov/cmd/cmd and b/go/pov/cmd/cmd differ diff --git a/go/pov/cmd/main.go b/go/pov/cmd/main.go index 1066f1f..35249e1 100644 --- a/go/pov/cmd/main.go +++ b/go/pov/cmd/main.go @@ -8,19 +8,13 @@ import ( func main() { g := pov.New() - g.AddNode("parent") - g.AddArc("parent", "x") - g.AddArc("x", "sib-2") - g.AddArc("x", "sib-3") - g.AddArc("x", "sib-4") + g.AddNode("sibling") + g.AddNode("x") g.AddArc("parent", "sibling") - g.AddArc("sibling", "child-1") - g.AddArc("sibling", "child-2") - g.AddArc("sibling", "child-3") - g.AddArc("child-3", "grandchild-1") - g.AddArc("grandchild-1", "greatgrandchild-1") - pov.PrintGraph(g) + g.AddArc("parent", "x") fmt.Println("== Change Root to child-3 ==") - n := g.ChangeRoot("parent", "child-3") - pov.PrintGraph(n) + g.Print("parent") + n := g.ChangeRoot("parent", "x") + fmt.Println(n.ArcList()) + g.Print("x") } diff --git a/go/pov/pov.go b/go/pov/pov.go index c1df882..6d0740d 100644 --- a/go/pov/pov.go +++ b/go/pov/pov.go @@ -2,8 +2,14 @@ package pov const testVersion = 2 +// A Graph is just a collection of Nodes +type Node struct { + label string + connections []Node +} + type Graph struct { - leaves []Node + nodes []Node } func New() *Graph { @@ -11,124 +17,120 @@ func New() *Graph { } func (g *Graph) AddNode(lbl string) { - // Make sure that g doesn't already have node lbl - if g.getNode(lbl) != nil { - return + if g.getNode(lbl) == nil { + g.nodes = append(g.nodes, Node{label: lbl}) } - g.leaves = append(g.leaves, Node{label: lbl}) -} - -func (g *Graph) AddArc(fr, to string) { - if frN := g.getNode(fr); frN != nil { - frN.AddNode(to) - } -} - -func (g *Graph) ArcList() []string { - var arcList []string - for i := range g.leaves { - arcList = append(arcList, g.leaves[i].ArcList()...) - } - return arcList -} - -func (g *Graph) GetPath(fr, to string) []string { - if frN := g.getNode(fr); frN != nil { - return frN.GetPath(to) - } - return []string{} } func (g *Graph) getNode(lbl string) *Node { - for i := range g.leaves { - if r := g.leaves[i].getNode(lbl); r != nil { - return r + for i := range g.nodes { + if g.nodes[i].label == lbl { + return &g.nodes[i] } } return nil } -// Return a graph from 'newRoot's POV -func (g *Graph) ChangeRoot(oldRoot, newRoot string) *Graph { - root := g.getNode(newRoot) - if root == nil { - return nil +func (g *Graph) AddArc(fr, to string) { + frN := g.getNode(fr) + if frN == nil { + g.AddNode(fr) + frN = g.getNode(fr) } - ret := New() - //pth := g.GetPath(oldRoot, newRoot) - if root.parent != nil { - root.parent.removeLeaf(root.label) - root.parent.parent = root - root.addWholeNode(root.parent) - root.parent = nil + toN := g.getNode(to) + if g.getNode(to) == nil { + g.AddNode(to) + toN = g.getNode(to) } - ret.addWholeNode(root) - return ret + frN.connections = append(frN.connections, *toN) } -func (g *Graph) addWholeNode(n *Node) { - g.leaves = append(g.leaves, *n) -} - -type Node struct { - label string - leaves []Node - parent *Node -} - -func (n *Node) AddNode(lbl string) { - nn := Node{label: lbl, parent: n} - n.leaves = append(n.leaves, nn) -} - -func (n *Node) addWholeNode(nd *Node) { - n.leaves = append(n.leaves, *nd) -} - -func (n *Node) removeLeaf(lbl string) { - for i := range n.leaves { - if n.leaves[i].label == lbl { - n.leaves = append(n.leaves[:i], n.leaves[i+1:]...) - } - } -} - -func (n *Node) ArcList() []string { +func (g *Graph) ArcList() []string { var ret []string - for i := range n.leaves { - // Append this arc - ret = append(ret, n.label+" -> "+n.leaves[i].label) - // Append all sub-arcs - ret = append(ret, n.leaves[i].ArcList()...) + for _, k := range g.nodes { + for _, l := range k.connections { + ret = append(ret, k.label+" -> "+l.label) + } } return ret } -// GetPath returns a string slice of all leaves leading to 'to' -func (n *Node) GetPath(to string) []string { - ret := []string{n.label} - if n.label == to { - return ret +// getPath returns the shortest path from 'fr' to 'to' +func (g *Graph) getPath(fr, to string) []string { + if fr == to { + return []string{fr} } - for i := range n.leaves { - if toN := n.leaves[i].getNode(to); toN != nil { - // This is the leaf to follow - return append(ret, n.leaves[i].GetPath(to)...) + st := g.getNode(fr) + if st == nil { + // Couldn't find the starting node + return []string{} + } + var valPaths [][]string + for i := range st.connections { + if st.connections[i].label == to { + return []string{fr, to} + } + tst := g.getPath(st.connections[i].label, to) + if len(tst) > 0 { + valPaths = append(valPaths, tst) } } - // Couldn't get there - return []string{} + if len(valPaths) == 0 { + // No valid paths found + return []string{} + } + var ret []string + for i := range valPaths { + if len(valPaths[i]) < len(ret) || len(ret) == 0 { + ret = valPaths[i] + } + } + return ret } -// Returns the node with label lbl or nil -func (n *Node) getNode(lbl string) *Node { - if n.label == lbl { - return n +func (g *Graph) ChangeRoot(oldRoot, newRoot string) *Graph { + pth := g.getPath(oldRoot, newRoot) + if len(pth) == 0 { + // No valid path + return g } - for i := range n.leaves { - if r := n.leaves[i].getNode(lbl); r != nil { - return r + for oldRoot != newRoot { + // We just keep swapping the first two in pth until we're done + if len(pth) >= 2 { + n := g.getNode(pth[1]) + if n == nil { + return g + } + n = n.copy() + p := g.getNode(pth[0]) + if p == nil { + return g + } + p = p.copy() + p.removeConnection(n.label) + n.connections = append(n.connections, *p) + oldRoot = n.label } } - return nil + return g +} + +func (n *Node) removeConnection(to string) { + for i, k := range n.connections { + if k.label == to { + copy(n.connections[i:], n.connections[i+1:]) + n.connections[len(n.connections)-1] = Node{} + n.connections = n.connections[:len(n.connections)-1] + } + } +} + +// Node.copy() returns a new node that is a copy of this node +func (n *Node) copy() *Node { + ret := Node{label: n.label} + for _, k := range n.connections { + cp := k.copy() + ret.connections = append(ret.connections, *cp) + } + return &ret } diff --git a/go/pov/pov_helper.go b/go/pov/pov_helper.go index f01b6c9..3e4cae4 100644 --- a/go/pov/pov_helper.go +++ b/go/pov/pov_helper.go @@ -5,20 +5,19 @@ import ( "strings" ) -func PrintGraph(g *Graph) { - for i := range g.leaves { - PrintNode(&g.leaves[i], 1) +func (g *Graph) Print(root string) { + r := g.getNode(root) + if r != nil { + r.Print(0) + } else { + fmt.Println("Couldn't find root node:", root) } } -func PrintNode(n *Node, lvl int) { - fmt.Print(strings.Repeat(" ", lvl)) - if n.parent == nil { - fmt.Println("{label:", n.label, "}") - } else { - fmt.Println("{label:", n.label, ", parent:", n.parent.label, "}") - } - for i := range n.leaves { - PrintNode(&n.leaves[i], lvl+1) +func (n *Node) Print(ind int) { + pad := strings.Repeat(" ", ind) + fmt.Println(pad + n.label) + for i := range n.connections { + n.connections[i].Print(ind + 1) } } diff --git a/go/pov/pov_test.go b/go/pov/pov_test.go index 6d7872d..b2e22c2 100644 --- a/go/pov/pov_test.go +++ b/go/pov/pov_test.go @@ -1,6 +1,7 @@ package pov import ( + "fmt" "reflect" "sort" "testing" @@ -266,10 +267,13 @@ func TestTestVersion(t *testing.T) { } func TestConstruction(t *testing.T) { + fmt.Println("TestConstruction") for _, tc := range testCases { + fmt.Println("Starting test:", tc.description) got := tc.graph().ArcList() want := tc.arcStrings tc.testResult(got, want, "incorrect graph construction", t) + fmt.Println(" Test Passed:", tc.description) } } diff --git a/go/pov/tree/pov.go b/go/pov/tree/pov.go new file mode 100644 index 0000000..27b49a2 --- /dev/null +++ b/go/pov/tree/pov.go @@ -0,0 +1,206 @@ +package pov + +const testVersion = 2 + +type Graph struct { + leaves []Node + Iters int +} + +func New() *Graph { + return new(Graph) +} + +func (g *Graph) AddNode(lbl string) { + // Make sure that g doesn't already have node lbl + if g.getNode(lbl) != nil { + return + } + g.leaves = append(g.leaves, Node{label: lbl}) +} + +func (g *Graph) AddArc(fr, to string) { + var frN *Node + if frN = g.getNode(fr); frN == nil { + // frN doesn't exist yet... Create it and + // drop + frN = &Node{label: fr} + } + frN.AddNode(to) +} + +func (g *Graph) ArcList() []string { + var arcList []string + for i := range g.leaves { + arcList = append(arcList, g.leaves[i].ArcList()...) + } + return arcList +} + +func (g *Graph) GetPath(fr, to string) []string { + if frN := g.getNode(fr); frN != nil { + return frN.GetPath(to) + } + return []string{} +} + +func (g *Graph) getNode(lbl string) *Node { + for i := range g.leaves { + if r := g.leaves[i].getNode(lbl); r != nil { + return r + } + } + return nil +} + +// Return a graph from newRoot's POV +func (g *Graph) ChangeRoot(oldRoot, newRoot string) *Graph { + ret := g + pth := ret.GetPath(oldRoot, newRoot) + for oldRoot != newRoot { + // Swap the first two in pth + if len(pth) >= 2 { + n := ret.getNode(pth[1]) + if n == nil { + return ret + } + n = n.copy() + p := ret.getNode(pth[0]) + if p == nil { + return ret + } + p = p.copy() + if n != nil && p != nil { + p.removeLeaf(n.label) + n.addWholeNode(p) + if p.parent != nil { + n.parent = p.parent + p.parent = nil + } else { + n.parent = nil + } + } + ret = New() + ret.addWholeNode(n) + oldRoot = n.label + } + pth = ret.GetPath(oldRoot, newRoot) + } + return ret +} + +/* +// Return a graph from newRoot's POV +func (g *Graph) ChangeRoot(oldRoot, newRoot string) *Graph { + if oldRoot == newRoot { + return g + } + ret := New() + pth := g.GetPath(oldRoot, newRoot) + fmt.Println(pth) + // Swap the first two in pth + if len(pth) >= 2 { + fmt.Println("Swap ", pth[0], "<>", pth[1]) + n := g.getNode(pth[1]) + p := g.getNode(pth[0]) + if n != nil && p != nil { + p.removeLeaf(n.label) + n.addWholeNode(p) + if p.parent != nil { + n.parent = p.parent + p.parent = nil + } else { + n.parent = nil + } + } + ret.addWholeNode(n) + } + PrintGraph(ret) + if pth[1] != newRoot { + fmt.Println("Recurse:", pth[1], "<>", newRoot) + return ret + //return ret.ChangeRoot(pth[1], newRoot) + } else { + return ret + } +} +*/ + +func (g *Graph) addWholeNode(n *Node) { + g.leaves = append(g.leaves, *n) +} + +type Node struct { + label string + leaves []Node + parent *Node +} + +func (n *Node) copy() *Node { + // Returns a new node that is a copy of this node + ret := Node{label: n.label, parent: n.parent} + for _, k := range n.leaves { + cp := k.copy() + ret.leaves = append(ret.leaves, *cp) + } + return &ret +} + +func (n *Node) AddNode(lbl string) { + nn := Node{label: lbl, parent: n} + n.leaves = append(n.leaves, nn) +} + +func (n *Node) addWholeNode(nd *Node) { + n.leaves = append(n.leaves, *nd) +} + +func (n *Node) removeLeaf(lbl string) { + for i, k := range n.leaves { + if k.label == lbl { + copy(n.leaves[i:], n.leaves[i+1:]) + n.leaves[len(n.leaves)-1] = Node{} + n.leaves = n.leaves[:len(n.leaves)-1] + } + } +} + +func (n *Node) ArcList() []string { + var ret []string + for i := range n.leaves { + // Append this arc + ret = append(ret, n.label+" -> "+n.leaves[i].label) + // Append all sub-arcs + ret = append(ret, n.leaves[i].ArcList()...) + } + return ret +} + +// GetPath returns a string slice of all leaves leading to 'to' +func (n *Node) GetPath(to string) []string { + ret := []string{n.label} + if n.label == to { + return ret + } + for i := range n.leaves { + if toN := n.leaves[i].getNode(to); toN != nil { + // This is the leaf to follow + return append(ret, n.leaves[i].GetPath(to)...) + } + } + // Couldn't get there + return []string{} +} + +// Returns the node with label lbl or nil +func (n *Node) getNode(lbl string) *Node { + if n.label == lbl { + return n + } + for i := range n.leaves { + if r := n.leaves[i].getNode(lbl); r != nil { + return r + } + } + return nil +}