From e01d6dfa9d658425559a7ca7d49a88e6f205548d Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Fri, 11 Jul 2014 19:05:17 +0200
Subject: [PATCH] Split ContextPreserving from Unrestricted Grammar

---
 alib2/src/grammar/GrammarBase.cpp             |   4 +
 alib2/src/grammar/GrammarBase.h               |   5 +-
 alib2/src/grammar/GrammarToXMLComposer.cpp    |   9 ++
 alib2/src/grammar/GrammarToXMLComposer.h      |   3 +
 .../ContextPreservingUnrestrictedGrammar.cpp  | 122 ++++++++++++++++++
 .../ContextPreservingUnrestrictedGrammar.h    |  51 ++++++++
 .../Unrestricted/UnrestrictedGrammar.cpp      |  19 +--
 7 files changed, 194 insertions(+), 19 deletions(-)
 create mode 100644 alib2/src/grammar/Unrestricted/ContextPreservingUnrestrictedGrammar.cpp
 create mode 100644 alib2/src/grammar/Unrestricted/ContextPreservingUnrestrictedGrammar.h

diff --git a/alib2/src/grammar/GrammarBase.cpp b/alib2/src/grammar/GrammarBase.cpp
index cda2451564..af929e3434 100644
--- a/alib2/src/grammar/GrammarBase.cpp
+++ b/alib2/src/grammar/GrammarBase.cpp
@@ -69,6 +69,10 @@ bool GrammarBase::operator==(const UnrestrictedGrammar&) const {
 	return false;
 }
 
