From 2913e37824ab2041b1eae27edec093f45811c4f3 Mon Sep 17 00:00:00 2001 From: James Swift Date: Sun, 23 Jun 2019 18:05:38 +0100 Subject: [PATCH] 1.3 Arbitrary alphabet size support asalib now supports arbilitrarily large alphabet sizes, while preserving multithreaded capability. New classes include types::word to represent words, rather than std::string, and types::parihkVector has been upgraded to support arbitrary alphabet sizes. --- Analysis/analysis_main.cpp | 19 ++-- Morphism/morphism_main.cpp | 16 ++- SingleWord/singleword_main.cpp | 10 +- asalib/asalib.vcxproj | 4 + asalib/private/asalib.cpp | 2 +- asalib/private/prefix.cpp | 72 ++++++------ asalib/private/word.cpp | 150 +++++++------------------ asalib/public/library.h | 23 +++- asalib/public/morphism.hpp | 4 +- asalib/public/prefix.hpp | 9 +- asalib/public/types.hpp | 199 +++++++++++++++++++-------------- 11 files changed, 248 insertions(+), 260 deletions(-) diff --git a/Analysis/analysis_main.cpp b/Analysis/analysis_main.cpp index 876857a..063e772 100644 --- a/Analysis/analysis_main.cpp +++ b/Analysis/analysis_main.cpp @@ -12,10 +12,7 @@ #include #include -using json = nlohmann::json; -using namespace AbelianSquaresAnalysis::morphism; -using namespace AbelianSquaresAnalysis::prefix; -using namespace AbelianSquaresAnalysis::utility; +using namespace AbelianSquaresAnalysis; #define asalib_VERBOSE(v,...) if (v) printf(##__VA_ARGS__) @@ -41,27 +38,27 @@ int main(int argc, char* argv[]) { // Load input from json asalib_VERBOSE(verboseOption, "Loading into program from file \"%s\"\n", input_file.c_str()); - morphismOutput input_cpp = LoadClassFromFile(input_file); + morphism::morphismOutput input_cpp = utility::LoadClassFromFile(input_file); // Analyse prefix asalib_VERBOSE(verboseOption, "Analysing prefix . . .\n"); - prefixAnalysisOutput analysisOutput(input_cpp); - AnalysePrefix(analysisOutput.generatedPrefix, analysisOutput); + prefix::prefixAnalysisOutput analysisOutput(input_cpp); + prefix::AnalysePrefix(analysisOutput.generatedPrefix, analysisOutput); asalib_VERBOSE(verboseOption, "Analysis complete!\n"); // Prepare output directory asalib_VERBOSE(verboseOption, "Preparing output directory\n"); - std::string parent_directory = GetParentDirectory(input_file); + std::string parent_directory = utility::GetParentDirectory(input_file); if (outputRelativityOption) { asalib_VERBOSE(verboseOption, "Output is relative to executable\n"); - parent_directory = CurrentExecutablePath(); + parent_directory = utility::CurrentExecutablePath(); } - std::string outputDirectory = PrepareSubdirectory(parent_directory, output_directory); + std::string outputDirectory = utility::PrepareSubdirectory(parent_directory, output_directory); // Output to file std::string file_location = outputDirectory + "\\" + analysisOutput.input.morphismName + analysisOutput.input.startWord + ".json"; printf("Generating output file \"%s\"\n", file_location.c_str()); - SaveClassToFile(file_location, analysisOutput); + utility::SaveClassToFile(file_location, analysisOutput); asalib_VERBOSE(verboseOption, "Program completed successfull\n"); asalib_wait_debug(); diff --git a/Morphism/morphism_main.cpp b/Morphism/morphism_main.cpp index 4b9d4d2..15932fc 100644 --- a/Morphism/morphism_main.cpp +++ b/Morphism/morphism_main.cpp @@ -12,9 +12,7 @@ #include #include -using json = nlohmann::json; -using namespace AbelianSquaresAnalysis::morphism; -using namespace AbelianSquaresAnalysis::utility; +using namespace AbelianSquaresAnalysis; #define asalib_VERBOSE(v,...) if (v) printf(##__VA_ARGS__) @@ -41,11 +39,11 @@ int main(int argc, char* argv[]) { // Load input from json asalib_VERBOSE(verboseOption, "Loading into program from file \"%s\"\n", input_file.c_str()); - morphismInput input_cpp = LoadClassFromFile(input_file); + morphism::morphismInput input_cpp = utility::LoadClassFromFile(input_file); // Run morphism! asalib_VERBOSE(verboseOption, "Running morphisms . . .\n"); - std::vector output = RunMorphisms(input_cpp); + std::vector output = morphism::RunMorphisms(input_cpp); #ifdef _WIN64 asalib_VERBOSE(verboseOption, "%llu morphisms iterated\n", output.size()); #else @@ -54,12 +52,12 @@ int main(int argc, char* argv[]) { // Prepare output directory asalib_VERBOSE(verboseOption, "Preparing output directory\n"); - std::string parent_directory = GetParentDirectory(input_file); + std::string parent_directory = utility::GetParentDirectory(input_file); if (outputRelativityOption) { asalib_VERBOSE(verboseOption, "Output is relative to executable\n"); - parent_directory = CurrentExecutablePath(); + parent_directory = utility::CurrentExecutablePath(); } - std::string outputDirectory = PrepareSubdirectory(parent_directory, output_directory); + std::string outputDirectory = utility::PrepareSubdirectory(parent_directory, output_directory); // for each generated prefix for (const auto& output_entry : output) { @@ -67,7 +65,7 @@ int main(int argc, char* argv[]) { // Output to file std::string file_location = outputDirectory + "\\" + output_entry.input.morphismName + output_entry.input.startWord + ".out"; asalib_VERBOSE(verboseOption, "Generating output file \"%s\"\n", file_location.c_str()); - SaveClassToFile(file_location, output_entry); + utility::SaveClassToFile(file_location, output_entry); } diff --git a/SingleWord/singleword_main.cpp b/SingleWord/singleword_main.cpp index 6d193c1..cc7b6ac 100644 --- a/SingleWord/singleword_main.cpp +++ b/SingleWord/singleword_main.cpp @@ -7,11 +7,11 @@ #include #include +#include #include #include #include -using json = nlohmann::json; using namespace AbelianSquaresAnalysis; #define asalib_VERBOSE(v,...) if (v) printf(##__VA_ARGS__) @@ -20,18 +20,18 @@ using namespace AbelianSquaresAnalysis; #define asalib_singleword_dictionary_found "\tFound %llu " #define asalib_singleword_dictionary_ofwhich "\t\tOf which %llu trivial and %llu non-trivial.\n" #define asalib_singleword_dictionary_detailedinformation "\t\tOutputing detailed information:\n" -#define asalib_singleword_dictionary_detail "\t\t\t\"%s\" at position %zu, (%llu,%llu)\n" +#define asalib_singleword_dictionary_detail "\t\t\t\"%s\" at position %zu, %s\n" #else #define asalib_singleword_dictionary_found "\tFound %lu " #define asalib_singleword_dictionary_ofwhich "\t\tOf which %lu trivial and %lu non-trivial.\n" #define asalib_singleword_dictionary_detailedinformation "\t\tOutputing detailed information on total squares:\n" -#define asalib_singleword_dictionary_detailed "\t\t\t\"%s\" at position %zu, (%lu,%lu)\n" +#define asalib_singleword_dictionary_detail "\t\t\t\"%s\" at position %zu, %s\n" #endif inline void PrintDetailedInformationOnType(prefix::prefixAnalysisOutputSquareType& typeOutput) { printf(asalib_singleword_dictionary_detailedinformation); - for (const auto& square : typeOutput.list) { - printf(asalib_singleword_dictionary_detail, square.word.c_str(), square.position, square.vector.a, square.vector.b); + for (auto& square : typeOutput.list) { + printf(asalib_singleword_dictionary_detail, square.word.c_str(), square.position, ((std::string)square.vector).c_str()); } } diff --git a/asalib/asalib.vcxproj b/asalib/asalib.vcxproj index 48237f8..5fd1ac1 100644 --- a/asalib/asalib.vcxproj +++ b/asalib/asalib.vcxproj @@ -107,6 +107,7 @@ stdcpplatest false Speed + Fast Windows @@ -125,6 +126,7 @@ true stdcpplatest false + Fast Windows @@ -141,6 +143,7 @@ true stdcpplatest false + Fast Windows @@ -160,6 +163,7 @@ stdcpplatest false Speed + Fast Windows diff --git a/asalib/private/asalib.cpp b/asalib/private/asalib.cpp index 2aad882..25ae0f3 100644 --- a/asalib/private/asalib.cpp +++ b/asalib/private/asalib.cpp @@ -5,4 +5,4 @@ #include -asalib const char* AbelianSquaresAnalysis::BUILD = __TIMESTAMP__; +asalib const char* AbelianSquaresAnalysis::BUILD = "1.3"; diff --git a/asalib/private/prefix.cpp b/asalib/private/prefix.cpp index b1b991a..b243861 100644 --- a/asalib/private/prefix.cpp +++ b/asalib/private/prefix.cpp @@ -10,18 +10,28 @@ #include #include +#define asalib_prefix_MULTITHREAD + using namespace AbelianSquaresAnalysis; +asalib AbelianSquaresAnalysis::prefix::substringAnalysisOutput::substringAnalysisOutput() + : vector() +{ +} + +asalib AbelianSquaresAnalysis::prefix::substringAnalysisOutput::substringAnalysisOutput(const prefix::substringAnalysisInput& base) + : prefix::substringAnalysisInput(base), vector() +{ +} + asalib AbelianSquaresAnalysis::prefix::prefixAnalysisOutput::prefixAnalysisOutput(const morphism::morphismOutput& base) : morphism::morphismOutput(base) { - // Copy construct prefixAnalysisOutput } asalib AbelianSquaresAnalysis::prefix::prefixAnalysisOutput::prefixAnalysisOutput(const morphism::morphismOutput& base, const prefix::AnalysePrefixOutput& base2) : morphism::morphismOutput(base), prefix::AnalysePrefixOutput(base2) { - // Copy construct prefixAnalysisOutput } #define asalib_prefixanalysis_output_category(name, info)\ @@ -40,14 +50,14 @@ void asalib AbelianSquaresAnalysis::prefix::to_json(nlohmann::json& j, const pre {"success", data.morphismSuccess}, {"startWord", data.input.startWord}, {"lengthBound", data.input.lengthBound}, - {"generatedPrefix", data.generatedPrefix}, + {"generatedPrefix",data.generatedPrefix}, {"generatedPrefixLength", data.generatedPrefixLength}, {"generatedPrefixRuns", data.runs}, {"prefixAnalysis",{ asalib_prefixanalysis_output_category("totalSquares", data.total), asalib_prefixanalysis_output_category("distinctSquares", data.distinct), asalib_prefixanalysis_output_category("nonequivalentSquares", data.nonequivalent), - {"totalN_less_than_length_over_four", (data.nonequivalent.trivial + data.nonequivalent.nontrivial) < floor(data.generatedPrefixLength / 4)} + {"totalN_less_than_length_over_four", ((long)data.nonequivalent.trivial + (long)data.nonequivalent.nontrivial) < floor((long)data.generatedPrefixLength / 4)} }} }; } @@ -57,7 +67,7 @@ void asalib AbelianSquaresAnalysis::prefix::to_json(nlohmann::json& j, const pre prefix::substringAnalysisOutput asalib AbelianSquaresAnalysis::prefix::AnalyseSubstring(substringAnalysisInput input) { // Setup return information - prefix::substringAnalysisOutput output; + prefix::substringAnalysisOutput output = (prefix::substringAnalysisOutput) input; // odd length substrings are not squares if (input.word.length() % 2 != 0) { @@ -65,32 +75,17 @@ prefix::substringAnalysisOutput asalib AbelianSquaresAnalysis::prefix::AnalyseSu } // Count first half - types::parihkVector firstHalf; - std::string firstHalfSubString = input.word.substr(0, input.length / 2); - firstHalf.a = asalib_prefix_substringanalysis_count_occurence(firstHalfSubString, 'a'); - firstHalf.b = asalib_prefix_substringanalysis_count_occurence(firstHalfSubString, 'b'); - //types::parihkVector firstHalf = substring.substr(0, substring.length() / 2).countOccurences(); + types::parihkVector firstHalf = input.alphabet; // copy construct + input.word.countOccurences(0, input.length / 2, firstHalf); // Count second half - types::parihkVector secondHalf; - std::string secondHalfSubString = input.word.substr(input.length / 2, std::string::npos); - secondHalf.a = asalib_prefix_substringanalysis_count_occurence(secondHalfSubString, 'a'); - secondHalf.b = asalib_prefix_substringanalysis_count_occurence(secondHalfSubString, 'b'); - //types::parihkVector secondHalf = substring.substr(substring.length() / 2).countOccurences(); - - // substring is square if vectors for each side are equal - if (firstHalf.a == secondHalf.a && firstHalf.b == secondHalf.b) { - output.isSquare = true; - output.vector.a = firstHalf.a; - output.vector.b = firstHalf.b; - - if (firstHalf.a == 0 || firstHalf.b == 0) { - output.isTrivial = true; - } + types::parihkVector secondHalf = input.alphabet; // copy construct + input.word.countOccurences(input.length / 2, std::string::npos, secondHalf); - output.word = input.word; - output.position = input.position; - output.length = input.length; + if (firstHalf == secondHalf) { + output.isSquare = true; + output.vector = firstHalf; + output.isTrivial = firstHalf.isTrivial(); } return output; @@ -106,10 +101,11 @@ prefix::prefixAnalysisOutput asalib AbelianSquaresAnalysis::prefix::AnalysePrefi void asalib AbelianSquaresAnalysis::prefix::AnalysePrefix(types::word input, prefix::AnalysePrefixOutput& output) { // Prepare thread pool +#ifdef asalib_prefix_MULTITHREAD AbelianSquaresAnalysis::ThreadPool pool; +#endif - // Sanitize input - std::transform(input.begin(), input.end(), input.begin(), ::tolower); + types::parihkVector alphabet = input.countAlphabetSize(); // For every even word length for (unsigned int len = 2; len <= input.length(); len += 2) { @@ -119,17 +115,26 @@ void asalib AbelianSquaresAnalysis::prefix::AnalysePrefix(types::word input, pre AnalysisInput.word = input.substr(pos, len); AnalysisInput.length = len; AnalysisInput.position = pos; + AnalysisInput.alphabet = alphabet; +#ifdef asalib_prefix_MULTITHREAD pool.AddTask(prefix::AnalyseSubstring, AnalysisInput); +#else + prefix::substringAnalysisOutput computation_output = prefix::AnalyseSubstring(AnalysisInput); + if (computation_output.isSquare) + output.total.list.push_back(computation_output); +#endif } } +#ifdef asalib_prefix_MULTITHREAD pool.WaitForTasks(); for (auto& computation_output : pool.GetResults()) { if (computation_output.isSquare) output.total.list.push_back(computation_output); } +#endif prefix::SquaresCountTrivials(output.total); @@ -160,15 +165,12 @@ bool asalib AbelianSquaresAnalysis::prefix::SquaresSortDistinctPredicate bool asalib AbelianSquaresAnalysis::prefix::SquaresComparisonNoneqPredicate (prefix::substringAnalysisOutput left, prefix::substringAnalysisOutput right) { - return (left.vector.a == right.vector.a && left.vector.b == right.vector.b); + return (left.vector == right.vector); } bool asalib AbelianSquaresAnalysis::prefix::SquaresSortNoneqPredicate (prefix::substringAnalysisOutput left, prefix::substringAnalysisOutput right) { - if (left.vector.a != right.vector.a) { - return left.vector.a > right.vector.a; - } - return left.vector.b > right.vector.b; + return (left.vector > right.vector); } asalib AbelianSquaresAnalysis::prefix::SquaresCategoriseInput::SquaresCategoriseInput(std::vector& in, std::vector& out): diff --git a/asalib/private/word.cpp b/asalib/private/word.cpp index 60b7b9b..7c1c7bc 100644 --- a/asalib/private/word.cpp +++ b/asalib/private/word.cpp @@ -1,123 +1,59 @@ -/*#include "types.hpp" +/// @file word.cpp +/// @author James R Swift +/// @date 23/06/2019 +/// @brief Implements common functionality word words and parihk vectors -using namespace AbelianSquaresAnalysis; +#include +#include -types::word::word(const char* s = "") { // constructor - initialize_c_str(s); -} - -types::word::word(const char* s = "", size_t length) { // constructor - initialize_c_str(s, length); -} - -types::word::word(const types::word& other) { // copy constructor - initialize_c_str(other._c_str); -} - -types::word::word(const std::string& other) : - word(other.c_str()) +AbelianSquaresAnalysis::types::parihkVector::parihkVector() + : std::map() { - -} - -types::word::~word() { //destructor - delete[] _c_str; -} - -void types::word::initialize_c_str(const char* s, size_t _length) { - _c_str = new char[_length]; - std::memcpy(_c_str, s, _length); -} - -void types::word::initialize_c_str(const char* s) { - _length = std::strlen(s) + 1; - _c_str = new char[_length]; - std::memcpy(_c_str, s, _length); -} - -types::length types::word::length() const { - return _length; -} - -types::word types::word::substr(types::length position) { - char* substring = _c_str + position; - return types::word(substring); -} - -types::word types::word::substr(types::length position, size_t length) { - char* substring = _c_str + position; - return types::word(substring, length); } -types::characterCount types::word::countOccurences() { - types::characterCount counter; - for (char character : *this) { - if (character = 'a') counter.a++; - if (character = 'b') counter.b++; +bool asalib AbelianSquaresAnalysis::types::parihkVector::isTrivial() const { + unsigned int count = 0; + for (const auto& entry : *this) { + if (entry.second == 0) count++; } - return counter; -} - -char types::word::at(size_t position) const { - return *(_c_str + position); // Beware of out of range! -} - -inline bool types::word::operator==(const types::word& right) const { - return strcmp(this->_c_str, right._c_str) == 0; -} - -inline bool types::word::operator!=(const types::word& right) const { - return strcmp(this->_c_str, right._c_str) != 0; -} -inline bool types::word::operator<(const types::word& right) const { - strcmp(this->_c_str, right._c_str) < 0; -} - -inline bool types::word::operator>(const types::word& right) const { - strcmp(this->_c_str, right._c_str) > 0; + return count == 1; // if a parihk vector of ([0,]*)^2 is tested, isTrivial returns false; } -inline bool types::word::operator<=(const types::word& right) const { - strcmp(this->_c_str, right._c_str) <= 0; +void asalib AbelianSquaresAnalysis::types::to_json(nlohmann::json& j, const AbelianSquaresAnalysis::types::parihkVector& data) { + j = (std::map)data; } -inline bool types::word::operator>=(const types::word& right) const { - strcmp(this->_c_str, right._c_str) >= 0; +void asalib AbelianSquaresAnalysis::types::from_json(const nlohmann::json& j, AbelianSquaresAnalysis::types::parihkVector& data) { + j.get_to>(data); } -inline types::word::operator std::string() { - return std::string(_c_str); +AbelianSquaresAnalysis::types::parihkVector asalib AbelianSquaresAnalysis::types::word::countAlphabetSize() { + types::parihkVector out; + for (auto character : *this) { + if (out.find(character) == out.end()) { + out.insert(std::pair(character, 0)); + } + } + return out; +} + +void AbelianSquaresAnalysis::types::word::countOccurences(size_t offset, size_t count, AbelianSquaresAnalysis::types::parihkVector& out) { + std::string substr = this->substr(offset, count); + for (const auto& character : substr) { + types::parihkVector::iterator it = out.find(character); + if (it != out.end()) { + it->second++; + } + else { + throw new std::exception("Attempt to count occurences into ill-formed parihk vector!"); + } + } } -inline types::word& types::word::operator=(const types::word& other) { // copy assingment - // IMPLEMENT +void asalib AbelianSquaresAnalysis::types::to_json(nlohmann::json& j, const AbelianSquaresAnalysis::types::word& data) { + j = (std::string)data; } -inline void types::word::iterator_state::next(const types::word* ref) { ++pos; } -inline void types::word::iterator_state::prev(const types::word* ref) { --pos; } -inline void types::word::iterator_state::begin(const types::word* ref) { pos = 0; } -inline void types::word::iterator_state::end(const types::word* ref) { pos = ref->length(); } -inline char& types::word::iterator_state::get(types::word* ref) { return ref->_c_str[pos]; } -inline const char& types::word::iterator_state::get(const types::word* ref) { return ref->_c_str[pos]; } -inline bool types::word::iterator_state::cmp(const types::word::iterator_state& s) const { return pos != s.pos; } - -types::word::iterator types::word::begin() { return types::word::iterator::begin(this); } -types::word::iterator types::word::end() { return types::word::iterator::end(this); } - -types::word::const_iterator types::word::begin() const { return types::word::const_iterator::begin(this); } -types::word::const_iterator types::word::end() const { return types::word::const_iterator::end(this); } - -inline void types::word::reverse_iterator_state::next(const types::word* ref) { types::word::iterator_state::prev(ref); } -inline void types::word::reverse_iterator_state::prev(const types::word* ref) { types::word::iterator_state::next(ref); } -inline void types::word::reverse_iterator_state::begin(const types::word* ref) { types::word::iterator_state::end(ref); types::word::iterator_state::prev(ref); } -inline void types::word::reverse_iterator_state::end(const types::word* ref) { types::word::iterator_state::begin(ref); types::word::iterator_state::prev(ref); } - -types::word::reverse_iterator types::word::rbegin() { return types::word::reverse_iterator::begin(this); } -types::word::reverse_iterator types::word::rend() { return types::word::reverse_iterator::end(this); } - -types::word::const_reverse_iterator types::word::rbegin() const { - return types::word::const_reverse_iterator::begin(this); -} -types::word::const_reverse_iterator types::word::rend() const { - return types::word::const_reverse_iterator::end(this); -}*/ \ No newline at end of file +void asalib AbelianSquaresAnalysis::types::from_json(const nlohmann::json& j, AbelianSquaresAnalysis::types::word& data) { + j.get_to(data); +} \ No newline at end of file diff --git a/asalib/public/library.h b/asalib/public/library.h index fc1e763..90ff65a 100644 --- a/asalib/public/library.h +++ b/asalib/public/library.h @@ -19,10 +19,29 @@ #define asalib_wait_debug() #endif +#if defined _WIN32 || defined __CYGWIN__ #ifdef ASALIB_COMPILE -#define asalib __declspec(dllexport) +#ifdef __GNUC__ +#define asalib __attribute__ ((dllexport)) #else -#define asalib __declspec(dllimport) +#define asalib __declspec(dllexport) +#endif +#else +#ifdef __GNUC__ +#define asalib __attribute__ ((dllimport)) +#else +#define asalib __declspec(dllimport) +#endif +#endif +#define asalib_local +#else +#if __GNUC__ >= 4 +#define asalib __attribute__ ((visibility ("default"))) +#define asalib_local __attribute__ ((visibility ("hidden"))) +#else +#define asalib +#define asalib_local +#endif #endif namespace AbelianSquaresAnalysis { diff --git a/asalib/public/morphism.hpp b/asalib/public/morphism.hpp index cc62420..8a22c8e 100644 --- a/asalib/public/morphism.hpp +++ b/asalib/public/morphism.hpp @@ -41,14 +41,14 @@ namespace AbelianSquaresAnalysis { std::string morphismName; ///< Name of the applied morphism. AbelianSquaresAnalysis::types::mapping morphism; ///< Mappings of applied morphism. AbelianSquaresAnalysis::types::word startWord; ///< Start word to which morphism was applied - AbelianSquaresAnalysis::types::length lengthBound; ///< Requested minimum length when generating prefix. + AbelianSquaresAnalysis::types::length lengthBound = 0; ///< Requested minimum length when generating prefix. } input; ///< Settings given to morphism iterator. struct morphismAnalysis { std::vector prolongable; ///< Vector of mappings which are prolongable. size_t k_uniform = 0; ///< k-uniformity of morphism, where 0 is no uniformity. } morphismAnalysis; ///< Results of analysis on morphism itself. AbelianSquaresAnalysis::types::word generatedPrefix; ///< Prefix generated from application of morphism onto startword for a number of iterations so as to provide a prefix of atleast lengthBound length. - size_t generatedPrefixLength; ///< Length of generated prefix. Equal or greater than lengthBound where morphismSuccess is true. + size_t generatedPrefixLength = 0; ///< Length of generated prefix. Equal or greater than lengthBound where morphismSuccess is true. AbelianSquaresAnalysis::types::length runs = 0; ///< Number of iterations required to achieve length greater of equal to lengthBound. }; diff --git a/asalib/public/prefix.hpp b/asalib/public/prefix.hpp index ff375d8..c948808 100644 --- a/asalib/public/prefix.hpp +++ b/asalib/public/prefix.hpp @@ -19,12 +19,17 @@ namespace AbelianSquaresAnalysis { /// @brief Input structure for AbelianSquaresAnalysis::prefix::AnalyseSubstring struct substringAnalysisInput { types::word word; ///< substring to analyse. - size_t length; ///< length of substring. - size_t position; ///< Start position of string in parent prefix. + size_t length = 0; ///< length of substring. + size_t position = 0; ///< Start position of string in parent prefix. + types::parihkVector alphabet; }; /// @brief Structure containing information for a substring of a prefix. This is currently only used internally. struct substringAnalysisOutput : public substringAnalysisInput { + + asalib substringAnalysisOutput(); + asalib substringAnalysisOutput(const substringAnalysisInput& base); + types::boolean isSquare = false; ///< If the substring is an abelian square. If false, other members may not be set. types::boolean isTrivial = false; ///< If the substring is a trivial abelian square. types::parihkVector vector; ///< Parihk vector of the abelian square. diff --git a/asalib/public/types.hpp b/asalib/public/types.hpp index 5ee22d0..9918ecc 100644 --- a/asalib/public/types.hpp +++ b/asalib/public/types.hpp @@ -4,110 +4,137 @@ /// @brief Common header for library, defining commonly used types. #pragma once +#include "library.h" #include #include - -//#include +#include namespace AbelianSquaresAnalysis { namespace types { - typedef bool boolean; ///< Internally used type for consistency between builds. - typedef std::string word; ///< Type containing words, substrings and prefixes. - typedef std::map mapping; ///< Type containing morphism information. - typedef std::map morphism_list; ///< Type containing a list of morphisms. + typedef unsigned int length; ///< Internally used type for consistency between builds. #ifdef _WIN64 - typedef unsigned int length; ///< Internally used type for consistency between builds. typedef unsigned long long int integer; ///< Internally used type for consistency between builds. #else - typedef unsigned int length; ///< Internally used type for consistency between builds. typedef unsigned long int integer; ///< Internally used type for consistency between builds. #endif - /// @brief Structure used to store information about a given substring, currently limited to alphabets of size 2. - /// @todo Allow greater alphabet sizes. - struct parihkVector { - types::integer a = 0; ///< Counter of instances of first alphabet letter. - types::integer b = 0; ///< Counter of instances of second alphabet letter. - }; + /// @brief Structure used to store information about a given substring, for arbitrary alphabet sizes. + class parihkVector : public std::map { + public: - //typedef std::map characterCount; - /*typedef parihkVector characterCount; + /// @brief Default constructor for parihkVector class + parihkVector(); + + /// @brief Builds the string representation of a parihk vector, used in detail output. + /// @return String representation of parihk vector. + inline operator std::string() { + bool first = true; + std::string output = "("; + for (const auto& entry : *this) { + if (!first) { + output += ", "; + } + output += std::to_string(entry.second); + first = false; + } + output += ")^2"; + return output; + } + + /// @brief Comparison function between two parihk vectors. Commutitive. + /// @param[in] other Other parihk vector with which to compare. + /// @return Are the two parihk vectors equal. + inline bool operator==(const types::parihkVector& other) const { + return this->size() == other.size() + && std::equal(this->begin(), this->end(), other.begin()) + && std::equal(other.begin(), other.end(), this->begin()); + } + + /// @brief Comparison function between two parihk vectors. Non-commutitive. + /// + /// This function is used in the sorting algorithm when finding non-equivalent squares. + /// This shouldn't be used generally. + /// @param[in] other Other parihk vector with which to compare. + /// @return bool Is the parihk vector greater than another. + inline bool operator>(const types::parihkVector& other) const { + for (const auto& entry : *this) { + auto it = other.find(entry.first); + if (it == other.end()) return true; + if (entry.second != other.at(entry.first)) { + return entry.second > other.at(entry.first); + } + } + return false; + } + + /// @brief Utility function for determining if the parihk vector denotes a trivial square. + /// @return Is the parihk vector one of a trivial square. + bool asalib isTrivial() const; + }; - class word { - private: - size_t _length = 0; - char* _c_str; - void initialize_c_str(const char* s); - void initialize_c_str(const char* s, size_t length); + /// @brief Function designed for use by nlohmann::json to convert AbelianSquaresAnalysis::types::parihkVector to JSON. + /// @param[out] j JSON object. + /// @param[in] data input AbelianSquaresAnalysis::types::parihkVector. + /// @see AbelianSquaresAnalysis::types::parihkVector. + void asalib to_json(nlohmann::json& j, const types::parihkVector& data); + + /// @brief Function designed for use by nlohmann::json to convert AbelianSquaresAnalysis::types::parihkVector from JSON. + /// @param[in] j JSON object. + /// @param[out] data input AbelianSquaresAnalysis::types::parihkVector. + /// @see AbelianSquaresAnalysis::types::parihkVector. + void asalib from_json(const nlohmann::json& j, types::parihkVector& data); + + /// @brief Class extension of std::string to represent words internally. + /// + /// This class implements several utility functions in order to simplify algorithms. + class word : public std::string { public: - word(const char* s = ""); - word(const char* s, size_t length); - word(const types::word& other); // copy constructor - word(const std::string& other); - ~word(); - - types::length length() const; - types::word substr(types::length position); - types::word substr(types::length position, size_t length); - types::characterCount countOccurences(); - char at(size_t position) const; - - inline bool operator==(const types::word& right) const; - inline bool operator!=(const types::word& right) const; - inline bool operator<(const types::word& right) const; - inline bool operator>(const types::word& right) const; - inline bool operator<=(const types::word& right) const; - inline bool operator>=(const types::word& right) const; - - inline operator std::string(); - - inline types::word& operator=(const types::word& other); // coppy assingment - - STL_TYPEDEFS(char); - - struct iterator_state { - int pos; - inline void next(const types::word* ref); - inline void prev(const types::word* ref); - inline void begin(const types::word* ref); - inline void end(const types::word* ref); - inline char& get(types::word* ref); - inline const char& get(const types::word* ref); - inline bool cmp(const iterator_state& s) const; - }; - - // Mutable Iterator: - typedef iterator_tpl::iterator iterator; - iterator begin(); - iterator end(); - - // Const Iterator: - typedef iterator_tpl::const_iterator const_iterator; - const_iterator begin() const; - const_iterator end() const; - - // Reverse `iterator_state`: - struct reverse_iterator_state : public iterator_state { - inline void next(const types::word* ref); - inline void prev(const types::word* ref); - inline void begin(const types::word* ref); - inline void end(const types::word* ref); - }; - - // Mutable Reverse Iterator: - typedef iterator_tpl::iterator reverse_iterator; - reverse_iterator rbegin(); - reverse_iterator rend(); - - // Const Reverse Iterator: - typedef iterator_tpl::const_iterator const_reverse_iterator; - const_reverse_iterator rbegin() const; - const_reverse_iterator rend() const; - };*/ + /// @brief Default constructor for types::word class + inline word() : word("") {} + + /// @brief Constructor of types:word class with initial string value. + /// + /// This function sanitizes the input to reduce algorithm cost later. + /// @param[in] in Initial value that types::word class holds. + inline word(std::string in): std::string(in) + { + std::transform(this->begin(), this->end(), this->begin(), ::tolower); + } + + /// @brief Counts the number of different characters in a word, and constructs a copyable parihkVector + /// representing said alphabet. + /// @return empty parihk vector representing alphabet size. + types::parihkVector asalib countAlphabetSize(); + + /// @brief Counts the occurence of different characters in word for a given alphabet. + /// @warning When analyzing substrings of a greater word, the input parihk vector must be a copy construct parihk vector of the alphabet over the parent word! + /// @param[in] offset start point of occurences count. + /// @param[in] count number of positions to check. + /// @param[in/out] out Modified alphabet parihk vector counting occurences of given characters. + void countOccurences(size_t offset, size_t count, types::parihkVector& out); + }; + + /// @brief Function designed for use by nlohmann::json to convert AbelianSquaresAnalysis::types::word to JSON. + /// @param[out] j JSON object. + /// @param[in] data input AbelianSquaresAnalysis::types::word. + /// @see AbelianSquaresAnalysis::types::word. + void asalib to_json(nlohmann::json& j, const types::word& data); + + /// @brief Function designed for use by nlohmann::json to convert AbelianSquaresAnalysis::types::word from JSON. + /// @param[in] j JSON object. + /// @param[out] data input AbelianSquaresAnalysis::types::word. + /// @see AbelianSquaresAnalysis::types::word. + void asalib from_json(const nlohmann::json& j, types::word& data); + + typedef bool boolean; ///< Internally used type for consistency between builds. + typedef std::map mapping; ///< Type containing morphism information. + typedef std::map morphism_list; ///< Type containing a list of morphisms. + + } } \ No newline at end of file