// // 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 implementation for a class to manage cosets for a // ToddCoxeter instance.
#include"libsemigroups/coset.hpp"
#include <cstddef> // for size_t #include <numeric> // for iota
#include"libsemigroups/debug.hpp"// for LIBSEMIGROUPS_ASSERT #include"libsemigroups/exception.hpp"// for LIBSEMIGROUPS_EXCEPTION
#ifdef LIBSEMIGROUPS_DEBUG #include"libsemigroups/report.hpp"// for REPORT_DEBUG #endif
//////////////////////////////////////////////////////////////////////////////// // // We use these two vectors to implement a doubly-linked list of cosets. There // are two types of coset, those that are "active" and those that are "free". // // If c is a coset, then // * _forwd[c] is the coset that comes after c in the list, // _forwd[the last coset in the list] = UNDEFINED // // * _bckwd[c] is the coset that comes before c in the list, // _bckwd[_id_coset] = _id_coset // // If c is an active coset, then _ident[c] = c. // // If c is a free coset, then _ident[c] != c. // // We also store some special locations in the list: // // * _id_coset: the first coset, this never changes. // // * _current: is the coset which we are currently using for something in a // loop somewhere, the member functions of this class guarantee that // _current always points to an active coset, even if the value changes // during a function call. // // * _current_la: is similar to _current, and can be used independently of // _current. // // * _last_active_coset points to the final active coset in the list. // // * _first_free_coset points to the first free coset in the list, if there // are any, or is set to UNDEFINED if there aren't any. Otherwise, // _first_free_coset == _forwd[_last_active_coset]. // ////////////////////////////////////////////////////////////////////////////////
CosetManager& CosetManager::growth_factor(float val) { if (val < 1.0) {
LIBSEMIGROUPS_EXCEPTION("expected a value of at least 1.0, found %f",
val);
}
_growth_factor = val; return *this;
}
//////////////////////////////////////////////////////////////////////// // CosetManager - member functions - protected ////////////////////////////////////////////////////////////////////////
void CosetManager::add_active_cosets(size_t n) { if (n > (coset_capacity() - number_of_cosets_active())) {
size_t const m = n - (coset_capacity() - number_of_cosets_active());
add_free_cosets(m); // add_free_cosets adds new free cosets to the start of the free list
_last_active_coset = _forwd.size() - 1;
_first_free_coset = _forwd[_last_active_coset];
std::iota(_ident.begin() + (_ident.size() - m),
_ident.end(),
_ident.size() - m);
_active += m;
_defined += m;
n -= m;
}
_active += n;
_defined += n; for (; n > 0; --n) {
_bckwd[_first_free_coset] = _last_active_coset;
_last_active_coset = _first_free_coset;
_first_free_coset = _forwd[_last_active_coset];
_ident[_last_active_coset] = _last_active_coset;
}
}
void CosetManager::add_free_cosets(size_t n) { // We add n new free cosets at the end of the current list, and link them // in as follows: // // 0 <-> ... <-> _last_active_coset <-> old_capacity <-> new free coset 1 // <-> ... <-> new free coset n <-> old_first_free_coset // <-> remaining old free cosets
size_t const old_capacity = _forwd.size();
coset_type const old_first_free_coset = _first_free_coset;
coset_type CosetManager::new_active_coset() { if (_first_free_coset == UNDEFINED) { // There are no free cosets to recycle: make new ones. // It seems to be marginally faster to make lots like this, than to // just make 1, in some examples, notably ToddCoxeter 040 (Walker 3).
add_free_cosets(growth_factor() * coset_capacity());
}
add_active_cosets(1); return _last_active_coset;
}
_current = ff(c, d, _current);
_last_active_coset = ff(c, d, _last_active_coset);
_first_free_coset = ff(c, d, _first_free_coset); // This is never called from lookahead so we don't have to update // _current_la, also it might be that we are calling this after // everything is finished and so _current may not be active.
// The permutation p ^ -1 must map the active cosets to the [0, .. // , number_of_cosets_active()) void CosetManager::apply_permutation(CosetManager::Perm& p) {
size_t const n = p.size(); for (coset_type i = 0; i < n; ++i) {
coset_type current = i; while (i != p[current]) {
size_t next = p[current];
switch_cosets(current, next);
p[current] = current;
current = next;
}
p[current] = current;
}
}
//////////////////////////////////////////////////////////////////////// // CosetManager - member functions - private ////////////////////////////////////////////////////////////////////////
void CosetManager::free_coset(coset_type c) {
_active--;
_cosets_killed++;
LIBSEMIGROUPS_ASSERT(is_active_coset(c)); // If any "controls" point to <c>, move them back one in the list
LIBSEMIGROUPS_ASSERT(_current < _bckwd.size()
|| _current == _first_free_coset);
_current = (c == _current ? _bckwd[_current] : _current);
LIBSEMIGROUPS_ASSERT(_current_la < _bckwd.size()
|| _current_la == _first_free_coset);
_current_la = (c == _current_la ? _bckwd[_current_la] : _current_la);
if (c == _last_active_coset) { // Simply move the start of the free list back by 1
LIBSEMIGROUPS_ASSERT(_last_active_coset < _bckwd.size());
_last_active_coset = _bckwd[_last_active_coset];
} else {
LIBSEMIGROUPS_ASSERT(_forwd[c] != UNDEFINED); // Remove <c> from the active list
_bckwd[_forwd[c]] = _bckwd[c];
_forwd[_bckwd[c]] = _forwd[c]; // Add <c> to the start of the free list
_forwd[c] = _first_free_coset;
LIBSEMIGROUPS_ASSERT(_last_active_coset < _forwd.size()); if (_first_free_coset != UNDEFINED) {
_bckwd[_first_free_coset] = c;
}
_forwd[_last_active_coset] = c;
}
_bckwd[c] = _last_active_coset;
_first_free_coset = c;
_ident[c] = _id_coset;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.