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  }