+bool GrammarBase::operator==(const ContextPreservingUnrestrictedGrammar&) const {
+	return false;
+}
+
 std::ostream& operator<<(std::ostream& os, const GrammarBase& grammar) {
 	grammar >> os;
 	return os;
diff --git a/alib2/src/grammar/GrammarBase.h b/alib2/src/grammar/GrammarBase.h
index 21bc658c6f..4953e8b004 100644
--- a/alib2/src/grammar/GrammarBase.h
+++ b/alib2/src/grammar/GrammarBase.h
@@ -25,12 +25,13 @@ class CNF;
 class GNF;
 class CSG;
 class NonContractingGrammar;
+class ContextPreservingUnrestrictedGrammar;
 class UnrestrictedGrammar;
 
 /**
  * Abstract base class for all automata.
  */
-class GrammarBase : public std::elementBase<UnknownGrammar, LeftLG, LeftRG, RightLG, RightRG, LG, CFG, EpsilonFreeCFG, CNF, GNF, CSG, NonContractingGrammar, UnrestrictedGrammar> {
+class GrammarBase : public std::elementBase<UnknownGrammar, LeftLG, LeftRG, RightLG, RightRG, LG, CFG, EpsilonFreeCFG, CNF, GNF, CSG, NonContractingGrammar, ContextPreservingUnrestrictedGrammar, UnrestrictedGrammar> {
 public:
 	virtual GrammarBase* clone() const = 0;
 
@@ -65,6 +66,8 @@ public:
 	virtual bool operator==(const NonContractingGrammar& other) const;
 	
 	virtual bool operator==(const UnrestrictedGrammar& other) const;
+	
+	virtual bool operator==(const ContextPreservingUnrestrictedGrammar& other) const;
 
 	virtual bool operator==(const GrammarBase& other) const = 0;
 
diff --git a/alib2/src/grammar/GrammarToXMLComposer.cpp b/alib2/src/grammar/GrammarToXMLComposer.cpp
index 6bb874ad22..781b5a160f 100644
--- a/alib2/src/grammar/GrammarToXMLComposer.cpp
+++ b/alib2/src/grammar/GrammarToXMLComposer.cpp
@@ -96,6 +96,11 @@ std::list<sax::Token> GrammarToXMLComposer::compose(const NonContractingGrammar&
 	return out;
 }
 
+std::list<sax::Token> GrammarToXMLComposer::compose(const ContextPreservingUnrestrictedGrammar& grammar) const {
+	std::list<sax::Token> out;
+	return out;
+}
+
 std::list<sax::Token> GrammarToXMLComposer::compose(const UnrestrictedGrammar& grammar) const {
 	std::list<sax::Token> out;
 	out.push_back(sax::Token("UnrestrictedGrammar", sax::Token::TokenType::START_ELEMENT));
@@ -241,6 +246,10 @@ void GrammarToXMLComposer::Visit(void* data, const NonContractingGrammar& gramma
 	*((std::list<sax::Token>*) data) = this->compose(grammar);
 }
 
+void GrammarToXMLComposer::Visit(void* data, const ContextPreservingUnrestrictedGrammar& grammar) const {
+	*((std::list<sax::Token>*) data) = this->compose(grammar);
+}
+
 void GrammarToXMLComposer::Visit(void* data, const UnrestrictedGrammar& grammar) const {
 	*((std::list<sax::Token>*) data) = this->compose(grammar);
 }
diff --git a/alib2/src/grammar/GrammarToXMLComposer.h b/alib2/src/grammar/GrammarToXMLComposer.h
index 53f76cb656..c0433201cc 100644
--- a/alib2/src/grammar/GrammarToXMLComposer.h
+++ b/alib2/src/grammar/GrammarToXMLComposer.h
@@ -23,6 +23,7 @@ class CNF;
 class GNF;
 class CSG;
 class NonContractingGrammar;
+#include "Unrestricted/ContextPreservingUnrestrictedGrammar.h"
 #include "Unrestricted/UnrestrictedGrammar.h"
 #include "../sax/Token.h"
 
@@ -45,6 +46,7 @@ class GrammarToXMLComposer : public GrammarBase::const_visitor_type {
 	void Visit(void*, const GNF& grammar) const;
 	void Visit(void*, const CSG& grammar) const;
 	void Visit(void*, const NonContractingGrammar& grammar) const;
+	void Visit(void*, const ContextPreservingUnrestrictedGrammar& grammar) const;
 	void Visit(void*, const UnrestrictedGrammar& grammar) const;
 
 	void composeNonterminalAlphabet(std::list<sax::Token>& out, const std::set<alphabet::Symbol>& symbols) const;
@@ -78,6 +80,7 @@ public:
 	std::list<sax::Token> compose(const GNF& grammar) const;
 	std::list<sax::Token> compose(const CSG& grammar) const;
 	std::list<sax::Token> compose(const NonContractingGrammar& grammar) const;
+	std::list<sax::Token> compose(const ContextPreservingUnrestrictedGrammar& grammar) const;
 	std::list<sax::Token> compose(const UnrestrictedGrammar& grammar) const;
 };
 
diff --git a/alib2/src/grammar/Unrestricted/ContextPreservingUnrestrictedGrammar.cpp b/alib2/src/grammar/Unrestricted/ContextPreservingUnrestrictedGrammar.cpp
new file mode 100644
index 0000000000..ecd4d70852
--- /dev/null
+++ b/alib2/src/grammar/Unrestricted/ContextPreservingUnrestrictedGrammar.cpp
@@ -0,0 +1,122 @@
+/*
+ * ContextPreservingUnrestrictedGrammar.cpp
+ *
+ *  Created on: Nov 17, 2013
+ *      Author: martin
+ */
+
+#include "ContextPreservingUnrestrictedGrammar.h"
+#include "../../std/map.hpp"
+#include "../GrammarException.h"
+#include <algorithm>
+
+#include "../../alphabet/Symbol.h"
+
+namespace grammar {
+
+ContextPreservingUnrestrictedGrammar::ContextPreservingUnrestrictedGrammar(const alphabet::Symbol& initialSymbol) : TerminalNonterminalAlphabetInitialSymbol(initialSymbol) {
+
+}
+
+ContextPreservingUnrestrictedGrammar::ContextPreservingUnrestrictedGrammar(const std::set<alphabet::Symbol>& nonterminalAlphabet, const std::set<alphabet::Symbol>& terminalAlphabet, const alphabet::Symbol& initialSymbol) : TerminalNonterminalAlphabetInitialSymbol(initialSymbol) {
+	setNonterminalAlphabet(nonterminalAlphabet);
+	setTerminalAlphabet(terminalAlphabet);
+}
+
+GrammarBase* ContextPreservingUnrestrictedGrammar::clone() const {
+	return new ContextPreservingUnrestrictedGrammar(*this);
+}
+
+GrammarBase* ContextPreservingUnrestrictedGrammar::plunder() && {
+	return new ContextPreservingUnrestrictedGrammar(std::move(*this));
+}
+
+bool ContextPreservingUnrestrictedGrammar::removeTerminalSymbol(const alphabet::Symbol& symbol) {
+	for(const std::pair<std::vector<alphabet::Symbol>, std::set<std::vector<alphabet::Symbol>>>& rule : rules) {
+		if(std::find(rule.first.begin(), rule.first.end(), symbol) != rule.first.end())
+			throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is used in rule.");
+
+		for(const std::vector<alphabet::Symbol>& rhs : rule.second)
+			if(std::find(rhs.begin(), rhs.end(), symbol) != rhs.end())
+				throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is used in rule.");
+	}
+
+	return terminalAlphabet.erase(symbol);
+}
+
+bool ContextPreservingUnrestrictedGrammar::removeNonterminalSymbol(const alphabet::Symbol& symbol) {
+	for(const std::pair<std::vector<alphabet::Symbol>, std::set<std::vector<alphabet::Symbol>>>& rule : rules) {
+		if(std::find(rule.first.begin(), rule.first.end(), symbol) != rule.first.end())
+			throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is used in rule.");
+
+		for(const std::vector<alphabet::Symbol>& rhs : rule.second)
+			if(std::find(rhs.begin(), rhs.end(), symbol) != rhs.end())
+				throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is used in rule.");
+	}
+
+	if(initialSymbol == symbol)
+		throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is initial symbol.");
+
+
+	return nonterminalAlphabet.erase(symbol);
+}
+
+bool ContextPreservingUnrestrictedGrammar::addRule(const std::vector<alphabet::Symbol>& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) {
+	int lSize = leftHandSide.size();
+	int rSize = rightHandSide.size();
+
+	if(lSize > rSize + 1)
+		throw GrammarException("Invalid size of right hand side of a rule");
+
+	int lContext;
+	int rContext;
+	for(lContext = 0; lContext < lSize - 1 && leftHandSide[lContext] == rightHandSide[lContext]; lContext++);
+	for(rContext = 0; rContext < lSize - 1 && leftHandSide[lSize - rContext] == rightHandSide[rSize - rContext]; rContext++);
+
+	if(lContext + rContext + 1 < lSize) {
+		throw GrammarException("Rule must rewrite only one symbol");
+	} else
+	if(lContext + rContext + 1 == lSize) {
+		if(!nonterminalAlphabet.count(leftHandSide[lContext])) throw GrammarException("Rule must rewrite nonterminal symbol");
+	} else
+	if(/* lContext + rContext + 1 > lSize */ std::all_of(leftHandSide.end() - rContext + 1, leftHandSide.begin() + lContext - 1, [&](const alphabet::Symbol symbol) {return !nonterminalAlphabet.count(symbol);}))
+		throw GrammarException("Rule must rewrite nonterminal symbol");
+
+
+	for(const alphabet::Symbol& symbol : leftHandSide)
+		if(terminalAlphabet.find(symbol) == terminalAlphabet.end() && nonterminalAlphabet.find(symbol) == nonterminalAlphabet.end())
+			throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is not neither terminal nor nonterminal symbol");
+
+	for(const alphabet::Symbol& symbol : rightHandSide)
+		if(terminalAlphabet.find(symbol) == terminalAlphabet.end() && nonterminalAlphabet.find(symbol) == nonterminalAlphabet.end())
+			throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is not neither terminal nor nonterminal symbol");
+
+	return rules[leftHandSide].insert(rightHandSide).second;
+}
+
+const std::map<std::vector<alphabet::Symbol>, std::set<std::vector<alphabet::Symbol>>> ContextPreservingUnrestrictedGrammar::getRules() const {
+	return rules;
+}
+
+bool ContextPreservingUnrestrictedGrammar::removeRule(const std::vector<alphabet::Symbol>& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) {
+	return rules[leftHandSide].erase(rightHandSide);
+}
+
+bool ContextPreservingUnrestrictedGrammar::operator==(const GrammarBase& other) const {
+	return other == *this;
+}
+
+bool ContextPreservingUnrestrictedGrammar::operator==(const ContextPreservingUnrestrictedGrammar& other) const {
+	return this->nonterminalAlphabet == other.nonterminalAlphabet && this->terminalAlphabet == other.terminalAlphabet && this->initialSymbol == other.initialSymbol && this->rules == other.rules;
+}
+
+void ContextPreservingUnrestrictedGrammar::operator>>(std::ostream& out) const {
+	out << "(ContextPreservingUnrestrictedGrammar"
+			<< "nonterminalAlphabet = " << nonterminalAlphabet
+			<< "terminalAlphabet = " << terminalAlphabet
+			<< "initialSymbol = " << initialSymbol
+			<< "rules = " << rules
+			<< ")";
+}
+
+} /* namespace grammar */
diff --git a/alib2/src/grammar/Unrestricted/ContextPreservingUnrestrictedGrammar.h b/alib2/src/grammar/Unrestricted/ContextPreservingUnrestrictedGrammar.h
new file mode 100644
index 0000000000..082cfcfef6
--- /dev/null
+++ b/alib2/src/grammar/Unrestricted/ContextPreservingUnrestrictedGrammar.h
@@ -0,0 +1,51 @@
+/*
+ * ContextPreservingUnrestrictedGrammar.h
+ *
+ *  Created on: Nov 17, 2013
+ *      Author: martin
+ */
+
+#ifndef CONTEXT_PRESERVING_UNRESTRICTED_GRAMMAR_H_
+#define CONTEXT_PRESERVING_UNRESTRICTED_GRAMMAR_H_
+
+#include "../GrammarBase.h"
+#include <map>
+#include "../common/TerminalNonterminalAlphabetInitialSymbol.h"
+
+namespace grammar {
+
+/**
+ * UnrestrictedGrammar grammar. Type 0 in Chomsky hierarchy. Produces recursively enumerable language.
+ */
+class ContextPreservingUnrestrictedGrammar : public std::element<ContextPreservingUnrestrictedGrammar, GrammarBase>, public TerminalNonterminalAlphabetInitialSymbol {
+	std::map<std::vector<alphabet::Symbol>, std::set<std::vector<alphabet::Symbol>>> rules;
+
+public:
+	ContextPreservingUnrestrictedGrammar(const alphabet::Symbol& initialSymbol);
+
+	ContextPreservingUnrestrictedGrammar(const std::set<alphabet::Symbol>& nonTerminalSymbols, const std::set<alphabet::Symbol>& terminalSymbols, const alphabet::Symbol& initialSymbol);
+
+	virtual GrammarBase* clone() const;
+
+	virtual GrammarBase* plunder() &&;
+
+	bool addRule(const std::vector<alphabet::Symbol>& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide);
+
+	const std::map<std::vector<alphabet::Symbol>, std::set<std::vector<alphabet::Symbol>>> getRules() const;
+
+	bool removeRule(const std::vector<alphabet::Symbol>& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide);
+
+	bool removeTerminalSymbol(const alphabet::Symbol& symbol);
+
+	bool removeNonterminalSymbol(const alphabet::Symbol& symbol);
+
+	virtual bool operator==(const GrammarBase& other) const;
+
+	virtual bool operator==(const ContextPreservingUnrestrictedGrammar& other) const;
+
+	virtual void operator>>(std::ostream& os) const;
+};
+
+} /* namespace grammar */
+
+#endif /* CONTEXT_PRESERVING_UNRESTRICTED_GRAMMAR_H_ */
diff --git a/alib2/src/grammar/Unrestricted/UnrestrictedGrammar.cpp b/alib2/src/grammar/Unrestricted/UnrestrictedGrammar.cpp
index ed842072fe..28f2e366fa 100644
--- a/alib2/src/grammar/Unrestricted/UnrestrictedGrammar.cpp
+++ b/alib2/src/grammar/Unrestricted/UnrestrictedGrammar.cpp
@@ -62,24 +62,7 @@ bool UnrestrictedGrammar::removeNonterminalSymbol(const alphabet::Symbol& symbol
 }
 
 bool UnrestrictedGrammar::addRule(const std::vector<alphabet::Symbol>& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) {
-	int lSize = leftHandSide.size();
-	int rSize = rightHandSide.size();
-
-	if(lSize > rSize + 1)
-		throw GrammarException("Invalid size of right hand side of a rule");
-
-	int lContext;
-	int rContext;
-	for(lContext = 0; lContext < lSize - 1 && leftHandSide[lContext] == rightHandSide[lContext]; lContext++);
-	for(rContext = 0; rContext < lSize - 1 && leftHandSide[lSize - rContext] == rightHandSide[rSize - rContext]; rContext++);
-
-	if(lContext + rContext + 1 < lSize) {
-		throw GrammarException("Rule must rewrite only one symbol");
-	} else
-	if(lContext + rContext + 1 == lSize) {
-		if(!nonterminalAlphabet.count(leftHandSide[lContext])) throw GrammarException("Rule must rewrite nonterminal symbol");
-	} else
-	if(/* lContext + rContext + 1 > lSize */ std::all_of(leftHandSide.end() - rContext + 1, leftHandSide.begin() + lContext - 1, [&](const alphabet::Symbol symbol) {return !nonterminalAlphabet.count(symbol);}))
+	if(std::all_of(leftHandSide.begin(), leftHandSide.end(), [&](const alphabet::Symbol symbol) {return !nonterminalAlphabet.count(symbol);}))
 		throw GrammarException("Rule must rewrite nonterminal symbol");
 
 
-- 
GitLab