817 lines
23 KiB
Go
817 lines
23 KiB
Go
// Copyright 2014 Sonia Keys
|
|
// License MIT: http://opensource.org/licenses/MIT
|
|
|
|
package graph
|
|
|
|
// undir.go has methods specific to undirected graphs, Undirected and
|
|
// LabeledUndirected.
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/soniakeys/bits"
|
|
)
|
|
|
|
// AddEdge adds an edge to a graph.
|
|
//
|
|
// It can be useful for constructing undirected graphs.
|
|
//
|
|
// When n1 and n2 are distinct, it adds the arc n1->n2 and the reciprocal
|
|
// n2->n1. When n1 and n2 are the same, it adds a single arc loop.
|
|
//
|
|
// The pointer receiver allows the method to expand the graph as needed
|
|
// to include the values n1 and n2. If n1 or n2 happen to be greater than
|
|
// len(*p) the method does not panic, but simply expands the graph.
|
|
//
|
|
// If you know or can compute the final graph order however, consider
|
|
// preallocating to avoid any overhead of expanding the graph.
|
|
// See second example, "More".
|
|
func (p *Undirected) AddEdge(n1, n2 NI) {
|
|
// Similar code in LabeledAdjacencyList.AddEdge.
|
|
|
|
// determine max of the two end points
|
|
max := n1
|
|
if n2 > max {
|
|
max = n2
|
|
}
|
|
// expand graph if needed, to include both
|
|
g := p.AdjacencyList
|
|
if int(max) >= len(g) {
|
|
p.AdjacencyList = make(AdjacencyList, max+1)
|
|
copy(p.AdjacencyList, g)
|
|
g = p.AdjacencyList
|
|
}
|
|
// create one half-arc,
|
|
g[n1] = append(g[n1], n2)
|
|
// and except for loops, create the reciprocal
|
|
if n1 != n2 {
|
|
g[n2] = append(g[n2], n1)
|
|
}
|
|
}
|
|
|
|
// RemoveEdge removes a single edge between nodes n1 and n2.
|
|
//
|
|
// It removes reciprocal arcs in the case of distinct n1 and n2 or removes
|
|
// a single arc loop in the case of n1 == n2.
|
|
//
|
|
// Returns true if the specified edge is found and successfully removed,
|
|
// false if the edge does not exist.
|
|
func (g Undirected) RemoveEdge(n1, n2 NI) (ok bool) {
|
|
ok, x1, x2 := g.HasEdge(n1, n2)
|
|
if !ok {
|
|
return
|
|
}
|
|
a := g.AdjacencyList
|
|
to := a[n1]
|
|
last := len(to) - 1
|
|
to[x1] = to[last]
|
|
a[n1] = to[:last]
|
|
if n1 == n2 {
|
|
return
|
|
}
|
|
to = a[n2]
|
|
last = len(to) - 1
|
|
to[x2] = to[last]
|
|
a[n2] = to[:last]
|
|
return
|
|
}
|
|
|
|
// ArcDensity returns density for a simple directed graph.
|
|
//
|
|
// Parameter n is order, or number of nodes of a simple directed graph.
|
|
// Parameter a is the arc size, or number of directed arcs.
|
|
//
|
|
// Returned density is the fraction `a` over the total possible number of arcs
|
|
// or a / (n * (n-1)).
|
|
//
|
|
// See also Density for density of a simple undirected graph.
|
|
//
|
|
// See also the corresponding methods AdjacencyList.ArcDensity and
|
|
// LabeledAdjacencyList.ArcDensity.
|
|
func ArcDensity(n, a int) float64 {
|
|
return float64(a) / (float64(n) * float64(n-1))
|
|
}
|
|
|
|
// Density returns density for a simple undirected graph.
|
|
//
|
|
// Parameter n is order, or number of nodes of a simple undirected graph.
|
|
// Parameter m is the size, or number of undirected edges.
|
|
//
|
|
// Returned density is the fraction m over the total possible number of edges
|
|
// or m / ((n * (n-1))/2).
|
|
//
|
|
// See also ArcDensity for simple directed graphs.
|
|
//
|
|
// See also the corresponding methods AdjacencyList.Density and
|
|
// LabeledAdjacencyList.Density.
|
|
func Density(n, m int) float64 {
|
|
return float64(m) * 2 / (float64(n) * float64(n-1))
|
|
}
|
|
|
|
// An EdgeVisitor is an argument to some traversal methods.
|
|
//
|
|
// Traversal methods call the visitor function for each edge visited.
|
|
// Argument e is the edge being visited.
|
|
type EdgeVisitor func(e Edge)
|
|
|
|
// Edges iterates over the edges of an undirected graph.
|
|
//
|
|
// Edge visitor v is called for each edge of the graph. That is, it is called
|
|
// once for each reciprocal arc pair and once for each loop.
|
|
//
|
|
// See also LabeledUndirected.Edges for a labeled version.
|
|
// See also Undirected.SimpleEdges for a version that emits only the simple
|
|
// subgraph.
|
|
func (g Undirected) Edges(v EdgeVisitor) {
|
|
a := g.AdjacencyList
|
|
unpaired := make(AdjacencyList, len(a))
|
|
for fr, to := range a {
|
|
arc: // for each arc in a
|
|
for _, to := range to {
|
|
if to == NI(fr) {
|
|
v(Edge{NI(fr), to}) // output loop
|
|
continue
|
|
}
|
|
// search unpaired arcs
|
|
ut := unpaired[to]
|
|
for i, u := range ut {
|
|
if u == NI(fr) { // found reciprocal
|
|
v(Edge{u, to}) // output edge
|
|
last := len(ut) - 1
|
|
ut[i] = ut[last]
|
|
unpaired[to] = ut[:last]
|
|
continue arc
|
|
}
|
|
}
|
|
// reciprocal not found
|
|
unpaired[fr] = append(unpaired[fr], to)
|
|
}
|
|
}
|
|
// undefined behavior is that unpaired arcs are silently ignored.
|
|
}
|
|
|
|
// FromList builds a forest with a tree spanning each connected component.
|
|
//
|
|
// For each component a root is chosen and spanning is done with the method
|
|
// Undirected.SpanTree, and so is breadth-first. Returned is a FromList with
|
|
// all spanned trees, a list of roots chosen, and a bool indicating if the
|
|
// receiver graph g was found to be a simple graph connected as a forest.
|
|
// Any cycles, loops, or parallel edges in any component will cause
|
|
// simpleForest to be false, but FromList f will still be populated with
|
|
// a valid and complete spanning forest.
|
|
func (g Undirected) FromList() (f FromList, roots []NI, simpleForest bool) {
|
|
p := make([]PathEnd, g.Order())
|
|
for i := range p {
|
|
p[i].From = -1
|
|
}
|
|
f.Paths = p
|
|
simpleForest = true
|
|
ts := 0
|
|
for n := range g.AdjacencyList {
|
|
if p[n].From >= 0 {
|
|
continue
|
|
}
|
|
roots = append(roots, NI(n))
|
|
ns, st := g.SpanTree(NI(n), &f)
|
|
if !st {
|
|
simpleForest = false
|
|
}
|
|
ts += ns
|
|
if ts == len(p) {
|
|
break
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// HasEdge returns true if g has any edge between nodes n1 and n2.
|
|
//
|
|
// Also returned are indexes x1 and x2 such that g[n1][x1] == n2
|
|
// and g[n2][x2] == n1. If no edge between n1 and n2 is present HasArc
|
|
// returns `has` == false.
|
|
//
|
|
// See also HasArc. If you are interested only in the boolean result and
|
|
// g is a well formed (passes IsUndirected) then HasArc is an adequate test.
|
|
func (g Undirected) HasEdge(n1, n2 NI) (has bool, x1, x2 int) {
|
|
if has, x1 = g.HasArc(n1, n2); !has {
|
|
return has, x1, x1
|
|
}
|
|
has, x2 = g.HasArc(n2, n1)
|
|
return
|
|
}
|
|
|
|
// SimpleEdges iterates over the edges of the simple subgraph of an undirected
|
|
// graph.
|
|
//
|
|
// Edge visitor v is called for each pair of distinct nodes that is connected
|
|
// with an edge. That is, loops are ignored and parallel edges are reduced to
|
|
// a single edge.
|
|
//
|
|
// See also Undirected.Edges for a version that emits all edges.
|
|
func (g Undirected) SimpleEdges(v EdgeVisitor) {
|
|
for fr, to := range g.AdjacencyList {
|
|
e := bits.New(len(g.AdjacencyList))
|
|
for _, to := range to {
|
|
if to > NI(fr) && e.Bit(int(to)) == 0 {
|
|
e.SetBit(int(to), 1)
|
|
v(Edge{NI(fr), to})
|
|
}
|
|
}
|
|
}
|
|
// undefined behavior is that unpaired arcs may or may not be emitted.
|
|
}
|
|
|
|
// SpanTree builds a tree spanning a connected component.
|
|
//
|
|
// The component is spanned by breadth-first search from the given root.
|
|
// The resulting spanning tree in stored a FromList.
|
|
//
|
|
// If FromList.Paths is not the same length as g, it is allocated and
|
|
// initialized. This allows a zero value FromList to be passed as f.
|
|
// If FromList.Paths is the same length as g, it is used as is and is not
|
|
// reinitialized. This allows multiple trees to be spanned in the same
|
|
// FromList with successive calls.
|
|
//
|
|
// For nodes spanned, the Path member of the returned FromList is populated
|
|
// with both From and Len values. The MaxLen member will be updated but
|
|
// not Leaves.
|
|
//
|
|
// Returned is the number of nodes spanned, which will be the number of nodes
|
|
// in the component, and a bool indicating if the component was found to be a
|
|
// simply connected unrooted tree in the receiver graph g. Any cycles, loops,
|
|
// or parallel edges in the component will cause simpleTree to be false, but
|
|
// FromList f will still be populated with a valid and complete spanning tree.
|
|
func (g Undirected) SpanTree(root NI, f *FromList) (nSpanned int, simpleTree bool) {
|
|
a := g.AdjacencyList
|
|
p := f.Paths
|
|
if len(p) != len(a) {
|
|
p = make([]PathEnd, len(a))
|
|
for i := range p {
|
|
p[i].From = -1
|
|
}
|
|
f.Paths = p
|
|
}
|
|
simpleTree = true
|
|
p[root] = PathEnd{From: -1, Len: 1}
|
|
type arc struct {
|
|
from NI
|
|
half NI
|
|
}
|
|
var next []arc
|
|
frontier := []arc{{-1, root}}
|
|
for len(frontier) > 0 {
|
|
for _, fa := range frontier { // fa frontier arc
|
|
nSpanned++
|
|
l := p[fa.half].Len + 1
|
|
for _, to := range a[fa.half] {
|
|
if to == fa.from {
|
|
continue
|
|
}
|
|
if p[to].Len > 0 {
|
|
simpleTree = false
|
|
continue
|
|
}
|
|
p[to] = PathEnd{From: fa.half, Len: l}
|
|
if l > f.MaxLen {
|
|
f.MaxLen = l
|
|
}
|
|
next = append(next, arc{fa.half, to})
|
|
}
|
|
}
|
|
frontier, next = next, frontier[:0]
|
|
}
|
|
return
|
|
}
|
|
|
|
// TarjanBiconnectedComponents decomposes a graph into maximal biconnected
|
|
// components, components for which if any node were removed the component
|
|
// would remain connected.
|
|
//
|
|
// The receiver g must be a simple graph. The method calls the emit argument
|
|
// for each component identified, as long as emit returns true. If emit
|
|
// returns false, TarjanBiconnectedComponents returns immediately.
|
|
//
|
|
// See also the eqivalent labeled TarjanBiconnectedComponents.
|
|
func (g Undirected) TarjanBiconnectedComponents(emit func([]Edge) bool) {
|
|
// Implemented closely to pseudocode in "Depth-first search and linear
|
|
// graph algorithms", Robert Tarjan, SIAM J. Comput. Vol. 1, No. 2,
|
|
// June 1972.
|
|
//
|
|
// Note Tarjan's "adjacency structure" is graph.AdjacencyList,
|
|
// His "adjacency list" is an element of a graph.AdjacencyList, also
|
|
// termed a "to-list", "neighbor list", or "child list."
|
|
a := g.AdjacencyList
|
|
number := make([]int, len(a))
|
|
lowpt := make([]int, len(a))
|
|
var stack []Edge
|
|
var i int
|
|
var biconnect func(NI, NI) bool
|
|
biconnect = func(v, u NI) bool {
|
|
i++
|
|
number[v] = i
|
|
lowpt[v] = i
|
|
for _, w := range a[v] {
|
|
if number[w] == 0 {
|
|
stack = append(stack, Edge{v, w})
|
|
if !biconnect(w, v) {
|
|
return false
|
|
}
|
|
if lowpt[w] < lowpt[v] {
|
|
lowpt[v] = lowpt[w]
|
|
}
|
|
if lowpt[w] >= number[v] {
|
|
var bcc []Edge
|
|
top := len(stack) - 1
|
|
for number[stack[top].N1] >= number[w] {
|
|
bcc = append(bcc, stack[top])
|
|
stack = stack[:top]
|
|
top--
|
|
}
|
|
bcc = append(bcc, stack[top])
|
|
stack = stack[:top]
|
|
top--
|
|
if !emit(bcc) {
|
|
return false
|
|
}
|
|
}
|
|
} else if number[w] < number[v] && w != u {
|
|
stack = append(stack, Edge{v, w})
|
|
if number[w] < lowpt[v] {
|
|
lowpt[v] = number[w]
|
|
}
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
for w := range a {
|
|
if number[w] == 0 && !biconnect(NI(w), -1) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func (g Undirected) BlockCut(block func([]Edge) bool, cut func(NI) bool, isolated func(NI) bool) {
|
|
a := g.AdjacencyList
|
|
number := make([]int, len(a))
|
|
lowpt := make([]int, len(a))
|
|
var stack []Edge
|
|
var i, rc int
|
|
var biconnect func(NI, NI) bool
|
|
biconnect = func(v, u NI) bool {
|
|
i++
|
|
number[v] = i
|
|
lowpt[v] = i
|
|
for _, w := range a[v] {
|
|
if number[w] == 0 {
|
|
if u < 0 {
|
|
rc++
|
|
}
|
|
stack = append(stack, Edge{v, w})
|
|
if !biconnect(w, v) {
|
|
return false
|
|
}
|
|
if lowpt[w] < lowpt[v] {
|
|
lowpt[v] = lowpt[w]
|
|
}
|
|
if lowpt[w] >= number[v] {
|
|
if u >= 0 && !cut(v) {
|
|
return false
|
|
}
|
|
var bcc []Edge
|
|
top := len(stack) - 1
|
|
for number[stack[top].N1] >= number[w] {
|
|
bcc = append(bcc, stack[top])
|
|
stack = stack[:top]
|
|
top--
|
|
}
|
|
bcc = append(bcc, stack[top])
|
|
stack = stack[:top]
|
|
top--
|
|
if !block(bcc) {
|
|
return false
|
|
}
|
|
}
|
|
} else if number[w] < number[v] && w != u {
|
|
stack = append(stack, Edge{v, w})
|
|
if number[w] < lowpt[v] {
|
|
lowpt[v] = number[w]
|
|
}
|
|
}
|
|
}
|
|
if u < 0 && rc > 1 {
|
|
return cut(v)
|
|
}
|
|
return true
|
|
}
|
|
for w := range a {
|
|
if number[w] > 0 {
|
|
continue
|
|
}
|
|
if len(a[w]) == 0 {
|
|
if !isolated(NI(w)) {
|
|
return
|
|
}
|
|
continue
|
|
}
|
|
rc = 0
|
|
if !biconnect(NI(w), -1) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// AddEdge adds an edge to a labeled graph.
|
|
//
|
|
// It can be useful for constructing undirected graphs.
|
|
//
|
|
// When n1 and n2 are distinct, it adds the arc n1->n2 and the reciprocal
|
|
// n2->n1. When n1 and n2 are the same, it adds a single arc loop.
|
|
//
|
|
// If the edge already exists in *p, a parallel edge is added.
|
|
//
|
|
// The pointer receiver allows the method to expand the graph as needed
|
|
// to include the values n1 and n2. If n1 or n2 happen to be greater than
|
|
// len(*p) the method does not panic, but simply expands the graph.
|
|
func (p *LabeledUndirected) AddEdge(e Edge, l LI) {
|
|
// Similar code in AdjacencyList.AddEdge.
|
|
|
|
// determine max of the two end points
|
|
max := e.N1
|
|
if e.N2 > max {
|
|
max = e.N2
|
|
}
|
|
// expand graph if needed, to include both
|
|
g := p.LabeledAdjacencyList
|
|
if max >= NI(len(g)) {
|
|
p.LabeledAdjacencyList = make(LabeledAdjacencyList, max+1)
|
|
copy(p.LabeledAdjacencyList, g)
|
|
g = p.LabeledAdjacencyList
|
|
}
|
|
// create one half-arc,
|
|
g[e.N1] = append(g[e.N1], Half{To: e.N2, Label: l})
|
|
// and except for loops, create the reciprocal
|
|
if e.N1 != e.N2 {
|
|
g[e.N2] = append(g[e.N2], Half{To: e.N1, Label: l})
|
|
}
|
|
}
|
|
|
|
// A LabeledEdgeVisitor is an argument to some traversal methods.
|
|
//
|
|
// Traversal methods call the visitor function for each edge visited.
|
|
// Argument e is the edge being visited.
|
|
type LabeledEdgeVisitor func(e LabeledEdge)
|
|
|
|
// Edges iterates over the edges of a labeled undirected graph.
|
|
//
|
|
// Edge visitor v is called for each edge of the graph. That is, it is called
|
|
// once for each reciprocal arc pair and once for each loop.
|
|
//
|
|
// See also Undirected.Edges for an unlabeled version.
|
|
// See also the more simplistic LabeledAdjacencyList.ArcsAsEdges.
|
|
func (g LabeledUndirected) Edges(v LabeledEdgeVisitor) {
|
|
// similar code in LabeledAdjacencyList.InUndirected
|
|
a := g.LabeledAdjacencyList
|
|
unpaired := make(LabeledAdjacencyList, len(a))
|
|
for fr, to := range a {
|
|
arc: // for each arc in a
|
|
for _, to := range to {
|
|
if to.To == NI(fr) {
|
|
v(LabeledEdge{Edge{NI(fr), to.To}, to.Label}) // output loop
|
|
continue
|
|
}
|
|
// search unpaired arcs
|
|
ut := unpaired[to.To]
|
|
for i, u := range ut {
|
|
if u.To == NI(fr) && u.Label == to.Label { // found reciprocal
|
|
v(LabeledEdge{Edge{NI(fr), to.To}, to.Label}) // output edge
|
|
last := len(ut) - 1
|
|
ut[i] = ut[last]
|
|
unpaired[to.To] = ut[:last]
|
|
continue arc
|
|
}
|
|
}
|
|
// reciprocal not found
|
|
unpaired[fr] = append(unpaired[fr], to)
|
|
}
|
|
}
|
|
}
|
|
|
|
// FromList builds a forest with a tree spanning each connected component in g.
|
|
//
|
|
// A root is chosen and spanning is done with the LabeledUndirected.SpanTree
|
|
// method, and so is breadth-first. Returned is a FromList with all spanned
|
|
// trees, labels corresponding to arcs in f,
|
|
// a list of roots chosen, and a bool indicating if the receiver graph g was
|
|
// found to be a simple graph connected as a forest. Any cycles, loops, or
|
|
// parallel edges in any component will cause simpleForest to be false, but
|
|
// FromList f will still be populated with a valid and complete spanning forest.
|
|
|
|
// FromList builds a forest with a tree spanning each connected component.
|
|
//
|
|
// For each component a root is chosen and spanning is done with the method
|
|
// Undirected.SpanTree, and so is breadth-first. Returned is a FromList with
|
|
// all spanned trees, labels corresponding to arcs in f, a list of roots
|
|
// chosen, and a bool indicating if the receiver graph g was found to be a
|
|
// simple graph connected as a forest. Any cycles, loops, or parallel edges
|
|
// in any component will cause simpleForest to be false, but FromList f will
|
|
// still be populated with a valid and complete spanning forest.
|
|
func (g LabeledUndirected) FromList() (f FromList, labels []LI, roots []NI, simpleForest bool) {
|
|
p := make([]PathEnd, g.Order())
|
|
for i := range p {
|
|
p[i].From = -1
|
|
}
|
|
f.Paths = p
|
|
labels = make([]LI, len(p))
|
|
simpleForest = true
|
|
ts := 0
|
|
for n := range g.LabeledAdjacencyList {
|
|
if p[n].From >= 0 {
|
|
continue
|
|
}
|
|
roots = append(roots, NI(n))
|
|
ns, st := g.SpanTree(NI(n), &f, labels)
|
|
if !st {
|
|
simpleForest = false
|
|
}
|
|
ts += ns
|
|
if ts == len(p) {
|
|
break
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// SpanTree builds a tree spanning a connected component.
|
|
//
|
|
// The component is spanned by breadth-first search from the given root.
|
|
// The resulting spanning tree in stored a FromList, and arc labels optionally
|
|
// stored in a slice.
|
|
//
|
|
// If FromList.Paths is not the same length as g, it is allocated and
|
|
// initialized. This allows a zero value FromList to be passed as f.
|
|
// If FromList.Paths is the same length as g, it is used as is and is not
|
|
// reinitialized. This allows multiple trees to be spanned in the same
|
|
// FromList with successive calls.
|
|
//
|
|
// For nodes spanned, the Path member of returned FromList f is populated
|
|
// populated with both From and Len values. The MaxLen member will be
|
|
// updated but not Leaves.
|
|
//
|
|
// The labels slice will be populated only if it is same length as g.
|
|
// Nil can be passed for example if labels are not needed.
|
|
//
|
|
// Returned is the number of nodes spanned, which will be the number of nodes
|
|
// in the component, and a bool indicating if the component was found to be a
|
|
// simply connected unrooted tree in the receiver graph g. Any cycles, loops,
|
|
// or parallel edges in the component will cause simpleTree to be false, but
|
|
// FromList f will still be populated with a valid and complete spanning tree.
|
|
func (g LabeledUndirected) SpanTree(root NI, f *FromList, labels []LI) (nSpanned int, simple bool) {
|
|
a := g.LabeledAdjacencyList
|
|
p := f.Paths
|
|
if len(p) != len(a) {
|
|
p = make([]PathEnd, len(a))
|
|
for i := range p {
|
|
p[i].From = -1
|
|
}
|
|
f.Paths = p
|
|
}
|
|
simple = true
|
|
p[root].Len = 1
|
|
type arc struct {
|
|
from NI
|
|
half Half
|
|
}
|
|
var next []arc
|
|
frontier := []arc{{-1, Half{root, -1}}}
|
|
for len(frontier) > 0 {
|
|
for _, fa := range frontier { // fa frontier arc
|
|
nSpanned++
|
|
l := p[fa.half.To].Len + 1
|
|
for _, to := range a[fa.half.To] {
|
|
if to.To == fa.from && to.Label == fa.half.Label {
|
|
continue
|
|
}
|
|
if p[to.To].Len > 0 {
|
|
simple = false
|
|
continue
|
|
}
|
|
p[to.To] = PathEnd{From: fa.half.To, Len: l}
|
|
if len(labels) == len(p) {
|
|
labels[to.To] = to.Label
|
|
}
|
|
if l > f.MaxLen {
|
|
f.MaxLen = l
|
|
}
|
|
next = append(next, arc{fa.half.To, to})
|
|
}
|
|
}
|
|
frontier, next = next, frontier[:0]
|
|
}
|
|
return
|
|
}
|
|
|
|
// HasEdge returns true if g has any edge between nodes n1 and n2.
|
|
//
|
|
// Also returned are indexes x1 and x2 such that g[n1][x1] == Half{n2, l}
|
|
// and g[n2][x2] == {n1, l} for some label l. If no edge between n1 and n2
|
|
// exists, HasArc returns `has` == false.
|
|
//
|
|
// See also HasArc. If you are only interested in the boolean result then
|
|
// HasArc is an adequate test.
|
|
func (g LabeledUndirected) HasEdge(n1, n2 NI) (has bool, x1, x2 int) {
|
|
if has, x1 = g.HasArc(n1, n2); !has {
|
|
return has, x1, x1
|
|
}
|
|
has, x2 = g.HasArcLabel(n2, n1, g.LabeledAdjacencyList[n1][x1].Label)
|
|
return
|
|
}
|
|
|
|
// HasEdgeLabel returns true if g has any edge between nodes n1 and n2 with
|
|
// label l.
|
|
//
|
|
// Also returned are indexes x1 and x2 such that g[n1][x1] == Half{n2, l}
|
|
// and g[n2][x2] == Half{n1, l}. If no edge between n1 and n2 with label l
|
|
// is present HasArc returns `has` == false.
|
|
func (g LabeledUndirected) HasEdgeLabel(n1, n2 NI, l LI) (has bool, x1, x2 int) {
|
|
if has, x1 = g.HasArcLabel(n1, n2, l); !has {
|
|
return has, x1, x1
|
|
}
|
|
has, x2 = g.HasArcLabel(n2, n1, l)
|
|
return
|
|
}
|
|
|
|
// RemoveEdge removes a single edge between nodes n1 and n2.
|
|
//
|
|
// It removes reciprocal arcs in the case of distinct n1 and n2 or removes
|
|
// a single arc loop in the case of n1 == n2.
|
|
//
|
|
// If the specified edge is found and successfully removed, RemoveEdge returns
|
|
// true and the label of the edge removed. If no edge exists between n1 and n2,
|
|
// RemoveEdge returns false, 0.
|
|
func (g LabeledUndirected) RemoveEdge(n1, n2 NI) (ok bool, label LI) {
|
|
ok, x1, x2 := g.HasEdge(n1, n2)
|
|
if !ok {
|
|
return
|
|
}
|
|
a := g.LabeledAdjacencyList
|
|
to := a[n1]
|
|
label = to[x1].Label // return value
|
|
last := len(to) - 1
|
|
to[x1] = to[last]
|
|
a[n1] = to[:last]
|
|
if n1 == n2 {
|
|
return
|
|
}
|
|
to = a[n2]
|
|
last = len(to) - 1
|
|
to[x2] = to[last]
|
|
a[n2] = to[:last]
|
|
return
|
|
}
|
|
|
|
// RemoveEdgeLabel removes a single edge between nodes n1 and n2 with label l.
|
|
//
|
|
// It removes reciprocal arcs in the case of distinct n1 and n2 or removes
|
|
// a single arc loop in the case of n1 == n2.
|
|
//
|
|
// Returns true if the specified edge is found and successfully removed,
|
|
// false if the edge does not exist.
|
|
func (g LabeledUndirected) RemoveEdgeLabel(n1, n2 NI, l LI) (ok bool) {
|
|
ok, x1, x2 := g.HasEdgeLabel(n1, n2, l)
|
|
if !ok {
|
|
return
|
|
}
|
|
a := g.LabeledAdjacencyList
|
|
to := a[n1]
|
|
last := len(to) - 1
|
|
to[x1] = to[last]
|
|
a[n1] = to[:last]
|
|
if n1 == n2 {
|
|
return
|
|
}
|
|
to = a[n2]
|
|
last = len(to) - 1
|
|
to[x2] = to[last]
|
|
a[n2] = to[:last]
|
|
return
|
|
}
|
|
|
|
// TarjanBiconnectedComponents decomposes a graph into maximal biconnected
|
|
// components, components for which if any node were removed the component
|
|
// would remain connected.
|
|
//
|
|
// The receiver g must be a simple graph. The method calls the emit argument
|
|
// for each component identified, as long as emit returns true. If emit
|
|
// returns false, TarjanBiconnectedComponents returns immediately.
|
|
//
|
|
// See also the eqivalent unlabeled TarjanBiconnectedComponents.
|
|
func (g LabeledUndirected) TarjanBiconnectedComponents(emit func([]LabeledEdge) bool) {
|
|
// Code nearly identical to unlabled version.
|
|
number := make([]int, g.Order())
|
|
lowpt := make([]int, g.Order())
|
|
var stack []LabeledEdge
|
|
var i int
|
|
var biconnect func(NI, NI) bool
|
|
biconnect = func(v, u NI) bool {
|
|
i++
|
|
number[v] = i
|
|
lowpt[v] = i
|
|
for _, w := range g.LabeledAdjacencyList[v] {
|
|
if number[w.To] == 0 {
|
|
stack = append(stack, LabeledEdge{Edge{v, w.To}, w.Label})
|
|
if !biconnect(w.To, v) {
|
|
return false
|
|
}
|
|
if lowpt[w.To] < lowpt[v] {
|
|
lowpt[v] = lowpt[w.To]
|
|
}
|
|
if lowpt[w.To] >= number[v] {
|
|
var bcc []LabeledEdge
|
|
top := len(stack) - 1
|
|
for number[stack[top].N1] >= number[w.To] {
|
|
bcc = append(bcc, stack[top])
|
|
stack = stack[:top]
|
|
top--
|
|
}
|
|
bcc = append(bcc, stack[top])
|
|
stack = stack[:top]
|
|
top--
|
|
if !emit(bcc) {
|
|
return false
|
|
}
|
|
}
|
|
} else if number[w.To] < number[v] && w.To != u {
|
|
stack = append(stack, LabeledEdge{Edge{v, w.To}, w.Label})
|
|
if number[w.To] < lowpt[v] {
|
|
lowpt[v] = number[w.To]
|
|
}
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
for w := range g.LabeledAdjacencyList {
|
|
if number[w] == 0 && !biconnect(NI(w), -1) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func (e *eulerian) pushUndir() error {
|
|
for u := e.top(); ; {
|
|
e.uv.SetBit(int(u), 0)
|
|
arcs := e.g[u]
|
|
if len(arcs) == 0 {
|
|
return nil
|
|
}
|
|
w := arcs[0]
|
|
e.s++
|
|
e.p[e.s] = w
|
|
e.g[u] = arcs[1:] // consume arc
|
|
// difference from directed counterpart in dir.go:
|
|
// as long as it's not a loop, consume reciprocal arc as well
|
|
if w != u {
|
|
a2 := e.g[w]
|
|
for x, rx := range a2 {
|
|
if rx == u { // here it is
|
|
last := len(a2) - 1
|
|
a2[x] = a2[last] // someone else gets the seat
|
|
e.g[w] = a2[:last] // and it's gone.
|
|
goto l
|
|
}
|
|
}
|
|
return fmt.Errorf("graph not undirected. %d -> %d reciprocal not found", u, w)
|
|
}
|
|
l:
|
|
u = w
|
|
}
|
|
}
|
|
|
|
func (e *labEulerian) pushUndir() error {
|
|
for u := e.top(); ; {
|
|
e.uv.SetBit(int(u.To), 0)
|
|
arcs := e.g[u.To]
|
|
if len(arcs) == 0 {
|
|
return nil
|
|
}
|
|
w := arcs[0]
|
|
e.s++
|
|
e.p[e.s] = w
|
|
e.g[u.To] = arcs[1:] // consume arc
|
|
// difference from directed counterpart in dir.go:
|
|
// as long as it's not a loop, consume reciprocal arc as well
|
|
if w.To != u.To {
|
|
a2 := e.g[w.To]
|
|
for x, rx := range a2 {
|
|
if rx.To == u.To && rx.Label == w.Label { // here it is
|
|
last := len(a2) - 1
|
|
a2[x] = a2[last] // someone else can have the seat
|
|
e.g[w.To] = a2[:last] // and it's gone.
|
|
goto l
|
|
}
|
|
}
|
|
return fmt.Errorf("graph not undirected. %d -> %v reciprocal not found", u.To, w)
|
|
}
|
|
l:
|
|
u = w
|
|
}
|
|
}
|