mirror of
https://github.com/gonum/gonum.git
synced 2025-10-26 16:50:28 +08:00
149 lines
3.9 KiB
Go
149 lines
3.9 KiB
Go
package concrete
|
|
|
|
import (
|
|
"github.com/gonum/graph"
|
|
"math"
|
|
)
|
|
|
|
// A dense graph is a graph such that all IDs are in a contiguous block from 0 to
|
|
// TheNumberOfNodes-1. It uses an adjacency matrix and should be relatively fast for both access
|
|
// and writing.
|
|
//
|
|
// This graph implements the CrunchGraph, but since it's naturally dense this is superfluous.
|
|
type DenseGraph struct {
|
|
adjacencyMatrix []float64
|
|
numNodes int
|
|
}
|
|
|
|
// Creates a dense graph with the proper number of nodes. If passable is true all nodes will have
|
|
// an edge with cost 1.0, otherwise every node will start unconnected (cost of +Inf.)
|
|
func NewDenseGraph(numNodes int, passable bool) *DenseGraph {
|
|
dg := &DenseGraph{adjacencyMatrix: make([]float64, numNodes*numNodes), numNodes: numNodes}
|
|
if passable {
|
|
for i := range dg.adjacencyMatrix {
|
|
dg.adjacencyMatrix[i] = 1.0
|
|
}
|
|
} else {
|
|
for i := range dg.adjacencyMatrix {
|
|
dg.adjacencyMatrix[i] = math.Inf(1)
|
|
}
|
|
}
|
|
|
|
return dg
|
|
}
|
|
|
|
func (dg *DenseGraph) NodeExists(node graph.Node) bool {
|
|
return node.ID() < dg.numNodes
|
|
}
|
|
|
|
func (dg *DenseGraph) Degree(node graph.Node) int {
|
|
deg := 0
|
|
for i := 0; i < dg.numNodes; i++ {
|
|
if dg.adjacencyMatrix[i*dg.numNodes+node.ID()] != math.Inf(1) {
|
|
deg++
|
|
}
|
|
|
|
if dg.adjacencyMatrix[node.ID()*dg.numNodes+i] != math.Inf(1) {
|
|
deg++
|
|
}
|
|
}
|
|
|
|
return deg
|
|
}
|
|
|
|
func (dg *DenseGraph) NodeList() []graph.Node {
|
|
nodes := make([]graph.Node, dg.numNodes)
|
|
for i := 0; i < dg.numNodes; i++ {
|
|
nodes[i] = Node(i)
|
|
}
|
|
|
|
return nodes
|
|
}
|
|
|
|
func (dg *DenseGraph) DirectedEdgeList() []graph.Edge {
|
|
edges := make([]graph.Edge, 0, len(dg.adjacencyMatrix))
|
|
for i := 0; i < dg.numNodes; i++ {
|
|
for j := 0; j < dg.numNodes; j++ {
|
|
if dg.adjacencyMatrix[i*dg.numNodes+j] != math.Inf(1) {
|
|
edges = append(edges, Edge{Node(i), Node(j)})
|
|
}
|
|
}
|
|
}
|
|
|
|
return edges
|
|
}
|
|
|
|
func (dg *DenseGraph) Neighbors(node graph.Node) []graph.Node {
|
|
neighbors := make([]graph.Node, 0)
|
|
for i := 0; i < dg.numNodes; i++ {
|
|
if dg.adjacencyMatrix[i*dg.numNodes+node.ID()] != math.Inf(1) ||
|
|
dg.adjacencyMatrix[node.ID()*dg.numNodes+i] != math.Inf(1) {
|
|
neighbors = append(neighbors, Node(i))
|
|
}
|
|
}
|
|
|
|
return neighbors
|
|
}
|
|
|
|
func (dg *DenseGraph) EdgeBetween(node, neighbor graph.Node) graph.Edge {
|
|
if dg.adjacencyMatrix[neighbor.ID()*dg.numNodes+node.ID()] != math.Inf(1) ||
|
|
dg.adjacencyMatrix[node.ID()*dg.numNodes+neighbor.ID()] != math.Inf(1) {
|
|
return Edge{node, neighbor}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (dg *DenseGraph) Successors(node graph.Node) []graph.Node {
|
|
neighbors := make([]graph.Node, 0)
|
|
for i := 0; i < dg.numNodes; i++ {
|
|
if dg.adjacencyMatrix[node.ID()*dg.numNodes+i] != math.Inf(1) {
|
|
neighbors = append(neighbors, Node(i))
|
|
}
|
|
}
|
|
|
|
return neighbors
|
|
}
|
|
|
|
func (dg *DenseGraph) EdgeTo(node, succ graph.Node) graph.Edge {
|
|
if dg.adjacencyMatrix[node.ID()*dg.numNodes+succ.ID()] != math.Inf(1) {
|
|
return Edge{node, succ}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (dg *DenseGraph) Predecessors(node graph.Node) []graph.Node {
|
|
neighbors := make([]graph.Node, 0)
|
|
for i := 0; i < dg.numNodes; i++ {
|
|
if dg.adjacencyMatrix[i*dg.numNodes+node.ID()] != math.Inf(1) {
|
|
neighbors = append(neighbors, Node(i))
|
|
}
|
|
}
|
|
|
|
return neighbors
|
|
}
|
|
|
|
// DenseGraph is naturally dense, we don't need to do anything
|
|
func (dg *DenseGraph) Crunch() {
|
|
}
|
|
|
|
func (dg *DenseGraph) Cost(e graph.Edge) float64 {
|
|
return dg.adjacencyMatrix[e.Head().ID()*dg.numNodes+e.Tail().ID()]
|
|
}
|
|
|
|
// Sets the cost of an edge. If the cost is +Inf, it will remove the edge,
|
|
// if directed is true, it will only remove the edge one way. If it's false it will change the cost
|
|
// of the edge from succ to node as well.
|
|
func (dg *DenseGraph) SetEdgeCost(e graph.Edge, cost float64, directed bool) {
|
|
dg.adjacencyMatrix[e.Head().ID()*dg.numNodes+e.Tail().ID()] = cost
|
|
if !directed {
|
|
dg.adjacencyMatrix[e.Tail().ID()*dg.numNodes+e.Head().ID()] = cost
|
|
}
|
|
}
|
|
|
|
// Equivalent to SetEdgeCost(edge, math.Inf(1), directed)
|
|
func (dg *DenseGraph) RemoveEdge(e graph.Edge, directed bool) {
|
|
dg.SetEdgeCost(e, math.Inf(1), directed)
|
|
}
|