github.com/gopherd/gonum@v0.0.4/graph/topo/bron_kerbosch_test.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 topo
     6  
     7  import (
     8  	"reflect"
     9  	"testing"
    10  
    11  	"github.com/gopherd/gonum/graph"
    12  	"github.com/gopherd/gonum/graph/internal/ordered"
    13  	"github.com/gopherd/gonum/graph/simple"
    14  )
    15  
    16  var vOrderTests = []struct {
    17  	g        []intset
    18  	wantCore [][]int64
    19  	wantK    int
    20  }{
    21  	{
    22  		g: []intset{
    23  			0: linksTo(1, 2, 4, 6),
    24  			1: linksTo(2, 4, 6),
    25  			2: linksTo(3, 6),
    26  			3: linksTo(4, 5),
    27  			4: linksTo(6),
    28  			5: nil,
    29  			6: nil,
    30  		},
    31  		wantCore: [][]int64{
    32  			{},
    33  			{5},
    34  			{3},
    35  			{0, 1, 2, 4, 6},
    36  		},
    37  		wantK: 3,
    38  	},
    39  	{
    40  		g: batageljZaversnikGraph,
    41  		wantCore: [][]int64{
    42  			{0},
    43  			{5, 9, 10, 16},
    44  			{1, 2, 3, 4, 11, 12, 13, 15},
    45  			{6, 7, 8, 14, 17, 18, 19, 20},
    46  		},
    47  		wantK: 3,
    48  	},
    49  }
    50  
    51  func TestDegeneracyOrdering(t *testing.T) {
    52  	for i, test := range vOrderTests {
    53  		g := simple.NewUndirectedGraph()
    54  		for u, e := range test.g {
    55  			// Add nodes that are not defined by an edge.
    56  			if g.Node(int64(u)) == nil {
    57  				g.AddNode(simple.Node(u))
    58  			}
    59  			for v := range e {
    60  				g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
    61  			}
    62  		}
    63  		order, core := DegeneracyOrdering(g)
    64  		if len(core)-1 != test.wantK {
    65  			t.Errorf("unexpected value of k for test %d: got: %d want: %d", i, len(core)-1, test.wantK)
    66  		}
    67  		var offset int
    68  		for k, want := range test.wantCore {
    69  			ordered.Int64s(want)
    70  			got := make([]int64, len(want))
    71  			for j, n := range order[len(order)-len(want)-offset : len(order)-offset] {
    72  				got[j] = n.ID()
    73  			}
    74  			ordered.Int64s(got)
    75  			if !reflect.DeepEqual(got, want) {
    76  				t.Errorf("unexpected %d-core for test %d:\ngot: %v\nwant:%v", k, i, got, want)
    77  			}
    78  
    79  			for j, n := range core[k] {
    80  				got[j] = n.ID()
    81  			}
    82  			ordered.Int64s(got)
    83  			if !reflect.DeepEqual(got, want) {
    84  				t.Errorf("unexpected %d-core for test %d:\ngot: %v\nwant:%v", k, i, got, want)
    85  			}
    86  			offset += len(want)
    87  		}
    88  	}
    89  }
    90  
    91  func TestKCore(t *testing.T) {
    92  	for i, test := range vOrderTests {
    93  		g := simple.NewUndirectedGraph()
    94  		for u, e := range test.g {
    95  			// Add nodes that are not defined by an edge.
    96  			if g.Node(int64(u)) == nil {
    97  				g.AddNode(simple.Node(u))
    98  			}
    99  			for v := range e {
   100  				g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
   101  			}
   102  		}
   103  
   104  		for k := 0; k <= test.wantK+1; k++ {
   105  			var want []int64
   106  			for _, c := range test.wantCore[k:] {
   107  				want = append(want, c...)
   108  			}
   109  			core := KCore(k, g)
   110  			if len(core) != len(want) {
   111  				t.Errorf("unexpected %d-core length for test %d:\ngot: %v\nwant:%v", k, i, len(core), len(want))
   112  				continue
   113  			}
   114  
   115  			var got []int64
   116  			for _, n := range core {
   117  				got = append(got, n.ID())
   118  			}
   119  			ordered.Int64s(got)
   120  			ordered.Int64s(want)
   121  			if !reflect.DeepEqual(got, want) {
   122  				t.Errorf("unexpected %d-core for test %d:\ngot: %v\nwant:%v", k, i, got, want)
   123  			}
   124  		}
   125  	}
   126  }
   127  
   128  var bronKerboschTests = []struct {
   129  	name string
   130  	g    []intset
   131  	want [][]int64
   132  }{
   133  	{
   134  		// This is the example given in the Bron-Kerbosch article on wikipedia (renumbered).
   135  		// http://en.wikipedia.org/w/index.php?title=Bron%E2%80%93Kerbosch_algorithm&oldid=656805858
   136  		name: "wikipedia example",
   137  		g: []intset{
   138  			0: linksTo(1, 4),
   139  			1: linksTo(2, 4),
   140  			2: linksTo(3),
   141  			3: linksTo(4, 5),
   142  			4: nil,
   143  			5: nil,
   144  		},
   145  		want: [][]int64{
   146  			{0, 1, 4},
   147  			{1, 2},
   148  			{2, 3},
   149  			{3, 4},
   150  			{3, 5},
   151  		},
   152  	},
   153  	{
   154  		name: "Batagelj-Zaversnik Graph",
   155  		g:    batageljZaversnikGraph,
   156  		want: [][]int64{
   157  			{0},
   158  			{1, 2},
   159  			{1, 3},
   160  			{2, 4},
   161  			{3, 4},
   162  			{4, 5},
   163  			{6, 7, 8, 14},
   164  			{7, 11, 12},
   165  			{9, 11},
   166  			{10, 11},
   167  			{12, 18},
   168  			{13, 14, 15},
   169  			{14, 15, 17},
   170  			{15, 16},
   171  			{17, 18, 19, 20},
   172  		},
   173  	},
   174  }
   175  
   176  func TestBronKerbosch(t *testing.T) {
   177  	for _, test := range bronKerboschTests {
   178  		g := simple.NewUndirectedGraph()
   179  		for u, e := range test.g {
   180  			// Add nodes that are not defined by an edge.
   181  			if g.Node(int64(u)) == nil {
   182  				g.AddNode(simple.Node(u))
   183  			}
   184  			for v := range e {
   185  				g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
   186  			}
   187  		}
   188  		cliques := BronKerbosch(g)
   189  		got := make([][]int64, len(cliques))
   190  		for j, c := range cliques {
   191  			ids := make([]int64, len(c))
   192  			for k, n := range c {
   193  				ids[k] = n.ID()
   194  			}
   195  			ordered.Int64s(ids)
   196  			got[j] = ids
   197  		}
   198  		ordered.BySliceValues(got)
   199  		if !reflect.DeepEqual(got, test.want) {
   200  			t.Errorf("unexpected cliques for test %q:\ngot: %v\nwant:%v", test.name, got, test.want)
   201  		}
   202  	}
   203  }
   204  
   205  func BenchmarkBronKerbosch(b *testing.B) {
   206  	for _, test := range bronKerboschTests {
   207  		g := simple.NewUndirectedGraph()
   208  		for u, e := range test.g {
   209  			// Add nodes that are not defined by an edge.
   210  			if g.Node(int64(u)) == nil {
   211  				g.AddNode(simple.Node(u))
   212  			}
   213  			for v := range e {
   214  				g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
   215  			}
   216  		}
   217  
   218  		b.Run(test.name, func(b *testing.B) {
   219  			var got [][]graph.Node
   220  			for i := 0; i < b.N; i++ {
   221  				got = BronKerbosch(g)
   222  			}
   223  			if len(got) != len(test.want) {
   224  				b.Errorf("unexpected cliques for test %q:\ngot: %v\nwant:%v", test.name, got, test.want)
   225  			}
   226  		})
   227  	}
   228  }