2
0
mirror of https://github.com/boostorg/graph.git synced 2026-01-30 07:52:10 +00:00

new files, under construction

[SVN r9534]
This commit is contained in:
Jeremy Siek
2001-03-10 02:49:09 +00:00
parent 613594cc4b
commit 019e7d59a4
2 changed files with 1404 additions and 0 deletions

View File

@@ -0,0 +1,704 @@
// (C) Copyright Jeremy Siek 2001. Permission to copy, use, modify,
// sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided
// "as is" without express or implied warranty, and with no claim as
// to its suitability for any purpose.
/*
* Copyright (c) 1998
* Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Silicon Graphics makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*/
#include <boost/config.hpp>
#include <memory>
#include <algorithm>
#include <boost/pending/ct_if.hpp>
// This provides versions of std::bitset with both static and dynamic size.
// UNDER CONSTRUCTION
// replace this later
#include <cassert>
#define BOOST_ASSERT_THROW(expr, except) assert(expr)
namespace boost {
namespace detail {
// structure to aid in counting bits
template<bool dummy = true>
struct bit_count {
static unsigned char value[256];
};
// Mapping from 8 bit unsigned integers to the index of the first bit
template<bool dummy = true>
struct first_bit_location {
static unsigned char value[256];
};
template <typename WordType> // this size is in bits
struct word_traits {
typedef WordType word_type;
static const std::size_t word_size = CHAR_BIT * sizeof(word_type);
};
// ------------------------------------------------------------
// Helper class to zero out the unused high-order bits in the highest word.
template <size_type ExtraBits> struct sanitize_high {
template <typename WordType>
static void apply(WordType& val)
};
template <> struct sanitize_high<0> {
template <typename WordType>
static void apply(WordType) {}
};
//=========================================================================
template <class WordTraits, class SizeType, class Derived>
class bitset_base
{
private:
typedef SizeType size_type;
typedef typename WordTraits::word_type word_type;
static size_type s_which_word(size_type pos) {
return pos / WordTraits::word_size;
}
static size_type s_which_byte(size_type pos) {
return (__pos % WordTraits::word_size) / CHAR_BIT;
}
static size_type s_which_bit(size_type pos) {
return pos % WordTraits::word_size;
}
static word_type s_mask_bit(size_type pos) {
return (static_cast<word_type>(1)) << s_which_bit(pos);
}
word_type& m_get_word(size_type pos) {
return data()[s_which_word(pos)];
}
word_type m_get_word(size_type pos) const {
return data()[s_which_word(pos)];
}
word_type& m_hi_word() { return data()[num_words() - 1]; }
word_type m_hi_word() const { return data()[num_words() - 1]; }
void sanitize_highest() {
size_type extra_bits = num_words() % WordTraits::word_size;
if (extra_bits)
m_hi_word() &= ~((~static_cast<WordType>(0)) << extra_bits);
}
public:
class reference {
friend class bitset_base;
word_type *m_word_ptr;
size_type m_bit_pos;
// left undefined
reference();
reference(bitset_base& b, size_type pos ) {
m_word_ptr = &b._M_getword(pos);
m_bit_pos = _S_whichbit(pos);
}
public:
~reference() {}
// for b[i] = x;
reference& operator=(bool x) {
if ( x )
*m_word_ptr |= _S_maskbit(m_bit_pos);
else
*m_word_ptr &= ~_S_maskbit(m_bit_pos);
return *this;
}
// for b[i] = b[j];
reference& operator=(const reference& j) {
if ( (*(j.m_word_ptr) & s_mask_bit(j.m_bit_pos)) )
*m_word_ptr |= s_mask_bit(m_bit_pos);
else
*m_word_ptr &= ~s_mask_bit(m_bit_pos);
return *this;
}
// flips the bit
bool operator~() const {
return (*(m_word_ptr) & s_mask_bit(m_bit_pos)) == 0;
}
// for x = b[i];
operator bool() const {
return (*(m_word_ptr) & s_mask_bit(m_bit_pos)) != 0;
}
// for b[i].flip();
reference& flip() {
*m_word_ptr ^= s_mask_bit(m_bit_pos);
return *this;
}
};
// intersection: this = this & x
Derived& operator&=(const Derived& x) {
for (size_type i = 0; i < num_words(); ++i)
data()[i] &= x.data()[i];
return static_cast<Derived&>(*this);
}
// union: this = this | x
Derived& operator|=(const Derived& x) {
for (size_type i = 0; i < num_words(); ++i)
data()[i] |= x.data()[i];
return static_cast<Derived&>(*this);
}
// exclusive or: this = this ^ x
Derived& operator^=(const Derived& x) {
for (size_type i = 0; i < num_words(); ++i)
data()[i] ^= x.data()[i];
return static_cast<Derived&>(*this);
}
// left shift
Derived& operator<<=(size_type pos);
// right shift
Derived& operator>>=(size_type pos);
Derived& set() {
for (size_type i = 0; i < num_words(); ++i)
data()[i] = ~static_cast<word_type>(0);
return static_cast<Derived&>(*this);
}
Derived& set(size_type pos, int val = true)
{
BOOST_ASSERT_THROW(pos < size(),
out_of_range("boost::bit_set::set(pos,value)"));
if (val)
m_get_word(pos) |= s_mask_bit(pos);
else
m_get_word(pos) &= ~s_mask_bit(pos);
return static_cast<Derived&>(*this);
}
Derived& reset() {
for (size_type i = 0; i < num_words(); ++i)
data()[i] = 0;
return static_cast<Derived&>(*this);
}
Derived& reset(size_type pos) {
BOOST_ASSERT_THROW(pos < size(),
out_of_range("boost::bit_set::reset(pos)"));
m_get_word(pos) &= ~s_mask_bit(pos);
return static_cast<Derived&>(*this);
}
// compliment
Derived operator~() const {
return Derived(*this).flip();
}
Derived& flip() {
for (size_type i = 0; i < num_words(); ++i)
data()[i] = ~data()[i];
return static_cast<Derived&>(*this);
}
Derived& flip(size_type pos) {
BOOST_ASSERT_THROW(pos < size(),
out_of_range("boost::bit_set::flip(pos)"));
m_get_word(pos) ^= s_mask_bit(pos);
return static_cast<Derived&>(*this);
}
// element access
reference operator[](size_type pos) { return reference(*this, pos); }
bool operator[](size_type pos) const { return test(pos); }
unsigned long to_ulong() const;
// to_string
size_type count() const {
size_type result = 0;
const unsigned char* byte_ptr = (const unsigned char*)data();
const unsigned char* end_ptr =
(const unsigned char*)(data() + num_words());
while ( byte_ptr < end_ptr ) {
result += bit_count<>::value[*byte_ptr];
byte_ptr++;
}
return result;
}
// size() must be provided by Derived class
bool operator==(const Derived& x) const {
return std::equal(data(), data() + num_words(), x.data());
}
bool operator!=(const Derived& x) const {
return !std::equal(data(), data() + num_words(), x.data());
}
bool any() const {
for (size_type i = 0; i < num_words(); ++i) {
if ( data()[i] != static_cast<word_type>(0) )
return true;
}
return false;
}
bool none() const {
return !any();
}
Derived operator<<(size_type pos) const
{ return Derived(*this) <<= pos; }
Derived operator>>(size_type pos) const
{ return Derived(*this) >>= pos; }
//-----------------------------------------------------------------------
// Stuff not in std::bitset
// difference: this = this - x
Derived& operator-=(const Derived& x) {
for (size_type i = 0; i < num_words(); ++i)
data()[i] &= ~x.data()[i];
return static_cast<Derived&>(*this);
}
// less-than compare
bool operator<(const Derived& x) const {
return std::lexicographical_compare
(data(), data() + num_words(), x.data(), x.data() + x.num_words());
}
// find the index of the first "on" bit
size_type find_first() const;
// find the index of the next "on" bit after prev
size_type find_next(size_type prev) const;
private:
word_type* data()
{ return static_cast<Derived>(this)->data(); }
const word_type* data() const
{ return static_cast<Derived>(this)->data(); }
size_type num_words() const
{ return static_cast<Derived>(this)->num_words(); }
};
//=========================================================================
template <typename WordType = unsigned long,
typename SizeType = std::size_t,
typename Allocator = std::allocator<
typename word_traits<WordSize>::word_type>
>
class dynamic_bitset
: public bitset_base<word_traits<WordType>, SizeType,
dynamic_bitset<WordType,SizeType,Allocator> >
{
typedef bit_set self;
public:
typedef SizeType size_type;
private:
typedef word_traits<word_size> WordTraits;
static const size_type word_size = WordTraits::word_size;
public:
bit_set(size_type N, const Allocator& alloc = Allocator())
: m_data(alloc.allocate((N + word_size - 1) / word_size)),
m_size(N), m_num_words((N + word_size - 1) / word_size)
{ }
~bit_set() {
alloc.deallocate(m_data, m_num_words);
}
size_type size() const { return m_size; }
// protected:
size_type num_words() const { return m_num_words; }
word_type* data() { return m_data; }
const word_type* data() const { return m_data; }
protected:
word_type* m_data;
SizeType m_size;
SizeType m_num_words;
};
//=========================================================================
template <std::size_t N, typename WordType = unsigned long,
typename SizeType = std::size_t>
class bitset
: public bitset_base<word_traits<WordType>, SizeType,
static_bitset<N, WordType, SizeType> >
{
typedef bitset self;
static const std::size_t word_size = word_traits<WordType>::word_size;
public:
// 23.3.5.1 constructors:
bitset() {}
bitset(unsigned long val) {
init_from_ulong(val);
}
template<class CharT, class Traits, class Alloc>
explicit bitset
(const basic_string<CharT,Traits,Alloc>& s,
std::size_t pos = 0,
std::size_t n = size_t(basic_string<CharT,Traits,Alloc>::npos))
{
BOOST_ASSERT_THROW(pos < s.size(), out_of_range("bitset"));
m_copy_from_string(s, pos, n);
}
protected:
word_type m_data[(N + word_size - 1) / word_size];
};
//=========================================================================
struct select_static_bitset {
template <std::size_t N, typename WordT, typename SizeT, typename Alloc>
struct bind {
typedef bitset<N, WordT, SizeT> type;
};
};
struct select_dynamic_bitset {
template <std::size_t N, typename WordT, typename SizeT, typename Alloc>
struct bind {
typedef dynamic_bitset<WordT, SizeT, Alloc> type;
};
};
template <std::size_t N = 0, // 0 means use dynamic
typename WordType = unsigned long,
typename Size_type = std::size_t,
typename Allocator = std::allocator<
typename word_traits<WordSize>::word_type>
class bitset_generator {
typedef typename ct_if<N, select_dynamic_bitset,
select_static_bitset>::type selector;
public:
typedef typename selector
::template bind<N, WordType, SizeType, Allocator>::type type;
};
//=========================================================================
// bitset_base non-inline member function implementations
template <class WordTraits, class SizeType, class Derived>
bitset_base<WordTraits, SizeType, Derived>::
operator<<=(size_type shift)
{
typedef typename WordTraits::word_type word_type;
typedef typename WordTraits::size_type size_type;
if (shift != 0) {
const size_type wshift = shift / WordTraits::word_size;
const size_type offset = shift % WordTraits::word_size;
const size_type sub_offset = WordTraits::word_size - offset;
size_type n = num_words() - 1;
for ( ; n > wshift; --n)
data()[n] = (data()[n - wshift] << offset) |
(data()[n - wshift - 1] >> sub_offset);
if (n == wshift)
data()[n] = data()[0] << offset;
for (size_type n1 = 0; n1 < n; ++n1)
data()[n1] = static_cast<word_type>(0);
}
} // end operator<<=
template <class WordTraits, class SizeType, class Derived>
bitset_base<WordTraits, SizeType, Derived>::
operator>>=(size_type shift)
{
typedef typename WordTraits::word_type word_type;
typedef typename WordTraits::size_type size_type;
if (shift != 0) {
const size_type wshift = shift / WordTraits::word_size;
const size_type offset = shift % WordTraits::word_size;
const size_type sub_offset = WordTraits::word_size - offset;
const size_type limit = num_words() - wshift - 1;
size_type n = 0;
for ( ; n < limit; ++n)
data()[n] = (data()[n + wshift] >> offset) |
(data()[n + wshift + 1] << sub_offset);
data()[limit] = data()[num_words()-1] >> offset;
for (size_type n1 = limit + 1; n1 < num_words(); ++n1)
data()[n1] = static_cast<word_type>(0);
}
} // end operator>>=
template <class WordTraits, class SizeType, class Derived>
unsigned long bitset_base<WordTraits, SizeType, Derived>::
to_ulong() const
{
typedef typename WordTraits::word_type word_type;
typedef typename WordTraits::size_type size_type;
const overflow_error
overflow("boost::bit_set::operator unsigned long()");
if (sizeof(word_type) >= sizeof(unsigned long)) {
for (size_type i = 1; i < num_words(); ++i)
BOOST_ASSERT_THROW(! data()[i], overflow);
const word_type mask
= static_cast<word_type>(static_cast<unsigned long>(-1));
BOOST_ASSERT_THROW(! (data()[0] & ~mask), overflow);
return static_cast<unsigned long>(data()[0] & mask);
}
else { // sizeof(word_type) < sizeof(unsigned long).
const size_type nwords =
(sizeof(unsigned long) + sizeof(word_type) - 1) / sizeof(word_type);
size_type min_nwords = nwords;
if (num_words() > nwords) {
for (size_type i = nwords; i < num_words(); ++i)
BOOST_ASSERT_THROW(!data()[i], overflow);
}
else
min_nwords = num_words();
// If unsigned long is 8 bytes and word_type is 6 bytes, then
// an unsigned long consists of all of one word plus 2 bytes
// from another word.
const size_type part = sizeof(unsigned long) % sizeof(word_type);
BOOST_ASSERT_THROW((part != 0
&& nwords <= num_words()
&& (data()[min_nwords - 1] >>
((sizeof(word_type) - part) * CHAR_BIT)) != 0),
overflow);
unsigned long result = 0;
for (size_type i = 0; i < min_nwords; ++i) {
result |= static_cast<unsigned long>(
data()[i]) << (i * sizeof(word_type) * CHAR_BIT);
}
return result;
}
}// end operator unsigned long()
template <class WordTraits, class SizeType, class Derived>
SizeType bitset_base<WordTraits,SizeType,Derived>::
find_first(size_type not_found) const
{
for (size_type i = 0; i < _Nw; i++ ) {
word_type thisword = _M_w[i];
if ( thisword != static_cast<word_type>(0) ) {
// find byte within word
for ( size_t j = 0; j < sizeof(word_type); j++ ) {
unsigned char this_byte
= static_cast<unsigned char>(thisword & (~(unsigned char)0));
if ( this_byte )
return i*BITS_PER_WORDT(word_type) + j*CHAR_BIT +
_First_one<true>::_S_first_one[this_byte];
thisword >>= CHAR_BIT;
}
}
}
// not found, so return an indication of failure.
return not_found;
}
template <class WordTraits, class SizeType, class Derived>
SizeType bitset_base<WordTraits, SizeType, Derived>::
bitset_base<WordTraits,SizeType,Derived>::
find_next(size_type prev,
size_type not_found) const
{
// make bound inclusive
++prev;
// check out of bounds
if ( prev >= num_words() * WordTraits::word_size )
return not_found;
// search first word
size_type i = _S_whichword(prev);
word_type thisword = data()[i];
// mask off bits below bound
thisword &= (~static_cast<word_type>(0)) << _S_whichbit(prev);
if ( thisword != static_cast<word_type>(0) ) {
// find byte within word
// get first byte into place
thisword >>= _S_whichbyte(prev) * CHAR_BIT;
for ( size_type j = _S_whichbyte(prev); j < sizeof(word_type); j++ ) {
unsigned char this_byte
= static_cast<unsigned char>(thisword & (~(unsigned char)0));
if ( this_byte )
return i * WordTraits::word_size + j*CHAR_BIT +
first_bit_location<>::value[this_byte];
thisword >>= CHAR_BIT;
}
}
// check subsequent words
i++;
for ( ; i < num_words(); i++ ) {
word_type thisword = data()[i];
if ( thisword != static_cast<word_type>(0) ) {
// find byte within word
for ( size_type j = 0; j < sizeof(word_type); j++ ) {
unsigned char this_byte
= static_cast<unsigned char>(thisword & (~(unsigned char)0));
if ( this_byte )
return i * WordTraits::word_size + j * CHAR_BIT +
first_bit_location<>::value[this_byte];
thisword >>= CHAR_BIT;
}
}
}
// not found, so return an indication of failure.
return not_found;
} // end find_next
template <bool dummy>
unsigned char bit_count<dummy>::value[] = {
0, /* 0 */ 1, /* 1 */ 1, /* 2 */ 2, /* 3 */ 1, /* 4 */
2, /* 5 */ 2, /* 6 */ 3, /* 7 */ 1, /* 8 */ 2, /* 9 */
2, /* 10 */ 3, /* 11 */ 2, /* 12 */ 3, /* 13 */ 3, /* 14 */
4, /* 15 */ 1, /* 16 */ 2, /* 17 */ 2, /* 18 */ 3, /* 19 */
2, /* 20 */ 3, /* 21 */ 3, /* 22 */ 4, /* 23 */ 2, /* 24 */
3, /* 25 */ 3, /* 26 */ 4, /* 27 */ 3, /* 28 */ 4, /* 29 */
4, /* 30 */ 5, /* 31 */ 1, /* 32 */ 2, /* 33 */ 2, /* 34 */
3, /* 35 */ 2, /* 36 */ 3, /* 37 */ 3, /* 38 */ 4, /* 39 */
2, /* 40 */ 3, /* 41 */ 3, /* 42 */ 4, /* 43 */ 3, /* 44 */
4, /* 45 */ 4, /* 46 */ 5, /* 47 */ 2, /* 48 */ 3, /* 49 */
3, /* 50 */ 4, /* 51 */ 3, /* 52 */ 4, /* 53 */ 4, /* 54 */
5, /* 55 */ 3, /* 56 */ 4, /* 57 */ 4, /* 58 */ 5, /* 59 */
4, /* 60 */ 5, /* 61 */ 5, /* 62 */ 6, /* 63 */ 1, /* 64 */
2, /* 65 */ 2, /* 66 */ 3, /* 67 */ 2, /* 68 */ 3, /* 69 */
3, /* 70 */ 4, /* 71 */ 2, /* 72 */ 3, /* 73 */ 3, /* 74 */
4, /* 75 */ 3, /* 76 */ 4, /* 77 */ 4, /* 78 */ 5, /* 79 */
2, /* 80 */ 3, /* 81 */ 3, /* 82 */ 4, /* 83 */ 3, /* 84 */
4, /* 85 */ 4, /* 86 */ 5, /* 87 */ 3, /* 88 */ 4, /* 89 */
4, /* 90 */ 5, /* 91 */ 4, /* 92 */ 5, /* 93 */ 5, /* 94 */
6, /* 95 */ 2, /* 96 */ 3, /* 97 */ 3, /* 98 */ 4, /* 99 */
3, /* 100 */ 4, /* 101 */ 4, /* 102 */ 5, /* 103 */ 3, /* 104 */
4, /* 105 */ 4, /* 106 */ 5, /* 107 */ 4, /* 108 */ 5, /* 109 */
5, /* 110 */ 6, /* 111 */ 3, /* 112 */ 4, /* 113 */ 4, /* 114 */
5, /* 115 */ 4, /* 116 */ 5, /* 117 */ 5, /* 118 */ 6, /* 119 */
4, /* 120 */ 5, /* 121 */ 5, /* 122 */ 6, /* 123 */ 5, /* 124 */
6, /* 125 */ 6, /* 126 */ 7, /* 127 */ 1, /* 128 */ 2, /* 129 */
2, /* 130 */ 3, /* 131 */ 2, /* 132 */ 3, /* 133 */ 3, /* 134 */
4, /* 135 */ 2, /* 136 */ 3, /* 137 */ 3, /* 138 */ 4, /* 139 */
3, /* 140 */ 4, /* 141 */ 4, /* 142 */ 5, /* 143 */ 2, /* 144 */
3, /* 145 */ 3, /* 146 */ 4, /* 147 */ 3, /* 148 */ 4, /* 149 */
4, /* 150 */ 5, /* 151 */ 3, /* 152 */ 4, /* 153 */ 4, /* 154 */
5, /* 155 */ 4, /* 156 */ 5, /* 157 */ 5, /* 158 */ 6, /* 159 */
2, /* 160 */ 3, /* 161 */ 3, /* 162 */ 4, /* 163 */ 3, /* 164 */
4, /* 165 */ 4, /* 166 */ 5, /* 167 */ 3, /* 168 */ 4, /* 169 */
4, /* 170 */ 5, /* 171 */ 4, /* 172 */ 5, /* 173 */ 5, /* 174 */
6, /* 175 */ 3, /* 176 */ 4, /* 177 */ 4, /* 178 */ 5, /* 179 */
4, /* 180 */ 5, /* 181 */ 5, /* 182 */ 6, /* 183 */ 4, /* 184 */
5, /* 185 */ 5, /* 186 */ 6, /* 187 */ 5, /* 188 */ 6, /* 189 */
6, /* 190 */ 7, /* 191 */ 2, /* 192 */ 3, /* 193 */ 3, /* 194 */
4, /* 195 */ 3, /* 196 */ 4, /* 197 */ 4, /* 198 */ 5, /* 199 */
3, /* 200 */ 4, /* 201 */ 4, /* 202 */ 5, /* 203 */ 4, /* 204 */
5, /* 205 */ 5, /* 206 */ 6, /* 207 */ 3, /* 208 */ 4, /* 209 */
4, /* 210 */ 5, /* 211 */ 4, /* 212 */ 5, /* 213 */ 5, /* 214 */
6, /* 215 */ 4, /* 216 */ 5, /* 217 */ 5, /* 218 */ 6, /* 219 */
5, /* 220 */ 6, /* 221 */ 6, /* 222 */ 7, /* 223 */ 3, /* 224 */
4, /* 225 */ 4, /* 226 */ 5, /* 227 */ 4, /* 228 */ 5, /* 229 */
5, /* 230 */ 6, /* 231 */ 4, /* 232 */ 5, /* 233 */ 5, /* 234 */
6, /* 235 */ 5, /* 236 */ 6, /* 237 */ 6, /* 238 */ 7, /* 239 */
4, /* 240 */ 5, /* 241 */ 5, /* 242 */ 6, /* 243 */ 5, /* 244 */
6, /* 245 */ 6, /* 246 */ 7, /* 247 */ 5, /* 248 */ 6, /* 249 */
6, /* 250 */ 7, /* 251 */ 6, /* 252 */ 7, /* 253 */ 7, /* 254 */
8 /* 255 */
}; // end _Bit_count
template <bool dummy>
unsigned char first_bit_location<dummy>::value[] = {
0, /* 0 */ 0, /* 1 */ 1, /* 2 */ 0, /* 3 */ 2, /* 4 */
0, /* 5 */ 1, /* 6 */ 0, /* 7 */ 3, /* 8 */ 0, /* 9 */
1, /* 10 */ 0, /* 11 */ 2, /* 12 */ 0, /* 13 */ 1, /* 14 */
0, /* 15 */ 4, /* 16 */ 0, /* 17 */ 1, /* 18 */ 0, /* 19 */
2, /* 20 */ 0, /* 21 */ 1, /* 22 */ 0, /* 23 */ 3, /* 24 */
0, /* 25 */ 1, /* 26 */ 0, /* 27 */ 2, /* 28 */ 0, /* 29 */
1, /* 30 */ 0, /* 31 */ 5, /* 32 */ 0, /* 33 */ 1, /* 34 */
0, /* 35 */ 2, /* 36 */ 0, /* 37 */ 1, /* 38 */ 0, /* 39 */
3, /* 40 */ 0, /* 41 */ 1, /* 42 */ 0, /* 43 */ 2, /* 44 */
0, /* 45 */ 1, /* 46 */ 0, /* 47 */ 4, /* 48 */ 0, /* 49 */
1, /* 50 */ 0, /* 51 */ 2, /* 52 */ 0, /* 53 */ 1, /* 54 */
0, /* 55 */ 3, /* 56 */ 0, /* 57 */ 1, /* 58 */ 0, /* 59 */
2, /* 60 */ 0, /* 61 */ 1, /* 62 */ 0, /* 63 */ 6, /* 64 */
0, /* 65 */ 1, /* 66 */ 0, /* 67 */ 2, /* 68 */ 0, /* 69 */
1, /* 70 */ 0, /* 71 */ 3, /* 72 */ 0, /* 73 */ 1, /* 74 */
0, /* 75 */ 2, /* 76 */ 0, /* 77 */ 1, /* 78 */ 0, /* 79 */
4, /* 80 */ 0, /* 81 */ 1, /* 82 */ 0, /* 83 */ 2, /* 84 */
0, /* 85 */ 1, /* 86 */ 0, /* 87 */ 3, /* 88 */ 0, /* 89 */
1, /* 90 */ 0, /* 91 */ 2, /* 92 */ 0, /* 93 */ 1, /* 94 */
0, /* 95 */ 5, /* 96 */ 0, /* 97 */ 1, /* 98 */ 0, /* 99 */
2, /* 100 */ 0, /* 101 */ 1, /* 102 */ 0, /* 103 */ 3, /* 104 */
0, /* 105 */ 1, /* 106 */ 0, /* 107 */ 2, /* 108 */ 0, /* 109 */
1, /* 110 */ 0, /* 111 */ 4, /* 112 */ 0, /* 113 */ 1, /* 114 */
0, /* 115 */ 2, /* 116 */ 0, /* 117 */ 1, /* 118 */ 0, /* 119 */
3, /* 120 */ 0, /* 121 */ 1, /* 122 */ 0, /* 123 */ 2, /* 124 */
0, /* 125 */ 1, /* 126 */ 0, /* 127 */ 7, /* 128 */ 0, /* 129 */
1, /* 130 */ 0, /* 131 */ 2, /* 132 */ 0, /* 133 */ 1, /* 134 */
0, /* 135 */ 3, /* 136 */ 0, /* 137 */ 1, /* 138 */ 0, /* 139 */
2, /* 140 */ 0, /* 141 */ 1, /* 142 */ 0, /* 143 */ 4, /* 144 */
0, /* 145 */ 1, /* 146 */ 0, /* 147 */ 2, /* 148 */ 0, /* 149 */
1, /* 150 */ 0, /* 151 */ 3, /* 152 */ 0, /* 153 */ 1, /* 154 */
0, /* 155 */ 2, /* 156 */ 0, /* 157 */ 1, /* 158 */ 0, /* 159 */
5, /* 160 */ 0, /* 161 */ 1, /* 162 */ 0, /* 163 */ 2, /* 164 */
0, /* 165 */ 1, /* 166 */ 0, /* 167 */ 3, /* 168 */ 0, /* 169 */
1, /* 170 */ 0, /* 171 */ 2, /* 172 */ 0, /* 173 */ 1, /* 174 */
0, /* 175 */ 4, /* 176 */ 0, /* 177 */ 1, /* 178 */ 0, /* 179 */
2, /* 180 */ 0, /* 181 */ 1, /* 182 */ 0, /* 183 */ 3, /* 184 */
0, /* 185 */ 1, /* 186 */ 0, /* 187 */ 2, /* 188 */ 0, /* 189 */
1, /* 190 */ 0, /* 191 */ 6, /* 192 */ 0, /* 193 */ 1, /* 194 */
0, /* 195 */ 2, /* 196 */ 0, /* 197 */ 1, /* 198 */ 0, /* 199 */
3, /* 200 */ 0, /* 201 */ 1, /* 202 */ 0, /* 203 */ 2, /* 204 */
0, /* 205 */ 1, /* 206 */ 0, /* 207 */ 4, /* 208 */ 0, /* 209 */
1, /* 210 */ 0, /* 211 */ 2, /* 212 */ 0, /* 213 */ 1, /* 214 */
0, /* 215 */ 3, /* 216 */ 0, /* 217 */ 1, /* 218 */ 0, /* 219 */
2, /* 220 */ 0, /* 221 */ 1, /* 222 */ 0, /* 223 */ 5, /* 224 */
0, /* 225 */ 1, /* 226 */ 0, /* 227 */ 2, /* 228 */ 0, /* 229 */
1, /* 230 */ 0, /* 231 */ 3, /* 232 */ 0, /* 233 */ 1, /* 234 */
0, /* 235 */ 2, /* 236 */ 0, /* 237 */ 1, /* 238 */ 0, /* 239 */
4, /* 240 */ 0, /* 241 */ 1, /* 242 */ 0, /* 243 */ 2, /* 244 */
0, /* 245 */ 1, /* 246 */ 0, /* 247 */ 3, /* 248 */ 0, /* 249 */
1, /* 250 */ 0, /* 251 */ 2, /* 252 */ 0, /* 253 */ 1, /* 254 */
0, /* 255 */
}; // end _First_one
} // namespace detail
} // namespace boost

