// ==========================================================================
//                 SeqAn - The Library for Sequence Analysis
// ==========================================================================
// Copyright (c) 2006-2013, Knut Reinert, FU Berlin
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of Knut Reinert or the FU Berlin nor the names of
//       its contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL KNUT REINERT OR THE FU BERLIN BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
// DAMAGE.
//
// ==========================================================================

#ifndef SEQAN_HEADER_TEST_GRAPH_TYPES_H
#define SEQAN_HEADER_TEST_GRAPH_TYPES_H

using namespace seqan;

void Test_Directed() {
//____________________________________________________________________________
// Graph without edge cargo but with edge ids

	typedef Graph<Directed<> > StandardGraph;
	typedef VertexDescriptor<StandardGraph>::Type TVertexDescriptor;
	typedef EdgeDescriptor<StandardGraph>::Type TEdgeDescriptor;
	
	StandardGraph g;
	SEQAN_ASSERT(numVertices(g) == 0);
	SEQAN_ASSERT(numEdges(g) == 0);
	SEQAN_ASSERT(empty(g) == true);

	// Add vertex
	TVertexDescriptor v0 = addVertex(g);
	SEQAN_ASSERT(v0 == 0);
	SEQAN_ASSERT(outDegree(g, v0) == 0);	
	SEQAN_ASSERT(inDegree(g, 0) == 0);
	SEQAN_ASSERT(degree(g, 0) == 0);
	SEQAN_ASSERT(numVertices(g) == 1);
	SEQAN_ASSERT(empty(g) == false);
	
	// Add edge
	TEdgeDescriptor e1 =addEdge(g,v0,v0);
	SEQAN_ASSERT(findEdge(g, v0, v0) == e1);
	SEQAN_ASSERT(_getVertexString(g)[0] == e1);
	SEQAN_ASSERT(getIdUpperBound(_getVertexIdManager(g)) == 1);
	SEQAN_ASSERT(getIdUpperBound(_getEdgeIdManager(g)) == 1);
	SEQAN_ASSERT(targetVertex(g, e1) == 0);
	SEQAN_ASSERT(sourceVertex(g, e1) == 0);  //Expensive in standard graph!
	SEQAN_ASSERT(numEdges(g) == 1);
	SEQAN_ASSERT(outDegree(g, v0) == 1);	
	SEQAN_ASSERT(inDegree(g, v0) == 1);
	SEQAN_ASSERT(degree(g, v0) == 2);
	
	// Add further edges and vertices
	TVertexDescriptor v1 = addVertex(g);
	TEdgeDescriptor e2 =addEdge(g,0,1);
	SEQAN_ASSERT(v1 == 1);
	SEQAN_ASSERT(numVertices(g) == 2);
	SEQAN_ASSERT(targetVertex(g, e2) == 1);
	SEQAN_ASSERT(sourceVertex(g, e2) == 0);
	SEQAN_ASSERT(numEdges(g) == 2);
	SEQAN_ASSERT(outDegree(g, v0) == 2);	
	SEQAN_ASSERT(inDegree(g, 1) == 1);
	SEQAN_ASSERT(inDegree(g, 0) == 1);	
	SEQAN_ASSERT(degree(g, 0) == 3);
		
	// Add more vertices and edges
	addVertex(g);  //2
	TVertexDescriptor v3 = addVertex(g);  //3
	addVertex(g);  //4
	addEdge(g,3,4);
	TEdgeDescriptor my_edge = addEdge(g,3,1);
	addEdge(g,3,0);
	SEQAN_ASSERT(v3 == 3);
	SEQAN_ASSERT(numVertices(g) == 5);
	SEQAN_ASSERT(targetVertex(g, e2) == 1);
	SEQAN_ASSERT(sourceVertex(g, e2) == 0);
	SEQAN_ASSERT(targetVertex(g, my_edge) == 1);
	SEQAN_ASSERT(sourceVertex(g, my_edge) == 3);
	SEQAN_ASSERT(numEdges(g) == 5);
	SEQAN_ASSERT(outDegree(g, v3) == 3);	
	
	// Output
	std::stringstream sstream;
	sstream << g;
	char const * EXPECTED =
	    "Adjacency list:\n"
        "0 -> 1,0,\n"
        "1 -> \n"
        "2 -> \n"
        "3 -> 0,1,4,\n"
        "4 -> \n"
        "Edge list:\n"
        "Source: 0,Target: 1 (Id: 1)\n"
        "Source: 0,Target: 0 (Id: 0)\n"
        "Source: 3,Target: 0 (Id: 4)\n"
        "Source: 3,Target: 1 (Id: 3)\n"
        "Source: 3,Target: 4 (Id: 2)\n";
    SEQAN_ASSERT(EXPECTED == sstream.str());

	// Remove edges
	removeEdge(g,my_edge);
	removeEdge(g,0,1);
	SEQAN_ASSERT(numEdges(g) == 3);

	// Remove vertices 
	TEdgeDescriptor e3 = addEdge(g,3,3);
	addEdge(g,1,3);
	addEdge(g,0,3);
	addEdge(g,0,4);
	SEQAN_ASSERT(outDegree(g, 0) == 3);
	SEQAN_ASSERT(outDegree(g, 1) == 1);
	SEQAN_ASSERT(targetVertex(g, e3) == 3);
	SEQAN_ASSERT(sourceVertex(g, e3) == 3);
	removeVertex(g, v3);
	SEQAN_ASSERT(outDegree(g, 0) == 2);
	SEQAN_ASSERT(outDegree(g, 1) == 0);
	SEQAN_ASSERT(numVertices(g) == 4);
	SEQAN_ASSERT(numEdges(g) == 2);

	// Clear graph
	clearEdges(g);
	SEQAN_ASSERT(numVertices(g) == 4);
	SEQAN_ASSERT(numEdges(g) == 0);
	addEdge(g,2,0);
	addEdge(g,4,1);
	clearVertices(g);
	SEQAN_ASSERT(numVertices(g) == 0);
	SEQAN_ASSERT(numEdges(g) == 0);
	addVertex(g);addVertex(g);addVertex(g);
	addVertex(g);addVertex(g);
	addEdge(g,2,0);
	addEdge(g,4,1);
	clear(g);
	SEQAN_ASSERT(numVertices(g) == 0);
	SEQAN_ASSERT(numEdges(g) == 0);
	addVertex(g);addVertex(g);addVertex(g);
	addVertex(g);addVertex(g);
	addEdge(g,2,0);
	addEdge(g,4,1);
	addEdge(g,4,2);
	removeVertex(g,3);
	SEQAN_ASSERT(numVertices(g) == 4);
	SEQAN_ASSERT(numEdges(g) == 3);
	SEQAN_ASSERT(outDegree(g, 4) == 2);
	SEQAN_ASSERT(inDegree(g, 4) == 0);

	// Transpose
	transpose(g); 
	SEQAN_ASSERT(numVertices(g) == 4);
	SEQAN_ASSERT(numEdges(g) == 3);
	SEQAN_ASSERT(outDegree(g, 4) == 0);
	SEQAN_ASSERT(inDegree(g, 4) == 2);
	StandardGraph g_copy(g);
	SEQAN_ASSERT(numVertices(g_copy) == 4);
	SEQAN_ASSERT(numEdges(g_copy) == 3);
	SEQAN_ASSERT(outDegree(g_copy, 4) == 0);
	SEQAN_ASSERT(inDegree(g_copy, 4) == 2);
	addVertex(g_copy);
	addEdge(g_copy,3,0);
	g_copy = g;
	SEQAN_ASSERT(numVertices(g_copy) == 4);
	SEQAN_ASSERT(numEdges(g_copy) == 3);
	SEQAN_ASSERT(outDegree(g_copy, 4) == 0);
	SEQAN_ASSERT(inDegree(g_copy, 4) == 2);
	//Copies the graph and transposes just the copy
	transpose(g,g_copy);  // g does not change!
	SEQAN_ASSERT(numVertices(g_copy) == 4);
	SEQAN_ASSERT(numEdges(g_copy) == 3);
	SEQAN_ASSERT(outDegree(g_copy, 4) == 2);
	SEQAN_ASSERT(inDegree(g_copy, 4) == 0);
	removeVertex(g,0);



	// Adjacency matrix
	String<unsigned int> mat;
	getAdjacencyMatrix(g, mat);
	unsigned int len = (unsigned int) std::sqrt((double) length(mat));
	SEQAN_ASSERT(getValue(mat, 1*len+4) == 1);
	SEQAN_ASSERT(getValue(mat, 2*len+4) == 1);
	SEQAN_ASSERT(getValue(mat, 2*len+2) == 0);

//____________________________________________________________________________
//Graph with edge cargo and edge ids
	typedef Pair<char, int> TPair;
	typedef Directed<TPair> TEdges;
	typedef VertexDescriptor<Graph<TEdges> >::Type TVertexDescriptor2;
	typedef EdgeDescriptor<Graph<TEdges> >::Type TEdgeDescriptor2;

	Graph<TEdges> g2;
	SEQAN_ASSERT(numVertices(g2) == 0);
	SEQAN_ASSERT(numEdges(g2) == 0);
	TVertexDescriptor2 ver0 = addVertex(g2);
	SEQAN_ASSERT(ver0 == 0);
	SEQAN_ASSERT(numVertices(g2) == 1);
	TVertexDescriptor2 ver1 = addVertex(g2);
	SEQAN_ASSERT(ver1 == 1);
	SEQAN_ASSERT(numVertices(g2) == 2);
	TEdgeDescriptor2 ed1 =addEdge(g2,ver0,ver0, TPair('a',3));
	TEdgeDescriptor2 ed2 =addEdge(g2,0,1);
	SEQAN_ASSERT((getCargo(ed1)).i1 == 'a');
	SEQAN_ASSERT((getCargo(ed1)).i2 == 3);
	SEQAN_ASSERT(targetVertex(g2, ed1) == v0);
	SEQAN_ASSERT(targetVertex(g2, ed1) == 0);
	SEQAN_ASSERT(sourceVertex(g2, ed1) == 0);
	SEQAN_ASSERT(targetVertex(g2, ed2) == 1);
	SEQAN_ASSERT(numEdges(g2) == 2);
	assignCargo(ed2, TPair('b',4));
	SEQAN_ASSERT((getCargo(ed1)).i1 == 'a');
	SEQAN_ASSERT((getCargo(ed1)).i2 == 3);
	SEQAN_ASSERT((getCargo(ed2)).i1 == 'b');
	SEQAN_ASSERT((getCargo(ed2)).i2 == 4);
	cargo(ed1) = TPair('c',1);
	SEQAN_ASSERT((getCargo(ed1)).i1 == 'c');
	SEQAN_ASSERT((getCargo(ed1)).i2 == 1);
	addVertex(g2);
	addVertex(g2);
	addVertex(g2);
	TEdgeDescriptor2 ed4 =addEdge(g2,1,4);
	cargo(ed4) = TPair('z',100);
	removeVertex(g2, 2);
	Graph<TEdges> g2_copy(g2);
	SEQAN_ASSERT(numVertices(g2_copy) == 4);
	SEQAN_ASSERT(numEdges(g2_copy) == 3);
	clearEdges(g2_copy);
	SEQAN_ASSERT(numVertices(g2_copy) == 4);
	SEQAN_ASSERT(numEdges(g2_copy) == 0);
	clearVertices(g2_copy);
	SEQAN_ASSERT(numVertices(g2_copy) == 0);
	addVertex(g2_copy);addVertex(g2_copy);
	addEdge(g2_copy,0,1);
	clear(g2_copy);
	SEQAN_ASSERT(numVertices(g2_copy) == 0);
	addVertex(g2_copy);addVertex(g2_copy);
	addEdge(g2_copy,0,1);
	SEQAN_ASSERT(numEdges(g2) == 3);
	SEQAN_ASSERT(outDegree(g2, 0) == 2);
	SEQAN_ASSERT(inDegree(g2, 0) == 1);
	transpose(g2, g2_copy);
	SEQAN_ASSERT(outDegree(g2_copy, 0) == 1);
	SEQAN_ASSERT(inDegree(g2_copy, 0) == 2);
	SEQAN_ASSERT(numEdges(g2_copy) == 3);
	TEdgeDescriptor2 edgCargo = addEdge(g2, 0, 0, TPair('m',3));
	SEQAN_ASSERT((getCargo(edgCargo)).i1 == 'm');
	SEQAN_ASSERT((getCargo(edgCargo)).i2 == 3);

//____________________________________________________________________________
//Graph without edge cargo and without edge ids
	typedef Directed<void, WithoutEdgeId> TEdges3;
	typedef EdgeDescriptor<Graph<TEdges3> >::Type TEdgeDescriptor3;

	Graph<TEdges3> g3;
	addVertex(g3);addVertex(g3);addVertex(g3);
	addVertex(g3);addVertex(g3);
	addEdge(g3,1,4);
	SEQAN_ASSERT(numVertices(g3) == 5);
	SEQAN_ASSERT(numEdges(g3) == 1);
	TEdgeDescriptor3 edge3 = addEdge(g3,0,4);
	//SEQAN_ASSERT(_getId(edge3) == 0);
	SEQAN_ASSERT(getCargo(edge3) == (void*) 0);
	addEdge(g3,0,2);
	addEdge(g3,0,0);
	removeEdge(g3,0,4);
	removeEdge(g3,0,2);
	SEQAN_ASSERT(numEdges(g3) == 2);

	// Multigraph
	StandardGraph multiG;
	addVertex(multiG);addVertex(multiG);addVertex(multiG);
	TEdgeDescriptor edgeD1 = addEdge(multiG, 1, 2);
	TEdgeDescriptor edgeD2 = addEdge(multiG, 1, 2);
	TEdgeDescriptor edgeD3 = addEdge(multiG, 1, 2);
	removeEdge(multiG, edgeD2);
	SEQAN_ASSERT(sourceVertex(multiG,edgeD1) == 1);
	SEQAN_ASSERT(sourceVertex(multiG,edgeD2) == 0); // EdgeDescriptor invalid
	SEQAN_ASSERT(sourceVertex(multiG,edgeD3) == 1);
}

