act/vendor/github.com/soniakeys/graph/undir_RO.go

1139 lines
31 KiB
Go
Raw Normal View History

// Copyright 2014 Sonia Keys
// License MIT: http://opensource.org/licenses/MIT
package graph
import (
"errors"
"fmt"
"github.com/soniakeys/bits"
)
// undir_RO.go is code generated from undir_cg.go by directives in graph.go.
// Editing undir_cg.go is okay. It is the code generation source.
// DO NOT EDIT undir_RO.go.
// The RO means read only and it is upper case RO to slow you down a bit
// in case you start to edit the file.
//-------------------
// Bipartite constructs an object indexing the bipartite structure of a graph.
//
// In a bipartite component, nodes can be partitioned into two sets, or
// "colors," such that every edge in the component goes from one set to the
// other.
//
// If the graph is bipartite, the method constructs and returns a new
// Bipartite object as b and returns ok = true.
//
// If the component is not bipartite, a representative odd cycle as oc and
// returns ok = false.
//
// In the case of a graph with mulitiple connected components, this method
// provides no control over the color orientation by component. See
// Undirected.BipartiteComponent if this control is needed.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g Undirected) Bipartite() (b *Bipartite, oc []NI, ok bool) {
c1 := bits.New(g.Order())
c2 := bits.New(g.Order())
r, _, _ := g.ConnectedComponentReps()
// accumulate n2 number of zero bits in c2 as number of one bits in n1
var n, n2 int
for _, r := range r {
ok, n, _, oc = g.BipartiteComponent(r, c1, c2)
if !ok {
return
}
n2 += n
}
return &Bipartite{g, c2, n2}, nil, true
}
// BipartiteComponent analyzes the bipartite structure of a connected component
// of an undirected graph.
//
// In a bipartite component, nodes can be partitioned into two sets, or
// "colors," such that every edge in the component goes from one set to the
// other.
//
// Argument n can be any representative node of the component to be analyzed.
// Arguments c1 and c2 must be separate bits.Bits objects constructed to be
// of length of the number of nodes of g. These bitmaps are used in the
// component traversal and the bits of the component must be zero when the
// method is called.
//
// If the component is bipartite, BipartiteComponent populates bitmaps
// c1 and c2 with the two-coloring of the component, always assigning the set
// with representative node n to bitmap c1. It returns b = true,
// and also returns the number of bits set in c1 and c2 as n1 and n2
// respectively.
//
// If the component is not bipartite, BipartiteComponent returns b = false
// and a representative odd cycle as oc.
//
// See also method Bipartite.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g Undirected) BipartiteComponent(n NI, c1, c2 bits.Bits) (b bool, n1, n2 int, oc []NI) {
a := g.AdjacencyList
b = true
var open bool
var df func(n NI, c1, c2 *bits.Bits, n1, n2 *int)
df = func(n NI, c1, c2 *bits.Bits, n1, n2 *int) {
c1.SetBit(int(n), 1)
*n1++
for _, nb := range a[n] {
if c1.Bit(int(nb)) == 1 {
b = false
oc = []NI{nb, n}
open = true
return
}
if c2.Bit(int(nb)) == 1 {
continue
}
df(nb, c2, c1, n2, n1)
if b {
continue
}
switch {
case !open:
case n == oc[0]:
open = false
default:
oc = append(oc, n)
}
return
}
}
df(n, &c1, &c2, &n1, &n2)
if b {
return b, n1, n2, nil
}
return b, 0, 0, oc
}
// BronKerbosch1 finds maximal cliques in an undirected graph.
//
// The graph must not contain parallel edges or loops.
//
// See https://en.wikipedia.org/wiki/Clique_(graph_theory) and
// https://en.wikipedia.org/wiki/Bron%E2%80%93Kerbosch_algorithm for background.
//
// This method implements the BronKerbosch1 algorithm of WP; that is,
// the original algorithm without improvements.
//
// The method calls the emit argument for each maximal clique in g, as long
// as emit returns true. If emit returns false, BronKerbosch1 returns
// immediately.
//
// There are equivalent labeled and unlabeled versions of this method.
//
// See also more sophisticated variants BronKerbosch2 and BronKerbosch3.
func (g Undirected) BronKerbosch1(emit func(bits.Bits) bool) {
a := g.AdjacencyList
var f func(R, P, X bits.Bits) bool
f = func(R, P, X bits.Bits) bool {
switch {
case !P.AllZeros():
r2 := bits.New(len(a))
p2 := bits.New(len(a))
x2 := bits.New(len(a))
pf := func(n int) bool {
r2.Set(R)
r2.SetBit(n, 1)
p2.ClearAll()
x2.ClearAll()
for _, to := range a[n] {
if P.Bit(int(to)) == 1 {
p2.SetBit(int(to), 1)
}
if X.Bit(int(to)) == 1 {
x2.SetBit(int(to), 1)
}
}
if !f(r2, p2, x2) {
return false
}
P.SetBit(n, 0)
X.SetBit(n, 1)
return true
}
if !P.IterateOnes(pf) {
return false
}
case X.AllZeros():
return emit(R)
}
return true
}
var R, P, X bits.Bits
R = bits.New(len(a))
P = bits.New(len(a))
X = bits.New(len(a))
P.SetAll()
f(R, P, X)
}
// BKPivotMaxDegree is a strategy for BronKerbosch methods.
//
// To use it, take the method value (see golang.org/ref/spec#Method_values)
// and pass it as the argument to BronKerbosch2 or 3.
//
// The strategy is to pick the node from P or X with the maximum degree
// (number of edges) in g. Note this is a shortcut from evaluating degrees
// in P.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g Undirected) BKPivotMaxDegree(P, X bits.Bits) (p NI) {
// choose pivot u as highest degree node from P or X
a := g.AdjacencyList
maxDeg := -1
P.IterateOnes(func(n int) bool { // scan P
if d := len(a[n]); d > maxDeg {
p = NI(n)
maxDeg = d
}
return true
})
X.IterateOnes(func(n int) bool { // scan X
if d := len(a[n]); d > maxDeg {
p = NI(n)
maxDeg = d
}
return true
})
return
}
// BKPivotMinP is a strategy for BronKerbosch methods.
//
// To use it, take the method value (see golang.org/ref/spec#Method_values)
// and pass it as the argument to BronKerbosch2 or 3.
//
// The strategy is to simply pick the first node in P.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g Undirected) BKPivotMinP(P, X bits.Bits) NI {
return NI(P.OneFrom(0))
}
// BronKerbosch2 finds maximal cliques in an undirected graph.
//
// The graph must not contain parallel edges or loops.
//
// See https://en.wikipedia.org/wiki/Clique_(graph_theory) and
// https://en.wikipedia.org/wiki/Bron%E2%80%93Kerbosch_algorithm for background.
//
// This method implements the BronKerbosch2 algorithm of WP; that is,
// the original algorithm plus pivoting.
//
// The argument is a pivot function that must return a node of P or X.
// P is guaranteed to contain at least one node. X is not.
// For example see BKPivotMaxDegree.
//
// The method calls the emit argument for each maximal clique in g, as long
// as emit returns true. If emit returns false, BronKerbosch1 returns
// immediately.
//
// There are equivalent labeled and unlabeled versions of this method.
//
// See also simpler variant BronKerbosch1 and more sophisticated variant
// BronKerbosch3.
func (g Undirected) BronKerbosch2(pivot func(P, X bits.Bits) NI, emit func(bits.Bits) bool) {
a := g.AdjacencyList
var f func(R, P, X bits.Bits) bool
f = func(R, P, X bits.Bits) bool {
switch {
case !P.AllZeros():
r2 := bits.New(len(a))
p2 := bits.New(len(a))
x2 := bits.New(len(a))
pnu := bits.New(len(a))
// compute P \ N(u). next 5 lines are only difference from BK1
pnu.Set(P)
for _, to := range a[pivot(P, X)] {
pnu.SetBit(int(to), 0)
}
// remaining code like BK1
pf := func(n int) bool {
r2.Set(R)
r2.SetBit(n, 1)
p2.ClearAll()
x2.ClearAll()
for _, to := range a[n] {
if P.Bit(int(to)) == 1 {
p2.SetBit(int(to), 1)
}
if X.Bit(int(to)) == 1 {
x2.SetBit(int(to), 1)
}
}
if !f(r2, p2, x2) {
return false
}
P.SetBit(n, 0)
X.SetBit(n, 1)
return true
}
if !pnu.IterateOnes(pf) {
return false
}
case X.AllZeros():
return emit(R)
}
return true
}
R := bits.New(len(a))
P := bits.New(len(a))
X := bits.New(len(a))
P.SetAll()
f(R, P, X)
}
// BronKerbosch3 finds maximal cliques in an undirected graph.
//
// The graph must not contain parallel edges or loops.
//
// See https://en.wikipedia.org/wiki/Clique_(graph_theory) and
// https://en.wikipedia.org/wiki/Bron%E2%80%93Kerbosch_algorithm for background.
//
// This method implements the BronKerbosch3 algorithm of WP; that is,
// the original algorithm with pivoting and degeneracy ordering.
//
// The argument is a pivot function that must return a node of P or X.
// P is guaranteed to contain at least one node. X is not.
// For example see BKPivotMaxDegree.
//
// The method calls the emit argument for each maximal clique in g, as long
// as emit returns true. If emit returns false, BronKerbosch1 returns
// immediately.
//
// There are equivalent labeled and unlabeled versions of this method.
//
// See also simpler variants BronKerbosch1 and BronKerbosch2.
func (g Undirected) BronKerbosch3(pivot func(P, X bits.Bits) NI, emit func(bits.Bits) bool) {
a := g.AdjacencyList
var f func(R, P, X bits.Bits) bool
f = func(R, P, X bits.Bits) bool {
switch {
case !P.AllZeros():
r2 := bits.New(len(a))
p2 := bits.New(len(a))
x2 := bits.New(len(a))
pnu := bits.New(len(a))
// compute P \ N(u). next lines are only difference from BK1
pnu.Set(P)
for _, to := range a[pivot(P, X)] {
pnu.SetBit(int(to), 0)
}
// remaining code like BK2
pf := func(n int) bool {
r2.Set(R)
r2.SetBit(n, 1)
p2.ClearAll()
x2.ClearAll()
for _, to := range a[n] {
if P.Bit(int(to)) == 1 {
p2.SetBit(int(to), 1)
}
if X.Bit(int(to)) == 1 {
x2.SetBit(int(to), 1)
}
}
if !f(r2, p2, x2) {
return false
}
P.SetBit(n, 0)
X.SetBit(n, 1)
return true
}
if !pnu.IterateOnes(pf) {
return false
}
case X.AllZeros():
return emit(R)
}
return true
}
R := bits.New(len(a))
P := bits.New(len(a))
X := bits.New(len(a))
P.SetAll()
// code above same as BK2
// code below new to BK3
ord, _ := g.DegeneracyOrdering()
p2 := bits.New(len(a))
x2 := bits.New(len(a))
for _, n := range ord {
R.SetBit(int(n), 1)
p2.ClearAll()
x2.ClearAll()
for _, to := range a[n] {
if P.Bit(int(to)) == 1 {
p2.SetBit(int(to), 1)
}
if X.Bit(int(to)) == 1 {
x2.SetBit(int(to), 1)
}
}
if !f(R, p2, x2) {
return
}
R.SetBit(int(n), 0)
P.SetBit(int(n), 0)
X.SetBit(int(n), 1)
}
}
// ConnectedComponentBits returns a function that iterates over connected
// components of g, returning a member bitmap for each.
//
// Each call of the returned function returns the order, arc size,
// and bits of a connected component. The underlying bits allocation is
// the same for each call and is overwritten on subsequent calls. Use or
// save the bits before calling the function again. The function returns
// zeros after returning all connected components.
//
// There are equivalent labeled and unlabeled versions of this method.
//
// See also ConnectedComponentInts, ConnectedComponentReps, and
// ConnectedComponentReps.
func (g Undirected) ConnectedComponentBits() func() (order, arcSize int, bits bits.Bits) {
a := g.AdjacencyList
vg := bits.New(len(a)) // nodes visited in graph
vc := bits.New(len(a)) // nodes visited in current component
var order, arcSize int
var df func(NI)
df = func(n NI) {
vg.SetBit(int(n), 1)
vc.SetBit(int(n), 1)
order++
arcSize += len(a[n])
for _, nb := range a[n] {
if vg.Bit(int(nb)) == 0 {
df(nb)
}
}
return
}
var n int
return func() (o, ma int, b bits.Bits) {
for ; n < len(a); n++ {
if vg.Bit(n) == 0 {
vc.ClearAll()
order, arcSize = 0, 0
df(NI(n))
return order, arcSize, vc
}
}
return // return zeros signalling no more components
}
}
// ConnectedComponenInts returns a list of component numbers (ints) for each
// node of graph g.
//
// The method assigns numbers to components 1-based, 1 through the number of
// components. Return value ci contains the component number for each node.
// Return value nc is the number of components.
//
// There are equivalent labeled and unlabeled versions of this method.
//
// See also ConnectedComponentBits, ConnectedComponentLists, and
// ConnectedComponentReps.
func (g Undirected) ConnectedComponentInts() (ci []int, nc int) {
a := g.AdjacencyList
ci = make([]int, len(a))
var df func(NI)
df = func(nd NI) {
ci[nd] = nc
for _, to := range a[nd] {
if ci[to] == 0 {
df(to)
}
}
return
}
for nd := range a {
if ci[nd] == 0 {
nc++
df(NI(nd))
}
}
return
}
// ConnectedComponentLists returns a function that iterates over connected
// components of g, returning the member list of each.
//
// Each call of the returned function returns a node list of a connected
// component and the arc size of the component. The returned function returns
// nil, 0 after returning all connected components.
//
// There are equivalent labeled and unlabeled versions of this method.
//
// See also ConnectedComponentBits, ConnectedComponentInts, and
// ConnectedComponentReps.
func (g Undirected) ConnectedComponentLists() func() (nodes []NI, arcSize int) {
a := g.AdjacencyList
vg := bits.New(len(a)) // nodes visited in graph
var l []NI // accumulated node list of current component
var ma int // accumulated arc size of current component
var df func(NI)
df = func(n NI) {
vg.SetBit(int(n), 1)
l = append(l, n)
ma += len(a[n])
for _, nb := range a[n] {
if vg.Bit(int(nb)) == 0 {
df(nb)
}
}
return
}
var n int
return func() ([]NI, int) {
for ; n < len(a); n++ {
if vg.Bit(n) == 0 {
l, ma = nil, 0
df(NI(n))
return l, ma
}
}
return nil, 0
}
}
// ConnectedComponentReps returns a representative node from each connected
// component of g.
//
// Returned is a slice with a single representative node from each connected
// component and also parallel slices with the orders and arc sizes
// in the corresponding components.
//
// This is fairly minimal information describing connected components.
// From a representative node, other nodes in the component can be reached
// by depth first traversal for example.
//
// There are equivalent labeled and unlabeled versions of this method.
//
// See also ConnectedComponentBits and ConnectedComponentLists which can
// collect component members in a single traversal, and IsConnected which
// is an even simpler boolean test.
func (g Undirected) ConnectedComponentReps() (reps []NI, orders, arcSizes []int) {
a := g.AdjacencyList
c := bits.New(len(a))
var o, ma int
var df func(NI)
df = func(n NI) {
c.SetBit(int(n), 1)
o++
ma += len(a[n])
for _, nb := range a[n] {
if c.Bit(int(nb)) == 0 {
df(nb)
}
}
return
}
for n := range a {
if c.Bit(n) == 0 {
o, ma = 0, 0
df(NI(n))
reps = append(reps, NI(n))
orders = append(orders, o)
arcSizes = append(arcSizes, ma)
}
}
return
}
// Copy makes a deep copy of g.
// Copy also computes the arc size ma, the number of arcs.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g Undirected) Copy() (c Undirected, ma int) {
l, s := g.AdjacencyList.Copy()
return Undirected{l}, s
}
// Degeneracy is a measure of dense subgraphs within a graph.
//
// See Wikipedia https://en.wikipedia.org/wiki/Degeneracy_(graph_theory)
//
// See also method DegeneracyOrdering which returns a degeneracy node
// ordering and k-core breaks.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g Undirected) Degeneracy() (k int) {
a := g.AdjacencyList
// WP algorithm, attributed to Matula and Beck.
L := bits.New(len(a))
d := make([]int, len(a))
var D [][]NI
for v, nb := range a {
dv := len(nb)
d[v] = dv
for len(D) <= dv {
D = append(D, nil)
}
D[dv] = append(D[dv], NI(v))
}
for range a {
// find a non-empty D
i := 0
for len(D[i]) == 0 {
i++
}
// k is max(i, k)
if i > k {
k = i
}
// select from D[i]
Di := D[i]
last := len(Di) - 1
v := Di[last]
// Add v to ordering, remove from Di
L.SetBit(int(v), 1)
D[i] = Di[:last]
// move neighbors
for _, nb := range a[v] {
if L.Bit(int(nb)) == 1 {
continue
}
dn := d[nb] // old number of neighbors of nb
Ddn := D[dn] // nb is in this list
// remove it from the list
for wx, w := range Ddn {
if w == nb {
last := len(Ddn) - 1
Ddn[wx], Ddn[last] = Ddn[last], Ddn[wx]
D[dn] = Ddn[:last]
}
}
dn-- // new number of neighbors
d[nb] = dn
// re--add it to it's new list
D[dn] = append(D[dn], nb)
}
}
return
}
// DegeneracyOrdering computes degeneracy node ordering and k-core breaks.
//
// See Wikipedia https://en.wikipedia.org/wiki/Degeneracy_(graph_theory)
//
// In return value ordering, nodes are ordered by their "coreness" as
// defined at https://en.wikipedia.org/wiki/Degeneracy_(graph_theory)#k-Cores.
//
// Return value kbreaks indexes ordering by coreness number. len(kbreaks)
// will be one more than the graph degeneracy as returned by the Degeneracy
// method. If degeneracy is d, d = len(kbreaks) - 1, kbreaks[d] is the last
// value in kbreaks and ordering[:kbreaks[d]] contains nodes of the d-cores
// of the graph. kbreaks[0] is always the number of nodes in g as all nodes
// are in in a 0-core.
//
// Note that definitions of "k-core" differ on whether a k-core must be a
// single connected component. This method does not resolve individual
// connected components.
//
// See also method Degeneracy which returns just the degeneracy number.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g Undirected) DegeneracyOrdering() (ordering []NI, kbreaks []int) {
a := g.AdjacencyList
// WP algorithm
k := 0
ordering = make([]NI, len(a))
kbreaks = []int{len(a)}
L := bits.New(len(a))
d := make([]int, len(a))
var D [][]NI
for v, nb := range a {
dv := len(nb)
d[v] = dv
for len(D) <= dv {
D = append(D, nil)
}
D[dv] = append(D[dv], NI(v))
}
for ox := len(a) - 1; ox >= 0; ox-- {
// find a non-empty D
i := 0
for len(D[i]) == 0 {
i++
}
// k is max(i, k)
if i > k {
for len(kbreaks) <= i {
kbreaks = append(kbreaks, ox+1)
}
k = i
}
// select from D[i]
Di := D[i]
last := len(Di) - 1
v := Di[last]
// Add v to ordering, remove from Di
ordering[ox] = v
L.SetBit(int(v), 1)
D[i] = Di[:last]
// move neighbors
for _, nb := range a[v] {
if L.Bit(int(nb)) == 1 {
continue
}
dn := d[nb] // old number of neighbors of nb
Ddn := D[dn] // nb is in this list
// remove it from the list
for wx, w := range Ddn {
if w == nb {
last := len(Ddn) - 1
Ddn[wx], Ddn[last] = Ddn[last], Ddn[wx]
D[dn] = Ddn[:last]
}
}
dn-- // new number of neighbors
d[nb] = dn
// re--add it to it's new list
D[dn] = append(D[dn], nb)
}
}
//for i, j := 0, k; i < j; i, j = i+1, j-1 {
// kbreaks[i], kbreaks[j] = kbreaks[j], kbreaks[i]
//}
return
}
// Degree for undirected graphs, returns the degree of a node.
//
// The degree of a node in an undirected graph is the number of incident
// edges, where loops count twice.
//
// If g is known to be loop-free, the result is simply equivalent to len(g[n]).
// See handshaking lemma example at AdjacencyList.ArcSize.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g Undirected) Degree(n NI) int {
to := g.AdjacencyList[n]
d := len(to) // just "out" degree,
for _, to := range to {
if to == n {
d++ // except loops count twice
}
}
return d
}
// DegreeCentralization returns the degree centralization metric of a graph.
//
// Degree of a node is one measure of node centrality and is directly
// available from the adjacency list representation. This allows degree
// centralization for the graph to be very efficiently computed.
//
// The value returned is from 0 to 1 inclusive for simple graphs of three or
// more nodes. As a special case, 0 is returned for graphs of two or fewer
// nodes. The value returned can be > 1 for graphs with loops or parallel
// edges.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g Undirected) DegreeCentralization() float64 {
a := g.AdjacencyList
if len(a) <= 2 {
return 0
}
var max, sum int
for _, to := range a {
if len(to) > max {
max = len(to)
}
sum += len(to)
}
return float64(len(a)*max-sum) / float64((len(a)-1)*(len(a)-2))
}
// Density returns density for a simple graph.
//
// See also Density function.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g Undirected) Density() float64 {
return Density(g.Order(), g.Size())
}
// Eulerian scans an undirected graph to determine if it is Eulerian.
//
// If the graph represents an Eulerian cycle, it returns -1, -1, nil.
//
// If the graph does not represent an Eulerian cycle but does represent an
// Eulerian path, it returns the two end nodes of the path, and nil.
//
// Otherwise it returns an error.
//
// See also method EulerianStart, which short-circuits as soon as it finds
// a node that must be a start or end node of an Eulerian path.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g Undirected) Eulerian() (end1, end2 NI, err error) {
end1 = -1
end2 = -1
for n := range g.AdjacencyList {
switch {
case g.Degree(NI(n))%2 == 0:
case end1 < 0:
end1 = NI(n)
case end2 < 0:
end2 = NI(n)
default:
err = errors.New("non-Eulerian")
return
}
}
return
}
// EulerianCycle finds an Eulerian cycle in an undirected multigraph.
//
// * If g has no nodes, result is nil, nil.
//
// * If g is Eulerian, result is an Eulerian cycle with err = nil.
// The first element of the result represents only a start node.
// The remaining elements represent the half arcs of the cycle.
//
// * Otherwise, result is nil, with a non-nil error giving a reason the graph
// is not Eulerian.
//
// Internally, EulerianCycle copies the entire graph g.
// See EulerianCycleD for a more space efficient version.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g Undirected) EulerianCycle() ([]NI, error) {
c, _ := g.Copy()
return c.EulerianCycleD(c.Size())
}
// EulerianCycleD finds an Eulerian cycle in an undirected multigraph.
//
// EulerianCycleD is destructive on its receiver g. See EulerianCycle for
// a non-destructive version.
//
// Parameter m must be the size of the undirected graph -- the
// number of edges. Use Undirected.Size if the size is unknown.
//
// * If g has no nodes, result is nil, nil.
//
// * If g is Eulerian, result is an Eulerian cycle with err = nil.
// The first element of the result represents only a start node.
// The remaining elements represent the half arcs of the cycle.
//
// * Otherwise, result is nil, with a non-nil error giving a reason the graph
// is not Eulerian.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g Undirected) EulerianCycleD(m int) ([]NI, error) {
if g.Order() == 0 {
return nil, nil
}
e := newEulerian(g.AdjacencyList, m)
e.p[0] = 0
for e.s >= 0 {
v := e.top()
if err := e.pushUndir(); err != nil {
return nil, err
}
if e.top() != v {
return nil, errors.New("not Eulerian")
}
e.keep()
}
if !e.uv.AllZeros() {
return nil, errors.New("not strongly connected")
}
return e.p, nil
}
// EulerianPath finds an Eulerian path in an undirected multigraph.
//
// * If g has no nodes, result is nil, nil.
//
// * If g has an Eulerian path, result is an Eulerian path with err = nil.
// The first element of the result represents only a start node.
// The remaining elements represent the half arcs of the path.
//
// * Otherwise, result is nil, with a non-nil error giving a reason the graph
// is not Eulerian.
//
// Internally, EulerianPath copies the entire graph g.
// See EulerianPathD for a more space efficient version.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g Undirected) EulerianPath() ([]NI, error) {
c, _ := g.Copy()
start := c.EulerianStart()
if start < 0 {
start = 0
}
return c.EulerianPathD(c.Size(), start)
}
// EulerianPathD finds an Eulerian path in a undirected multigraph.
//
// EulerianPathD is destructive on its receiver g. See EulerianPath for
// a non-destructive version.
//
// Argument m must be the correct size, or number of edges in g.
// Argument start must be a valid start node for the path.
//
// * If g has no nodes, result is nil, nil.
//
// * If g has an Eulerian path starting at start, result is an Eulerian path
// with err = nil.
// The first element of the result represents only a start node.
// The remaining elements represent the half arcs of the path.
//
// * Otherwise, result is nil, with a non-nil error giving a reason the graph
// is not Eulerian.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g Undirected) EulerianPathD(m int, start NI) ([]NI, error) {
if g.Order() == 0 {
return nil, nil
}
e := newEulerian(g.AdjacencyList, m)
e.p[0] = start
// unlike EulerianCycle, the first path doesn't have to be a cycle.
if err := e.pushUndir(); err != nil {
return nil, err
}
e.keep()
for e.s >= 0 {
start = e.top()
e.push()
// paths after the first must be cycles though
// (as long as there are nodes on the stack)
if e.top() != start {
return nil, errors.New("no Eulerian path")
}
e.keep()
}
if !e.uv.AllZeros() {
return nil, errors.New("no Eulerian path")
}
return e.p, nil
}
// EulerianStart finds a candidate start node for an Eulerian path.
//
// A graph representing an Eulerian path can have two nodes with odd degree.
// If it does, these must be the end nodes of the path. EulerianEnd scans
// for a node with an odd degree, returning immediately with the first one
// it finds.
//
// If the scan completes without finding a node with odd degree the method
// returns -1.
//
// See also method Eulerian, which completely validates a graph as representing
// an Eulerian path.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g Undirected) EulerianStart() NI {
for n := range g.AdjacencyList {
if g.Degree(NI(n))%2 != 0 {
return NI(n)
}
}
return -1
}
// AddNode maps a node in a supergraph to a subgraph node.
//
// Argument p must be an NI in supergraph s.Super. AddNode panics if
// p is not a valid node index of s.Super.
//
// AddNode is idempotent in that it does not add a new node to the subgraph if
// a subgraph node already exists mapped to supergraph node p.
//
// The mapped subgraph NI is returned.
func (s *UndirectedSubgraph) AddNode(p NI) (b NI) {
if int(p) < 0 || int(p) >= s.Super.Order() {
panic(fmt.Sprint("AddNode: NI ", p, " not in supergraph"))
}
if b, ok := s.SubNI[p]; ok {
return b
}
a := s.Undirected.AdjacencyList
b = NI(len(a))
s.Undirected.AdjacencyList = append(a, nil)
s.SuperNI = append(s.SuperNI, p)
s.SubNI[p] = b
return
}
// InduceList constructs a node-induced subgraph.
//
// The subgraph is induced on receiver graph g. Argument l must be a list of
// NIs in receiver graph g. Receiver g becomes the supergraph of the induced
// subgraph.
//
// Duplicate NIs are allowed in list l. The duplicates are effectively removed
// and only a single corresponding node is created in the subgraph. Subgraph
// NIs are mapped in the order of list l, execpt for ignoring duplicates.
// NIs in l that are not in g will panic.
//
// Returned is the constructed Subgraph object containing the induced subgraph
// and the mappings to the supergraph.
func (g *Undirected) InduceList(l []NI) *UndirectedSubgraph {
sub, sup := mapList(l)
return &UndirectedSubgraph{
Super: g,
SubNI: sub,
SuperNI: sup,
Undirected: Undirected{
g.AdjacencyList.induceArcs(sub, sup),
}}
}
// InduceBits constructs a node-induced subgraph.
//
// The subgraph is induced on receiver graph g. Argument t must be a bitmap
// representing NIs in receiver graph g. Receiver g becomes the supergraph
// of the induced subgraph. NIs in t that are not in g will panic.
//
// Returned is the constructed Subgraph object containing the induced subgraph
// and the mappings to the supergraph.
func (g *Undirected) InduceBits(t bits.Bits) *UndirectedSubgraph {
sub, sup := mapBits(t)
return &UndirectedSubgraph{
Super: g,
SubNI: sub,
SuperNI: sup,
Undirected: Undirected{
g.AdjacencyList.induceArcs(sub, sup),
}}
}
// IsConnected tests if an undirected graph is a single connected component.
//
// There are equivalent labeled and unlabeled versions of this method.
//
// See also ConnectedComponentReps for a method returning more information.
func (g Undirected) IsConnected() bool {
a := g.AdjacencyList
if len(a) == 0 {
return true
}
b := bits.New(len(a))
var df func(NI)
df = func(n NI) {
b.SetBit(int(n), 1)
for _, to := range a[n] {
if b.Bit(int(to)) == 0 {
df(to)
}
}
}
df(0)
return b.AllOnes()
}
// IsTree identifies trees in undirected graphs.
//
// Return value isTree is true if the connected component reachable from root
// is a tree. Further, return value allTree is true if the entire graph g is
// connected.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g Undirected) IsTree(root NI) (isTree, allTree bool) {
a := g.AdjacencyList
v := bits.New(len(a))
v.SetAll()
var df func(NI, NI) bool
df = func(fr, n NI) bool {
if v.Bit(int(n)) == 0 {
return false
}
v.SetBit(int(n), 0)
for _, to := range a[n] {
if to != fr && !df(n, to) {
return false
}
}
return true
}
v.SetBit(int(root), 0)
for _, to := range a[root] {
if !df(root, to) {
return false, false
}
}
return true, v.AllZeros()
}
// Size returns the number of edges in g.
//
// See also ArcSize and AnyLoop.
func (g Undirected) Size() int {
m2 := 0
for fr, to := range g.AdjacencyList {
m2 += len(to)
for _, to := range to {
if to == NI(fr) {
m2++
}
}
}
return m2 / 2
}
// Density returns edge density of a bipartite graph.
//
// Edge density is number of edges over maximum possible number of edges.
// Maximum possible number of edges in a bipartite graph is number of
// nodes of one color times number of nodes of the other color.
func (g Bipartite) Density() float64 {
a := g.Undirected.AdjacencyList
s := 0
g.Color.IterateOnes(func(n int) bool {
s += len(a[n])
return true
})
return float64(s) / float64(g.N0*(len(a)-g.N0))
}
// PermuteBiadjacency permutes a bipartite graph in place so that a prefix
// of the adjacency list encodes a biadjacency matrix.
//
// The permutation applied is returned. This would be helpful in referencing
// any externally stored node information.
//
// The biadjacency matrix is encoded as the prefix AdjacencyList[:g.N0].
// Note though that this slice does not represent a valid complete
// AdjacencyList. BoundsOk would return false, for example.
//
// In adjacency list terms, the result of the permutation is that nodes of
// the prefix only have arcs to the suffix and nodes of the suffix only have
// arcs to the prefix.
func (g Bipartite) PermuteBiadjacency() []int {
p := make([]int, g.Order())
i := 0
g.Color.IterateZeros(func(n int) bool {
p[n] = i
i++
return true
})
g.Color.IterateOnes(func(n int) bool {
p[n] = i
i++
return true
})
g.Permute(p)
g.Color.ClearAll()
for i := g.N0; i < g.Order(); i++ {
g.Color.SetBit(i, 1)
}
return p
}