diff --git a/graph/alt_graph.cpp b/graph/alt_graph.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b687a0af0f31723158cbf811dc008a555e6f7eae
--- /dev/null
+++ b/graph/alt_graph.cpp
@@ -0,0 +1,164 @@
+// Old implementation, maybe superior for some graphs.
+
+//=============================================================================
+// Class for Graph Nodes (one line of the adjacency matrix):
+//=============================================================================
+
+class Node {
+	public:
+
+	// Constructor:
+	Node(int graph_num_nodes)
+	{
+		num_nodes_ = graph_num_nodes;
+		int bytes = (num_nodes_ + BYTE_SIZE - 1) / BYTE_SIZE;
+		connections_ = new char[bytes];
+		char *p = connections_;
+		for(int i = bytes; i > 0; i--)
+			*p++ = '\0';
+	}
+
+	// Accessor Functions:
+	inline int num_nodes() const { return num_nodes_; }
+
+	// Store edge in adjacency matrix:
+	void store_connection(int to) {
+		// Check nodes:
+		if(to <= 0 || to > num_nodes_) {
+			std::cerr << "Invalid to node: " << to << "\n";
+			exit(3);
+		}
+
+		// Determine position in adjacency matrix:
+		long index = to - 1;
+		int bit = index % 8;
+		index = index / 8;
+
+		// Set bit:
+		connections_[index] |= (0x1) << bit;
+	}
+
+	// Check whether edge exists:
+	bool connection_exists(int to) const {
+		// Check node:
+		if(to <= 0 || to > num_nodes_) {
+			std::cerr << "Invalid to node: " << to << "\n";
+			exit(4);
+		}
+
+		// Determine position in adjacency matrix:
+		long index = to - 1;
+		int bit = index % 8;
+		index = index / 8;
+
+		// Check bit:
+		return (connections_[index] & ((0x1) << bit)) != 0;
+	}
+
+	// Copy other node into this node:
+	void copy(Node *node) {
+		if(node->num_nodes_ != num_nodes_) {
+			std::cerr << "Can copy only node of same size!\n";
+			exit(5);
+		}
+		int bytes = (num_nodes_ + BYTE_SIZE - 1) / BYTE_SIZE;
+		char *to = connections_;
+		char *from = node->connections_;
+		while(bytes-- > 0)
+			*to++ = *from++;
+	}
+
+	// Attributes:
+	private:
+	int num_nodes_;
+	char *connections_;
+};
+
+//-----------------------------------------------------------------------------
+// Pointer Type for Node Data:
+//-----------------------------------------------------------------------------
+
+typedef Node *node_t;
+
+#define NODE_NULL (static_cast<node_t>(0))
+
+
+//=============================================================================
+// Class for Graphs (contains adjacency matrix):
+//=============================================================================
+
+class Graph {
+	public:
+
+	// Constructor:
+	Graph(int graph_num_nodes)
+	{
+		num_nodes_ = graph_num_nodes;
+		nodes_ = new node_t[num_nodes_];
+		for(int i = 0; i < graph_num_nodes; i++)
+			nodes_[i] = new Node(graph_num_nodes);
+	}
+
+	// Accessor Functions:
+	inline int num_nodes() const { return num_nodes_; }
+	inline node_t node(int i) const { return nodes_[i-1]; }
+
+	// Store edge in adjacency matrix:
+	void store_edge(int from, int to) {
+		// Check nodes:
+		if(from <= 0 || from > num_nodes_) {
+			std::cerr << "Invalid from node: " << from << "\n";
+			exit(6);
+		}
+		if(to <= 0 || to > num_nodes_) {
+			std::cerr << "Invalid to node: " << to << "\n";
+			exit(7);
+		}
+
+		// Store edge in adjacency matrix:
+		long index = from - 1;
+		nodes_[index]->store_connection(to);
+	}
+
+	// Check whether edge exists:
+	bool edge_exists(int from, int to) const {
+		// Check nodes:
+		if(from <= 0 || from > num_nodes_) {
+			std::cerr << "Invalid from node: " << from << "\n";
+			exit(8);
+		}
+		if(to <= 0 || to > num_nodes_) {
+			std::cerr << "Invalid to node: " << to << "\n";
+			exit(9);
+		}
+
+		// Look up edge in adjacency matrix:
+		long index = from - 1;
+		return nodes_[index]->connection_exists(to);
+	}
+
+	// Copy a graph (of the same size) into this graph:
+	void copy(Graph *g)
+	{
+		if(g->num_nodes_ != num_nodes_) {
+			std::cerr << "Can copy only graph of same size!\n";
+			exit(10);
+		}
+		for(int i = 0; i < num_nodes_; i++)
+			nodes_[i]->copy(g->nodes_[i]);
+	}
+
+	// Attributes:
+	private:
+	int num_nodes_;
+	node_t *nodes_;
+};
+
+//-----------------------------------------------------------------------------
+// Pointer Type for Graph Data:
+//-----------------------------------------------------------------------------
+
+typedef Graph *graph_t;
+
+#define GRAPH_NULL (static_cast<graph_t>(0))
+
diff --git a/graph/graph.cpp b/graph/graph.cpp
index 71e518e771d142594316d475e4add3128b035b6f..7a96e60c4a3b3655a4ed51d27ed6095aada40e3b 100644
--- a/graph/graph.cpp
+++ b/graph/graph.cpp
@@ -179,13 +179,19 @@
 
 #define COST_TABLE "BENCH_COST"
 
-
 //=============================================================================
 // How many bytes does the bitstring in one element of the adjacency list have?
 //=============================================================================
 
 #define BITSTRING_BYTES 4
 