//////////////////////////////////////////////////////////////////////////////

void Test_Undirected() {
//____________________________________________________________________________
// Graph without edge cargo but with edge ids

	typedef Graph<Undirected<void> > StandardGraph;
	typedef VertexDescriptor<StandardGraph>::Type TVertexDescriptor;
	typedef EdgeDescriptor<StandardGraph>::Type TEdgeDescriptor;
	
	StandardGraph g;
	SEQAN_ASSERT(numVertices(g) == 0);
	SEQAN_ASSERT(numEdges(g) == 0);
	SEQAN_ASSERT(empty(g) == true);

	// Add vertex
	TVertexDescriptor v0 = addVertex(g);
	SEQAN_ASSERT(v0 == 0);
	SEQAN_ASSERT(outDegree(g, v0) == 0);	
	SEQAN_ASSERT(inDegree(g, 0) == 0);
	SEQAN_ASSERT(degree(g, 0) == 0);
	SEQAN_ASSERT(numVertices(g) == 1);
	SEQAN_ASSERT(empty(g) == false);
	
	// Add edge
	// TEdgeDescriptor e1 =addEdge(g,v0,v0);  // Self edges are not allowed in undirected graphs
	TVertexDescriptor v1 = addVertex(g);
	TEdgeDescriptor e =addEdge(g,0,1);
	SEQAN_ASSERT(findEdge(g, 0, 1) == e);
	SEQAN_ASSERT(_getVertexString(g)[0] == e);
	SEQAN_ASSERT(getIdUpperBound(_getVertexIdManager(g)) == 2);
	SEQAN_ASSERT(getIdUpperBound(_getEdgeIdManager(g)) == 1);
	SEQAN_ASSERT(v1 == 1);
	SEQAN_ASSERT(numVertices(g) == 2);
	SEQAN_ASSERT(targetVertex(g, e) == 1);
	SEQAN_ASSERT(sourceVertex(g, e) == 0);
	SEQAN_ASSERT(numEdges(g) == 1);
	SEQAN_ASSERT(outDegree(g, v0) == 1);	
	SEQAN_ASSERT(inDegree(g, 1) == 1);
	SEQAN_ASSERT(inDegree(g, 0) == 1);	
	SEQAN_ASSERT(degree(g, 0) == 1);

	// Add more vertices and edges
	addVertex(g);  //2
	TVertexDescriptor v3 = addVertex(g);  //3
	addVertex(g);  //4
	addEdge(g,3,4);
	TEdgeDescriptor my_edge = addEdge(g,3,1);
	addEdge(g,3,0);
	SEQAN_ASSERT(v3 == 3);
	SEQAN_ASSERT(numVertices(g) == 5);
	SEQAN_ASSERT(targetVertex(g, my_edge) == 3);
	SEQAN_ASSERT(sourceVertex(g, my_edge) == 1);
	SEQAN_ASSERT(numEdges(g) == 4);
	SEQAN_ASSERT(outDegree(g, v3) == 3);
	SEQAN_ASSERT(inDegree(g, v3) == 3);
	SEQAN_ASSERT(degree(g, v3) == 3);

	// Output
	std::stringstream sstream;
	sstream << g;
	char const * EXPECTED =
        "Adjacency list:\n"
        "0 -> 3,1,\n"
        "1 -> 3,0,\n"
        "2 -> \n"
        "3 -> 0,1,4,\n"
        "4 -> 3,\n"
        "Edge list:\n"
        "Source: 0,Target: 3 (Id: 3)\n"
        "Source: 0,Target: 1 (Id: 0)\n"
        "Source: 1,Target: 3 (Id: 2)\n"
        "Source: 3,Target: 4 (Id: 1)\n";
    SEQAN_ASSERT(EXPECTED == sstream.str());

	// Remove edges
	removeEdge(g,my_edge);
	removeEdge(g,0,1);
	SEQAN_ASSERT(numEdges(g) == 2);

	
	// Remove vertices 
	addVertex(g);  //5
	addEdge(g,5,2);
	addEdge(g,2,3);
	addEdge(g,1,3);
	addEdge(g,1,4);
	SEQAN_ASSERT(outDegree(g, 3) == 4);
	SEQAN_ASSERT(outDegree(g, 4) == 2);
	removeVertex(g, v3);
	SEQAN_ASSERT(outDegree(g, 4) == 1);
	SEQAN_ASSERT(outDegree(g, 0) == 0);
	SEQAN_ASSERT(numVertices(g) == 5);
	SEQAN_ASSERT(numEdges(g) == 2);

	// Clear graph
	clearEdges(g);
	SEQAN_ASSERT(numVertices(g) == 5);
	SEQAN_ASSERT(numEdges(g) == 0);
	addEdge(g,2,0);
	addEdge(g,4,1);
	clearVertices(g);
	SEQAN_ASSERT(numVertices(g) == 0);
	SEQAN_ASSERT(numEdges(g) == 0);
	addVertex(g);addVertex(g);addVertex(g);
	addVertex(g);addVertex(g);
	addEdge(g,2,0);
	addEdge(g,4,1);
	clear(g);
	SEQAN_ASSERT(numVertices(g) == 0);
	SEQAN_ASSERT(numEdges(g) == 0);
	addVertex(g);addVertex(g);addVertex(g);
	addVertex(g);addVertex(g);
	addEdge(g,2,0);
	addEdge(g,4,1);
	addEdge(g,4,2);
	removeVertex(g,3);
	SEQAN_ASSERT(numVertices(g) == 4);
	SEQAN_ASSERT(numEdges(g) == 3);
	SEQAN_ASSERT(outDegree(g, 4) == 2);
	SEQAN_ASSERT(inDegree(g, 4) == 2);

	// Transpose
	transpose(g); 
	SEQAN_ASSERT(numVertices(g) == 4);
	SEQAN_ASSERT(numEdges(g) == 3);
	SEQAN_ASSERT(outDegree(g, 4) == 2);
	SEQAN_ASSERT(inDegree(g, 4) == 2);
	StandardGraph g_copy(g);
	SEQAN_ASSERT(numVertices(g_copy) == 4);
	SEQAN_ASSERT(numEdges(g_copy) == 3);
	SEQAN_ASSERT(outDegree(g_copy, 4) == 2);
	SEQAN_ASSERT(inDegree(g_copy, 4) == 2);
	addVertex(g_copy);
	addEdge(g_copy,3,0);
	g_copy = g;
	SEQAN_ASSERT(numVertices(g_copy) == 4);
	SEQAN_ASSERT(numEdges(g_copy) == 3);
	SEQAN_ASSERT(outDegree(g_copy, 4) == 2);
	SEQAN_ASSERT(inDegree(g_copy, 4) == 2);
	//Copies the graph and transposes just the copy
	transpose(g,g_copy);  // g does not change!
	SEQAN_ASSERT(numVertices(g_copy) == 4);
	SEQAN_ASSERT(numEdges(g_copy) == 3);
	SEQAN_ASSERT(outDegree(g_copy, 4) == 2);
	SEQAN_ASSERT(inDegree(g_copy, 4) == 2);

	// Adjacency matrix
	String<unsigned int> mat;
	getAdjacencyMatrix(g, mat);
	unsigned int len = (unsigned int) std::sqrt((double) length(mat));
	SEQAN_ASSERT(getValue(mat,0*len+2) == 1);
	SEQAN_ASSERT(getValue(mat,3*len+2) == 0);
	SEQAN_ASSERT(getValue(mat,0*len+2) == getValue(mat,2*len+0));
	SEQAN_ASSERT(getValue(mat,1*len+4) == getValue(mat,4*len+1));
	SEQAN_ASSERT(getValue(mat,2*len+4) == getValue(mat,4*len+2));

//____________________________________________________________________________
//Graph with edge cargo and edge ids
	typedef Pair<char, int> TPair;
	typedef Undirected<TPair> TEdges;
	typedef VertexDescriptor<Graph<TEdges> >::Type TVertexDescriptor2;
	typedef EdgeDescriptor<Graph<TEdges> >::Type TEdgeDescriptor2;

	Graph<TEdges> g2;
	SEQAN_ASSERT(numVertices(g2) == 0);
	SEQAN_ASSERT(numEdges(g2) == 0);
	TVertexDescriptor2 ver0 = addVertex(g2);
	SEQAN_ASSERT(ver0 == 0);
	SEQAN_ASSERT(numVertices(g2) == 1);
	TVertexDescriptor2 ver1 = addVertex(g2);
	SEQAN_ASSERT(ver1 == 1);
	SEQAN_ASSERT(numVertices(g2) == 2);
	TEdgeDescriptor2 ed1 =addEdge(g2,0,1);
	SEQAN_ASSERT(targetVertex(g2, ed1) == 1);
	SEQAN_ASSERT(sourceVertex(g2, ed1) == 0);
	SEQAN_ASSERT(numEdges(g2) == 1);
	assignCargo(ed1, TPair('a',3));
	SEQAN_ASSERT((getCargo(ed1)).i1 == 'a');
	SEQAN_ASSERT((getCargo(ed1)).i2 == 3);
	cargo(ed1) = TPair('c',1);
	SEQAN_ASSERT((getCargo(ed1)).i1 == 'c');
	SEQAN_ASSERT((getCargo(ed1)).i2 == 1);
	addVertex(g2);
	addVertex(g2);
	addVertex(g2);
	TEdgeDescriptor2 ed4 =addEdge(g2,1,4);
	cargo(ed4) = TPair('z',100);
	removeVertex(g2, 2);
	Graph<TEdges> g2_copy(g2);
	SEQAN_ASSERT(numVertices(g2_copy) == 4);
	SEQAN_ASSERT(numEdges(g2_copy) == 2);
	clearEdges(g2_copy);
	SEQAN_ASSERT(numVertices(g2_copy) == 4);
	SEQAN_ASSERT(numEdges(g2_copy) == 0);
	clearVertices(g2_copy);
	SEQAN_ASSERT(numVertices(g2_copy) == 0);
	addVertex(g2_copy);addVertex(g2_copy);
	addEdge(g2_copy,0,1);
	clear(g2_copy);
	SEQAN_ASSERT(numVertices(g2_copy) == 0);
	addVertex(g2_copy);addVertex(g2_copy);
	addEdge(g2_copy,0,1);
	transpose(g2, g2_copy);
	SEQAN_ASSERT(outDegree(g2_copy, 0) == 1);
	SEQAN_ASSERT(inDegree(g2_copy, 0) == 1);
	SEQAN_ASSERT(numEdges(g2_copy) == 2);
	TEdgeDescriptor2 edgCargo = addEdge(g2, 0, 3, TPair('m',3));
	SEQAN_ASSERT((getCargo(edgCargo)).i1 == 'm');
	SEQAN_ASSERT((getCargo(edgCargo)).i2 == 3);

//____________________________________________________________________________
//Graph without edge cargo and without edge ids
	typedef Undirected<void, WithoutEdgeId> TEdges3;
	typedef EdgeDescriptor<Graph<TEdges3> >::Type TEdgeDescriptor3;

	Graph<TEdges3> g3;
	addVertex(g3);addVertex(g3);addVertex(g3);
	addVertex(g3);addVertex(g3);
	addEdge(g3,1,4);
	SEQAN_ASSERT(numVertices(g3) == 5);
	SEQAN_ASSERT(numEdges(g3) == 1);
	TEdgeDescriptor3 edge3 = addEdge(g3,0,4);
	SEQAN_ASSERT(_getId(edge3) == 0);
	SEQAN_ASSERT(getCargo(edge3) == (void*) 0);
	addEdge(g3,0,2);
	addEdge(g3,0,1);
	removeEdge(g3,0,4);
	removeEdge(g3,0,2);
	SEQAN_ASSERT(numEdges(g3) == 2);
	removeInEdges(g3,1);
	SEQAN_ASSERT(numEdges(g3) == 0);
	

//____________________________________________________________________________
// Undirected graph iterators
	typedef Graph<Undirected<> > TGraphIter;
	
	TGraphIter gIter;
	addVertex(gIter);addVertex(gIter);addVertex(gIter);addVertex(gIter);
	addVertex(gIter);addVertex(gIter);addVertex(gIter);addVertex(gIter);
	removeVertex(gIter,0);
	removeVertex(gIter,5);
	addEdge(gIter,2,7);
	addEdge(gIter,2,3);
	addEdge(gIter,2,4);
	addEdge(gIter,4,3);
	addEdge(gIter,3,6);
	addEdge(gIter,4,6);

	typedef Iterator<TGraphIter, OutEdgeIterator>::Type TOutEdgeIterator;
	TOutEdgeIterator itOutEdge(gIter,3);
	// Both ways are fast for undirected graphs
	SEQAN_ASSERT(sourceVertex(gIter, getValue(itOutEdge))==3);
	SEQAN_ASSERT(targetVertex(gIter, getValue(itOutEdge))==6);
	SEQAN_ASSERT(sourceVertex(itOutEdge)==3);
	SEQAN_ASSERT(targetVertex(itOutEdge)==6);
	SEQAN_ASSERT(sourceVertex(gIter, value(itOutEdge))==3);
	SEQAN_ASSERT(targetVertex(gIter, *itOutEdge)==6);
	SEQAN_ASSERT(atEnd(itOutEdge)==false);
	SEQAN_ASSERT(atBegin(itOutEdge)==true);
	goNext(itOutEdge);
	SEQAN_ASSERT(atEnd(itOutEdge)==false);
	SEQAN_ASSERT(atBegin(itOutEdge)==false);
	SEQAN_ASSERT(sourceVertex(itOutEdge)==3);
	SEQAN_ASSERT(targetVertex(itOutEdge)==4);
	++itOutEdge;
	itOutEdge++;
	SEQAN_ASSERT(atEnd(itOutEdge)==true);
	SEQAN_ASSERT(atBegin(itOutEdge)==false);
	goPrevious(itOutEdge);
	SEQAN_ASSERT(sourceVertex(gIter, getValue(itOutEdge))==2);
	SEQAN_ASSERT(targetVertex(gIter, getValue(itOutEdge))==3);
	--itOutEdge;
	itOutEdge--; 
	SEQAN_ASSERT(sourceVertex(gIter, getValue(itOutEdge))==3);
	SEQAN_ASSERT(targetVertex(gIter, getValue(itOutEdge))==6);
	itOutEdge--;
	itOutEdge--;
	SEQAN_ASSERT(atBegin(itOutEdge)==true);
	TOutEdgeIterator itEdge2(itOutEdge);
	TOutEdgeIterator itEdge3;
	itEdge3 = itOutEdge;
	SEQAN_ASSERT(itOutEdge == itEdge2);
	SEQAN_ASSERT(itEdge2 == itEdge3);
	goEnd(itOutEdge);
	SEQAN_ASSERT(itEdge2 != itOutEdge);
	goEnd(itEdge2);
	SEQAN_ASSERT(itEdge2 == itOutEdge);
	goBegin(itEdge2);
	SEQAN_ASSERT(atBegin(itEdge2)==true);
	SEQAN_ASSERT(&gIter == &hostGraph(itOutEdge));

	
	typedef Iterator<TGraphIter, EdgeIterator>::Type TEdgeIterator;
	TEdgeIterator itEdge(gIter);
	SEQAN_ASSERT(sourceVertex(gIter, getValue(itEdge))==2);
	SEQAN_ASSERT(targetVertex(gIter, getValue(itEdge))==4);
	SEQAN_ASSERT(atBegin(itEdge)==true);
	SEQAN_ASSERT(atEnd(itEdge)==false);
	goNext(itEdge);
	SEQAN_ASSERT(sourceVertex(gIter, getValue(itEdge))==2);
	SEQAN_ASSERT(targetVertex(gIter, getValue(itEdge))==3);
	SEQAN_ASSERT(atBegin(itEdge)==false);
	SEQAN_ASSERT(atEnd(itEdge)==false);
	goNext(itEdge);
	SEQAN_ASSERT(sourceVertex(gIter, getValue(itEdge))==2);
	SEQAN_ASSERT(targetVertex(gIter, getValue(itEdge))==7);
	++itEdge;
	SEQAN_ASSERT(sourceVertex(gIter, getValue(itEdge))==3);
	SEQAN_ASSERT(targetVertex(gIter, getValue(itEdge))==6);
	itEdge++;
	SEQAN_ASSERT(sourceVertex(gIter, getValue(itEdge))==3);
	SEQAN_ASSERT(targetVertex(gIter, getValue(itEdge))==4);
	goNext(itEdge);
	SEQAN_ASSERT(sourceVertex(gIter, getValue(itEdge))==4);
	SEQAN_ASSERT(targetVertex(gIter, getValue(itEdge))==6);
	goNext(itEdge);
	SEQAN_ASSERT(atBegin(itEdge)==false);
	SEQAN_ASSERT(atEnd(itEdge)==true);
	goPrevious(itEdge);	
	SEQAN_ASSERT(sourceVertex(gIter, getValue(itEdge))==4);
	SEQAN_ASSERT(targetVertex(gIter, getValue(itEdge))==6);
	--itEdge;	
	SEQAN_ASSERT(sourceVertex(gIter, getValue(itEdge))==3);
	SEQAN_ASSERT(targetVertex(gIter, getValue(itEdge))==4);
	itEdge--;	
	SEQAN_ASSERT(sourceVertex(gIter, getValue(itEdge))==3);
	SEQAN_ASSERT(targetVertex(gIter, getValue(itEdge))==6);
	goPrevious(itEdge);	
	SEQAN_ASSERT(sourceVertex(gIter, getValue(itEdge))==2);
	SEQAN_ASSERT(targetVertex(gIter, getValue(itEdge))==7);
	goPrevious(itEdge);	
	SEQAN_ASSERT(sourceVertex(gIter, getValue(itEdge))==2);
	SEQAN_ASSERT(targetVertex(gIter, getValue(itEdge))==3);
	goPrevious(itEdge);	
	SEQAN_ASSERT(sourceVertex(gIter, getValue(itEdge))==2);
	SEQAN_ASSERT(targetVertex(gIter, getValue(itEdge))==4);
	SEQAN_ASSERT(atBegin(itEdge)==true);
	SEQAN_ASSERT(atEnd(itEdge)==false);

	// Multigraph
	StandardGraph multiG;
	addVertex(multiG);addVertex(multiG);addVertex(multiG);
	addEdge(multiG, 1, 2);
	TEdgeDescriptor edgeD2 = addEdge(multiG, 1, 2);
	addEdge(multiG, 1, 2);
	removeEdge(multiG, edgeD2);
	SEQAN_ASSERT(numEdges(multiG) == 2);
}


