<tb@panthema.net>
<http://www.gnu.org/licenses/>
#ifndef BISPANNING_GRAPH6_HEADER
#define BISPANNING_GRAPH6_HEADER
#include <cstdio>
#include <cstring>
#include <sstream>
#include <stdexcept>
#include "debug.h"
#include "graph.h"
class Graph6Reader
{
protected:
const std::string& s;
size_t m_pos, m_bit;
public:
explicit Graph6Reader(const std::string& _s)
: s(_s), m_pos(0), m_bit(0)
{ }
bool have_bits(unsigned int k)
{
return (m_pos + (m_bit + k - 1) / 6) < s.size();
}
unsigned int get_number()
{
assert(m_pos < s.size());
unsigned char c = s[m_pos];
assert(c >= 63);
c -= 63;
++m_pos;
if (c < 126) return c;
assert(!"TODO");
abort();
}
unsigned int get_bit()
{
assert(m_pos < s.size());
unsigned char c = s[m_pos];
assert(c >= 63);
c -= 63;
c >>= (5 - m_bit);
m_bit++;
if (m_bit == 6) { m_pos++; m_bit = 0; }
return (c & 0x01);
}
unsigned int get_bits(unsigned int k)
{
unsigned int v = 0;
for (unsigned int i = 0; i < k; ++i)
{
v *= 2;
v += get_bit();
}
return v;
}
};
class Graph6Writer : public std::string
{
protected:
unsigned int j;
public:
Graph6Writer()
: j(0)
{ }
void put_number(unsigned int i)
{
if (i < 63) {
append(1, (unsigned char)(i + 63));
j = 6;
}
else if (i < 258048) {
unsigned char b2 = (i >> (2 * 6)) & 0x3F;
unsigned char b1 = (i >> (1 * 6)) & 0x3F;
unsigned char b0 = (i >> (0 * 6)) & 0x3F;
append(1, 126);
append(1, (unsigned char)(b2 + 63));
append(1, (unsigned char)(b1 + 63));
append(1, (unsigned char)(b0 + 63));
j = 6;
}
else {
assert(!"TODO");
}
}
void put_bit(bool b)
{
if (j == 6)
{
append(1, 63);
j = 0;
}
if (b)
{
unsigned char c = operator [] (size() - 1);
c -= 63;
c |= 1 << (5 - j);
c += 63;
operator [] (size() - 1) = c;
}
j++;
}
void put_bits(unsigned int v, unsigned int k)
{
for (unsigned int i = k; i > 0; --i)
{
put_bit((v >> (i - 1)) & 1);
}
}
void fill_ones()
{
while (j != 6) put_bit(1);
}
};
template <typename GraphType>
GraphType read_sparse6(const std::string& graph_string)
{
static const bool debug = false;
Graph6Reader gr(graph_string);
size_t n = gr.get_number();
size_t k = ceil(log(n) / log(2));
DBG("|V| = " << n << " - k = " << k);
GraphType g(n);
unsigned int v = 0;
while (gr.have_bits(1 + k))
{
unsigned int b = gr.get_bit();
unsigned int x = gr.get_bits(k);
if (x >= n) break;
DBG("b=" << b << " - x=" << x);
if (b) v = v + 1;
if (v >= n) break;
if (x > v)
v = x;
else {
DBG("edge " << x << " - " << v);
g.add_edge(x, v);
}
}
return g;
}
template <typename GraphType>
GraphType read_graph6(const std::string& graph_string)
{
if (graph_string[0] == ':')
return read_sparse6<GraphType>(graph_string.substr(1));
Graph6Reader gr(graph_string);
size_t n = gr.get_number();
GraphType g(n);
for (unsigned int j = 1; j < n; ++j)
{
for (unsigned int i = 0; i < j; ++i)
{
bool e = gr.get_bit();
if (e) {
g.add_edge(i, j);
}
}
}
return g;
}
template <typename GraphType>
std::string write_sparse6(const GraphType& g)
{
static const bool debug = false;
Graph6Writer go;
size_t n = g.total_vertex();
size_t k = ceil(log(n) / log(2));
DBG("|V| = " << n << " - k = " << k);
go.put_number(n);
unsigned int v = 0;
for (unsigned int j = 0; j < n; ++j)
{
if (g.vertex_deleted(j)) continue;
for (unsigned int i = 0; i < j; ++i)
{
if (g.vertex_deleted(i)) continue;
unsigned int ec = g.count_edges(i, j);
DBG("(" << i << "," << j << ") = " << ec);
for (unsigned int c = 0; c < ec; ++c)
{
if (j == v) {
go.put_bit(0);
}
else if (j == v + 1) {
go.put_bit(1);
v = j;
}
else {
go.put_bit(1);
go.put_bits(j, k);
assert(j > v);
v = j;
go.put_bit(0);
}
go.put_bits(i, k);
}
}
}
go.fill_ones();
return ":" + go;
}
template <typename GraphType>
std::string write_graph6(const GraphType& g)
{
Graph6Writer go;
size_t n = g.total_vertex();
go.put_number(n);
for (unsigned int j = 1; j < n; ++j)
{
for (unsigned int i = 0; i < j; ++i)
{
typename GraphType::id_type count =
g.vertex_deleted(i) || g.vertex_deleted(j) ? 0 :
g.count_edges(i, j);
if (count > 1) return write_sparse6(g);
go.put_bit(count == 1);
}
}
return go;
}
class GengEnumerate
{
protected:
FILE* stream;
public:
GengEnumerate(unsigned int num_vertex, unsigned int num_edge,
const std::string& options = "")
{
std::ostringstream os;
os << "geng -c " << options << " " << num_vertex << " " << num_edge;
stream = popen(os.str().c_str(), "r");
if (!stream) {
perror("Could not run geng.");
abort();
}
}
template <typename GraphType>
bool operator () (GraphType& g)
{
const int MAX_BUFFER = 2048;
char buffer[MAX_BUFFER];
if (feof(stream)) return false;
if (fgets(buffer, MAX_BUFFER - 1, stream) == nullptr)
return false;
size_t blen = strlen(buffer);
if (buffer[blen - 1] == '\n') {
buffer[blen - 1] = 0;
--blen;
}
if (buffer[0] == '>') return operator () (g);
g = read_graph6<GraphType>(buffer);
if (1)
{
std::string s6 = write_graph6(g);
GraphType h = read_graph6<GraphType>(s6);
assert(buffer == s6);
}
return true;
}
~GengEnumerate()
{
pclose(stream);
}
};
class GenbgEnumerate
{
protected:
FILE* stream;
public:
GenbgEnumerate(unsigned int num_vertex, unsigned int num_edge,
const std::string& options = "")
{
std::ostringstream os;
os << "genbg -d2 -D2:" << num_edge << " -Z2 " << options << " "
<< num_edge << " " << num_vertex << " " << 2 * num_edge;
stream = popen(os.str().c_str(), "r");
if (!stream) {
perror("Could not run genbg.");
abort();
}
}
template <typename GraphType>
bool operator () (GraphType& g)
{
const int MAX_BUFFER = 2048;
char buffer[MAX_BUFFER];
if (feof(stream)) return false;
if (fgets(buffer, MAX_BUFFER - 1, stream) == nullptr)
return false;
size_t blen = strlen(buffer);
if (buffer[blen - 1] == '\n') {
buffer[blen - 1] = 0;
--blen;
}
if (buffer[0] == '>') return operator () (g);
g = read_graph6<GraphType>(buffer);
if (1)
{
std::string s6 = write_graph6(g);
GraphType h = read_graph6<GraphType>(s6);
assert(buffer == s6);
}
return true;
}
~GenbgEnumerate()
{
pclose(stream);
}
};
#endif