From e0fee60fdf7da2f065d825f21f1a8e3cf640b0bc Mon Sep 17 00:00:00 2001
From: David Rosca <roscadav@fit.cvut.cz>
Date: Sat, 28 Feb 2015 21:22:42 +0100
Subject: [PATCH] Add UndirectedGraph

Without a IUndirectedGraph implementation yet
---
 alib2data/src/XmlApi.cpp                      |  17 ++
 alib2data/src/XmlApi.hpp                      |   9 ++
 alib2data/src/graph/GraphFromStringParser.cpp |  18 +--
 alib2data/src/graph/GraphFromXMLParser.cpp    |  22 +--
 alib2data/src/graph/GraphToStringComposer.cpp |  11 +-
 alib2data/src/graph/GraphToXMLComposer.cpp    |  20 +++
 alib2data/src/graph/GraphToXMLComposer.h      |   3 +
 alib2data/src/graph/directed/IDirectedGraph.h |   1 -
 .../src/graph/undirected/IUndirectedGraph.cpp |  23 +++
 .../src/graph/undirected/IUndirectedGraph.h   |  37 +++++
 .../src/graph/undirected/UndirectedGraph.cpp  | 151 ++++++++++++++++++
 .../src/graph/undirected/UndirectedGraph.h    |  60 ++++++-
 alib2data/src/object/ObjectBase.h             |   4 +-
 13 files changed, 346 insertions(+), 30 deletions(-)
 create mode 100644 alib2data/src/graph/undirected/IUndirectedGraph.cpp
 create mode 100644 alib2data/src/graph/undirected/IUndirectedGraph.h
 create mode 100644 alib2data/src/graph/undirected/UndirectedGraph.cpp

diff --git a/alib2data/src/XmlApi.cpp b/alib2data/src/XmlApi.cpp
index 824409f9e6..0a662152fa 100644
--- a/alib2data/src/XmlApi.cpp
+++ b/alib2data/src/XmlApi.cpp
@@ -85,6 +85,7 @@ const std::string Names::GRAMMAR_NON_CONTRACTING_GRAMMAR = "NonContractingGramma
 const std::string Names::GRAMMAR_CONTEXT_PRESERVING_UNRESTRICTED_GRAMMAR = "ContextPpreservingUnrestrictedGrammar";
 const std::string Names::GRAMMAR_UNRESTRICTED_GRAMMAR = "UnrestrictedGrammar";
 const std::string Names::GRAPH_DIRECTED_GRAPH = "DirectedGraph";
+const std::string Names::GRAPH_UNDIRECTED_GRAPH = "UndirectedGraph";
 const std::string Names::LABEL_PRIMITIVE_LABEL = "PrimitiveLabel";
 const std::string Names::LABEL_HEXAVIGESIMAL_LABEL = "HexavigesimalLabel";
 const std::string Names::LABEL_OBJECT_LABEL = "ObjectLabel";
@@ -778,6 +779,18 @@ void xmlApi<graph::DirectedGraph>::compose(std::list<sax::Token>& output, const
 	ToXMLComposers::graphComposer.compose(output, data);
 }
 
+graph::UndirectedGraph xmlApi<graph::UndirectedGraph>::parse(std::list<sax::Token>& input) {
+	return FromXMLParsers::graphParser.parseUndirectedGraph(input);
+}
+
+bool xmlApi<graph::UndirectedGraph>::first(const std::list<sax::Token>& input) {
+	return sax::FromXMLParserHelper::isToken(input, sax::Token::TokenType::START_ELEMENT, Names::GRAPH_UNDIRECTED_GRAPH);
+}
+
+void xmlApi<graph::UndirectedGraph>::compose(std::list<sax::Token>& output, const graph::UndirectedGraph& data) {
+	ToXMLComposers::graphComposer.compose(output, data);
+}
+
 
 label::Label xmlApi<label::Label>::parse(std::list<sax::Token>& input) {
 	return FromXMLParsers::labelParser.parseLabel(input);
@@ -1278,6 +1291,10 @@ void ToXMLComposers::Visit(void* data, const graph::DirectedGraph& graph) const
 	xmlApi<graph::DirectedGraph>::compose(*((std::list<sax::Token>*) data), graph);
 }
 