//////////////////////////////////////////////////////////////////////////////

void Test_Automaton() {
//____________________________________________________________________________
// Standard automaton: No edge cargo

	typedef Graph<Automaton<Dna> > StandardAutomaton;
	typedef VertexDescriptor<StandardAutomaton>::Type TVertexDescriptor;
	typedef EdgeDescriptor<StandardAutomaton>::Type TEdgeDescriptor;
	
	StandardAutomaton g;
	SEQAN_ASSERT(numVertices(g) == 0);
	SEQAN_ASSERT(numEdges(g) == 0);
	SEQAN_ASSERT(empty(g) == true);

	// Add vertex
	createRoot(g);
	TVertexDescriptor v0 = getRoot(g);
	SEQAN_ASSERT(v0 == 0);
	SEQAN_ASSERT(outDegree(g, v0) == 0);	
	SEQAN_ASSERT(inDegree(g, 0) == 0);
	SEQAN_ASSERT(degree(g, 0) == 0);
	SEQAN_ASSERT(numVertices(g) == 1);
	SEQAN_ASSERT(empty(g) == false);

	// Add edge
	TEdgeDescriptor e1 =addEdge(g,v0,v0,'a');
	SEQAN_ASSERT(findEdge(g, 0, 'a') == e1);
	SEQAN_ASSERT(&_getVertexString(g)[0].data_edge[0] == e1);
	SEQAN_ASSERT(getIdUpperBound(_getVertexIdManager(g)) == 1);
	SEQAN_ASSERT(getIdUpperBound(_getEdgeIdManager(g)) == 1);
	SEQAN_ASSERT(_getId(e1) == 0);
	SEQAN_ASSERT(_getId(e1) == 0);
	SEQAN_ASSERT(targetVertex(g, e1) == 0);
	SEQAN_ASSERT(sourceVertex(g, e1) == 0); 
	SEQAN_ASSERT(numEdges(g) == 1);
	SEQAN_ASSERT(outDegree(g, v0) == 1);	
	SEQAN_ASSERT(inDegree(g, v0) == 1);
	SEQAN_ASSERT(degree(g, v0) == 2);
	
	// Add further edges and vertices
	TVertexDescriptor v1 = addVertex(g);
	TEdgeDescriptor e2 =addEdge(g,0,1,'g');
	SEQAN_ASSERT(_getId(e2) == 1);
	SEQAN_ASSERT(v1 == 1);
	SEQAN_ASSERT(numVertices(g) == 2);
	SEQAN_ASSERT(targetVertex(g, e2) == 1);
	SEQAN_ASSERT(sourceVertex(g, e2) == 0);
	SEQAN_ASSERT(numEdges(g) == 2);
	SEQAN_ASSERT(outDegree(g, v0) == 2);	
	SEQAN_ASSERT(inDegree(g, 1) == 1);
	SEQAN_ASSERT(inDegree(g, 0) == 1);	
	SEQAN_ASSERT(degree(g, 0) == 3);

	// Add more vertices and edges
	addVertex(g);  //2
	TVertexDescriptor v3 = addVertex(g);  //3
	addVertex(g);  //4
	addEdge(g,3,4,'g');
	TEdgeDescriptor my_edge = addEdge(g,3,1,'c');
	SEQAN_ASSERT(_getId(my_edge) == 3);
	addEdge(g,3,0,'t');
	SEQAN_ASSERT(v3 == 3);
	SEQAN_ASSERT(numVertices(g) == 5);
	SEQAN_ASSERT(targetVertex(g, e2) == 1);
	SEQAN_ASSERT(sourceVertex(g, e2) == 0);
	SEQAN_ASSERT(targetVertex(g, my_edge) == 1);
	SEQAN_ASSERT(sourceVertex(g, my_edge) == 3);
	SEQAN_ASSERT(numEdges(g) == 5);
	SEQAN_ASSERT(outDegree(g, v3) == 3);	

	// Output
	std::stringstream sstream;
	sstream << g;
	char const * EXPECTED =
        "Automaton - State: (Input / NextState)\n"
        "0:  (A / 0)  (C / nil)  (G / 1)  (T / nil) \n"
        "1:  (A / nil)  (C / nil)  (G / nil)  (T / nil) \n"
        "2:  (A / nil)  (C / nil)  (G / nil)  (T / nil) \n"
        "3:  (A / nil)  (C / 1)  (G / 4)  (T / 0) \n"
        "4:  (A / nil)  (C / nil)  (G / nil)  (T / nil) \n";
    SEQAN_ASSERT(EXPECTED == sstream.str());

	// Remove edges
	removeEdge(g,3,1,'c');
	removeEdge(g,0,1,'g');
	SEQAN_ASSERT(numEdges(g) == 3);

	// Remove vertices 
	TEdgeDescriptor e3 = addEdge(g,3,3,'a');
	addEdge(g,1,3,'a');
	addEdge(g,0,3,'c');
	addEdge(g,0,4,'t');
	SEQAN_ASSERT(outDegree(g, 0) == 3);
	SEQAN_ASSERT(outDegree(g, 1) == 1);
	SEQAN_ASSERT(targetVertex(g, e3) == 3);
	SEQAN_ASSERT(sourceVertex(g, e3) == 3);
	SEQAN_ASSERT(numEdges(g) == 7);
	removeVertex(g, v3);
	SEQAN_ASSERT(outDegree(g, 0) == 2);
	SEQAN_ASSERT(outDegree(g, 1) == 0);
	SEQAN_ASSERT(numVertices(g) == 4);
	SEQAN_ASSERT(numEdges(g) == 2);

	// Clear graph
	clearEdges(g);
	SEQAN_ASSERT(numVertices(g) == 4);
	SEQAN_ASSERT(numEdges(g) == 0);
	addEdge(g,2,0,'a');
	addEdge(g,4,1,'c');
	clearVertices(g);
	SEQAN_ASSERT(numVertices(g) == 0);
	SEQAN_ASSERT(numEdges(g) == 0);
	addVertex(g);addVertex(g);addVertex(g);
	addVertex(g);addVertex(g);
	addEdge(g,2,0,'t');
	addEdge(g,4,1,'g');
	clear(g);
	SEQAN_ASSERT(numVertices(g) == 0);
	SEQAN_ASSERT(numEdges(g) == 0);
	addVertex(g);addVertex(g);addVertex(g);
	addVertex(g);addVertex(g);
	addEdge(g,2,0,'c');
	addEdge(g,4,1,'g');
	addEdge(g,4,2,'t');
	removeVertex(g,3);
	SEQAN_ASSERT(numVertices(g) == 4);
	SEQAN_ASSERT(numEdges(g) == 3);
	SEQAN_ASSERT(outDegree(g, 4) == 2);
	SEQAN_ASSERT(inDegree(g, 4) == 0);

	//Transposes the graph in-place
	transpose(g); 
	SEQAN_ASSERT(numVertices(g) == 4);
	SEQAN_ASSERT(numEdges(g) == 3);
	SEQAN_ASSERT(outDegree(g, 4) == 0);
	SEQAN_ASSERT(inDegree(g, 4) == 2);
	StandardAutomaton g_copy(g);
	SEQAN_ASSERT(numVertices(g_copy) == 4);
	SEQAN_ASSERT(numEdges(g_copy) == 3);
	SEQAN_ASSERT(outDegree(g_copy, 4) == 0);
	SEQAN_ASSERT(inDegree(g_copy, 4) == 2);
	addVertex(g_copy);
	addEdge(g_copy,3,0,'a');
	g_copy = g;
	SEQAN_ASSERT(numVertices(g_copy) == 4);
	SEQAN_ASSERT(numEdges(g_copy) == 3);
	SEQAN_ASSERT(outDegree(g_copy, 4) == 0);
	SEQAN_ASSERT(inDegree(g_copy, 4) == 2);
	//Copies the graph and transposes just the copy
	transpose(g,g_copy);  // g does not change!
	SEQAN_ASSERT(numVertices(g_copy) == 4);
	SEQAN_ASSERT(numEdges(g_copy) == 3);
	SEQAN_ASSERT(outDegree(g_copy, 4) == 2);
	SEQAN_ASSERT(inDegree(g_copy, 4) == 0);
	removeVertex(g,0);

	// Adjacency matrix
	String<unsigned int> mat;
	getAdjacencyMatrix(g, mat);
	unsigned int len = (unsigned int) std::sqrt((double) length(mat));
	SEQAN_ASSERT(getValue(mat,1*len+4) == 1);
	SEQAN_ASSERT(getValue(mat,2*len+4) == 1);
	SEQAN_ASSERT(getValue(mat,0*len+2) == 0);

	// Test iterators
	typedef Iterator<StandardAutomaton, VertexIterator>::Type TVertexIterator;
	TVertexIterator itVert(g);
	SEQAN_ASSERT(getValue(itVert) == 1);
	++itVert;
	SEQAN_ASSERT(getValue(itVert) == 2);
	itVert++;
	SEQAN_ASSERT(getValue(itVert) == 4);
	goNext(itVert);
	SEQAN_ASSERT(atEnd(itVert) == true);

	addEdge(g,1,2,'T');
	typedef Iterator<StandardAutomaton, OutEdgeIterator>::Type TOutEdgeIterator;
	TOutEdgeIterator itEdge(g,1);
	// Slow
	SEQAN_ASSERT(sourceVertex(g, getValue(itEdge))==1);
	SEQAN_ASSERT(targetVertex(g, getValue(itEdge))==4);
	// Fast
	SEQAN_ASSERT(sourceVertex(itEdge)==1);
	SEQAN_ASSERT(targetVertex(itEdge)==4);
	
	SEQAN_ASSERT(sourceVertex(g, value(itEdge))==1);
	SEQAN_ASSERT(targetVertex(g, *itEdge)==4);
	SEQAN_ASSERT(atEnd(itEdge)==false);
	SEQAN_ASSERT(atBegin(itEdge)==true);
	goNext(itEdge);
	SEQAN_ASSERT(sourceVertex(itEdge)==1);
	SEQAN_ASSERT(targetVertex(itEdge)==2);
	++itEdge;
	itEdge++;
	SEQAN_ASSERT(atEnd(itEdge)==true);
	SEQAN_ASSERT(atBegin(itEdge)==false);
	goPrevious(itEdge);
	SEQAN_ASSERT(sourceVertex(g, getValue(itEdge))==1);
	SEQAN_ASSERT(targetVertex(g, getValue(itEdge))==2);
	--itEdge;
	itEdge++; 
	SEQAN_ASSERT(sourceVertex(g, getValue(itEdge))==1);
	SEQAN_ASSERT(targetVertex(g, getValue(itEdge))==2);
	itEdge--;
	itEdge--;
	SEQAN_ASSERT(atBegin(itEdge)==true);
	TOutEdgeIterator itEdge2(itEdge);
	TOutEdgeIterator itEdge3;
	itEdge3 = itEdge;
	SEQAN_ASSERT(itEdge == itEdge2);
	SEQAN_ASSERT(itEdge2 == itEdge3);
	goEnd(itEdge);
	SEQAN_ASSERT(itEdge2 != itEdge);
	goEnd(itEdge2);
	SEQAN_ASSERT(itEdge2 == itEdge);
	goBegin(itEdge2);
	SEQAN_ASSERT(atBegin(itEdge2)==true);
	SEQAN_ASSERT(&g == &hostGraph(itEdge));

	typedef Iterator<StandardAutomaton, EdgeIterator>::Type TEdgeIterator;
	TEdgeIterator itEd(g);
	SEQAN_ASSERT(sourceVertex(g, getValue(itEd))==1);
	SEQAN_ASSERT(targetVertex(g, getValue(itEd))==4);
	SEQAN_ASSERT(sourceVertex(g, value(itEd))==1);
	SEQAN_ASSERT(targetVertex(g, *itEd)==4);
	SEQAN_ASSERT(atEnd(itEd)==false);
	SEQAN_ASSERT(atBegin(itEd)==true);
	goNext(itEd);
	SEQAN_ASSERT(sourceVertex(g, getValue(itEd))==1);
	SEQAN_ASSERT(targetVertex(g, getValue(itEd))==2);
	SEQAN_ASSERT(atEnd(itEd)==false);
	SEQAN_ASSERT(atBegin(itEd)==false);
	++itEd;
	SEQAN_ASSERT(atEnd(itEd)==false);
	SEQAN_ASSERT(atBegin(itEd)==false);
	// Slow
	SEQAN_ASSERT(sourceVertex(g, getValue(itEd))==2);
	SEQAN_ASSERT(targetVertex(g, getValue(itEd))==4);
	// Fast
	SEQAN_ASSERT(sourceVertex(itEd)==2);
	SEQAN_ASSERT(targetVertex(itEd)==4);
	itEd++;
	itEd++;
	SEQAN_ASSERT(atEnd(itEd)==true);
	SEQAN_ASSERT(atBegin(itEd)==false);
	goPrevious(itEd);
	SEQAN_ASSERT(sourceVertex(g, getValue(itEd))==2);
	SEQAN_ASSERT(targetVertex(g, getValue(itEd))==4);
	--itEd;
	SEQAN_ASSERT(sourceVertex(g, getValue(itEd))==1);
	SEQAN_ASSERT(targetVertex(g, getValue(itEd))==2);
	TEdgeIterator itEd2(g);
	TEdgeIterator itEd3;
	goBegin(itEd);
	itEd3 = itEd;
	SEQAN_ASSERT(itEd == itEd2);
	SEQAN_ASSERT(itEd2 == itEd3);
	goEnd(itEd);
	SEQAN_ASSERT(itEd2 != itEd);
	goEnd(itEd2);
	SEQAN_ASSERT(itEd2 == itEd);
	goBegin(itEd2);
	SEQAN_ASSERT(itEd2 != itEd);
	SEQAN_ASSERT(&hostGraph(itEd) == &g);

	typedef Iterator<StandardAutomaton, AdjacencyIterator>::Type TAdjacencyIterator;
	TAdjacencyIterator itAd(g,1);
	SEQAN_ASSERT(getValue(itAd) == 4);
	SEQAN_ASSERT(&hostGraph(itAd) == &g);
	SEQAN_ASSERT(value(itAd) == 4);
	SEQAN_ASSERT(*itAd == 4);
	SEQAN_ASSERT(atEnd(itAd)==false);
	SEQAN_ASSERT(atBegin(itAd)==true);
	goNext(itAd);
	SEQAN_ASSERT(getValue(itAd)==2);
	SEQAN_ASSERT(atEnd(itAd)==false);
	SEQAN_ASSERT(atBegin(itAd)==false);
	++itAd;
	SEQAN_ASSERT(atEnd(itAd)==true);
	SEQAN_ASSERT(atBegin(itAd)==false);
	goBegin(itAd);
	itAd++;
	itAd++;
	itAd++;
	SEQAN_ASSERT(atEnd(itAd)==true);
	SEQAN_ASSERT(atBegin(itAd)==false);
	goPrevious(itAd);
	SEQAN_ASSERT(getValue(itAd)==2);
	--itAd;
	SEQAN_ASSERT(getValue(itAd)==4);
	SEQAN_ASSERT(atEnd(itAd)==false);
	SEQAN_ASSERT(atBegin(itAd)==true);
	goEnd(itAd);
	itAd--;
	SEQAN_ASSERT(getValue(itAd)==2);
	goBegin(itAd);
	TAdjacencyIterator itAd2(itAd);
	TAdjacencyIterator itAd3;
	itAd3 = itAd;
	SEQAN_ASSERT(itAd == itAd2);
	SEQAN_ASSERT(itAd2 == itAd3);
	goEnd(itAd);
	SEQAN_ASSERT(itAd2 != itAd);
	goEnd(itAd2);
	SEQAN_ASSERT(itAd2 == itAd);
	goBegin(itAd2);
	SEQAN_ASSERT(itAd2 != itAd);



//____________________________________________________________________________
// Automaton - Different alphabet
	typedef VertexDescriptor<Graph<Automaton<char> > >::Type VertexDescriptorType;
	Graph<Automaton<char> > automaton;
	VertexDescriptorType rootVertex = addVertex(automaton); // A = 0
	addVertex(automaton); // B = 1
	addVertex(automaton); // C = 2
	addVertex(automaton); // D = 3
	addVertex(automaton); // E = 4
	addVertex(automaton); // F = 5
	addEdge(automaton,0,1,'2');
	addEdge(automaton,1,0,'1');
	addEdge(automaton,4,0,'6');
	addEdge(automaton,0,3,'7');
	addEdge(automaton,1,1,'3');
	addEdge(automaton,1,2,'4');
	addEdge(automaton,5,1,'8');
	addEdge(automaton,2,5,'5');
	addEdge(automaton,3,4,'2');
	addEdge(automaton,5,3,'7');

	VertexDescriptorType succ;
	succ = getSuccessor(automaton,rootVertex,'7');
	SEQAN_ASSERT(succ == 3);
	// Throws an error in debug mode because edge does not exist
	//succ = getSuccessor(automaton,rootVertex,'6');
	succ = getSuccessor(automaton,succ,'2');
	SEQAN_ASSERT(succ == 4);
	succ = getSuccessor(automaton,succ,'6');
	SEQAN_ASSERT(succ == 0);
	// If no map is specified it is assumed that an edge cargo exists!!!
	succ = getSuccessor(automaton,succ,'2');
	SEQAN_ASSERT(succ == 1);

	// Now using shortcuts
	SEQAN_ASSERT(canParseString(automaton, rootVertex, "7262"));
	SEQAN_ASSERT(!canParseString(automaton, rootVertex, "726C"));
	SEQAN_ASSERT(canParseString(automaton, "7262"));
	SEQAN_ASSERT(!canParseString(automaton, "726C"));
	succ = parseString(automaton,rootVertex,"7262");
	SEQAN_ASSERT(succ == 1);
	std::string str = "7262";
	succ = parseString(automaton,rootVertex, str.begin(), str.end());
	SEQAN_ASSERT(succ == 1);
	String<char> str2("7262");
	succ = parseString(automaton,rootVertex, begin(str2), end(str2));
	SEQAN_ASSERT(succ == 1);
	String<char> input("7262");
	SEQAN_ASSERT(canParseString(automaton, rootVertex, input));
	SEQAN_ASSERT(canParseString(automaton, input));
	succ = parseString(automaton,rootVertex, input);
	SEQAN_ASSERT(succ == 1);

	// Additional cargo
	typedef Graph<Automaton<Dna, short> > TGraph9;
	typedef EdgeDescriptor<TGraph9>::Type TEdgeDescriptor9;

	TGraph9 g9;
	addVertex(g9);
	addVertex(g9);
	Dna aDna('a');
	Dna gDna('g');
	TEdgeDescriptor9 edg1 = addEdge(g9,0,1,aDna,12);
	TEdgeDescriptor9 edg2 = addEdge(g9,1,0,gDna,21);
	TGraph9 g10;
	transpose(g9, g10);
	TEdgeDescriptor9 edg1_10 = findEdge(g10, 1, aDna);
	TEdgeDescriptor9 edg1_11 = findEdge(g10, 0, gDna);
	SEQAN_ASSERT(getCargo(edg1)==12);
	SEQAN_ASSERT(getCargo(edg2)==21);
	SEQAN_ASSERT(getCargo(edg1_10)==12);
	SEQAN_ASSERT(getCargo(edg1_11)==21);

	// Multigraph
	StandardAutomaton multiG;
	addVertex(multiG);addVertex(multiG);addVertex(multiG);
	addEdge(multiG, 1, 2, 'a');
	TEdgeDescriptor edgeD2 = addEdge(multiG, 1, 2, 'c');
	addEdge(multiG, 1, 2, 'g');
	removeEdge(multiG, edgeD2);
	SEQAN_ASSERT(numEdges(multiG) == 2);
}

