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:
704
include/boost/graph/detail/bitset.hpp
Normal file
704
include/boost/graph/detail/bitset.hpp
Normal 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
|
||||
700
include/boost/graph/isomorphism.hpp
Normal file
700
include/boost/graph/isomorphism.hpp
Normal 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
|
||||
Reference in New Issue
Block a user