mirror of
https://github.com/gonum/gonum.git
synced 2025-10-07 08:01:20 +08:00
86 lines
1.8 KiB
Go
86 lines
1.8 KiB
Go
// Copyright ©2017 The Gonum Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package topo
|
|
|
|
import (
|
|
"gonum.org/v1/gonum/graph"
|
|
"gonum.org/v1/gonum/graph/internal/linear"
|
|
"gonum.org/v1/gonum/graph/internal/set"
|
|
)
|
|
|
|
// UndirectedCyclesIn returns a set of cycles that forms a cycle basis in the graph g.
|
|
// Any cycle in g can be constructed as a symmetric difference of its elements.
|
|
func UndirectedCyclesIn(g graph.Undirected) [][]graph.Node {
|
|
// From "An algorithm for finding a fundamental set of cycles of a graph"
|
|
// https://doi.org/10.1145/363219.363232
|
|
|
|
var cycles [][]graph.Node
|
|
done := make(set.Int64s)
|
|
var tree linear.NodeStack
|
|
nodes := g.Nodes()
|
|
for nodes.Next() {
|
|
n := nodes.Node()
|
|
id := n.ID()
|
|
if done.Has(id) {
|
|
continue
|
|
}
|
|
done.Add(id)
|
|
|
|
tree = tree[:0]
|
|
tree.Push(n)
|
|
from := sets{id: set.Int64s{}}
|
|
to := map[int64]graph.Node{id: n}
|
|
|
|
for tree.Len() != 0 {
|
|
u := tree.Pop()
|
|
uid := u.ID()
|
|
adj := from[uid]
|
|
it := g.From(uid)
|
|
for it.Next() {
|
|
v := it.Node()
|
|
vid := v.ID()
|
|
switch {
|
|
case uid == vid:
|
|
cycles = append(cycles, []graph.Node{u})
|
|
case !from.has(vid):
|
|
done.Add(vid)
|
|
to[vid] = u
|
|
tree.Push(v)
|
|
from.add(uid, vid)
|
|
case !adj.Has(vid):
|
|
c := []graph.Node{v, u}
|
|
adj := from[vid]
|
|
p := to[uid]
|
|
for !adj.Has(p.ID()) {
|
|
c = append(c, p)
|
|
p = to[p.ID()]
|
|
}
|
|
c = append(c, p, c[0])
|
|
cycles = append(cycles, c)
|
|
adj.Add(uid)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return cycles
|
|
}
|
|
|
|
type sets map[int64]set.Int64s
|
|
|
|
func (s sets) add(uid, vid int64) {
|
|
e, ok := s[vid]
|
|
if !ok {
|
|
e = make(set.Int64s)
|
|
s[vid] = e
|
|
}
|
|
e.Add(uid)
|
|
}
|
|
|
|
func (s sets) has(uid int64) bool {
|
|
_, ok := s[uid]
|
|
return ok
|
|
}
|