//////////////////////////////////////////////////////////////////////////////

void Test_WordGraph() {
//____________________________________________________________________________
// Standard automaton: No edge cargo

	typedef Graph<Automaton<Dna, String<Dna>, WordGraph<> > > TWordGraph;
	typedef VertexDescriptor<TWordGraph>::Type TVertexDescriptor;
	typedef EdgeDescriptor<TWordGraph>::Type TEdgeDescriptor;
	

	TWordGraph g;
	SEQAN_ASSERT(numVertices(g) == 0);
	SEQAN_ASSERT(numEdges(g) == 0);
	SEQAN_ASSERT(empty(g) == true);

	// Add vertex
	TVertexDescriptor v0 = addVertex(g);
	SEQAN_ASSERT(v0 == 0);
	SEQAN_ASSERT(outDegree(g, v0) == 0);	
	SEQAN_ASSERT(inDegree(g, 0) == 0);
	SEQAN_ASSERT(degree(g, 0) == 0);
	SEQAN_ASSERT(numVertices(g) == 1);
	SEQAN_ASSERT(empty(g) == false);
	addVertex(g);
	addVertex(g);
	TVertexDescriptor v3 = addVertex(g);
	SEQAN_ASSERT(isRoot(g, 0) == true);
	SEQAN_ASSERT(getRoot(g) == 0);
	assignRoot(g,3);
	SEQAN_ASSERT(getRoot(g) == 3);
	SEQAN_ASSERT(isRoot(g, 0) == false);
	SEQAN_ASSERT(isRoot(g, 3) == true);
	root(g) = 2;
	SEQAN_ASSERT(getRoot(g) == 2);
	SEQAN_ASSERT(isRoot(g, 3) == false);
	SEQAN_ASSERT(isRoot(g, 2) == true);

	// Add edge
	TEdgeDescriptor e1 =addEdge(g,v0,v3,"ag");
	SEQAN_ASSERT(findEdge(g,v0,'a') == e1);
	SEQAN_ASSERT(_getId(e1) == 0);
	// First letter -> edge label, all other letters into the cargo
	SEQAN_ASSERT(getCargo(e1) == "g");
	SEQAN_ASSERT(targetVertex(g, e1) == 3);
	SEQAN_ASSERT(sourceVertex(g, e1) == 0); 
	SEQAN_ASSERT(numEdges(g) == 1);
	SEQAN_ASSERT(outDegree(g, v0) == 1);	
	SEQAN_ASSERT(inDegree(g, v0) == 0);
	SEQAN_ASSERT(degree(g, v0) == 1);

	// Add further edges and vertices
	addVertex(g);
	TVertexDescriptor v5 = addVertex(g);
	TEdgeDescriptor e2 =addEdge(g,0,5,"g");
	SEQAN_ASSERT(_getId(e2) == 1); 
	SEQAN_ASSERT(v5 == 5);
	SEQAN_ASSERT(numVertices(g) == 6);
	SEQAN_ASSERT(targetVertex(g, e2) == 5);
	SEQAN_ASSERT(sourceVertex(g, e2) == 0);
	SEQAN_ASSERT(numEdges(g) == 2);
	removeEdge(g,0,5,String<Dna>("g"));
	SEQAN_ASSERT(numEdges(g) == 1);
	e2 =addEdge(g,0,5,"g");
	SEQAN_ASSERT(outDegree(g, v0) == 2);	
	SEQAN_ASSERT(inDegree(g, 5) == 1);
	SEQAN_ASSERT(degree(g, 0) == 2);
	SEQAN_ASSERT(getSuccessor(g, 0, "g") == 5);
	SEQAN_ASSERT(getSuccessor(g, 0, String<Dna>("ag")) == 3);  // The whole edge label or just the first letter
	SEQAN_ASSERT(getSuccessor(g, 0, "a") == getNil<TVertexDescriptor>());
	addVertex(g);
	addVertex(g);
	addEdge(g,3,1,"aggg");
	addEdge(g,3,4,"gg");
	addEdge(g,5,2,"aggg");
	addEdge(g,5,7,"g");
	addEdge(g,7,6,"g");
	SEQAN_ASSERT(parseString(g, 0, "agaggg") == 1);
	SEQAN_ASSERT(parseString(g, 0, "aga") == 3);  // Does not reach 1
	SEQAN_ASSERT(parseString(g, 0, "g") == 5);
	SEQAN_ASSERT(parseString(g, 0, "ggg") == 6);
	SEQAN_ASSERT(parseString(g, 0, "gaggg") == 2);
	SEQAN_ASSERT(parseString(g, 0, "gagggg") == 2);
	assignRoot(g,0);

	// Output
	std::stringstream sstream;
	sstream << g;
	char const * EXPECTED =
        "WordGraph - Directed:\n"
        "0->3  Label: AG\n"
        "0->5  Label: G\n"
        "3->1  Label: AGGG\n"
        "3->4  Label: GG\n"
        "5->2  Label: AGGG\n"
        "5->7  Label: G\n"
        "7->6  Label: G\n";
    SEQAN_ASSERT_EQ(EXPECTED, sstream.str());

	assignRoot(g,2);
	TWordGraph g_tmp(g);
	SEQAN_ASSERT(numVertices(g_tmp) == 8);
	SEQAN_ASSERT(parseString(g_tmp, 0, "agaggg") == 1);
	SEQAN_ASSERT(inDegree(g_tmp, 5) == 1);
	SEQAN_ASSERT(degree(g_tmp, 0) == 2);
	SEQAN_ASSERT(isRoot(g_tmp, 2) == true);
	TWordGraph g_assign;
	g_assign = g;
	SEQAN_ASSERT(numVertices(g_assign) == 8);
	SEQAN_ASSERT(parseString(g_assign, 0, "agaggg") == 1);
	SEQAN_ASSERT(inDegree(g_assign, 5) == 1);
	SEQAN_ASSERT(degree(g_assign, 0) == 2);

	// Transpose
	transpose(g, g_tmp);
	SEQAN_ASSERT(numVertices(g_tmp) == 8);
	SEQAN_ASSERT(parseString(g_tmp, 2, "aggg") == 5);
	SEQAN_ASSERT(inDegree(g_tmp, 5) == 2);
	SEQAN_ASSERT(outDegree(g_tmp, 0) == 0);
	SEQAN_ASSERT(isRoot(g_tmp, 2) == true);
}


