From efa5497c85bc46709d1e357570332fc474d6456d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ing=2E=20Radom=C3=ADr=20Pol=C3=A1ch?= <polacrad@fit.cvut.cz>
Date: Sun, 14 Sep 2014 14:27:36 +0200
Subject: [PATCH] FEATURE: cyclic string canonical form in O(n) time and O(n)
 space

---
 alib2data/makefile                    |  2 +-
 alib2data/src/string/CyclicString.cpp | 41 ++++++++++++++++++++++-----
 2 files changed, 35 insertions(+), 8 deletions(-)

diff --git a/alib2data/makefile b/alib2data/makefile
index 57af86af63..f138e3cb54 100644
--- a/alib2data/makefile
+++ b/alib2data/makefile
@@ -2,7 +2,7 @@ SHELL:=/bin/bash
 LIBRARY:=libalib2data.so 
 TESTBIN:=alib2test
 
-LDFLAGS:= /usr/lib64/libbfd.a /usr/lib64/libiberty.a -lz -ldl -rdynamic -shared -lxml2
+LDFLAGS:=-lbfd -liberty -lz -ldl -rdynamic -shared -lxml2
 TEST_LDFLAGS:= -L../alib2data/lib -rdynamic -lxml2 -lalib2data -lcppunit -Wl,-rpath,.
 
 OBJECTS:=$(patsubst src/%.cpp, obj/%.o, $(shell find src/ -name *cpp))
diff --git a/alib2data/src/string/CyclicString.cpp b/alib2data/src/string/CyclicString.cpp
index dccd4fad7f..fcf1fc8e58 100644
--- a/alib2data/src/string/CyclicString.cpp
+++ b/alib2data/src/string/CyclicString.cpp
@@ -83,13 +83,40 @@ void CyclicString::setContent(std::vector<alphabet::Symbol> data) {
 	if(unknownSymbols.size() > 0)
 		throw exception::AlibException("Input symbols not in the alphabet.");
 
-	m_Data = data;
-	for(unsigned i = 1; i < data.size(); i++) {
-		data.push_back(std::move(data[0]));
-		data.erase(data.begin());
-
-		if(m_Data > data) m_Data = data;
-	}
+    /**
+     * Lexicographically least circular substrings
+     * Kellogg S. Booth
+     * 1979
+     */
+    int* f = new int[data.size()]; /** Knuth–Morris–Pratt like array */
+    int k = 0; /** Least circular string shift value */
+    int i;
+    f[0]=-1;
+    for (unsigned j = 1; j < 2*data.size(); ++j) {
+        /** condition adjusted by Radomír Polách, >= is not correct */
+        if (j - k > data.size()) break; 
+        i = f[j - k -1];
+        while (data[j % data.size()] != data[(k + i + 1) % data.size()] && i != -1) {
+            if (data[j % data.size()] < data[(k + i + 1) % data.size()]) k = j - i - 1;
+            i = f[i];
+        }
+        if (data[j % data.size()] != data[(k + i + 1) % data.size()] && i == -1) {
+            if (data[j % data.size()] < data[(k + i + 1) % data.size()]) k = j;
+            f[j - k] = -1;
+        } else f[j - k] = i+1;
+    }
+    delete [] f;
+   
+    if (k == 0) {
+        m_Data = data;
+        return;
+    }
+ 
+    std::vector<alphabet::Symbol> tmp;
+    for (unsigned l = k; l < data.size() + k; ++l) {
+        tmp.push_back(std::move(data[l % data.size()]));
+    }
+    m_Data = tmp;
 }
 
 bool CyclicString::isEmpty() const {
-- 
GitLab