std::vector< std::set<int> > GetStrongComponents(const std::vector<Edge> &list_of_edges, int vertices_amount) {
    auto graph = MakeCompactGraph(list_of_edges, vertices_amount);
    Tarjan tarjan_algo(vertices_amount);
    DFS(*graph, tarjan_algo);

    return tarjan_algo.GetComponents();
}
inline void TestMakeCompactGraph(const std::vector<Edge> &list_of_edges, int vertices_amount) {

    try {
        auto graph = MakeCompactGraph(list_of_edges, vertices_amount);

        if (IncidenceMatrixGraph::ByteSize(vertices_amount, list_of_edges.size()) >
                IncidenceListGraph::ByteSize(vertices_amount, list_of_edges.size())) {

            if (typeid(*graph) != typeid(IncidenceListGraph))
                throw std::logic_error("FAIL");
        }
        else if (typeid(*graph) != typeid(IncidenceMatrixGraph))
            throw std::logic_error("FAIL");
    } catch (const std::exception& ex) {
        throw std::logic_error("TestMakeCompactGraph: " + std::string(ex.what()));
    }
}
inline void StressTestTopologicalSort(const std::vector<Edge> &list_of_edges, int vertices_amount) {

    try {
        if (StupidIsSircle(vertices_amount, list_of_edges)) return;

        std::vector<int> topologically_ordered_vertices = GetTopologicallyOrderedVerties(list_of_edges, vertices_amount);
        if (topologically_ordered_vertices.size() != vertices_amount) throw std::logic_error("FAIL");

	auto graph = MakeCompactGraph(list_of_edges, vertices_amount);
        for (int i = 0; i < topologically_ordered_vertices.size() - 1; ++i) {
            for (int j = i + 1; j < topologically_ordered_vertices.size(); ++j) {
                if (graph->HasEdge(topologically_ordered_vertices[j], topologically_ordered_vertices[i]))
                     throw std::logic_error("FAIL");
            }
        } 
    } catch (const std::exception& ex) {
        throw std::logic_error("TestTopologicalSort: " + std::string(ex.what()));
    }
}
inline void FirstSearchTests(const std::vector<Edge> &list_of_edges, int vertices_amount) {
        auto graph = MakeCompactGraph(list_of_edges, vertices_amount);

    try {
        FirstSearchTester dfs_tester;
        DFS(*graph, dfs_tester);
        OneFirstSearchTest(list_of_edges, vertices_amount, dfs_tester);
    } catch (const std::exception& ex) {
        throw std::logic_error("TestDFS: " + std::string(ex.what()));
    }

    try {
        FirstSearchTester bfs_tester;
        DFS(*graph, bfs_tester);
        OneFirstSearchTest(list_of_edges, vertices_amount, bfs_tester);
    } catch (const std::exception& ex) {
         throw std::logic_error("TestBFS: " + std::string(ex.what()));
    }
}
inline void TestGetCondensationGraph(const std::vector<Edge> list_of_edges, int vertices_amount, 
                const std::vector< std::set<int> >& components) {
    try {
	auto graph = MakeCompactGraph(list_of_edges, vertices_amount);
        std::vector<int> vertex_component_number(graph->GetNumberOfVertices());

        for (size_t component_index = 0; component_index < components.size(); ++component_index) {   
            for (const auto& vertex : components[component_index]) {
                vertex_component_number[vertex] = component_index;
            }
        }
  
        std::set<Edge> right_set_of_condensation_graph_edges;
        for (int vertex = 0; vertex < graph->GetNumberOfVertices(); ++vertex) {
            std::vector<int> vertex_incidences = graph->GetIncidenceList(vertex);

            for (size_t i = 0; i < vertex_incidences.size(); ++i) {
                int incident_vertex = vertex_incidences[i];

                if (vertex_component_number[incident_vertex] != vertex_component_number[vertex]) 
                    right_set_of_condensation_graph_edges.insert(Edge(vertex_component_number[vertex], 
                            vertex_component_number[incident_vertex]));
            }
        }

        auto condensation_graph = GetCondensationGraph(*graph, components);
        if (condensation_graph->GetNumberOfVertices() != components.size()) throw std::logic_error("FAIL");
        std::set<Edge> algo_set_of_condensation_graph_edges;
        for (int vertex = 0; vertex < condensation_graph->GetNumberOfVertices(); ++vertex) {
            std::vector<int> vertex_incidences = condensation_graph->GetIncidenceList(vertex);
        
            for (size_t i = 0; i < vertex_incidences.size(); ++i) {
                int incident_vertex = vertex_incidences[i];
                algo_set_of_condensation_graph_edges.insert(Edge(vertex, incident_vertex));
            }
        }

        if (right_set_of_condensation_graph_edges != algo_set_of_condensation_graph_edges) 
            throw std::logic_error("FAIL");
    } catch (const std::exception& ex) {
        throw std::logic_error("TestGetCondensationGraph: " + std::string(ex.what()));
    }
}