//////////////////////////////////////////////////////////////////////////////

void Test_Tree() {
//____________________________________________________________________________
// Tree without edge cargo

	typedef Graph<Tree<void> > TTree;
	typedef VertexDescriptor<TTree>::Type TVertexDescriptor;
	typedef EdgeDescriptor<TTree>::Type TEdgeDescriptor;
	
	TTree g;
	SEQAN_ASSERT(empty(g) == true);
	createRoot(g);
	TVertexDescriptor rootV = getRoot(g);
	SEQAN_ASSERT(rootV == 0);
	SEQAN_ASSERT(isRoot(g, rootV) == true);
	SEQAN_ASSERT(root(g) == rootV);
	SEQAN_ASSERT(empty(g) == false);
	TVertexDescriptor childC1 = addChild(g,rootV);
	String<TVertexDescriptor> leaves;
	collectLeaves(g, rootV, leaves);
	TEdgeDescriptor childC1e = findEdge(g, rootV, childC1);
	SEQAN_ASSERT(_getVertexString(g)[0] == childC1e);
	SEQAN_ASSERT(getIdUpperBound(_getVertexIdManager(g)) == 2);
	SEQAN_ASSERT(getIdUpperBound(_getEdgeIdManager(g)) == 2);
	SEQAN_ASSERT(targetVertex(g, childC1e) == childC1); // Target in a tree = child
	SEQAN_ASSERT(sourceVertex(g, childC1e) == rootV);  // Source in a tree = parent
	SEQAN_ASSERT(childVertex(g, childC1e) == childC1);  // Shortcuts
	SEQAN_ASSERT(parentVertex(g, childC1e) == rootV);
	SEQAN_ASSERT(parentVertex(g, childC1) == rootV);
	SEQAN_ASSERT(empty(g) == false);
	SEQAN_ASSERT(outDegree(g, rootV) == 1);
	TVertexDescriptor childC2 = addChild(g,rootV);
	TVertexDescriptor childC3 = addChild(g,rootV);
	clear(leaves);
	collectLeaves(g, rootV, leaves);
	SEQAN_ASSERT(length(leaves) == 3);
	SEQAN_ASSERT(outDegree(g, rootV) == 3);
	SEQAN_ASSERT(childC1 == 1);
	SEQAN_ASSERT(childC2 == 2);
	SEQAN_ASSERT(childC3 == 3);
	TVertexDescriptor childC2C1 = addChild(g,childC2);
	TVertexDescriptor childC2C1C1 = addChild(g,childC2C1);
	TVertexDescriptor childC2C1C1C1 = addChild(g,childC2C1C1);
    (void)childC2C1C1C1;
	TVertexDescriptor childC2C1C1C2 = addChild(g,childC2C1C1);
    (void)childC2C1C1C2;
	TVertexDescriptor childC4 = addChild(g,rootV);
    (void)childC4;
	SEQAN_ASSERT(inDegree(g, childC2C1) == 1); 
	SEQAN_ASSERT(outDegree(g, childC2C1) == 1);
	SEQAN_ASSERT(degree(g, childC2C1) == 2);
	SEQAN_ASSERT(numEdges(g) == 8);
	SEQAN_ASSERT(numVertices(g) == 9);
	SEQAN_ASSERT(numTreeEdges(g) == numVertices(g) - 1);
	TEdgeDescriptor childC2C1C1e = findEdge(g, childC2C1C1, childC2C1);
	
	// Output
	std::stringstream sstream;
	sstream << g;
	char const * EXPECTED =
        "Adjacency list:\n"
        "0 -> 8,3,2,1,\n"
        "1 -> \n"
        "2 -> 4,\n"
        "3 -> \n"
        "4 -> 5,\n"
        "5 -> 7,6,\n"
        "6 -> \n"
        "7 -> \n"
        "8 -> \n"
        "Edge list:\n"
        "Source: 0,Target: 8 (Id: 8)\n"
        "Source: 0,Target: 3 (Id: 3)\n"
        "Source: 0,Target: 2 (Id: 2)\n"
        "Source: 0,Target: 1 (Id: 1)\n"
        "Source: 2,Target: 4 (Id: 4)\n"
        "Source: 4,Target: 5 (Id: 5)\n"
        "Source: 5,Target: 7 (Id: 7)\n"
        "Source: 5,Target: 6 (Id: 6)\n";
    SEQAN_ASSERT(EXPECTED == sstream.str());

	SEQAN_ASSERT(g.data_parent[0]==getNil<TVertexDescriptor>());
	SEQAN_ASSERT(g.data_parent[1]==0);
	SEQAN_ASSERT(g.data_parent[2]==0);
	SEQAN_ASSERT(g.data_parent[3]==0);
	SEQAN_ASSERT(g.data_parent[4]==2);
	SEQAN_ASSERT(g.data_parent[5]==4);
	SEQAN_ASSERT(g.data_parent[6]==5);
	SEQAN_ASSERT(g.data_parent[7]==5);
	SEQAN_ASSERT(g.data_parent[8]==0);
	_rebuildParentMap(g);
	SEQAN_ASSERT(g.data_parent[0]==getNil<TVertexDescriptor>());
	SEQAN_ASSERT(g.data_parent[1]==0);
	SEQAN_ASSERT(g.data_parent[2]==0);
	SEQAN_ASSERT(g.data_parent[3]==0);
	SEQAN_ASSERT(g.data_parent[4]==2);
	SEQAN_ASSERT(g.data_parent[5]==4);
	SEQAN_ASSERT(g.data_parent[6]==5);
	SEQAN_ASSERT(g.data_parent[7]==5);
	SEQAN_ASSERT(g.data_parent[8]==0);
	SEQAN_ASSERT(childVertex(g, childC2C1C1e) == childC2C1C1);  
	SEQAN_ASSERT(parentVertex(g, childC2C1C1e) == childC2C1);
	removeChild(g, rootV, childC2);
	SEQAN_ASSERT(g.data_parent[0]==getNil<TVertexDescriptor>());
	SEQAN_ASSERT(g.data_parent[1]==0);
	SEQAN_ASSERT(g.data_parent[2]==getNil<TVertexDescriptor>());
	SEQAN_ASSERT(g.data_parent[3]==0);
	SEQAN_ASSERT(g.data_parent[4]==getNil<TVertexDescriptor>());
	SEQAN_ASSERT(g.data_parent[5]==getNil<TVertexDescriptor>());
	SEQAN_ASSERT(g.data_parent[6]==getNil<TVertexDescriptor>());
	SEQAN_ASSERT(g.data_parent[7]==getNil<TVertexDescriptor>());
	SEQAN_ASSERT(g.data_parent[8]==0);
	SEQAN_ASSERT(numEdges(g) == 3);
	SEQAN_ASSERT(numVertices(g) == 4);
	SEQAN_ASSERT(empty(g) == false);
	SEQAN_ASSERT(inDegree(g, rootV) == 0); 
	SEQAN_ASSERT(outDegree(g, rootV) == 3);
	SEQAN_ASSERT(degree(g, rootV) == 3);
	childC2 = addChild(g,rootV);
	childC2C1 = addChild(g,childC2);
	childC2C1C1 = addChild(g,childC2C1);
	childC2C1C1C1 = addChild(g,childC2C1C1);
	childC2C1C1C2 = addChild(g,childC2C1C1);
	removeAllChildren(g, rootV);
	SEQAN_ASSERT(empty(g) == false);
	SEQAN_ASSERT(numEdges(g) == 0);
	SEQAN_ASSERT(numTreeEdges(g) == 0);
	SEQAN_ASSERT(numVertices(g) == 1); // Just the root
	SEQAN_ASSERT(inDegree(g, rootV) == 0); 
	SEQAN_ASSERT(outDegree(g, rootV) == 0);
	SEQAN_ASSERT(degree(g, rootV) == 0);
	addChild(g,rootV);addChild(g,rootV);
	SEQAN_ASSERT(empty(g) == false);
	SEQAN_ASSERT(numEdges(g) == 2);
	clearEdges(g);
	SEQAN_ASSERT(numEdges(g) == 0);
	SEQAN_ASSERT(numVertices(g) == 3);
	SEQAN_ASSERT(empty(g) == false);
	addChild(g,rootV);addChild(g,rootV);
	clearVertices(g);
	SEQAN_ASSERT(empty(g) == true);
	SEQAN_ASSERT(numVertices(g) == 0);
	SEQAN_ASSERT(numEdges(g) == 0);
	createRoot(g);
	childC1 = addChild(g,rootV);
	SEQAN_ASSERT(empty(g) == false);
	SEQAN_ASSERT(numEdges(g) == 1);
	childC3 = addChild(g,rootV);
	childC2 = addChild(g,rootV);
	childC2C1 = addChild(g,childC2);
	childC2C1C1 = addChild(g,childC2C1);
	childC2C1C1C1 = addChild(g,childC2C1C1);
	childC2C1C1C2 = addChild(g,childC2C1C1);
	childC4 = addChild(g,rootV);
	String<unsigned int> mat; 	// Adjacency matrix
	getAdjacencyMatrix(g, mat);
	unsigned int len = (unsigned int) std::sqrt((double) length(mat));
	SEQAN_ASSERT(getValue(mat, 0*len+8) == 1);
	SEQAN_ASSERT(getValue(mat, 8*len+0) == 0);
	SEQAN_ASSERT(getValue(mat, 3*len+0) == 0);
	SEQAN_ASSERT(getValue(mat, 0*len+3) == 1);
	SEQAN_ASSERT(getValue(mat, 0*len+4) == 0);
	SEQAN_ASSERT(numEdges(g) == 8);
	SEQAN_ASSERT(numVertices(g) == 9);
	transpose(g); 
	SEQAN_ASSERT(numEdges(g) == 8);
	SEQAN_ASSERT(numVertices(g) == 9);
	TTree g_copy(g);
	SEQAN_ASSERT(numEdges(g) == 8);
	SEQAN_ASSERT(numVertices(g) == 9);
	clear(g_copy);
	g_copy = g;
	SEQAN_ASSERT(numEdges(g) == 8);
	SEQAN_ASSERT(numVertices(g) == 9);
	transpose(g,g_copy);  
	g = g_copy;
	_rebuildParentMap(g);
	SEQAN_ASSERT(numEdges(g) == 8);
	SEQAN_ASSERT(numVertices(g) == 9);
	SEQAN_ASSERT(g.data_parent[0]==getNil<TVertexDescriptor>());
	SEQAN_ASSERT(g.data_parent[1]==0);
	SEQAN_ASSERT(g.data_parent[2]==0);
	SEQAN_ASSERT(g.data_parent[3]==0);
	SEQAN_ASSERT(g.data_parent[4]==3);
	SEQAN_ASSERT(g.data_parent[5]==4);
	SEQAN_ASSERT(g.data_parent[6]==5);
	SEQAN_ASSERT(g.data_parent[7]==5);
	SEQAN_ASSERT(g.data_parent[8]==0);
	removeOutEdges(g,childC2C1C1);
	SEQAN_ASSERT(g.data_parent[0]==getNil<TVertexDescriptor>());
	SEQAN_ASSERT(g.data_parent[1]==0);
	SEQAN_ASSERT(g.data_parent[2]==0);
	SEQAN_ASSERT(g.data_parent[3]==0);
	SEQAN_ASSERT(g.data_parent[4]==3);
	SEQAN_ASSERT(g.data_parent[5]==4);
	SEQAN_ASSERT(g.data_parent[6]==getNil<TVertexDescriptor>());
	SEQAN_ASSERT(g.data_parent[7]==getNil<TVertexDescriptor>());
	SEQAN_ASSERT(g.data_parent[8]==0);
	SEQAN_ASSERT(numVertices(g) == 9);
	SEQAN_ASSERT(numEdges(g) == 6);
	removeVertex(g,childC2C1);
	SEQAN_ASSERT(g.data_parent[0]==getNil<TVertexDescriptor>());
	SEQAN_ASSERT(g.data_parent[1]==0);
	SEQAN_ASSERT(g.data_parent[2]==0);
	SEQAN_ASSERT(g.data_parent[3]==0);
	SEQAN_ASSERT(g.data_parent[5]==getNil<TVertexDescriptor>());
	SEQAN_ASSERT(g.data_parent[6]==getNil<TVertexDescriptor>());
	SEQAN_ASSERT(g.data_parent[7]==getNil<TVertexDescriptor>());
	SEQAN_ASSERT(g.data_parent[8]==0);
	SEQAN_ASSERT(numEdges(g) == 4);

	SEQAN_ASSERT(numVertices(g) == 8);
	removeInEdges(g,childC2);
	SEQAN_ASSERT(numEdges(g) == 3);
	SEQAN_ASSERT(numVertices(g) == 8);
	removeOutEdges(g,rootV);
	SEQAN_ASSERT(g.data_parent[0]==getNil<TVertexDescriptor>());
	SEQAN_ASSERT(g.data_parent[1]==getNil<TVertexDescriptor>());
	SEQAN_ASSERT(g.data_parent[2]==getNil<TVertexDescriptor>());
	SEQAN_ASSERT(g.data_parent[3]==getNil<TVertexDescriptor>());
	SEQAN_ASSERT(g.data_parent[5]==getNil<TVertexDescriptor>());
	SEQAN_ASSERT(g.data_parent[6]==getNil<TVertexDescriptor>());
	SEQAN_ASSERT(g.data_parent[7]==getNil<TVertexDescriptor>());
	SEQAN_ASSERT(g.data_parent[8]==getNil<TVertexDescriptor>());
	SEQAN_ASSERT(numVertices(g) == 8);
	SEQAN_ASSERT(numEdges(g) == 0);
	SEQAN_ASSERT(empty(g) == false); 
	addVertex(g);
	TEdgeDescriptor my_edge = addEdge(g,0,1);
	removeEdge(g,my_edge);

//____________________________________________________________________________
// Tree with cargo

	typedef Pair<char, int> TPair;
	typedef Tree<TPair> TEdges;
	typedef Graph<TEdges> TCargoGraph;
	typedef VertexDescriptor<TCargoGraph>::Type TVertexDescriptor2;
	typedef EdgeDescriptor<TCargoGraph>::Type TEdgeDescriptor2;

	TCargoGraph g2;
	createRoot(g2);
	SEQAN_ASSERT(numVertices(g2) == 1);
	SEQAN_ASSERT(numEdges(g2) == 0);
	TVertexDescriptor2 ver1 = addChild(g2, getRoot(g2), TPair('a',3));
	SEQAN_ASSERT(numChildren(g2, getRoot(g2)) == 1);
	SEQAN_ASSERT(ver1 == 1);
	SEQAN_ASSERT(numVertices(g2) == 2);
	TVertexDescriptor2 ver2 = addChild(g2, getRoot(g2));
	SEQAN_ASSERT(ver2 == 2);
	SEQAN_ASSERT(numVertices(g2) == 3);
	TEdgeDescriptor2 ed1 =findEdge(g2,getRoot(g2),ver1);
	TEdgeDescriptor2 ed2 =findEdge(g2,getRoot(g2),ver2);
	SEQAN_ASSERT((getCargo(ed1)).i1 == 'a');
	SEQAN_ASSERT((getCargo(ed1)).i2 == 3);
	SEQAN_ASSERT(targetVertex(g2, ed1) == ver1);
	SEQAN_ASSERT(sourceVertex(g2, ed1) == getRoot(g2));
	SEQAN_ASSERT(numEdges(g2) == 2);
	assignCargo(ed2, TPair('b',4));
	SEQAN_ASSERT((getCargo(ed1)).i1 == 'a');
	SEQAN_ASSERT((getCargo(ed1)).i2 == 3);
	SEQAN_ASSERT((getCargo(ed2)).i1 == 'b');
	SEQAN_ASSERT((getCargo(ed2)).i2 == 4);
	cargo(ed1) = TPair('c',1);
	SEQAN_ASSERT((getCargo(ed1)).i1 == 'c');
	SEQAN_ASSERT((getCargo(ed1)).i2 == 1);
	assignRoot(g2,1);
	SEQAN_ASSERT(getRoot(g2) == 1);

	//// File read
	//fstream strmKnut;
	//TTree gKnut;
	//strmKnut.open(TEST_PATH "my_tree2.dot", ios_base::in);
	//String<String<char> > nodeMap;
	//String<String<char> > edgeMap;
	//read(strmKnut, gKnut, nodeMap, edgeMap, DotDrawing());
	//strmKnut.close();

	//assignRoot(gKnut, 26);
	//typedef Iterator<TTree, DfsPreorder>::Type TDfsPreorder;
	//TDfsPreorder dfsIt(gKnut, 26);
	//for(;!atEnd(dfsIt);++dfsIt) {
	//	std::cout << *dfsIt << ": ";
	//	std::cout << getProperty(nodeMap, *dfsIt) << std::endl;
	//}
	//std::cout << gKnut << std::endl;
}



