github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/graph/encoding/digraph6/digraph6.go (about) 1 // Copyright ©2018 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 digraph6 implements graphs specified by digraph6 strings. 6 package digraph6 // import "github.com/jingcheng-WU/gonum/graph/encoding/digraph6" 7 8 import ( 9 "fmt" 10 "math/big" 11 "sort" 12 "strings" 13 14 "github.com/jingcheng-WU/gonum/graph" 15 "github.com/jingcheng-WU/gonum/graph/internal/ordered" 16 "github.com/jingcheng-WU/gonum/graph/iterator" 17 "github.com/jingcheng-WU/gonum/graph/simple" 18 ) 19 20 // Graph is a digraph6-represented directed graph. 21 // 22 // See https://users.cecs.anu.edu.au/~bdm/data/formats.txt for details. 23 // 24 // Note that the digraph6 format specifies that the first character of the graph 25 // string is a '&'. This character must be present for use in the digraph6 package. 26 // A Graph without this prefix is treated as the null graph. 27 type Graph string 28 29 var ( 30 d6 Graph 31 32 _ graph.Graph = d6 33 _ graph.Directed = d6 34 ) 35 36 // Encode returns a graph6 encoding of the topology of the given graph using a 37 // lexical ordering of the nodes by ID to map them to [0, n). 38 func Encode(g graph.Graph) Graph { 39 nodes := graph.NodesOf(g.Nodes()) 40 n := len(nodes) 41 sort.Sort(ordered.ByID(nodes)) 42 indexOf := make(map[int64]int, n) 43 for i, n := range nodes { 44 indexOf[n.ID()] = i 45 } 46 47 size := n * n 48 var b big.Int 49 for i, u := range nodes { 50 it := g.From(u.ID()) 51 for it.Next() { 52 vid := it.Node().ID() 53 j := indexOf[vid] 54 b.SetBit(&b, bitFor(int64(i), int64(j), int64(n)), 1) 55 } 56 } 57 58 var buf strings.Builder 59 buf.WriteByte('&') 60 // digraph6 specifies graphs of order up to 2^36-1 which 61 // overflows int on 32-bit architectures. We know that on 62 // those machines n will not be this large, since it came 63 // from a length, but explicitly convert to 64 bits to 64 // allow the package to build on those architectures. 65 switch n := int64(n); { 66 case n < 63: 67 buf.WriteByte(byte(n) + 63) 68 case n < 258048: 69 buf.Write([]byte{126, byte(n>>12) + 63, byte(n>>6) + 63, byte(n) + 63}) 70 case n < 68719476736: 71 buf.Write([]byte{126, 126, byte(n>>30) + 63, byte(n>>24) + 63, byte(n>>18) + 63, byte(n>>12) + 63, byte(n>>6) + 63, byte(n) + 63}) 72 default: 73 panic("digraph6: too large") 74 } 75 76 var c byte 77 for i := 0; i < size; i++ { 78 bit := i % 6 79 c |= byte(b.Bit(i)) << uint(5-bit) 80 if bit == 5 { 81 buf.WriteByte(c + 63) 82 c = 0 83 } 84 } 85 if size%6 != 0 { 86 buf.WriteByte(c + 63) 87 } 88 89 return Graph(buf.String()) 90 } 91 92 // IsValid returns whether the graph is a valid digraph6 encoding. An invalid Graph 93 // behaves as the null graph. 94 func IsValid(g Graph) bool { 95 n := int(numberOf(g)) 96 if n < 0 { 97 return false 98 } 99 size := (n*n + 5) / 6 // ceil(n^2 / 6) 100 g = g[1:] 101 switch { 102 case g[0] != 126: 103 return len(g[1:]) == size 104 case g[1] != 126: 105 return len(g[4:]) == size 106 default: 107 return len(g[8:]) == size 108 } 109 } 110 111 // Edge returns the edge from u to v, with IDs uid and vid, if such an edge 112 // exists and nil otherwise. The node v must be directly reachable from u as 113 // defined by the From method. 114 func (g Graph) Edge(uid, vid int64) graph.Edge { 115 if !IsValid(g) { 116 return nil 117 } 118 if !g.HasEdgeFromTo(uid, vid) { 119 return nil 120 } 121 return simple.Edge{F: simple.Node(uid), T: simple.Node(vid)} 122 } 123 124 // From returns all nodes that can be reached directly from the node with the 125 // given ID. 126 func (g Graph) From(id int64) graph.Nodes { 127 if !IsValid(g) { 128 return graph.Empty 129 } 130 if g.Node(id) == nil { 131 return nil 132 } 133 return &d6ForwardIterator{g: g, from: id, to: -1} 134 } 135 136 // HasEdgeBetween returns whether an edge exists between nodes with IDs xid 137 // and yid without considering direction. 138 func (g Graph) HasEdgeBetween(xid, yid int64) bool { 139 if !IsValid(g) { 140 return false 141 } 142 return g.HasEdgeFromTo(xid, yid) || g.HasEdgeFromTo(yid, xid) 143 } 144 145 // HasEdgeFromTo returns whether an edge exists in the graph from u to v with 146 // IDs uid and vid. 147 func (g Graph) HasEdgeFromTo(uid, vid int64) bool { 148 if !IsValid(g) { 149 return false 150 } 151 if uid == vid { 152 return false 153 } 154 n := numberOf(g) 155 if uid < 0 || n <= uid { 156 return false 157 } 158 if vid < 0 || n <= vid { 159 return false 160 } 161 return isSet(bitFor(uid, vid, n), g) 162 } 163 164 // Node returns the node with the given ID if it exists in the graph, and nil 165 // otherwise. 166 func (g Graph) Node(id int64) graph.Node { 167 if !IsValid(g) { 168 return nil 169 } 170 if id < 0 || numberOf(g) <= id { 171 return nil 172 } 173 return simple.Node(id) 174 } 175 176 // Nodes returns all the nodes in the graph. 177 func (g Graph) Nodes() graph.Nodes { 178 if !IsValid(g) { 179 return graph.Empty 180 } 181 return iterator.NewImplicitNodes(0, int(numberOf(g)), func(id int) graph.Node { return simple.Node(id) }) 182 } 183 184 // To returns all nodes that can reach directly to the node with the given ID. 185 func (g Graph) To(id int64) graph.Nodes { 186 if !IsValid(g) || g.Node(id) == nil { 187 return graph.Empty 188 } 189 return &d6ReverseIterator{g: g, from: -1, to: id} 190 } 191 192 // d6ForwardIterator is a graph.Nodes for digraph6 graph edges for forward hops. 193 type d6ForwardIterator struct { 194 g Graph 195 from int64 196 to int64 197 } 198 199 var _ graph.Nodes = (*d6ForwardIterator)(nil) 200 201 func (i *d6ForwardIterator) Next() bool { 202 n := numberOf(i.g) 203 for i.to < n-1 { 204 i.to++ 205 if i.to != i.from && isSet(bitFor(i.from, i.to, n), i.g) { 206 return true 207 } 208 } 209 return false 210 } 211 212 func (i *d6ForwardIterator) Len() int { 213 var cnt int 214 n := numberOf(i.g) 215 for to := i.to; to < n-1; { 216 to++ 217 if to != i.from && isSet(bitFor(i.from, to, n), i.g) { 218 cnt++ 219 } 220 } 221 return cnt 222 } 223 224 func (i *d6ForwardIterator) Reset() { i.to = -1 } 225 226 func (i *d6ForwardIterator) Node() graph.Node { return simple.Node(i.to) } 227 228 // d6ReverseIterator is a graph.Nodes for digraph6 graph edges for reverse hops. 229 type d6ReverseIterator struct { 230 g Graph 231 from int64 232 to int64 233 } 234 235 var _ graph.Nodes = (*d6ReverseIterator)(nil) 236 237 func (i *d6ReverseIterator) Next() bool { 238 n := numberOf(i.g) 239 for i.from < n-1 { 240 i.from++ 241 if i.to != i.from && isSet(bitFor(i.from, i.to, n), i.g) { 242 return true 243 } 244 } 245 return false 246 } 247 248 func (i *d6ReverseIterator) Len() int { 249 var cnt int 250 n := numberOf(i.g) 251 for from := i.from; from < n-1; { 252 from++ 253 if from != i.to && isSet(bitFor(from, i.to, n), i.g) { 254 cnt++ 255 } 256 } 257 return cnt 258 } 259 260 func (i *d6ReverseIterator) Reset() { i.from = -1 } 261 262 func (i *d6ReverseIterator) Node() graph.Node { return simple.Node(i.from) } 263 264 // numberOf returns the digraph6-encoded number corresponding to g. 265 func numberOf(g Graph) int64 { 266 if len(g) < 2 { 267 return -1 268 } 269 if g[0] != '&' { 270 return -1 271 } 272 g = g[1:] 273 if g[0] != 126 { 274 return int64(g[0] - 63) 275 } 276 if len(g) < 4 { 277 return -1 278 } 279 if g[1] != 126 { 280 return int64(g[1]-63)<<12 | int64(g[2]-63)<<6 | int64(g[3]-63) 281 } 282 if len(g) < 8 { 283 return -1 284 } 285 return int64(g[2]-63)<<30 | int64(g[3]-63)<<24 | int64(g[4]-63)<<18 | int64(g[5]-63)<<12 | int64(g[6]-63)<<6 | int64(g[7]-63) 286 } 287 288 // bitFor returns the index into the digraph6 adjacency matrix for uid->vid in a graph 289 // order n. 290 func bitFor(uid, vid, n int64) int { 291 return int(uid*n + vid) 292 } 293 294 // isSet returns whether the given bit of the adjacency matrix is set. 295 func isSet(bit int, g Graph) bool { 296 g = g[1:] 297 switch { 298 case g[0] != 126: 299 g = g[1:] 300 case g[1] != 126: 301 g = g[4:] 302 default: 303 g = g[8:] 304 } 305 if bit/6 >= len(g) { 306 panic("digraph6: index out of range") 307 } 308 return (g[bit/6]-63)&(1<<uint(5-bit%6)) != 0 309 } 310 311 func (g Graph) GoString() string { 312 if !IsValid(g) { 313 return "" 314 } 315 bin, m6 := binary(g) 316 format := fmt.Sprintf("%%d:%%0%db", m6) 317 return fmt.Sprintf(format, numberOf(g), bin) 318 } 319 320 func binary(g Graph) (b *big.Int, l int) { 321 n := int(numberOf(g)) 322 g = g[1:] 323 switch { 324 case g[0] != 126: 325 g = g[1:] 326 case g[1] != 126: 327 g = g[4:] 328 default: 329 g = g[8:] 330 } 331 b = &big.Int{} 332 var c big.Int 333 for i := range g { 334 c.SetUint64(uint64(g[len(g)-i-1] - 63)) 335 c.Lsh(&c, uint(6*i)) 336 b.Or(b, &c) 337 } 338 339 // Truncate to only the relevant parts of the bit vector. 340 b.Rsh(b, uint(len(g)*6-(n*n))) 341 342 return b, n * n 343 }