+void ToXMLComposers::Visit(void* data, const graph::UndirectedGraph& graph) const {
+	xmlApi<graph::UndirectedGraph>::compose(*((std::list<sax::Token>*) data), graph);
+}
+
 void ToXMLComposers::Visit(void* data, const label::PrimitiveLabel& label) const {
 	xmlApi<label::PrimitiveLabel>::compose(*((std::list<sax::Token>*) data), label);
 }
diff --git a/alib2data/src/XmlApi.hpp b/alib2data/src/XmlApi.hpp
index 5278d7af1b..5563687add 100644
--- a/alib2data/src/XmlApi.hpp
+++ b/alib2data/src/XmlApi.hpp
@@ -86,6 +86,7 @@ public:
 	const static std::string GRAMMAR_CONTEXT_PRESERVING_UNRESTRICTED_GRAMMAR;
 	const static std::string GRAMMAR_UNRESTRICTED_GRAMMAR;
 	const static std::string GRAPH_DIRECTED_GRAPH;
+	const static std::string GRAPH_UNDIRECTED_GRAPH;
 	const static std::string LABEL_PRIMITIVE_LABEL;
 	const static std::string LABEL_HEXAVIGESIMAL_LABEL;
 	const static std::string LABEL_OBJECT_LABEL;
@@ -543,6 +544,13 @@ struct xmlApi<graph::DirectedGraph> {
 	static void compose(std::list<sax::Token>& output, const graph::DirectedGraph& data);
 };
 