//////////////////////////////////////////////////////////////////////////////

void Test_Fragment() {
	// Test Fragment
	typedef String<char> TString;
	typedef StringSet<TString, Dependent<> > TStringSet;
	typedef	Id<TStringSet>::Type TId;
	typedef	Size<TStringSet>::Type TSize;
	
	TStringSet str;
	TString str0("annual");	assignValueById(str, str0);
	TString str1("anneal"); assignValueById(str, str1);

	// Fragment: SeqId1, Begin1, SeqId2, Begin2, Length of Fragment
	Fragment<> f(0,4,1,4,2);
	SEQAN_ASSERT(f.seqId1 == 0);
	SEQAN_ASSERT(f.begin1 == 4);
	SEQAN_ASSERT(f.seqId2 == 1);
	SEQAN_ASSERT(f.begin2 == 4);
	SEQAN_ASSERT(f.len == 2);
	SEQAN_ASSERT(fragmentBegin(f, 0) == 4);
	SEQAN_ASSERT(fragmentBegin(f, 1) == 4);
	SEQAN_ASSERT(fragmentLength(f, 0) == 2);
	SEQAN_ASSERT(fragmentLength(f, 1) == 2);
	SEQAN_ASSERT(sequenceId(f, 0) == 0);
	SEQAN_ASSERT(sequenceId(f, 1) == 1);
	SEQAN_ASSERT(label(f, str, 0) == "al");
	SEQAN_ASSERT(label(f, str, 1) == "al");
	TId id2;
	TSize pos2;
	getProjectedPosition(f, 0, 5, id2, pos2);
	SEQAN_ASSERT(pos2 == 5);
	SEQAN_ASSERT(id2 == 1);
	getProjectedPosition(f, 1, 5, id2, pos2);
	SEQAN_ASSERT(pos2 == 5);
	SEQAN_ASSERT(id2 == 0);

	// Reversable Fragment
	typedef Fragment<Size<Fragment<> >::Type, ExactReversableFragment<> > TRevFrag;
	TRevFrag fRev(0,4,1,4,2);
	SEQAN_ASSERT(fRev.seqId1 == 0);
	SEQAN_ASSERT(fRev.begin1 == 4);
	SEQAN_ASSERT(fRev.seqId2 == 1);
	SEQAN_ASSERT(fRev.begin2 == 4);
	SEQAN_ASSERT(fRev.len == 2);
	SEQAN_ASSERT(fragmentBegin(fRev, 0) == 4);
	SEQAN_ASSERT(fragmentBegin(fRev, 1) == 4);
	SEQAN_ASSERT(fragmentLength(fRev, 0) == 2);
	SEQAN_ASSERT(fragmentLength(fRev, 1) == 2);
	SEQAN_ASSERT(sequenceId(fRev, 0) == 0);
	SEQAN_ASSERT(sequenceId(fRev, 1) == 1);
	SEQAN_ASSERT(label(fRev, str, 0) == "al");
	SEQAN_ASSERT(label(fRev, str, 1) == "al");
	SEQAN_ASSERT(!isReversed(fRev));
	getProjectedPosition(fRev, 0, 5, id2, pos2);
	SEQAN_ASSERT(pos2 == 5);
	SEQAN_ASSERT(id2 == 1);
	getProjectedPosition(fRev, 1, 5, id2, pos2);
	SEQAN_ASSERT(pos2 == 5);
	SEQAN_ASSERT(id2 == 0);
	TRevFrag fRev2(0,4,1,4,2, true);
	SEQAN_ASSERT(fRev2.seqId1 == 0);
	SEQAN_ASSERT(fRev2.begin1 == 4);
	SEQAN_ASSERT(fRev2.seqId2 == 1);
	SEQAN_ASSERT(fRev2.begin2 == 4);
	SEQAN_ASSERT(fRev2.len == 2);
	SEQAN_ASSERT(fragmentBegin(fRev2, 0) == 4);
	SEQAN_ASSERT(fragmentBegin(fRev2, 1) == 4);
	SEQAN_ASSERT(fragmentLength(fRev2, 0) == 2);
	SEQAN_ASSERT(fragmentLength(fRev2, 1) == 2);
	SEQAN_ASSERT(sequenceId(fRev2, 0) == 0);
	SEQAN_ASSERT(sequenceId(fRev2, 1) == 1);
	SEQAN_ASSERT(label(fRev2, str, 0) == "al");
	SEQAN_ASSERT(label(fRev2, str, 1) == "al");
	SEQAN_ASSERT(isReversed(fRev2));
	getProjectedPosition(fRev2, 0, 5, id2, pos2);
	SEQAN_ASSERT(pos2 == 4);
	SEQAN_ASSERT(id2 == 1);
	getProjectedPosition(fRev2, 1, 5, id2, pos2);
	SEQAN_ASSERT(pos2 == 4);
	SEQAN_ASSERT(id2 == 0);

	// Fragment: SeqId1, Begin1, SeqId2, Begin2, Length of Fragment
	Fragment<> f2(0,0,1,4,1);
	SEQAN_ASSERT(f2.seqId1 == 0);
	SEQAN_ASSERT(f2.begin1 == 0);
	SEQAN_ASSERT(f2.seqId2 == 1);
	SEQAN_ASSERT(f2.begin2 == 4);
	SEQAN_ASSERT(f2.len == 1);
	SEQAN_ASSERT(fragmentBegin(f2, 0) == 0);
	SEQAN_ASSERT(fragmentBegin(f2, 1) == 4);
	SEQAN_ASSERT(fragmentLength(f2, 0) == 1);
	SEQAN_ASSERT(fragmentLength(f2, 1) == 1);
	SEQAN_ASSERT(fragmentLength(f2) == 1);
	SEQAN_ASSERT(label(f2, str, 0) == "a");
	SEQAN_ASSERT(label(f2, str, 1) == "a");
	getProjectedPosition(f2, 0, 0, id2, pos2);
	SEQAN_ASSERT(pos2 == 4);
	SEQAN_ASSERT(id2 == 1);
	getProjectedPosition(f2, 1, 4, id2, pos2);
	SEQAN_ASSERT(pos2 == 0);
	SEQAN_ASSERT(id2 == 0);
}

