github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/graph/simple/dense_directed_matrix.go (about) 1 // Copyright ©2014 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package simple 6 7 import ( 8 "sort" 9 10 "github.com/jingcheng-WU/gonum/graph" 11 "github.com/jingcheng-WU/gonum/graph/internal/ordered" 12 "github.com/jingcheng-WU/gonum/graph/iterator" 13 "github.com/jingcheng-WU/gonum/mat" 14 ) 15 16 var ( 17 dm *DirectedMatrix 18 19 _ graph.Graph = dm 20 _ graph.Directed = dm 21 _ edgeSetter = dm 22 _ weightedEdgeSetter = dm 23 ) 24 25 // DirectedMatrix represents a directed graph using an adjacency 26 // matrix such that all IDs are in a contiguous block from 0 to n-1. 27 // Edges are stored implicitly as an edge weight, so edges stored in 28 // the graph are not recoverable. 29 type DirectedMatrix struct { 30 mat *mat.Dense 31 nodes []graph.Node 32 33 self float64 34 absent float64 35 } 36 37 // NewDirectedMatrix creates a directed dense graph with n nodes. 38 // All edges are initialized with the weight given by init. The self parameter 39 // specifies the cost of self connection, and absent specifies the weight 40 // returned for absent edges. 41 func NewDirectedMatrix(n int, init, self, absent float64) *DirectedMatrix { 42 matrix := make([]float64, n*n) 43 if init != 0 { 44 for i := range matrix { 45 matrix[i] = init 46 } 47 } 48 for i := 0; i < len(matrix); i += n + 1 { 49 matrix[i] = self 50 } 51 return &DirectedMatrix{ 52 mat: mat.NewDense(n, n, matrix), 53 self: self, 54 absent: absent, 55 } 56 } 57 58 // NewDirectedMatrixFrom creates a directed dense graph with the given nodes. 59 // The IDs of the nodes must be contiguous from 0 to len(nodes)-1, but may 60 // be in any order. If IDs are not contiguous NewDirectedMatrixFrom will panic. 61 // All edges are initialized with the weight given by init. The self parameter 62 // specifies the cost of self connection, and absent specifies the weight 63 // returned for absent edges. 64 func NewDirectedMatrixFrom(nodes []graph.Node, init, self, absent float64) *DirectedMatrix { 65 sort.Sort(ordered.ByID(nodes)) 66 for i, n := range nodes { 67 if int64(i) != n.ID() { 68 panic("simple: non-contiguous node IDs") 69 } 70 } 71 g := NewDirectedMatrix(len(nodes), init, self, absent) 72 g.nodes = nodes 73 return g 74 } 75 76 // Edge returns the edge from u to v if such an edge exists and nil otherwise. 77 // The node v must be directly reachable from u as defined by the From method. 78 func (g *DirectedMatrix) Edge(uid, vid int64) graph.Edge { 79 return g.WeightedEdge(uid, vid) 80 } 81 82 // Edges returns all the edges in the graph. 83 func (g *DirectedMatrix) Edges() graph.Edges { 84 var edges []graph.Edge 85 r, _ := g.mat.Dims() 86 for i := 0; i < r; i++ { 87 for j := 0; j < r; j++ { 88 if i == j { 89 continue 90 } 91 if w := g.mat.At(i, j); !isSame(w, g.absent) { 92 edges = append(edges, WeightedEdge{F: g.Node(int64(i)), T: g.Node(int64(j)), W: w}) 93 } 94 } 95 } 96 if len(edges) == 0 { 97 return graph.Empty 98 } 99 return iterator.NewOrderedEdges(edges) 100 } 101 102 // From returns all nodes in g that can be reached directly from n. 103 func (g *DirectedMatrix) From(id int64) graph.Nodes { 104 if !g.has(id) { 105 return graph.Empty 106 } 107 var nodes []graph.Node 108 _, c := g.mat.Dims() 109 for j := 0; j < c; j++ { 110 if int64(j) == id { 111 continue 112 } 113 // id is not greater than maximum int by this point. 114 if !isSame(g.mat.At(int(id), j), g.absent) { 115 nodes = append(nodes, g.Node(int64(j))) 116 } 117 } 118 if len(nodes) == 0 { 119 return graph.Empty 120 } 121 return iterator.NewOrderedNodes(nodes) 122 } 123 124 // HasEdgeBetween returns whether an edge exists between nodes x and y without 125 // considering direction. 126 func (g *DirectedMatrix) HasEdgeBetween(xid, yid int64) bool { 127 if !g.has(xid) { 128 return false 129 } 130 if !g.has(yid) { 131 return false 132 } 133 // xid and yid are not greater than maximum int by this point. 134 return xid != yid && (!isSame(g.mat.At(int(xid), int(yid)), g.absent) || !isSame(g.mat.At(int(yid), int(xid)), g.absent)) 135 } 136 137 // HasEdgeFromTo returns whether an edge exists in the graph from u to v. 138 func (g *DirectedMatrix) HasEdgeFromTo(uid, vid int64) bool { 139 if !g.has(uid) { 140 return false 141 } 142 if !g.has(vid) { 143 return false 144 } 145 // uid and vid are not greater than maximum int by this point. 146 return uid != vid && !isSame(g.mat.At(int(uid), int(vid)), g.absent) 147 } 148 149 // Matrix returns the mat.Matrix representation of the graph. The orientation 150 // of the matrix is such that the matrix entry at G_{ij} is the weight of the edge 151 // from node i to node j. 152 func (g *DirectedMatrix) Matrix() mat.Matrix { 153 // Prevent alteration of dimensions of the returned matrix. 154 m := *g.mat 155 return &m 156 } 157 158 // Node returns the node with the given ID if it exists in the graph, 159 // and nil otherwise. 160 func (g *DirectedMatrix) Node(id int64) graph.Node { 161 if !g.has(id) { 162 return nil 163 } 164 if g.nodes == nil { 165 return Node(id) 166 } 167 return g.nodes[id] 168 } 169 170 // Nodes returns all the nodes in the graph. 171 func (g *DirectedMatrix) Nodes() graph.Nodes { 172 if g.nodes != nil { 173 nodes := make([]graph.Node, len(g.nodes)) 174 copy(nodes, g.nodes) 175 return iterator.NewOrderedNodes(nodes) 176 } 177 r, _ := g.mat.Dims() 178 // Matrix graphs must have at least one node. 179 return iterator.NewImplicitNodes(0, r, newSimpleNode) 180 } 181 182 // RemoveEdge removes the edge with the given end point nodes from the graph, leaving the terminal 183 // nodes. If the edge does not exist it is a no-op. 184 func (g *DirectedMatrix) RemoveEdge(fid, tid int64) { 185 if !g.has(fid) { 186 return 187 } 188 if !g.has(tid) { 189 return 190 } 191 // fid and tid are not greater than maximum int by this point. 192 g.mat.Set(int(fid), int(tid), g.absent) 193 } 194 195 // SetEdge sets e, an edge from one node to another with unit weight. If the ends of the edge 196 // are not in g or the edge is a self loop, SetEdge panics. SetEdge will store the nodes of 197 // e in the graph if it was initialized with NewDirectedMatrixFrom. 198 func (g *DirectedMatrix) SetEdge(e graph.Edge) { 199 g.setWeightedEdge(e, 1) 200 } 201 202 // SetWeightedEdge sets e, an edge from one node to another. If the ends of the edge are not in g 203 // or the edge is a self loop, SetWeightedEdge panics. SetWeightedEdge will store the nodes of 204 // e in the graph if it was initialized with NewDirectedMatrixFrom. 205 func (g *DirectedMatrix) SetWeightedEdge(e graph.WeightedEdge) { 206 g.setWeightedEdge(e, e.Weight()) 207 } 208 209 func (g *DirectedMatrix) setWeightedEdge(e graph.Edge, weight float64) { 210 from := e.From() 211 fid := from.ID() 212 to := e.To() 213 tid := to.ID() 214 if fid == tid { 215 panic("simple: set illegal edge") 216 } 217 if int64(int(fid)) != fid { 218 panic("simple: unavailable from node ID for dense graph") 219 } 220 if int64(int(tid)) != tid { 221 panic("simple: unavailable to node ID for dense graph") 222 } 223 if g.nodes != nil { 224 g.nodes[fid] = from 225 g.nodes[tid] = to 226 } 227 // fid and tid are not greater than maximum int by this point. 228 g.mat.Set(int(fid), int(tid), weight) 229 } 230 231 // To returns all nodes in g that can reach directly to n. 232 func (g *DirectedMatrix) To(id int64) graph.Nodes { 233 if !g.has(id) { 234 return graph.Empty 235 } 236 var nodes []graph.Node 237 r, _ := g.mat.Dims() 238 for i := 0; i < r; i++ { 239 if int64(i) == id { 240 continue 241 } 242 // id is not greater than maximum int by this point. 243 if !isSame(g.mat.At(i, int(id)), g.absent) { 244 nodes = append(nodes, g.Node(int64(i))) 245 } 246 } 247 if len(nodes) == 0 { 248 return graph.Empty 249 } 250 return iterator.NewOrderedNodes(nodes) 251 } 252 253 // Weight returns the weight for the edge between x and y if Edge(x, y) returns a non-nil Edge. 254 // If x and y are the same node or there is no joining edge between the two nodes the weight 255 // value returned is either the graph's absent or self value. Weight returns true if an edge 256 // exists between x and y or if x and y have the same ID, false otherwise. 257 func (g *DirectedMatrix) Weight(xid, yid int64) (w float64, ok bool) { 258 if xid == yid { 259 return g.self, true 260 } 261 if g.HasEdgeFromTo(xid, yid) { 262 // xid and yid are not greater than maximum int by this point. 263 return g.mat.At(int(xid), int(yid)), true 264 } 265 return g.absent, false 266 } 267 268 // WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise. 269 // The node v must be directly reachable from u as defined by the From method. 270 func (g *DirectedMatrix) WeightedEdge(uid, vid int64) graph.WeightedEdge { 271 if g.HasEdgeFromTo(uid, vid) { 272 // xid and yid are not greater than maximum int by this point. 273 return WeightedEdge{F: g.Node(uid), T: g.Node(vid), W: g.mat.At(int(uid), int(vid))} 274 } 275 return nil 276 } 277 278 // WeightedEdges returns all the edges in the graph. 279 func (g *DirectedMatrix) WeightedEdges() graph.WeightedEdges { 280 var edges []graph.WeightedEdge 281 r, _ := g.mat.Dims() 282 for i := 0; i < r; i++ { 283 for j := 0; j < r; j++ { 284 if i == j { 285 continue 286 } 287 if w := g.mat.At(i, j); !isSame(w, g.absent) { 288 edges = append(edges, WeightedEdge{F: g.Node(int64(i)), T: g.Node(int64(j)), W: w}) 289 } 290 } 291 } 292 if len(edges) == 0 { 293 return graph.Empty 294 } 295 return iterator.NewOrderedWeightedEdges(edges) 296 } 297 298 func (g *DirectedMatrix) has(id int64) bool { 299 r, _ := g.mat.Dims() 300 return 0 <= id && id < int64(r) 301 }