+//=============================================================================
+// Should Assertions be tested or is speed of highest importance?
+//=============================================================================
+
+// If this is defined, asserstions are skipped (faster code):
+//#define NDEBUG
+
 //=============================================================================
 // Include Files:
 //=============================================================================
@@ -194,6 +200,7 @@
 #include <fstream>
 #include <cstdint>
 #include <time.h>
+#include <assert.h>
 
 //=============================================================================
 // Type for Large Integers (64 Bit):
@@ -364,6 +371,162 @@ long str_int(str_t digits) {
 }
 
 
+//=============================================================================
+// Class for Graph/Benchmark Size Measures:
+//=============================================================================
+
+class GSize {
+	public:
+
+	// Constructor:
+	GSize()
+	{
+		num_nodes_  = -1;
+		num_edges_  = -1;
+		tc_size_    = -1;
+		tc_iter_    = -1;
+		tc_inst_    = -1;
+		sg_size_    = -1;
+		sg_iter_    = -1;
+		sg_inst_    = -1;
+	}
+
+	// Accessor Functions:
+	inline int      num_nodes() const { return num_nodes_; }
+	inline int      num_edges() const { return num_edges_; }
+	inline bigint_t tc_size()   const { return tc_size_; }
+	inline int      tc_iter()   const { return tc_iter_; }
+	inline bigint_t tc_inst()   const { return tc_inst_; }
+	inline bigint_t sg_size()   const { return sg_size_; }
+	inline int      sg_iter()   const { return sg_iter_; }
+	inline bigint_t sg_inst()   const { return sg_inst_; }
+
+	// Set functions:
+	inline void set_num_nodes(int n)    { num_nodes_ = n; }
+	inline void set_num_edges(int n)    { num_edges_ = n; }
+	inline void set_tc_size(bigint_t n) { tc_size_   = n; }
+	inline void set_tc_iter(int n)      { tc_iter_   = n; }
+	inline void set_tc_inst(bigint_t n) { tc_inst_   = n; }
+	inline void set_sg_size(bigint_t n) { sg_size_   = n; }
+	inline void set_sg_iter(int n)      { sg_iter_   = n; }
+	inline void set_sg_inst(bigint_t n) { sg_inst_   = n; }
+
+	// Print defined values:
+	void print() {
+		if(num_nodes_ >= 0)
+			std::cout << "\tNodes:   " << num_nodes_ << "\n";
+		if(num_edges_ >= 0)
+			std::cout << "\tEdges:   " << num_edges_ << "\n";
+		if(tc_iter_ >= 0)
+			std::cout << "\tTC Iter: " << tc_iter_ << "\n";
+		if(tc_size_ >= 0)
+			std::cout << "\tTC Size: " << tc_size_ << "\n";
+		if(tc_inst_ >= 0)
+			std::cout << "\tTC Inst: " << tc_inst_ << "\n";
+		if(sg_iter_ >= 0)
+			std::cout << "\tSG Iter: " << sg_iter_ << "\n";
+		if(sg_size_ >= 0)
+			std::cout << "\tSG Size: " << sg_size_ << "\n";
+		if(sg_inst_ >= 0)
+			std::cout << "\tSG Inst: " << sg_inst_ << "\n";
+	}
+
+	// Check consistency of two graph size objects:
+	bool consistent(GSize *gsize) {
+
+		// Compare number of nodes (if defined in both objects):
+		if(num_nodes_ != -1 && gsize->num_nodes_ != -1) {
+			if(num_nodes_ != gsize->num_nodes_)
+				return false;
+		}
+
+		// Compare number of edges:
+		if(num_edges_ != -1 && gsize->num_edges_ != -1) {
+			if(num_edges_ != gsize->num_edges_)
+				return false;
+		}
+
+		// Compare transitive closure iterations:
+		if(tc_iter_ != -1 && gsize->tc_iter_ != -1) {
+			if(tc_iter_ != gsize->tc_iter_)
+				return false;
+		}
+
+		// Compare transitive closure size:
+		if(tc_size_ != -1 && gsize->tc_size_ != -1) {
+			if(tc_size_ != gsize->tc_size_)
+				return false;
+		}
+
+		// Compare transitive closure rule instances:
+		if(tc_inst_ != -1 && gsize->tc_inst_ != -1) {
+			if(tc_inst_ != gsize->tc_inst_)
+				return false;
+		}
+
+		// Compare same generation iterations:
+		if(sg_iter_ != -1 && gsize->sg_iter_ != -1) {
+			if(sg_iter_ != gsize->sg_iter_)
+				return false;
+		}
+
+		// Compare same generation size:
+		if(sg_size_ != -1 && gsize->sg_size_ != -1) {
+			if(sg_size_ != gsize->sg_size_)
+				return false;
+		}
+
+		// Compare same generation rule instances:
+		if(sg_inst_ != -1 && gsize->sg_inst_ != -1) {
+			if(sg_inst_ != gsize->sg_inst_)
+				return false;
+		}
+
+		// Ok:
+		return true;
+	}
+
+	// Attributes:
+	private:
+	int      num_nodes_;
+	int      num_edges_;
+	bigint_t tc_size_;
+	int      tc_iter_;
+	bigint_t tc_inst_;
+	bigint_t sg_size_;
+	int      sg_iter_;
+	bigint_t sg_inst_;
+};
+
+//-----------------------------------------------------------------------------
+// Pointer Type for Graph Size Data:
+//-----------------------------------------------------------------------------
+
+typedef GSize *gsize_t;
+
+#define GSIZE_NULL (static_cast<gsize_t>(0))
+
+
+//=============================================================================
+// Type for Nodes in a Graph:
+//=============================================================================
+
+// In order to make the algorithms for computing problem sizes independent
+// from the data structures used for representing graphs, we define a type
+// for graph nodes here.
+// Currently, the graph nodes are represented as positive integers starting
+// from 1.
+// The graph data structures use a linked list of bitmaps to represent
+// sets of nodes.
+// These bitmaps could also represent the number 0, which is not used.
+// However, it would complicate the programs, and probably slow down them,
+// to distinguish between bit positions (starting from 0) and node numbers
+// (starting from 1).
+
+typedef int node_t;
+
+#define NODE_NULL	0
+
 //=============================================================================
 // Class for Linked List Element in Node Set (contains bit array):
 //=============================================================================