//////////////////////////////////////////////////////////////////////////////

void Test_Hmm() {
	typedef double TProbability;
	typedef Dna TAlphabet;
	typedef Size<TAlphabet>::Type TSize;
	typedef Graph<Hmm<TAlphabet, TProbability> > THmm;
	typedef VertexDescriptor<THmm>::Type TVertexDescriptor;
	typedef EdgeDescriptor<THmm>::Type TEdgeDescriptor;
	TSize alph_size = ValueSize<TAlphabet>::VALUE;
	
	Dna dnaA = Dna('A');
	Dna dnaC = Dna('C');
	Dna dnaG = Dna('G');
	Dna dnaT = Dna('T');

	// Create an empty HMM
	THmm hmm;
	SEQAN_ASSERT(numVertices(hmm) == 0);
	SEQAN_ASSERT(numEdges(hmm) == 0);
	SEQAN_ASSERT(empty(hmm) == true);
	clearEdges(hmm);
	clearVertices(hmm);
	SEQAN_ASSERT(numVertices(hmm) == 0);
	SEQAN_ASSERT(numEdges(hmm) == 0);
	SEQAN_ASSERT(empty(hmm) == true);

	// Add state1
	TVertexDescriptor state1 = addVertex(hmm);
	SEQAN_ASSERT(length(_getVertexString(hmm)) == 1);
	SEQAN_ASSERT(empty(hmm) == false);
	SEQAN_ASSERT(outDegree(hmm, state1) == 0);
	SEQAN_ASSERT(inDegree(hmm, state1) == 0);
	SEQAN_ASSERT(degree(hmm, state1) == 0);
	SEQAN_ASSERT(numVertices(hmm) == 1);
	SEQAN_ASSERT(numEdges(hmm) == 0);
	emissionProbability(hmm, state1, dnaA) = 0.2;
	SEQAN_ASSERT(getEmissionProbability(hmm, state1, dnaA) == 0.2);
	emissionProbability(hmm, state1, dnaC) = 0.2;
	emissionProbability(hmm, state1, dnaG) = 0.3;
	emissionProbability(hmm, state1, dnaT) = 0.3;
	SEQAN_ASSERT(getEmissionProbability(hmm, state1, dnaA) == 0.2);
	SEQAN_ASSERT(getEmissionProbability(hmm, state1, dnaG) == 0.3);

	// Add state2
	String<TProbability> emis;
	resize(emis, alph_size);
	value(emis, ordValue(dnaA)) = 0.5;
	value(emis, ordValue(dnaC)) = 0.5;
	value(emis, ordValue(dnaG)) = 0.0;
	value(emis, ordValue(dnaT)) = 0.0;
	TVertexDescriptor state2 = addVertex(hmm, emis);
	SEQAN_ASSERT(numVertices(hmm) == 2);
	SEQAN_ASSERT(numEdges(hmm) == 0);
	SEQAN_ASSERT(getEmissionProbability(hmm, state2, dnaC) == 0.5);

	// Add state3
	TVertexDescriptor state3 = addVertex(hmm, emis);
	assignEmissionProbability(hmm, state3, dnaA, 0.3);
	assignEmissionProbability(hmm, state3, dnaC, 0.3);
	assignEmissionProbability(hmm, state3, dnaG, 0.2);
	assignEmissionProbability(hmm, state3, dnaT, 0.2);
	SEQAN_ASSERT(numVertices(hmm) == 3);
	SEQAN_ASSERT(numEdges(hmm) == 0);
	SEQAN_ASSERT(getEmissionProbability(hmm, state3, dnaC) == 0.3);

	// Add edges (transitions)
	TEdgeDescriptor e = addEdge(hmm, state1, state1, 0.95);
	SEQAN_ASSERT(numEdges(hmm) == 1);
	removeEdge(hmm, e);
	SEQAN_ASSERT(numEdges(hmm) == 0);
	e = addEdge(hmm, state1, state1, 0.95);
	SEQAN_ASSERT(numEdges(hmm) == 1);
	removeOutEdges(hmm, state1);
	SEQAN_ASSERT(numEdges(hmm) == 0);
	e = addEdge(hmm, state1, state1, 0.95);
	removeEdge(hmm, sourceVertex(hmm, e), targetVertex(hmm, e));
	SEQAN_ASSERT(numEdges(hmm) == 0);
	e = addEdge(hmm, state1, state1, 0.95);
	removeInEdges(hmm, state1);
	SEQAN_ASSERT(numEdges(hmm) == 0);
	e = addEdge(hmm, state1, state1, 0.95);
	SEQAN_ASSERT(outDegree(hmm, state1) == 1);
	SEQAN_ASSERT(inDegree(hmm, state1) == 1);
	SEQAN_ASSERT(degree(hmm, state1) == 2);
	e = addEdge(hmm, state1, state3);
	assignTransitionProbability(hmm, e, 0.05);
	THmm hmm_tr = hmm;
	transpose(hmm_tr);
	SEQAN_ASSERT(getTransitionProbability(hmm_tr, state3, state1) == 0.05);
	clear(hmm_tr);
	transpose(hmm, hmm_tr);
	SEQAN_ASSERT(getTransitionProbability(hmm_tr, state3, state1) == 0.05);
	e = addEdge(hmm, state3, state3);
	transitionProbability(hmm, e) = 0.4;
	SEQAN_ASSERT(getTransitionProbability(hmm, e) == 0.4);
	e = addEdge(hmm, state3, state1);
	transitionProbability(hmm, state3, state1) = 0.1;
	e = addEdge(hmm, state2, state2);
	assignTransitionProbability(hmm, state2, state2, 1.0);
	SEQAN_ASSERT(numVertices(hmm) == 3);
	SEQAN_ASSERT(numEdges(hmm) == 5);
	SEQAN_ASSERT(getTransitionProbability(hmm, state3, state1) == 0.1);
	
	// Add begin and end state
	TVertexDescriptor begState = addVertex(hmm);
	TVertexDescriptor eState = addVertex(hmm);
	addEdge(hmm, begState, state1, 1.0);
	addEdge(hmm, state3, eState, 0.5);
	addEdge(hmm, eState, eState, 1.0);
	beginState(hmm) = state3;
	SEQAN_ASSERT(numVertices(hmm) == 5);
	SEQAN_ASSERT(getBeginState(hmm) == state3);
	assignBeginState(hmm, begState);
	SEQAN_ASSERT(getBeginState(hmm) == begState);
	endState(hmm) = state3;
	SEQAN_ASSERT(getEndState(hmm) == state3);
	assignEndState(hmm, eState);
	SEQAN_ASSERT(getEndState(hmm) == eState);
	
	// Output
	std::stringstream sstream;
	sstream << hmm;
	char const * EXPECTED =
        "Alphabet:\n"
        "{A,C,G,T}\n"
        "States:\n"
        "{0,1,2,3 (Silent),4 (Silent)}\n"
        "Begin state: 3\n"
        "End state: 4\n"
        "Transition probabilities:\n"
        "0 -> 2 (0.05) ,0 (0.95) \n"
        "1 -> 1 (1) \n"
        "2 -> 4 (0.5) ,0 (0.1) ,2 (0.4) \n"
        "3 -> 0 (1) \n"
        "4 -> 4 (1) \n"
        "Emission probabilities:\n"
        "0: A (0.2) ,C (0.2) ,G (0.3) ,T (0.3) \n"
        "1: A (0.5) ,C (0.5) ,G (0) ,T (0) \n"
        "2: A (0.3) ,C (0.3) ,G (0.2) ,T (0.2) ";
    SEQAN_ASSERT_EQ(EXPECTED, sstream.str());

	// Change model
	removeVertex(hmm, state2);
	THmm hmm_copy(hmm);
	SEQAN_ASSERT(numVertices(hmm_copy) == 4);
	SEQAN_ASSERT(getBeginState(hmm_copy) == begState);
	SEQAN_ASSERT(getEndState(hmm_copy) == eState);
	clear(hmm_copy);
	SEQAN_ASSERT(numVertices(hmm_copy) == 0);
	hmm_copy = hmm;
	SEQAN_ASSERT(numVertices(hmm_copy) == 4);
	SEQAN_ASSERT(getBeginState(hmm_copy) == begState);
	SEQAN_ASSERT(getEndState(hmm_copy) == eState);
	SEQAN_ASSERT(idCount(_getEdgeIdManager(hmm_copy)) == 7);

	// Test silent states
	TVertexDescriptor testState1 = addVertex(hmm, emis, true);
	TVertexDescriptor testState2 = addVertex(hmm, emis, false);
	SEQAN_ASSERT(isSilent(hmm, testState1) != isSilent(hmm, testState2));
	assignSilentStatus(hmm, testState1, false);
	SEQAN_ASSERT(isSilent(hmm, testState1) == isSilent(hmm, testState2));
	silentStatus(hmm, testState1) = true;
	SEQAN_ASSERT(isSilent(hmm, testState1) != isSilent(hmm, testState2));
}

//////////////////////////////////////////////////////////////////////////////

void Test_GraphTypes() {
	Test_Directed();	// Directed graphs
	Test_Undirected();	// Undirected graphs
	Test_Automaton();	// Automatons
	Test_WordGraph();	// Word Graph
	Test_Tree();		// Trees
	Test_Fragment();	// Fragment
	Test_Hmm();			// Hmm
}

//////////////////////////////////////////////////////////////////////////////

SEQAN_DEFINE_TEST(test_graph_types)
{
	Test_GraphTypes();
}

#endif

