//
// libsemigroups - C++ library for semigroups and monoids
// Copyright (C) 2019 James D. Mitchell
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// This file contains the declaration for a class to manage cosets for a
// ToddCoxeter instance.
#ifndef LIBSEMIGROUPS_COSET_HPP_
#define LIBSEMIGROUPS_COSET_HPP_
#include <cstddef>
// for size_t
#include <cstdint>
// for uint32_t
#include <vector>
// for vector
#include "constants.hpp" // for UNDEFINED
#include "debug.hpp" // for LIBSEMIGROUPS_ASSERT/DEBUG
namespace libsemigroups {
namespace detail {
class CosetManager {
public:
////////////////////////////////////////////////////////////////////////
// CosetManager - typedefs - public
////////////////////////////////////////////////////////////////////////
//! Type of cosets stored in the table.
using coset_type = uint32_t;
using Perm = std::vector<coset_type>;
////////////////////////////////////////////////////////////////////////
// CosetManager - constructors + destructor - public
////////////////////////////////////////////////////////////////////////
CosetManager();
CosetManager(CosetManager
const&) =
default;
CosetManager(CosetManager&&) =
default;
CosetManager&
operator=(CosetManager
const&) =
delete;
CosetManager&
operator=(CosetManager&&) =
delete;
~CosetManager();
////////////////////////////////////////////////////////////////////////
// CosetManager - member functions - public
////////////////////////////////////////////////////////////////////////
//! Returns the capacity of the coset table.
//!
//! \returns A value of type \c size_t.
//!
//! \exceptions
//! \noexcept
//!
//! \complexity
//! Constant
//!
//! \par Parameters
//! (None)
// std::vector::size is noexcept
inline size_t coset_capacity()
const noexcept {
return _forwd.size();
}
//! Returns the first free coset.
//!
//! \returns A value of type CosetManager::coset_type
//!
//! \exceptions
//! \noexcept
//!
//! \complexity
//! Constant
//!
//! \par Parameters
//! (None)
inline coset_type first_free_coset()
const noexcept {
return _first_free_coset;
}
//! Check if there are any free cosets.
//!
//! \returns A value of type \c bool.
//!
//! \exceptions
//! \noexcept
//!
//! \complexity
//! Constant
//!
//! \par Parameters
//! (None)
inline bool has_free_cosets()
const noexcept {
return _first_free_coset != UNDEFINED;
}
//! Check if the given coset is active or not.
//!
//! \param c the coset to check.
//!
//! \returns A value of type \c bool.
//!
//! \exceptions
//! \no_libsemigroups_except
//!
//! \complexity
//! Constant
// not noexcept since std::vector::operator[] isn't.
inline bool is_active_coset(coset_type c)
const {
LIBSEMIGROUPS_ASSERT(c < _ident.size() || c == UNDEFINED);
return c != UNDEFINED && _ident[c] == c;
}
//! Check if the given coset is valid.
//!
//! \param c the coset to check.
//!
//! \returns A value of type \c bool.
//!
//! \exceptions
//! \noexcept
//!
//! \complexity
//! Constant
inline bool is_valid_coset(coset_type c)
const noexcept {
return c < _forwd.size();
}
//! Returns the next active coset after the given coset.
//!
//! \param c the coset.
//!
//! \returns A value of type CosetManager::coset_type
//!
//! \exceptions
//! \no_libsemigroups_except
//!
//! \complexity
//! Constant
// not noexcept since std::vector::operator[] isn't.
inline coset_type next_active_coset(coset_type c)
const {
LIBSEMIGROUPS_ASSERT(is_active_coset(c));
return _forwd[c];
}
//! Returns the number of active cosets.
//!
//! \returns A value of type \c size_t.
//!
//! \exceptions
//! \noexcept
//!
//! \complexity
//! Constant
//!
//! \par Parameters
//! (None)
inline size_t number_of_cosets_active()
const noexcept {
return _active;
}
//! Returns the total number of cosets defined so far.
//!
//! \returns A value of type \c size_t.
//!
//! \exceptions
//! \noexcept
//!
//! \complexity
//! Constant
//!
//! \par Parameters
//! (None)
inline size_t number_of_cosets_defined()
const noexcept {
return _
defined;
}
//! Returns the total number of cosets that have been killed so far.
//!
//! \returns A value of type \c size_t.
//!
//! \exceptions
//! \noexcept
//!
//! \complexity
//! Constant
//!
//! \par Parameters
//! (None)
inline size_t number_of_cosets_killed()
const noexcept {
return _cosets_killed;
}
//! Set the value of the growth factor setting.
//!
//! This setting is used to determine the factor by which the number of
//! cosets in the table is increased, when more cosets are required.
//!
//! The default value of this setting is \c 2.0.
//!
//! \param val the new value of the setting.
//!
//! \returns A reference to \c *this.
//!
//! \throws LibsemigroupsException if \p val is less than \c 1.0.
//!
//! \complexity
//! Constant
CosetManager& growth_factor(
float val);
//! The current value of the growth factor setting.
//!
//! \parameters
//! (None)
//!
//! \returns A value of type \c float.
//!
//! \exceptions
//! \noexcept
//!
//! \complexity
//! Constant
float growth_factor()
const noexcept {
return _growth_factor;
}
protected:
////////////////////////////////////////////////////////////////////////
// CosetManager - member functions - protected
////////////////////////////////////////////////////////////////////////
// not noexcept because free_coset isn't, and std::vector::operator[]
// isn't.
//! No doc
inline void union_cosets(coset_type min, coset_type max) {
LIBSEMIGROUPS_ASSERT(is_active_coset(min));
LIBSEMIGROUPS_ASSERT(is_active_coset(max));
LIBSEMIGROUPS_ASSERT(max > min);
free_coset(max);
// Leave a "forwarding address" so we know what <max> was identified
// with
_ident[max] = min;
}
// not noexcept since std::vector::operator[] isn't.
//! No doc
inline coset_type find_coset(coset_type c)
const {
LIBSEMIGROUPS_ASSERT(is_valid_coset(c));
while (
true) {
coset_type d = _ident[c];
if (d == c) {
return d;
}
coset_type e = _ident[d];
if (d == e) {
return d;
}
_ident[c] = e;
c = e;
}
LIBSEMIGROUPS_ASSERT(is_active_coset(c));
return c;
}
//! No doc
void add_active_cosets(size_t);
//! No doc
void add_free_cosets(size_t);
//! No doc
void erase_free_cosets();
//! No doc
coset_type new_active_coset();
//! No doc
void switch_cosets(coset_type
const, coset_type
const);
//! No doc
void apply_permutation(Perm& p);
// not noexcept since std::vector::operator[] isn't.
void free_coset(coset_type
const);
////////////////////////////////////////////////////////////////////////
// CosetManager - data - protected
////////////////////////////////////////////////////////////////////////
static constexpr coset_type _id_coset = 0;
coset_type _current;
coset_type _current_la;
private:
////////////////////////////////////////////////////////////////////////
// CosetManager - member functions - private
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// CosetManager - data - private
////////////////////////////////////////////////////////////////////////
size_t _active;
std::vector<coset_type> _bckwd;
size_t _cosets_killed;
size_t _
defined;
coset_type _first_free_coset;
std::vector<coset_type> _forwd;
float _growth_factor;
mutable std::vector<coset_type> _ident;
coset_type _last_active_coset;
#ifdef LIBSEMIGROUPS_DEBUG
protected:
////////////////////////////////////////////////////////////////////////
// CosetManager - member functions (debug only) - protected
////////////////////////////////////////////////////////////////////////
void debug_validate_forwd_bckwd()
const;
#endif
};
}
// namespace detail
}
// namespace libsemigroups
#endif // LIBSEMIGROUPS_COSET_HPP_