// edgeNodesFor returns the pair of nodes for the ith edge in a simple // undirected graph. The pair is returned such that w.ID < v.ID. func edgeNodesFor(i int) (v, w simple.Node) { // This is an algebraic simplification of the expressions described // on p3 of http://algo.uni-konstanz.de/publications/bb-eglrn-05.pdf v = simple.Node(0.5 + math.Sqrt(float64(1+8*i))/2) w = simple.Node(i) - v*(v-1)/2 return v, w }
// Builds a BFS tree (as a directed graph) from the given graph and start node. func BFSTree(g graph.Graph, start graph.Node) *simple.DirectedGraph { if !g.Has(start) { panic(fmt.Sprintf("BFSTree: Start node %r not in graph %r", start, g)) } ret := simple.NewDirectedGraph(0.0, math.Inf(1)) seen := make(map[int]bool) q := queue.New() q.Add(start) ret.AddNode(simple.Node(start.ID())) for q.Length() > 0 { node := q.Peek().(graph.Node) q.Remove() for _, neighbor := range g.From(node) { if !seen[neighbor.ID()] { seen[neighbor.ID()] = true ret.AddNode(simple.Node(neighbor.ID())) ret.SetEdge(simple.Edge{F: simple.Node(node.ID()), T: simple.Node(neighbor.ID()), W: g.Edge(node, neighbor).Weight()}) q.Add(neighbor) } } } return ret }
func TestCommunityQ(t *testing.T) { for _, test := range communityQTests { g := simple.NewUndirectedGraph(0, 0) 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), W: 1}) } } for _, structure := range test.structures { communities := make([][]graph.Node, len(structure.memberships)) for i, c := range structure.memberships { for n := range c { communities[i] = append(communities[i], simple.Node(n)) } } got := Q(g, communities, structure.resolution) if !floats.EqualWithinAbsOrRel(got, structure.want, structure.tol, structure.tol) && math.IsNaN(got) != math.IsNaN(structure.want) { for _, c := range communities { sort.Sort(ordered.ByID(c)) } t.Errorf("unexpected Q value for %q %v: got: %v want: %v", test.name, communities, got, structure.want) } } } }
func TestBetweennessWeighted(t *testing.T) { for i, test := range betweennessTests { g := simple.NewUndirectedGraph(0, math.Inf(1)) 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), W: 1}) } } p, ok := path.FloydWarshall(g) if !ok { t.Errorf("unexpected negative cycle in test %d", i) continue } got := BetweennessWeighted(g, p) prec := 1 - int(math.Log10(test.wantTol)) for n := range test.g { gotN, gotOK := got[n] wantN, wantOK := test.want[n] if gotOK != wantOK { t.Errorf("unexpected betweenness existence for test %d, node %c", i, n+'A') } if !floats.EqualWithinAbsOrRel(gotN, wantN, test.wantTol, test.wantTol) { t.Errorf("unexpected betweenness result for test %d:\ngot: %v\nwant:%v", i, orderedFloats(got, prec), orderedFloats(test.want, prec)) break } } } }
func TestDepthFirst(t *testing.T) { for i, test := range depthFirstTests { g := simple.NewUndirectedGraph(0, math.Inf(1)) 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)}) } } w := DepthFirst{ EdgeFilter: test.edge, } var got []int final := w.Walk(g, test.from, func(n graph.Node) bool { if test.until != nil && test.until(n) { return true } got = append(got, n.ID()) return false }) if !test.final[final] { t.Errorf("unexepected final node for test %d:\ngot: %v\nwant: %v", i, final, test.final) } sort.Ints(got) if test.want != nil && !reflect.DeepEqual(got, test.want) { t.Errorf("unexepected DFS traversed nodes for test %d:\ngot: %v\nwant: %v", i, got, test.want) } } }
func TestHITS(t *testing.T) { for i, test := range hitsTests { g := simple.NewDirectedGraph(0, math.Inf(1)) 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)}) } } got := HITS(g, test.tol) prec := 1 - int(math.Log10(test.wantTol)) for n := range test.g { if !floats.EqualWithinAbsOrRel(got[n].Hub, test.want[n].Hub, test.wantTol, test.wantTol) { t.Errorf("unexpected HITS result for test %d:\ngot: %v\nwant:%v", i, orderedHubAuth(got, prec), orderedHubAuth(test.want, prec)) break } if !floats.EqualWithinAbsOrRel(got[n].Authority, test.want[n].Authority, test.wantTol, test.wantTol) { t.Errorf("unexpected HITS result for test %d:\ngot: %v\nwant:%v", i, orderedHubAuth(got, prec), orderedHubAuth(test.want, prec)) break } } } }
func TestSort(t *testing.T) { for i, test := range tarjanTests { g := simple.NewDirectedGraph(0, math.Inf(1)) 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)}) } } sorted, err := Sort(g) var gotSortedLen int for _, n := range sorted { if n != nil { gotSortedLen++ } } if gotSortedLen != test.sortedLength { t.Errorf("unexpected number of sortable nodes for test %d: got:%d want:%d", i, gotSortedLen, test.sortedLength) } if err == nil != test.sortable { t.Errorf("unexpected sortability for test %d: got error: %v want: nil-error=%t", i, err, test.sortable) } if err != nil && len(err.(Unorderable)) != test.unorderableLength { t.Errorf("unexpected number of unorderable nodes for test %d: got:%d want:%d", i, len(err.(Unorderable)), test.unorderableLength) } } }
func TestTarjanSCC(t *testing.T) { for i, test := range tarjanTests { g := simple.NewDirectedGraph(0, math.Inf(1)) 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)}) } } 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 TestAStar(t *testing.T) { for _, test := range aStarTests { pt, _ := AStar(simple.Node(test.s), simple.Node(test.t), test.g, test.heuristic) p, cost := pt.To(simple.Node(test.t)) if !topo.IsPathIn(test.g, p) { t.Error("got path that is not path in input graph for %q", test.name) } bfp, ok := BellmanFordFrom(simple.Node(test.s), test.g) if !ok { t.Fatalf("unexpected negative cycle in %q", test.name) } if want := bfp.WeightTo(simple.Node(test.t)); cost != want { t.Errorf("unexpected cost for %q: got:%v want:%v", test.name, cost, want) } var got = make([]int, 0, len(p)) for _, n := range p { got = append(got, n.ID()) } if test.wantPath != nil && !reflect.DeepEqual(got, test.wantPath) { t.Errorf("unexpected result for %q:\ngot: %v\nwant:%v", test.name, got, test.wantPath) } } }
func TestBronKerbosch(t *testing.T) { for i, test := range bronKerboschTests { g := simple.NewUndirectedGraph(0, math.Inf(1)) 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)}) } } cliques := 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(ordered.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(ordered.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 TestEdgeBetweenness(t *testing.T) { for i, test := range betweennessTests { g := simple.NewUndirectedGraph(0, math.Inf(1)) 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 { // Weight omitted to show weight-independence. g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v), W: 0}) } } got := EdgeBetweenness(g) prec := 1 - int(math.Log10(test.wantTol)) outer: for u := range test.g { for v := range test.g { wantQ, gotOK := got[[2]int{u, v}] gotQ, wantOK := test.wantEdges[[2]int{u, v}] if gotOK != wantOK { t.Errorf("unexpected betweenness result for test %d, edge (%c,%c)", i, u+'A', v+'A') } if !floats.EqualWithinAbsOrRel(gotQ, wantQ, test.wantTol, test.wantTol) { t.Errorf("unexpected betweenness result for test %d:\ngot: %v\nwant:%v", i, orderedPairFloats(got, prec), orderedPairFloats(test.wantEdges, prec)) break outer } } } } }
// Gnm constructs a graph in the destination, dst, of order n and size m. If src is not // nil it is used as the random source, otherwise rand.Float64 is used. The graph is // constructed in O(m) expected time for m ≤ (n choose 2)/2. func Gnm(dst GraphBuilder, n, m int, src *rand.Rand) error { if m == 0 { return nil } hasEdge := dst.HasEdgeBetween d, isDirected := dst.(graph.Directed) if isDirected { m /= 2 hasEdge = d.HasEdgeFromTo } nChoose2 := (n - 1) * n / 2 if m < 0 || m > nChoose2 { return fmt.Errorf("gen: bad size: m=%d", m) } var rnd func(int) int if src == nil { rnd = rand.Intn } else { rnd = src.Intn } for i := 0; i < n; i++ { if !dst.Has(simple.Node(i)) { dst.AddNode(simple.Node(i)) } } // Add forward edges for all graphs. for i := 0; i < m; i++ { for { v, w := edgeNodesFor(rnd(nChoose2)) e := simple.Edge{F: w, T: v, W: 1} if !hasEdge(e.F, e.T) { dst.SetEdge(e) break } } } // Add backward edges for directed graphs. if !isDirected { return nil } for i := 0; i < m; i++ { for { v, w := edgeNodesFor(rnd(nChoose2)) e := simple.Edge{F: v, T: w, W: 1} if !hasEdge(e.F, e.T) { dst.SetEdge(e) break } } } return nil }
func benchmarkAStarHeuristic(b *testing.B, g graph.Undirected, h Heuristic) { var expanded int for i := 0; i < b.N; i++ { _, expanded = AStar(simple.Node(0), simple.Node(1), g, h) } if expanded == 0 { b.Fatal("unexpected number of expanded nodes") } }
func undirectedEdgeAttrGraphFrom(g []set, attr map[edge][]Attribute) graph.Graph { dg := simple.NewUndirectedGraph(0, math.Inf(1)) for u, e := range g { for v := range e { dg.SetEdge(attrEdge{from: simple.Node(u), to: simple.Node(v), attr: attr[edge{from: u, to: v}]}) } } return dg }
func undirectedGraphFrom(g []set) graph.Graph { dg := simple.NewUndirectedGraph(0, math.Inf(1)) for u, e := range g { for v := range e { dg.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } return dg }
func TestReduceQConsistency(t *testing.T) { tests: for _, test := range communityQTests { g := simple.NewUndirectedGraph(0, 0) 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), W: 1}) } } for _, structure := range test.structures { if math.IsNaN(structure.want) { continue tests } communities := make([][]graph.Node, len(structure.memberships)) for i, c := range structure.memberships { for n := range c { communities[i] = append(communities[i], simple.Node(n)) } sort.Sort(ordered.ByID(communities[i])) } gQ := Q(g, communities, structure.resolution) gQnull := Q(g, nil, 1) cg0 := reduce(g, nil) cg0Qnull := Q(cg0, cg0.Structure(), 1) if !floats.EqualWithinAbsOrRel(gQnull, cg0Qnull, structure.tol, structure.tol) { t.Errorf("disgagreement between null Q from method: %v and function: %v", cg0Qnull, gQnull) } cg0Q := Q(cg0, communities, structure.resolution) if !floats.EqualWithinAbsOrRel(gQ, cg0Q, structure.tol, structure.tol) { t.Errorf("unexpected Q result after initial conversion: got: %v want :%v", gQ, cg0Q) } cg1 := reduce(cg0, communities) cg1Q := Q(cg1, cg1.Structure(), structure.resolution) if !floats.EqualWithinAbsOrRel(gQ, cg1Q, structure.tol, structure.tol) { t.Errorf("unexpected Q result after initial condensation: got: %v want :%v", gQ, cg1Q) } } } }
// Nodes returns all the nodes in the grid. func (l *LimitedVisionGrid) Nodes() []graph.Node { nodes := make([]graph.Node, 0, len(l.Grid.open)) for id := range l.Grid.open { nodes = append(nodes, simple.Node(id)) } return nodes }
// Nodes returns all the open nodes in the grid if AllVisible is // false, otherwise all nodes are returned. func (g *Grid) Nodes() []graph.Node { var nodes []graph.Node for id, ok := range g.open { if ok || g.AllVisible { nodes = append(nodes, simple.Node(id)) } } return nodes }
func undirectedStructuredGraphFrom(c []edge, g ...[]set) graph.Graph { s := &structuredGraph{UndirectedGraph: simple.NewUndirectedGraph(0, math.Inf(1))} var base int for i, sg := range g { sub := simple.NewUndirectedGraph(0, math.Inf(1)) for u, e := range sg { for v := range e { ce := simple.Edge{F: simple.Node(u + base), T: simple.Node(v + base)} sub.SetEdge(ce) } } s.sub = append(s.sub, namedGraph{id: i, Graph: sub}) base += len(sg) } for _, e := range c { s.SetEdge(simple.Edge{F: simple.Node(e.from), T: simple.Node(e.to)}) } return s }
func TestNonContiguous(t *testing.T) { g := simple.NewUndirectedGraph(0, 0) for _, e := range []simple.Edge{ {F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(4), T: simple.Node(5), W: 1}, } { g.SetEdge(e) } func() { defer func() { r := recover() if r != nil { t.Error("unexpected panic with non-contiguous ID range") } }() Louvain(g, 1, nil) }() }
func TestWalkAll(t *testing.T) { for i, test := range walkAllTests { g := simple.NewUndirectedGraph(0, math.Inf(1)) for u, e := range test.g { if !g.Has(simple.Node(u)) { g.AddNode(simple.Node(u)) } for v := range e { if !g.Has(simple.Node(v)) { g.AddNode(simple.Node(v)) } g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } type walker interface { WalkAll(g graph.Undirected, before, after func(), during func(graph.Node)) } for _, w := range []walker{ &BreadthFirst{}, &DepthFirst{}, } { var ( c []graph.Node cc [][]graph.Node ) switch w := w.(type) { case *BreadthFirst: w.EdgeFilter = test.edge case *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(ordered.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 := simple.NewUndirectedGraph(0, math.Inf(1)) for u, e := range test.g { if !g.Has(simple.Node(u)) { g.AddNode(simple.Node(u)) } for v := range e { if !g.Has(simple.Node(v)) { g.AddNode(simple.Node(v)) } g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) } } cc := 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(ordered.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 TestMoveLocal(t *testing.T) { for _, test := range localMoveTests { g := simple.NewUndirectedGraph(0, 0) 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), W: 1}) } } for _, structure := range test.structures { communities := make([][]graph.Node, len(structure.memberships)) for i, c := range structure.memberships { for n := range c { communities[i] = append(communities[i], simple.Node(n)) } sort.Sort(ordered.ByID(communities[i])) } r := reduce(reduce(g, nil), communities) l := newLocalMover(r, r.communities, structure.resolution) for _, n := range structure.targetNodes { dQ, dst, src := l.deltaQ(n) if dQ > 0 { before := Q(r, l.communities, structure.resolution) l.move(dst, src) after := Q(r, l.communities, structure.resolution) want := after - before if !floats.EqualWithinAbsOrRel(dQ, want, structure.tol, structure.tol) { t.Errorf("unexpected deltaQ: got: %v want: %v", dQ, want) } } } } } }
// PreferentialAttachment constructs a graph in the destination, dst, of order n. // The graph is constructed successively starting from an m order graph with one // node having degree m-1. At each iteration of graph addition, one node is added // with m additional edges joining existing nodes with probability proportional // to the nodes' degrees. If src is not nil it is used as the random source, // otherwise rand.Float64 is used. // // The algorithm is essentially as described in http://arxiv.org/abs/cond-mat/0110452 // after 10.1126/science.286.5439.509. func PreferentialAttachment(dst graph.UndirectedBuilder, n, m int, src *rand.Rand) error { if n <= m { return fmt.Errorf("gen: n <= m: n=%v m=%d", n, m) } // Initial condition. wt := make([]float64, n) for u := 0; u < m; u++ { if !dst.Has(simple.Node(u)) { dst.AddNode(simple.Node(u)) } // We need to give equal probability for // adding the first generation of edges. wt[u] = 1 } ws := sample.NewWeighted(wt, src) for i := range wt { // These weights will organically grow // after the first growth iteration. wt[i] = 0 } // Growth. for v := m; v < n; v++ { for i := 0; i < m; i++ { // Preferential attachment. u, ok := ws.Take() if !ok { return errors.New("gen: depleted distribution") } dst.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v), W: 1}) wt[u]++ wt[v]++ } ws.ReweightAll(wt) } return nil }
func TestVertexOrdering(t *testing.T) { for i, test := range vOrderTests { g := simple.NewUndirectedGraph(0, math.Inf(1)) 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)}) } } order, core := VertexOrdering(g) if len(core)-1 != test.wantK { t.Errorf("unexpected value of k for test %d: got: %d want: %d", i, len(core)-1, test.wantK) } var offset int for k, want := range test.wantCore { sort.Ints(want) got := make([]int, len(want)) for j, n := range order[len(order)-len(want)-offset : len(order)-offset] { got[j] = n.ID() } sort.Ints(got) if !reflect.DeepEqual(got, want) { t.Errorf("unexpected %d-core for test %d:\ngot: %v\nwant:%v", got, test.wantCore) } for j, n := range core[k] { got[j] = n.ID() } sort.Ints(got) if !reflect.DeepEqual(got, want) { t.Errorf("unexpected %d-core for test %d:\ngot: %v\nwant:%v", got, test.wantCore) } offset += len(want) } } }
func TestIsPath(t *testing.T) { dg := simple.NewDirectedGraph(0, math.Inf(1)) if !IsPathIn(dg, nil) { t.Error("IsPath returns false on nil path") } p := []graph.Node{simple.Node(0)} if IsPathIn(dg, p) { t.Error("IsPath returns true on nonexistant node") } dg.AddNode(p[0]) if !IsPathIn(dg, p) { t.Error("IsPath returns false on single-length path with existing node") } p = append(p, simple.Node(1)) dg.AddNode(p[1]) if IsPathIn(dg, p) { t.Error("IsPath returns true on bad path of length 2") } dg.SetEdge(simple.Edge{F: p[0], T: p[1], W: 1}) if !IsPathIn(dg, p) { t.Error("IsPath returns false on correct path of length 2") } p[0], p[1] = p[1], p[0] if IsPathIn(dg, p) { t.Error("IsPath erroneously returns true for a reverse path") } p = []graph.Node{p[1], p[0], simple.Node(2)} dg.SetEdge(simple.Edge{F: p[1], T: p[2], W: 1}) if !IsPathIn(dg, p) { t.Error("IsPath does not find a correct path for path > 2 nodes") } ug := simple.NewUndirectedGraph(0, math.Inf(1)) ug.SetEdge(simple.Edge{F: p[1], T: p[0], W: 1}) ug.SetEdge(simple.Edge{F: p[1], T: p[2], W: 1}) if !IsPathIn(dg, p) { t.Error("IsPath does not correctly account for undirected behavior") } }
func TestPageRankSparse(t *testing.T) { for i, test := range pageRankTests { g := simple.NewDirectedGraph(0, math.Inf(1)) 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)}) } } got := PageRankSparse(g, test.damp, test.tol) prec := 1 - int(math.Log10(test.wantTol)) for n := range test.g { if !floats.EqualWithinAbsOrRel(got[n], test.want[n], test.wantTol, test.wantTol) { t.Errorf("unexpected PageRank result for test %d:\ngot: %v\nwant:%v", i, orderedFloats(got, prec), orderedFloats(test.want, prec)) break } } } }
func TestBreadthFirst(t *testing.T) { for i, test := range breadthFirstTests { g := simple.NewUndirectedGraph(0, math.Inf(1)) 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)}) } } w := BreadthFirst{ EdgeFilter: test.edge, } var got [][]int final := w.Walk(g, test.from, func(n graph.Node, d int) bool { if test.until != nil && test.until(n, d) { return true } if d >= len(got) { got = append(got, []int(nil)) } got[d] = append(got[d], n.ID()) return false }) if !test.final[final] { t.Errorf("unexepected final node for test %d:\ngot: %v\nwant: %v", i, final, test.final) } for _, l := range got { sort.Ints(l) } if !reflect.DeepEqual(got, test.want) { t.Errorf("unexepected BFS level structure for test %d:\ngot: %v\nwant: %v", i, got, test.want) } } }
func undirectedSubGraphFrom(g []set, s map[int][]set) graph.Graph { var base int subs := make(map[int]subGraph) for i, sg := range s { sub := simple.NewUndirectedGraph(0, math.Inf(1)) for u, e := range sg { for v := range e { ce := simple.Edge{F: simple.Node(u + base), T: simple.Node(v + base)} sub.SetEdge(ce) } } subs[i] = subGraph{id: i, Graph: sub} base += len(sg) } dg := simple.NewUndirectedGraph(0, math.Inf(1)) for u, e := range g { var nu graph.Node if sg, ok := subs[u]; ok { sg.id += base nu = sg } else { nu = simple.Node(u + base) } for v := range e { var nv graph.Node if sg, ok := subs[v]; ok { sg.id += base nv = sg } else { nv = simple.Node(v + base) } dg.SetEdge(simple.Edge{F: nu, T: nv}) } } return dg }