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  }