418 lines
12 KiB
Go
418 lines
12 KiB
Go
|
// Copyright 2014 Sonia Keys
|
||
|
// License MIT: http://opensource.org/licenses/MIT
|
||
|
|
||
|
package graph
|
||
|
|
||
|
// adj_RO.go is code generated from adj_cg.go by directives in graph.go.
|
||
|
// Editing adj_cg.go is okay.
|
||
|
// DO NOT EDIT adj_RO.go. The RO is for Read Only.
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"math/rand"
|
||
|
|
||
|
"github.com/soniakeys/bits"
|
||
|
)
|
||
|
|
||
|
// ArcDensity returns density for an simple directed graph.
|
||
|
//
|
||
|
// See also ArcDensity function.
|
||
|
//
|
||
|
// There are equivalent labeled and unlabeled versions of this method.
|
||
|
func (g AdjacencyList) ArcDensity() float64 {
|
||
|
return ArcDensity(len(g), g.ArcSize())
|
||
|
}
|
||
|
|
||
|
// ArcSize returns the number of arcs in g.
|
||
|
//
|
||
|
// Note that for an undirected graph without loops, the number of undirected
|
||
|
// edges -- the traditional meaning of graph size -- will be ArcSize()/2.
|
||
|
// On the other hand, if g is an undirected graph that has or may have loops,
|
||
|
// g.ArcSize()/2 is not a meaningful quantity.
|
||
|
//
|
||
|
// There are equivalent labeled and unlabeled versions of this method.
|
||
|
func (g AdjacencyList) ArcSize() int {
|
||
|
m := 0
|
||
|
for _, to := range g {
|
||
|
m += len(to)
|
||
|
}
|
||
|
return m
|
||
|
}
|
||
|
|
||
|
// BoundsOk validates that all arcs in g stay within the slice bounds of g.
|
||
|
//
|
||
|
// BoundsOk returns true when no arcs point outside the bounds of g.
|
||
|
// Otherwise it returns false and an example arc that points outside of g.
|
||
|
//
|
||
|
// Most methods of this package assume the BoundsOk condition and may
|
||
|
// panic when they encounter an arc pointing outside of the graph. This
|
||
|
// function can be used to validate a graph when the BoundsOk condition
|
||
|
// is unknown.
|
||
|
//
|
||
|
// There are equivalent labeled and unlabeled versions of this method.
|
||
|
func (g AdjacencyList) BoundsOk() (ok bool, fr NI, to NI) {
|
||
|
for fr, to := range g {
|
||
|
for _, to := range to {
|
||
|
if to < 0 || to >= NI(len(g)) {
|
||
|
return false, NI(fr), to
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return true, -1, to
|
||
|
}
|
||
|
|
||
|
// BreadthFirst traverses a directed or undirected graph in breadth
|
||
|
// first order.
|
||
|
//
|
||
|
// Traversal starts at node start and visits the nodes reachable from
|
||
|
// start. The function visit is called for each node visited. Nodes
|
||
|
// not reachable from start are not visited.
|
||
|
//
|
||
|
// There are equivalent labeled and unlabeled versions of this method.
|
||
|
//
|
||
|
// See also alt.BreadthFirst, a variant with more options, and
|
||
|
// alt.BreadthFirst2, a direction optimizing variant.
|
||
|
func (g AdjacencyList) BreadthFirst(start NI, visit func(NI)) {
|
||
|
v := bits.New(len(g))
|
||
|
v.SetBit(int(start), 1)
|
||
|
visit(start)
|
||
|
var next []NI
|
||
|
for frontier := []NI{start}; len(frontier) > 0; {
|
||
|
for _, n := range frontier {
|
||
|
for _, nb := range g[n] {
|
||
|
if v.Bit(int(nb)) == 0 {
|
||
|
v.SetBit(int(nb), 1)
|
||
|
visit(nb)
|
||
|
next = append(next, nb)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
frontier, next = next, frontier[:0]
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 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 AdjacencyList) Copy() (c AdjacencyList, ma int) {
|
||
|
c = make(AdjacencyList, len(g))
|
||
|
for n, to := range g {
|
||
|
c[n] = append([]NI{}, to...)
|
||
|
ma += len(to)
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// DepthFirst traverses a directed or undirected graph in depth
|
||
|
// first order.
|
||
|
//
|
||
|
// Traversal starts at node start and visits the nodes reachable from
|
||
|
// start. The function visit is called for each node visited. Nodes
|
||
|
// not reachable from start are not visited.
|
||
|
//
|
||
|
// There are equivalent labeled and unlabeled versions of this method.
|
||
|
//
|
||
|
// See also alt.DepthFirst, a variant with more options.
|
||
|
func (g AdjacencyList) DepthFirst(start NI, visit func(NI)) {
|
||
|
v := bits.New(len(g))
|
||
|
var f func(NI)
|
||
|
f = func(n NI) {
|
||
|
visit(n)
|
||
|
v.SetBit(int(n), 1)
|
||
|
for _, to := range g[n] {
|
||
|
if v.Bit(int(to)) == 0 {
|
||
|
f(to)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
f(start)
|
||
|
}
|
||
|
|
||
|
// HasArc returns true if g has any arc from node `fr` to node `to`.
|
||
|
//
|
||
|
// Also returned is the index within the slice of arcs from node `fr`.
|
||
|
// If no arc from `fr` to `to` is present, HasArc returns false, -1.
|
||
|
//
|
||
|
// There are equivalent labeled and unlabeled versions of this method.
|
||
|
//
|
||
|
// See also the method ParallelArcs, which finds all parallel arcs from
|
||
|
// `fr` to `to`.
|
||
|
func (g AdjacencyList) HasArc(fr, to NI) (bool, int) {
|
||
|
for x, h := range g[fr] {
|
||
|
if h == to {
|
||
|
return true, x
|
||
|
}
|
||
|
}
|
||
|
return false, -1
|
||
|
}
|
||
|
|
||
|
// AnyLoop identifies if a graph contains a loop, an arc that leads from a
|
||
|
// a node back to the same node.
|
||
|
//
|
||
|
// If g contains a loop, the method returns true and an example of a node
|
||
|
// with a loop. If there are no loops in g, the method returns false, -1.
|
||
|
//
|
||
|
// There are equivalent labeled and unlabeled versions of this method.
|
||
|
func (g AdjacencyList) AnyLoop() (bool, NI) {
|
||
|
for fr, to := range g {
|
||
|
for _, to := range to {
|
||
|
if NI(fr) == to {
|
||
|
return true, to
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return false, -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 *Subgraph) 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.AdjacencyList
|
||
|
b = NI(len(a))
|
||
|
s.AdjacencyList = append(a, nil)
|
||
|
s.SuperNI = append(s.SuperNI, p)
|
||
|
s.SubNI[p] = b
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// AddArc adds an arc to a subgraph.
|
||
|
//
|
||
|
// Arguments fr, to must be NIs in supergraph s.Super. As with AddNode,
|
||
|
// AddArc panics if fr and to are not valid node indexes of s.Super.
|
||
|
//
|
||
|
// The arc specfied by fr, to must exist in s.Super. Further, the number of
|
||
|
// parallel arcs in the subgraph cannot exceed the number of corresponding
|
||
|
// parallel arcs in the supergraph. That is, each arc already added to the
|
||
|
// subgraph counts against the arcs available in the supergraph. If a matching
|
||
|
// arc is not available, AddArc returns an error.
|
||
|
//
|
||
|
// If a matching arc is available, subgraph nodes are added as needed, the
|
||
|
// subgraph arc is added, and the method returns nil.
|
||
|
func (s *Subgraph) AddArc(fr NI, to NI) error {
|
||
|
// verify supergraph NIs first, but without adding subgraph nodes just yet.
|
||
|
if int(fr) < 0 || int(fr) >= s.Super.Order() {
|
||
|
panic(fmt.Sprint("AddArc: NI ", fr, " not in supergraph"))
|
||
|
}
|
||
|
if int(to) < 0 || int(to) >= s.Super.Order() {
|
||
|
panic(fmt.Sprint("AddArc: NI ", to, " not in supergraph"))
|
||
|
}
|
||
|
// count existing matching arcs in subgraph
|
||
|
n := 0
|
||
|
a := s.AdjacencyList
|
||
|
if bf, ok := s.SubNI[fr]; ok {
|
||
|
if bt, ok := s.SubNI[to]; ok {
|
||
|
// both NIs already exist in subgraph, need to count arcs
|
||
|
bTo := to
|
||
|
bTo = bt
|
||
|
for _, t := range a[bf] {
|
||
|
if t == bTo {
|
||
|
n++
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// verify matching arcs are available in supergraph
|
||
|
for _, t := range (*s.Super)[fr] {
|
||
|
if t == to {
|
||
|
if n > 0 {
|
||
|
n-- // match existing arc
|
||
|
continue
|
||
|
}
|
||
|
// no more existing arcs need to be matched. nodes can finally
|
||
|
// be added as needed and then the arc can be added.
|
||
|
bf := s.AddNode(fr)
|
||
|
to = s.AddNode(to)
|
||
|
s.AdjacencyList[bf] = append(s.AdjacencyList[bf], to)
|
||
|
return nil // success
|
||
|
}
|
||
|
}
|
||
|
return errors.New("arc not available in supergraph")
|
||
|
}
|
||
|
|
||
|
func (super AdjacencyList) induceArcs(sub map[NI]NI, sup []NI) AdjacencyList {
|
||
|
s := make(AdjacencyList, len(sup))
|
||
|
for b, p := range sup {
|
||
|
var a []NI
|
||
|
for _, to := range super[p] {
|
||
|
if bt, ok := sub[to]; ok {
|
||
|
to = bt
|
||
|
a = append(a, to)
|
||
|
}
|
||
|
}
|
||
|
s[b] = a
|
||
|
}
|
||
|
return s
|
||
|
}
|
||
|
|
||
|
// 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 *AdjacencyList) InduceList(l []NI) *Subgraph {
|
||
|
sub, sup := mapList(l)
|
||
|
return &Subgraph{
|
||
|
Super: g,
|
||
|
SubNI: sub,
|
||
|
SuperNI: sup,
|
||
|
|
||
|
AdjacencyList: g.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 *AdjacencyList) InduceBits(t bits.Bits) *Subgraph {
|
||
|
sub, sup := mapBits(t)
|
||
|
return &Subgraph{
|
||
|
Super: g,
|
||
|
SubNI: sub,
|
||
|
SuperNI: sup,
|
||
|
|
||
|
AdjacencyList: g.induceArcs(sub, sup)}
|
||
|
}
|
||
|
|
||
|
// IsSimple checks for loops and parallel arcs.
|
||
|
//
|
||
|
// A graph is "simple" if it has no loops or parallel arcs.
|
||
|
//
|
||
|
// IsSimple returns true, -1 for simple graphs. If a loop or parallel arc is
|
||
|
// found, simple returns false and a node that represents a counterexample
|
||
|
// to the graph being simple.
|
||
|
//
|
||
|
// See also separate methods AnyLoop and AnyParallel.
|
||
|
//
|
||
|
// There are equivalent labeled and unlabeled versions of this method.
|
||
|
func (g AdjacencyList) IsSimple() (ok bool, n NI) {
|
||
|
if lp, n := g.AnyLoop(); lp {
|
||
|
return false, n
|
||
|
}
|
||
|
if pa, n, _ := g.AnyParallel(); pa {
|
||
|
return false, n
|
||
|
}
|
||
|
return true, -1
|
||
|
}
|
||
|
|
||
|
// IsolatedNodes returns a bitmap of isolated nodes in receiver graph g.
|
||
|
//
|
||
|
// An isolated node is one with no arcs going to or from it.
|
||
|
//
|
||
|
// There are equivalent labeled and unlabeled versions of this method.
|
||
|
func (g AdjacencyList) IsolatedNodes() (i bits.Bits) {
|
||
|
i = bits.New(len(g))
|
||
|
i.SetAll()
|
||
|
for fr, to := range g {
|
||
|
if len(to) > 0 {
|
||
|
i.SetBit(fr, 0)
|
||
|
for _, to := range to {
|
||
|
i.SetBit(int(to), 0)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Order is the number of nodes in receiver g.
|
||
|
//
|
||
|
// It is simply a wrapper method for the Go builtin len().
|
||
|
//
|
||
|
// There are equivalent labeled and unlabeled versions of this method.
|
||
|
func (g AdjacencyList) Order() int {
|
||
|
// Why a wrapper for len()? Mostly for Directed and Undirected.
|
||
|
// u.Order() is a little nicer than len(u.LabeledAdjacencyList).
|
||
|
return len(g)
|
||
|
}
|
||
|
|
||
|
// ParallelArcs identifies all arcs from node `fr` to node `to`.
|
||
|
//
|
||
|
// The returned slice contains an element for each arc from node `fr` to node `to`.
|
||
|
// The element value is the index within the slice of arcs from node `fr`.
|
||
|
//
|
||
|
// There are equivalent labeled and unlabeled versions of this method.
|
||
|
//
|
||
|
// See also the method HasArc, which stops after finding a single arc.
|
||
|
func (g AdjacencyList) ParallelArcs(fr, to NI) (p []int) {
|
||
|
for x, h := range g[fr] {
|
||
|
if h == to {
|
||
|
p = append(p, x)
|
||
|
}
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Permute permutes the node labeling of receiver g.
|
||
|
//
|
||
|
// Argument p must be a permutation of the node numbers of the graph,
|
||
|
// 0 through len(g)-1. A permutation returned by rand.Perm(len(g)) for
|
||
|
// example is acceptable.
|
||
|
//
|
||
|
// The graph is permuted in place. The graph keeps the same underlying
|
||
|
// memory but values of the graph representation are permuted to produce
|
||
|
// an isomorphic graph. The node previously labeled 0 becomes p[0] and so on.
|
||
|
// See example (or the code) for clarification.
|
||
|
//
|
||
|
// There are equivalent labeled and unlabeled versions of this method.
|
||
|
func (g AdjacencyList) Permute(p []int) {
|
||
|
old := append(AdjacencyList{}, g...) // shallow copy
|
||
|
for fr, arcs := range old {
|
||
|
for i, to := range arcs {
|
||
|
arcs[i] = NI(p[to])
|
||
|
}
|
||
|
g[p[fr]] = arcs
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ShuffleArcLists shuffles the arc lists of each node of receiver g.
|
||
|
//
|
||
|
// For example a node with arcs leading to nodes 3 and 7 might have an
|
||
|
// arc list of either [3 7] or [7 3] after calling this method. The
|
||
|
// connectivity of the graph is not changed. The resulting graph stays
|
||
|
// equivalent but a traversal will encounter arcs in a different
|
||
|
// order.
|
||
|
//
|
||
|
// If Rand r is nil, the rand package default shared source is used.
|
||
|
//
|
||
|
// There are equivalent labeled and unlabeled versions of this method.
|
||
|
func (g AdjacencyList) ShuffleArcLists(r *rand.Rand) {
|
||
|
ri := rand.Intn
|
||
|
if r != nil {
|
||
|
ri = r.Intn
|
||
|
}
|
||
|
// Knuth-Fisher-Yates
|
||
|
for _, to := range g {
|
||
|
for i := len(to); i > 1; {
|
||
|
j := ri(i)
|
||
|
i--
|
||
|
to[i], to[j] = to[j], to[i]
|
||
|
}
|
||
|
}
|
||
|
}
|