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