// Kruskal generates a minimum spanning tree of g by greedy tree coalescence, placing // the result in the destination, dst. If the edge weights of g are distinct // it will be the unique minimum spanning tree of g. The destination is not cleared // first. The weight of the minimum spanning tree is returned. If g is not connected, // a minimum spanning forest will be constructed in dst and the sum of minimum // spanning tree weights will be returned. func Kruskal(dst graph.UndirectedBuilder, g UndirectedWeightLister) float64 { edges := g.Edges() ascend := make([]simple.Edge, 0, len(edges)) for _, e := range edges { u := e.From() v := e.To() w, ok := g.Weight(u, v) if !ok { panic("kruskal: unexpected invalid weight") } ascend = append(ascend, simple.Edge{F: u, T: v, W: w}) } sort.Sort(byWeight(ascend)) ds := newDisjointSet() for _, node := range g.Nodes() { ds.makeSet(node.ID()) } var w float64 for _, e := range ascend { if s1, s2 := ds.find(e.From().ID()), ds.find(e.To().ID()); s1 != s2 { ds.union(s1, s2) dst.SetEdge(e) w += e.Weight() } } return w }
// Prim generates a minimum spanning tree of g by greedy tree extension, placing // the result in the destination, dst. If the edge weights of g are distinct // it will be the unique minimum spanning tree of g. The destination is not cleared // first. The weight of the minimum spanning tree is returned. If g is not connected, // a minimum spanning forest will be constructed in dst and the sum of minimum // spanning tree weights will be returned. func Prim(dst graph.UndirectedBuilder, g UndirectedWeighter) float64 { nodes := g.Nodes() if len(nodes) == 0 { return 0 } q := &primQueue{ indexOf: make(map[int]int, len(nodes)-1), nodes: make([]simple.Edge, 0, len(nodes)-1), } for _, u := range nodes[1:] { heap.Push(q, simple.Edge{F: u, W: math.Inf(1)}) } u := nodes[0] for _, v := range g.From(u) { w, ok := g.Weight(u, v) if !ok { panic("prim: unexpected invalid weight") } q.update(v, u, w) } var w float64 for q.Len() > 0 { e := heap.Pop(q).(simple.Edge) if e.To() != nil && g.HasEdgeBetween(e.From(), e.To()) { dst.SetEdge(e) w += e.Weight() } u = e.From() for _, n := range g.From(u) { if key, ok := q.key(n); ok { w, ok := g.Weight(u, n) if !ok { panic("prim: unexpected invalid weight") } if w < key { q.update(n, u, w) } } } } return w }
// 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 }
// TunableClusteringScaleFree 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. The edges are formed as a triad with probability, p. // If src is not nil it is used as the random source, otherwise rand.Float64 and // rand.Intn are used. // // The algorithm is essentially as described in http://arxiv.org/abs/cond-mat/0110452. func TunableClusteringScaleFree(dst graph.UndirectedBuilder, n, m int, p float64, src *rand.Rand) error { if p < 0 || p > 1 { return fmt.Errorf("gen: bad probability: p=%v", p) } if n <= m { return fmt.Errorf("gen: n <= m: n=%v m=%d", n, m) } var ( rnd func() float64 rndN func(int) int ) if src == nil { rnd = rand.Float64 rndN = rand.Intn } else { rnd = src.Float64 rndN = src.Intn } // 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++ { var u int pa: for i := 0; i < m; i++ { // Triad formation. if i != 0 && rnd() < p { for _, w := range permute(dst.From(simple.Node(u)), rndN) { wid := w.ID() if wid == v || dst.HasEdgeBetween(w, simple.Node(v)) { continue } dst.SetEdge(simple.Edge{F: w, T: simple.Node(v), W: 1}) wt[wid]++ wt[v]++ continue pa } } // Preferential attachment. for { var ok bool u, ok = ws.Take() if !ok { return errors.New("gen: depleted distribution") } if u == v || dst.HasEdgeBetween(simple.Node(u), simple.Node(v)) { continue } dst.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v), W: 1}) wt[u]++ wt[v]++ break } } ws.ReweightAll(wt) } return nil }