@@ -371,7 +534,7 @@ long str_int(str_t digits) {
 class NodeSetElem {
 	public:
 
-	// Constructor:
+	// Normal Constructor:
 	NodeSetElem(int start_value)
 	{
 		next_  = (NodeSetElem *) 0;
@@ -381,6 +544,16 @@ class NodeSetElem {
 			*p++ = '\0';
 	}
 
+	// Constructor that copies a given node (except next pointer):
+	NodeSetElem(NodeSetElem *elem) {
+		next_  = (NodeSetElem *) 0;
+		start_ = elem->start_;
+		unsigned char *to   = bits_;
+		unsigned char *from = elem->bits_;
+		for(int i = BITSTRING_BYTES; i > 0; i--)
+			*to++ = *from++;
+	}
+
 	// Get start node number (to be added to all numbers in bit array):
 	inline int start() const {
 		return start_;
@@ -399,21 +572,15 @@ class NodeSetElem {
 	// Get bit in bit array:
 	inline bool bit(int index) const {
 
-		// Check validity, part I:
-		if(index < 0) {
-			std::cerr << "get_bit: Invalid bit index (negative)!";
-			exit(3);
-		}
+		// Check validity of parameter, part I:
+		assert(index >= 0);
 
 		// Determine position in bit array:
 		int bit_no = index % 8;
 		index = index / 8;
 
-		// Check parameter, part II:
-		if(index >= BITSTRING_BYTES) {
-			std::cerr << "get_bit: Invalid bit index (too large)!";
-			exit(4);
-		}
+		// Check parameter of parameter, part II:
+		assert(index < BITSTRING_BYTES);
 
 		// Get bit:
 		return (bits_[index] & ((0x1) << bit_no)) != 0;
@@ -422,21 +589,15 @@ class NodeSetElem {
 	// Set bit in bit array:
 	inline void set_bit(int index) {
 
-		// Check validity, part I:
-		if(index < 0) {
-			std::cerr << "set_bit: Invalid bit index (negative)!";
-			exit(5);
-		}
+		// Check validity of parameter, part I:
+		assert(index >= 0);
 
 		// Determine position in bit array:
 		int bit_no = index % 8;
 		index = index / 8;
 
-		// Check parameter, part II:
-		if(index >= BITSTRING_BYTES) {
-			std::cerr << "set_bit: Invalid bit index (too large)!";
-			exit(6);
-		}
+		// Check parameter of parameter, part II:
+		assert(index < BITSTRING_BYTES);
 
 		// Set bit:
 		bits_[index] |= (0x1) << bit_no;
@@ -445,21 +606,15 @@ class NodeSetElem {
 	// Find next set bit in bit array with position >= index:
 	inline int next_bit(int index) {
 
-		// Check validity, part I:
-		if(index < 0) {
-			std::cerr << "next_bit: Invalid bit index (negative)!";
-			exit(7);
-		}
+		// Check validity of parameter, part I:
+		assert(index >= 0);
 
 		// Determine position in bit array:
 		int bit_no = index % 8;
 		index = index / 8;
 
 		// Check parameter, part II:
-		if(index >= BITSTRING_BYTES) {
-			std::cerr << "next_bit: Invalid bit index (too large)!";
-			exit(8);
-		}
+		assert(index < BITSTRING_BYTES);
 
 		// Find next set bit (-1 if there is no further bit):
 		unsigned char byte = bits_[index];
@@ -524,6 +679,18 @@ class NodeSetElem {
 		return -1;
 	}
 
+	// Copy start and bitmap from another element (sets next to null):
+	inline void copy_data(NodeSetElem *other_elem) {
+		next_  = static_cast<NodeSetElem *>(0);
+		start_ = other_elem->start_;
+
+		// Copy bitmap:
+		unsigned char *from = other_elem->bits_;
+		unsigned char *to   = bits_;
+		for(int i = BITSTRING_BYTES; i-- > 0; )
+			*to++ = *from++;
+	}
+
 	// Attributes:
 	private:
 	NodeSetElem *next_;
@@ -541,78 +708,10 @@ typedef NodeSetElem *node_set_elem_t;
 
 
 //=============================================================================
-// Class for Scan/Cursor over Node Set (set of non-negative integers):
+// Forward declaration for NodeSetScan:
 //=============================================================================
 
-class NodeSetScan {
-	public:
-
-	// Constructor:
-	NodeSetScan(node_set_elem_t list)
-	{
-		list_ = list;
-		curr_elem_  = list;
-		if(curr_elem_ != NODE_SET_ELEM_NULL)
-			start_ = curr_elem_->start();
-		else
-			start_ = 0;
-		next_index_ = 0;
-	}
-
-	// Get next node number in set (-1 if there is no further element):
-	int next() {
-		// Check whether we are at the end of the list:
-		if(curr_elem_ == NODE_SET_ELEM_NULL)
-			return -1;
-
-		// Try to find next value in current list element:
-		if(next_index_ < BITSTRING_BYTES * 8) {
-			int bit = curr_elem_->next_bit(next_index_);
-			if(bit >= 0) {
-				next_index_ = bit + 1;
-				return start_ + bit;
-			}
-		}
-
-		// Move to next list element:
-		curr_elem_ = curr_elem_->next();
-		if(curr_elem_ == NODE_SET_ELEM_NULL)
-			return -1;
-
-		// We know that list elements are non-empty:
-		start_ = curr_elem_->start();
-		int bit = curr_elem_->next_bit(next_index_);
-		next_index_ = bit + 1;
-		return start_ + bit;
-	}
-
-	// Reset scan to start:
-	void reset() {
-		curr_elem_ = list_;
-		if(curr_elem_ != NODE_SET_ELEM_NULL)
-			start_ = curr_elem_->start();
-		else
-			start_ = 0;
-		next_index_ = 0;
-	}
-
-	// Attributes:
-	private:
-	node_set_elem_t list_;
-	node_set_elem_t curr_elem_;
-	int start_;
-	int next_index_;
-};
-
-//-----------------------------------------------------------------------------
-// Pointer Type for Node Number List Element:
-//-----------------------------------------------------------------------------
-
-typedef NodeSetScan *node_set_scan_t;
-
-#define NODE_SET_SCAN_NULL (static_cast<node_set_scan_t>(0))
-
-
+class NodeSetScan;
 
 //=============================================================================
 // Class for Node Set (represented as linked list of bit arrays):
@@ -632,15 +731,16 @@ class NodeSet {
 
 	// Destructor:
 	~NodeSet() {
-		node_set_elem_t next = NODE_SET_ELEM_NULL;
-		for(node_set_elem_t elem = list_; elem; elem = next) {
-			next = elem->next();
-			delete elem;
-		}
+		free_list(list_);
 	}
 
 	// Insert a node number:
-	void insert(int n) {
+	void insert(node_t n) {
+
+		// Check parameter:
+		assert(n >= 1);
+
+		// Compute position in bitmap list:
 		int start = n / (BITSTRING_BYTES * 8);
 		int index = n % (BITSTRING_BYTES * 8);
 
@@ -694,9 +794,16 @@ class NodeSet {
 	}
 
 	// Check whether a nonnegative integer exists in the set:
-	bool contains(int n) {
+	bool contains(node_t n) {
+
+		// Check parameter:
+		assert(n >= 1);
+
+		// Compute position in bitmap list:
 		int start = n / (BITSTRING_BYTES * 8);
 		int index = n % (BITSTRING_BYTES * 8);
+
+		// Search list element with requested start value:
 		for(node_set_elem_t elem = list_; elem; elem = elem->next()) {
 			int elem_start = elem->start();
 			if(elem_start == start)
@@ -704,318 +811,308 @@ class NodeSet {
 			if(elem_start > start)
 				return false;
 		}
+		return false;
 	}
 
-	// Attributes:
-	private:
-	node_set_elem_t list_;
-};
+	// Check whether node set is empty:
+	inline bool is_empty() {
+		// List elements are only constructed when needed,
+		// i.e. there are no empty bitmaps.
+		return list_ == NODE_SET_ELEM_NULL;
+	}
 
-//-----------------------------------------------------------------------------
-// Pointer Type for Node Set (really a set of non-negative integers):
-//-----------------------------------------------------------------------------
+	// Copy a given node set into this node set (overwrites existing data):
+	void copy(NodeSet *node_set) {
 
-typedef NodeSet *node_set_t;
+		// The current list is only used as recycle material for
+		// NodeSetElem objects.
+		// The objects themselves are overwritten.
+		// Currently, all calls to the copy function are called
+		// with a superset of nodes. This is not a requirement,
+		// but this motivates that the NodeSet does not keep its
+		// own free list, but directly deletes any superfluous nodes.
+		// With the current usage, this will anyway not happen.
 
-#define NODE_SET_NULL (static_cast<node_set_t>(0))
+		// List of nodes to be used:
+		node_set_elem_t nodes = list_;
 
-//=============================================================================
-// Class for Graph Nodes (one line of the adjacency matrix):
-//=============================================================================
+		// prev is the previous element of the list that is built.
+		// If it is null, then the start (attribute list_) must be set.
+		node_set_elem_t prev = NODE_SET_ELEM_NULL;
 
-class Node {
-	public:
+		// Copy list, using existing nodes:
+		node_set_elem_t from = node_set->list_;
+		for( ; from && nodes; from = from->next()) {
 
-	// Constructor:
-	Node(int graph_num_nodes)
-	{
-		num_nodes_ = graph_num_nodes;
-		int bytes = (num_nodes_ + BYTE_SIZE - 1) / BYTE_SIZE;
-		connections_ = new char[bytes];
-		char *p = connections_;
-		for(int i = bytes; i > 0; i--)
-			*p++ = '\0';
-	}
+			// Get node from recycle list:
+			node_set_elem_t elem = nodes;
+				nodes = nodes->next();
 
-	// Accessor Functions:
-	inline int num_nodes() const { return num_nodes_; }
+			// Copy node (except next pointer):
+			elem->copy_data(from);
 
-	// Store edge in adjacency matrix:
-	void store_connection(int to) {
-		// Check nodes:
-		if(to <= 0 || to > num_nodes_) {
-			std::cerr << "Invalid to node: " << to << "\n";
-			exit(3);
+			// Link new element to constructed list:
+			if(prev == NODE_SET_ELEM_NULL)
+				list_ = elem;
+			else
+				prev->set_next(elem);
+
+			// The copied node is now the previous node:
+			prev = elem;
 		}
 
-		// Determine position in adjacency matrix:
-		long index = to - 1;
-		int bit = index % 8;
-		index = index / 8;
+		// For the remaining elements, allocate new nodes:
+		for( ; from; from = from->next()) {
+			node_set_elem_t elem = new NodeSetElem(from);
 
-		// Set bit:
-		connections_[index] |= (0x1) << bit;
-	}
+			// Link new element to "to" list (via prev):
+			if(prev == NODE_SET_ELEM_NULL)
+				list_ = elem;
+			else
+				prev->set_next(elem);
 
-	// Check whether edge exists:
-	bool connection_exists(int to) const {
-		// Check node:
-		if(to <= 0 || to > num_nodes_) {
-			std::cerr << "Invalid to node: " << to << "\n";
-			exit(4);
+			// The previous element pointer is always one behind:
+			prev = elem;
 		}
 
-		// Determine position in adjacency matrix:
-		long index = to - 1;
-		int bit = index % 8;
-		index = index / 8;
-
-		// Check bit:
-		return (connections_[index] & ((0x1) << bit)) != 0;
+		// If from list is shorter, delete remaining recycle elements:
+		free_list(nodes);
 	}
 
-	// Copy other node into this node:
-	void copy(Node *node) {
-		if(node->num_nodes_ != num_nodes_) {
-			std::cerr << "Can copy only node of same size!\n";
-			exit(5);
+	// Auxiliary function to free all (remaining) list elements:
+	private:
+	void free_list(node_set_elem_t list) {
+		node_set_elem_t next;
+		for(node_set_elem_t elem = list; elem; elem = next) {
+			next = elem->next();
+			delete elem;
 		}
-		int bytes = (num_nodes_ + BYTE_SIZE - 1) / BYTE_SIZE;
-		char *to = connections_;
-		char *from = node->connections_;
-		while(bytes-- > 0)
-			*to++ = *from++;
 	}
 
 	// Attributes:
 	private:
-	int num_nodes_;
-	char *connections_;
+	node_set_elem_t list_;
+
+	// The NodeSetScan constructor and reset must be able to access list_:
+	friend NodeSetScan;
 };
 
 //-----------------------------------------------------------------------------
-// Pointer Type for Node Data:
+// Pointer Type for Node Set (really a set of non-negative integers):
 //-----------------------------------------------------------------------------
 
-typedef Node *node_t;
+typedef NodeSet *node_set_t;
 
-#define NODE_NULL (static_cast<node_t>(0))
+#define NODE_SET_NULL (static_cast<node_set_t>(0))
 
 
 //=============================================================================
-// Class for Graphs (contains adjacency matrix):
+// Class for Scan/Cursor over Node Set (set of non-negative integers):
 //=============================================================================
 
-class Graph {
+class NodeSetScan {
 	public:
 
 	// Constructor:
-	Graph(int graph_num_nodes)
+	NodeSetScan(NodeSet *node_set)
 	{
-		num_nodes_ = graph_num_nodes;
-		nodes_ = new node_t[num_nodes_];
-		for(int i = 0; i < graph_num_nodes; i++)
-			nodes_[i] = new Node(graph_num_nodes);
-	}
-
-	// Accessor Functions:
-	inline int num_nodes() const { return num_nodes_; }
-	inline node_t node(int i) const { return nodes_[i-1]; }
+		// Access is permitted by friend declaration in NodeSet:
+		node_set_ = node_set;
 
-	// Store edge in adjacency matrix:
-	void store_edge(int from, int to) {
-		// Check nodes:
-		if(from <= 0 || from > num_nodes_) {
-			std::cerr << "Invalid from node: " << from << "\n";
-			exit(6);
-		}
-		if(to <= 0 || to > num_nodes_) {
-			std::cerr << "Invalid to node: " << to << "\n";
-			exit(7);
-		}
+		// Set current bitmap list elem:
+		curr_elem_  = node_set_->list_;
+		if(curr_elem_ != NODE_SET_ELEM_NULL)
+			start_ = curr_elem_->start();
+		else
+			start_ = 0;
 
-		// Store edge in adjacency matrix:
-		long index = from - 1;
-		nodes_[index]->store_connection(to);
+		// Next bit that will be checked in current bitmap list elem:
+		next_index_ = 0;
 	}
 
-	// Check whether edge exists:
-	bool edge_exists(int from, int to) const {
-		// Check nodes:
-		if(from <= 0 || from > num_nodes_) {
-			std::cerr << "Invalid from node: " << from << "\n";
-			exit(8);
-		}
-		if(to <= 0 || to > num_nodes_) {
-			std::cerr << "Invalid to node: " << to << "\n";
-			exit(9);
+	// Get next node number in set (-1 if there is no further element):
+	node_t next() {
+		// Check whether we are at the end of the list:
+		if(curr_elem_ == NODE_SET_ELEM_NULL)
+			return NODE_NULL;
+
+		// Try to find next value in current list element:
+		if(next_index_ < BITSTRING_BYTES * 8) {
+			int bit = curr_elem_->next_bit(next_index_);
+			if(bit >= 0) {
+				next_index_ = bit + 1;
+				return start_ + bit;
+			}
 		}
 
-		// Look up edge in adjacency matrix:
-		long index = from - 1;
-		return nodes_[index]->connection_exists(to);
+		// Move to next list element:
+		curr_elem_ = curr_elem_->next();
+		if(curr_elem_ == NODE_SET_ELEM_NULL)
+			return NODE_NULL;
+
+		// We know that list elements are non-empty:
+		start_ = curr_elem_->start();
+		int bit = curr_elem_->next_bit(next_index_);
+		next_index_ = bit + 1;
+		return start_ + bit;
 	}
 
-	// Copy a graph (of the same size) into this graph:
-	void copy(Graph *g)
-	{
-		if(g->num_nodes_ != num_nodes_) {
-			std::cerr << "Can copy only graph of same size!\n";
-			exit(10);
-		}
-		for(int i = 0; i < num_nodes_; i++)
-			nodes_[i]->copy(g->nodes_[i]);
+	// Reset scan to start:
+	void reset() {
+		curr_elem_ = node_set_->list_;
+		if(curr_elem_ != NODE_SET_ELEM_NULL)
+			start_ = curr_elem_->start();
+		else
+			start_ = 0;
+		next_index_ = 0;
 	}
 
 	// Attributes:
 	private:
-	int num_nodes_;
-	node_t *nodes_;
+	node_set_t node_set_;
+	node_set_elem_t curr_elem_;
+	int start_;
+	int next_index_;
 };
 
 //-----------------------------------------------------------------------------
-// Pointer Type for Graph Data:
+// Pointer Type for Node Set Scan:
 //-----------------------------------------------------------------------------
 
-typedef Graph *graph_t;
+typedef NodeSetScan *node_set_scan_t;
 
-#define GRAPH_NULL (static_cast<graph_t>(0))
+#define NODE_SET_SCAN_NULL (static_cast<node_set_scan_t>(0))
 
+//-----------------------------------------------------------------------------
+// Macro for Loops over the Nodes in a Node Set Scan:
+//-----------------------------------------------------------------------------
+
+#define NODE_LOOP(N, S)	for(node_t N = S.next(); N != NODE_NULL; N = S.next())
 
 //=============================================================================
-// Class for Graph/Benchmark Size Measures:
+// Class for Graphs:
 //=============================================================================
 
-class GSize {
+class Graph {
 	public:
 
 	// Constructor:
-	GSize()
+	Graph(int graph_num_nodes) : out_nodes_()
 	{
-		num_nodes_  = -1;
-		num_edges_  = -1;
-		tc_size_    = -1;
-		tc_iter_    = -1;
-		tc_inst_    = -1;
-		sg_size_    = -1;
-		sg_iter_    = -1;
-		sg_inst_    = -1;
+		num_nodes_ = graph_num_nodes;
+		incoming_  = new NodeSet[num_nodes_ + 1];// Index 0 is not used
+		outgoing_  = new NodeSet[num_nodes_ + 1];// Index 0 is not used
+		changed_   = false;
 	}
 
 	// Accessor Functions:
-	inline int      num_nodes() const { return num_nodes_; }
-	inline int      num_edges() const { return num_edges_; }
-	inline bigint_t tc_size()   const { return tc_size_; }
-	inline int      tc_iter()   const { return tc_iter_; }
-	inline bigint_t tc_inst()   const { return tc_inst_; }
-	inline bigint_t sg_size()   const { return sg_size_; }
-	inline int      sg_iter()   const { return sg_iter_; }
-	inline bigint_t sg_inst()   const { return sg_inst_; }
+	inline int num_nodes() const { return num_nodes_; }
 
-	// Set functions:
-	inline void set_num_nodes(int n)    { num_nodes_ = n; }
-	inline void set_num_edges(int n)    { num_edges_ = n; }
-	inline void set_tc_size(bigint_t n) { tc_size_   = n; }
-	inline void set_tc_iter(int n)      { tc_iter_   = n; }
-	inline void set_tc_inst(bigint_t n) { tc_inst_   = n; }
-	inline void set_sg_size(bigint_t n) { sg_size_   = n; }
-	inline void set_sg_iter(int n)      { sg_iter_   = n; }
-	inline void set_sg_inst(bigint_t n) { sg_inst_   = n; }
+	// Store edge in adjacency matrix:
+	void store_edge(node_t from, node_t to) {
 
-	// Print defined values:
-	void print() {
-		if(num_nodes_ >= 0)
-			std::cout << "\tNodes:   " << num_nodes_ << "\n";
-		if(num_edges_ >= 0)
-			std::cout << "\tEdges:   " << num_edges_ << "\n";
-		if(tc_iter_ >= 0)
-			std::cout << "\tTC Iter: " << tc_iter_ << "\n";
-		if(tc_size_ >= 0)
-			std::cout << "\tTC Size: " << tc_size_ << "\n";
-		if(tc_inst_ >= 0)
-			std::cout << "\tTC Inst: " << tc_inst_ << "\n";
-		if(sg_iter_ >= 0)
-			std::cout << "\tSG Iter: " << sg_iter_ << "\n";
-		if(sg_size_ >= 0)
-			std::cout << "\tSG Size: " << sg_size_ << "\n";
-		if(sg_inst_ >= 0)
-			std::cout << "\tSG Inst: " << sg_inst_ << "\n";
+		// Check nodes:
+		assert(from > 0);
+		assert(from <= num_nodes_);
+		assert(to > 0);
+		assert(to <= num_nodes_);
+
+		// Store edge:
+		incoming_[to].insert(from);
+		outgoing_[from].insert(to);
+
+		// Mark change:
+		changed_ = true;
 	}
 
-	// Check consistency of two graph size objects:
-	bool consistent(GSize *gsize) {
+	// Check whether edge exists:
+	bool edge_exists(node_t from, node_t to) const {
 
-		// Compare number of nodes (if defined in both objects):
-		if(num_nodes_ != -1 && gsize->num_nodes_ != -1) {
-			if(num_nodes_ != gsize->num_nodes_)
-				return false;
-		}
+		// Check nodes:
+		assert(from > 0);
+		assert(from <= num_nodes_);
+		assert(to > 0);
+		assert(to <= num_nodes_);
 
-		// Compare number of edges:
-		if(num_edges_ != -1 && gsize->num_edges_ != -1) {
-			if(num_edges_ != gsize->num_edges_)
-				return false;
-		}
+		// Look up edge:
+		return outgoing_[from].contains(to);
+	}
 
-		// Compare transitive closure iterations:
-		if(tc_iter_ != -1 && gsize->tc_iter_ != -1) {
-			if(tc_iter_ != gsize->tc_iter_)
-				return false;
-		}
+	// Return set of nodes reachable from a given node:
+	node_set_t outgoing(node_t from) const {
 
-		// Compare transitive closure size:
-		if(tc_size_ != -1 && gsize->tc_size_ != -1) {
-			if(tc_size_ != gsize->tc_size_)
-				return false;
-		}
+		// Check parameter node:
+		assert(from > 0);
+		assert(from <= num_nodes_);
 
-		// Compare transitive closure rule instances:
-		if(tc_inst_ != -1 && gsize->tc_inst_ != -1) {
-			if(tc_inst_ != gsize->tc_inst_)
-				return false;
-		}
+		// Look up edge:
+		return &(outgoing_[from]);
+	}
 
-		// Compare same generation iterations:
-		if(sg_iter_ != -1 && gsize->sg_iter_ != -1) {
-			if(sg_iter_ != gsize->sg_iter_)
-				return false;
-		}
 
-		// Compare same generation size:
-		if(sg_size_ != -1 && gsize->sg_size_ != -1) {
-			if(sg_size_ != gsize->sg_size_)
-				return false;
-		}
+	// Access the set of nodes from which this node is reachable:
+	node_set_t incoming(node_t to) {
 
-		// Compare same generation rule instances:
-		if(sg_inst_ != -1 && gsize->sg_inst_ != -1) {
-			if(sg_inst_ != gsize->sg_inst_)
-				return false;
+		// Check parameter node:
+		assert(to > 0);
+		assert(to <= num_nodes_);
+
+		// Return set of nodes:
+		return &(incoming_[to]);
+	}
+
+	// Access the set of nodes that have at least one outgoing edge:
+	node_set_t out_nodes() {
+
+		// Usually, this is only called after the graph was fully
+		// constructed.
+		// Therefore, it seems more efficient to compute the node set
+		// only once instead of doing an insertion for every inserted
+		// edge.
+
+		// Do we need to recompute the set?
+		if(changed_) {
+			for(int i = 1; i <= num_nodes_; i++) {
+				if(!outgoing_[i].is_empty())
+					out_nodes_.insert(i);
+			}
+			changed_ = false;
 		}
 
-		// Ok:
-		return true;
+		// Return precomputed node set:
+		return &out_nodes_;
+	}
+
+	// Copy a graph (of the same size) into this graph:
+	void copy(Graph *g)
+	{
+		if(g->num_nodes_ != num_nodes_) {
+			std::cerr << "Can copy only graph of same size!\n";
+			exit(10);
+		}
+		for(int i = 1; i <= num_nodes_; i++) {
+			incoming_[i].copy(&(g->incoming_[i]));
+			outgoing_[i].copy(&(g->outgoing_[i]));
+		}
+		changed_ = true;
 	}
 
 	// Attributes:
 	private:
-	int      num_nodes_;
-	int      num_edges_;
-	bigint_t tc_size_;
-	int      tc_iter_;
-	bigint_t tc_inst_;
-	bigint_t sg_size_;
-	int      sg_iter_;
-	bigint_t sg_inst_;
+	int num_nodes_;
+	bool changed_;
+	node_set_t incoming_;
+	node_set_t outgoing_;
+	NodeSet out_nodes_;
 };
 
 //-----------------------------------------------------------------------------
-// Pointer Type for Graph Size Data:
+// Pointer Type for Graph Data:
 //-----------------------------------------------------------------------------
 
-typedef GSize *gsize_t;
+typedef Graph *graph_t;
 
-#define GSIZE_NULL (static_cast<gsize_t>(0))
+#define GRAPH_NULL (static_cast<graph_t>(0))
 
 
 //=============================================================================
@@ -1037,15 +1134,16 @@ class TC {
 		iter_ = 0;
 		num_edges_ = 0;
 
-		// Compute transitive closure:
+		// Compute transitive closure. First nonrecursive rule:
 		bool changed = false;
 		std::cout << "Iteration 0.\n";
-		for(int i = 1; i <= num_nodes_; i++) {
-			node_t input_node = input_->node(i);
-			node_t tc_node = tc_->node(i);
-			for(int j = 1; j <= num_nodes_; j++) {
-				if(input_node->connection_exists(j)) {
-					tc_node->store_connection(j);
+		{ // xs is used locally in this rule (avoids shadowing warning)
+			// tc(X, Y) :- input(X,Y).
+			NodeSetScan xs(input_->out_nodes());
+			NODE_LOOP(x, xs) {
+				NodeSetScan ys(input_->outgoing(x));
+				NODE_LOOP(y, ys) {
+					tc_->store_edge(x, y);
 					rule_inst_++;
 					tc_size_++;
 					num_edges_++;
@@ -1060,23 +1158,16 @@ class TC {
 			changed = false;
 			tc_prev_->copy(tc_);
 			iter_++;
-			for(int i = 1; i <= num_nodes_; i++) {
-				node_t par_x = input_->node(i);
-				node_t tc_x = tc_->node(i);
-				for(int j = 1; j <= num_nodes_; j++) {
-					if(!par_x->connection_exists(j))
-						continue;
-					node_t tc_y = tc_prev_->node(j);
-					for(int k = 1; k <= num_nodes_; k++) {
-						if(!tc_y->connection_exists(k))
-							continue;
-						if(tc_x->connection_exists(k))
-							continue;
-						// I.e. conditions are:
-						// input_->edge_exists(i,j)
-						// tc_prev_->edge_exists(j,k)
-						// !tc_->edge_exists(i,k))
-						tc_x->store_connection(k);
+			// tc(X, Z) :- input(X,Y), tc_prev(Y, Z).
+			NodeSetScan xs(input_->out_nodes());
+			NODE_LOOP(x, xs) {
+				NodeSetScan ys(input_->outgoing(x));
+				NODE_LOOP(y, ys) {
+					NodeSetScan zs(tc_prev_->outgoing(y));
+					NODE_LOOP(z, zs) {
+						if(tc_->edge_exists(x,z))
+							continue; // duplicate
+						tc_->store_edge(x,z);
 						tc_size_++;
 						changed = true;
 					}
@@ -1087,15 +1178,12 @@ class TC {
 		// Computation of Rule Instances:
 		std::cout << "Computation of Rule Instances ...\n";
 		// Instances of the non-recursive rule were counted above.
-		for(int i = 1; i <= num_nodes_; i++) {
-			node_t par_x = input_->node(i);
-			for(int j = 1; j <= num_nodes_; j++) {
-				if(!par_x->connection_exists(j))
-					continue;
-				node_t tc_y = tc_->node(j);
-				for(int k = 1; k <= num_nodes_; k++) {
-					if(!tc_y->connection_exists(k))
-						continue;
+		NodeSetScan xs(input_->out_nodes());
+		NODE_LOOP(x, xs) {
+			NodeSetScan ys(input_->outgoing(x));
+			NODE_LOOP(y, ys) {
+				NodeSetScan zs(tc_->outgoing(y));
+				NODE_LOOP(z, zs) {
 					rule_inst_++;
 				}
 			}
@@ -1120,13 +1208,12 @@ class TC {
 
 	// Print TC:
 	void print() {
-		for(int i = 1; i <= num_nodes_; i++) {
-			node_t node = tc_->node(i);
-			for(int j = 1; j <= num_nodes_; j++) {
-				if(node->connection_exists(j)) {
-					std::cout << "\ttc(" << i << "," << j <<
+		NodeSetScan xs(tc_->out_nodes());
+		NODE_LOOP(x, xs) {
+			NodeSetScan ys(tc_->outgoing(x));
+			NODE_LOOP(y, ys) {
+				std::cout << "\ttc(" << x << "," << y <<
 							").\n";
-				}
 			}
 		}
 		std::cout << "\n";
@@ -1175,18 +1262,19 @@ class SG {
 		// Compute same generation cousins:
 		bool changed = false;
 		std::cout << "Iteration 0.\n";
-		for(int i = 1; i <= num_nodes_; i++) {
-			node_t input_node = input_->node(i);
-			for(int j = 1; j <= num_nodes_; j++) {
-				if(input_node->connection_exists(j)) {
-					node_t sg_node = sg_->node(j);
-					if(!sg_node->connection_exists(j)) {
-						sg_node->store_connection(j);
-						sg_size_++;
-						changed = true;
-					}
-					rule_inst_++;
+		// sg(Y, Y) :- input(X, Y).
+		{ // xs is used locally in this rule (avoids shadowing warning)
+			NodeSetScan xs(input_->out_nodes());
+			NODE_LOOP(x, xs) {
+				NodeSetScan ys(input_->outgoing(x));
+				NODE_LOOP(y, ys) {
 					num_edges_++;
+					rule_inst_++;
+					if(sg_->edge_exists(y, y))
+						continue; // duplicate
+					sg_->store_edge(y, y);
+					sg_size_++;
+					changed = true;
 				}
 			}
 		}
@@ -1201,30 +1289,21 @@ class SG {
 			rec_inst = 0;
 			sg_prev_->copy(sg_);
 			iter_++;
-			for(int i = 1; i <= num_nodes_; i++) {
-				node_t sg_prev_i = sg_prev_->node(i);
-				for(int j = 1; j <= num_nodes_; j++) {
-					if(!sg_prev_i->connection_exists(j))
-						continue;
-					for(int i2 = 1; i2 <= num_nodes_; i2++){
-						if(!input_->edge_exists(i2,i))
-							continue;
-						for(int j2 = 1;
-							j2 <= num_nodes_;
-							j2++){
-							if(!input_->
-							    edge_exists(j2,j))
-								continue;
+			// sg(X, Y) :- input(X, A), sg(A, B), input(Y, B).
+			NodeSetScan as(sg_prev_->out_nodes());
+			NODE_LOOP(a, as) {
+				NodeSetScan bs(sg_prev_->outgoing(a));
+				NODE_LOOP(b, bs) {
+					NodeSetScan xs(input_->incoming(a));
+					NODE_LOOP(x, xs) {
+						NodeSetScan ys(
+							input_->incoming(b));
+						NODE_LOOP(y, ys) {
 							rec_inst++;
 							if(sg_->
-							    edge_exists(i2,j2))
+							    edge_exists(x,y))
 								continue;
-						// I.e. conditions are:
-						// sg_prev_->edge_exists(i,j)
-						// input_->edge_exists(i2,i)
-						// input_->edge_exists(j2,j)
-						// !sg_->edge_exists(i2,j2))
-							sg_->store_edge(i2,j2);
+							sg_->store_edge(x,y);
 							sg_size_++;
 							changed = true;
 						}
@@ -1235,6 +1314,9 @@ class SG {
 
 		// Add instances of recursive rule to rule instances:
 		rule_inst_ += rec_inst;
+			// Note that this is outside the iteration.
+			// I.e. it is the number of rule instances
+			// considered in the last iteration.
 	}
 
 	// Accessor Functions:
@@ -1255,13 +1337,12 @@ class SG {
 
 	// Print SG:
 	void print() {
-		for(int i = 1; i <= num_nodes_; i++) {
-			node_t node = sg_->node(i);
-			for(int j = 1; j <= num_nodes_; j++) {
-				if(node->connection_exists(j)) {
-					std::cout << "\tsg(" << i << "," << j <<
-							").\n";
-				}
+		NodeSetScan xs(sg_->out_nodes());
+		NODE_LOOP(x, xs) {
+			NodeSetScan ys(sg_->outgoing(x));
+			NODE_LOOP(y, ys) {
+				std::cout << "\tsg(" << x << "," << y <<
+						").\n";
 			}
 		}
 		std::cout << "\n";