github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/graph/encoding/graph6/graph6.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 graph6 implements graphs specified by graph6 strings. 6 package graph6 // import "github.com/jingcheng-WU/gonum/graph/encoding/graph6" 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 graph6-represented undirected graph. 21 // 22 // See https://users.cecs.anu.edu.au/~bdm/data/formats.txt for details 23 // and https://hog.grinvin.org/ for a source of interesting graphs in graph6 24 // format. 25 type Graph string 26 27 var ( 28 g6 Graph 29 30 _ graph.Graph = g6 31 _ graph.Undirected = g6 32 ) 33 34 // Encode returns a graph6 encoding of the topology of the given graph using a 35 // lexical ordering of the nodes by ID to map them to [0, n). 36 func Encode(g graph.Graph) Graph { 37 nodes := graph.NodesOf(g.Nodes()) 38 n := len(nodes) 39 sort.Sort(ordered.ByID(nodes)) 40 indexOf := make(map[int64]int, n) 41 for i, n := range nodes { 42 indexOf[n.ID()] = i 43 } 44 45 size := (n*n - n) / 2 46 var b big.Int 47 for i, u := range nodes { 48 uid := u.ID() 49 it := g.From(uid) 50 for it.Next() { 51 vid := it.Node().ID() 52 if vid < uid { 53 continue 54 } 55 j := indexOf[vid] 56 b.SetBit(&b, bitFor(int64(i), int64(j)), 1) 57 } 58 } 59 60 var buf strings.Builder 61 // graph6 specifies graphs of order up to 2^36-1 which 62 // overflows int on 32-bit architectures. We know that on 63 // those machines n will not be this large, since it came 64 // from a length, but explicitly convert to 64 bits to 65 // allow the package to build on those architectures. 66 switch n := int64(n); { 67 case n < 63: 68 buf.WriteByte(byte(n) + 63) 69 case n < 258048: 70 buf.Write([]byte{126, byte(n>>12) + 63, byte(n>>6) + 63, byte(n) + 63}) 71 case n < 68719476736: 72 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}) 73 default: 74 panic("graph6: too large") 75 } 76 77 var c byte 78 for i := 0; i < size; i++ { 79 bit := i % 6 80 c |= byte(b.Bit(i)) << uint(5-bit) 81 if bit == 5 { 82 buf.WriteByte(c + 63) 83 c = 0 84 } 85 } 86 if size%6 != 0 { 87 buf.WriteByte(c + 63) 88 } 89 90 return Graph(buf.String()) 91 } 92 93 // IsValid returns whether the graph is a valid graph6 encoding. An invalid Graph 94 // behaves as the null graph. 95 func IsValid(g Graph) bool { 96 n := int(numberOf(g)) 97 if n < 0 { 98 return false 99 } 100 size := ((n*n-n)/2 + 5) / 6 // ceil(((n*n-n)/2) / 6) 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.HasEdgeBetween(uid, vid) { 119 return nil 120 } 121 return simple.Edge{F: simple.Node(uid), T: simple.Node(vid)} 122 } 123 124 // EdgeBetween returns the edge between nodes x and y with IDs xid and yid. 125 func (g Graph) EdgeBetween(xid, yid int64) graph.Edge { 126 return g.Edge(xid, yid) 127 } 128 129 // From returns all nodes that can be reached directly from the node with the 130 // given ID. 131 func (g Graph) From(id int64) graph.Nodes { 132 if !IsValid(g) { 133 return graph.Empty 134 } 135 if g.Node(id) == nil { 136 return nil 137 } 138 return &g6Iterator{g: g, from: id, to: -1} 139 } 140 141 // HasEdgeBetween returns whether an edge exists between nodes with IDs xid 142 // and yid without considering direction. 143 func (g Graph) HasEdgeBetween(xid, yid int64) bool { 144 if !IsValid(g) { 145 return false 146 } 147 if xid == yid { 148 return false 149 } 150 if xid < 0 || numberOf(g) <= xid { 151 return false 152 } 153 if yid < 0 || numberOf(g) <= yid { 154 return false 155 } 156 return isSet(bitFor(xid, yid), g) 157 } 158 159 // Node returns the node with the given ID if it exists in the graph, and nil 160 // otherwise. 161 func (g Graph) Node(id int64) graph.Node { 162 if !IsValid(g) { 163 return nil 164 } 165 if id < 0 || numberOf(g) <= id { 166 return nil 167 } 168 return simple.Node(id) 169 } 170 171 // Nodes returns all the nodes in the graph. 172 func (g Graph) Nodes() graph.Nodes { 173 if !IsValid(g) { 174 return graph.Empty 175 } 176 return iterator.NewImplicitNodes(0, int(numberOf(g)), func(id int) graph.Node { return simple.Node(id) }) 177 } 178 179 // g6Iterator is a graph.Nodes for graph6 graph edges. 180 type g6Iterator struct { 181 g Graph 182 from int64 183 to int64 184 } 185 186 var _ graph.Nodes = (*g6Iterator)(nil) 187 188 func (i *g6Iterator) Next() bool { 189 n := numberOf(i.g) 190 for i.to < n-1 { 191 i.to++ 192 if i.to != i.from && isSet(bitFor(i.from, i.to), i.g) { 193 return true 194 } 195 } 196 return false 197 } 198 199 func (i *g6Iterator) Len() int { 200 var cnt int 201 n := numberOf(i.g) 202 for to := i.to; to < n-1; { 203 to++ 204 if to != i.from && isSet(bitFor(i.from, to), i.g) { 205 cnt++ 206 } 207 } 208 return cnt 209 } 210 211 func (i *g6Iterator) Reset() { i.to = -1 } 212 213 func (i *g6Iterator) Node() graph.Node { return simple.Node(i.to) } 214 215 // numberOf returns the graph6-encoded number corresponding to g. 216 func numberOf(g Graph) int64 { 217 if len(g) < 1 { 218 return -1 219 } 220 if g[0] != 126 { 221 return int64(g[0] - 63) 222 } 223 if len(g) < 4 { 224 return -1 225 } 226 if g[1] != 126 { 227 return int64(g[1]-63)<<12 | int64(g[2]-63)<<6 | int64(g[3]-63) 228 } 229 if len(g) < 8 { 230 return -1 231 } 232 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) 233 } 234 235 // bitFor returns the index into the graph6 adjacency matrix for xid--yid. 236 func bitFor(xid, yid int64) int { 237 if xid < yid { 238 xid, yid = yid, xid 239 } 240 return int((xid*xid-xid)/2 + yid) 241 } 242 243 // isSet returns whether the given bit of the adjacency matrix is set. 244 func isSet(bit int, g Graph) bool { 245 switch { 246 case g[0] != 126: 247 g = g[1:] 248 case g[1] != 126: 249 g = g[4:] 250 default: 251 g = g[8:] 252 } 253 if bit/6 >= len(g) { 254 panic("g6: index out of range") 255 } 256 return (g[bit/6]-63)&(1<<uint(5-bit%6)) != 0 257 } 258 259 func (g Graph) GoString() string { 260 bin, m6 := binary(g) 261 format := fmt.Sprintf("%%d:%%0%db", m6) 262 return fmt.Sprintf(format, numberOf(g), bin) 263 } 264 265 func binary(g Graph) (b *big.Int, l int) { 266 n := int(numberOf(g)) 267 268 switch { 269 case g[0] != 126: 270 g = g[1:] 271 case g[1] != 126: 272 g = g[4:] 273 default: 274 g = g[8:] 275 } 276 b = &big.Int{} 277 var c big.Int 278 for i := range g { 279 c.SetUint64(uint64(g[len(g)-i-1] - 63)) 280 c.Lsh(&c, uint(6*i)) 281 b.Or(b, &c) 282 } 283 284 // Truncate to only the relevant parts of the bit vector. 285 b.Rsh(b, uint(len(g)*6-(n*n-n)/2)) 286 287 return b, (n*n - n) / 2 288 }