View File

@@ -0,0 +1,700 @@
#ifndef BOOST_GRAPH_ISOMORPHISM_HPP
#define BOOST_GRAPH_ISOMORPHISM_HPP
// UNDER CONSTRUCTION
namespace boost {
namespace detail {
//=========================================================================
// Mathematical Set Concept
//
// bool equal(a,b)
// bool is_subset(a, b)
// bool is_proper_subset(a, b)
// void intersect(a, b, c)
// void union(a, b, c)
// void difference(a, b, c)
// void complement(a, c)
// void insert(a, x)
// void remove(a, x)
// bool contains(a, x)
// void clear(a)
// bool empty(a)
// set_traits<S>::size_type
// size_type size(a)
// set_traits<S>::iterator
// iterator begin(a)
// iterator end(a)
//=========================================================================
// d_G(v,W) == out_degree(v, vertex_subset_filter(W, G))
//
// for all V_i, V_j \in \pi
// d_G(v_i,V_j) = d_ij for all v_i \in V_i
template <typename PartitionCells, typename Graph>
bool is_equitable_partition(const PartitionCells& p,
const Graph& g)
{
typedef typename PartitionCells::value_type cell_t;
typedef typename vertex_subset_filter<Graph, cell_t>::type subgraph_t;
for (i = 0; i != size(p); ++i)
for (j = 0; j != size(p); ++j) {
subgraph_t w(p[j], g);
assert(size(p[i]) > 0);
vi = begin(p[i]);
d = out_degree(*vi++, w);
for (; vi != end(p[i]); ++vi) {
if (d != out_degree(*vi, w))
return false;
}
}
return true;
}
//=========================================================================
template <typename Set1, typename Set2, typename Permutation>
void permutation_set(const Set1& set1,
Set2& set2,
const Permutation& perm)
{
clear(set2);
for (typename set_traits<Set1>::iterator i = begin(set1);
i != end(set1); ++i)
insert(set2, perm[*i]);
}
//=========================================================================
template <typename Graph, typename Permutation>
bool is_automorphism(const Graph& g, const Permutation& perm)
{
for (tie(i, i_end) = vertices(g); i != i_end; ++i)
for (tie(j, j_end) = adjacent_vertices(*i, g); j != j_end; ++j)
if (!edge(*j, perm[*j], g).second)
return false;
return true;
}
//=========================================================================
template <typename OrbitsMap, typename Permutation>
int join_orbits(OrbitsMap& orbits,
const Permutation& perm,
int n)
{
int i, j1, j2;
for (i = 0; i < n; ++i) {
j1 = orbits[i];
while (orbits[j1] != j1)
j1 = orbits[j1];
j2 = orbits[perm[i]];
while (orbits[j2] != j2)
j2 = orbits[j2];
if (j1 < j2)
orbits[j2] = j1;
else if (j1 > j2)
orbits[j1] = j2;
}
j1 = 0;
for (i = 0; i < n; ++i)
if ((orbits[i] = orbits[orbits[i]]) == i)
++j1;
return j1;
}
//=========================================================================
template <typename Graph1, typename Graph2,
typename Labeling1, typename Labeling2>
int test_canonical_labeling(const Graph1& g, const Graph2& canonical_g,
const Labeling1& g_labeling,
const Labeling2& canonical_g_labeling,
int& samerows)
{
int i, j;
set *ph;
permutation_type work_perm(n);
set_type work_set(m);
for (i = 0; i < n; ++i)
work_perm[labeling[i]] = i;
//for (i = 0, ph = canong; i < n; ++i, ph += M) {
for (tie(i, i_end) = vertices(canonical_g); i != i_end; ++i) {
adjacent_vertices_set<Graph1>::type i_set(labeling[*i], g);
adjacent_vertices_set<Graph2>::type ph(*i, canonical_g);
permutation_set(i_set, work_set, work_perm);
int g_num = subset_number<int>(i_set, make_permuted_map(g_labeling,
work_perm));
int cg_num = subset_number<int>(ph, canonical_g_labeling);
if (g_num < cg_num)
return -1;
else if (g_num > cg_num)
return 1;
}
*samerows = n;
return 0;
}
template <typename Graph, ...>
class canonical_labeling_algo {
typedef std::vector<int> nvector_type;
public:
//=======================================================================
int first_path_node(nvector_type& lab,
nvector_type& ptn,
int level,
int numcells,
tcell_list_type::iterator tcnode_parent)
{
tcell_list_type::iterator tcnode_this = tcnode_parent;
++tcnode_this;
if (tcnode_this == tcell_list.end()) {
tcell_list.push_back(set_type());
tcnode_this = prior(tcell_list.end());
}
set_type& tcell = *tcnode_this;
// doref()
refine_partition(g, lab, level, numcells, qinv, workperm,
active, refcode, refinement_fun, vertex_invariant_fun,
mininvarlevel, maxinvarlevel, invararg,
digraph, M, n);
firstcode[level] = refcode;
if (qinvar > 0) {
++invsuccesses;
if (mininvarlevel < 0)
mininvarlevel = level;
if (maxinvarlevel < 0)
maxinvarlevel = level;
if (level < invarsuclevel)
invarsuclevel = level;
}
tc = -1;
if (numcells != n) {
/* locate new target cell, setting tc to its position in lab, tcell
to its contents, and tcellsize to its size: */
target_cell_fun(g, lab, ptn, level, numcells, tcell,&tcellsize,
&tc, tc_level, -1, M, n);
}
firsttc[level] = tc;
/* optionally call user-defined node examination procedure: */
tree_node_fun(g,lab,ptn,level,numcells,tc,(int)firstcode[level],M,n);
if (numcells == n) /* found first leaf? */
{
first_terminal(lab,level);
level_fun(lab,ptn,level,orbits,stats,0,1,1,n,0,n);
return level-1;
}
if (noncheaplevel >= level && !cheapautom(ptn,level,digraph,n))
noncheaplevel = level + 1;
/* use the elements of the target cell to produce the children: */
index = 0;
for (tv1 = tv = nextelement(tcell,M,-1); tv >= 0;
tv = nextelement(tcell,M,tv))
{
if (orbits[tv] == tv) /* ie, not equiv to previous child */
{
breakout(lab,ptn,level+1,tc,tv,active,M);
insert(tv, fixedpts);
cosetindex = tv;
if (tv == tv1) {
rtnlevel = first_path_node(lab,ptn,level+1,numcells+1,
tcnode_this);
childcount = 1;
gca_first = level;
stabvertex = tv1;
}
else {
rtnlevel = other_node(lab,ptn,level+1,numcells+1,
tcnode_this);
++childcount;
}
remove(tv, fixedpts);
if (rtnlevel < level)
return rtnlevel;
if (needshortprune) {
needshortprune = FALSE;
shortprune(tcell,fmptr-M,M);
}
recover(ptn,level);
}
if (orbits[tv] == tv1) /* ie, in same orbit as tv1 */
++index;
}
// MULTIPLY(stats->grpsize1, stats->grpsize2, index);
if (tcellsize == index && allsamelevel == level + 1)
--allsamelevel;
if (domarkers)
writemarker(level,tv1,index,tcellsize,stats->numorbits,numcells);
level_fun(lab,ptn,level,orbits,stats,tv1,index,tcellsize,
numcells,childcount,n);
return level-1;
} // first_path_node()
//=======================================================================
int other_node(lab, ptn, level, numcells, tcnode_parent)
{
int tv;
int tv1,refcode,rtnlevel,tcellsize,tc,qinvar;
short code;
tcell_list_type::iterator tcnode_this = tcnode_parent;
++tcnode_type;
if (tcnode_this == tcell_list.end()) {
tcell_list.push_back(set_type());
tcnode_this = prior(tcell_list.end());
}
set_type& tcell = *tcnode_this;
++stats->numnodes;
// doref()
refine_partition(g,lab,ptn,level,numcells,qinvar,workperm,active,
refcode,refinement_fun,vertex_invariant_fun,
mininvarlevel,maxinvarlevel,
invararg,digraph,M,n);
code = (short)refcode;
if (qinvar > 0) {
++invapplics;
if (qinvar == 2) {
++invsuccesses;
if (level < invarsuclevel)
invarsuclevel = level;
}
}
if (eqlev_first == level - 1 && code == firstcode[level])
eqlev_first = level;
if (getcanon) {
if (eqlev_canon == level - 1){
if (code < canoncode[level])
comp_canon = -1;
else if (code > canoncode[level])
comp_canon = 1;
else {
comp_canon = 0;
eqlev_canon = level;
}
}
if (comp_canon > 0)
canoncode[level] = code;
}
tc = -1;
// If children will be required, find new target cell and set
// tc to its position in lab, tcell to its contents, and
// tcellsize to its size:
if (numcells < n && (eqlev_first == level ||
getcanon && comp_canon >= 0)) {
if (!getcanon || comp_canon < 0) {
target_cell_fun(g,lab,ptn,level,numcells,tcell,tcellsize,
tc,tc_level,firsttc[level],M,n);
if (tc != firsttc[level])
eqlev_first = level - 1;
}
else
target_cell_fun(g,lab,ptn,level,numcells,tcell,tcellsize,
tc,tc_level,-1,M,n);
stats->tctotal += tcellsize;
}
// optionally call user-defined node examination procedure:
tree_node_fun(g,lab,ptn,level,numcells,tc,(int)code,M,n);
// call process_node to classify the type of this node:
rtnlevel = process_node(lab,ptn,level,numcells);
if (rtnlevel < level) /* keep returning if necessary */
return rtnlevel;
if (needshortprune) {
needshortprune = FALSE;
shortprune(tcell,fmptr-M,M);
}
if (!cheapautom(ptn,level,digraph,n))
noncheaplevel = level + 1;
// use the elements of the target cell to produce the children:
for (tv1 = tv = nextelement(tcell,M,-1); tv >= 0;
tv = nextelement(tcell,M,tv)) {
breakout(lab,ptn,level+1,tc,tv,active,M);
insert(tv, fixedpts);
rtnlevel = other_node(lab,ptn,level+1,numcells+1,tcnode_this);
remove(tv, fixedpts);
if (rtnlevel < level)
return rtnlevel;
// use stored automorphism data to prune target cell:
if (needshortprune) {
needshortprune = FALSE;
short_prune(tcell,fmptr-M,M);
}
if (tv == tv1)
long_prune(tcell,fixedpts,workspace,fmptr,M);
recover(ptn,level);
}
return level-1;
}
//=======================================================================
void first_terminal(nvector_type& lab, int level)
{
register int i;
stats->maxlevel = level;
gca_first = allsamelevel = eqlev_first = level;
firstcode[level+1] = 077777;
firsttc[level+1] = -1;
for (i = 0; i < n; ++i)
firstlab[i] = lab[i];
if (getcanon) {
canonlevel = eqlev_canon = gca_canon = level;
comp_canon = 0;
samerows = 0;
for (i = 0; i < n; ++i)
canonlab[i] = lab[i];
for (i = 0; i <= level; ++i)
canoncode[i] = firstcode[i];
canoncode[level+1] = 077777;
stats->canupdates = 1;
}
}
//=======================================================================
int process_node(nvector_type& lab, nvector_type& ptn,
int level, int numcells)
{
int i,code,save,newlevel;
bool ispruneok;
int sr;
code = 0;
if (eqlev_first != level && (!getcanon || comp_canon < 0))
code = 4;
else if (numcells == n) {
if (eqlev_first == level) {
for (i = 0; i < n; ++i)
workperm[firstlab[i]] = lab[i];
if (gca_first >= noncheaplevel ||
isautom(g,workperm,digraph,M,n))
code = 1;
}
if (code == 0)
if (getcanon) {
sr = 0;
if (comp_canon == 0) {
if (level < canonlevel)
comp_canon = 1;
else {
update_can(g,canong,canonlab, samerows,M,n);
samerows = n;
comp_canon = testcanlab(g,canong,lab,&sr,M,n);
}
}
if (comp_canon == 0) {
for (i = 0; i < n; ++i)
workperm[canonlab[i]] = lab[i];
code = 2;
}
else if (comp_canon > 0)
code = 3;
else
code = 4;
}
else
code = 4;
}
if (code != 0 && level > stats->maxlevel)
stats->maxlevel = level;
switch (code) {
case 0: /* nothing unusual noticed */
return level;
case 1: /* lab is equivalent to firstlab */
if (fmptr == worktop)
fmptr -= 2 * M;
fmperm(workperm,fmptr,fmptr+M,M,n);
fmptr += 2 * M;
if (writeautoms)
writeperm(outfile,workperm,cartesian,linelength,n);
stats->numorbits = orbjoin(orbits,workperm,n);
++stats->numgenerators;
automorphism_fun(stats->numgenerators,workperm,orbits,
stats->numorbits,stabvertex,n);
return gca_first;
case 2: /* lab is equivalent to canonlab */
if (fmptr == worktop)
fmptr -= 2 * M;
fmperm(workperm,fmptr,fmptr+M,M,n);
fmptr += 2 * M;
save = stats->numorbits;
stats->numorbits = orbjoin(orbits,workperm,n);
if (stats->numorbits == save)
{
if (gca_canon != gca_first)
needshortprune = TRUE;
return gca_canon;
}
if (writeautoms)
writeperm(outfile,workperm,cartesian,linelength,n);
++stats->numgenerators;
automorphism_fun(stats->numgenerators,workperm,orbits,
stats->numorbits,stabvertex,n);
if (orbits[cosetindex] < cosetindex)
return gca_first;
if (gca_canon != gca_first)
needshortprune = TRUE;
return gca_canon;
case 3: /* lab is better than canonlab */
++stats->canupdates;
for (i = 0; i < n; ++i)
canonlab[i] = lab[i];
canonlevel = eqlev_canon = gca_canon = level;
comp_canon = 0;
canoncode[level+1] = 077777;
samerows = sr;
break;
case 4: /* non-automorphism terminal node */
++stats->numbadleaves;
break;
} /* end of switch statement */
/* only cases 3 and 4 get this far: */
if (level != noncheaplevel) {
ispruneok = TRUE;
if (fmptr == worktop)
fmptr -= 2 * M;
fmptn(lab,ptn,noncheaplevel,fmptr,fmptr+M,M,n);
fmptr += 2 * M;
}
else
ispruneok = FALSE;
save = (allsamelevel > eqlev_canon ? allsamelevel-1 : eqlev_canon);
newlevel = (noncheaplevel <= save ? noncheaplevel-1 : save);
if (ispruneok && newlevel != gca_first)
needshortprune = TRUE;
return newlevel;
} // process_node()
//=======================================================================
void recover(nvector_type& ptn, int level)
{
int i;
for (i = 0; i < n; ++i)
if (ptn[i] > level)
ptn[i] = INFINITY;
if (level < noncheaplevel)
noncheaplevel = level + 1;
if (level < eqlev_first)
eqlev_first = level;
if (getcanon) {
if (level < gca_canon)
gca_canon = level;
if (level <= eqlev_canon) {
eqlev_canon = level;
comp_canon = 0;
}
}
}
//=======================================================================
void write_marker(int level, int tv, int index, int tcellsize,
int numorbits, int numcells)
{
outfile << "level ";
outfile << level;
outfile << ": ";
if (numcells != numorbits) {
outfile << numcells;
outfile << " cell";
if (numcells == 1)
outfile << "; ";
else
outfile << "s; ";
}
outfile << numorbits;
outfile << " orbit";
if (numorbits == 1)
outfile << "; ";
else
outfile << "s; ";
outfile << tv+labelorg;
outfile << " fixed; index ";
outfile << index;
if (tcellsize != index) {
outfile << "/";
outfile << tcellsize;
}
outfile << "\n";
}
//=======================================================================
protected:
typedef std::bitset<int> set_type;
typedef std::vector<int> permutation_type;
typedef std::list<set_type> tcell_list_type;
tcell_list_type tcell_list; // target cell list
int m, n;
nvector_type orbits;
graph_type canong;
Graph g;
long invapplics,invsuccesses;
int invarsuclevel;
int gca_first, // level of greatest common ancestor of current
// node and first leaf
gca_canon, // ditto for current node and bsf leaf
noncheaplevel, // level of greatest ancestor for which
// cheapautom == FALSE
allsamelevel, // level of least ancestor of first leaf for
// which all descendant leaves are known to be
// equivalent
eqlev_first, // level to which codes for this node match
// those for first leaf
eqlev_canon, /* level to which codes for this node match those
for the bsf leaf. */
comp_canon, /* -1,0,1 according as code at eqlev_canon+1 is
<,==,> that for bsf leaf. Also used for
similar purpose during leaf processing */
samerows, /* number of rows of canong which are correct for
the bsf leaf BDM:correct? */
canonlevel, /* level of bsf leaf */
stabvertex, /* point fixed in ancestor of first leaf at level
gca_canon */
cosetindex; /* the point being fixed at level gca_first */
bool needshortprune; /* used to flag calls to shortprune */
set_type defltwork; /* workspace in case none provided */
permutation_type workperm; /* various scratch uses */
set_type fixedpts; /* points which were explicitly
fixed to get current node */
permutation_type firstlab, /* label from first leaf */
canonlab; /* label from bsf leaf */
codes_type firstcode, /* codes for first leaf */
canoncode; /* codes for bsf leaf */
std::vector<int> firsttc; /* index of target cell for left path */
set_type active; /* used to contain index to cells now
active for refinement purposes */
#if 0
set *workspace,*worktop; /* first and just-after-last addresses of
work area to hold automorphism data */
set *fmptr; /* pointer into workspace */
int alloc_m = 0;
#endif
// Various user-parameterizable functions:
TargetCellFunction target_cell_fun;// target cell function
RefinementFunction refinement_fun; // refinement function
AutomorphismFunction automorphism_fun; // automorphism callback
LevelFunction level_fun; // level callback
TreeNodeFunction tree_node_fun; // tree node callback
VertexInvariantFunction vertex_invariant_fun; // vertex invariant function
};
// This is a "UPROC" user-procedure
class target_cell
{
public:
target_cell() { }
operator()(Graph& g,
nvector_type& lab, nvector_type& ptn,
int level, int numcells,
set_type& tcell,
int& cellpos, int tc_level, int hint, int m, int n)
{
int i, j, k;
if (hint >= 0 && ptn[hint] > level &&
(hint == 0 || ptn[hint-1] <= level))
i = hint;
else if (level <= tc_level)
i = bestcell(g, lab, ptn, level, tc_level, m, n);
else
for (i = 0; i < n && ptn[i] <= level; ++i)
{ }
if (i == n)
i = j = 0;
else
for (j = i + 1; ptn[j] > level; ++j)
{ }
tcell.clear();
for (k = i; k <= j; ++k)
tcell.insert(lab[k]);
*cellpos = i;
}
};
} // namespace detail
template <typename Graph,
typename VertexIndexMap1,
typename VertexIndexMap2>
void
canonical_labeling(const Graph& g, // IN
VertexIndexMap1 old_labels, // IN
VertexIndexMap2 new_labels, // OUT
OrbitMap orbits) // OUT
{
typedef typename property_traits<VertexIndexMap2>::value_type label_type;
std::stack<partition_type> S;
while (! S.empty() {
}
}
} // namespace boost
#endif // BOOST_GRAPH_ISOMORPHISM_HPP