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