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