// // 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 a base class for f.p. semigroup like classes.
#include"libsemigroups/fpsemi-intf.hpp"
#include <algorithm> // for sort #include <string> // for std::string
#include"libsemigroups/config.hpp"// for LIBSEMIGROUPS_DEBUG #include"libsemigroups/exception.hpp"// for LIBSEMIGROUPS_EXCEPTION #include"libsemigroups/froidure-pin-base.hpp"// for FroidurePinBase #include"libsemigroups/report.hpp"// for REPORT_DEFAULT ... #include"libsemigroups/string.hpp"// for detail::to_string
//////////////////////////////////////////////////////////////////////////// // Runner - pure virtual overridden function - public ////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////// // FpSemigroupInterface - non-virtual member functions - public //////////////////////////////////////////////////////////////////////////////
void FpSemigroupInterface::set_alphabet(std::string const& lphbt) { if (!_alphabet.empty()) {
LIBSEMIGROUPS_EXCEPTION("the alphabet cannot be set more than once");
} elseif (lphbt.empty()) {
LIBSEMIGROUPS_EXCEPTION("the alphabet must be non-empty");
} for (size_t i = 0; i < lphbt.size(); ++i) { if (_alphabet_map.find(lphbt[i]) != _alphabet_map.end()) {
_alphabet_map.clear(); // Strong exception guarantee
LIBSEMIGROUPS_EXCEPTION( "invalid alphabet, it contains the duplicate letter "
+ detail::to_string(lphbt[i]));
}
_alphabet_map.emplace(lphbt[i], i);
}
_alphabet = lphbt;
set_alphabet_impl(lphbt);
reset();
}
void FpSemigroupInterface::set_alphabet(size_t number_of_letters) { if (!_alphabet.empty()) {
LIBSEMIGROUPS_EXCEPTION("the alphabet cannot be set more than once");
} elseif (number_of_letters == 0) {
LIBSEMIGROUPS_EXCEPTION("the alphabet must be non-empty");
} elseif (number_of_letters > 256) {
LIBSEMIGROUPS_EXCEPTION("the alphabet must contain at most 256 letters");
} for (size_t i = 0; i < number_of_letters; ++i) { #ifdef LIBSEMIGROUPS_DEBUG
_alphabet += static_cast<char>(i + 97); #else
_alphabet += static_cast<char>(i + 1); #endif
_alphabet_map.emplace(_alphabet[i], i);
}
set_alphabet_impl(number_of_letters);
reset();
}
void FpSemigroupInterface::add_rules(FroidurePinBase& S) { if (!_alphabet.empty() && _alphabet.size() != S.number_of_generators()) {
LIBSEMIGROUPS_EXCEPTION("incompatible number of generators, found "
+ detail::to_string(S.number_of_generators())
+ ", should be at most "
+ detail::to_string(_alphabet.size()));
}
add_rules_impl(S);
reset();
}
// Note that this can be called repeatedly, and that's fine. void FpSemigroupInterface::set_identity(std::string const& id) { if (validate_identity_impl(id)) {
_identity = id[0]; for (auto l : alphabet()) { if (l == id[0]) {
add_rule(id + id, id);
} else {
add_rule(detail::to_string(l) + id, detail::to_string(l));
add_rule(id + detail::to_string(l), detail::to_string(l));
}
}
}
_identity_defined = true;
}
std::string const& FpSemigroupInterface::identity() const { if (_identity_defined) { return _identity;
} else {
LIBSEMIGROUPS_EXCEPTION("no identity has been defined");
}
}
void FpSemigroupInterface::set_inverses(std::string const& inv) { if (!_inverses.empty()) {
LIBSEMIGROUPS_EXCEPTION( "inverses already defined, cannot define inverses more than once");
} elseif (_alphabet.empty()) {
LIBSEMIGROUPS_EXCEPTION( "no alphabet has been defined, define an alphabet first");
} elseif (!_identity_defined) {
LIBSEMIGROUPS_EXCEPTION( "no identity has been defined, define an identity first");
} elseif (_alphabet.size() != inv.size()) {
LIBSEMIGROUPS_EXCEPTION("invalid inverses, expected "
+ detail::to_string(_alphabet.size())
+ " but found " + detail::to_string(inv.size()));
}
// Checks the inv consists of valid letters in the alphabet
validate_word(inv);
std::string cpy = inv;
std::sort(cpy.begin(), cpy.end()); for (auto it = cpy.cbegin(); it < cpy.cend() - 1; ++it) { if (*it == *(it + 1)) {
LIBSEMIGROUPS_EXCEPTION( "invalid inverses, it contains the duplicate letter "
+ detail::to_string(*it));
}
}
// Check that (x ^ - 1) ^ -1 = x for (size_t i = 0; i < _alphabet.size(); ++i) { if (_alphabet[i] == identity()[0] && inv[i] != identity()[0]) {
LIBSEMIGROUPS_EXCEPTION( "invalid inverses, the identity is %c, but %c ^ -1 = %c",
_alphabet[i],
_alphabet[i],
inv[i]);
} for (size_t j = 0; j < _alphabet.size(); ++j) { if (_alphabet[j] == inv[i]) { if (inv[j] != _alphabet[i]) {
LIBSEMIGROUPS_EXCEPTION( "invalid inverses, %c ^ -1 = %c but %c ^ -1 = %c",
_alphabet[i],
inv[i],
inv[i],
inv[j]);
} break;
}
}
}
_inverses = inv;
for (size_t i = 0; i < _alphabet.size(); ++i) { if (_alphabet[i] != identity()[0]) {
add_rule(std::string(1, _alphabet[i]) + _inverses[i], _identity);
}
}
}
std::string const& FpSemigroupInterface::inverses() const { if (!_inverses.empty()) { return _inverses;
} else {
LIBSEMIGROUPS_EXCEPTION("no inverses have been defined");
}
}
word_type FpSemigroupInterface::string_to_word(std::string const& s) const {
word_type w;
w.reserve(s.size()); for (charconst& c : s) {
w.push_back(char_to_uint(c));
} return w;
}
bool FpSemigroupInterface::is_obviously_infinite() {
REPORT_DEFAULT("checking if the semigroup is obviously infinite . . .\n"); // If has_parent_froidure_pin(), then that is either finite (and so this // is not obviously infinite), or infinite, which is undecidable in // general, so we leave the answer to this question to // is_quotient_obviously_infinite_impl in the derived class. if (alphabet().empty()) { // If number_of_generators() is undefined, then there is no quotient yet, // and so it is not obviously infinite, or anything!
REPORT_VERBOSE_DEFAULT("not obviously infinite (no alphabet defined)\n"); returnfalse;
} elseif (has_froidure_pin() && froidure_pin()->finished()) { // If the isomorphic FroidurePin is fully enumerated, it must be // finite, and hence this is not (obviously) infinite.
REPORT_VERBOSE_DEFAULT("not obviously infinite (finite)\n"); returnfalse;
} elseif (is_obviously_infinite_impl()) { // The derived class of FpSemigroupInterface knows the quotient is // infinite returntrue;
} returnfalse;
}
bool FpSemigroupInterface::is_obviously_finite() { if (alphabet().empty()) { // If the alphabet is empty, then so is the fp semigrorup and so it is // obviously finite.
REPORT_VERBOSE_DEFAULT("obviously finite (no alphabet defined)\n"); returntrue;
} elseif (has_froidure_pin() && froidure_pin()->finished()) { // If the isomorphic FroidurePin is fully enumerated, it must be // finite, and hence this is (obviously) finite.
REPORT_VERBOSE_DEFAULT("obviously finite (finite)\n"); returntrue;
} elseif (is_obviously_finite_impl()) { // The derived class of FpSemigroupInterface knows it is // finite returntrue;
} returnfalse;
}
std::string FpSemigroupInterface::to_gap_string() { auto to_gap_word = [](std::string const& w) -> std::string { if (w.empty()) { return"One(free)";
}
std::string out; for (auto it = w.cbegin(); it < w.cend() - 1; ++it) {
out += to_human_readable(*it);
out += " * ";
}
out += to_human_readable(w.back()); return out;
};
std::string out = "free := FreeMonoid("; for (auto x : alphabet()) {
out += std::string("\"") + to_human_readable(x) + "\""; if (x != alphabet().back()) {
out += ", ";
}
}
out += ");\n";
out += "AssignGeneratorVariables(free);\n";
out += "rules := [\n"; for (auto it = cbegin_rules(); it < cend_rules(); ++it) {
out += " [";
out += to_gap_word(it->first);
out += ", ";
out += to_gap_word(it->second); if (it != cend_rules() - 1) {
out += "],\n";
} else {
out += "]\n";
}
}
out += " ];\n";
out += "S := free / rules;\n"; return out;
}
////////////////////////////////////////////////////////////////////////////// // FpSemigroupInterface - non-virtual member functions - protected //////////////////////////////////////////////////////////////////////////////
void FpSemigroupInterface::validate_letter(char c) const { if (_alphabet.empty()) {
LIBSEMIGROUPS_EXCEPTION("no alphabet has been defined");
} elseif (_alphabet_map.find(c) == _alphabet_map.end()) {
LIBSEMIGROUPS_EXCEPTION( "invalid letter %c, valid letters are \"%s\"", c, _alphabet.c_str());
}
}
void FpSemigroupInterface::validate_letter(letter_type c) const { if (_alphabet.empty()) {
LIBSEMIGROUPS_EXCEPTION("no alphabet has been defined");
} elseif (c >= _alphabet.size()) {
LIBSEMIGROUPS_EXCEPTION( "invalid letter %d, the valid range is [0, %d)", c, _alphabet.size());
}
}
void FpSemigroupInterface::validate_word_impl(std::string const& w) const { if (w.empty()) {
LIBSEMIGROUPS_EXCEPTION("invalid word, found the empty word but " "words must be non-empty");
}
}
void FpSemigroupInterface::validate_word_impl(word_type const& w) const { if (w.empty()) {
LIBSEMIGROUPS_EXCEPTION("invalid word, found the empty word but " "words must be non-empty");
}
}
void FpSemigroupInterface::add_rule_private(std::string&& u,
std::string&& v) { if (started()) {
LIBSEMIGROUPS_EXCEPTION("cannot add further rules at this stage"); // Note that there is actually nothing that prevents us from adding // rules to KnuthBendix (i.e. it is setup so that it can be run // (partially or fully) and then more rules can be added and everything // is valid. We add this restriction to simplify things in the first // instance.
}
validate_word(u);
validate_word(v); if (u == v) { return;
}
_rules.emplace_back(u, v);
add_rule_impl(_rules.back().first, _rules.back().second);
reset();
}
} // namespace libsemigroups
¤ Dauer der Verarbeitung: 0.18 Sekunden
(vorverarbeitet)
¤
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.