func TestTarjanSCC(t *testing.T) { for i, test := range tarjanTests { g := concrete.NewDirectedGraph(0, math.Inf(1)) for u, e := range test.g { // Add nodes that are not defined by an edge. if !g.Has(concrete.Node(u)) { g.AddNode(concrete.Node(u)) } for v := range e { g.SetEdge(concrete.Edge{F: concrete.Node(u), T: concrete.Node(v)}) } } gotSCCs := TarjanSCC(g) // tarjan.strongconnect does range iteration over maps, // so sort SCC members to ensure consistent ordering. gotIDs := make([][]int, len(gotSCCs)) for i, scc := range gotSCCs { gotIDs[i] = make([]int, len(scc)) for j, id := range scc { gotIDs[i][j] = id.ID() } sort.Ints(gotIDs[i]) } for _, iv := range test.ambiguousOrder { sort.Sort(internal.BySliceValues(test.want[iv.start:iv.end])) sort.Sort(internal.BySliceValues(gotIDs[iv.start:iv.end])) } if !reflect.DeepEqual(gotIDs, test.want) { t.Errorf("unexpected Tarjan scc result for %d:\n\tgot:%v\n\twant:%v", i, gotIDs, test.want) } } }
func TestWalkAll(t *testing.T) { for i, test := range walkAllTests { g := concrete.NewGraph() for u, e := range test.g { if !g.Has(concrete.Node(u)) { g.AddNode(concrete.Node(u)) } for v := range e { if !g.Has(concrete.Node(v)) { g.AddNode(concrete.Node(v)) } g.SetEdge(concrete.Edge{F: concrete.Node(u), T: concrete.Node(v)}, 0) } } type walker interface { WalkAll(g graph.Undirected, before, after func(), during func(graph.Node)) } for _, w := range []walker{ &traverse.BreadthFirst{}, &traverse.DepthFirst{}, } { var ( c []graph.Node cc [][]graph.Node ) switch w := w.(type) { case *traverse.BreadthFirst: w.EdgeFilter = test.edge case *traverse.DepthFirst: w.EdgeFilter = test.edge default: panic(fmt.Sprintf("bad walker type: %T", w)) } during := func(n graph.Node) { c = append(c, n) } after := func() { cc = append(cc, []graph.Node(nil)) cc[len(cc)-1] = append(cc[len(cc)-1], c...) c = c[:0] } w.WalkAll(g, nil, after, during) got := make([][]int, len(cc)) for j, c := range cc { ids := make([]int, len(c)) for k, n := range c { ids[k] = n.ID() } sort.Ints(ids) got[j] = ids } sort.Sort(internal.BySliceValues(got)) if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected connected components for test %d using %T:\ngot: %v\nwant:%v", i, w, got, test.want) } } } }
func TestConnectedComponents(t *testing.T) { for i, test := range connectedComponentTests { g := concrete.NewGraph() for u, e := range test.g { if !g.Has(concrete.Node(u)) { g.AddNode(concrete.Node(u)) } for v := range e { if !g.Has(concrete.Node(v)) { g.AddNode(concrete.Node(v)) } g.SetEdge(concrete.Edge{F: concrete.Node(u), T: concrete.Node(v)}, 0) } } cc := topo.ConnectedComponents(g) got := make([][]int, len(cc)) for j, c := range cc { ids := make([]int, len(c)) for k, n := range c { ids[k] = n.ID() } sort.Ints(ids) got[j] = ids } sort.Sort(internal.BySliceValues(got)) if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected connected components for test %d %T:\ngot: %v\nwant:%v", i, g, got, test.want) } } }
func TestBronKerbosch(t *testing.T) { for i, test := range bronKerboschTests { g := concrete.NewGraph() for u, e := range test.g { // Add nodes that are not defined by an edge. if !g.Has(concrete.Node(u)) { g.AddNode(concrete.Node(u)) } for v := range e { g.SetEdge(concrete.Edge{F: concrete.Node(u), T: concrete.Node(v)}, 0) } } cliques := topo.BronKerbosch(g) got := make([][]int, len(cliques)) for j, c := range cliques { ids := make([]int, len(c)) for k, n := range c { ids[k] = n.ID() } sort.Ints(ids) got[j] = ids } sort.Sort(internal.BySliceValues(got)) if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected cliques for test %d:\ngot: %v\nwant:%v", i, got, test.want) } } }
func TestCyclesIn(t *testing.T) { for i, test := range cyclesInTests { g := simple.NewDirectedGraph(0, math.Inf(1)) g.AddNode(simple.Node(-10)) // Make sure we test graphs with sparse IDs. for u, e := range test.g { // Add nodes that are not defined by an edge. if !g.Has(simple.Node(u)) { g.AddNode(simple.Node(u)) } for v := range e { g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } cycles := CyclesIn(g) var got [][]int if cycles != nil { got = make([][]int, len(cycles)) } // johnson.circuit does range iteration over maps, // so sort to ensure consistent ordering. for j, c := range cycles { ids := make([]int, len(c)) for k, n := range c { ids[k] = n.ID() } got[j] = ids } sort.Sort(internal.BySliceValues(got)) if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected johnson result for %d:\n\tgot:%#v\n\twant:%#v", i, got, test.want) } } }
func TestDijkstraAllPaths(t *testing.T) { for _, test := range shortestPathTests { g := test.g() for _, e := range test.edges { g.SetEdge(e, e.Cost) } var ( pt path.AllShortest panicked bool ) func() { defer func() { panicked = recover() != nil }() pt = path.DijkstraAllPaths(g.(graph.Graph)) }() if panicked || test.negative { if !test.negative { t.Errorf("%q: unexpected panic", test.name) } if !panicked { t.Errorf("%q: expected panic for negative edge weight", test.name) } continue } // Check all random paths returned are OK. for i := 0; i < 10; i++ { p, weight, unique := pt.Between(test.query.From(), test.query.To()) if weight != test.weight { t.Errorf("%q: unexpected weight from Between: got:%f want:%f", test.name, weight, test.weight) } if weight := pt.Weight(test.query.From(), test.query.To()); weight != test.weight { t.Errorf("%q: unexpected weight from Weight: got:%f want:%f", test.name, weight, test.weight) } if unique != test.unique { t.Errorf("%q: unexpected number of paths: got: unique=%t want: unique=%t", test.name, unique, test.unique) } var got []int for _, n := range p { got = append(got, n.ID()) } ok := len(got) == 0 && len(test.want) == 0 for _, sp := range test.want { if reflect.DeepEqual(got, sp) { ok = true break } } if !ok { t.Errorf("%q: unexpected shortest path:\ngot: %v\nwant from:%v", test.name, p, test.want) } } np, weight, unique := pt.Between(test.none.From(), test.none.To()) if np != nil || !math.IsInf(weight, 1) || unique != false { t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f unique=%t\nwant:path=<nil> weight=+Inf unique=false", test.name, np, weight, unique) } paths, weight := pt.AllBetween(test.query.From(), test.query.To()) if weight != test.weight { t.Errorf("%q: unexpected weight from Between: got:%f want:%f", test.name, weight, test.weight) } var got [][]int if len(paths) != 0 { got = make([][]int, len(paths)) } for i, p := range paths { for _, v := range p { got[i] = append(got[i], v.ID()) } } sort.Sort(internal.BySliceValues(got)) if !reflect.DeepEqual(got, test.want) { t.Errorf("testing %q: unexpected shortest paths:\ngot: %v\nwant:%v", test.name, got, test.want) } nps, weight := pt.AllBetween(test.none.From(), test.none.To()) if nps != nil || !math.IsInf(weight, 1) { t.Errorf("%q: unexpected path:\ngot: paths=%v weight=%f\nwant:path=<nil> weight=+Inf", test.name, nps, weight) } } }
func TestJohnsonAllPaths(t *testing.T) { for _, test := range testgraphs.ShortestPathTests { g := test.Graph() for _, e := range test.Edges { g.SetEdge(e) } pt, ok := JohnsonAllPaths(g.(graph.Graph)) if test.HasNegativeCycle { if ok { t.Errorf("%q: expected negative cycle", test.Name) } continue } if !ok { t.Fatalf("%q: unexpected negative cycle", test.Name) } // Check all random paths returned are OK. for i := 0; i < 10; i++ { p, weight, unique := pt.Between(test.Query.From(), test.Query.To()) if weight != test.Weight { t.Errorf("%q: unexpected weight from Between: got:%f want:%f", test.Name, weight, test.Weight) } if weight := pt.Weight(test.Query.From(), test.Query.To()); weight != test.Weight { t.Errorf("%q: unexpected weight from Weight: got:%f want:%f", test.Name, weight, test.Weight) } if unique != test.HasUniquePath { t.Errorf("%q: unexpected number of paths: got: unique=%t want: unique=%t", test.Name, unique, test.HasUniquePath) } var got []int for _, n := range p { got = append(got, n.ID()) } ok := len(got) == 0 && len(test.WantPaths) == 0 for _, sp := range test.WantPaths { if reflect.DeepEqual(got, sp) { ok = true break } } if !ok { t.Errorf("%q: unexpected shortest path:\ngot: %v\nwant from:%v", test.Name, p, test.WantPaths) } } np, weight, unique := pt.Between(test.NoPathFor.From(), test.NoPathFor.To()) if np != nil || !math.IsInf(weight, 1) || unique != false { t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f unique=%t\nwant:path=<nil> weight=+Inf unique=false", test.Name, np, weight, unique) } paths, weight := pt.AllBetween(test.Query.From(), test.Query.To()) if weight != test.Weight { t.Errorf("%q: unexpected weight from Between: got:%f want:%f", test.Name, weight, test.Weight) } var got [][]int if len(paths) != 0 { got = make([][]int, len(paths)) } for i, p := range paths { for _, v := range p { got[i] = append(got[i], v.ID()) } } sort.Sort(internal.BySliceValues(got)) if !reflect.DeepEqual(got, test.WantPaths) { t.Errorf("testing %q: unexpected shortest paths:\ngot: %v\nwant:%v", test.Name, got, test.WantPaths) } nps, weight := pt.AllBetween(test.NoPathFor.From(), test.NoPathFor.To()) if nps != nil || !math.IsInf(weight, 1) { t.Errorf("%q: unexpected path:\ngot: paths=%v weight=%f\nwant:path=<nil> weight=+Inf", test.Name, nps, weight) } } }