From 0f92d103b6dd63066f21837e8b47cf05a24ef91e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rajmund=20Hru=C5=A1ka?= <rajmund.hruska@gmail.com> Date: Wed, 29 Apr 2020 00:25:33 +0200 Subject: [PATCH] algo: covers: Add approximate enhaced covers --- .../ApproximateEnhancedCoversComputation.cpp | 6 + .../ApproximateEnhancedCoversComputation.h | 123 ++++++++++++++++++ ...proximateEnhancedCoversComputationTest.cpp | 76 +++++++++++ 3 files changed, 205 insertions(+) create mode 100644 alib2algo/src/stringology/cover/ApproximateEnhancedCoversComputation.cpp create mode 100644 alib2algo/src/stringology/cover/ApproximateEnhancedCoversComputation.h create mode 100644 alib2algo/test-src/stringology/cover/ApproximateEnhancedCoversComputationTest.cpp diff --git a/alib2algo/src/stringology/cover/ApproximateEnhancedCoversComputation.cpp b/alib2algo/src/stringology/cover/ApproximateEnhancedCoversComputation.cpp new file mode 100644 index 0000000000..1789326202 --- /dev/null +++ b/alib2algo/src/stringology/cover/ApproximateEnhancedCoversComputation.cpp @@ -0,0 +1,6 @@ +#include "ApproximateEnhancedCoversComputation.h" +#include <registration/AlgoRegistration.hpp> + +namespace stringology::cover { +auto ApproximateEnhancedCoversString = registration::AbstractRegister < ApproximateEnhancedCoversComputation, ext::set < string::LinearString < DefaultSymbolType > >, const string::LinearString < > &, unsigned > ( ApproximateEnhancedCoversComputation::compute ); +} /* namespace stringology::cover */ diff --git a/alib2algo/src/stringology/cover/ApproximateEnhancedCoversComputation.h b/alib2algo/src/stringology/cover/ApproximateEnhancedCoversComputation.h new file mode 100644 index 0000000000..cde4310e11 --- /dev/null +++ b/alib2algo/src/stringology/cover/ApproximateEnhancedCoversComputation.h @@ -0,0 +1,123 @@ +#ifndef APPROXIMATE_ENHANCED_COVERS_COMPUTATION_H +#define APPROXIMATE_ENHANCED_COVERS_COMPUTATION_H + +#include <alib/set> +#include <string/LinearString.h> + +namespace stringology::cover { + +struct Element { + unsigned depth, level; + Element ( ) = default; + Element ( unsigned d, unsigned l ) : depth ( d ), level ( l ) { } +}; + +struct State { + unsigned depth; + ext::vector < Element > elements; +}; + +class ApproximateEnhancedCoversComputation { +private: + static unsigned distEnhCov ( State const * q ); + template < class SymbolType > + static State * constrFirstState ( const string::LinearString < SymbolType > & x, unsigned k ); + template < class SymbolType > + static State * constrNextState ( const string::LinearString < SymbolType > & x, State const * previousState, unsigned k ); + template < class SymbolType > + static void updateEnhCov ( State const * state, const string::LinearString < SymbolType > & x, ext::set < string::LinearString < SymbolType > > & enhCovers, unsigned & h ); + +public: + template < class SymbolType > + static ext::set < string::LinearString < SymbolType > > compute ( const string::LinearString < SymbolType > & x, unsigned k ); +}; + +template < class SymbolType > +ext::set < string::LinearString < SymbolType > > ApproximateEnhancedCoversComputation::compute ( const string::LinearString < SymbolType > & x, unsigned k ) { + ext::set < string::LinearString < SymbolType > > result; + unsigned h = 0; + State * previousState = constrFirstState ( x, k ); + State * nextState = nullptr; + + for ( size_t i = 2; i < x.getContent ( ).size ( ); ++i ) { + nextState = constrNextState ( x, previousState, k ); + + if ( nextState->elements.size ( ) < 2 ) + break; + + delete previousState; + Element lastElement = nextState->elements[nextState->elements.size ( ) - 1]; + + if ( ( lastElement.depth == x.getContent ( ).size ( ) ) && ( lastElement.level == 0 ) && ( nextState->depth > k ) ) + updateEnhCov ( nextState, x, result, h ); + + previousState = nextState; + } + + delete previousState; + return result; +} + +unsigned ApproximateEnhancedCoversComputation::distEnhCov ( State const * q ) { + unsigned r = 0; + unsigned m = q->elements[0].depth; + + for ( size_t i = 2; i < q->elements.size ( ); ++i ) { + if ( q->elements[i].depth - q->elements[i - 1].depth < m ) + r += q->elements[i].depth - q->elements[i - 1].depth; + else + r += m; + } + + return r; +} + +template < class SymbolType > +State * ApproximateEnhancedCoversComputation::constrFirstState ( const string::LinearString < SymbolType > & x, unsigned k ) { + auto * firstState = new State ( ); + + firstState->depth = 1; + + for ( size_t i = 0; i < x.getContent ( ).size ( ); ++i ) { + if ( x.getContent ( )[0] == x.getContent ( )[i] ) + firstState->elements.push_back ( Element ( i + 1, 0 ) ); + else if ( k > 0 ) + firstState->elements.push_back ( Element ( i + 1, 1 ) ); + } + + return firstState; +} + +template < class SymbolType > +State * ApproximateEnhancedCoversComputation::constrNextState ( const string::LinearString < SymbolType > & x, State const * previousState, unsigned k ) { + auto * nextState = new State ( ); + + nextState->depth = previousState->depth + 1; + + for ( const auto & element : previousState->elements ) + if ( element.depth < x.getContent ( ).size ( ) ) { + if ( x.getContent ( )[previousState->depth] == x.getContent ( )[element.depth] ) + nextState->elements.push_back ( Element ( element.depth + 1, element.level ) ); + else if ( element.level < k ) + nextState->elements.push_back ( Element ( element.depth + 1, element.level + 1 ) ); + } + + return nextState; +} + +template < class SymbolType > +void ApproximateEnhancedCoversComputation::updateEnhCov ( State const * state, const string::LinearString < SymbolType > & x, ext::set < string::LinearString < SymbolType > > & enhCovers, unsigned & h ) { + unsigned hNext = distEnhCov ( state ); + string::LinearString u ( ext::vector < SymbolType > ( x.getContent ( ).begin ( ), x.getContent ( ).begin ( ) + state->depth ) ); + + if ( hNext > h ) { + h = hNext; + enhCovers.clear ( ); + } + + if ( hNext == h ) + enhCovers.insert ( u ); +} + +} /* namespace stringology::cover */ +#endif /* APPROXIMATE_ENHANCED_COVERS_COMPUTATION_H */ diff --git a/alib2algo/test-src/stringology/cover/ApproximateEnhancedCoversComputationTest.cpp b/alib2algo/test-src/stringology/cover/ApproximateEnhancedCoversComputationTest.cpp new file mode 100644 index 0000000000..23deeccda4 --- /dev/null +++ b/alib2algo/test-src/stringology/cover/ApproximateEnhancedCoversComputationTest.cpp @@ -0,0 +1,76 @@ +// + +// Created by hruskraj on 28. 4. 2020 +// + +#include <catch2/catch.hpp> + +#include <alib/set> +#include <string/LinearString.h> +#include <stringology/cover/ApproximateEnhancedCoversComputation.h> + +TEST_CASE ( "Approximate Enhanced Covers", "[unit][stringology][cover]" ) { + SECTION ( "Test 1" ) { + string::LinearString < char > pattern ( "abacaccababa" ); + unsigned int k = 1; + + ext::set < string::LinearString < char > > refSet; + string::LinearString < char > a1 ( "aba" ); + + refSet.insert ( a1 ); + + ext::set < string::LinearString < char > > result = stringology::cover::ApproximateEnhancedCoversComputation::compute ( pattern, k ); + + CHECK ( result == refSet ); + } + + SECTION ( "Test 2" ) { + string::LinearString < char > pattern ( "" ); + unsigned int k = 1; + + ext::set < string::LinearString < char > > result = stringology::cover::ApproximateEnhancedCoversComputation::compute ( pattern, k ); + + CHECK ( result.empty ( ) ); + } + + SECTION ( "Test 3" ) { + string::LinearString < char > pattern ( "abcd" ); + unsigned int k = 1; + + ext::set < string::LinearString < char > > result = stringology::cover::ApproximateEnhancedCoversComputation::compute ( pattern, k ); + + CHECK ( result.empty ( ) ); + } + + SECTION ( "Test 4" ) { + string::LinearString < char > pattern ( "adesgvsade" ); + unsigned int k = 4; + + ext::set < string::LinearString < char > > result = stringology::cover::ApproximateEnhancedCoversComputation::compute ( pattern, k ); + + CHECK ( result.empty ( ) ); + } + + SECTION ( "Test 5" ) { + string::LinearString < char > pattern ( "abcdefghabcd" ); + unsigned int k = 3; + + ext::set < string::LinearString < char > > refSet; + string::LinearString < char > a1 ( "abcd" ); + + refSet.insert ( a1 ); + + ext::set < string::LinearString < char > > result = stringology::cover::ApproximateEnhancedCoversComputation::compute ( pattern, k ); + + CHECK ( result == refSet ); + } + + SECTION ( "Test 6" ) { + string::LinearString < char > pattern ( "a" ); + unsigned int k = 0; + + ext::set < string::LinearString < char > > result = stringology::cover::ApproximateEnhancedCoversComputation::compute ( pattern, k ); + + CHECK ( result.empty ( ) ); + } +} -- GitLab