github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/graph/community/bisect_example_test.go (about)

     1  // Copyright ©2016 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 community_test
     6  
     7  import (
     8  	"fmt"
     9  	"log"
    10  	"sort"
    11  
    12  	"golang.org/x/exp/rand"
    13  
    14  	"github.com/jingcheng-WU/gonum/graph/community"
    15  	"github.com/jingcheng-WU/gonum/graph/internal/ordered"
    16  	"github.com/jingcheng-WU/gonum/graph/simple"
    17  )
    18  
    19  func ExampleProfile_simple() {
    20  	// Profile calls Modularize which implements the Louvain modularization algorithm.
    21  	// Since this is a randomized algorithm we use a defined random source to ensure
    22  	// consistency between test runs. In practice, results will not differ greatly
    23  	// between runs with different PRNG seeds.
    24  	src := rand.NewSource(1)
    25  
    26  	// Create dumbell graph:
    27  	//
    28  	//  0       4
    29  	//  |\     /|
    30  	//  | 2 - 3 |
    31  	//  |/     \|
    32  	//  1       5
    33  	//
    34  	g := simple.NewUndirectedGraph()
    35  	for u, e := range smallDumbell {
    36  		for v := range e {
    37  			g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
    38  		}
    39  	}
    40  
    41  	// Get the profile of internal node weight for resolutions
    42  	// between 0.1 and 10 using logarithmic bisection.
    43  	p, err := community.Profile(
    44  		community.ModularScore(g, community.Weight, 10, src),
    45  		true, 1e-3, 0.1, 10,
    46  	)
    47  	if err != nil {
    48  		log.Fatal(err)
    49  	}
    50  
    51  	// Print out each step with communities ordered.
    52  	for _, d := range p {
    53  		comm := d.Communities()
    54  		for _, c := range comm {
    55  			sort.Sort(ordered.ByID(c))
    56  		}
    57  		sort.Sort(ordered.BySliceIDs(comm))
    58  		fmt.Printf("Low:%.2v High:%.2v Score:%v Communities:%v Q=%.3v\n",
    59  			d.Low, d.High, d.Score, comm, community.Q(g, comm, d.Low))
    60  	}
    61  
    62  	// Output:
    63  	// Low:0.1 High:0.29 Score:14 Communities:[[0 1 2 3 4 5]] Q=0.9
    64  	// Low:0.29 High:2.3 Score:12 Communities:[[0 1 2] [3 4 5]] Q=0.714
    65  	// Low:2.3 High:3.5 Score:4 Communities:[[0 1] [2] [3] [4 5]] Q=-0.31
    66  	// Low:3.5 High:10 Score:0 Communities:[[0] [1] [2] [3] [4] [5]] Q=-0.607
    67  }
    68  
    69  // intset is an integer set.
    70  type intset map[int]struct{}
    71  
    72  func linksTo(i ...int) intset {
    73  	if len(i) == 0 {
    74  		return nil
    75  	}
    76  	s := make(intset)
    77  	for _, v := range i {
    78  		s[v] = struct{}{}
    79  	}
    80  	return s
    81  }
    82  
    83  var (
    84  	smallDumbell = []intset{
    85  		0: linksTo(1, 2),
    86  		1: linksTo(2),
    87  		2: linksTo(3),
    88  		3: linksTo(4, 5),
    89  		4: linksTo(5),
    90  		5: nil,
    91  	}
    92  
    93  	// http://www.slate.com/blogs/the_world_/2014/07/17/the_middle_east_friendship_chart.html
    94  	middleEast = struct{ friends, complicated, enemies []intset }{
    95  		// green cells
    96  		friends: []intset{
    97  			0:  nil,
    98  			1:  linksTo(5, 7, 9, 12),
    99  			2:  linksTo(11),
   100  			3:  linksTo(4, 5, 10),
   101  			4:  linksTo(3, 5, 10),
   102  			5:  linksTo(1, 3, 4, 8, 10, 12),
   103  			6:  nil,
   104  			7:  linksTo(1, 12),
   105  			8:  linksTo(5, 9, 11),
   106  			9:  linksTo(1, 8, 12),
   107  			10: linksTo(3, 4, 5),
   108  			11: linksTo(2, 8),
   109  			12: linksTo(1, 5, 7, 9),
   110  		},
   111  
   112  		// yellow cells
   113  		complicated: []intset{
   114  			0:  linksTo(2, 4),
   115  			1:  linksTo(4, 8),
   116  			2:  linksTo(0, 3, 4, 5, 8, 9),
   117  			3:  linksTo(2, 8, 11),
   118  			4:  linksTo(0, 1, 2, 8),
   119  			5:  linksTo(2),
   120  			6:  nil,
   121  			7:  linksTo(9, 11),
   122  			8:  linksTo(1, 2, 3, 4, 10, 12),
   123  			9:  linksTo(2, 7, 11),
   124  			10: linksTo(8),
   125  			11: linksTo(3, 7, 9, 12),
   126  			12: linksTo(8, 11),
   127  		},
   128  
   129  		// red cells
   130  		enemies: []intset{
   131  			0:  linksTo(1, 3, 5, 6, 7, 8, 9, 10, 11, 12),
   132  			1:  linksTo(0, 2, 3, 6, 10, 11),
   133  			2:  linksTo(1, 6, 7, 10, 12),
   134  			3:  linksTo(0, 1, 6, 7, 9, 12),
   135  			4:  linksTo(6, 7, 9, 11, 12),
   136  			5:  linksTo(0, 6, 7, 9, 11),
   137  			6:  linksTo(0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12),
   138  			7:  linksTo(0, 2, 3, 4, 5, 6, 8, 10),
   139  			8:  linksTo(0, 6, 7),
   140  			9:  linksTo(0, 3, 4, 5, 6, 10),
   141  			10: linksTo(0, 1, 2, 6, 7, 9, 11, 12),
   142  			11: linksTo(0, 1, 4, 5, 6, 10),
   143  			12: linksTo(0, 2, 3, 4, 6, 10),
   144  		},
   145  	}
   146  )
   147  
   148  var friends, enemies *simple.WeightedUndirectedGraph
   149  
   150  func init() {
   151  	friends = simple.NewWeightedUndirectedGraph(0, 0)
   152  	for u, e := range middleEast.friends {
   153  		// Ensure unconnected nodes are included.
   154  		if friends.Node(int64(u)) == nil {
   155  			friends.AddNode(simple.Node(u))
   156  		}
   157  		for v := range e {
   158  			friends.SetWeightedEdge(simple.WeightedEdge{F: simple.Node(u), T: simple.Node(v), W: 1})
   159  		}
   160  	}
   161  	enemies = simple.NewWeightedUndirectedGraph(0, 0)
   162  	for u, e := range middleEast.enemies {
   163  		// Ensure unconnected nodes are included.
   164  		if enemies.Node(int64(u)) == nil {
   165  			enemies.AddNode(simple.Node(u))
   166  		}
   167  		for v := range e {
   168  			enemies.SetWeightedEdge(simple.WeightedEdge{F: simple.Node(u), T: simple.Node(v), W: -1})
   169  		}
   170  	}
   171  }
   172  
   173  func ExampleProfile_multiplex() {
   174  	// Profile calls ModularizeMultiplex which implements the Louvain modularization
   175  	// algorithm. Since this is a randomized algorithm we use a defined random source
   176  	// to ensure consistency between test runs. In practice, results will not differ
   177  	// greatly between runs with different PRNG seeds.
   178  	src := rand.NewSource(1)
   179  
   180  	// The undirected graphs, friends and enemies, are the political relationships
   181  	// in the Middle East as described in the Slate article:
   182  	// http://www.slate.com/blogs/the_world_/2014/07/17/the_middle_east_friendship_chart.html
   183  	g, err := community.NewUndirectedLayers(friends, enemies)
   184  	if err != nil {
   185  		log.Fatal(err)
   186  	}
   187  	weights := []float64{1, -1}
   188  
   189  	// Get the profile of internal node weight for resolutions
   190  	// between 0.1 and 10 using logarithmic bisection.
   191  	p, err := community.Profile(
   192  		community.ModularMultiplexScore(g, weights, true, community.WeightMultiplex, 10, src),
   193  		true, 1e-3, 0.1, 10,
   194  	)
   195  	if err != nil {
   196  		log.Fatal(err)
   197  	}
   198  
   199  	// Print out each step with communities ordered.
   200  	for _, d := range p {
   201  		comm := d.Communities()
   202  		for _, c := range comm {
   203  			sort.Sort(ordered.ByID(c))
   204  		}
   205  		sort.Sort(ordered.BySliceIDs(comm))
   206  		fmt.Printf("Low:%.2v High:%.2v Score:%v Communities:%v Q=%.3v\n",
   207  			d.Low, d.High, d.Score, comm, community.QMultiplex(g, comm, weights, []float64{d.Low}))
   208  	}
   209  
   210  	// Output:
   211  	// Low:0.1 High:0.72 Score:26 Communities:[[0] [1 7 9 12] [2 8 11] [3 4 5 10] [6]] Q=[24.7 1.97]
   212  	// Low:0.72 High:1.1 Score:24 Communities:[[0 6] [1 7 9 12] [2 8 11] [3 4 5 10]] Q=[16.9 14.1]
   213  	// Low:1.1 High:1.2 Score:18 Communities:[[0 2 6 11] [1 7 9 12] [3 4 5 8 10]] Q=[9.16 25.1]
   214  	// Low:1.2 High:1.6 Score:10 Communities:[[0 3 4 5 6 10] [1 7 9 12] [2 8 11]] Q=[10.5 26.7]
   215  	// Low:1.6 High:1.6 Score:8 Communities:[[0 1 6 7 9 12] [2 8 11] [3 4 5 10]] Q=[5.56 39.8]
   216  	// Low:1.6 High:1.8 Score:2 Communities:[[0 2 3 4 5 6 10] [1 7 8 9 11 12]] Q=[-1.82 48.6]
   217  	// Low:1.8 High:2.3 Score:-6 Communities:[[0 2 3 4 5 6 8 10 11] [1 7 9 12]] Q=[-5 57.5]
   218  	// Low:2.3 High:2.4 Score:-10 Communities:[[0 1 2 6 7 8 9 11 12] [3 4 5 10]] Q=[-11.2 79]
   219  	// Low:2.4 High:4.3 Score:-52 Communities:[[0 1 2 3 4 5 6 7 8 9 10 11 12]] Q=[-46.1 117]
   220  	// Low:4.3 High:10 Score:-54 Communities:[[0 1 2 3 4 6 7 8 9 10 11 12] [5]] Q=[-82 254]
   221  }