+template<>
+struct xmlApi<graph::UndirectedGraph> {
+	static graph::UndirectedGraph parse(std::list<sax::Token>& input);
+	static bool first(const std::list<sax::Token>& input);
+	static void compose(std::list<sax::Token>& output, const graph::UndirectedGraph& data);
+};
+
 
 template<>
 struct xmlApi<label::Label> {
@@ -808,6 +816,7 @@ class ToXMLComposers : public VisitableObjectBase::const_visitor_type {
 	void Visit(void*, const grammar::UnrestrictedGrammar& grammar) const;
 
 	void Visit(void*, const graph::DirectedGraph& graph) const;
+	void Visit(void*, const graph::UndirectedGraph& graph) const;
 
 	void Visit(void*, const label::PrimitiveLabel& label) const;
 	void Visit(void*, const label::HexavigesimalLabel& label) const;
diff --git a/alib2data/src/graph/GraphFromStringParser.cpp b/alib2data/src/graph/GraphFromStringParser.cpp
index 4b75e0bfa0..b7941294e4 100644
--- a/alib2data/src/graph/GraphFromStringParser.cpp
+++ b/alib2data/src/graph/GraphFromStringParser.cpp
@@ -23,12 +23,12 @@ Graph GraphFromStringParser::parseGraph(std::istream &input) const
 		return graph;
 	} else if (str == "UndirectedGraph") {
 		parseDelimiter(input); // :
-		//Graph graph{parseUndirectedGraph(input)};
+		Graph graph{parseUndirectedGraph(input)};
 
 		if (lexer.next(input).type != GraphFromStringLexer::TokenType::RPAR) {
 			throw exception::AlibException("Invalid input. Expected RPAR");
 		}
-		// return graph;
+		return graph;
 	}
 
 	throw exception::AlibException("Invalid graph type");
@@ -46,12 +46,12 @@ DirectedGraph GraphFromStringParser::parseDirectedGraph(std::istream &input) con
 
 UndirectedGraph GraphFromStringParser::parseUndirectedGraph(std::istream &input) const
 {
-	//UndirectedGraph graph(parseRepresentation(input));
-	//parseDelimiter(input); // :
-	//parseNodes(input, graph);
-	//parseDelimiter(input); // :
-	//parseUndirectedEdges(input, graph);
-	//return graph;
+	UndirectedGraph graph(parseRepresentation(input));
+	parseDelimiter(input); // :
+	parseNodes(input, graph);
+	parseDelimiter(input); // :
+	parseUndirectedEdges(input, graph);
+	return graph;
 }
 
 REPRESENTATION GraphFromStringParser::parseRepresentation(std::istream &input) const
@@ -139,7 +139,7 @@ void GraphFromStringParser::parseUndirectedEdges(std::istream &input, Undirected
 	lexer.putback(input, token);
 
 	while (true) {
-		//graph.addEdge(parseUndirectedEdge(input));
+		graph.addEdge(parseUndirectedEdge(input));
 
 		token = lexer.next(input);
 		if (token.type != GraphFromStringLexer::TokenType::COMMA) {
diff --git a/alib2data/src/graph/GraphFromXMLParser.cpp b/alib2data/src/graph/GraphFromXMLParser.cpp
index 8858373146..d44bc3c173 100644
--- a/alib2data/src/graph/GraphFromXMLParser.cpp
+++ b/alib2data/src/graph/GraphFromXMLParser.cpp
@@ -37,14 +37,14 @@ DirectedGraph GraphFromXMLParser::parseDirectedGraph(std::list<sax::Token> &inpu
 
 UndirectedGraph GraphFromXMLParser::parseUndirectedGraph(std::list<sax::Token> &input) const
 {
-	//popToken(input, sax::Token::TokenType::START_ELEMENT, alib::Names::GRAPH_UNDIRECTED_GRAPH);
+	popToken(input, sax::Token::TokenType::START_ELEMENT, alib::Names::GRAPH_UNDIRECTED_GRAPH);
 
-	//UndirectedGraph graph(parseRepresentation(input));
-	//parseNodes(input, graph);
-	//parseUndirectedEdges(input, graph);
+	UndirectedGraph graph(parseRepresentation(input));
+	parseNodes(input, graph);
+	parseUndirectedEdges(input, graph);
 
-	//popToken(input, sax::Token::TokenType::END_ELEMENT, alib::Names::GRAPH_UNDIRECTED_GRAPH);
-	//return graph;
+	popToken(input, sax::Token::TokenType::END_ELEMENT, alib::Names::GRAPH_UNDIRECTED_GRAPH);
+	return graph;
 }
 
 REPRESENTATION GraphFromXMLParser::parseRepresentation(std::list<sax::Token> &input) const
@@ -128,13 +128,13 @@ void GraphFromXMLParser::parseDirectedEdges(std::list<sax::Token> &input, Direct
 
 void GraphFromXMLParser::parseUndirectedEdges(std::list<sax::Token> &input, UndirectedGraph &graph) const
 {
-	//popToken(input, sax::Token::TokenType::START_ELEMENT, "edges");
+	popToken(input, sax::Token::TokenType::START_ELEMENT, "edges");
 
-	//while (isTokenType(input, sax::Token::TokenType::START_ELEMENT)) {
-	//	graph.addEdge(parseUndirectedEdge(input));
-	//}
+	while (isTokenType(input, sax::Token::TokenType::START_ELEMENT)) {
+		graph.addEdge(parseUndirectedEdge(input));
+	}
 
-	//popToken(input, sax::Token::TokenType::END_ELEMENT, "edges");
+	popToken(input, sax::Token::TokenType::END_ELEMENT, "edges");
 }
 
 } // namespace graph
diff --git a/alib2data/src/graph/GraphToStringComposer.cpp b/alib2data/src/graph/GraphToStringComposer.cpp
index 8ec08c07c2..226da7fd55 100644
--- a/alib2data/src/graph/GraphToStringComposer.cpp
+++ b/alib2data/src/graph/GraphToStringComposer.cpp
@@ -29,12 +29,11 @@ void GraphToStringComposer::Visit(void *data, const UndirectedGraph &graph) cons
 	std::ostream &out = *static_cast<std::ostream*>(data);
 
 	out << "UndirectedGraph:";
-	(void) graph;
-	//composeRepresentation(out, graph.getRepresentation());
-	//out << ":";
-	//composeNodes(out, graph.getNodes());
-	//out << ":";
-	//composeUndirectedEdges(out, graph.getEdges());
+	composeRepresentation(out, graph.getRepresentation());
+	out << ":";
+	composeNodes(out, graph.getNodes());
+	out << ":";
+	composeUndirectedEdges(out, graph.getEdges());
 }
 
 void GraphToStringComposer::Visit(void *data, const Node &node) const
diff --git a/alib2data/src/graph/GraphToXMLComposer.cpp b/alib2data/src/graph/GraphToXMLComposer.cpp
index 1c909506bb..5421105b43 100644
--- a/alib2data/src/graph/GraphToXMLComposer.cpp
+++ b/alib2data/src/graph/GraphToXMLComposer.cpp
@@ -73,6 +73,17 @@ void GraphToXMLComposer::compose(std::list<sax::Token> &out, const DirectedGraph
 	out.push_back(sax::Token(alib::Names::GRAPH_DIRECTED_GRAPH, sax::Token::TokenType::END_ELEMENT));
 }
 
+void GraphToXMLComposer::compose(std::list<sax::Token> &out, const UndirectedGraph &graph) const
+{
+	out.push_back(sax::Token(alib::Names::GRAPH_UNDIRECTED_GRAPH, sax::Token::TokenType::START_ELEMENT));
+
+	composeRepresentation(out, representationToString(graph.getRepresentation()));
+	composeNodes(out, graph.getNodes());
+	composeUndirectedEdges(out, graph.getEdges());
+
+	out.push_back(sax::Token(alib::Names::GRAPH_UNDIRECTED_GRAPH, sax::Token::TokenType::END_ELEMENT));
+}
+
 void GraphToXMLComposer::composeRepresentation(std::list<sax::Token> &out, const std::string &representation) const
 {
 	out.push_back(sax::Token("representation", sax::Token::TokenType::START_ELEMENT));
@@ -98,4 +109,13 @@ void GraphToXMLComposer::composeDirectedEdges(std::list<sax::Token> &out, const
 	out.push_back(sax::Token("edges", sax::Token::TokenType::END_ELEMENT));
 }
 
+void GraphToXMLComposer::composeUndirectedEdges(std::list<sax::Token> &out, const std::set<UndirectedEdge> &edges) const
+{
+	out.push_back(sax::Token("edges", sax::Token::TokenType::START_ELEMENT));
+	for (const UndirectedEdge &edge : edges) {
+		edge.Accept(static_cast<void*>(&out), *this);
+	}
+	out.push_back(sax::Token("edges", sax::Token::TokenType::END_ELEMENT));
+}
+
 } // namespace graph
diff --git a/alib2data/src/graph/GraphToXMLComposer.h b/alib2data/src/graph/GraphToXMLComposer.h
index a53d9b1e88..0fd0e1d8c5 100644
--- a/alib2data/src/graph/GraphToXMLComposer.h
+++ b/alib2data/src/graph/GraphToXMLComposer.h
@@ -31,9 +31,12 @@ private:
 	void compose(std::list<sax::Token> &out, const GraphBase &graph) const;
 	void compose(std::list<sax::Token> &out, const Graph &graph) const;
 	void compose(std::list<sax::Token> &out, const DirectedGraph &graph) const;
+	void compose(std::list<sax::Token> &out, const UndirectedGraph &graph) const;
+
 	void composeRepresentation(std::list<sax::Token> &out, const std::string &representation) const;
 	void composeNodes(std::list<sax::Token> &out, const std::set<Node> &nodes) const;
 	void composeDirectedEdges(std::list<sax::Token> &out, const std::set<DirectedEdge> &edges) const;
+	void composeUndirectedEdges(std::list<sax::Token> &out, const std::set<UndirectedEdge> &edges) const;
 
 	template<typename T> friend class alib::xmlApi;
 };
diff --git a/alib2data/src/graph/directed/IDirectedGraph.h b/alib2data/src/graph/directed/IDirectedGraph.h
index 5961c0817f..44bcc4de9b 100644
--- a/alib2data/src/graph/directed/IDirectedGraph.h
+++ b/alib2data/src/graph/directed/IDirectedGraph.h
@@ -2,7 +2,6 @@
 #define I_DIRECTED_GRAPH_H_
 
 #include <set>
-#include <map>
 
 #include "../common/Node.h"
 #include "DirectedEdge.h"
diff --git a/alib2data/src/graph/undirected/IUndirectedGraph.cpp b/alib2data/src/graph/undirected/IUndirectedGraph.cpp
new file mode 100644
index 0000000000..d8c5cec9c7
--- /dev/null
+++ b/alib2data/src/graph/undirected/IUndirectedGraph.cpp
@@ -0,0 +1,23 @@
+#include "IUndirectedGraph.h"
+
+#include <sstream>
+
+namespace graph {
+
+IUndirectedGraph::~IUndirectedGraph() noexcept
+{
+}
+
+IUndirectedGraph::operator std::string() const
+{
+	std::stringstream ss;
+	for (const Node &node : allNodes()) {
+		ss << node;
+	}
+	for (const UndirectedEdge &edge : allEdges()) {
+		ss << edge;
+	}
+	return ss.str();
+}
+
+} // namespace graph
diff --git a/alib2data/src/graph/undirected/IUndirectedGraph.h b/alib2data/src/graph/undirected/IUndirectedGraph.h
new file mode 100644
index 0000000000..5fec2ea80a
--- /dev/null
+++ b/alib2data/src/graph/undirected/IUndirectedGraph.h
@@ -0,0 +1,37 @@
+#ifndef I_UNDIRECTED_GRAPH_H_
+#define I_UNDIRECTED_GRAPH_H_
+
+#include <set>
+
+#include "../common/Node.h"
+#include "UndirectedEdge.h"
+
+namespace graph {
+
+class IUndirectedGraph
+{
+public:
+	virtual ~IUndirectedGraph() noexcept;
+
+	virtual std::set<Node> allNodes() const = 0;
+	virtual std::set<UndirectedEdge> allEdges() const = 0;
+
+	virtual std::set<UndirectedEdge> findEdges(const Node &first, const Node &second) const = 0;
+
+	virtual std::set<Node> neighbors(const Node &node) const = 0;
+	virtual std::set<UndirectedEdge> neighborEdges(const Node &node) const = 0;
+
+	virtual void addNode(const Node &node) = 0;
+	virtual void removeNode(const Node &node) = 0;
+
+	virtual void addEdge(const UndirectedEdge &edge) = 0;
+	virtual void removeEdge(const UndirectedEdge &edge) = 0;
+
+	virtual int compare(IUndirectedGraph *other) const = 0;
+
+	operator std::string() const;
+};
+
+} // namespace graph
+
+#endif // I_UNDIRECTED_GRAPH_H_
diff --git a/alib2data/src/graph/undirected/UndirectedGraph.cpp b/alib2data/src/graph/undirected/UndirectedGraph.cpp
new file mode 100644
index 0000000000..cfd3ccbc53
--- /dev/null
+++ b/alib2data/src/graph/undirected/UndirectedGraph.cpp
@@ -0,0 +1,151 @@
+#include "UndirectedGraph.h"
+#include "IUndirectedGraph.h"
+#include "../../std/set.hpp"
+
+#include <iostream>
+#include <algorithm>
+#include <sstream>
+
+namespace graph {
+
+UndirectedGraph::UndirectedGraph(REPRESENTATION representation)
+	: representation(representation)
+{
+	init();
+}
+
+UndirectedGraph::~UndirectedGraph() noexcept
+{
+	delete impl;
+}
+
+UndirectedGraph::UndirectedGraph(const UndirectedGraph &other)
+	: representation(other.representation)
+{
+	init();
+}
+
+UndirectedGraph::UndirectedGraph(UndirectedGraph &&other) noexcept
+	: representation(other.representation)
+	, impl(other.impl)
+{
+	other.impl = 0;
+}
+
+UndirectedGraph &UndirectedGraph::operator=(const UndirectedGraph &other)
+{
+	if (this == &other) {
+		return *this;
+	}
+
+	*this = UndirectedGraph(other);
+	return *this;
+}
+
+UndirectedGraph &UndirectedGraph::operator=(UndirectedGraph &&other) noexcept
+{
+	this->representation = other.representation;
+	std::swap(this->impl, other.impl);
+	return *this;
+}
+
+GraphBase *UndirectedGraph::clone() const
+{
+	return new UndirectedGraph(*this);
+}
+
+GraphBase *UndirectedGraph::plunder() &&
+{
+	return new UndirectedGraph(std::move(*this));
+}
+
+REPRESENTATION UndirectedGraph::getRepresentation() const
+{
+	return representation;
+}
+
+std::set<Node> UndirectedGraph::getNodes() const
+{
+	return impl->allNodes();
+}
+
+std::set<UndirectedEdge> UndirectedGraph::getEdges() const
+{
+	return impl->allEdges();
+}
+
+bool UndirectedGraph::hasEdge(const Node &from, const Node &to) const
+{
+	return !impl->findEdges(from, to).empty();
+}
+
+std::set<UndirectedEdge> UndirectedGraph::findEdges(const Node &from, const Node &to) const
+{
+	return impl->findEdges(from, to);
+}
+
+std::set<Node> UndirectedGraph::neighbors(const Node &node) const
+{
+	return impl->neighbors(node);
+}
+
+std::set<UndirectedEdge> UndirectedGraph::neighborEdges(const Node &node) const
+{
+	return impl->neighborEdges(node);
+}
+
+void UndirectedGraph::addNode(const Node &node)
+{
+	return impl->addNode(node);
+}
+
+void UndirectedGraph::removeNode(const Node &node)
+{
+	return impl->removeNode(node);
+}
+
+void UndirectedGraph::addEdge(const UndirectedEdge &edge)
+{
+	return impl->addEdge(edge);
+}
+
+void UndirectedGraph::removeEdge(const UndirectedEdge &edge)
+{
+	return impl->removeEdge(edge);
+}
+
+void UndirectedGraph::operator>>(std::ostream &out) const
+{
+	out << "(UndirectedGraph " << static_cast<std::string>(*impl) << ")";
+}
+
+int UndirectedGraph::compare(const UndirectedGraph &other) const
+{
+	if (representation != other.representation) {
+		return static_cast<int>(representation) - static_cast<int>(other.representation);
+	}
+
+	return impl->compare(other.impl);
+}
+
+UndirectedGraph::operator std::string() const
+{
+	std::stringstream ss;
+	ss << *this;
+	return ss.str();
+}
+
+void UndirectedGraph::init()
+{
+	switch (representation) {
+	case REPRESENTATION::ADJACENCY_LIST:
+	case REPRESENTATION::ADJACENCY_MATRIX:
+	case REPRESENTATION::INCIDENCE_MATRIX:
+
+	default:
+		impl = 0;
+	}
+}
+
+} // namespace graph
+
diff --git a/alib2data/src/graph/undirected/UndirectedGraph.h b/alib2data/src/graph/undirected/UndirectedGraph.h
index 1c48850279..3a99d937c0 100644
--- a/alib2data/src/graph/undirected/UndirectedGraph.h
+++ b/alib2data/src/graph/undirected/UndirectedGraph.h
@@ -1,14 +1,72 @@
 #ifndef UNDIRECTED_GRAPH_H_
 #define UNDIRECTED_GRAPH_H_
 
+#include "../GraphBase.h"
+#include "../GraphRepresentation.h"
+#include "../common/Macros.h"
+#include "../common/Node.h"
 #include "UndirectedEdge.h"
 
 namespace graph {
 
-class UndirectedGraph
+class IUndirectedGraph;
+
+class UndirectedGraph : public std::acceptor<UndirectedGraph, VisitableGraphBase, std::acceptor<UndirectedGraph, alib::VisitableObjectBase, GraphBase>>
 {
+public:
+	explicit UndirectedGraph(REPRESENTATION representation);
+	~UndirectedGraph() noexcept;
+
+	UndirectedGraph(const UndirectedGraph &other);
+	UndirectedGraph(UndirectedGraph &&other) noexcept;
+	UndirectedGraph &operator=(const UndirectedGraph &other);
+	UndirectedGraph &operator=(UndirectedGraph &&other) noexcept;
+
+	GraphBase *clone() const override;
+	GraphBase *plunder() && override;
+
+	REPRESENTATION getRepresentation() const;
+
+	std::set<Node> getNodes() const;
+	std::set<UndirectedEdge> getEdges() const;
+
+	bool hasEdge(const Node &from, const Node &to) const;
+	std::set<UndirectedEdge> findEdges(const Node &from, const Node &to) const;
+
+	std::set<Node> neighbors(const Node &node) const;
+	std::set<UndirectedEdge> neighborEdges(const Node &node) const;
+
+	void addNode(const Node &node);
+	void removeNode(const Node &node);
+
+	void addEdge(const UndirectedEdge &edge);
+	void removeEdge(const UndirectedEdge &edge);
+
+	int compare(const ObjectBase &other) const override
+	{
+		return -other.compare(*this);
+	}
+
+	int compare(const UndirectedGraph &other) const;
+
+	void operator>>(std::ostream &out) const override;
+
+	operator std::string() const override;
+
+	int selfTypeId() const override
+	{
+		return typeId<UndirectedGraph>();
+	}
+
+private:
+	void init();
+
+	REPRESENTATION representation;
+	IUndirectedGraph *impl;
 };
 
 } // namespace graph
 
+GRAPH_DEFINE_STD_COMPARE(UndirectedGraph)
+
 #endif // UNDIRECTED_GRAPH_H_
diff --git a/alib2data/src/object/ObjectBase.h b/alib2data/src/object/ObjectBase.h
index 5596022611..cf2dd385cb 100644
--- a/alib2data/src/object/ObjectBase.h
+++ b/alib2data/src/object/ObjectBase.h
@@ -142,7 +142,7 @@ typedef std::acceptor_base<ObjectBase,
 			exception::AlibException,
 			automaton::DFA, automaton::NFA, automaton::MultiInitialStateNFA, automaton::EpsilonNFA, automaton::CompactNFA, automaton::ExtendedNFA, automaton::DPDA, automaton::SinglePopDPDA, automaton::InputDrivenDPDA, automaton::VisiblyPushdownDPDA, automaton::RealTimeHeightDeterministicDPDA, automaton::NPDA, automaton::SinglePopNPDA, automaton::InputDrivenNPDA, automaton::VisiblyPushdownNPDA, automaton::RealTimeHeightDeterministicNPDA, automaton::OneTapeDTM,
 			grammar::LeftLG, grammar::LeftRG, grammar::RightLG, grammar::RightRG, grammar::LG, grammar::CFG, grammar::EpsilonFreeCFG, grammar::CNF, grammar::GNF, grammar::CSG, grammar::NonContractingGrammar, grammar::ContextPreservingUnrestrictedGrammar, grammar::UnrestrictedGrammar,
-			graph::DirectedGraph,
+			graph::DirectedGraph, graph::UndirectedGraph,
 			label::PrimitiveLabel, label::HexavigesimalLabel, label::ObjectLabel, label::LabelSetLabel, label::LabelPairLabel, label::UniqueLabel,
 			regexp::UnboundedRegExp, regexp::FormalRegExp,
 			string::Epsilon, string::LinearString, string::CyclicString,
@@ -158,7 +158,7 @@ class ObjectBase :
 			exception::AlibException,
 			automaton::DFA, automaton::NFA, automaton::MultiInitialStateNFA, automaton::EpsilonNFA, automaton::CompactNFA, automaton::ExtendedNFA, automaton::DPDA, automaton::SinglePopDPDA, automaton::InputDrivenDPDA, automaton::VisiblyPushdownDPDA, automaton::RealTimeHeightDeterministicDPDA, automaton::NPDA, automaton::SinglePopNPDA, automaton::InputDrivenNPDA, automaton::VisiblyPushdownNPDA, automaton::RealTimeHeightDeterministicNPDA, automaton::OneTapeDTM,
 			grammar::LeftLG, grammar::LeftRG, grammar::RightLG, grammar::RightRG, grammar::LG, grammar::CFG, grammar::EpsilonFreeCFG, grammar::CNF, grammar::GNF, grammar::CSG, grammar::NonContractingGrammar, grammar::ContextPreservingUnrestrictedGrammar, grammar::UnrestrictedGrammar,
-			graph::DirectedGraph,
+			graph::DirectedGraph, graph::UndirectedGraph,
 			label::PrimitiveLabel, label::HexavigesimalLabel, label::ObjectLabel, label::LabelSetLabel, label::LabelPairLabel, label::UniqueLabel,
 			regexp::UnboundedRegExp, regexp::FormalRegExp,
 			string::Epsilon, string::LinearString, string::CyclicString,
-- 
GitLab