From c41214cc037b373da7ebcc1214d1f61ebcc4118c Mon Sep 17 00:00:00 2001
From: Tomas Pecka <tomas.pecka@fit.cvut.cz>
Date: Thu, 10 Oct 2019 16:21:28 +0200
Subject: [PATCH] Tree Border Array - quadratic time solution

---
 alib2algo/src/tree/properties/BorderArray.cpp | 18 ++++
 alib2algo/src/tree/properties/BorderArray.h   | 83 +++++++++++++++++++
 .../test-src/tests/borderArrayTest.cpp        | 54 ++++++++++++
 3 files changed, 155 insertions(+)
 create mode 100644 alib2algo/src/tree/properties/BorderArray.cpp
 create mode 100644 alib2algo/src/tree/properties/BorderArray.h
 create mode 100644 alib2integrationtest/test-src/tests/borderArrayTest.cpp

diff --git a/alib2algo/src/tree/properties/BorderArray.cpp b/alib2algo/src/tree/properties/BorderArray.cpp
new file mode 100644
index 0000000000..7ac7f17c54
--- /dev/null
+++ b/alib2algo/src/tree/properties/BorderArray.cpp
@@ -0,0 +1,18 @@
+/*
+ * BorderArray.cpp
+ *
+ *  Created on: 4. 10. 2019
+ *      Author: Tomas Pecka, Jan Travnicek
+ */
+
+#include "BorderArray.h"
+#include <registration/AlgoRegistration.hpp>
+
+namespace {
+
+auto BorderArrayPrefixRankedBarNonlinearPattern = registration::AbstractRegister < tree::properties::BorderArray, ext::vector < size_t >, const tree::PrefixRankedBarNonlinearPattern < > & > ( tree::properties::BorderArray::construct );
+auto BorderArrayPrefixRankedBarPattern          = registration::AbstractRegister < tree::properties::BorderArray, ext::vector < size_t >, const tree::PrefixRankedBarPattern < > & >          ( tree::properties::BorderArray::construct );
+auto BorderArrayPrefixRankedNonlinearPattern    = registration::AbstractRegister < tree::properties::BorderArray, ext::vector < size_t >, const tree::PrefixRankedNonlinearPattern < > & >    ( tree::properties::BorderArray::construct );
+auto BorderArrayPrefixRankedPattern             = registration::AbstractRegister < tree::properties::BorderArray, ext::vector < size_t >, const tree::PrefixRankedPattern < > & >             ( tree::properties::BorderArray::construct );
+
+} /* namespace */
diff --git a/alib2algo/src/tree/properties/BorderArray.h b/alib2algo/src/tree/properties/BorderArray.h
new file mode 100644
index 0000000000..35cc993ddc
--- /dev/null
+++ b/alib2algo/src/tree/properties/BorderArray.h
@@ -0,0 +1,83 @@
+/*
+ * BorderArray.cpp
+ *
+ *  Created on: 4. 10. 2019
+ *      Author: Tomas Pecka, Jan Travnicek
+ */
+
+#ifndef _ARBOLOGY_BORDER_ARRAY_H_
+#define _ARBOLOGY_BORDER_ARRAY_H_
+
+#include <cstdlib>
+
+#include <alib/vector>
+
+#include <global/GlobalData.h>
+
+#include "SubtreeJumpTable.h"
+
+#include <tree/ranked/PrefixRankedBarNonlinearPattern.h>
+#include <tree/ranked/PrefixRankedBarPattern.h>
+#include <tree/ranked/PrefixRankedNonlinearPattern.h>
+#include <tree/ranked/PrefixRankedPattern.h>
+
+namespace tree::properties {
+
+class BorderArray {
+
+public:
+	template < class PrefixRankedPatternType >
+	static ext::vector < size_t > construct ( const PrefixRankedPatternType & pattern );
+};
+
+template < class PrefixRankedPatternType >
+ext::vector < size_t > BorderArray::construct ( const PrefixRankedPatternType & pattern ) {
+	ext::vector < int > subtreeJumpTable = SubtreeJumpTable::compute ( pattern );
+	ext::vector < size_t > res ( pattern.getContent ( ).size ( ) + 1, 0 );
+	ext::vector < unsigned > mins ( pattern.getContent ( ).size ( ) + 1 );
+	for ( unsigned i = 0; i <= pattern.getContent ( ) .size ( ); i++ )
+		mins [ i ] = i + 1;
+	res [ 0 ] = -1;
+
+	for ( unsigned ofs = 1; ofs < pattern.getContent ( ).size ( ); ofs++ ) {
+
+		unsigned i = 0;   // index do patternu
+		unsigned j = ofs; // index do factoru
+
+		while ( 1 ) {
+			if ( i >= pattern.getContent ( ).size ( ) ) {
+				while ( j < pattern.getContent ( ).size ( ) ) {
+					mins [ j ] = std::min ( mins [ j ], ofs );
+					j++;
+				}
+				break;
+			} else if ( j >= pattern.getContent ( ).size ( ) ) {
+				break;
+			} else if ( pattern.getContent ( )[ i ] == pattern.getContent ( )[ j ] ) {
+				mins [ j ] = std::min ( mins [ j ], ofs );;
+				i++;
+				j++;
+			} else if ( pattern.getContent ( )[ i ] == pattern.getSubtreeWildcard ( ) || pattern.getContent ( )[ j ] == pattern.getSubtreeWildcard ( ) ) {
+				for ( int k = ( int ) j; k < subtreeJumpTable [ j ] ; k++ )
+					mins [ k ] = std::min ( mins [ k ], ofs );;
+
+				i = subtreeJumpTable[ i ];
+				j = subtreeJumpTable[ j ];
+			} else {
+				break;
+			}
+		}
+	}
+
+	// std::cout << mins << std::endl;
+
+	for ( size_t i = 1; i <= pattern.getContent ( ).size ( ); i++ ) {
+		res [ i ] = i - mins [ i - 1 ];
+	}
+
+	return res;
+}
+
+} /* namespace tree::properties */
+
+#endif /* _ARBOLOGY_BORDER_ARRAY_H_ */
diff --git a/alib2integrationtest/test-src/tests/borderArrayTest.cpp b/alib2integrationtest/test-src/tests/borderArrayTest.cpp
new file mode 100644
index 0000000000..f2a926c6c8
--- /dev/null
+++ b/alib2integrationtest/test-src/tests/borderArrayTest.cpp
@@ -0,0 +1,54 @@
+#include <catch2/catch.hpp>
+#include "testing/TimeoutAqlTest.hpp"
+
+#include <tree/properties/BorderArrayNaive.h>
+#include <tree/properties/BorderArray.h>
+
+const size_t PATTERN_SIZE = 50;
+const size_t PATTERN_HEIGHT = 7;
+
+const size_t ALPHABET_SIZE = 3;
+const size_t RANDOM_ITERATIONS = 100;
+
+std::string gen ( const std::string & cast, const std::string & var ) {
+	std::ostringstream oss;
+
+	oss << "execute ( " << cast << " ) tree::generate::RandomRankedPatternFactory ";
+	oss << "(int) " << PATTERN_HEIGHT << " ";
+	oss << "(int) " << PATTERN_SIZE   << " ";
+	oss << "(int) " << ALPHABET_SIZE  << " ";
+	oss << "(bool) false ";
+	oss << "(int) 5"; // rank
+	oss << " > $" << var;
+
+	return oss.str ( );
+}
+
+void run ( const std::string & prefixRankedType ) {
+	ext::vector < std::string > qs = {
+		gen ( prefixRankedType, "pattern" ),
+		"execute tree::properties::BorderArrayNaive $pattern > $res1",
+		"execute tree::properties::BorderArray      $pattern > $res2",
+		// "execute $pattern | string::Compose - ",
+		// "execute $res1",
+		// "execute $res2",
+		"quit compare::VectorCompare $res1 $res2",
+	};
+	for ( size_t i = 0; i < RANDOM_ITERATIONS; i++ )
+		TimeoutAqlTest ( 1s, qs );
+}
+
+TEST_CASE ( "Tree BorderArray", "[integration]" ) {
+	SECTION ( "PrefixRankedPattern" ) {
+		run ( "PrefixRankedPattern" );
+	}
+	SECTION ( "PrefixRankedBarPattern" ) {
+		run ( "PrefixRankedBarPattern" );
+	}
+	SECTION ( "PrefixRankedNonlinearPattern" ) {
+		run ( "PrefixRankedNonlinearPattern" );
+	}
+	SECTION ( "PrefixRankedBarNonlinearPattern" ) {
+		run ( "PrefixRankedBarNonlinearPattern" );
+	}
+}
-- 
GitLab