github.com/gopherd/gonum@v0.0.4/graph/graphs/gen/duplication.go (about) 1 // Copyright ©2015 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package gen 6 7 import ( 8 "fmt" 9 "math" 10 11 "math/rand" 12 13 "github.com/gopherd/gonum/graph" 14 "github.com/gopherd/gonum/graph/internal/ordered" 15 ) 16 17 // UndirectedMutator is an undirected graph builder that can remove edges. 18 type UndirectedMutator interface { 19 graph.UndirectedBuilder 20 graph.EdgeRemover 21 } 22 23 // Duplication constructs a graph in the destination, dst, of order n. New nodes 24 // are created by duplicating an existing node and all its edges. Each new edge is 25 // deleted with probability delta. Additional edges are added between the new node 26 // and existing nodes with probability alpha/|V|. An exception to this addition 27 // rule is made for the parent node when sigma is not NaN; in this case an edge is 28 // created with probability sigma. With the exception of the sigma parameter, this 29 // corresponds to the completely correlated case in doi:10.1016/S0022-5193(03)00028-6. 30 // If src is not nil it is used as the random source, otherwise rand.Float64 is used. 31 func Duplication(dst UndirectedMutator, n int, delta, alpha, sigma float64, src rand.Source) error { 32 // As described in doi:10.1016/S0022-5193(03)00028-6 but 33 // also clarified in doi:10.1186/gb-2007-8-4-r51. 34 35 if delta < 0 || delta > 1 { 36 return fmt.Errorf("gen: bad delta: delta=%v", delta) 37 } 38 if alpha <= 0 || alpha > 1 { 39 return fmt.Errorf("gen: bad alpha: alpha=%v", alpha) 40 } 41 if sigma < 0 || sigma > 1 { 42 return fmt.Errorf("gen: bad sigma: sigma=%v", sigma) 43 } 44 45 var ( 46 rnd func() float64 47 rndN func(int) int 48 ) 49 if src == nil { 50 rnd = rand.Float64 51 rndN = rand.Intn 52 } else { 53 r := rand.New(src) 54 rnd = r.Float64 55 rndN = r.Intn 56 } 57 58 nodes := graph.NodesOf(dst.Nodes()) 59 ordered.ByID(nodes) 60 if len(nodes) == 0 { 61 n-- 62 u := dst.NewNode() 63 dst.AddNode(u) 64 nodes = append(nodes, u) 65 } 66 for i := 0; i < n; i++ { 67 u := nodes[rndN(len(nodes))] 68 d := dst.NewNode() 69 did := d.ID() 70 71 // Add the duplicate node. 72 dst.AddNode(d) 73 74 // Loop until we have connectivity 75 // into the rest of the graph. 76 for { 77 // Add edges to parent's neighbours. 78 to := graph.NodesOf(dst.From(u.ID())) 79 ordered.ByID(to) 80 for _, v := range to { 81 vid := v.ID() 82 if rnd() < delta || dst.HasEdgeBetween(vid, did) { 83 continue 84 } 85 if vid < did { 86 dst.SetEdge(dst.NewEdge(v, d)) 87 } else { 88 dst.SetEdge(dst.NewEdge(d, v)) 89 } 90 } 91 92 // Add edges to old nodes. 93 scaledAlpha := alpha / float64(len(nodes)) 94 for _, v := range nodes { 95 uid := u.ID() 96 vid := v.ID() 97 switch vid { 98 case uid: 99 if !math.IsNaN(sigma) { 100 if i == 0 || rnd() < sigma { 101 if vid < did { 102 dst.SetEdge(dst.NewEdge(v, d)) 103 } else { 104 dst.SetEdge(dst.NewEdge(d, v)) 105 } 106 } 107 continue 108 } 109 fallthrough 110 default: 111 if rnd() < scaledAlpha && !dst.HasEdgeBetween(vid, did) { 112 if vid < did { 113 dst.SetEdge(dst.NewEdge(v, d)) 114 } else { 115 dst.SetEdge(dst.NewEdge(d, v)) 116 } 117 } 118 } 119 } 120 121 if dst.From(did).Len() != 0 { 122 break 123 } 124 } 125 126 nodes = append(nodes, d) 127 } 128 129 return nil 130 }