forked from LaconicNetwork/kompose
251 lines
5.0 KiB
Go
251 lines
5.0 KiB
Go
// Copyright ©2014 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 concrete
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/gonum/graph"
|
|
)
|
|
|
|
// A simple int alias.
|
|
type Node int
|
|
|
|
func (n Node) ID() int {
|
|
return int(n)
|
|
}
|
|
|
|
// Just a collection of two nodes
|
|
type Edge struct {
|
|
F, T graph.Node
|
|
}
|
|
|
|
func (e Edge) From() graph.Node {
|
|
return e.F
|
|
}
|
|
|
|
func (e Edge) To() graph.Node {
|
|
return e.T
|
|
}
|
|
|
|
type WeightedEdge struct {
|
|
graph.Edge
|
|
Cost float64
|
|
}
|
|
|
|
// A GonumGraph is a very generalized graph that can handle an arbitrary number of vertices and
|
|
// edges -- as well as act as either directed or undirected.
|
|
//
|
|
// Internally, it uses a map of successors AND predecessors, to speed up some operations (such as
|
|
// getting all successors/predecessors). It also speeds up things like adding edges (assuming both
|
|
// edges exist).
|
|
//
|
|
// However, its generality is also its weakness (and partially a flaw in needing to satisfy
|
|
// MutableGraph). For most purposes, creating your own graph is probably better. For instance,
|
|
// see TileGraph for an example of an immutable 2D grid of tiles that also implements the Graph
|
|
// interface, but would be more suitable if all you needed was a simple undirected 2D grid.
|
|
type Graph struct {
|
|
neighbors map[int]map[int]WeightedEdge
|
|
nodeMap map[int]graph.Node
|
|
|
|
// Node add/remove convenience vars
|
|
maxID int
|
|
freeMap map[int]struct{}
|
|
}
|
|
|
|
func NewGraph() *Graph {
|
|
return &Graph{
|
|
neighbors: make(map[int]map[int]WeightedEdge),
|
|
nodeMap: make(map[int]graph.Node),
|
|
maxID: 0,
|
|
freeMap: make(map[int]struct{}),
|
|
}
|
|
}
|
|
|
|
func (g *Graph) NewNodeID() int {
|
|
if g.maxID != maxInt {
|
|
g.maxID++
|
|
return g.maxID
|
|
}
|
|
|
|
// Implicitly checks if len(g.freeMap) == 0
|
|
for id := range g.freeMap {
|
|
return id
|
|
}
|
|
|
|
// I cannot foresee this ever happening, but just in case, we check.
|
|
if len(g.nodeMap) == maxInt {
|
|
panic("cannot allocate node: graph too large")
|
|
}
|
|
|
|
for i := 0; i < maxInt; i++ {
|
|
if _, ok := g.nodeMap[i]; !ok {
|
|
return i
|
|
}
|
|
}
|
|
|
|
// Should not happen.
|
|
panic("cannot allocate node id: no free id found")
|
|
}
|
|
|
|
func (g *Graph) AddNode(n graph.Node) {
|
|
if _, exists := g.nodeMap[n.ID()]; exists {
|
|
panic(fmt.Sprintf("concrete: node ID collision: %d", n.ID()))
|
|
}
|
|
g.nodeMap[n.ID()] = n
|
|
g.neighbors[n.ID()] = make(map[int]WeightedEdge)
|
|
|
|
delete(g.freeMap, n.ID())
|
|
g.maxID = max(g.maxID, n.ID())
|
|
}
|
|
|
|
func (g *Graph) SetEdge(e graph.Edge, cost float64) {
|
|
var (
|
|
from = e.From()
|
|
fid = from.ID()
|
|
to = e.To()
|
|
tid = to.ID()
|
|
)
|
|
|
|
if fid == tid {
|
|
panic("concrete: adding self edge")
|
|
}
|
|
|
|
if !g.Has(from) {
|
|
g.AddNode(from)
|
|
}
|
|
|
|
if !g.Has(to) {
|
|
g.AddNode(to)
|
|
}
|
|
|
|
g.neighbors[fid][tid] = WeightedEdge{Edge: e, Cost: cost}
|
|
g.neighbors[tid][fid] = WeightedEdge{Edge: e, Cost: cost}
|
|
}
|
|
|
|
func (g *Graph) RemoveNode(n graph.Node) {
|
|
if _, ok := g.nodeMap[n.ID()]; !ok {
|
|
return
|
|
}
|
|
delete(g.nodeMap, n.ID())
|
|
|
|
for neigh := range g.neighbors[n.ID()] {
|
|
delete(g.neighbors[neigh], n.ID())
|
|
}
|
|
delete(g.neighbors, n.ID())
|
|
|
|
if g.maxID != 0 && n.ID() == g.maxID {
|
|
g.maxID--
|
|
}
|
|
g.freeMap[n.ID()] = struct{}{}
|
|
}
|
|
|
|
func (g *Graph) RemoveEdge(e graph.Edge) {
|
|
from, to := e.From(), e.To()
|
|
if _, ok := g.nodeMap[from.ID()]; !ok {
|
|
return
|
|
} else if _, ok := g.nodeMap[to.ID()]; !ok {
|
|
return
|
|
}
|
|
|
|
delete(g.neighbors[from.ID()], to.ID())
|
|
delete(g.neighbors[to.ID()], from.ID())
|
|
}
|
|
|
|
func (g *Graph) EmptyGraph() {
|
|
g.neighbors = make(map[int]map[int]WeightedEdge)
|
|
g.nodeMap = make(map[int]graph.Node)
|
|
}
|
|
|
|
/* Graph implementation */
|
|
|
|
func (g *Graph) From(n graph.Node) []graph.Node {
|
|
if !g.Has(n) {
|
|
return nil
|
|
}
|
|
|
|
neighbors := make([]graph.Node, len(g.neighbors[n.ID()]))
|
|
i := 0
|
|
for id := range g.neighbors[n.ID()] {
|
|
neighbors[i] = g.nodeMap[id]
|
|
i++
|
|
}
|
|
|
|
return neighbors
|
|
}
|
|
|
|
func (g *Graph) HasEdge(n, neigh graph.Node) bool {
|
|
_, ok := g.neighbors[n.ID()][neigh.ID()]
|
|
return ok
|
|
}
|
|
|
|
func (g *Graph) Edge(u, v graph.Node) graph.Edge {
|
|
return g.EdgeBetween(u, v)
|
|
}
|
|
|
|
func (g *Graph) EdgeBetween(u, v graph.Node) graph.Edge {
|
|
// We don't need to check if neigh exists because
|
|
// it's implicit in the neighbors access.
|
|
if !g.Has(u) {
|
|
return nil
|
|
}
|
|
|
|
return g.neighbors[u.ID()][v.ID()].Edge
|
|
}
|
|
|
|
func (g *Graph) Node(id int) graph.Node {
|
|
return g.nodeMap[id]
|
|
}
|
|
|
|
func (g *Graph) Has(n graph.Node) bool {
|
|
_, ok := g.nodeMap[n.ID()]
|
|
|
|
return ok
|
|
}
|
|
|
|
func (g *Graph) Nodes() []graph.Node {
|
|
nodes := make([]graph.Node, len(g.nodeMap))
|
|
i := 0
|
|
for _, n := range g.nodeMap {
|
|
nodes[i] = n
|
|
i++
|
|
}
|
|
|
|
return nodes
|
|
}
|
|
|
|
func (g *Graph) Weight(e graph.Edge) float64 {
|
|
if n, ok := g.neighbors[e.From().ID()]; ok {
|
|
if we, ok := n[e.To().ID()]; ok {
|
|
return we.Cost
|
|
}
|
|
}
|
|
return inf
|
|
}
|
|
|
|
func (g *Graph) Edges() []graph.Edge {
|
|
m := make(map[WeightedEdge]struct{})
|
|
toReturn := make([]graph.Edge, 0)
|
|
|
|
for _, neighs := range g.neighbors {
|
|
for _, we := range neighs {
|
|
if _, ok := m[we]; !ok {
|
|
m[we] = struct{}{}
|
|
toReturn = append(toReturn, we.Edge)
|
|
}
|
|
}
|
|
}
|
|
|
|
return toReturn
|
|
}
|
|
|
|
func (g *Graph) Degree(n graph.Node) int {
|
|
if _, ok := g.nodeMap[n.ID()]; !ok {
|
|
return 0
|
|
}
|
|
|
|
return len(g.neighbors[n.ID()])
|
|
}
|