Files
gonum/graph/graphs/gen/gen.go

160 lines
4.0 KiB
Go

// Copyright ©2015 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 gen
import (
"fmt"
"gonum.org/v1/gonum/graph"
)
// GraphBuilder is a graph that can have nodes and edges added.
type GraphBuilder interface {
HasEdgeBetween(xid, yid int64) bool
graph.Builder
}
func abs(a int) int {
if a < 0 {
return -a
}
return a
}
// NodeIDGraphBuild is a graph that can create new nodes with
// specified IDs.
type NodeIDGraphBuilder interface {
graph.Builder
graph.NodeWithIDer
}
// IDer is a mapping from an index to a node ID.
type IDer interface {
// Len returns the length of the set of node IDs.
Len() int
// ID returns the ID of the indexed node.
// ID must be a bijective function. No check
// is made for this property.
ID(int) int64
}
// IDRange is an IDer that provides a set of IDs in [First, Last].
type IDRange struct{ First, Last int64 }
func (r IDRange) Len() int { return int(r.Last - r.First + 1) }
func (r IDRange) ID(i int) int64 { return r.First + int64(i) }
// IDSet is an IDer providing an explicit set of IDs.
type IDSet []int64
func (s IDSet) Len() int { return len(s) }
func (s IDSet) ID(i int) int64 { return s[i] }
// Complete constructs a complete graph in dst using nodes with the given IDs.
func Complete(dst NodeIDGraphBuilder, ids IDer) error {
if ids.Len() == 1 {
u, new := dst.NodeWithID(ids.ID(0))
if new {
dst.AddNode(u)
}
return nil
}
for i := 0; i < ids.Len(); i++ {
uid := ids.ID(i)
u, _ := dst.NodeWithID(uid)
for j := i + 1; j < ids.Len(); j++ {
vid := ids.ID(j)
if uid == vid {
return fmt.Errorf("gen: node ID collision i=%d j=%d: %d", i, j, uid)
}
v, _ := dst.NodeWithID(vid)
dst.SetEdge(dst.NewEdge(u, v))
}
}
return nil
}
// Cycle constructs a cycle in dst using the node IDs in cycle.
// If dst is a directed graph, edges are directed from earlier nodes to later
// nodes in cycle.
func Cycle(dst NodeIDGraphBuilder, cycle IDer) error {
if cycle.Len() == 1 {
u, new := dst.NodeWithID(cycle.ID(0))
if new {
dst.AddNode(u)
}
return nil
}
for i := 0; i < cycle.Len(); i++ {
uid := cycle.ID(i)
vid := cycle.ID((i + 1) % cycle.Len())
if uid == vid {
return fmt.Errorf("gen: adjacent node IDs equal at %d: %d", i, uid)
}
u, _ := dst.NodeWithID(uid)
v, _ := dst.NodeWithID(vid)
dst.SetEdge(dst.NewEdge(u, v))
}
return nil
}
// Path constructs a path graph in dst with
// If dst is a directed graph, edges are directed from earlier nodes to later
// nodes in path.
func Path(dst NodeIDGraphBuilder, path IDer) error {
if path.Len() == 1 {
u, new := dst.NodeWithID(path.ID(0))
if new {
dst.AddNode(u)
}
return nil
}
for i := 0; i < path.Len()-1; i++ {
uid := path.ID(i)
vid := path.ID(i + 1)
if uid == vid {
return fmt.Errorf("gen: adjacent node IDs equal at %d: %d", i, uid)
}
u, _ := dst.NodeWithID(uid)
v, _ := dst.NodeWithID(vid)
dst.SetEdge(dst.NewEdge(u, v))
}
return nil
}
// Star constructs a star graph in dst with edges between the center node ID to
// node with IDs specified in leaves.
// If dst is a directed graph, edges are directed from the center node to the
// leaves.
func Star(dst NodeIDGraphBuilder, center int64, leaves IDer) error {
c, new := dst.NodeWithID(center)
if new {
dst.AddNode(c)
}
for i := 0; i < leaves.Len(); i++ {
id := leaves.ID(i)
if id == center {
return fmt.Errorf("gen: leaf %d ID matches central node ID: %d", i, center)
}
n, _ := dst.NodeWithID(id)
dst.SetEdge(dst.NewEdge(c, n))
}
return nil
}
// Wheel constructs a wheel graph in dst with edges from the center
// node ID to node with IDs specified in cycle and between nodes with IDs
// adjacent in the cycle.
// If dst is a directed graph, edges are directed from the center node to the
// cycle and from earlier nodes to later nodes in cycle.
func Wheel(dst NodeIDGraphBuilder, center int64, cycle IDer) error {
err := Star(dst, center, cycle)
if err != nil {
return err
}
return Cycle(dst, cycle)
}