diff options
Diffstat (limited to 'lemon/test')
82 files changed, 11746 insertions, 0 deletions
diff --git a/lemon/test/.deps/adaptors_test.Po b/lemon/test/.deps/adaptors_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/adaptors_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/bellman_ford_test.Po b/lemon/test/.deps/bellman_ford_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/bellman_ford_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/bfs_test.Po b/lemon/test/.deps/bfs_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/bfs_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/circulation_test.Po b/lemon/test/.deps/circulation_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/circulation_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/connectivity_test.Po b/lemon/test/.deps/connectivity_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/connectivity_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/counter_test.Po b/lemon/test/.deps/counter_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/counter_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/dfs_test.Po b/lemon/test/.deps/dfs_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/dfs_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/digraph_test.Po b/lemon/test/.deps/digraph_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/digraph_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/dijkstra_test.Po b/lemon/test/.deps/dijkstra_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/dijkstra_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/dim_test.Po b/lemon/test/.deps/dim_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/dim_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/edge_set_test.Po b/lemon/test/.deps/edge_set_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/edge_set_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/error_test.Po b/lemon/test/.deps/error_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/error_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/euler_test.Po b/lemon/test/.deps/euler_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/euler_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/fractional_matching_test.Po b/lemon/test/.deps/fractional_matching_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/fractional_matching_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/gomory_hu_test.Po b/lemon/test/.deps/gomory_hu_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/gomory_hu_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/graph_copy_test.Po b/lemon/test/.deps/graph_copy_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/graph_copy_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/graph_test.Po b/lemon/test/.deps/graph_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/graph_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/graph_utils_test.Po b/lemon/test/.deps/graph_utils_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/graph_utils_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/hao_orlin_test.Po b/lemon/test/.deps/hao_orlin_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/hao_orlin_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/heap_test.Po b/lemon/test/.deps/heap_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/heap_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/kruskal_test.Po b/lemon/test/.deps/kruskal_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/kruskal_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/lgf_test.Po b/lemon/test/.deps/lgf_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/lgf_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/lp_test.Po b/lemon/test/.deps/lp_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/lp_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/maps_test.Po b/lemon/test/.deps/maps_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/maps_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/matching_test.Po b/lemon/test/.deps/matching_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/matching_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/min_cost_arborescence_test.Po b/lemon/test/.deps/min_cost_arborescence_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/min_cost_arborescence_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/min_cost_flow_test.Po b/lemon/test/.deps/min_cost_flow_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/min_cost_flow_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/min_mean_cycle_test.Po b/lemon/test/.deps/min_mean_cycle_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/min_mean_cycle_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/mip_test.Po b/lemon/test/.deps/mip_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/mip_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/path_test.Po b/lemon/test/.deps/path_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/path_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/planarity_test.Po b/lemon/test/.deps/planarity_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/planarity_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/preflow_test.Po b/lemon/test/.deps/preflow_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/preflow_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/radix_sort_test.Po b/lemon/test/.deps/radix_sort_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/radix_sort_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/random_test.Po b/lemon/test/.deps/random_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/random_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/suurballe_test.Po b/lemon/test/.deps/suurballe_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/suurballe_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/test_tools_fail.Po b/lemon/test/.deps/test_tools_fail.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/test_tools_fail.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/test_tools_pass.Po b/lemon/test/.deps/test_tools_pass.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/test_tools_pass.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/time_measure_test.Po b/lemon/test/.deps/time_measure_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/time_measure_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/.deps/unionfind_test.Po b/lemon/test/.deps/unionfind_test.Po new file mode 100644 index 0000000..9ce06a8 --- /dev/null +++ b/lemon/test/.deps/unionfind_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lemon/test/CMakeLists.txt b/lemon/test/CMakeLists.txt new file mode 100644 index 0000000..8d13982 --- /dev/null +++ b/lemon/test/CMakeLists.txt @@ -0,0 +1,151 @@ +INCLUDE_DIRECTORIES( + ${PROJECT_SOURCE_DIR} + ${PROJECT_BINARY_DIR} +) + +LINK_DIRECTORIES( + ${PROJECT_BINARY_DIR}/lemon +) + +SET(TEST_WITH_VALGRIND "NO" CACHE STRING + "Run the test with valgrind (YES/NO).") +SET(VALGRIND_FLAGS "" CACHE STRING "Valgrind flags used by the tests.") + +SET(TESTS + adaptors_test + bellman_ford_test + bfs_test + circulation_test + connectivity_test + counter_test + dfs_test + digraph_test + dijkstra_test + dim_test + edge_set_test + error_test + euler_test + fractional_matching_test + gomory_hu_test + graph_copy_test + graph_test + graph_utils_test + hao_orlin_test + heap_test + kruskal_test + lgf_test + maps_test + matching_test + min_cost_arborescence_test + min_cost_flow_test + min_mean_cycle_test + path_test + planarity_test + preflow_test + radix_sort_test + random_test + suurballe_test + time_measure_test + unionfind_test +) + +IF(LEMON_HAVE_LP) + IF(${CMAKE_BUILD_TYPE} STREQUAL "Maintainer") + ADD_EXECUTABLE(lp_test lp_test.cc) + ELSE() + ADD_EXECUTABLE(lp_test EXCLUDE_FROM_ALL lp_test.cc) + ENDIF() + + SET(LP_TEST_LIBS lemon) + + IF(LEMON_HAVE_GLPK) + SET(LP_TEST_LIBS ${LP_TEST_LIBS} ${GLPK_LIBRARIES}) + ENDIF() + IF(LEMON_HAVE_CPLEX) + SET(LP_TEST_LIBS ${LP_TEST_LIBS} ${CPLEX_LIBRARIES}) + ENDIF() + IF(LEMON_HAVE_CLP) + SET(LP_TEST_LIBS ${LP_TEST_LIBS} ${COIN_CLP_LIBRARIES}) + ENDIF() + + TARGET_LINK_LIBRARIES(lp_test ${LP_TEST_LIBS}) + ADD_TEST(lp_test lp_test) + ADD_DEPENDENCIES(check lp_test) + + IF(WIN32 AND LEMON_HAVE_GLPK) + GET_TARGET_PROPERTY(TARGET_LOC lp_test LOCATION) + GET_FILENAME_COMPONENT(TARGET_PATH ${TARGET_LOC} PATH) + ADD_CUSTOM_COMMAND(TARGET lp_test POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/glpk.dll ${TARGET_PATH} + COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/libltdl3.dll ${TARGET_PATH} + COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/zlib1.dll ${TARGET_PATH} + ) + ENDIF() + + IF(WIN32 AND LEMON_HAVE_CPLEX) + GET_TARGET_PROPERTY(TARGET_LOC lp_test LOCATION) + GET_FILENAME_COMPONENT(TARGET_PATH ${TARGET_LOC} PATH) + ADD_CUSTOM_COMMAND(TARGET lp_test POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CPLEX_BIN_DIR}/cplex91.dll ${TARGET_PATH} + ) + ENDIF() +ENDIF() + +IF(LEMON_HAVE_MIP) + IF(${CMAKE_BUILD_TYPE} STREQUAL "Maintainer") + ADD_EXECUTABLE(mip_test mip_test.cc) + ELSE() + ADD_EXECUTABLE(mip_test EXCLUDE_FROM_ALL mip_test.cc) + ENDIF() + + SET(MIP_TEST_LIBS lemon) + + IF(LEMON_HAVE_GLPK) + SET(MIP_TEST_LIBS ${MIP_TEST_LIBS} ${GLPK_LIBRARIES}) + ENDIF() + IF(LEMON_HAVE_CPLEX) + SET(MIP_TEST_LIBS ${MIP_TEST_LIBS} ${CPLEX_LIBRARIES}) + ENDIF() + IF(LEMON_HAVE_CBC) + SET(MIP_TEST_LIBS ${MIP_TEST_LIBS} ${COIN_CBC_LIBRARIES}) + ENDIF() + + TARGET_LINK_LIBRARIES(mip_test ${MIP_TEST_LIBS}) + ADD_TEST(mip_test mip_test) + ADD_DEPENDENCIES(check mip_test) + + IF(WIN32 AND LEMON_HAVE_GLPK) + GET_TARGET_PROPERTY(TARGET_LOC mip_test LOCATION) + GET_FILENAME_COMPONENT(TARGET_PATH ${TARGET_LOC} PATH) + ADD_CUSTOM_COMMAND(TARGET mip_test POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/glpk.dll ${TARGET_PATH} + COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/libltdl3.dll ${TARGET_PATH} + COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/zlib1.dll ${TARGET_PATH} + ) + ENDIF() + + IF(WIN32 AND LEMON_HAVE_CPLEX) + GET_TARGET_PROPERTY(TARGET_LOC mip_test LOCATION) + GET_FILENAME_COMPONENT(TARGET_PATH ${TARGET_LOC} PATH) + ADD_CUSTOM_COMMAND(TARGET mip_test POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CPLEX_BIN_DIR}/cplex91.dll ${TARGET_PATH} + ) + ENDIF() +ENDIF() + +FOREACH(TEST_NAME ${TESTS}) + IF(${CMAKE_BUILD_TYPE} STREQUAL "Maintainer") + ADD_EXECUTABLE(${TEST_NAME} ${TEST_NAME}.cc) + ELSE() + ADD_EXECUTABLE(${TEST_NAME} EXCLUDE_FROM_ALL ${TEST_NAME}.cc) + ENDIF() + TARGET_LINK_LIBRARIES(${TEST_NAME} lemon) + IF(TEST_WITH_VALGRIND) + ADD_TEST(${TEST_NAME} + valgrind --error-exitcode=1 ${VALGRIND_FLAGS} + ${CMAKE_CURRENT_BINARY_DIR}/${TEST_NAME} ) + ELSE() + ADD_TEST(${TEST_NAME} ${TEST_NAME}) + ENDIF() + ADD_DEPENDENCIES(check ${TEST_NAME}) +ENDFOREACH() diff --git a/lemon/test/Makefile.am b/lemon/test/Makefile.am new file mode 100644 index 0000000..b5fcca7 --- /dev/null +++ b/lemon/test/Makefile.am @@ -0,0 +1,101 @@ +if USE_VALGRIND +TESTS_ENVIRONMENT=$(top_srcdir)/scripts/valgrind-wrapper.sh +endif + +EXTRA_DIST += \ + test/CMakeLists.txt + +noinst_HEADERS += \ + test/graph_test.h \ + test/test_tools.h + +check_PROGRAMS += \ + test/adaptors_test \ + test/bellman_ford_test \ + test/bfs_test \ + test/circulation_test \ + test/connectivity_test \ + test/counter_test \ + test/dfs_test \ + test/digraph_test \ + test/dijkstra_test \ + test/dim_test \ + test/edge_set_test \ + test/error_test \ + test/euler_test \ + test/fractional_matching_test \ + test/gomory_hu_test \ + test/graph_copy_test \ + test/graph_test \ + test/graph_utils_test \ + test/hao_orlin_test \ + test/heap_test \ + test/kruskal_test \ + test/lgf_test \ + test/maps_test \ + test/matching_test \ + test/min_cost_arborescence_test \ + test/min_cost_flow_test \ + test/min_mean_cycle_test \ + test/path_test \ + test/planarity_test \ + test/preflow_test \ + test/radix_sort_test \ + test/random_test \ + test/suurballe_test \ + test/test_tools_fail \ + test/test_tools_pass \ + test/time_measure_test \ + test/unionfind_test + +test_test_tools_pass_DEPENDENCIES = demo + +if HAVE_LP +check_PROGRAMS += test/lp_test +endif HAVE_LP +if HAVE_MIP +check_PROGRAMS += test/mip_test +endif HAVE_MIP + +TESTS += $(check_PROGRAMS) +XFAIL_TESTS += test/test_tools_fail$(EXEEXT) + +test_adaptors_test_SOURCES = test/adaptors_test.cc +test_bellman_ford_test_SOURCES = test/bellman_ford_test.cc +test_bfs_test_SOURCES = test/bfs_test.cc +test_circulation_test_SOURCES = test/circulation_test.cc +test_counter_test_SOURCES = test/counter_test.cc +test_connectivity_test_SOURCES = test/connectivity_test.cc +test_dfs_test_SOURCES = test/dfs_test.cc +test_digraph_test_SOURCES = test/digraph_test.cc +test_dijkstra_test_SOURCES = test/dijkstra_test.cc +test_dim_test_SOURCES = test/dim_test.cc +test_edge_set_test_SOURCES = test/edge_set_test.cc +test_error_test_SOURCES = test/error_test.cc +test_euler_test_SOURCES = test/euler_test.cc +test_fractional_matching_test_SOURCES = test/fractional_matching_test.cc +test_gomory_hu_test_SOURCES = test/gomory_hu_test.cc +test_graph_copy_test_SOURCES = test/graph_copy_test.cc +test_graph_test_SOURCES = test/graph_test.cc +test_graph_utils_test_SOURCES = test/graph_utils_test.cc +test_hao_orlin_test_SOURCES = test/hao_orlin_test.cc +test_heap_test_SOURCES = test/heap_test.cc +test_kruskal_test_SOURCES = test/kruskal_test.cc +test_lgf_test_SOURCES = test/lgf_test.cc +test_lp_test_SOURCES = test/lp_test.cc +test_maps_test_SOURCES = test/maps_test.cc +test_mip_test_SOURCES = test/mip_test.cc +test_matching_test_SOURCES = test/matching_test.cc +test_min_cost_arborescence_test_SOURCES = test/min_cost_arborescence_test.cc +test_min_cost_flow_test_SOURCES = test/min_cost_flow_test.cc +test_min_mean_cycle_test_SOURCES = test/min_mean_cycle_test.cc +test_path_test_SOURCES = test/path_test.cc +test_planarity_test_SOURCES = test/planarity_test.cc +test_preflow_test_SOURCES = test/preflow_test.cc +test_radix_sort_test_SOURCES = test/radix_sort_test.cc +test_suurballe_test_SOURCES = test/suurballe_test.cc +test_random_test_SOURCES = test/random_test.cc +test_test_tools_fail_SOURCES = test/test_tools_fail.cc +test_test_tools_pass_SOURCES = test/test_tools_pass.cc +test_time_measure_test_SOURCES = test/time_measure_test.cc +test_unionfind_test_SOURCES = test/unionfind_test.cc diff --git a/lemon/test/adaptors_test.cc b/lemon/test/adaptors_test.cc new file mode 100644 index 0000000..9c625f2 --- /dev/null +++ b/lemon/test/adaptors_test.cc @@ -0,0 +1,1463 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2009 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <iostream> +#include <limits> + +#include <lemon/list_graph.h> +#include <lemon/grid_graph.h> +#include <lemon/bfs.h> +#include <lemon/path.h> + +#include <lemon/concepts/digraph.h> +#include <lemon/concepts/graph.h> +#include <lemon/concepts/graph_components.h> +#include <lemon/concepts/maps.h> +#include <lemon/concept_check.h> + +#include <lemon/adaptors.h> + +#include "test/test_tools.h" +#include "test/graph_test.h" + +using namespace lemon; + +void checkReverseDigraph() { + // Check concepts + checkConcept<concepts::Digraph, ReverseDigraph<concepts::Digraph> >(); + checkConcept<concepts::Digraph, ReverseDigraph<ListDigraph> >(); + checkConcept<concepts::AlterableDigraphComponent<>, + ReverseDigraph<ListDigraph> >(); + checkConcept<concepts::ExtendableDigraphComponent<>, + ReverseDigraph<ListDigraph> >(); + checkConcept<concepts::ErasableDigraphComponent<>, + ReverseDigraph<ListDigraph> >(); + checkConcept<concepts::ClearableDigraphComponent<>, + ReverseDigraph<ListDigraph> >(); + + // Create a digraph and an adaptor + typedef ListDigraph Digraph; + typedef ReverseDigraph<Digraph> Adaptor; + + Digraph digraph; + Adaptor adaptor(digraph); + + // Add nodes and arcs to the original digraph + Digraph::Node n1 = digraph.addNode(); + Digraph::Node n2 = digraph.addNode(); + Digraph::Node n3 = digraph.addNode(); + + Digraph::Arc a1 = digraph.addArc(n1, n2); + Digraph::Arc a2 = digraph.addArc(n1, n3); + Digraph::Arc a3 = digraph.addArc(n2, n3); + + // Check the adaptor + checkGraphNodeList(adaptor, 3); + checkGraphArcList(adaptor, 3); + checkGraphConArcList(adaptor, 3); + + checkGraphOutArcList(adaptor, n1, 0); + checkGraphOutArcList(adaptor, n2, 1); + checkGraphOutArcList(adaptor, n3, 2); + + checkGraphInArcList(adaptor, n1, 2); + checkGraphInArcList(adaptor, n2, 1); + checkGraphInArcList(adaptor, n3, 0); + + checkNodeIds(adaptor); + checkArcIds(adaptor); + + checkGraphNodeMap(adaptor); + checkGraphArcMap(adaptor); + + // Check the orientation of the arcs + for (Adaptor::ArcIt a(adaptor); a != INVALID; ++a) { + check(adaptor.source(a) == digraph.target(a), "Wrong reverse"); + check(adaptor.target(a) == digraph.source(a), "Wrong reverse"); + } + + // Add and erase nodes and arcs in the digraph through the adaptor + Adaptor::Node n4 = adaptor.addNode(); + + Adaptor::Arc a4 = adaptor.addArc(n4, n3); + Adaptor::Arc a5 = adaptor.addArc(n2, n4); + Adaptor::Arc a6 = adaptor.addArc(n2, n4); + Adaptor::Arc a7 = adaptor.addArc(n1, n4); + Adaptor::Arc a8 = adaptor.addArc(n1, n2); + + adaptor.erase(a1); + adaptor.erase(n3); + + // Check the adaptor + checkGraphNodeList(adaptor, 3); + checkGraphArcList(adaptor, 4); + checkGraphConArcList(adaptor, 4); + + checkGraphOutArcList(adaptor, n1, 2); + checkGraphOutArcList(adaptor, n2, 2); + checkGraphOutArcList(adaptor, n4, 0); + + checkGraphInArcList(adaptor, n1, 0); + checkGraphInArcList(adaptor, n2, 1); + checkGraphInArcList(adaptor, n4, 3); + + checkNodeIds(adaptor); + checkArcIds(adaptor); + + checkGraphNodeMap(adaptor); + checkGraphArcMap(adaptor); + + // Check the digraph + checkGraphNodeList(digraph, 3); + checkGraphArcList(digraph, 4); + checkGraphConArcList(digraph, 4); + + checkGraphOutArcList(digraph, n1, 0); + checkGraphOutArcList(digraph, n2, 1); + checkGraphOutArcList(digraph, n4, 3); + + checkGraphInArcList(digraph, n1, 2); + checkGraphInArcList(digraph, n2, 2); + checkGraphInArcList(digraph, n4, 0); + + checkNodeIds(digraph); + checkArcIds(digraph); + + checkGraphNodeMap(digraph); + checkGraphArcMap(digraph); + + // Check the conversion of nodes and arcs + Digraph::Node nd = n4; + nd = n4; + Adaptor::Node na = n1; + na = n2; + Digraph::Arc ad = a4; + ad = a5; + Adaptor::Arc aa = a1; + aa = a2; +} + +void checkSubDigraph() { + // Check concepts + checkConcept<concepts::Digraph, SubDigraph<concepts::Digraph> >(); + checkConcept<concepts::Digraph, SubDigraph<ListDigraph> >(); + checkConcept<concepts::AlterableDigraphComponent<>, + SubDigraph<ListDigraph> >(); + checkConcept<concepts::ExtendableDigraphComponent<>, + SubDigraph<ListDigraph> >(); + checkConcept<concepts::ErasableDigraphComponent<>, + SubDigraph<ListDigraph> >(); + checkConcept<concepts::ClearableDigraphComponent<>, + SubDigraph<ListDigraph> >(); + + // Create a digraph and an adaptor + typedef ListDigraph Digraph; + typedef Digraph::NodeMap<bool> NodeFilter; + typedef Digraph::ArcMap<bool> ArcFilter; + typedef SubDigraph<Digraph, NodeFilter, ArcFilter> Adaptor; + + Digraph digraph; + NodeFilter node_filter(digraph); + ArcFilter arc_filter(digraph); + Adaptor adaptor(digraph, node_filter, arc_filter); + + // Add nodes and arcs to the original digraph and the adaptor + Digraph::Node n1 = digraph.addNode(); + Digraph::Node n2 = digraph.addNode(); + Adaptor::Node n3 = adaptor.addNode(); + + node_filter[n1] = node_filter[n2] = node_filter[n3] = true; + + Digraph::Arc a1 = digraph.addArc(n1, n2); + Digraph::Arc a2 = digraph.addArc(n1, n3); + Adaptor::Arc a3 = adaptor.addArc(n2, n3); + + arc_filter[a1] = arc_filter[a2] = arc_filter[a3] = true; + + checkGraphNodeList(adaptor, 3); + checkGraphArcList(adaptor, 3); + checkGraphConArcList(adaptor, 3); + + checkGraphOutArcList(adaptor, n1, 2); + checkGraphOutArcList(adaptor, n2, 1); + checkGraphOutArcList(adaptor, n3, 0); + + checkGraphInArcList(adaptor, n1, 0); + checkGraphInArcList(adaptor, n2, 1); + checkGraphInArcList(adaptor, n3, 2); + + checkNodeIds(adaptor); + checkArcIds(adaptor); + + checkGraphNodeMap(adaptor); + checkGraphArcMap(adaptor); + + // Hide an arc + adaptor.status(a2, false); + adaptor.disable(a3); + if (!adaptor.status(a3)) adaptor.enable(a3); + + checkGraphNodeList(adaptor, 3); + checkGraphArcList(adaptor, 2); + checkGraphConArcList(adaptor, 2); + + checkGraphOutArcList(adaptor, n1, 1); + checkGraphOutArcList(adaptor, n2, 1); + checkGraphOutArcList(adaptor, n3, 0); + + checkGraphInArcList(adaptor, n1, 0); + checkGraphInArcList(adaptor, n2, 1); + checkGraphInArcList(adaptor, n3, 1); + + checkNodeIds(adaptor); + checkArcIds(adaptor); + + checkGraphNodeMap(adaptor); + checkGraphArcMap(adaptor); + + // Hide a node + adaptor.status(n1, false); + adaptor.disable(n3); + if (!adaptor.status(n3)) adaptor.enable(n3); + + checkGraphNodeList(adaptor, 2); + checkGraphArcList(adaptor, 1); + checkGraphConArcList(adaptor, 1); + + checkGraphOutArcList(adaptor, n2, 1); + checkGraphOutArcList(adaptor, n3, 0); + + checkGraphInArcList(adaptor, n2, 0); + checkGraphInArcList(adaptor, n3, 1); + + checkNodeIds(adaptor); + checkArcIds(adaptor); + + checkGraphNodeMap(adaptor); + checkGraphArcMap(adaptor); + + // Hide all nodes and arcs + node_filter[n1] = node_filter[n2] = node_filter[n3] = false; + arc_filter[a1] = arc_filter[a2] = arc_filter[a3] = false; + + checkGraphNodeList(adaptor, 0); + checkGraphArcList(adaptor, 0); + checkGraphConArcList(adaptor, 0); + + checkNodeIds(adaptor); + checkArcIds(adaptor); + + checkGraphNodeMap(adaptor); + checkGraphArcMap(adaptor); + + // Check the conversion of nodes and arcs + Digraph::Node nd = n3; + nd = n3; + Adaptor::Node na = n1; + na = n2; + Digraph::Arc ad = a3; + ad = a3; + Adaptor::Arc aa = a1; + aa = a2; +} + +void checkFilterNodes1() { + // Check concepts + checkConcept<concepts::Digraph, FilterNodes<concepts::Digraph> >(); + checkConcept<concepts::Digraph, FilterNodes<ListDigraph> >(); + checkConcept<concepts::AlterableDigraphComponent<>, + FilterNodes<ListDigraph> >(); + checkConcept<concepts::ExtendableDigraphComponent<>, + FilterNodes<ListDigraph> >(); + checkConcept<concepts::ErasableDigraphComponent<>, + FilterNodes<ListDigraph> >(); + checkConcept<concepts::ClearableDigraphComponent<>, + FilterNodes<ListDigraph> >(); + + // Create a digraph and an adaptor + typedef ListDigraph Digraph; + typedef Digraph::NodeMap<bool> NodeFilter; + typedef FilterNodes<Digraph, NodeFilter> Adaptor; + + Digraph digraph; + NodeFilter node_filter(digraph); + Adaptor adaptor(digraph, node_filter); + + // Add nodes and arcs to the original digraph and the adaptor + Digraph::Node n1 = digraph.addNode(); + Digraph::Node n2 = digraph.addNode(); + Adaptor::Node n3 = adaptor.addNode(); + + node_filter[n1] = node_filter[n2] = node_filter[n3] = true; + + Digraph::Arc a1 = digraph.addArc(n1, n2); + Digraph::Arc a2 = digraph.addArc(n1, n3); + Adaptor::Arc a3 = adaptor.addArc(n2, n3); + + checkGraphNodeList(adaptor, 3); + checkGraphArcList(adaptor, 3); + checkGraphConArcList(adaptor, 3); + + checkGraphOutArcList(adaptor, n1, 2); + checkGraphOutArcList(adaptor, n2, 1); + checkGraphOutArcList(adaptor, n3, 0); + + checkGraphInArcList(adaptor, n1, 0); + checkGraphInArcList(adaptor, n2, 1); + checkGraphInArcList(adaptor, n3, 2); + + checkNodeIds(adaptor); + checkArcIds(adaptor); + + checkGraphNodeMap(adaptor); + checkGraphArcMap(adaptor); + + // Hide a node + adaptor.status(n1, false); + adaptor.disable(n3); + if (!adaptor.status(n3)) adaptor.enable(n3); + + checkGraphNodeList(adaptor, 2); + checkGraphArcList(adaptor, 1); + checkGraphConArcList(adaptor, 1); + + checkGraphOutArcList(adaptor, n2, 1); + checkGraphOutArcList(adaptor, n3, 0); + + checkGraphInArcList(adaptor, n2, 0); + checkGraphInArcList(adaptor, n3, 1); + + checkNodeIds(adaptor); + checkArcIds(adaptor); + + checkGraphNodeMap(adaptor); + checkGraphArcMap(adaptor); + + // Hide all nodes + node_filter[n1] = node_filter[n2] = node_filter[n3] = false; + + checkGraphNodeList(adaptor, 0); + checkGraphArcList(adaptor, 0); + checkGraphConArcList(adaptor, 0); + + checkNodeIds(adaptor); + checkArcIds(adaptor); + + checkGraphNodeMap(adaptor); + checkGraphArcMap(adaptor); + + // Check the conversion of nodes and arcs + Digraph::Node nd = n3; + nd = n3; + Adaptor::Node na = n1; + na = n2; + Digraph::Arc ad = a3; + ad = a3; + Adaptor::Arc aa = a1; + aa = a2; +} + +void checkFilterArcs() { + // Check concepts + checkConcept<concepts::Digraph, FilterArcs<concepts::Digraph> >(); + checkConcept<concepts::Digraph, FilterArcs<ListDigraph> >(); + checkConcept<concepts::AlterableDigraphComponent<>, + FilterArcs<ListDigraph> >(); + checkConcept<concepts::ExtendableDigraphComponent<>, + FilterArcs<ListDigraph> >(); + checkConcept<concepts::ErasableDigraphComponent<>, + FilterArcs<ListDigraph> >(); + checkConcept<concepts::ClearableDigraphComponent<>, + FilterArcs<ListDigraph> >(); + + // Create a digraph and an adaptor + typedef ListDigraph Digraph; + typedef Digraph::ArcMap<bool> ArcFilter; + typedef FilterArcs<Digraph, ArcFilter> Adaptor; + + Digraph digraph; + ArcFilter arc_filter(digraph); + Adaptor adaptor(digraph, arc_filter); + + // Add nodes and arcs to the original digraph and the adaptor + Digraph::Node n1 = digraph.addNode(); + Digraph::Node n2 = digraph.addNode(); + Adaptor::Node n3 = adaptor.addNode(); + + Digraph::Arc a1 = digraph.addArc(n1, n2); + Digraph::Arc a2 = digraph.addArc(n1, n3); + Adaptor::Arc a3 = adaptor.addArc(n2, n3); + + arc_filter[a1] = arc_filter[a2] = arc_filter[a3] = true; + + checkGraphNodeList(adaptor, 3); + checkGraphArcList(adaptor, 3); + checkGraphConArcList(adaptor, 3); + + checkGraphOutArcList(adaptor, n1, 2); + checkGraphOutArcList(adaptor, n2, 1); + checkGraphOutArcList(adaptor, n3, 0); + + checkGraphInArcList(adaptor, n1, 0); + checkGraphInArcList(adaptor, n2, 1); + checkGraphInArcList(adaptor, n3, 2); + + checkNodeIds(adaptor); + checkArcIds(adaptor); + + checkGraphNodeMap(adaptor); + checkGraphArcMap(adaptor); + + // Hide an arc + adaptor.status(a2, false); + adaptor.disable(a3); + if (!adaptor.status(a3)) adaptor.enable(a3); + + checkGraphNodeList(adaptor, 3); + checkGraphArcList(adaptor, 2); + checkGraphConArcList(adaptor, 2); + + checkGraphOutArcList(adaptor, n1, 1); + checkGraphOutArcList(adaptor, n2, 1); + checkGraphOutArcList(adaptor, n3, 0); + + checkGraphInArcList(adaptor, n1, 0); + checkGraphInArcList(adaptor, n2, 1); + checkGraphInArcList(adaptor, n3, 1); + + checkNodeIds(adaptor); + checkArcIds(adaptor); + + checkGraphNodeMap(adaptor); + checkGraphArcMap(adaptor); + + // Hide all arcs + arc_filter[a1] = arc_filter[a2] = arc_filter[a3] = false; + + checkGraphNodeList(adaptor, 3); + checkGraphArcList(adaptor, 0); + checkGraphConArcList(adaptor, 0); + + checkNodeIds(adaptor); + checkArcIds(adaptor); + + checkGraphNodeMap(adaptor); + checkGraphArcMap(adaptor); + + // Check the conversion of nodes and arcs + Digraph::Node nd = n3; + nd = n3; + Adaptor::Node na = n1; + na = n2; + Digraph::Arc ad = a3; + ad = a3; + Adaptor::Arc aa = a1; + aa = a2; +} + +void checkUndirector() { + // Check concepts + checkConcept<concepts::Graph, Undirector<concepts::Digraph> >(); + checkConcept<concepts::Graph, Undirector<ListDigraph> >(); + checkConcept<concepts::AlterableGraphComponent<>, + Undirector<ListDigraph> >(); + checkConcept<concepts::ExtendableGraphComponent<>, + Undirector<ListDigraph> >(); + checkConcept<concepts::ErasableGraphComponent<>, + Undirector<ListDigraph> >(); + checkConcept<concepts::ClearableGraphComponent<>, + Undirector<ListDigraph> >(); + + + // Create a digraph and an adaptor + typedef ListDigraph Digraph; + typedef Undirector<Digraph> Adaptor; + + Digraph digraph; + Adaptor adaptor(digraph); + + // Add nodes and arcs/edges to the original digraph and the adaptor + Digraph::Node n1 = digraph.addNode(); + Digraph::Node n2 = digraph.addNode(); + Adaptor::Node n3 = adaptor.addNode(); + + Digraph::Arc a1 = digraph.addArc(n1, n2); + Digraph::Arc a2 = digraph.addArc(n1, n3); + Adaptor::Edge e3 = adaptor.addEdge(n2, n3); + + // Check the original digraph + checkGraphNodeList(digraph, 3); + checkGraphArcList(digraph, 3); + checkGraphConArcList(digraph, 3); + + checkGraphOutArcList(digraph, n1, 2); + checkGraphOutArcList(digraph, n2, 1); + checkGraphOutArcList(digraph, n3, 0); + + checkGraphInArcList(digraph, n1, 0); + checkGraphInArcList(digraph, n2, 1); + checkGraphInArcList(digraph, n3, 2); + + checkNodeIds(digraph); + checkArcIds(digraph); + + checkGraphNodeMap(digraph); + checkGraphArcMap(digraph); + + // Check the adaptor + checkGraphNodeList(adaptor, 3); + checkGraphArcList(adaptor, 6); + checkGraphEdgeList(adaptor, 3); + checkGraphConArcList(adaptor, 6); + checkGraphConEdgeList(adaptor, 3); + + checkGraphIncEdgeArcLists(adaptor, n1, 2); + checkGraphIncEdgeArcLists(adaptor, n2, 2); + checkGraphIncEdgeArcLists(adaptor, n3, 2); + + checkNodeIds(adaptor); + checkArcIds(adaptor); + checkEdgeIds(adaptor); + + checkGraphNodeMap(adaptor); + checkGraphArcMap(adaptor); + checkGraphEdgeMap(adaptor); + + // Check the edges of the adaptor + for (Adaptor::EdgeIt e(adaptor); e != INVALID; ++e) { + check(adaptor.u(e) == digraph.source(e), "Wrong undir"); + check(adaptor.v(e) == digraph.target(e), "Wrong undir"); + } + + // Check CombinedArcMap + typedef Adaptor::CombinedArcMap + <Digraph::ArcMap<int>, Digraph::ArcMap<int> > IntCombinedMap; + typedef Adaptor::CombinedArcMap + <Digraph::ArcMap<bool>, Digraph::ArcMap<bool> > BoolCombinedMap; + checkConcept<concepts::ReferenceMap<Adaptor::Arc, int, int&, const int&>, + IntCombinedMap>(); + checkConcept<concepts::ReferenceMap<Adaptor::Arc, bool, bool&, const bool&>, + BoolCombinedMap>(); + + Digraph::ArcMap<int> fw_map(digraph), bk_map(digraph); + for (Digraph::ArcIt a(digraph); a != INVALID; ++a) { + fw_map[a] = digraph.id(a); + bk_map[a] = -digraph.id(a); + } + + Adaptor::CombinedArcMap<Digraph::ArcMap<int>, Digraph::ArcMap<int> > + comb_map(fw_map, bk_map); + for (Adaptor::ArcIt a(adaptor); a != INVALID; ++a) { + if (adaptor.source(a) == digraph.source(a)) { + check(comb_map[a] == fw_map[a], "Wrong combined map"); + } else { + check(comb_map[a] == bk_map[a], "Wrong combined map"); + } + } + + // Check the conversion of nodes and arcs/edges + Digraph::Node nd = n3; + nd = n3; + Adaptor::Node na = n1; + na = n2; + Digraph::Arc ad = e3; + ad = e3; + Adaptor::Edge ea = a1; + ea = a2; +} + +void checkResidualDigraph() { + // Check concepts + checkConcept<concepts::Digraph, ResidualDigraph<concepts::Digraph> >(); + checkConcept<concepts::Digraph, ResidualDigraph<ListDigraph> >(); + + // Create a digraph and an adaptor + typedef ListDigraph Digraph; + typedef Digraph::ArcMap<int> IntArcMap; + typedef ResidualDigraph<Digraph, IntArcMap> Adaptor; + + Digraph digraph; + IntArcMap capacity(digraph), flow(digraph); + Adaptor adaptor(digraph, capacity, flow); + + Digraph::Node n1 = digraph.addNode(); + Digraph::Node n2 = digraph.addNode(); + Digraph::Node n3 = digraph.addNode(); + Digraph::Node n4 = digraph.addNode(); + + Digraph::Arc a1 = digraph.addArc(n1, n2); + Digraph::Arc a2 = digraph.addArc(n1, n3); + Digraph::Arc a3 = digraph.addArc(n1, n4); + Digraph::Arc a4 = digraph.addArc(n2, n3); + Digraph::Arc a5 = digraph.addArc(n2, n4); + Digraph::Arc a6 = digraph.addArc(n3, n4); + + capacity[a1] = 8; + capacity[a2] = 6; + capacity[a3] = 4; + capacity[a4] = 4; + capacity[a5] = 6; + capacity[a6] = 10; + + // Check the adaptor with various flow values + for (Digraph::ArcIt a(digraph); a != INVALID; ++a) { + flow[a] = 0; + } + + checkGraphNodeList(adaptor, 4); + checkGraphArcList(adaptor, 6); + checkGraphConArcList(adaptor, 6); + + checkGraphOutArcList(adaptor, n1, 3); + checkGraphOutArcList(adaptor, n2, 2); + checkGraphOutArcList(adaptor, n3, 1); + checkGraphOutArcList(adaptor, n4, 0); + + checkGraphInArcList(adaptor, n1, 0); + checkGraphInArcList(adaptor, n2, 1); + checkGraphInArcList(adaptor, n3, 2); + checkGraphInArcList(adaptor, n4, 3); + + for (Digraph::ArcIt a(digraph); a != INVALID; ++a) { + flow[a] = capacity[a] / 2; + } + + checkGraphNodeList(adaptor, 4); + checkGraphArcList(adaptor, 12); + checkGraphConArcList(adaptor, 12); + + checkGraphOutArcList(adaptor, n1, 3); + checkGraphOutArcList(adaptor, n2, 3); + checkGraphOutArcList(adaptor, n3, 3); + checkGraphOutArcList(adaptor, n4, 3); + + checkGraphInArcList(adaptor, n1, 3); + checkGraphInArcList(adaptor, n2, 3); + checkGraphInArcList(adaptor, n3, 3); + checkGraphInArcList(adaptor, n4, 3); + + checkNodeIds(adaptor); + checkArcIds(adaptor); + + checkGraphNodeMap(adaptor); + checkGraphArcMap(adaptor); + + for (Digraph::ArcIt a(digraph); a != INVALID; ++a) { + flow[a] = capacity[a]; + } + + checkGraphNodeList(adaptor, 4); + checkGraphArcList(adaptor, 6); + checkGraphConArcList(adaptor, 6); + + checkGraphOutArcList(adaptor, n1, 0); + checkGraphOutArcList(adaptor, n2, 1); + checkGraphOutArcList(adaptor, n3, 2); + checkGraphOutArcList(adaptor, n4, 3); + + checkGraphInArcList(adaptor, n1, 3); + checkGraphInArcList(adaptor, n2, 2); + checkGraphInArcList(adaptor, n3, 1); + checkGraphInArcList(adaptor, n4, 0); + + // Saturate all backward arcs + // (set the flow to zero on all forward arcs) + for (Adaptor::ArcIt a(adaptor); a != INVALID; ++a) { + if (adaptor.backward(a)) + adaptor.augment(a, adaptor.residualCapacity(a)); + } + + checkGraphNodeList(adaptor, 4); + checkGraphArcList(adaptor, 6); + checkGraphConArcList(adaptor, 6); + + checkGraphOutArcList(adaptor, n1, 3); + checkGraphOutArcList(adaptor, n2, 2); + checkGraphOutArcList(adaptor, n3, 1); + checkGraphOutArcList(adaptor, n4, 0); + + checkGraphInArcList(adaptor, n1, 0); + checkGraphInArcList(adaptor, n2, 1); + checkGraphInArcList(adaptor, n3, 2); + checkGraphInArcList(adaptor, n4, 3); + + // Find maximum flow by augmenting along shortest paths + int flow_value = 0; + Adaptor::ResidualCapacity res_cap(adaptor); + while (true) { + + Bfs<Adaptor> bfs(adaptor); + bfs.run(n1, n4); + + if (!bfs.reached(n4)) break; + + Path<Adaptor> p = bfs.path(n4); + + int min = std::numeric_limits<int>::max(); + for (Path<Adaptor>::ArcIt a(p); a != INVALID; ++a) { + if (res_cap[a] < min) min = res_cap[a]; + } + + for (Path<Adaptor>::ArcIt a(p); a != INVALID; ++a) { + adaptor.augment(a, min); + } + flow_value += min; + } + + check(flow_value == 18, "Wrong flow with res graph adaptor"); + + // Check forward() and backward() + for (Adaptor::ArcIt a(adaptor); a != INVALID; ++a) { + check(adaptor.forward(a) != adaptor.backward(a), + "Wrong forward() or backward()"); + check((adaptor.forward(a) && adaptor.forward(Digraph::Arc(a)) == a) || + (adaptor.backward(a) && adaptor.backward(Digraph::Arc(a)) == a), + "Wrong forward() or backward()"); + } + + // Check the conversion of nodes and arcs + Digraph::Node nd = Adaptor::NodeIt(adaptor); + nd = ++Adaptor::NodeIt(adaptor); + Adaptor::Node na = n1; + na = n2; + Digraph::Arc ad = Adaptor::ArcIt(adaptor); + ad = ++Adaptor::ArcIt(adaptor); +} + +void checkSplitNodes() { + // Check concepts + checkConcept<concepts::Digraph, SplitNodes<concepts::Digraph> >(); + checkConcept<concepts::Digraph, SplitNodes<ListDigraph> >(); + + // Create a digraph and an adaptor + typedef ListDigraph Digraph; + typedef SplitNodes<Digraph> Adaptor; + + Digraph digraph; + Adaptor adaptor(digraph); + + Digraph::Node n1 = digraph.addNode(); + Digraph::Node n2 = digraph.addNode(); + Digraph::Node n3 = digraph.addNode(); + + Digraph::Arc a1 = digraph.addArc(n1, n2); + Digraph::Arc a2 = digraph.addArc(n1, n3); + Digraph::Arc a3 = digraph.addArc(n2, n3); + + checkGraphNodeList(adaptor, 6); + checkGraphArcList(adaptor, 6); + checkGraphConArcList(adaptor, 6); + + checkGraphOutArcList(adaptor, adaptor.inNode(n1), 1); + checkGraphOutArcList(adaptor, adaptor.outNode(n1), 2); + checkGraphOutArcList(adaptor, adaptor.inNode(n2), 1); + checkGraphOutArcList(adaptor, adaptor.outNode(n2), 1); + checkGraphOutArcList(adaptor, adaptor.inNode(n3), 1); + checkGraphOutArcList(adaptor, adaptor.outNode(n3), 0); + + checkGraphInArcList(adaptor, adaptor.inNode(n1), 0); + checkGraphInArcList(adaptor, adaptor.outNode(n1), 1); + checkGraphInArcList(adaptor, adaptor.inNode(n2), 1); + checkGraphInArcList(adaptor, adaptor.outNode(n2), 1); + checkGraphInArcList(adaptor, adaptor.inNode(n3), 2); + checkGraphInArcList(adaptor, adaptor.outNode(n3), 1); + + checkNodeIds(adaptor); + checkArcIds(adaptor); + + checkGraphNodeMap(adaptor); + checkGraphArcMap(adaptor); + + // Check split + for (Adaptor::ArcIt a(adaptor); a != INVALID; ++a) { + if (adaptor.origArc(a)) { + Digraph::Arc oa = a; + check(adaptor.source(a) == adaptor.outNode(digraph.source(oa)), + "Wrong split"); + check(adaptor.target(a) == adaptor.inNode(digraph.target(oa)), + "Wrong split"); + } else { + Digraph::Node on = a; + check(adaptor.source(a) == adaptor.inNode(on), "Wrong split"); + check(adaptor.target(a) == adaptor.outNode(on), "Wrong split"); + } + } + + // Check combined node map + typedef Adaptor::CombinedNodeMap + <Digraph::NodeMap<int>, Digraph::NodeMap<int> > IntCombinedNodeMap; + typedef Adaptor::CombinedNodeMap + <Digraph::NodeMap<bool>, Digraph::NodeMap<bool> > BoolCombinedNodeMap; + checkConcept<concepts::ReferenceMap<Adaptor::Node, int, int&, const int&>, + IntCombinedNodeMap>(); +//checkConcept<concepts::ReferenceMap<Adaptor::Node, bool, bool&, const bool&>, +// BoolCombinedNodeMap>(); + checkConcept<concepts::ReadWriteMap<Adaptor::Node, bool>, + BoolCombinedNodeMap>(); + + Digraph::NodeMap<int> in_map(digraph), out_map(digraph); + for (Digraph::NodeIt n(digraph); n != INVALID; ++n) { + in_map[n] = digraph.id(n); + out_map[n] = -digraph.id(n); + } + + Adaptor::CombinedNodeMap<Digraph::NodeMap<int>, Digraph::NodeMap<int> > + node_map(in_map, out_map); + for (Adaptor::NodeIt n(adaptor); n != INVALID; ++n) { + if (adaptor.inNode(n)) { + check(node_map[n] == in_map[n], "Wrong combined node map"); + } else { + check(node_map[n] == out_map[n], "Wrong combined node map"); + } + } + + // Check combined arc map + typedef Adaptor::CombinedArcMap + <Digraph::ArcMap<int>, Digraph::NodeMap<int> > IntCombinedArcMap; + typedef Adaptor::CombinedArcMap + <Digraph::ArcMap<bool>, Digraph::NodeMap<bool> > BoolCombinedArcMap; + checkConcept<concepts::ReferenceMap<Adaptor::Arc, int, int&, const int&>, + IntCombinedArcMap>(); +//checkConcept<concepts::ReferenceMap<Adaptor::Arc, bool, bool&, const bool&>, +// BoolCombinedArcMap>(); + checkConcept<concepts::ReadWriteMap<Adaptor::Arc, bool>, + BoolCombinedArcMap>(); + + Digraph::ArcMap<int> a_map(digraph); + for (Digraph::ArcIt a(digraph); a != INVALID; ++a) { + a_map[a] = digraph.id(a); + } + + Adaptor::CombinedArcMap<Digraph::ArcMap<int>, Digraph::NodeMap<int> > + arc_map(a_map, out_map); + for (Digraph::ArcIt a(digraph); a != INVALID; ++a) { + check(arc_map[adaptor.arc(a)] == a_map[a], "Wrong combined arc map"); + } + for (Digraph::NodeIt n(digraph); n != INVALID; ++n) { + check(arc_map[adaptor.arc(n)] == out_map[n], "Wrong combined arc map"); + } + + // Check the conversion of nodes + Digraph::Node nd = adaptor.inNode(n1); + check (nd == n1, "Wrong node conversion"); + nd = adaptor.outNode(n2); + check (nd == n2, "Wrong node conversion"); +} + +void checkSubGraph() { + // Check concepts + checkConcept<concepts::Graph, SubGraph<concepts::Graph> >(); + checkConcept<concepts::Graph, SubGraph<ListGraph> >(); + checkConcept<concepts::AlterableGraphComponent<>, + SubGraph<ListGraph> >(); + checkConcept<concepts::ExtendableGraphComponent<>, + SubGraph<ListGraph> >(); + checkConcept<concepts::ErasableGraphComponent<>, + SubGraph<ListGraph> >(); + checkConcept<concepts::ClearableGraphComponent<>, + SubGraph<ListGraph> >(); + + // Create a graph and an adaptor + typedef ListGraph Graph; + typedef Graph::NodeMap<bool> NodeFilter; + typedef Graph::EdgeMap<bool> EdgeFilter; + typedef SubGraph<Graph, NodeFilter, EdgeFilter> Adaptor; + + Graph graph; + NodeFilter node_filter(graph); + EdgeFilter edge_filter(graph); + Adaptor adaptor(graph, node_filter, edge_filter); + + // Add nodes and edges to the original graph and the adaptor + Graph::Node n1 = graph.addNode(); + Graph::Node n2 = graph.addNode(); + Adaptor::Node n3 = adaptor.addNode(); + Adaptor::Node n4 = adaptor.addNode(); + + node_filter[n1] = node_filter[n2] = node_filter[n3] = node_filter[n4] = true; + + Graph::Edge e1 = graph.addEdge(n1, n2); + Graph::Edge e2 = graph.addEdge(n1, n3); + Adaptor::Edge e3 = adaptor.addEdge(n2, n3); + Adaptor::Edge e4 = adaptor.addEdge(n3, n4); + + edge_filter[e1] = edge_filter[e2] = edge_filter[e3] = edge_filter[e4] = true; + + checkGraphNodeList(adaptor, 4); + checkGraphArcList(adaptor, 8); + checkGraphEdgeList(adaptor, 4); + checkGraphConArcList(adaptor, 8); + checkGraphConEdgeList(adaptor, 4); + + checkGraphIncEdgeArcLists(adaptor, n1, 2); + checkGraphIncEdgeArcLists(adaptor, n2, 2); + checkGraphIncEdgeArcLists(adaptor, n3, 3); + checkGraphIncEdgeArcLists(adaptor, n4, 1); + + checkNodeIds(adaptor); + checkArcIds(adaptor); + checkEdgeIds(adaptor); + + checkGraphNodeMap(adaptor); + checkGraphArcMap(adaptor); + checkGraphEdgeMap(adaptor); + + // Hide an edge + adaptor.status(e2, false); + adaptor.disable(e3); + if (!adaptor.status(e3)) adaptor.enable(e3); + + checkGraphNodeList(adaptor, 4); + checkGraphArcList(adaptor, 6); + checkGraphEdgeList(adaptor, 3); + checkGraphConArcList(adaptor, 6); + checkGraphConEdgeList(adaptor, 3); + + checkGraphIncEdgeArcLists(adaptor, n1, 1); + checkGraphIncEdgeArcLists(adaptor, n2, 2); + checkGraphIncEdgeArcLists(adaptor, n3, 2); + checkGraphIncEdgeArcLists(adaptor, n4, 1); + + checkNodeIds(adaptor); + checkArcIds(adaptor); + checkEdgeIds(adaptor); + + checkGraphNodeMap(adaptor); + checkGraphArcMap(adaptor); + checkGraphEdgeMap(adaptor); + + // Hide a node + adaptor.status(n1, false); + adaptor.disable(n3); + if (!adaptor.status(n3)) adaptor.enable(n3); + + checkGraphNodeList(adaptor, 3); + checkGraphArcList(adaptor, 4); + checkGraphEdgeList(adaptor, 2); + checkGraphConArcList(adaptor, 4); + checkGraphConEdgeList(adaptor, 2); + + checkGraphIncEdgeArcLists(adaptor, n2, 1); + checkGraphIncEdgeArcLists(adaptor, n3, 2); + checkGraphIncEdgeArcLists(adaptor, n4, 1); + + checkNodeIds(adaptor); + checkArcIds(adaptor); + checkEdgeIds(adaptor); + + checkGraphNodeMap(adaptor); + checkGraphArcMap(adaptor); + checkGraphEdgeMap(adaptor); + + // Hide all nodes and edges + node_filter[n1] = node_filter[n2] = node_filter[n3] = node_filter[n4] = false; + edge_filter[e1] = edge_filter[e2] = edge_filter[e3] = edge_filter[e4] = false; + + checkGraphNodeList(adaptor, 0); + checkGraphArcList(adaptor, 0); + checkGraphEdgeList(adaptor, 0); + checkGraphConArcList(adaptor, 0); + checkGraphConEdgeList(adaptor, 0); + + checkNodeIds(adaptor); + checkArcIds(adaptor); + checkEdgeIds(adaptor); + + checkGraphNodeMap(adaptor); + checkGraphArcMap(adaptor); + checkGraphEdgeMap(adaptor); + + // Check the conversion of nodes and edges + Graph::Node ng = n3; + ng = n4; + Adaptor::Node na = n1; + na = n2; + Graph::Edge eg = e3; + eg = e4; + Adaptor::Edge ea = e1; + ea = e2; +} + +void checkFilterNodes2() { + // Check concepts + checkConcept<concepts::Graph, FilterNodes<concepts::Graph> >(); + checkConcept<concepts::Graph, FilterNodes<ListGraph> >(); + checkConcept<concepts::AlterableGraphComponent<>, + FilterNodes<ListGraph> >(); + checkConcept<concepts::ExtendableGraphComponent<>, + FilterNodes<ListGraph> >(); + checkConcept<concepts::ErasableGraphComponent<>, + FilterNodes<ListGraph> >(); + checkConcept<concepts::ClearableGraphComponent<>, + FilterNodes<ListGraph> >(); + + // Create a graph and an adaptor + typedef ListGraph Graph; + typedef Graph::NodeMap<bool> NodeFilter; + typedef FilterNodes<Graph, NodeFilter> Adaptor; + + // Add nodes and edges to the original graph and the adaptor + Graph graph; + NodeFilter node_filter(graph); + Adaptor adaptor(graph, node_filter); + + Graph::Node n1 = graph.addNode(); + Graph::Node n2 = graph.addNode(); + Adaptor::Node n3 = adaptor.addNode(); + Adaptor::Node n4 = adaptor.addNode(); + + node_filter[n1] = node_filter[n2] = node_filter[n3] = node_filter[n4] = true; + + Graph::Edge e1 = graph.addEdge(n1, n2); + Graph::Edge e2 = graph.addEdge(n1, n3); + Adaptor::Edge e3 = adaptor.addEdge(n2, n3); + Adaptor::Edge e4 = adaptor.addEdge(n3, n4); + + checkGraphNodeList(adaptor, 4); + checkGraphArcList(adaptor, 8); + checkGraphEdgeList(adaptor, 4); + checkGraphConArcList(adaptor, 8); + checkGraphConEdgeList(adaptor, 4); + + checkGraphIncEdgeArcLists(adaptor, n1, 2); + checkGraphIncEdgeArcLists(adaptor, n2, 2); + checkGraphIncEdgeArcLists(adaptor, n3, 3); + checkGraphIncEdgeArcLists(adaptor, n4, 1); + + checkNodeIds(adaptor); + checkArcIds(adaptor); + checkEdgeIds(adaptor); + + checkGraphNodeMap(adaptor); + checkGraphArcMap(adaptor); + checkGraphEdgeMap(adaptor); + + // Hide a node + adaptor.status(n1, false); + adaptor.disable(n3); + if (!adaptor.status(n3)) adaptor.enable(n3); + + checkGraphNodeList(adaptor, 3); + checkGraphArcList(adaptor, 4); + checkGraphEdgeList(adaptor, 2); + checkGraphConArcList(adaptor, 4); + checkGraphConEdgeList(adaptor, 2); + + checkGraphIncEdgeArcLists(adaptor, n2, 1); + checkGraphIncEdgeArcLists(adaptor, n3, 2); + checkGraphIncEdgeArcLists(adaptor, n4, 1); + + checkNodeIds(adaptor); + checkArcIds(adaptor); + checkEdgeIds(adaptor); + + checkGraphNodeMap(adaptor); + checkGraphArcMap(adaptor); + checkGraphEdgeMap(adaptor); + + // Hide all nodes + node_filter[n1] = node_filter[n2] = node_filter[n3] = node_filter[n4] = false; + + checkGraphNodeList(adaptor, 0); + checkGraphArcList(adaptor, 0); + checkGraphEdgeList(adaptor, 0); + checkGraphConArcList(adaptor, 0); + checkGraphConEdgeList(adaptor, 0); + + checkNodeIds(adaptor); + checkArcIds(adaptor); + checkEdgeIds(adaptor); + + checkGraphNodeMap(adaptor); + checkGraphArcMap(adaptor); + checkGraphEdgeMap(adaptor); + + // Check the conversion of nodes and edges + Graph::Node ng = n3; + ng = n4; + Adaptor::Node na = n1; + na = n2; + Graph::Edge eg = e3; + eg = e4; + Adaptor::Edge ea = e1; + ea = e2; +} + +void checkFilterEdges() { + // Check concepts + checkConcept<concepts::Graph, FilterEdges<concepts::Graph> >(); + checkConcept<concepts::Graph, FilterEdges<ListGraph> >(); + checkConcept<concepts::AlterableGraphComponent<>, + FilterEdges<ListGraph> >(); + checkConcept<concepts::ExtendableGraphComponent<>, + FilterEdges<ListGraph> >(); + checkConcept<concepts::ErasableGraphComponent<>, + FilterEdges<ListGraph> >(); + checkConcept<concepts::ClearableGraphComponent<>, + FilterEdges<ListGraph> >(); + + // Create a graph and an adaptor + typedef ListGraph Graph; + typedef Graph::EdgeMap<bool> EdgeFilter; + typedef FilterEdges<Graph, EdgeFilter> Adaptor; + + Graph graph; + EdgeFilter edge_filter(graph); + Adaptor adaptor(graph, edge_filter); + + // Add nodes and edges to the original graph and the adaptor + Graph::Node n1 = graph.addNode(); + Graph::Node n2 = graph.addNode(); + Adaptor::Node n3 = adaptor.addNode(); + Adaptor::Node n4 = adaptor.addNode(); + + Graph::Edge e1 = graph.addEdge(n1, n2); + Graph::Edge e2 = graph.addEdge(n1, n3); + Adaptor::Edge e3 = adaptor.addEdge(n2, n3); + Adaptor::Edge e4 = adaptor.addEdge(n3, n4); + + edge_filter[e1] = edge_filter[e2] = edge_filter[e3] = edge_filter[e4] = true; + + checkGraphNodeList(adaptor, 4); + checkGraphArcList(adaptor, 8); + checkGraphEdgeList(adaptor, 4); + checkGraphConArcList(adaptor, 8); + checkGraphConEdgeList(adaptor, 4); + + checkGraphIncEdgeArcLists(adaptor, n1, 2); + checkGraphIncEdgeArcLists(adaptor, n2, 2); + checkGraphIncEdgeArcLists(adaptor, n3, 3); + checkGraphIncEdgeArcLists(adaptor, n4, 1); + + checkNodeIds(adaptor); + checkArcIds(adaptor); + checkEdgeIds(adaptor); + + checkGraphNodeMap(adaptor); + checkGraphArcMap(adaptor); + checkGraphEdgeMap(adaptor); + + // Hide an edge + adaptor.status(e2, false); + adaptor.disable(e3); + if (!adaptor.status(e3)) adaptor.enable(e3); + + checkGraphNodeList(adaptor, 4); + checkGraphArcList(adaptor, 6); + checkGraphEdgeList(adaptor, 3); + checkGraphConArcList(adaptor, 6); + checkGraphConEdgeList(adaptor, 3); + + checkGraphIncEdgeArcLists(adaptor, n1, 1); + checkGraphIncEdgeArcLists(adaptor, n2, 2); + checkGraphIncEdgeArcLists(adaptor, n3, 2); + checkGraphIncEdgeArcLists(adaptor, n4, 1); + + checkNodeIds(adaptor); + checkArcIds(adaptor); + checkEdgeIds(adaptor); + + checkGraphNodeMap(adaptor); + checkGraphArcMap(adaptor); + checkGraphEdgeMap(adaptor); + + // Hide all edges + edge_filter[e1] = edge_filter[e2] = edge_filter[e3] = edge_filter[e4] = false; + + checkGraphNodeList(adaptor, 4); + checkGraphArcList(adaptor, 0); + checkGraphEdgeList(adaptor, 0); + checkGraphConArcList(adaptor, 0); + checkGraphConEdgeList(adaptor, 0); + + checkNodeIds(adaptor); + checkArcIds(adaptor); + checkEdgeIds(adaptor); + + checkGraphNodeMap(adaptor); + checkGraphArcMap(adaptor); + checkGraphEdgeMap(adaptor); + + // Check the conversion of nodes and edges + Graph::Node ng = n3; + ng = n4; + Adaptor::Node na = n1; + na = n2; + Graph::Edge eg = e3; + eg = e4; + Adaptor::Edge ea = e1; + ea = e2; +} + +void checkOrienter() { + // Check concepts + checkConcept<concepts::Digraph, Orienter<concepts::Graph> >(); + checkConcept<concepts::Digraph, Orienter<ListGraph> >(); + checkConcept<concepts::AlterableDigraphComponent<>, + Orienter<ListGraph> >(); + checkConcept<concepts::ExtendableDigraphComponent<>, + Orienter<ListGraph> >(); + checkConcept<concepts::ErasableDigraphComponent<>, + Orienter<ListGraph> >(); + checkConcept<concepts::ClearableDigraphComponent<>, + Orienter<ListGraph> >(); + + // Create a graph and an adaptor + typedef ListGraph Graph; + typedef ListGraph::EdgeMap<bool> DirMap; + typedef Orienter<Graph> Adaptor; + + Graph graph; + DirMap dir(graph); + Adaptor adaptor(graph, dir); + + // Add nodes and edges to the original graph and the adaptor + Graph::Node n1 = graph.addNode(); + Graph::Node n2 = graph.addNode(); + Adaptor::Node n3 = adaptor.addNode(); + + Graph::Edge e1 = graph.addEdge(n1, n2); + Graph::Edge e2 = graph.addEdge(n1, n3); + Adaptor::Arc e3 = adaptor.addArc(n2, n3); + + dir[e1] = dir[e2] = dir[e3] = true; + + // Check the original graph + checkGraphNodeList(graph, 3); + checkGraphArcList(graph, 6); + checkGraphConArcList(graph, 6); + checkGraphEdgeList(graph, 3); + checkGraphConEdgeList(graph, 3); + + checkGraphIncEdgeArcLists(graph, n1, 2); + checkGraphIncEdgeArcLists(graph, n2, 2); + checkGraphIncEdgeArcLists(graph, n3, 2); + + checkNodeIds(graph); + checkArcIds(graph); + checkEdgeIds(graph); + + checkGraphNodeMap(graph); + checkGraphArcMap(graph); + checkGraphEdgeMap(graph); + + // Check the adaptor + checkGraphNodeList(adaptor, 3); + checkGraphArcList(adaptor, 3); + checkGraphConArcList(adaptor, 3); + + checkGraphOutArcList(adaptor, n1, 2); + checkGraphOutArcList(adaptor, n2, 1); + checkGraphOutArcList(adaptor, n3, 0); + + checkGraphInArcList(adaptor, n1, 0); + checkGraphInArcList(adaptor, n2, 1); + checkGraphInArcList(adaptor, n3, 2); + + checkNodeIds(adaptor); + checkArcIds(adaptor); + + checkGraphNodeMap(adaptor); + checkGraphArcMap(adaptor); + + // Check direction changing + { + dir[e1] = true; + Adaptor::Node u = adaptor.source(e1); + Adaptor::Node v = adaptor.target(e1); + + dir[e1] = false; + check (u == adaptor.target(e1), "Wrong dir"); + check (v == adaptor.source(e1), "Wrong dir"); + + check ((u == n1 && v == n2) || (u == n2 && v == n1), "Wrong dir"); + dir[e1] = n1 == u; + } + + { + dir[e2] = true; + Adaptor::Node u = adaptor.source(e2); + Adaptor::Node v = adaptor.target(e2); + + dir[e2] = false; + check (u == adaptor.target(e2), "Wrong dir"); + check (v == adaptor.source(e2), "Wrong dir"); + + check ((u == n1 && v == n3) || (u == n3 && v == n1), "Wrong dir"); + dir[e2] = n3 == u; + } + + { + dir[e3] = true; + Adaptor::Node u = adaptor.source(e3); + Adaptor::Node v = adaptor.target(e3); + + dir[e3] = false; + check (u == adaptor.target(e3), "Wrong dir"); + check (v == adaptor.source(e3), "Wrong dir"); + + check ((u == n2 && v == n3) || (u == n3 && v == n2), "Wrong dir"); + dir[e3] = n2 == u; + } + + // Check the adaptor again + checkGraphNodeList(adaptor, 3); + checkGraphArcList(adaptor, 3); + checkGraphConArcList(adaptor, 3); + + checkGraphOutArcList(adaptor, n1, 1); + checkGraphOutArcList(adaptor, n2, 1); + checkGraphOutArcList(adaptor, n3, 1); + + checkGraphInArcList(adaptor, n1, 1); + checkGraphInArcList(adaptor, n2, 1); + checkGraphInArcList(adaptor, n3, 1); + + checkNodeIds(adaptor); + checkArcIds(adaptor); + + checkGraphNodeMap(adaptor); + checkGraphArcMap(adaptor); + + // Check reverseArc() + adaptor.reverseArc(e2); + adaptor.reverseArc(e3); + adaptor.reverseArc(e2); + + checkGraphNodeList(adaptor, 3); + checkGraphArcList(adaptor, 3); + checkGraphConArcList(adaptor, 3); + + checkGraphOutArcList(adaptor, n1, 1); + checkGraphOutArcList(adaptor, n2, 0); + checkGraphOutArcList(adaptor, n3, 2); + + checkGraphInArcList(adaptor, n1, 1); + checkGraphInArcList(adaptor, n2, 2); + checkGraphInArcList(adaptor, n3, 0); + + // Check the conversion of nodes and arcs/edges + Graph::Node ng = n3; + ng = n3; + Adaptor::Node na = n1; + na = n2; + Graph::Edge eg = e3; + eg = e3; + Adaptor::Arc aa = e1; + aa = e2; +} + +void checkCombiningAdaptors() { + // Create a grid graph + GridGraph graph(2,2); + GridGraph::Node n1 = graph(0,0); + GridGraph::Node n2 = graph(0,1); + GridGraph::Node n3 = graph(1,0); + GridGraph::Node n4 = graph(1,1); + + GridGraph::EdgeMap<bool> dir_map(graph); + dir_map[graph.right(n1)] = graph.u(graph.right(n1)) != n1; + dir_map[graph.up(n1)] = graph.u(graph.up(n1)) == n1; + dir_map[graph.left(n4)] = graph.u(graph.left(n4)) == n4; + dir_map[graph.down(n4)] = graph.u(graph.down(n4)) == n4; + + // Apply several adaptors on the grid graph + typedef SplitNodes<Orienter< const GridGraph, GridGraph::EdgeMap<bool> > > + SplitGridGraph; + typedef Undirector<const SplitGridGraph> USplitGridGraph; + checkConcept<concepts::Digraph, SplitGridGraph>(); + checkConcept<concepts::Graph, USplitGridGraph>(); + + SplitGridGraph adaptor = splitNodes(orienter(graph, dir_map)); + USplitGridGraph uadaptor = undirector(adaptor); + + // Check adaptor + checkGraphNodeList(adaptor, 8); + checkGraphArcList(adaptor, 8); + checkGraphConArcList(adaptor, 8); + + checkGraphOutArcList(adaptor, adaptor.inNode(n1), 1); + checkGraphOutArcList(adaptor, adaptor.outNode(n1), 1); + checkGraphOutArcList(adaptor, adaptor.inNode(n2), 1); + checkGraphOutArcList(adaptor, adaptor.outNode(n2), 0); + checkGraphOutArcList(adaptor, adaptor.inNode(n3), 1); + checkGraphOutArcList(adaptor, adaptor.outNode(n3), 1); + checkGraphOutArcList(adaptor, adaptor.inNode(n4), 1); + checkGraphOutArcList(adaptor, adaptor.outNode(n4), 2); + + checkGraphInArcList(adaptor, adaptor.inNode(n1), 1); + checkGraphInArcList(adaptor, adaptor.outNode(n1), 1); + checkGraphInArcList(adaptor, adaptor.inNode(n2), 2); + checkGraphInArcList(adaptor, adaptor.outNode(n2), 1); + checkGraphInArcList(adaptor, adaptor.inNode(n3), 1); + checkGraphInArcList(adaptor, adaptor.outNode(n3), 1); + checkGraphInArcList(adaptor, adaptor.inNode(n4), 0); + checkGraphInArcList(adaptor, adaptor.outNode(n4), 1); + + checkNodeIds(adaptor); + checkArcIds(adaptor); + + checkGraphNodeMap(adaptor); + checkGraphArcMap(adaptor); + + // Check uadaptor + checkGraphNodeList(uadaptor, 8); + checkGraphEdgeList(uadaptor, 8); + checkGraphArcList(uadaptor, 16); + checkGraphConEdgeList(uadaptor, 8); + checkGraphConArcList(uadaptor, 16); + + checkNodeIds(uadaptor); + checkEdgeIds(uadaptor); + checkArcIds(uadaptor); + + checkGraphNodeMap(uadaptor); + checkGraphEdgeMap(uadaptor); + checkGraphArcMap(uadaptor); + + checkGraphIncEdgeArcLists(uadaptor, adaptor.inNode(n1), 2); + checkGraphIncEdgeArcLists(uadaptor, adaptor.outNode(n1), 2); + checkGraphIncEdgeArcLists(uadaptor, adaptor.inNode(n2), 3); + checkGraphIncEdgeArcLists(uadaptor, adaptor.outNode(n2), 1); + checkGraphIncEdgeArcLists(uadaptor, adaptor.inNode(n3), 2); + checkGraphIncEdgeArcLists(uadaptor, adaptor.outNode(n3), 2); + checkGraphIncEdgeArcLists(uadaptor, adaptor.inNode(n4), 1); + checkGraphIncEdgeArcLists(uadaptor, adaptor.outNode(n4), 3); +} + +int main(int, const char **) { + // Check the digraph adaptors (using ListDigraph) + checkReverseDigraph(); + checkSubDigraph(); + checkFilterNodes1(); + checkFilterArcs(); + checkUndirector(); + checkResidualDigraph(); + checkSplitNodes(); + + // Check the graph adaptors (using ListGraph) + checkSubGraph(); + checkFilterNodes2(); + checkFilterEdges(); + checkOrienter(); + + // Combine adaptors (using GridGraph) + checkCombiningAdaptors(); + + return 0; +} diff --git a/lemon/test/bellman_ford_test.cc b/lemon/test/bellman_ford_test.cc new file mode 100644 index 0000000..2f6c7dd --- /dev/null +++ b/lemon/test/bellman_ford_test.cc @@ -0,0 +1,285 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <lemon/concepts/digraph.h> +#include <lemon/smart_graph.h> +#include <lemon/list_graph.h> +#include <lemon/lgf_reader.h> +#include <lemon/bellman_ford.h> +#include <lemon/path.h> + +#include "graph_test.h" +#include "test_tools.h" + +using namespace lemon; + +char test_lgf[] = + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "@arcs\n" + " length\n" + "0 1 3\n" + "1 2 -3\n" + "1 2 -5\n" + "1 3 -2\n" + "0 2 -1\n" + "1 2 -4\n" + "0 3 2\n" + "4 2 -5\n" + "2 3 1\n" + "@attributes\n" + "source 0\n" + "target 3\n"; + + +void checkBellmanFordCompile() +{ + typedef int Value; + typedef concepts::Digraph Digraph; + typedef concepts::ReadMap<Digraph::Arc,Value> LengthMap; + typedef BellmanFord<Digraph, LengthMap> BF; + typedef Digraph::Node Node; + typedef Digraph::Arc Arc; + + Digraph gr; + Node s, t, n; + Arc e; + Value l; + int k=3; + bool b; + BF::DistMap d(gr); + BF::PredMap p(gr); + LengthMap length; + concepts::Path<Digraph> pp; + + { + BF bf_test(gr,length); + const BF& const_bf_test = bf_test; + + bf_test.run(s); + bf_test.run(s,k); + + bf_test.init(); + bf_test.addSource(s); + bf_test.addSource(s, 1); + b = bf_test.processNextRound(); + b = bf_test.processNextWeakRound(); + + bf_test.start(); + bf_test.checkedStart(); + bf_test.limitedStart(k); + + l = const_bf_test.dist(t); + e = const_bf_test.predArc(t); + s = const_bf_test.predNode(t); + b = const_bf_test.reached(t); + d = const_bf_test.distMap(); + p = const_bf_test.predMap(); + pp = const_bf_test.path(t); + pp = const_bf_test.negativeCycle(); + + for (BF::ActiveIt it(const_bf_test); it != INVALID; ++it) {} + } + { + BF::SetPredMap<concepts::ReadWriteMap<Node,Arc> > + ::SetDistMap<concepts::ReadWriteMap<Node,Value> > + ::SetOperationTraits<BellmanFordDefaultOperationTraits<Value> > + ::Create bf_test(gr,length); + + LengthMap length_map; + concepts::ReadWriteMap<Node,Arc> pred_map; + concepts::ReadWriteMap<Node,Value> dist_map; + + bf_test + .lengthMap(length_map) + .predMap(pred_map) + .distMap(dist_map); + + bf_test.run(s); + bf_test.run(s,k); + + bf_test.init(); + bf_test.addSource(s); + bf_test.addSource(s, 1); + b = bf_test.processNextRound(); + b = bf_test.processNextWeakRound(); + + bf_test.start(); + bf_test.checkedStart(); + bf_test.limitedStart(k); + + l = bf_test.dist(t); + e = bf_test.predArc(t); + s = bf_test.predNode(t); + b = bf_test.reached(t); + pp = bf_test.path(t); + pp = bf_test.negativeCycle(); + } +} + +void checkBellmanFordFunctionCompile() +{ + typedef int Value; + typedef concepts::Digraph Digraph; + typedef Digraph::Arc Arc; + typedef Digraph::Node Node; + typedef concepts::ReadMap<Digraph::Arc,Value> LengthMap; + + Digraph g; + bool b; + bellmanFord(g,LengthMap()).run(Node()); + b = bellmanFord(g,LengthMap()).run(Node(),Node()); + bellmanFord(g,LengthMap()) + .predMap(concepts::ReadWriteMap<Node,Arc>()) + .distMap(concepts::ReadWriteMap<Node,Value>()) + .run(Node()); + b=bellmanFord(g,LengthMap()) + .predMap(concepts::ReadWriteMap<Node,Arc>()) + .distMap(concepts::ReadWriteMap<Node,Value>()) + .path(concepts::Path<Digraph>()) + .dist(Value()) + .run(Node(),Node()); +} + + +template <typename Digraph, typename Value> +void checkBellmanFord() { + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + typedef typename Digraph::template ArcMap<Value> LengthMap; + + Digraph gr; + Node s, t; + LengthMap length(gr); + + std::istringstream input(test_lgf); + digraphReader(gr, input). + arcMap("length", length). + node("source", s). + node("target", t). + run(); + + BellmanFord<Digraph, LengthMap> + bf(gr, length); + bf.run(s); + Path<Digraph> p = bf.path(t); + + check(bf.reached(t) && bf.dist(t) == -1, "Bellman-Ford found a wrong path."); + check(p.length() == 3, "path() found a wrong path."); + check(checkPath(gr, p), "path() found a wrong path."); + check(pathSource(gr, p) == s, "path() found a wrong path."); + check(pathTarget(gr, p) == t, "path() found a wrong path."); + + ListPath<Digraph> path; + Value dist; + bool reached = bellmanFord(gr,length).path(path).dist(dist).run(s,t); + + check(reached && dist == -1, "Bellman-Ford found a wrong path."); + check(path.length() == 3, "path() found a wrong path."); + check(checkPath(gr, path), "path() found a wrong path."); + check(pathSource(gr, path) == s, "path() found a wrong path."); + check(pathTarget(gr, path) == t, "path() found a wrong path."); + + for(ArcIt e(gr); e!=INVALID; ++e) { + Node u=gr.source(e); + Node v=gr.target(e); + check(!bf.reached(u) || (bf.dist(v) - bf.dist(u) <= length[e]), + "Wrong output. dist(target)-dist(source)-arc_length=" << + bf.dist(v) - bf.dist(u) - length[e]); + } + + for(NodeIt v(gr); v!=INVALID; ++v) { + if (bf.reached(v)) { + check(v==s || bf.predArc(v)!=INVALID, "Wrong tree."); + if (bf.predArc(v)!=INVALID ) { + Arc e=bf.predArc(v); + Node u=gr.source(e); + check(u==bf.predNode(v),"Wrong tree."); + check(bf.dist(v) - bf.dist(u) == length[e], + "Wrong distance! Difference: " << + bf.dist(v) - bf.dist(u) - length[e]); + } + } + } +} + +void checkBellmanFordNegativeCycle() { + DIGRAPH_TYPEDEFS(SmartDigraph); + + SmartDigraph gr; + IntArcMap length(gr); + + Node n1 = gr.addNode(); + Node n2 = gr.addNode(); + Node n3 = gr.addNode(); + Node n4 = gr.addNode(); + + Arc a1 = gr.addArc(n1, n2); + Arc a2 = gr.addArc(n2, n2); + + length[a1] = 2; + length[a2] = -1; + + { + BellmanFord<SmartDigraph, IntArcMap> bf(gr, length); + bf.run(n1); + StaticPath<SmartDigraph> p = bf.negativeCycle(); + check(p.length() == 1 && p.front() == p.back() && p.front() == a2, + "Wrong negative cycle."); + } + + length[a2] = 0; + + { + BellmanFord<SmartDigraph, IntArcMap> bf(gr, length); + bf.run(n1); + check(bf.negativeCycle().empty(), + "Negative cycle should not be found."); + } + + length[gr.addArc(n1, n3)] = 5; + length[gr.addArc(n4, n3)] = 1; + length[gr.addArc(n2, n4)] = 2; + length[gr.addArc(n3, n2)] = -4; + + { + BellmanFord<SmartDigraph, IntArcMap> bf(gr, length); + bf.init(); + bf.addSource(n1); + for (int i = 0; i < 4; ++i) { + check(bf.negativeCycle().empty(), + "Negative cycle should not be found."); + bf.processNextRound(); + } + StaticPath<SmartDigraph> p = bf.negativeCycle(); + check(p.length() == 3, "Wrong negative cycle."); + check(length[p.nth(0)] + length[p.nth(1)] + length[p.nth(2)] == -1, + "Wrong negative cycle."); + } +} + +int main() { + checkBellmanFord<ListDigraph, int>(); + checkBellmanFord<SmartDigraph, double>(); + checkBellmanFordNegativeCycle(); + return 0; +} diff --git a/lemon/test/bfs_test.cc b/lemon/test/bfs_test.cc new file mode 100644 index 0000000..a1c16b3 --- /dev/null +++ b/lemon/test/bfs_test.cc @@ -0,0 +1,236 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <lemon/concepts/digraph.h> +#include <lemon/smart_graph.h> +#include <lemon/list_graph.h> +#include <lemon/lgf_reader.h> +#include <lemon/bfs.h> +#include <lemon/path.h> + +#include "graph_test.h" +#include "test_tools.h" + +using namespace lemon; + +char test_lgf[] = + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "5\n" + "@arcs\n" + " label\n" + "0 1 0\n" + "1 2 1\n" + "2 3 2\n" + "3 4 3\n" + "0 3 4\n" + "0 3 5\n" + "5 2 6\n" + "@attributes\n" + "source 0\n" + "target 4\n"; + +void checkBfsCompile() +{ + typedef concepts::Digraph Digraph; + typedef Bfs<Digraph> BType; + typedef Digraph::Node Node; + typedef Digraph::Arc Arc; + + Digraph G; + Node s, t, n; + Arc e; + int l, i; + bool b; + BType::DistMap d(G); + BType::PredMap p(G); + Path<Digraph> pp; + concepts::ReadMap<Node,bool> nm; + + { + BType bfs_test(G); + const BType& const_bfs_test = bfs_test; + + bfs_test.run(s); + bfs_test.run(s,t); + bfs_test.run(); + + bfs_test.init(); + bfs_test.addSource(s); + n = bfs_test.processNextNode(); + n = bfs_test.processNextNode(t, b); + n = bfs_test.processNextNode(nm, n); + n = const_bfs_test.nextNode(); + b = const_bfs_test.emptyQueue(); + i = const_bfs_test.queueSize(); + + bfs_test.start(); + bfs_test.start(t); + bfs_test.start(nm); + + l = const_bfs_test.dist(t); + e = const_bfs_test.predArc(t); + s = const_bfs_test.predNode(t); + b = const_bfs_test.reached(t); + d = const_bfs_test.distMap(); + p = const_bfs_test.predMap(); + pp = const_bfs_test.path(t); + } + { + BType + ::SetPredMap<concepts::ReadWriteMap<Node,Arc> > + ::SetDistMap<concepts::ReadWriteMap<Node,int> > + ::SetReachedMap<concepts::ReadWriteMap<Node,bool> > + ::SetStandardProcessedMap + ::SetProcessedMap<concepts::WriteMap<Node,bool> > + ::Create bfs_test(G); + + concepts::ReadWriteMap<Node,Arc> pred_map; + concepts::ReadWriteMap<Node,int> dist_map; + concepts::ReadWriteMap<Node,bool> reached_map; + concepts::WriteMap<Node,bool> processed_map; + + bfs_test + .predMap(pred_map) + .distMap(dist_map) + .reachedMap(reached_map) + .processedMap(processed_map); + + bfs_test.run(s); + bfs_test.run(s,t); + bfs_test.run(); + + bfs_test.init(); + bfs_test.addSource(s); + n = bfs_test.processNextNode(); + n = bfs_test.processNextNode(t, b); + n = bfs_test.processNextNode(nm, n); + n = bfs_test.nextNode(); + b = bfs_test.emptyQueue(); + i = bfs_test.queueSize(); + + bfs_test.start(); + bfs_test.start(t); + bfs_test.start(nm); + + l = bfs_test.dist(t); + e = bfs_test.predArc(t); + s = bfs_test.predNode(t); + b = bfs_test.reached(t); + pp = bfs_test.path(t); + } +} + +void checkBfsFunctionCompile() +{ + typedef int VType; + typedef concepts::Digraph Digraph; + typedef Digraph::Arc Arc; + typedef Digraph::Node Node; + + Digraph g; + bool b; + bfs(g).run(Node()); + b=bfs(g).run(Node(),Node()); + bfs(g).run(); + bfs(g) + .predMap(concepts::ReadWriteMap<Node,Arc>()) + .distMap(concepts::ReadWriteMap<Node,VType>()) + .reachedMap(concepts::ReadWriteMap<Node,bool>()) + .processedMap(concepts::WriteMap<Node,bool>()) + .run(Node()); + b=bfs(g) + .predMap(concepts::ReadWriteMap<Node,Arc>()) + .distMap(concepts::ReadWriteMap<Node,VType>()) + .reachedMap(concepts::ReadWriteMap<Node,bool>()) + .processedMap(concepts::WriteMap<Node,bool>()) + .path(concepts::Path<Digraph>()) + .dist(VType()) + .run(Node(),Node()); + bfs(g) + .predMap(concepts::ReadWriteMap<Node,Arc>()) + .distMap(concepts::ReadWriteMap<Node,VType>()) + .reachedMap(concepts::ReadWriteMap<Node,bool>()) + .processedMap(concepts::WriteMap<Node,bool>()) + .run(); +} + +template <class Digraph> +void checkBfs() { + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + + Digraph G; + Node s, t; + + std::istringstream input(test_lgf); + digraphReader(G, input). + node("source", s). + node("target", t). + run(); + + Bfs<Digraph> bfs_test(G); + bfs_test.run(s); + + check(bfs_test.dist(t)==2,"Bfs found a wrong path."); + + Path<Digraph> p = bfs_test.path(t); + check(p.length()==2,"path() found a wrong path."); + check(checkPath(G, p),"path() found a wrong path."); + check(pathSource(G, p) == s,"path() found a wrong path."); + check(pathTarget(G, p) == t,"path() found a wrong path."); + + + for(ArcIt a(G); a!=INVALID; ++a) { + Node u=G.source(a); + Node v=G.target(a); + check( !bfs_test.reached(u) || + (bfs_test.dist(v) <= bfs_test.dist(u)+1), + "Wrong output. " << G.id(u) << "->" << G.id(v)); + } + + for(NodeIt v(G); v!=INVALID; ++v) { + if (bfs_test.reached(v)) { + check(v==s || bfs_test.predArc(v)!=INVALID, "Wrong tree."); + if (bfs_test.predArc(v)!=INVALID ) { + Arc a=bfs_test.predArc(v); + Node u=G.source(a); + check(u==bfs_test.predNode(v),"Wrong tree."); + check(bfs_test.dist(v) - bfs_test.dist(u) == 1, + "Wrong distance. Difference: " + << std::abs(bfs_test.dist(v) - bfs_test.dist(u) - 1)); + } + } + } + + { + NullMap<Node,Arc> myPredMap; + bfs(G).predMap(myPredMap).run(s); + } +} + +int main() +{ + checkBfs<ListDigraph>(); + checkBfs<SmartDigraph>(); + return 0; +} diff --git a/lemon/test/circulation_test.cc b/lemon/test/circulation_test.cc new file mode 100644 index 0000000..99dc764 --- /dev/null +++ b/lemon/test/circulation_test.cc @@ -0,0 +1,168 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <iostream> + +#include "test_tools.h" +#include <lemon/list_graph.h> +#include <lemon/circulation.h> +#include <lemon/lgf_reader.h> +#include <lemon/concepts/digraph.h> +#include <lemon/concepts/maps.h> + +using namespace lemon; + +char test_lgf[] = + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "5\n" + "@arcs\n" + " lcap ucap\n" + "0 1 2 10\n" + "0 2 2 6\n" + "1 3 4 7\n" + "1 4 0 5\n" + "2 4 1 3\n" + "3 5 3 8\n" + "4 5 3 7\n" + "@attributes\n" + "source 0\n" + "sink 5\n"; + +void checkCirculationCompile() +{ + typedef int VType; + typedef concepts::Digraph Digraph; + + typedef Digraph::Node Node; + typedef Digraph::Arc Arc; + typedef concepts::ReadMap<Arc,VType> CapMap; + typedef concepts::ReadMap<Node,VType> SupplyMap; + typedef concepts::ReadWriteMap<Arc,VType> FlowMap; + typedef concepts::WriteMap<Node,bool> BarrierMap; + + typedef Elevator<Digraph, Digraph::Node> Elev; + typedef LinkedElevator<Digraph, Digraph::Node> LinkedElev; + + Digraph g; + Node n; + Arc a; + CapMap lcap, ucap; + SupplyMap supply; + FlowMap flow; + BarrierMap bar; + VType v; + bool b; + + typedef Circulation<Digraph, CapMap, CapMap, SupplyMap> + ::SetFlowMap<FlowMap> + ::SetElevator<Elev> + ::SetStandardElevator<LinkedElev> + ::Create CirculationType; + CirculationType circ_test(g, lcap, ucap, supply); + const CirculationType& const_circ_test = circ_test; + + circ_test + .lowerMap(lcap) + .upperMap(ucap) + .supplyMap(supply) + .flowMap(flow); + + const CirculationType::Elevator& elev = const_circ_test.elevator(); + circ_test.elevator(const_cast<CirculationType::Elevator&>(elev)); + CirculationType::Tolerance tol = const_circ_test.tolerance(); + circ_test.tolerance(tol); + + circ_test.init(); + circ_test.greedyInit(); + circ_test.start(); + circ_test.run(); + + v = const_circ_test.flow(a); + const FlowMap& fm = const_circ_test.flowMap(); + b = const_circ_test.barrier(n); + const_circ_test.barrierMap(bar); + + ignore_unused_variable_warning(fm); +} + +template <class G, class LM, class UM, class DM> +void checkCirculation(const G& g, const LM& lm, const UM& um, + const DM& dm, bool find) +{ + Circulation<G, LM, UM, DM> circ(g, lm, um, dm); + bool ret = circ.run(); + if (find) { + check(ret, "A feasible solution should have been found."); + check(circ.checkFlow(), "The found flow is corrupt."); + check(!circ.checkBarrier(), "A barrier should not have been found."); + } else { + check(!ret, "A feasible solution should not have been found."); + check(circ.checkBarrier(), "The found barrier is corrupt."); + } +} + +int main (int, char*[]) +{ + typedef ListDigraph Digraph; + DIGRAPH_TYPEDEFS(Digraph); + + Digraph g; + IntArcMap lo(g), up(g); + IntNodeMap delta(g, 0); + Node s, t; + + std::istringstream input(test_lgf); + DigraphReader<Digraph>(g,input). + arcMap("lcap", lo). + arcMap("ucap", up). + node("source",s). + node("sink",t). + run(); + + delta[s] = 7; delta[t] = -7; + checkCirculation(g, lo, up, delta, true); + + delta[s] = 13; delta[t] = -13; + checkCirculation(g, lo, up, delta, true); + + delta[s] = 6; delta[t] = -6; + checkCirculation(g, lo, up, delta, false); + + delta[s] = 14; delta[t] = -14; + checkCirculation(g, lo, up, delta, false); + + delta[s] = 7; delta[t] = -13; + checkCirculation(g, lo, up, delta, true); + + delta[s] = 5; delta[t] = -15; + checkCirculation(g, lo, up, delta, true); + + delta[s] = 10; delta[t] = -11; + checkCirculation(g, lo, up, delta, true); + + delta[s] = 11; delta[t] = -10; + checkCirculation(g, lo, up, delta, false); + + return 0; +} diff --git a/lemon/test/connectivity_test.cc b/lemon/test/connectivity_test.cc new file mode 100644 index 0000000..96c47c5 --- /dev/null +++ b/lemon/test/connectivity_test.cc @@ -0,0 +1,297 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <lemon/connectivity.h> +#include <lemon/list_graph.h> +#include <lemon/adaptors.h> + +#include "test_tools.h" + +using namespace lemon; + + +int main() +{ + typedef ListDigraph Digraph; + typedef Undirector<Digraph> Graph; + + { + Digraph d; + Digraph::NodeMap<int> order(d); + Graph g(d); + + check(stronglyConnected(d), "The empty digraph is strongly connected"); + check(countStronglyConnectedComponents(d) == 0, + "The empty digraph has 0 strongly connected component"); + check(connected(g), "The empty graph is connected"); + check(countConnectedComponents(g) == 0, + "The empty graph has 0 connected component"); + + check(biNodeConnected(g), "The empty graph is bi-node-connected"); + check(countBiNodeConnectedComponents(g) == 0, + "The empty graph has 0 bi-node-connected component"); + check(biEdgeConnected(g), "The empty graph is bi-edge-connected"); + check(countBiEdgeConnectedComponents(g) == 0, + "The empty graph has 0 bi-edge-connected component"); + + check(dag(d), "The empty digraph is DAG."); + check(checkedTopologicalSort(d, order), "The empty digraph is DAG."); + check(loopFree(d), "The empty digraph is loop-free."); + check(parallelFree(d), "The empty digraph is parallel-free."); + check(simpleGraph(d), "The empty digraph is simple."); + + check(acyclic(g), "The empty graph is acyclic."); + check(tree(g), "The empty graph is tree."); + check(bipartite(g), "The empty graph is bipartite."); + check(loopFree(g), "The empty graph is loop-free."); + check(parallelFree(g), "The empty graph is parallel-free."); + check(simpleGraph(g), "The empty graph is simple."); + } + + { + Digraph d; + Digraph::NodeMap<int> order(d); + Graph g(d); + Digraph::Node n = d.addNode(); + + check(stronglyConnected(d), "This digraph is strongly connected"); + check(countStronglyConnectedComponents(d) == 1, + "This digraph has 1 strongly connected component"); + check(connected(g), "This graph is connected"); + check(countConnectedComponents(g) == 1, + "This graph has 1 connected component"); + + check(biNodeConnected(g), "This graph is bi-node-connected"); + check(countBiNodeConnectedComponents(g) == 0, + "This graph has 0 bi-node-connected component"); + check(biEdgeConnected(g), "This graph is bi-edge-connected"); + check(countBiEdgeConnectedComponents(g) == 1, + "This graph has 1 bi-edge-connected component"); + + check(dag(d), "This digraph is DAG."); + check(checkedTopologicalSort(d, order), "This digraph is DAG."); + check(loopFree(d), "This digraph is loop-free."); + check(parallelFree(d), "This digraph is parallel-free."); + check(simpleGraph(d), "This digraph is simple."); + + check(acyclic(g), "This graph is acyclic."); + check(tree(g), "This graph is tree."); + check(bipartite(g), "This graph is bipartite."); + check(loopFree(g), "This graph is loop-free."); + check(parallelFree(g), "This graph is parallel-free."); + check(simpleGraph(g), "This graph is simple."); + } + + { + Digraph d; + Digraph::NodeMap<int> order(d); + Graph g(d); + + Digraph::Node n1 = d.addNode(); + Digraph::Node n2 = d.addNode(); + Digraph::Node n3 = d.addNode(); + Digraph::Node n4 = d.addNode(); + Digraph::Node n5 = d.addNode(); + Digraph::Node n6 = d.addNode(); + + d.addArc(n1, n3); + d.addArc(n3, n2); + d.addArc(n2, n1); + d.addArc(n4, n2); + d.addArc(n4, n3); + d.addArc(n5, n6); + d.addArc(n6, n5); + + check(!stronglyConnected(d), "This digraph is not strongly connected"); + check(countStronglyConnectedComponents(d) == 3, + "This digraph has 3 strongly connected components"); + check(!connected(g), "This graph is not connected"); + check(countConnectedComponents(g) == 2, + "This graph has 2 connected components"); + + check(!dag(d), "This digraph is not DAG."); + check(!checkedTopologicalSort(d, order), "This digraph is not DAG."); + check(loopFree(d), "This digraph is loop-free."); + check(parallelFree(d), "This digraph is parallel-free."); + check(simpleGraph(d), "This digraph is simple."); + + check(!acyclic(g), "This graph is not acyclic."); + check(!tree(g), "This graph is not tree."); + check(!bipartite(g), "This graph is not bipartite."); + check(loopFree(g), "This graph is loop-free."); + check(!parallelFree(g), "This graph is not parallel-free."); + check(!simpleGraph(g), "This graph is not simple."); + + d.addArc(n3, n3); + + check(!loopFree(d), "This digraph is not loop-free."); + check(!loopFree(g), "This graph is not loop-free."); + check(!simpleGraph(d), "This digraph is not simple."); + + d.addArc(n3, n2); + + check(!parallelFree(d), "This digraph is not parallel-free."); + } + + { + Digraph d; + Digraph::ArcMap<bool> cutarcs(d, false); + Graph g(d); + + Digraph::Node n1 = d.addNode(); + Digraph::Node n2 = d.addNode(); + Digraph::Node n3 = d.addNode(); + Digraph::Node n4 = d.addNode(); + Digraph::Node n5 = d.addNode(); + Digraph::Node n6 = d.addNode(); + Digraph::Node n7 = d.addNode(); + Digraph::Node n8 = d.addNode(); + + d.addArc(n1, n2); + d.addArc(n5, n1); + d.addArc(n2, n8); + d.addArc(n8, n5); + d.addArc(n6, n4); + d.addArc(n4, n6); + d.addArc(n2, n5); + d.addArc(n1, n8); + d.addArc(n6, n7); + d.addArc(n7, n6); + + check(!stronglyConnected(d), "This digraph is not strongly connected"); + check(countStronglyConnectedComponents(d) == 3, + "This digraph has 3 strongly connected components"); + Digraph::NodeMap<int> scomp1(d); + check(stronglyConnectedComponents(d, scomp1) == 3, + "This digraph has 3 strongly connected components"); + check(scomp1[n1] != scomp1[n3] && scomp1[n1] != scomp1[n4] && + scomp1[n3] != scomp1[n4], "Wrong stronglyConnectedComponents()"); + check(scomp1[n1] == scomp1[n2] && scomp1[n1] == scomp1[n5] && + scomp1[n1] == scomp1[n8], "Wrong stronglyConnectedComponents()"); + check(scomp1[n4] == scomp1[n6] && scomp1[n4] == scomp1[n7], + "Wrong stronglyConnectedComponents()"); + Digraph::ArcMap<bool> scut1(d, false); + check(stronglyConnectedCutArcs(d, scut1) == 0, + "This digraph has 0 strongly connected cut arc."); + for (Digraph::ArcIt a(d); a != INVALID; ++a) { + check(!scut1[a], "Wrong stronglyConnectedCutArcs()"); + } + + check(!connected(g), "This graph is not connected"); + check(countConnectedComponents(g) == 3, + "This graph has 3 connected components"); + Graph::NodeMap<int> comp(g); + check(connectedComponents(g, comp) == 3, + "This graph has 3 connected components"); + check(comp[n1] != comp[n3] && comp[n1] != comp[n4] && + comp[n3] != comp[n4], "Wrong connectedComponents()"); + check(comp[n1] == comp[n2] && comp[n1] == comp[n5] && + comp[n1] == comp[n8], "Wrong connectedComponents()"); + check(comp[n4] == comp[n6] && comp[n4] == comp[n7], + "Wrong connectedComponents()"); + + cutarcs[d.addArc(n3, n1)] = true; + cutarcs[d.addArc(n3, n5)] = true; + cutarcs[d.addArc(n3, n8)] = true; + cutarcs[d.addArc(n8, n6)] = true; + cutarcs[d.addArc(n8, n7)] = true; + + check(!stronglyConnected(d), "This digraph is not strongly connected"); + check(countStronglyConnectedComponents(d) == 3, + "This digraph has 3 strongly connected components"); + Digraph::NodeMap<int> scomp2(d); + check(stronglyConnectedComponents(d, scomp2) == 3, + "This digraph has 3 strongly connected components"); + check(scomp2[n3] == 0, "Wrong stronglyConnectedComponents()"); + check(scomp2[n1] == 1 && scomp2[n2] == 1 && scomp2[n5] == 1 && + scomp2[n8] == 1, "Wrong stronglyConnectedComponents()"); + check(scomp2[n4] == 2 && scomp2[n6] == 2 && scomp2[n7] == 2, + "Wrong stronglyConnectedComponents()"); + Digraph::ArcMap<bool> scut2(d, false); + check(stronglyConnectedCutArcs(d, scut2) == 5, + "This digraph has 5 strongly connected cut arcs."); + for (Digraph::ArcIt a(d); a != INVALID; ++a) { + check(scut2[a] == cutarcs[a], "Wrong stronglyConnectedCutArcs()"); + } + } + + { + // DAG example for topological sort from the book New Algorithms + // (T. H. Cormen, C. E. Leiserson, R. L. Rivest, C. Stein) + Digraph d; + Digraph::NodeMap<int> order(d); + + Digraph::Node belt = d.addNode(); + Digraph::Node trousers = d.addNode(); + Digraph::Node necktie = d.addNode(); + Digraph::Node coat = d.addNode(); + Digraph::Node socks = d.addNode(); + Digraph::Node shirt = d.addNode(); + Digraph::Node shoe = d.addNode(); + Digraph::Node watch = d.addNode(); + Digraph::Node pants = d.addNode(); + + d.addArc(socks, shoe); + d.addArc(pants, shoe); + d.addArc(pants, trousers); + d.addArc(trousers, shoe); + d.addArc(trousers, belt); + d.addArc(belt, coat); + d.addArc(shirt, belt); + d.addArc(shirt, necktie); + d.addArc(necktie, coat); + + check(dag(d), "This digraph is DAG."); + topologicalSort(d, order); + for (Digraph::ArcIt a(d); a != INVALID; ++a) { + check(order[d.source(a)] < order[d.target(a)], + "Wrong topologicalSort()"); + } + } + + { + ListGraph g; + ListGraph::NodeMap<bool> map(g); + + ListGraph::Node n1 = g.addNode(); + ListGraph::Node n2 = g.addNode(); + ListGraph::Node n3 = g.addNode(); + ListGraph::Node n4 = g.addNode(); + ListGraph::Node n5 = g.addNode(); + ListGraph::Node n6 = g.addNode(); + ListGraph::Node n7 = g.addNode(); + + g.addEdge(n1, n3); + g.addEdge(n1, n4); + g.addEdge(n2, n5); + g.addEdge(n3, n6); + g.addEdge(n4, n6); + g.addEdge(n4, n7); + g.addEdge(n5, n7); + + check(bipartite(g), "This graph is bipartite"); + check(bipartitePartitions(g, map), "This graph is bipartite"); + + check(map[n1] == map[n2] && map[n1] == map[n6] && map[n1] == map[n7], + "Wrong bipartitePartitions()"); + check(map[n3] == map[n4] && map[n3] == map[n5], + "Wrong bipartitePartitions()"); + } + + return 0; +} diff --git a/lemon/test/counter_test.cc b/lemon/test/counter_test.cc new file mode 100644 index 0000000..df31dd4 --- /dev/null +++ b/lemon/test/counter_test.cc @@ -0,0 +1,118 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2009 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <lemon/counter.h> +#include <vector> +#include <sstream> + +#include "test/test_tools.h" + +using namespace lemon; + +template <typename T> +void bubbleSort(std::vector<T>& v) { + std::stringstream s1, s2, s3; + { + Counter op("Bubble Sort - Operations: ", s1); + Counter::SubCounter as(op, "Assignments: ", s2); + Counter::SubCounter co(op, "Comparisons: ", s3); + for (int i = v.size()-1; i > 0; --i) { + for (int j = 0; j < i; ++j) { + if (v[j] > v[j+1]) { + T tmp = v[j]; + v[j] = v[j+1]; + v[j+1] = tmp; + as += 3; + } + ++co; + } + } + } + check(s1.str() == "Bubble Sort - Operations: 102\n", "Wrong counter"); + check(s2.str() == "Assignments: 57\n", "Wrong subcounter"); + check(s3.str() == "Comparisons: 45\n", "Wrong subcounter"); +} + +template <typename T> +void insertionSort(std::vector<T>& v) { + std::stringstream s1, s2, s3; + { + Counter op("Insertion Sort - Operations: ", s1); + Counter::SubCounter as(op, "Assignments: ", s2); + Counter::SubCounter co(op, "Comparisons: ", s3); + for (int i = 1; i < int(v.size()); ++i) { + T value = v[i]; + ++as; + int j = i; + while (j > 0 && v[j-1] > value) { + v[j] = v[j-1]; + --j; + ++co; ++as; + } + v[j] = value; + ++as; + } + } + check(s1.str() == "Insertion Sort - Operations: 56\n", "Wrong counter"); + check(s2.str() == "Assignments: 37\n", "Wrong subcounter"); + check(s3.str() == "Comparisons: 19\n", "Wrong subcounter"); +} + +template <typename MyCounter> +void counterTest(bool output) { + std::stringstream s1, s2, s3; + { + MyCounter c("Main Counter: ", s1); + c++; + typename MyCounter::SubCounter d(c, "SubCounter: ", s2); + d++; + typename MyCounter::SubCounter::NoSubCounter e(d, "SubSubCounter: ", s3); + e++; + d+=3; + c-=4; + e-=2; + c.reset(2); + c.reset(); + } + if (output) { + check(s1.str() == "Main Counter: 3\n", "Wrong Counter"); + check(s2.str() == "SubCounter: 3\n", "Wrong SubCounter"); + check(s3.str() == "", "Wrong NoSubCounter"); + } else { + check(s1.str() == "", "Wrong NoCounter"); + check(s2.str() == "", "Wrong SubCounter"); + check(s3.str() == "", "Wrong NoSubCounter"); + } +} + +void init(std::vector<int>& v) { + v[0] = 10; v[1] = 60; v[2] = 20; v[3] = 90; v[4] = 100; + v[5] = 80; v[6] = 40; v[7] = 30; v[8] = 50; v[9] = 70; +} + +int main() +{ + counterTest<Counter>(true); + counterTest<NoCounter>(false); + + std::vector<int> x(10); + init(x); bubbleSort(x); + init(x); insertionSort(x); + + return 0; +} diff --git a/lemon/test/dfs_test.cc b/lemon/test/dfs_test.cc new file mode 100644 index 0000000..36f6b0e --- /dev/null +++ b/lemon/test/dfs_test.cc @@ -0,0 +1,234 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2011 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <lemon/concepts/digraph.h> +#include <lemon/smart_graph.h> +#include <lemon/list_graph.h> +#include <lemon/lgf_reader.h> +#include <lemon/dfs.h> +#include <lemon/path.h> + +#include "graph_test.h" +#include "test_tools.h" + +using namespace lemon; + +char test_lgf[] = + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "5\n" + "6\n" + "@arcs\n" + " label\n" + "0 1 0\n" + "1 2 1\n" + "2 3 2\n" + "1 4 3\n" + "4 2 4\n" + "4 5 5\n" + "5 0 6\n" + "6 3 7\n" + "@attributes\n" + "source 0\n" + "target 5\n" + "source1 6\n" + "target1 3\n"; + + +void checkDfsCompile() +{ + typedef concepts::Digraph Digraph; + typedef Dfs<Digraph> DType; + typedef Digraph::Node Node; + typedef Digraph::Arc Arc; + + Digraph G; + Node s, t; + Arc e; + int l, i; + bool b; + DType::DistMap d(G); + DType::PredMap p(G); + Path<Digraph> pp; + concepts::ReadMap<Arc,bool> am; + + { + DType dfs_test(G); + const DType& const_dfs_test = dfs_test; + + dfs_test.run(s); + dfs_test.run(s,t); + dfs_test.run(); + + dfs_test.init(); + dfs_test.addSource(s); + e = dfs_test.processNextArc(); + e = const_dfs_test.nextArc(); + b = const_dfs_test.emptyQueue(); + i = const_dfs_test.queueSize(); + + dfs_test.start(); + dfs_test.start(t); + dfs_test.start(am); + + l = const_dfs_test.dist(t); + e = const_dfs_test.predArc(t); + s = const_dfs_test.predNode(t); + b = const_dfs_test.reached(t); + d = const_dfs_test.distMap(); + p = const_dfs_test.predMap(); + pp = const_dfs_test.path(t); + } + { + DType + ::SetPredMap<concepts::ReadWriteMap<Node,Arc> > + ::SetDistMap<concepts::ReadWriteMap<Node,int> > + ::SetReachedMap<concepts::ReadWriteMap<Node,bool> > + ::SetStandardProcessedMap + ::SetProcessedMap<concepts::WriteMap<Node,bool> > + ::Create dfs_test(G); + + concepts::ReadWriteMap<Node,Arc> pred_map; + concepts::ReadWriteMap<Node,int> dist_map; + concepts::ReadWriteMap<Node,bool> reached_map; + concepts::WriteMap<Node,bool> processed_map; + + dfs_test + .predMap(pred_map) + .distMap(dist_map) + .reachedMap(reached_map) + .processedMap(processed_map); + + dfs_test.run(s); + dfs_test.run(s,t); + dfs_test.run(); + dfs_test.init(); + + dfs_test.addSource(s); + e = dfs_test.processNextArc(); + e = dfs_test.nextArc(); + b = dfs_test.emptyQueue(); + i = dfs_test.queueSize(); + + dfs_test.start(); + dfs_test.start(t); + dfs_test.start(am); + + l = dfs_test.dist(t); + e = dfs_test.predArc(t); + s = dfs_test.predNode(t); + b = dfs_test.reached(t); + pp = dfs_test.path(t); + } +} + +void checkDfsFunctionCompile() +{ + typedef int VType; + typedef concepts::Digraph Digraph; + typedef Digraph::Arc Arc; + typedef Digraph::Node Node; + + Digraph g; + bool b; + dfs(g).run(Node()); + b=dfs(g).run(Node(),Node()); + dfs(g).run(); + dfs(g) + .predMap(concepts::ReadWriteMap<Node,Arc>()) + .distMap(concepts::ReadWriteMap<Node,VType>()) + .reachedMap(concepts::ReadWriteMap<Node,bool>()) + .processedMap(concepts::WriteMap<Node,bool>()) + .run(Node()); + b=dfs(g) + .predMap(concepts::ReadWriteMap<Node,Arc>()) + .distMap(concepts::ReadWriteMap<Node,VType>()) + .reachedMap(concepts::ReadWriteMap<Node,bool>()) + .processedMap(concepts::WriteMap<Node,bool>()) + .path(concepts::Path<Digraph>()) + .dist(VType()) + .run(Node(),Node()); + dfs(g) + .predMap(concepts::ReadWriteMap<Node,Arc>()) + .distMap(concepts::ReadWriteMap<Node,VType>()) + .reachedMap(concepts::ReadWriteMap<Node,bool>()) + .processedMap(concepts::WriteMap<Node,bool>()) + .run(); +} + +template <class Digraph> +void checkDfs() { + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + + Digraph G; + Node s, t; + Node s1, t1; + + std::istringstream input(test_lgf); + digraphReader(G, input). + node("source", s). + node("target", t). + node("source1", s1). + node("target1", t1). + run(); + + Dfs<Digraph> dfs_test(G); + dfs_test.run(s); + + Path<Digraph> p = dfs_test.path(t); + check(p.length() == dfs_test.dist(t),"path() found a wrong path."); + check(checkPath(G, p),"path() found a wrong path."); + check(pathSource(G, p) == s,"path() found a wrong path."); + check(pathTarget(G, p) == t,"path() found a wrong path."); + + for(NodeIt v(G); v!=INVALID; ++v) { + if (dfs_test.reached(v)) { + check(v==s || dfs_test.predArc(v)!=INVALID, "Wrong tree."); + if (dfs_test.predArc(v)!=INVALID ) { + Arc e=dfs_test.predArc(v); + Node u=G.source(e); + check(u==dfs_test.predNode(v),"Wrong tree."); + check(dfs_test.dist(v) - dfs_test.dist(u) == 1, + "Wrong distance. (" << dfs_test.dist(u) << "->" + << dfs_test.dist(v) << ")"); + } + } + } + + { + Dfs<Digraph> dfs(G); + check(dfs.run(s1,t1) && dfs.reached(t1),"Node 3 is reachable from Node 6."); + } + + { + NullMap<Node,Arc> myPredMap; + dfs(G).predMap(myPredMap).run(s); + } +} + +int main() +{ + checkDfs<ListDigraph>(); + checkDfs<SmartDigraph>(); + return 0; +} diff --git a/lemon/test/digraph_test.cc b/lemon/test/digraph_test.cc new file mode 100644 index 0000000..3c5e896 --- /dev/null +++ b/lemon/test/digraph_test.cc @@ -0,0 +1,562 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <lemon/concepts/digraph.h> +#include <lemon/list_graph.h> +#include <lemon/smart_graph.h> +#include <lemon/static_graph.h> +#include <lemon/full_graph.h> + +#include "test_tools.h" +#include "graph_test.h" + +using namespace lemon; +using namespace lemon::concepts; + +template <class Digraph> +void checkDigraphBuild() { + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + Digraph G; + + checkGraphNodeList(G, 0); + checkGraphArcList(G, 0); + + G.reserveNode(3); + G.reserveArc(4); + + Node + n1 = G.addNode(), + n2 = G.addNode(), + n3 = G.addNode(); + checkGraphNodeList(G, 3); + checkGraphArcList(G, 0); + + Arc a1 = G.addArc(n1, n2); + check(G.source(a1) == n1 && G.target(a1) == n2, "Wrong arc"); + checkGraphNodeList(G, 3); + checkGraphArcList(G, 1); + + checkGraphOutArcList(G, n1, 1); + checkGraphOutArcList(G, n2, 0); + checkGraphOutArcList(G, n3, 0); + + checkGraphInArcList(G, n1, 0); + checkGraphInArcList(G, n2, 1); + checkGraphInArcList(G, n3, 0); + + checkGraphConArcList(G, 1); + + Arc a2 = G.addArc(n2, n1), + a3 = G.addArc(n2, n3), + a4 = G.addArc(n2, n3); + + checkGraphNodeList(G, 3); + checkGraphArcList(G, 4); + + checkGraphOutArcList(G, n1, 1); + checkGraphOutArcList(G, n2, 3); + checkGraphOutArcList(G, n3, 0); + + checkGraphInArcList(G, n1, 1); + checkGraphInArcList(G, n2, 1); + checkGraphInArcList(G, n3, 2); + + checkGraphConArcList(G, 4); + + checkNodeIds(G); + checkArcIds(G); + checkGraphNodeMap(G); + checkGraphArcMap(G); +} + +template <class Digraph> +void checkDigraphSplit() { + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + + Digraph G; + Node n1 = G.addNode(), n2 = G.addNode(), n3 = G.addNode(); + Arc a1 = G.addArc(n1, n2), a2 = G.addArc(n2, n1), + a3 = G.addArc(n2, n3), a4 = G.addArc(n2, n3); + + Node n4 = G.split(n2); + + check(G.target(OutArcIt(G, n2)) == n4 && + G.source(InArcIt(G, n4)) == n2, + "Wrong split."); + + checkGraphNodeList(G, 4); + checkGraphArcList(G, 5); + + checkGraphOutArcList(G, n1, 1); + checkGraphOutArcList(G, n2, 1); + checkGraphOutArcList(G, n3, 0); + checkGraphOutArcList(G, n4, 3); + + checkGraphInArcList(G, n1, 1); + checkGraphInArcList(G, n2, 1); + checkGraphInArcList(G, n3, 2); + checkGraphInArcList(G, n4, 1); + + checkGraphConArcList(G, 5); +} + +template <class Digraph> +void checkDigraphAlter() { + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + + Digraph G; + Node n1 = G.addNode(), n2 = G.addNode(), + n3 = G.addNode(), n4 = G.addNode(); + Arc a1 = G.addArc(n1, n2), a2 = G.addArc(n4, n1), + a3 = G.addArc(n4, n3), a4 = G.addArc(n4, n3), + a5 = G.addArc(n2, n4); + + checkGraphNodeList(G, 4); + checkGraphArcList(G, 5); + + // Check changeSource() and changeTarget() + G.changeTarget(a4, n1); + + checkGraphNodeList(G, 4); + checkGraphArcList(G, 5); + + checkGraphOutArcList(G, n1, 1); + checkGraphOutArcList(G, n2, 1); + checkGraphOutArcList(G, n3, 0); + checkGraphOutArcList(G, n4, 3); + + checkGraphInArcList(G, n1, 2); + checkGraphInArcList(G, n2, 1); + checkGraphInArcList(G, n3, 1); + checkGraphInArcList(G, n4, 1); + + checkGraphConArcList(G, 5); + + G.changeSource(a4, n3); + + checkGraphNodeList(G, 4); + checkGraphArcList(G, 5); + + checkGraphOutArcList(G, n1, 1); + checkGraphOutArcList(G, n2, 1); + checkGraphOutArcList(G, n3, 1); + checkGraphOutArcList(G, n4, 2); + + checkGraphInArcList(G, n1, 2); + checkGraphInArcList(G, n2, 1); + checkGraphInArcList(G, n3, 1); + checkGraphInArcList(G, n4, 1); + + checkGraphConArcList(G, 5); + + // Check contract() + G.contract(n2, n4, false); + + checkGraphNodeList(G, 3); + checkGraphArcList(G, 5); + + checkGraphOutArcList(G, n1, 1); + checkGraphOutArcList(G, n2, 3); + checkGraphOutArcList(G, n3, 1); + + checkGraphInArcList(G, n1, 2); + checkGraphInArcList(G, n2, 2); + checkGraphInArcList(G, n3, 1); + + checkGraphConArcList(G, 5); + + G.contract(n2, n1); + + checkGraphNodeList(G, 2); + checkGraphArcList(G, 3); + + checkGraphOutArcList(G, n2, 2); + checkGraphOutArcList(G, n3, 1); + + checkGraphInArcList(G, n2, 2); + checkGraphInArcList(G, n3, 1); + + checkGraphConArcList(G, 3); +} + +template <class Digraph> +void checkDigraphErase() { + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + + Digraph G; + Node n1 = G.addNode(), n2 = G.addNode(), + n3 = G.addNode(), n4 = G.addNode(); + Arc a1 = G.addArc(n1, n2), a2 = G.addArc(n4, n1), + a3 = G.addArc(n4, n3), a4 = G.addArc(n3, n1), + a5 = G.addArc(n2, n4); + + // Check arc deletion + G.erase(a1); + + checkGraphNodeList(G, 4); + checkGraphArcList(G, 4); + + checkGraphOutArcList(G, n1, 0); + checkGraphOutArcList(G, n2, 1); + checkGraphOutArcList(G, n3, 1); + checkGraphOutArcList(G, n4, 2); + + checkGraphInArcList(G, n1, 2); + checkGraphInArcList(G, n2, 0); + checkGraphInArcList(G, n3, 1); + checkGraphInArcList(G, n4, 1); + + checkGraphConArcList(G, 4); + + // Check node deletion + G.erase(n4); + + checkGraphNodeList(G, 3); + checkGraphArcList(G, 1); + + checkGraphOutArcList(G, n1, 0); + checkGraphOutArcList(G, n2, 0); + checkGraphOutArcList(G, n3, 1); + checkGraphOutArcList(G, n4, 0); + + checkGraphInArcList(G, n1, 1); + checkGraphInArcList(G, n2, 0); + checkGraphInArcList(G, n3, 0); + checkGraphInArcList(G, n4, 0); + + checkGraphConArcList(G, 1); +} + + +template <class Digraph> +void checkDigraphSnapshot() { + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + + Digraph G; + Node n1 = G.addNode(), n2 = G.addNode(), n3 = G.addNode(); + Arc a1 = G.addArc(n1, n2), a2 = G.addArc(n2, n1), + a3 = G.addArc(n2, n3), a4 = G.addArc(n2, n3); + + typename Digraph::Snapshot snapshot(G); + + Node n = G.addNode(); + G.addArc(n3, n); + G.addArc(n, n3); + + checkGraphNodeList(G, 4); + checkGraphArcList(G, 6); + + snapshot.restore(); + + checkGraphNodeList(G, 3); + checkGraphArcList(G, 4); + + checkGraphOutArcList(G, n1, 1); + checkGraphOutArcList(G, n2, 3); + checkGraphOutArcList(G, n3, 0); + + checkGraphInArcList(G, n1, 1); + checkGraphInArcList(G, n2, 1); + checkGraphInArcList(G, n3, 2); + + checkGraphConArcList(G, 4); + + checkNodeIds(G); + checkArcIds(G); + checkGraphNodeMap(G); + checkGraphArcMap(G); + + G.addNode(); + snapshot.save(G); + + G.addArc(G.addNode(), G.addNode()); + + snapshot.restore(); + snapshot.save(G); + + checkGraphNodeList(G, 4); + checkGraphArcList(G, 4); + + G.addArc(G.addNode(), G.addNode()); + + snapshot.restore(); + + checkGraphNodeList(G, 4); + checkGraphArcList(G, 4); +} + +void checkConcepts() { + { // Checking digraph components + checkConcept<BaseDigraphComponent, BaseDigraphComponent >(); + + checkConcept<IDableDigraphComponent<>, + IDableDigraphComponent<> >(); + + checkConcept<IterableDigraphComponent<>, + IterableDigraphComponent<> >(); + + checkConcept<MappableDigraphComponent<>, + MappableDigraphComponent<> >(); + } + { // Checking skeleton digraph + checkConcept<Digraph, Digraph>(); + } + { // Checking ListDigraph + checkConcept<Digraph, ListDigraph>(); + checkConcept<AlterableDigraphComponent<>, ListDigraph>(); + checkConcept<ExtendableDigraphComponent<>, ListDigraph>(); + checkConcept<ClearableDigraphComponent<>, ListDigraph>(); + checkConcept<ErasableDigraphComponent<>, ListDigraph>(); + } + { // Checking SmartDigraph + checkConcept<Digraph, SmartDigraph>(); + checkConcept<AlterableDigraphComponent<>, SmartDigraph>(); + checkConcept<ExtendableDigraphComponent<>, SmartDigraph>(); + checkConcept<ClearableDigraphComponent<>, SmartDigraph>(); + } + { // Checking StaticDigraph + checkConcept<Digraph, StaticDigraph>(); + checkConcept<ClearableDigraphComponent<>, StaticDigraph>(); + } + { // Checking FullDigraph + checkConcept<Digraph, FullDigraph>(); + } +} + +template <typename Digraph> +void checkDigraphValidity() { + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + Digraph g; + + Node + n1 = g.addNode(), + n2 = g.addNode(), + n3 = g.addNode(); + + Arc + e1 = g.addArc(n1, n2), + e2 = g.addArc(n2, n3); + + check(g.valid(n1), "Wrong validity check"); + check(g.valid(e1), "Wrong validity check"); + + check(!g.valid(g.nodeFromId(-1)), "Wrong validity check"); + check(!g.valid(g.arcFromId(-1)), "Wrong validity check"); +} + +template <typename Digraph> +void checkDigraphValidityErase() { + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + Digraph g; + + Node + n1 = g.addNode(), + n2 = g.addNode(), + n3 = g.addNode(); + + Arc + e1 = g.addArc(n1, n2), + e2 = g.addArc(n2, n3); + + check(g.valid(n1), "Wrong validity check"); + check(g.valid(e1), "Wrong validity check"); + + g.erase(n1); + + check(!g.valid(n1), "Wrong validity check"); + check(g.valid(n2), "Wrong validity check"); + check(g.valid(n3), "Wrong validity check"); + check(!g.valid(e1), "Wrong validity check"); + check(g.valid(e2), "Wrong validity check"); + + check(!g.valid(g.nodeFromId(-1)), "Wrong validity check"); + check(!g.valid(g.arcFromId(-1)), "Wrong validity check"); +} + +void checkStaticDigraph() { + SmartDigraph g; + SmartDigraph::NodeMap<StaticDigraph::Node> nref(g); + SmartDigraph::ArcMap<StaticDigraph::Arc> aref(g); + + StaticDigraph G; + + checkGraphNodeList(G, 0); + checkGraphArcList(G, 0); + + G.build(g, nref, aref); + + checkGraphNodeList(G, 0); + checkGraphArcList(G, 0); + + SmartDigraph::Node + n1 = g.addNode(), + n2 = g.addNode(), + n3 = g.addNode(); + + G.build(g, nref, aref); + + checkGraphNodeList(G, 3); + checkGraphArcList(G, 0); + + SmartDigraph::Arc a1 = g.addArc(n1, n2); + + G.build(g, nref, aref); + + check(G.source(aref[a1]) == nref[n1] && G.target(aref[a1]) == nref[n2], + "Wrong arc or wrong references"); + checkGraphNodeList(G, 3); + checkGraphArcList(G, 1); + + checkGraphOutArcList(G, nref[n1], 1); + checkGraphOutArcList(G, nref[n2], 0); + checkGraphOutArcList(G, nref[n3], 0); + + checkGraphInArcList(G, nref[n1], 0); + checkGraphInArcList(G, nref[n2], 1); + checkGraphInArcList(G, nref[n3], 0); + + checkGraphConArcList(G, 1); + + SmartDigraph::Arc + a2 = g.addArc(n2, n1), + a3 = g.addArc(n2, n3), + a4 = g.addArc(n2, n3); + + digraphCopy(g, G).nodeRef(nref).run(); + + checkGraphNodeList(G, 3); + checkGraphArcList(G, 4); + + checkGraphOutArcList(G, nref[n1], 1); + checkGraphOutArcList(G, nref[n2], 3); + checkGraphOutArcList(G, nref[n3], 0); + + checkGraphInArcList(G, nref[n1], 1); + checkGraphInArcList(G, nref[n2], 1); + checkGraphInArcList(G, nref[n3], 2); + + checkGraphConArcList(G, 4); + + std::vector<std::pair<int,int> > arcs; + arcs.push_back(std::make_pair(0,1)); + arcs.push_back(std::make_pair(0,2)); + arcs.push_back(std::make_pair(1,3)); + arcs.push_back(std::make_pair(1,2)); + arcs.push_back(std::make_pair(3,0)); + arcs.push_back(std::make_pair(3,3)); + arcs.push_back(std::make_pair(4,2)); + arcs.push_back(std::make_pair(4,3)); + arcs.push_back(std::make_pair(4,1)); + + G.build(6, arcs.begin(), arcs.end()); + + checkGraphNodeList(G, 6); + checkGraphArcList(G, 9); + + checkGraphOutArcList(G, G.node(0), 2); + checkGraphOutArcList(G, G.node(1), 2); + checkGraphOutArcList(G, G.node(2), 0); + checkGraphOutArcList(G, G.node(3), 2); + checkGraphOutArcList(G, G.node(4), 3); + checkGraphOutArcList(G, G.node(5), 0); + + checkGraphInArcList(G, G.node(0), 1); + checkGraphInArcList(G, G.node(1), 2); + checkGraphInArcList(G, G.node(2), 3); + checkGraphInArcList(G, G.node(3), 3); + checkGraphInArcList(G, G.node(4), 0); + checkGraphInArcList(G, G.node(5), 0); + + checkGraphConArcList(G, 9); + + checkNodeIds(G); + checkArcIds(G); + checkGraphNodeMap(G); + checkGraphArcMap(G); + + int n = G.nodeNum(); + int m = G.arcNum(); + check(G.index(G.node(n-1)) == n-1, "Wrong index."); + check(G.index(G.arc(m-1)) == m-1, "Wrong index."); +} + +void checkFullDigraph(int num) { + typedef FullDigraph Digraph; + DIGRAPH_TYPEDEFS(Digraph); + + Digraph G(num); + check(G.nodeNum() == num && G.arcNum() == num * num, "Wrong size"); + + G.resize(num); + check(G.nodeNum() == num && G.arcNum() == num * num, "Wrong size"); + + checkGraphNodeList(G, num); + checkGraphArcList(G, num * num); + + for (NodeIt n(G); n != INVALID; ++n) { + checkGraphOutArcList(G, n, num); + checkGraphInArcList(G, n, num); + } + + checkGraphConArcList(G, num * num); + + checkNodeIds(G); + checkArcIds(G); + checkGraphNodeMap(G); + checkGraphArcMap(G); + + for (int i = 0; i < G.nodeNum(); ++i) { + check(G.index(G(i)) == i, "Wrong index"); + } + + for (NodeIt s(G); s != INVALID; ++s) { + for (NodeIt t(G); t != INVALID; ++t) { + Arc a = G.arc(s, t); + check(G.source(a) == s && G.target(a) == t, "Wrong arc lookup"); + } + } +} + +void checkDigraphs() { + { // Checking ListDigraph + checkDigraphBuild<ListDigraph>(); + checkDigraphSplit<ListDigraph>(); + checkDigraphAlter<ListDigraph>(); + checkDigraphErase<ListDigraph>(); + checkDigraphSnapshot<ListDigraph>(); + checkDigraphValidityErase<ListDigraph>(); + } + { // Checking SmartDigraph + checkDigraphBuild<SmartDigraph>(); + checkDigraphSplit<SmartDigraph>(); + checkDigraphSnapshot<SmartDigraph>(); + checkDigraphValidity<SmartDigraph>(); + } + { // Checking StaticDigraph + checkStaticDigraph(); + } + { // Checking FullDigraph + checkFullDigraph(8); + } +} + +int main() { + checkDigraphs(); + checkConcepts(); + return 0; +} diff --git a/lemon/test/dijkstra_test.cc b/lemon/test/dijkstra_test.cc new file mode 100644 index 0000000..c0fbf0b --- /dev/null +++ b/lemon/test/dijkstra_test.cc @@ -0,0 +1,242 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <lemon/concepts/digraph.h> +#include <lemon/smart_graph.h> +#include <lemon/list_graph.h> +#include <lemon/lgf_reader.h> +#include <lemon/dijkstra.h> +#include <lemon/path.h> +#include <lemon/bin_heap.h> + +#include "graph_test.h" +#include "test_tools.h" + +using namespace lemon; + +char test_lgf[] = + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "@arcs\n" + " label length\n" + "0 1 0 1\n" + "1 2 1 1\n" + "2 3 2 1\n" + "0 3 4 5\n" + "0 3 5 10\n" + "0 3 6 7\n" + "4 2 7 1\n" + "@attributes\n" + "source 0\n" + "target 3\n"; + +void checkDijkstraCompile() +{ + typedef int VType; + typedef concepts::Digraph Digraph; + typedef concepts::ReadMap<Digraph::Arc,VType> LengthMap; + typedef Dijkstra<Digraph, LengthMap> DType; + typedef Digraph::Node Node; + typedef Digraph::Arc Arc; + + Digraph G; + Node s, t, n; + Arc e; + VType l; + int i; + bool b; + DType::DistMap d(G); + DType::PredMap p(G); + LengthMap length; + Path<Digraph> pp; + concepts::ReadMap<Node,bool> nm; + + { + DType dijkstra_test(G,length); + const DType& const_dijkstra_test = dijkstra_test; + + dijkstra_test.run(s); + dijkstra_test.run(s,t); + + dijkstra_test.init(); + dijkstra_test.addSource(s); + dijkstra_test.addSource(s, 1); + n = dijkstra_test.processNextNode(); + n = const_dijkstra_test.nextNode(); + b = const_dijkstra_test.emptyQueue(); + i = const_dijkstra_test.queueSize(); + + dijkstra_test.start(); + dijkstra_test.start(t); + dijkstra_test.start(nm); + + l = const_dijkstra_test.dist(t); + e = const_dijkstra_test.predArc(t); + s = const_dijkstra_test.predNode(t); + b = const_dijkstra_test.reached(t); + b = const_dijkstra_test.processed(t); + d = const_dijkstra_test.distMap(); + p = const_dijkstra_test.predMap(); + pp = const_dijkstra_test.path(t); + l = const_dijkstra_test.currentDist(t); + } + { + DType + ::SetPredMap<concepts::ReadWriteMap<Node,Arc> > + ::SetDistMap<concepts::ReadWriteMap<Node,VType> > + ::SetStandardProcessedMap + ::SetProcessedMap<concepts::WriteMap<Node,bool> > + ::SetOperationTraits<DijkstraDefaultOperationTraits<VType> > + ::SetHeap<BinHeap<VType, concepts::ReadWriteMap<Node,int> > > + ::SetStandardHeap<BinHeap<VType, concepts::ReadWriteMap<Node,int> > > + ::SetHeap<BinHeap<VType, concepts::ReadWriteMap<Node,int> >, + concepts::ReadWriteMap<Node,int> > + ::Create dijkstra_test(G,length); + + LengthMap length_map; + concepts::ReadWriteMap<Node,Arc> pred_map; + concepts::ReadWriteMap<Node,VType> dist_map; + concepts::WriteMap<Node,bool> processed_map; + concepts::ReadWriteMap<Node,int> heap_cross_ref; + BinHeap<VType, concepts::ReadWriteMap<Node,int> > heap(heap_cross_ref); + + dijkstra_test + .lengthMap(length_map) + .predMap(pred_map) + .distMap(dist_map) + .processedMap(processed_map) + .heap(heap, heap_cross_ref); + + dijkstra_test.run(s); + dijkstra_test.run(s,t); + + dijkstra_test.addSource(s); + dijkstra_test.addSource(s, 1); + n = dijkstra_test.processNextNode(); + n = dijkstra_test.nextNode(); + b = dijkstra_test.emptyQueue(); + i = dijkstra_test.queueSize(); + + dijkstra_test.start(); + dijkstra_test.start(t); + dijkstra_test.start(nm); + + l = dijkstra_test.dist(t); + e = dijkstra_test.predArc(t); + s = dijkstra_test.predNode(t); + b = dijkstra_test.reached(t); + b = dijkstra_test.processed(t); + pp = dijkstra_test.path(t); + l = dijkstra_test.currentDist(t); + } + +} + +void checkDijkstraFunctionCompile() +{ + typedef int VType; + typedef concepts::Digraph Digraph; + typedef Digraph::Arc Arc; + typedef Digraph::Node Node; + typedef concepts::ReadMap<Digraph::Arc,VType> LengthMap; + + Digraph g; + bool b; + dijkstra(g,LengthMap()).run(Node()); + b=dijkstra(g,LengthMap()).run(Node(),Node()); + dijkstra(g,LengthMap()) + .predMap(concepts::ReadWriteMap<Node,Arc>()) + .distMap(concepts::ReadWriteMap<Node,VType>()) + .processedMap(concepts::WriteMap<Node,bool>()) + .run(Node()); + b=dijkstra(g,LengthMap()) + .predMap(concepts::ReadWriteMap<Node,Arc>()) + .distMap(concepts::ReadWriteMap<Node,VType>()) + .processedMap(concepts::WriteMap<Node,bool>()) + .path(concepts::Path<Digraph>()) + .dist(VType()) + .run(Node(),Node()); +} + +template <class Digraph> +void checkDijkstra() { + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + typedef typename Digraph::template ArcMap<int> LengthMap; + + Digraph G; + Node s, t; + LengthMap length(G); + + std::istringstream input(test_lgf); + digraphReader(G, input). + arcMap("length", length). + node("source", s). + node("target", t). + run(); + + Dijkstra<Digraph, LengthMap> + dijkstra_test(G, length); + dijkstra_test.run(s); + + check(dijkstra_test.dist(t)==3,"Dijkstra found a wrong path."); + + Path<Digraph> p = dijkstra_test.path(t); + check(p.length()==3,"path() found a wrong path."); + check(checkPath(G, p),"path() found a wrong path."); + check(pathSource(G, p) == s,"path() found a wrong path."); + check(pathTarget(G, p) == t,"path() found a wrong path."); + + for(ArcIt e(G); e!=INVALID; ++e) { + Node u=G.source(e); + Node v=G.target(e); + check( !dijkstra_test.reached(u) || + (dijkstra_test.dist(v) - dijkstra_test.dist(u) <= length[e]), + "Wrong output. dist(target)-dist(source)-arc_length=" << + dijkstra_test.dist(v) - dijkstra_test.dist(u) - length[e]); + } + + for(NodeIt v(G); v!=INVALID; ++v) { + if (dijkstra_test.reached(v)) { + check(v==s || dijkstra_test.predArc(v)!=INVALID, "Wrong tree."); + if (dijkstra_test.predArc(v)!=INVALID ) { + Arc e=dijkstra_test.predArc(v); + Node u=G.source(e); + check(u==dijkstra_test.predNode(v),"Wrong tree."); + check(dijkstra_test.dist(v) - dijkstra_test.dist(u) == length[e], + "Wrong distance! Difference: " << + std::abs(dijkstra_test.dist(v)-dijkstra_test.dist(u)-length[e])); + } + } + } + + { + NullMap<Node,Arc> myPredMap; + dijkstra(G,length).predMap(myPredMap).run(s); + } +} + +int main() { + checkDijkstra<ListDigraph>(); + checkDijkstra<SmartDigraph>(); + return 0; +} diff --git a/lemon/test/dim_test.cc b/lemon/test/dim_test.cc new file mode 100644 index 0000000..0b2b925 --- /dev/null +++ b/lemon/test/dim_test.cc @@ -0,0 +1,87 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2009 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <lemon/dim2.h> +#include <iostream> +#include "test_tools.h" + +using namespace std; +using namespace lemon; + +int main() +{ + typedef dim2::Point<int> Point; + + Point p; + check(p.size()==2, "Wrong dim2::Point initialization."); + + Point a(1,2); + Point b(3,4); + check(a[0]==1 && a[1]==2, "Wrong dim2::Point initialization."); + + p = a+b; + check(p.x==4 && p.y==6, "Wrong dim2::Point addition."); + + p = a-b; + check(p.x==-2 && p.y==-2, "Wrong dim2::Point subtraction."); + + check(a.normSquare()==5,"Wrong dim2::Point norm calculation."); + check(a*b==11, "Wrong dim2::Point scalar product."); + + int l=2; + p = a*l; + check(p.x==2 && p.y==4, "Wrong dim2::Point multiplication by a scalar."); + + p = b/l; + check(p.x==1 && p.y==2, "Wrong dim2::Point division by a scalar."); + + typedef dim2::Box<int> Box; + Box box1; + check(box1.empty(), "Wrong empty() in dim2::Box."); + + box1.add(a); + check(!box1.empty(), "Wrong empty() in dim2::Box."); + box1.add(b); + + check(box1.left()==1 && box1.bottom()==2 && + box1.right()==3 && box1.top()==4, + "Wrong addition of points to dim2::Box."); + + check(box1.inside(Point(2,3)), "Wrong inside() in dim2::Box."); + check(box1.inside(Point(1,3)), "Wrong inside() in dim2::Box."); + check(!box1.inside(Point(0,3)), "Wrong inside() in dim2::Box."); + + Box box2(Point(2,2)); + check(!box2.empty(), "Wrong empty() in dim2::Box."); + + box2.bottomLeft(Point(2,0)); + box2.topRight(Point(5,3)); + Box box3 = box1 & box2; + check(!box3.empty() && + box3.left()==2 && box3.bottom()==2 && + box3.right()==3 && box3.top()==3, + "Wrong intersection of two dim2::Box objects."); + + box1.add(box2); + check(!box1.empty() && + box1.left()==1 && box1.bottom()==0 && + box1.right()==5 && box1.top()==4, + "Wrong addition of two dim2::Box objects."); + + return 0; +} diff --git a/lemon/test/edge_set_test.cc b/lemon/test/edge_set_test.cc new file mode 100644 index 0000000..afe1098 --- /dev/null +++ b/lemon/test/edge_set_test.cc @@ -0,0 +1,380 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <iostream> +#include <vector> + +#include <lemon/concepts/digraph.h> +#include <lemon/concepts/graph.h> +#include <lemon/concept_check.h> + +#include <lemon/list_graph.h> + +#include <lemon/edge_set.h> + +#include "graph_test.h" +#include "test_tools.h" + +using namespace lemon; + +void checkSmartArcSet() { + checkConcept<concepts::Digraph, SmartArcSet<ListDigraph> >(); + + typedef ListDigraph Digraph; + typedef SmartArcSet<Digraph> ArcSet; + + Digraph digraph; + Digraph::Node + n1 = digraph.addNode(), + n2 = digraph.addNode(); + + Digraph::Arc ga1 = digraph.addArc(n1, n2); + + ArcSet arc_set(digraph); + + Digraph::Arc ga2 = digraph.addArc(n2, n1); + + checkGraphNodeList(arc_set, 2); + checkGraphArcList(arc_set, 0); + + Digraph::Node + n3 = digraph.addNode(); + checkGraphNodeList(arc_set, 3); + checkGraphArcList(arc_set, 0); + + ArcSet::Arc a1 = arc_set.addArc(n1, n2); + check(arc_set.source(a1) == n1 && arc_set.target(a1) == n2, "Wrong arc"); + checkGraphNodeList(arc_set, 3); + checkGraphArcList(arc_set, 1); + + checkGraphOutArcList(arc_set, n1, 1); + checkGraphOutArcList(arc_set, n2, 0); + checkGraphOutArcList(arc_set, n3, 0); + + checkGraphInArcList(arc_set, n1, 0); + checkGraphInArcList(arc_set, n2, 1); + checkGraphInArcList(arc_set, n3, 0); + + checkGraphConArcList(arc_set, 1); + + ArcSet::Arc a2 = arc_set.addArc(n2, n1), + a3 = arc_set.addArc(n2, n3), + a4 = arc_set.addArc(n2, n3); + checkGraphNodeList(arc_set, 3); + checkGraphArcList(arc_set, 4); + + checkGraphOutArcList(arc_set, n1, 1); + checkGraphOutArcList(arc_set, n2, 3); + checkGraphOutArcList(arc_set, n3, 0); + + checkGraphInArcList(arc_set, n1, 1); + checkGraphInArcList(arc_set, n2, 1); + checkGraphInArcList(arc_set, n3, 2); + + checkGraphConArcList(arc_set, 4); + + checkNodeIds(arc_set); + checkArcIds(arc_set); + checkGraphNodeMap(arc_set); + checkGraphArcMap(arc_set); + + check(arc_set.valid(), "Wrong validity"); + digraph.erase(n1); + check(!arc_set.valid(), "Wrong validity"); +} + +void checkListArcSet() { + checkConcept<concepts::Digraph, SmartArcSet<ListDigraph> >(); + + typedef ListDigraph Digraph; + typedef ListArcSet<Digraph> ArcSet; + + Digraph digraph; + Digraph::Node + n1 = digraph.addNode(), + n2 = digraph.addNode(); + + Digraph::Arc ga1 = digraph.addArc(n1, n2); + + ArcSet arc_set(digraph); + + Digraph::Arc ga2 = digraph.addArc(n2, n1); + + checkGraphNodeList(arc_set, 2); + checkGraphArcList(arc_set, 0); + + Digraph::Node + n3 = digraph.addNode(); + checkGraphNodeList(arc_set, 3); + checkGraphArcList(arc_set, 0); + + ArcSet::Arc a1 = arc_set.addArc(n1, n2); + check(arc_set.source(a1) == n1 && arc_set.target(a1) == n2, "Wrong arc"); + checkGraphNodeList(arc_set, 3); + checkGraphArcList(arc_set, 1); + + checkGraphOutArcList(arc_set, n1, 1); + checkGraphOutArcList(arc_set, n2, 0); + checkGraphOutArcList(arc_set, n3, 0); + + checkGraphInArcList(arc_set, n1, 0); + checkGraphInArcList(arc_set, n2, 1); + checkGraphInArcList(arc_set, n3, 0); + + checkGraphConArcList(arc_set, 1); + + ArcSet::Arc a2 = arc_set.addArc(n2, n1), + a3 = arc_set.addArc(n2, n3), + a4 = arc_set.addArc(n2, n3); + checkGraphNodeList(arc_set, 3); + checkGraphArcList(arc_set, 4); + + checkGraphOutArcList(arc_set, n1, 1); + checkGraphOutArcList(arc_set, n2, 3); + checkGraphOutArcList(arc_set, n3, 0); + + checkGraphInArcList(arc_set, n1, 1); + checkGraphInArcList(arc_set, n2, 1); + checkGraphInArcList(arc_set, n3, 2); + + checkGraphConArcList(arc_set, 4); + + checkNodeIds(arc_set); + checkArcIds(arc_set); + checkGraphNodeMap(arc_set); + checkGraphArcMap(arc_set); + + digraph.erase(n1); + + checkGraphNodeList(arc_set, 2); + checkGraphArcList(arc_set, 2); + + checkGraphOutArcList(arc_set, n2, 2); + checkGraphOutArcList(arc_set, n3, 0); + + checkGraphInArcList(arc_set, n2, 0); + checkGraphInArcList(arc_set, n3, 2); + + checkNodeIds(arc_set); + checkArcIds(arc_set); + checkGraphNodeMap(arc_set); + checkGraphArcMap(arc_set); + + checkGraphConArcList(arc_set, 2); +} + +void checkSmartEdgeSet() { + checkConcept<concepts::Digraph, SmartEdgeSet<ListDigraph> >(); + + typedef ListDigraph Digraph; + typedef SmartEdgeSet<Digraph> EdgeSet; + + Digraph digraph; + Digraph::Node + n1 = digraph.addNode(), + n2 = digraph.addNode(); + + Digraph::Arc ga1 = digraph.addArc(n1, n2); + + EdgeSet edge_set(digraph); + + Digraph::Arc ga2 = digraph.addArc(n2, n1); + + checkGraphNodeList(edge_set, 2); + checkGraphArcList(edge_set, 0); + checkGraphEdgeList(edge_set, 0); + + Digraph::Node + n3 = digraph.addNode(); + checkGraphNodeList(edge_set, 3); + checkGraphArcList(edge_set, 0); + checkGraphEdgeList(edge_set, 0); + + EdgeSet::Edge e1 = edge_set.addEdge(n1, n2); + check((edge_set.u(e1) == n1 && edge_set.v(e1) == n2) || + (edge_set.v(e1) == n1 && edge_set.u(e1) == n2), "Wrong edge"); + checkGraphNodeList(edge_set, 3); + checkGraphArcList(edge_set, 2); + checkGraphEdgeList(edge_set, 1); + + checkGraphOutArcList(edge_set, n1, 1); + checkGraphOutArcList(edge_set, n2, 1); + checkGraphOutArcList(edge_set, n3, 0); + + checkGraphInArcList(edge_set, n1, 1); + checkGraphInArcList(edge_set, n2, 1); + checkGraphInArcList(edge_set, n3, 0); + + checkGraphIncEdgeList(edge_set, n1, 1); + checkGraphIncEdgeList(edge_set, n2, 1); + checkGraphIncEdgeList(edge_set, n3, 0); + + checkGraphConEdgeList(edge_set, 1); + checkGraphConArcList(edge_set, 2); + + EdgeSet::Edge e2 = edge_set.addEdge(n2, n1), + e3 = edge_set.addEdge(n2, n3), + e4 = edge_set.addEdge(n2, n3); + checkGraphNodeList(edge_set, 3); + checkGraphEdgeList(edge_set, 4); + + checkGraphOutArcList(edge_set, n1, 2); + checkGraphOutArcList(edge_set, n2, 4); + checkGraphOutArcList(edge_set, n3, 2); + + checkGraphInArcList(edge_set, n1, 2); + checkGraphInArcList(edge_set, n2, 4); + checkGraphInArcList(edge_set, n3, 2); + + checkGraphIncEdgeList(edge_set, n1, 2); + checkGraphIncEdgeList(edge_set, n2, 4); + checkGraphIncEdgeList(edge_set, n3, 2); + + checkGraphConEdgeList(edge_set, 4); + checkGraphConArcList(edge_set, 8); + + checkArcDirections(edge_set); + + checkNodeIds(edge_set); + checkArcIds(edge_set); + checkEdgeIds(edge_set); + checkGraphNodeMap(edge_set); + checkGraphArcMap(edge_set); + checkGraphEdgeMap(edge_set); + + check(edge_set.valid(), "Wrong validity"); + digraph.erase(n1); + check(!edge_set.valid(), "Wrong validity"); +} + +void checkListEdgeSet() { + checkConcept<concepts::Digraph, ListEdgeSet<ListDigraph> >(); + + typedef ListDigraph Digraph; + typedef ListEdgeSet<Digraph> EdgeSet; + + Digraph digraph; + Digraph::Node + n1 = digraph.addNode(), + n2 = digraph.addNode(); + + Digraph::Arc ga1 = digraph.addArc(n1, n2); + + EdgeSet edge_set(digraph); + + Digraph::Arc ga2 = digraph.addArc(n2, n1); + + checkGraphNodeList(edge_set, 2); + checkGraphArcList(edge_set, 0); + checkGraphEdgeList(edge_set, 0); + + Digraph::Node + n3 = digraph.addNode(); + checkGraphNodeList(edge_set, 3); + checkGraphArcList(edge_set, 0); + checkGraphEdgeList(edge_set, 0); + + EdgeSet::Edge e1 = edge_set.addEdge(n1, n2); + check((edge_set.u(e1) == n1 && edge_set.v(e1) == n2) || + (edge_set.v(e1) == n1 && edge_set.u(e1) == n2), "Wrong edge"); + checkGraphNodeList(edge_set, 3); + checkGraphArcList(edge_set, 2); + checkGraphEdgeList(edge_set, 1); + + checkGraphOutArcList(edge_set, n1, 1); + checkGraphOutArcList(edge_set, n2, 1); + checkGraphOutArcList(edge_set, n3, 0); + + checkGraphInArcList(edge_set, n1, 1); + checkGraphInArcList(edge_set, n2, 1); + checkGraphInArcList(edge_set, n3, 0); + + checkGraphIncEdgeList(edge_set, n1, 1); + checkGraphIncEdgeList(edge_set, n2, 1); + checkGraphIncEdgeList(edge_set, n3, 0); + + checkGraphConEdgeList(edge_set, 1); + checkGraphConArcList(edge_set, 2); + + EdgeSet::Edge e2 = edge_set.addEdge(n2, n1), + e3 = edge_set.addEdge(n2, n3), + e4 = edge_set.addEdge(n2, n3); + checkGraphNodeList(edge_set, 3); + checkGraphEdgeList(edge_set, 4); + + checkGraphOutArcList(edge_set, n1, 2); + checkGraphOutArcList(edge_set, n2, 4); + checkGraphOutArcList(edge_set, n3, 2); + + checkGraphInArcList(edge_set, n1, 2); + checkGraphInArcList(edge_set, n2, 4); + checkGraphInArcList(edge_set, n3, 2); + + checkGraphIncEdgeList(edge_set, n1, 2); + checkGraphIncEdgeList(edge_set, n2, 4); + checkGraphIncEdgeList(edge_set, n3, 2); + + checkGraphConEdgeList(edge_set, 4); + checkGraphConArcList(edge_set, 8); + + checkArcDirections(edge_set); + + checkNodeIds(edge_set); + checkArcIds(edge_set); + checkEdgeIds(edge_set); + checkGraphNodeMap(edge_set); + checkGraphArcMap(edge_set); + checkGraphEdgeMap(edge_set); + + digraph.erase(n1); + + checkGraphNodeList(edge_set, 2); + checkGraphArcList(edge_set, 4); + checkGraphEdgeList(edge_set, 2); + + checkGraphOutArcList(edge_set, n2, 2); + checkGraphOutArcList(edge_set, n3, 2); + + checkGraphInArcList(edge_set, n2, 2); + checkGraphInArcList(edge_set, n3, 2); + + checkGraphIncEdgeList(edge_set, n2, 2); + checkGraphIncEdgeList(edge_set, n3, 2); + + checkNodeIds(edge_set); + checkArcIds(edge_set); + checkEdgeIds(edge_set); + checkGraphNodeMap(edge_set); + checkGraphArcMap(edge_set); + checkGraphEdgeMap(edge_set); + + checkGraphConEdgeList(edge_set, 2); + checkGraphConArcList(edge_set, 4); + +} + + +int main() { + + checkSmartArcSet(); + checkListArcSet(); + checkSmartEdgeSet(); + checkListEdgeSet(); + + return 0; +} diff --git a/lemon/test/error_test.cc b/lemon/test/error_test.cc new file mode 100644 index 0000000..1527519 --- /dev/null +++ b/lemon/test/error_test.cc @@ -0,0 +1,90 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2009 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <iostream> + +#include <lemon/error.h> +#include "test_tools.h" + +using namespace lemon; + +#ifdef LEMON_ENABLE_ASSERTS +#undef LEMON_ENABLE_ASSERTS +#endif + +#ifdef LEMON_DISABLE_ASSERTS +#undef LEMON_DISABLE_ASSERTS +#endif + +#ifdef NDEBUG +#undef NDEBUG +#endif + +//checking disabled asserts +#define LEMON_DISABLE_ASSERTS +#include <lemon/assert.h> + +void no_assertion_text_disable() { + LEMON_ASSERT(true, "This is a fault message"); +} + +void assertion_text_disable() { + LEMON_ASSERT(false, "This is a fault message"); +} + +void check_assertion_disable() { + no_assertion_text_disable(); + assertion_text_disable(); +} +#undef LEMON_DISABLE_ASSERTS + +//checking custom assert handler +#define LEMON_ASSERT_CUSTOM + +static int cnt = 0; +void my_assert_handler(const char*, int, const char*, + const char*, const char*) { + ++cnt; +} + +#define LEMON_CUSTOM_ASSERT_HANDLER my_assert_handler +#include <lemon/assert.h> + +void no_assertion_text_custom() { + LEMON_ASSERT(true, "This is a fault message"); +} + +void assertion_text_custom() { + LEMON_ASSERT(false, "This is a fault message"); +} + +void check_assertion_custom() { + no_assertion_text_custom(); + assertion_text_custom(); + check(cnt == 1, "The custom assert handler does not work"); +} + +#undef LEMON_ASSERT_CUSTOM + + +int main() { + check_assertion_disable(); + check_assertion_custom(); + + return 0; +} diff --git a/lemon/test/euler_test.cc b/lemon/test/euler_test.cc new file mode 100644 index 0000000..3f134b6 --- /dev/null +++ b/lemon/test/euler_test.cc @@ -0,0 +1,223 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <lemon/euler.h> +#include <lemon/list_graph.h> +#include <lemon/adaptors.h> +#include "test_tools.h" + +using namespace lemon; + +template <typename Digraph> +void checkDiEulerIt(const Digraph& g, + const typename Digraph::Node& start = INVALID) +{ + typename Digraph::template ArcMap<int> visitationNumber(g, 0); + + DiEulerIt<Digraph> e(g, start); + if (e == INVALID) return; + typename Digraph::Node firstNode = g.source(e); + typename Digraph::Node lastNode = g.target(e); + if (start != INVALID) { + check(firstNode == start, "checkDiEulerIt: Wrong first node"); + } + + for (; e != INVALID; ++e) { + if (e != INVALID) lastNode = g.target(e); + ++visitationNumber[e]; + } + + check(firstNode == lastNode, + "checkDiEulerIt: First and last nodes are not the same"); + + for (typename Digraph::ArcIt a(g); a != INVALID; ++a) + { + check(visitationNumber[a] == 1, + "checkDiEulerIt: Not visited or multiple times visited arc found"); + } +} + +template <typename Graph> +void checkEulerIt(const Graph& g, + const typename Graph::Node& start = INVALID) +{ + typename Graph::template EdgeMap<int> visitationNumber(g, 0); + + EulerIt<Graph> e(g, start); + if (e == INVALID) return; + typename Graph::Node firstNode = g.source(typename Graph::Arc(e)); + typename Graph::Node lastNode = g.target(typename Graph::Arc(e)); + if (start != INVALID) { + check(firstNode == start, "checkEulerIt: Wrong first node"); + } + + for (; e != INVALID; ++e) { + if (e != INVALID) lastNode = g.target(typename Graph::Arc(e)); + ++visitationNumber[e]; + } + + check(firstNode == lastNode, + "checkEulerIt: First and last nodes are not the same"); + + for (typename Graph::EdgeIt e(g); e != INVALID; ++e) + { + check(visitationNumber[e] == 1, + "checkEulerIt: Not visited or multiple times visited edge found"); + } +} + +int main() +{ + typedef ListDigraph Digraph; + typedef Undirector<Digraph> Graph; + + { + Digraph d; + Graph g(d); + + checkDiEulerIt(d); + checkDiEulerIt(g); + checkEulerIt(g); + + check(eulerian(d), "This graph is Eulerian"); + check(eulerian(g), "This graph is Eulerian"); + } + { + Digraph d; + Graph g(d); + Digraph::Node n = d.addNode(); + + checkDiEulerIt(d); + checkDiEulerIt(g); + checkEulerIt(g); + + check(eulerian(d), "This graph is Eulerian"); + check(eulerian(g), "This graph is Eulerian"); + } + { + Digraph d; + Graph g(d); + Digraph::Node n = d.addNode(); + d.addArc(n, n); + + checkDiEulerIt(d); + checkDiEulerIt(g); + checkEulerIt(g); + + check(eulerian(d), "This graph is Eulerian"); + check(eulerian(g), "This graph is Eulerian"); + } + { + Digraph d; + Graph g(d); + Digraph::Node n1 = d.addNode(); + Digraph::Node n2 = d.addNode(); + Digraph::Node n3 = d.addNode(); + + d.addArc(n1, n2); + d.addArc(n2, n1); + d.addArc(n2, n3); + d.addArc(n3, n2); + + checkDiEulerIt(d); + checkDiEulerIt(d, n2); + checkDiEulerIt(g); + checkDiEulerIt(g, n2); + checkEulerIt(g); + checkEulerIt(g, n2); + + check(eulerian(d), "This graph is Eulerian"); + check(eulerian(g), "This graph is Eulerian"); + } + { + Digraph d; + Graph g(d); + Digraph::Node n1 = d.addNode(); + Digraph::Node n2 = d.addNode(); + Digraph::Node n3 = d.addNode(); + Digraph::Node n4 = d.addNode(); + Digraph::Node n5 = d.addNode(); + Digraph::Node n6 = d.addNode(); + + d.addArc(n1, n2); + d.addArc(n2, n4); + d.addArc(n1, n3); + d.addArc(n3, n4); + d.addArc(n4, n1); + d.addArc(n3, n5); + d.addArc(n5, n2); + d.addArc(n4, n6); + d.addArc(n2, n6); + d.addArc(n6, n1); + d.addArc(n6, n3); + + checkDiEulerIt(d); + checkDiEulerIt(d, n1); + checkDiEulerIt(d, n5); + + checkDiEulerIt(g); + checkDiEulerIt(g, n1); + checkDiEulerIt(g, n5); + checkEulerIt(g); + checkEulerIt(g, n1); + checkEulerIt(g, n5); + + check(eulerian(d), "This graph is Eulerian"); + check(eulerian(g), "This graph is Eulerian"); + } + { + Digraph d; + Graph g(d); + Digraph::Node n0 = d.addNode(); + Digraph::Node n1 = d.addNode(); + Digraph::Node n2 = d.addNode(); + Digraph::Node n3 = d.addNode(); + Digraph::Node n4 = d.addNode(); + Digraph::Node n5 = d.addNode(); + + d.addArc(n1, n2); + d.addArc(n2, n3); + d.addArc(n3, n1); + + checkDiEulerIt(d); + checkDiEulerIt(d, n2); + + checkDiEulerIt(g); + checkDiEulerIt(g, n2); + checkEulerIt(g); + checkEulerIt(g, n2); + + check(!eulerian(d), "This graph is not Eulerian"); + check(!eulerian(g), "This graph is not Eulerian"); + } + { + Digraph d; + Graph g(d); + Digraph::Node n1 = d.addNode(); + Digraph::Node n2 = d.addNode(); + Digraph::Node n3 = d.addNode(); + + d.addArc(n1, n2); + d.addArc(n2, n3); + + check(!eulerian(d), "This graph is not Eulerian"); + check(!eulerian(g), "This graph is not Eulerian"); + } + + return 0; +} diff --git a/lemon/test/fractional_matching_test.cc b/lemon/test/fractional_matching_test.cc new file mode 100644 index 0000000..14316a3 --- /dev/null +++ b/lemon/test/fractional_matching_test.cc @@ -0,0 +1,525 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <iostream> +#include <sstream> +#include <vector> +#include <queue> +#include <cstdlib> + +#include <lemon/fractional_matching.h> +#include <lemon/smart_graph.h> +#include <lemon/concepts/graph.h> +#include <lemon/concepts/maps.h> +#include <lemon/lgf_reader.h> +#include <lemon/math.h> + +#include "test_tools.h" + +using namespace std; +using namespace lemon; + +GRAPH_TYPEDEFS(SmartGraph); + + +const int lgfn = 4; +const std::string lgf[lgfn] = { + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "5\n" + "6\n" + "7\n" + "@edges\n" + " label weight\n" + "7 4 0 984\n" + "0 7 1 73\n" + "7 1 2 204\n" + "2 3 3 583\n" + "2 7 4 565\n" + "2 1 5 582\n" + "0 4 6 551\n" + "2 5 7 385\n" + "1 5 8 561\n" + "5 3 9 484\n" + "7 5 10 904\n" + "3 6 11 47\n" + "7 6 12 888\n" + "3 0 13 747\n" + "6 1 14 310\n", + + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "5\n" + "6\n" + "7\n" + "@edges\n" + " label weight\n" + "2 5 0 710\n" + "0 5 1 241\n" + "2 4 2 856\n" + "2 6 3 762\n" + "4 1 4 747\n" + "6 1 5 962\n" + "4 7 6 723\n" + "1 7 7 661\n" + "2 3 8 376\n" + "1 0 9 416\n" + "6 7 10 391\n", + + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "5\n" + "6\n" + "7\n" + "@edges\n" + " label weight\n" + "6 2 0 553\n" + "0 7 1 653\n" + "6 3 2 22\n" + "4 7 3 846\n" + "7 2 4 981\n" + "7 6 5 250\n" + "5 2 6 539\n", + + "@nodes\n" + "label\n" + "0\n" + "@edges\n" + " label weight\n" + "0 0 0 100\n" +}; + +void checkMaxFractionalMatchingCompile() +{ + typedef concepts::Graph Graph; + typedef Graph::Node Node; + typedef Graph::Edge Edge; + + Graph g; + Node n; + Edge e; + + MaxFractionalMatching<Graph> mat_test(g); + const MaxFractionalMatching<Graph>& + const_mat_test = mat_test; + + mat_test.init(); + mat_test.start(); + mat_test.start(true); + mat_test.startPerfect(); + mat_test.startPerfect(true); + mat_test.run(); + mat_test.run(true); + mat_test.runPerfect(); + mat_test.runPerfect(true); + + const_mat_test.matchingSize(); + const_mat_test.matching(e); + const_mat_test.matching(n); + const MaxFractionalMatching<Graph>::MatchingMap& mmap = + const_mat_test.matchingMap(); + e = mmap[n]; + + const_mat_test.barrier(n); +} + +void checkMaxWeightedFractionalMatchingCompile() +{ + typedef concepts::Graph Graph; + typedef Graph::Node Node; + typedef Graph::Edge Edge; + typedef Graph::EdgeMap<int> WeightMap; + + Graph g; + Node n; + Edge e; + WeightMap w(g); + + MaxWeightedFractionalMatching<Graph> mat_test(g, w); + const MaxWeightedFractionalMatching<Graph>& + const_mat_test = mat_test; + + mat_test.init(); + mat_test.start(); + mat_test.run(); + + const_mat_test.matchingWeight(); + const_mat_test.matchingSize(); + const_mat_test.matching(e); + const_mat_test.matching(n); + const MaxWeightedFractionalMatching<Graph>::MatchingMap& mmap = + const_mat_test.matchingMap(); + e = mmap[n]; + + const_mat_test.dualValue(); + const_mat_test.nodeValue(n); +} + +void checkMaxWeightedPerfectFractionalMatchingCompile() +{ + typedef concepts::Graph Graph; + typedef Graph::Node Node; + typedef Graph::Edge Edge; + typedef Graph::EdgeMap<int> WeightMap; + + Graph g; + Node n; + Edge e; + WeightMap w(g); + + MaxWeightedPerfectFractionalMatching<Graph> mat_test(g, w); + const MaxWeightedPerfectFractionalMatching<Graph>& + const_mat_test = mat_test; + + mat_test.init(); + mat_test.start(); + mat_test.run(); + + const_mat_test.matchingWeight(); + const_mat_test.matching(e); + const_mat_test.matching(n); + const MaxWeightedPerfectFractionalMatching<Graph>::MatchingMap& mmap = + const_mat_test.matchingMap(); + e = mmap[n]; + + const_mat_test.dualValue(); + const_mat_test.nodeValue(n); +} + +void checkFractionalMatching(const SmartGraph& graph, + const MaxFractionalMatching<SmartGraph>& mfm, + bool allow_loops = true) { + int pv = 0; + for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { + int indeg = 0; + for (InArcIt a(graph, n); a != INVALID; ++a) { + if (mfm.matching(graph.source(a)) == a) { + ++indeg; + } + } + if (mfm.matching(n) != INVALID) { + check(indeg == 1, "Invalid matching"); + ++pv; + } else { + check(indeg == 0, "Invalid matching"); + } + } + check(pv == mfm.matchingSize(), "Wrong matching size"); + + for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) { + check((e == mfm.matching(graph.u(e)) ? 1 : 0) + + (e == mfm.matching(graph.v(e)) ? 1 : 0) == + mfm.matching(e), "Invalid matching"); + } + + SmartGraph::NodeMap<bool> processed(graph, false); + for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { + if (processed[n]) continue; + processed[n] = true; + if (mfm.matching(n) == INVALID) continue; + int num = 1; + Node v = graph.target(mfm.matching(n)); + while (v != n) { + processed[v] = true; + ++num; + v = graph.target(mfm.matching(v)); + } + check(num == 2 || num % 2 == 1, "Wrong cycle size"); + check(allow_loops || num != 1, "Wrong cycle size"); + } + + int anum = 0, bnum = 0; + SmartGraph::NodeMap<bool> neighbours(graph, false); + for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { + if (!mfm.barrier(n)) continue; + ++anum; + for (SmartGraph::InArcIt a(graph, n); a != INVALID; ++a) { + Node u = graph.source(a); + if (!allow_loops && u == n) continue; + if (!neighbours[u]) { + neighbours[u] = true; + ++bnum; + } + } + } + check(anum - bnum + mfm.matchingSize() == countNodes(graph), + "Wrong barrier"); +} + +void checkPerfectFractionalMatching(const SmartGraph& graph, + const MaxFractionalMatching<SmartGraph>& mfm, + bool perfect, bool allow_loops = true) { + if (perfect) { + for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { + int indeg = 0; + for (InArcIt a(graph, n); a != INVALID; ++a) { + if (mfm.matching(graph.source(a)) == a) { + ++indeg; + } + } + check(mfm.matching(n) != INVALID, "Invalid matching"); + check(indeg == 1, "Invalid matching"); + } + for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) { + check((e == mfm.matching(graph.u(e)) ? 1 : 0) + + (e == mfm.matching(graph.v(e)) ? 1 : 0) == + mfm.matching(e), "Invalid matching"); + } + } else { + int anum = 0, bnum = 0; + SmartGraph::NodeMap<bool> neighbours(graph, false); + for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { + if (!mfm.barrier(n)) continue; + ++anum; + for (SmartGraph::InArcIt a(graph, n); a != INVALID; ++a) { + Node u = graph.source(a); + if (!allow_loops && u == n) continue; + if (!neighbours[u]) { + neighbours[u] = true; + ++bnum; + } + } + } + check(anum - bnum > 0, "Wrong barrier"); + } +} + +void checkWeightedFractionalMatching(const SmartGraph& graph, + const SmartGraph::EdgeMap<int>& weight, + const MaxWeightedFractionalMatching<SmartGraph>& mwfm, + bool allow_loops = true) { + for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) { + if (graph.u(e) == graph.v(e) && !allow_loops) continue; + int rw = mwfm.nodeValue(graph.u(e)) + mwfm.nodeValue(graph.v(e)) + - weight[e] * mwfm.dualScale; + + check(rw >= 0, "Negative reduced weight"); + check(rw == 0 || !mwfm.matching(e), + "Non-zero reduced weight on matching edge"); + } + + int pv = 0; + for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { + int indeg = 0; + for (InArcIt a(graph, n); a != INVALID; ++a) { + if (mwfm.matching(graph.source(a)) == a) { + ++indeg; + } + } + check(indeg <= 1, "Invalid matching"); + if (mwfm.matching(n) != INVALID) { + check(mwfm.nodeValue(n) >= 0, "Invalid node value"); + check(indeg == 1, "Invalid matching"); + pv += weight[mwfm.matching(n)]; + SmartGraph::Node o = graph.target(mwfm.matching(n)); + } else { + check(mwfm.nodeValue(n) == 0, "Invalid matching"); + check(indeg == 0, "Invalid matching"); + } + } + + for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) { + check((e == mwfm.matching(graph.u(e)) ? 1 : 0) + + (e == mwfm.matching(graph.v(e)) ? 1 : 0) == + mwfm.matching(e), "Invalid matching"); + } + + int dv = 0; + for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { + dv += mwfm.nodeValue(n); + } + + check(pv * mwfm.dualScale == dv * 2, "Wrong duality"); + + SmartGraph::NodeMap<bool> processed(graph, false); + for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { + if (processed[n]) continue; + processed[n] = true; + if (mwfm.matching(n) == INVALID) continue; + int num = 1; + Node v = graph.target(mwfm.matching(n)); + while (v != n) { + processed[v] = true; + ++num; + v = graph.target(mwfm.matching(v)); + } + check(num == 2 || num % 2 == 1, "Wrong cycle size"); + check(allow_loops || num != 1, "Wrong cycle size"); + } + + return; +} + +void checkWeightedPerfectFractionalMatching(const SmartGraph& graph, + const SmartGraph::EdgeMap<int>& weight, + const MaxWeightedPerfectFractionalMatching<SmartGraph>& mwpfm, + bool allow_loops = true) { + for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) { + if (graph.u(e) == graph.v(e) && !allow_loops) continue; + int rw = mwpfm.nodeValue(graph.u(e)) + mwpfm.nodeValue(graph.v(e)) + - weight[e] * mwpfm.dualScale; + + check(rw >= 0, "Negative reduced weight"); + check(rw == 0 || !mwpfm.matching(e), + "Non-zero reduced weight on matching edge"); + } + + int pv = 0; + for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { + int indeg = 0; + for (InArcIt a(graph, n); a != INVALID; ++a) { + if (mwpfm.matching(graph.source(a)) == a) { + ++indeg; + } + } + check(mwpfm.matching(n) != INVALID, "Invalid perfect matching"); + check(indeg == 1, "Invalid perfect matching"); + pv += weight[mwpfm.matching(n)]; + SmartGraph::Node o = graph.target(mwpfm.matching(n)); + } + + for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) { + check((e == mwpfm.matching(graph.u(e)) ? 1 : 0) + + (e == mwpfm.matching(graph.v(e)) ? 1 : 0) == + mwpfm.matching(e), "Invalid matching"); + } + + int dv = 0; + for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { + dv += mwpfm.nodeValue(n); + } + + check(pv * mwpfm.dualScale == dv * 2, "Wrong duality"); + + SmartGraph::NodeMap<bool> processed(graph, false); + for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { + if (processed[n]) continue; + processed[n] = true; + if (mwpfm.matching(n) == INVALID) continue; + int num = 1; + Node v = graph.target(mwpfm.matching(n)); + while (v != n) { + processed[v] = true; + ++num; + v = graph.target(mwpfm.matching(v)); + } + check(num == 2 || num % 2 == 1, "Wrong cycle size"); + check(allow_loops || num != 1, "Wrong cycle size"); + } + + return; +} + + +int main() { + + for (int i = 0; i < lgfn; ++i) { + SmartGraph graph; + SmartGraph::EdgeMap<int> weight(graph); + + istringstream lgfs(lgf[i]); + graphReader(graph, lgfs). + edgeMap("weight", weight).run(); + + bool perfect_with_loops; + { + MaxFractionalMatching<SmartGraph> mfm(graph, true); + mfm.run(); + checkFractionalMatching(graph, mfm, true); + perfect_with_loops = mfm.matchingSize() == countNodes(graph); + } + + bool perfect_without_loops; + { + MaxFractionalMatching<SmartGraph> mfm(graph, false); + mfm.run(); + checkFractionalMatching(graph, mfm, false); + perfect_without_loops = mfm.matchingSize() == countNodes(graph); + } + + { + MaxFractionalMatching<SmartGraph> mfm(graph, true); + bool result = mfm.runPerfect(); + checkPerfectFractionalMatching(graph, mfm, result, true); + check(result == perfect_with_loops, "Wrong perfect matching"); + } + + { + MaxFractionalMatching<SmartGraph> mfm(graph, false); + bool result = mfm.runPerfect(); + checkPerfectFractionalMatching(graph, mfm, result, false); + check(result == perfect_without_loops, "Wrong perfect matching"); + } + + { + MaxWeightedFractionalMatching<SmartGraph> mwfm(graph, weight, true); + mwfm.run(); + checkWeightedFractionalMatching(graph, weight, mwfm, true); + } + + { + MaxWeightedFractionalMatching<SmartGraph> mwfm(graph, weight, false); + mwfm.run(); + checkWeightedFractionalMatching(graph, weight, mwfm, false); + } + + { + MaxWeightedPerfectFractionalMatching<SmartGraph> mwpfm(graph, weight, + true); + bool perfect = mwpfm.run(); + check(perfect == (mwpfm.matchingSize() == countNodes(graph)), + "Perfect matching found"); + check(perfect == perfect_with_loops, "Wrong perfect matching"); + + if (perfect) { + checkWeightedPerfectFractionalMatching(graph, weight, mwpfm, true); + } + } + + { + MaxWeightedPerfectFractionalMatching<SmartGraph> mwpfm(graph, weight, + false); + bool perfect = mwpfm.run(); + check(perfect == (mwpfm.matchingSize() == countNodes(graph)), + "Perfect matching found"); + check(perfect == perfect_without_loops, "Wrong perfect matching"); + + if (perfect) { + checkWeightedPerfectFractionalMatching(graph, weight, mwpfm, false); + } + } + + } + + return 0; +} diff --git a/lemon/test/gomory_hu_test.cc b/lemon/test/gomory_hu_test.cc new file mode 100644 index 0000000..c35f2e3 --- /dev/null +++ b/lemon/test/gomory_hu_test.cc @@ -0,0 +1,141 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <iostream> + +#include "test_tools.h" +#include <lemon/smart_graph.h> +#include <lemon/concepts/graph.h> +#include <lemon/concepts/maps.h> +#include <lemon/lgf_reader.h> +#include <lemon/gomory_hu.h> +#include <cstdlib> + +using namespace std; +using namespace lemon; + +typedef SmartGraph Graph; + +char test_lgf[] = + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "@arcs\n" + " label capacity\n" + "0 1 0 1\n" + "1 2 1 1\n" + "2 3 2 1\n" + "0 3 4 5\n" + "0 3 5 10\n" + "0 3 6 7\n" + "4 2 7 1\n" + "@attributes\n" + "source 0\n" + "target 3\n"; + +void checkGomoryHuCompile() +{ + typedef int Value; + typedef concepts::Graph Graph; + + typedef Graph::Node Node; + typedef Graph::Edge Edge; + typedef concepts::ReadMap<Edge, Value> CapMap; + typedef concepts::ReadWriteMap<Node, bool> CutMap; + + Graph g; + Node n; + CapMap cap; + CutMap cut; + Value v; + int d; + + GomoryHu<Graph, CapMap> gh_test(g, cap); + const GomoryHu<Graph, CapMap>& + const_gh_test = gh_test; + + gh_test.run(); + + n = const_gh_test.predNode(n); + v = const_gh_test.predValue(n); + d = const_gh_test.rootDist(n); + v = const_gh_test.minCutValue(n, n); + v = const_gh_test.minCutMap(n, n, cut); +} + +GRAPH_TYPEDEFS(Graph); +typedef Graph::EdgeMap<int> IntEdgeMap; +typedef Graph::NodeMap<bool> BoolNodeMap; + +int cutValue(const Graph& graph, const BoolNodeMap& cut, + const IntEdgeMap& capacity) { + + int sum = 0; + for (EdgeIt e(graph); e != INVALID; ++e) { + Node s = graph.u(e); + Node t = graph.v(e); + + if (cut[s] != cut[t]) { + sum += capacity[e]; + } + } + return sum; +} + + +int main() { + Graph graph; + IntEdgeMap capacity(graph); + + std::istringstream input(test_lgf); + GraphReader<Graph>(graph, input). + edgeMap("capacity", capacity).run(); + + GomoryHu<Graph> ght(graph, capacity); + ght.run(); + + for (NodeIt u(graph); u != INVALID; ++u) { + for (NodeIt v(graph); v != u; ++v) { + Preflow<Graph, IntEdgeMap> pf(graph, capacity, u, v); + pf.runMinCut(); + BoolNodeMap cm(graph); + ght.minCutMap(u, v, cm); + check(pf.flowValue() == ght.minCutValue(u, v), "Wrong cut 1"); + check(cm[u] != cm[v], "Wrong cut 2"); + check(pf.flowValue() == cutValue(graph, cm, capacity), "Wrong cut 3"); + + int sum=0; + for(GomoryHu<Graph>::MinCutEdgeIt a(ght, u, v);a!=INVALID;++a) + sum+=capacity[a]; + check(sum == ght.minCutValue(u, v), "Problem with MinCutEdgeIt"); + + sum=0; + for(GomoryHu<Graph>::MinCutNodeIt n(ght, u, v,true);n!=INVALID;++n) + sum++; + for(GomoryHu<Graph>::MinCutNodeIt n(ght, u, v,false);n!=INVALID;++n) + sum++; + check(sum == countNodes(graph), "Problem with MinCutNodeIt"); + } + } + + return 0; +} diff --git a/lemon/test/graph_copy_test.cc b/lemon/test/graph_copy_test.cc new file mode 100644 index 0000000..1fb2200 --- /dev/null +++ b/lemon/test/graph_copy_test.cc @@ -0,0 +1,215 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2011 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <lemon/smart_graph.h> +#include <lemon/list_graph.h> +#include <lemon/lgf_reader.h> +#include <lemon/error.h> + +#include "test_tools.h" + +using namespace std; +using namespace lemon; + +void digraph_copy_test() { + const int nn = 10; + + // Build a digraph + SmartDigraph from; + SmartDigraph::NodeMap<int> fnm(from); + SmartDigraph::ArcMap<int> fam(from); + SmartDigraph::Node fn = INVALID; + SmartDigraph::Arc fa = INVALID; + + std::vector<SmartDigraph::Node> fnv; + for (int i = 0; i < nn; ++i) { + SmartDigraph::Node node = from.addNode(); + fnv.push_back(node); + fnm[node] = i * i; + if (i == 0) fn = node; + } + + for (int i = 0; i < nn; ++i) { + for (int j = 0; j < nn; ++j) { + SmartDigraph::Arc arc = from.addArc(fnv[i], fnv[j]); + fam[arc] = i + j * j; + if (i == 0 && j == 0) fa = arc; + } + } + + // Test digraph copy + ListDigraph to; + ListDigraph::NodeMap<int> tnm(to); + ListDigraph::ArcMap<int> tam(to); + ListDigraph::Node tn; + ListDigraph::Arc ta; + + SmartDigraph::NodeMap<ListDigraph::Node> nr(from); + SmartDigraph::ArcMap<ListDigraph::Arc> er(from); + + ListDigraph::NodeMap<SmartDigraph::Node> ncr(to); + ListDigraph::ArcMap<SmartDigraph::Arc> ecr(to); + + digraphCopy(from, to). + nodeMap(fnm, tnm).arcMap(fam, tam). + nodeRef(nr).arcRef(er). + nodeCrossRef(ncr).arcCrossRef(ecr). + node(fn, tn).arc(fa, ta).run(); + + check(countNodes(from) == countNodes(to), "Wrong copy."); + check(countArcs(from) == countArcs(to), "Wrong copy."); + + for (SmartDigraph::NodeIt it(from); it != INVALID; ++it) { + check(ncr[nr[it]] == it, "Wrong copy."); + check(fnm[it] == tnm[nr[it]], "Wrong copy."); + } + + for (SmartDigraph::ArcIt it(from); it != INVALID; ++it) { + check(ecr[er[it]] == it, "Wrong copy."); + check(fam[it] == tam[er[it]], "Wrong copy."); + check(nr[from.source(it)] == to.source(er[it]), "Wrong copy."); + check(nr[from.target(it)] == to.target(er[it]), "Wrong copy."); + } + + for (ListDigraph::NodeIt it(to); it != INVALID; ++it) { + check(nr[ncr[it]] == it, "Wrong copy."); + } + + for (ListDigraph::ArcIt it(to); it != INVALID; ++it) { + check(er[ecr[it]] == it, "Wrong copy."); + } + check(tn == nr[fn], "Wrong copy."); + check(ta == er[fa], "Wrong copy."); + + // Test repeated copy + digraphCopy(from, to).run(); + + check(countNodes(from) == countNodes(to), "Wrong copy."); + check(countArcs(from) == countArcs(to), "Wrong copy."); +} + +void graph_copy_test() { + const int nn = 10; + + // Build a graph + SmartGraph from; + SmartGraph::NodeMap<int> fnm(from); + SmartGraph::ArcMap<int> fam(from); + SmartGraph::EdgeMap<int> fem(from); + SmartGraph::Node fn = INVALID; + SmartGraph::Arc fa = INVALID; + SmartGraph::Edge fe = INVALID; + + std::vector<SmartGraph::Node> fnv; + for (int i = 0; i < nn; ++i) { + SmartGraph::Node node = from.addNode(); + fnv.push_back(node); + fnm[node] = i * i; + if (i == 0) fn = node; + } + + for (int i = 0; i < nn; ++i) { + for (int j = 0; j < nn; ++j) { + SmartGraph::Edge edge = from.addEdge(fnv[i], fnv[j]); + fem[edge] = i * i + j * j; + fam[from.direct(edge, true)] = i + j * j; + fam[from.direct(edge, false)] = i * i + j; + if (i == 0 && j == 0) fa = from.direct(edge, true); + if (i == 0 && j == 0) fe = edge; + } + } + + // Test graph copy + ListGraph to; + ListGraph::NodeMap<int> tnm(to); + ListGraph::ArcMap<int> tam(to); + ListGraph::EdgeMap<int> tem(to); + ListGraph::Node tn; + ListGraph::Arc ta; + ListGraph::Edge te; + + SmartGraph::NodeMap<ListGraph::Node> nr(from); + SmartGraph::ArcMap<ListGraph::Arc> ar(from); + SmartGraph::EdgeMap<ListGraph::Edge> er(from); + + ListGraph::NodeMap<SmartGraph::Node> ncr(to); + ListGraph::ArcMap<SmartGraph::Arc> acr(to); + ListGraph::EdgeMap<SmartGraph::Edge> ecr(to); + + graphCopy(from, to). + nodeMap(fnm, tnm).arcMap(fam, tam).edgeMap(fem, tem). + nodeRef(nr).arcRef(ar).edgeRef(er). + nodeCrossRef(ncr).arcCrossRef(acr).edgeCrossRef(ecr). + node(fn, tn).arc(fa, ta).edge(fe, te).run(); + + check(countNodes(from) == countNodes(to), "Wrong copy."); + check(countEdges(from) == countEdges(to), "Wrong copy."); + check(countArcs(from) == countArcs(to), "Wrong copy."); + + for (SmartGraph::NodeIt it(from); it != INVALID; ++it) { + check(ncr[nr[it]] == it, "Wrong copy."); + check(fnm[it] == tnm[nr[it]], "Wrong copy."); + } + + for (SmartGraph::ArcIt it(from); it != INVALID; ++it) { + check(acr[ar[it]] == it, "Wrong copy."); + check(fam[it] == tam[ar[it]], "Wrong copy."); + check(nr[from.source(it)] == to.source(ar[it]), "Wrong copy."); + check(nr[from.target(it)] == to.target(ar[it]), "Wrong copy."); + } + + for (SmartGraph::EdgeIt it(from); it != INVALID; ++it) { + check(ecr[er[it]] == it, "Wrong copy."); + check(fem[it] == tem[er[it]], "Wrong copy."); + check(nr[from.u(it)] == to.u(er[it]) || nr[from.u(it)] == to.v(er[it]), + "Wrong copy."); + check(nr[from.v(it)] == to.u(er[it]) || nr[from.v(it)] == to.v(er[it]), + "Wrong copy."); + check((from.u(it) != from.v(it)) == (to.u(er[it]) != to.v(er[it])), + "Wrong copy."); + } + + for (ListGraph::NodeIt it(to); it != INVALID; ++it) { + check(nr[ncr[it]] == it, "Wrong copy."); + } + + for (ListGraph::ArcIt it(to); it != INVALID; ++it) { + check(ar[acr[it]] == it, "Wrong copy."); + } + for (ListGraph::EdgeIt it(to); it != INVALID; ++it) { + check(er[ecr[it]] == it, "Wrong copy."); + } + check(tn == nr[fn], "Wrong copy."); + check(ta == ar[fa], "Wrong copy."); + check(te == er[fe], "Wrong copy."); + + // Test repeated copy + graphCopy(from, to).run(); + + check(countNodes(from) == countNodes(to), "Wrong copy."); + check(countEdges(from) == countEdges(to), "Wrong copy."); + check(countArcs(from) == countArcs(to), "Wrong copy."); +} + + +int main() { + digraph_copy_test(); + graph_copy_test(); + + return 0; +} diff --git a/lemon/test/graph_test.cc b/lemon/test/graph_test.cc new file mode 100644 index 0000000..e383f9d --- /dev/null +++ b/lemon/test/graph_test.cc @@ -0,0 +1,597 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <lemon/concepts/graph.h> +#include <lemon/list_graph.h> +#include <lemon/smart_graph.h> +#include <lemon/full_graph.h> +#include <lemon/grid_graph.h> +#include <lemon/hypercube_graph.h> + +#include "test_tools.h" +#include "graph_test.h" + +using namespace lemon; +using namespace lemon::concepts; + +template <class Graph> +void checkGraphBuild() { + TEMPLATE_GRAPH_TYPEDEFS(Graph); + + Graph G; + checkGraphNodeList(G, 0); + checkGraphEdgeList(G, 0); + checkGraphArcList(G, 0); + + G.reserveNode(3); + G.reserveEdge(3); + + Node + n1 = G.addNode(), + n2 = G.addNode(), + n3 = G.addNode(); + checkGraphNodeList(G, 3); + checkGraphEdgeList(G, 0); + checkGraphArcList(G, 0); + + Edge e1 = G.addEdge(n1, n2); + check((G.u(e1) == n1 && G.v(e1) == n2) || (G.u(e1) == n2 && G.v(e1) == n1), + "Wrong edge"); + + checkGraphNodeList(G, 3); + checkGraphEdgeList(G, 1); + checkGraphArcList(G, 2); + + checkGraphIncEdgeArcLists(G, n1, 1); + checkGraphIncEdgeArcLists(G, n2, 1); + checkGraphIncEdgeArcLists(G, n3, 0); + + checkGraphConEdgeList(G, 1); + checkGraphConArcList(G, 2); + + Edge e2 = G.addEdge(n2, n1), + e3 = G.addEdge(n2, n3); + + checkGraphNodeList(G, 3); + checkGraphEdgeList(G, 3); + checkGraphArcList(G, 6); + + checkGraphIncEdgeArcLists(G, n1, 2); + checkGraphIncEdgeArcLists(G, n2, 3); + checkGraphIncEdgeArcLists(G, n3, 1); + + checkGraphConEdgeList(G, 3); + checkGraphConArcList(G, 6); + + checkArcDirections(G); + + checkNodeIds(G); + checkArcIds(G); + checkEdgeIds(G); + checkGraphNodeMap(G); + checkGraphArcMap(G); + checkGraphEdgeMap(G); +} + +template <class Graph> +void checkGraphAlter() { + TEMPLATE_GRAPH_TYPEDEFS(Graph); + + Graph G; + Node n1 = G.addNode(), n2 = G.addNode(), + n3 = G.addNode(), n4 = G.addNode(); + Edge e1 = G.addEdge(n1, n2), e2 = G.addEdge(n2, n1), + e3 = G.addEdge(n2, n3), e4 = G.addEdge(n1, n4), + e5 = G.addEdge(n4, n3); + + checkGraphNodeList(G, 4); + checkGraphEdgeList(G, 5); + checkGraphArcList(G, 10); + + // Check changeU() and changeV() + if (G.u(e2) == n2) { + G.changeU(e2, n3); + } else { + G.changeV(e2, n3); + } + + checkGraphNodeList(G, 4); + checkGraphEdgeList(G, 5); + checkGraphArcList(G, 10); + + checkGraphIncEdgeArcLists(G, n1, 3); + checkGraphIncEdgeArcLists(G, n2, 2); + checkGraphIncEdgeArcLists(G, n3, 3); + checkGraphIncEdgeArcLists(G, n4, 2); + + checkGraphConEdgeList(G, 5); + checkGraphConArcList(G, 10); + + if (G.u(e2) == n1) { + G.changeU(e2, n2); + } else { + G.changeV(e2, n2); + } + + checkGraphNodeList(G, 4); + checkGraphEdgeList(G, 5); + checkGraphArcList(G, 10); + + checkGraphIncEdgeArcLists(G, n1, 2); + checkGraphIncEdgeArcLists(G, n2, 3); + checkGraphIncEdgeArcLists(G, n3, 3); + checkGraphIncEdgeArcLists(G, n4, 2); + + checkGraphConEdgeList(G, 5); + checkGraphConArcList(G, 10); + + // Check contract() + G.contract(n1, n4, false); + + checkGraphNodeList(G, 3); + checkGraphEdgeList(G, 5); + checkGraphArcList(G, 10); + + checkGraphIncEdgeArcLists(G, n1, 4); + checkGraphIncEdgeArcLists(G, n2, 3); + checkGraphIncEdgeArcLists(G, n3, 3); + + checkGraphConEdgeList(G, 5); + checkGraphConArcList(G, 10); + + G.contract(n2, n3); + + checkGraphNodeList(G, 2); + checkGraphEdgeList(G, 3); + checkGraphArcList(G, 6); + + checkGraphIncEdgeArcLists(G, n1, 4); + checkGraphIncEdgeArcLists(G, n2, 2); + + checkGraphConEdgeList(G, 3); + checkGraphConArcList(G, 6); +} + +template <class Graph> +void checkGraphErase() { + TEMPLATE_GRAPH_TYPEDEFS(Graph); + + Graph G; + Node n1 = G.addNode(), n2 = G.addNode(), + n3 = G.addNode(), n4 = G.addNode(); + Edge e1 = G.addEdge(n1, n2), e2 = G.addEdge(n2, n1), + e3 = G.addEdge(n2, n3), e4 = G.addEdge(n1, n4), + e5 = G.addEdge(n4, n3); + + // Check edge deletion + G.erase(e2); + + checkGraphNodeList(G, 4); + checkGraphEdgeList(G, 4); + checkGraphArcList(G, 8); + + checkGraphIncEdgeArcLists(G, n1, 2); + checkGraphIncEdgeArcLists(G, n2, 2); + checkGraphIncEdgeArcLists(G, n3, 2); + checkGraphIncEdgeArcLists(G, n4, 2); + + checkGraphConEdgeList(G, 4); + checkGraphConArcList(G, 8); + + // Check node deletion + G.erase(n3); + + checkGraphNodeList(G, 3); + checkGraphEdgeList(G, 2); + checkGraphArcList(G, 4); + + checkGraphIncEdgeArcLists(G, n1, 2); + checkGraphIncEdgeArcLists(G, n2, 1); + checkGraphIncEdgeArcLists(G, n4, 1); + + checkGraphConEdgeList(G, 2); + checkGraphConArcList(G, 4); +} + + +template <class Graph> +void checkGraphSnapshot() { + TEMPLATE_GRAPH_TYPEDEFS(Graph); + + Graph G; + Node n1 = G.addNode(), n2 = G.addNode(), n3 = G.addNode(); + Edge e1 = G.addEdge(n1, n2), e2 = G.addEdge(n2, n1), + e3 = G.addEdge(n2, n3); + + checkGraphNodeList(G, 3); + checkGraphEdgeList(G, 3); + checkGraphArcList(G, 6); + + typename Graph::Snapshot snapshot(G); + + Node n = G.addNode(); + G.addEdge(n3, n); + G.addEdge(n, n3); + G.addEdge(n3, n2); + + checkGraphNodeList(G, 4); + checkGraphEdgeList(G, 6); + checkGraphArcList(G, 12); + + snapshot.restore(); + + checkGraphNodeList(G, 3); + checkGraphEdgeList(G, 3); + checkGraphArcList(G, 6); + + checkGraphIncEdgeArcLists(G, n1, 2); + checkGraphIncEdgeArcLists(G, n2, 3); + checkGraphIncEdgeArcLists(G, n3, 1); + + checkGraphConEdgeList(G, 3); + checkGraphConArcList(G, 6); + + checkNodeIds(G); + checkEdgeIds(G); + checkArcIds(G); + checkGraphNodeMap(G); + checkGraphEdgeMap(G); + checkGraphArcMap(G); + + G.addNode(); + snapshot.save(G); + + G.addEdge(G.addNode(), G.addNode()); + + snapshot.restore(); + snapshot.save(G); + + checkGraphNodeList(G, 4); + checkGraphEdgeList(G, 3); + checkGraphArcList(G, 6); + + G.addEdge(G.addNode(), G.addNode()); + + snapshot.restore(); + + checkGraphNodeList(G, 4); + checkGraphEdgeList(G, 3); + checkGraphArcList(G, 6); +} + +void checkFullGraph(int num) { + typedef FullGraph Graph; + GRAPH_TYPEDEFS(Graph); + + Graph G(num); + check(G.nodeNum() == num && G.edgeNum() == num * (num - 1) / 2, + "Wrong size"); + + G.resize(num); + check(G.nodeNum() == num && G.edgeNum() == num * (num - 1) / 2, + "Wrong size"); + + checkGraphNodeList(G, num); + checkGraphEdgeList(G, num * (num - 1) / 2); + + for (NodeIt n(G); n != INVALID; ++n) { + checkGraphOutArcList(G, n, num - 1); + checkGraphInArcList(G, n, num - 1); + checkGraphIncEdgeList(G, n, num - 1); + } + + checkGraphConArcList(G, num * (num - 1)); + checkGraphConEdgeList(G, num * (num - 1) / 2); + + checkArcDirections(G); + + checkNodeIds(G); + checkArcIds(G); + checkEdgeIds(G); + checkGraphNodeMap(G); + checkGraphArcMap(G); + checkGraphEdgeMap(G); + + + for (int i = 0; i < G.nodeNum(); ++i) { + check(G.index(G(i)) == i, "Wrong index"); + } + + for (NodeIt u(G); u != INVALID; ++u) { + for (NodeIt v(G); v != INVALID; ++v) { + Edge e = G.edge(u, v); + Arc a = G.arc(u, v); + if (u == v) { + check(e == INVALID, "Wrong edge lookup"); + check(a == INVALID, "Wrong arc lookup"); + } else { + check((G.u(e) == u && G.v(e) == v) || + (G.u(e) == v && G.v(e) == u), "Wrong edge lookup"); + check(G.source(a) == u && G.target(a) == v, "Wrong arc lookup"); + } + } + } +} + +void checkConcepts() { + { // Checking graph components + checkConcept<BaseGraphComponent, BaseGraphComponent >(); + + checkConcept<IDableGraphComponent<>, + IDableGraphComponent<> >(); + + checkConcept<IterableGraphComponent<>, + IterableGraphComponent<> >(); + + checkConcept<MappableGraphComponent<>, + MappableGraphComponent<> >(); + } + { // Checking skeleton graph + checkConcept<Graph, Graph>(); + } + { // Checking ListGraph + checkConcept<Graph, ListGraph>(); + checkConcept<AlterableGraphComponent<>, ListGraph>(); + checkConcept<ExtendableGraphComponent<>, ListGraph>(); + checkConcept<ClearableGraphComponent<>, ListGraph>(); + checkConcept<ErasableGraphComponent<>, ListGraph>(); + } + { // Checking SmartGraph + checkConcept<Graph, SmartGraph>(); + checkConcept<AlterableGraphComponent<>, SmartGraph>(); + checkConcept<ExtendableGraphComponent<>, SmartGraph>(); + checkConcept<ClearableGraphComponent<>, SmartGraph>(); + } + { // Checking FullGraph + checkConcept<Graph, FullGraph>(); + } + { // Checking GridGraph + checkConcept<Graph, GridGraph>(); + } + { // Checking HypercubeGraph + checkConcept<Graph, HypercubeGraph>(); + } +} + +template <typename Graph> +void checkGraphValidity() { + TEMPLATE_GRAPH_TYPEDEFS(Graph); + Graph g; + + Node + n1 = g.addNode(), + n2 = g.addNode(), + n3 = g.addNode(); + + Edge + e1 = g.addEdge(n1, n2), + e2 = g.addEdge(n2, n3); + + check(g.valid(n1), "Wrong validity check"); + check(g.valid(e1), "Wrong validity check"); + check(g.valid(g.direct(e1, true)), "Wrong validity check"); + + check(!g.valid(g.nodeFromId(-1)), "Wrong validity check"); + check(!g.valid(g.edgeFromId(-1)), "Wrong validity check"); + check(!g.valid(g.arcFromId(-1)), "Wrong validity check"); +} + +template <typename Graph> +void checkGraphValidityErase() { + TEMPLATE_GRAPH_TYPEDEFS(Graph); + Graph g; + + Node + n1 = g.addNode(), + n2 = g.addNode(), + n3 = g.addNode(); + + Edge + e1 = g.addEdge(n1, n2), + e2 = g.addEdge(n2, n3); + + check(g.valid(n1), "Wrong validity check"); + check(g.valid(e1), "Wrong validity check"); + check(g.valid(g.direct(e1, true)), "Wrong validity check"); + + g.erase(n1); + + check(!g.valid(n1), "Wrong validity check"); + check(g.valid(n2), "Wrong validity check"); + check(g.valid(n3), "Wrong validity check"); + check(!g.valid(e1), "Wrong validity check"); + check(g.valid(e2), "Wrong validity check"); + + check(!g.valid(g.nodeFromId(-1)), "Wrong validity check"); + check(!g.valid(g.edgeFromId(-1)), "Wrong validity check"); + check(!g.valid(g.arcFromId(-1)), "Wrong validity check"); +} + +void checkGridGraph(int width, int height) { + typedef GridGraph Graph; + GRAPH_TYPEDEFS(Graph); + Graph G(width, height); + + check(G.width() == width, "Wrong column number"); + check(G.height() == height, "Wrong row number"); + + G.resize(width, height); + check(G.width() == width, "Wrong column number"); + check(G.height() == height, "Wrong row number"); + + for (int i = 0; i < width; ++i) { + for (int j = 0; j < height; ++j) { + check(G.col(G(i, j)) == i, "Wrong column"); + check(G.row(G(i, j)) == j, "Wrong row"); + check(G.pos(G(i, j)).x == i, "Wrong column"); + check(G.pos(G(i, j)).y == j, "Wrong row"); + } + } + + for (int j = 0; j < height; ++j) { + for (int i = 0; i < width - 1; ++i) { + check(G.source(G.right(G(i, j))) == G(i, j), "Wrong right"); + check(G.target(G.right(G(i, j))) == G(i + 1, j), "Wrong right"); + } + check(G.right(G(width - 1, j)) == INVALID, "Wrong right"); + } + + for (int j = 0; j < height; ++j) { + for (int i = 1; i < width; ++i) { + check(G.source(G.left(G(i, j))) == G(i, j), "Wrong left"); + check(G.target(G.left(G(i, j))) == G(i - 1, j), "Wrong left"); + } + check(G.left(G(0, j)) == INVALID, "Wrong left"); + } + + for (int i = 0; i < width; ++i) { + for (int j = 0; j < height - 1; ++j) { + check(G.source(G.up(G(i, j))) == G(i, j), "Wrong up"); + check(G.target(G.up(G(i, j))) == G(i, j + 1), "Wrong up"); + } + check(G.up(G(i, height - 1)) == INVALID, "Wrong up"); + } + + for (int i = 0; i < width; ++i) { + for (int j = 1; j < height; ++j) { + check(G.source(G.down(G(i, j))) == G(i, j), "Wrong down"); + check(G.target(G.down(G(i, j))) == G(i, j - 1), "Wrong down"); + } + check(G.down(G(i, 0)) == INVALID, "Wrong down"); + } + + checkGraphNodeList(G, width * height); + checkGraphEdgeList(G, width * (height - 1) + (width - 1) * height); + checkGraphArcList(G, 2 * (width * (height - 1) + (width - 1) * height)); + + for (NodeIt n(G); n != INVALID; ++n) { + int nb = 4; + if (G.col(n) == 0) --nb; + if (G.col(n) == width - 1) --nb; + if (G.row(n) == 0) --nb; + if (G.row(n) == height - 1) --nb; + + checkGraphOutArcList(G, n, nb); + checkGraphInArcList(G, n, nb); + checkGraphIncEdgeList(G, n, nb); + } + + checkArcDirections(G); + + checkGraphConArcList(G, 2 * (width * (height - 1) + (width - 1) * height)); + checkGraphConEdgeList(G, width * (height - 1) + (width - 1) * height); + + checkNodeIds(G); + checkArcIds(G); + checkEdgeIds(G); + checkGraphNodeMap(G); + checkGraphArcMap(G); + checkGraphEdgeMap(G); + +} + +void checkHypercubeGraph(int dim) { + GRAPH_TYPEDEFS(HypercubeGraph); + + HypercubeGraph G(dim); + check(G.dimension() == dim, "Wrong dimension"); + + G.resize(dim); + check(G.dimension() == dim, "Wrong dimension"); + + checkGraphNodeList(G, 1 << dim); + checkGraphEdgeList(G, dim * (1 << (dim-1))); + checkGraphArcList(G, dim * (1 << dim)); + + Node n = G.nodeFromId(dim); + + for (NodeIt n(G); n != INVALID; ++n) { + checkGraphIncEdgeList(G, n, dim); + for (IncEdgeIt e(G, n); e != INVALID; ++e) { + check( (G.u(e) == n && + G.id(G.v(e)) == (G.id(n) ^ (1 << G.dimension(e)))) || + (G.v(e) == n && + G.id(G.u(e)) == (G.id(n) ^ (1 << G.dimension(e)))), + "Wrong edge or wrong dimension"); + } + + checkGraphOutArcList(G, n, dim); + for (OutArcIt a(G, n); a != INVALID; ++a) { + check(G.source(a) == n && + G.id(G.target(a)) == (G.id(n) ^ (1 << G.dimension(a))), + "Wrong arc or wrong dimension"); + } + + checkGraphInArcList(G, n, dim); + for (InArcIt a(G, n); a != INVALID; ++a) { + check(G.target(a) == n && + G.id(G.source(a)) == (G.id(n) ^ (1 << G.dimension(a))), + "Wrong arc or wrong dimension"); + } + } + + checkGraphConArcList(G, (1 << dim) * dim); + checkGraphConEdgeList(G, dim * (1 << (dim-1))); + + checkArcDirections(G); + + checkNodeIds(G); + checkArcIds(G); + checkEdgeIds(G); + checkGraphNodeMap(G); + checkGraphArcMap(G); + checkGraphEdgeMap(G); +} + +void checkGraphs() { + { // Checking ListGraph + checkGraphBuild<ListGraph>(); + checkGraphAlter<ListGraph>(); + checkGraphErase<ListGraph>(); + checkGraphSnapshot<ListGraph>(); + checkGraphValidityErase<ListGraph>(); + } + { // Checking SmartGraph + checkGraphBuild<SmartGraph>(); + checkGraphSnapshot<SmartGraph>(); + checkGraphValidity<SmartGraph>(); + } + { // Checking FullGraph + checkFullGraph(7); + checkFullGraph(8); + } + { // Checking GridGraph + checkGridGraph(5, 8); + checkGridGraph(8, 5); + checkGridGraph(5, 5); + checkGridGraph(0, 0); + checkGridGraph(1, 1); + } + { // Checking HypercubeGraph + checkHypercubeGraph(1); + checkHypercubeGraph(2); + checkHypercubeGraph(3); + checkHypercubeGraph(4); + } +} + +int main() { + checkConcepts(); + checkGraphs(); + return 0; +} diff --git a/lemon/test/graph_test.h b/lemon/test/graph_test.h new file mode 100644 index 0000000..352319a --- /dev/null +++ b/lemon/test/graph_test.h @@ -0,0 +1,293 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2009 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#ifndef LEMON_TEST_GRAPH_TEST_H +#define LEMON_TEST_GRAPH_TEST_H + +#include <set> + +#include <lemon/core.h> +#include <lemon/maps.h> + +#include "test_tools.h" + +namespace lemon { + + template<class Graph> + void checkGraphNodeList(const Graph &G, int cnt) + { + typename Graph::NodeIt n(G); + for(int i=0;i<cnt;i++) { + check(n!=INVALID,"Wrong Node list linking."); + ++n; + } + check(n==INVALID,"Wrong Node list linking."); + check(countNodes(G)==cnt,"Wrong Node number."); + } + + template<class Graph> + void checkGraphArcList(const Graph &G, int cnt) + { + typename Graph::ArcIt e(G); + for(int i=0;i<cnt;i++) { + check(e!=INVALID,"Wrong Arc list linking."); + check(G.oppositeNode(G.source(e), e) == G.target(e), + "Wrong opposite node"); + check(G.oppositeNode(G.target(e), e) == G.source(e), + "Wrong opposite node"); + ++e; + } + check(e==INVALID,"Wrong Arc list linking."); + check(countArcs(G)==cnt,"Wrong Arc number."); + } + + template<class Graph> + void checkGraphOutArcList(const Graph &G, typename Graph::Node n, int cnt) + { + typename Graph::OutArcIt e(G,n); + for(int i=0;i<cnt;i++) { + check(e!=INVALID,"Wrong OutArc list linking."); + check(n==G.source(e),"Wrong OutArc list linking."); + check(n==G.baseNode(e),"Wrong OutArc list linking."); + check(G.target(e)==G.runningNode(e),"Wrong OutArc list linking."); + ++e; + } + check(e==INVALID,"Wrong OutArc list linking."); + check(countOutArcs(G,n)==cnt,"Wrong OutArc number."); + } + + template<class Graph> + void checkGraphInArcList(const Graph &G, typename Graph::Node n, int cnt) + { + typename Graph::InArcIt e(G,n); + for(int i=0;i<cnt;i++) { + check(e!=INVALID,"Wrong InArc list linking."); + check(n==G.target(e),"Wrong InArc list linking."); + check(n==G.baseNode(e),"Wrong OutArc list linking."); + check(G.source(e)==G.runningNode(e),"Wrong OutArc list linking."); + ++e; + } + check(e==INVALID,"Wrong InArc list linking."); + check(countInArcs(G,n)==cnt,"Wrong InArc number."); + } + + template<class Graph> + void checkGraphEdgeList(const Graph &G, int cnt) + { + typename Graph::EdgeIt e(G); + for(int i=0;i<cnt;i++) { + check(e!=INVALID,"Wrong Edge list linking."); + check(G.oppositeNode(G.u(e), e) == G.v(e), "Wrong opposite node"); + check(G.oppositeNode(G.v(e), e) == G.u(e), "Wrong opposite node"); + ++e; + } + check(e==INVALID,"Wrong Edge list linking."); + check(countEdges(G)==cnt,"Wrong Edge number."); + } + + template<class Graph> + void checkGraphIncEdgeList(const Graph &G, typename Graph::Node n, int cnt) + { + typename Graph::IncEdgeIt e(G,n); + for(int i=0;i<cnt;i++) { + check(e!=INVALID,"Wrong IncEdge list linking."); + check(n==G.u(e) || n==G.v(e),"Wrong IncEdge list linking."); + check(n==G.baseNode(e),"Wrong OutArc list linking."); + check(G.u(e)==G.runningNode(e) || G.v(e)==G.runningNode(e), + "Wrong OutArc list linking."); + ++e; + } + check(e==INVALID,"Wrong IncEdge list linking."); + check(countIncEdges(G,n)==cnt,"Wrong IncEdge number."); + } + + template <class Graph> + void checkGraphIncEdgeArcLists(const Graph &G, typename Graph::Node n, + int cnt) + { + checkGraphIncEdgeList(G, n, cnt); + checkGraphOutArcList(G, n, cnt); + checkGraphInArcList(G, n, cnt); + } + + template <class Graph> + void checkGraphConArcList(const Graph &G, int cnt) { + int i = 0; + for (typename Graph::NodeIt u(G); u != INVALID; ++u) { + for (typename Graph::NodeIt v(G); v != INVALID; ++v) { + for (ConArcIt<Graph> a(G, u, v); a != INVALID; ++a) { + check(G.source(a) == u, "Wrong iterator."); + check(G.target(a) == v, "Wrong iterator."); + ++i; + } + } + } + check(cnt == i, "Wrong iterator."); + } + + template <class Graph> + void checkGraphConEdgeList(const Graph &G, int cnt) { + int i = 0; + for (typename Graph::NodeIt u(G); u != INVALID; ++u) { + for (typename Graph::NodeIt v(G); v != INVALID; ++v) { + for (ConEdgeIt<Graph> e(G, u, v); e != INVALID; ++e) { + check((G.u(e) == u && G.v(e) == v) || + (G.u(e) == v && G.v(e) == u), "Wrong iterator."); + i += u == v ? 2 : 1; + } + } + } + check(2 * cnt == i, "Wrong iterator."); + } + + template <typename Graph> + void checkArcDirections(const Graph& G) { + for (typename Graph::ArcIt a(G); a != INVALID; ++a) { + check(G.source(a) == G.target(G.oppositeArc(a)), "Wrong direction"); + check(G.target(a) == G.source(G.oppositeArc(a)), "Wrong direction"); + check(G.direct(a, G.direction(a)) == a, "Wrong direction"); + } + } + + template <typename Graph> + void checkNodeIds(const Graph& G) { + std::set<int> values; + for (typename Graph::NodeIt n(G); n != INVALID; ++n) { + check(G.nodeFromId(G.id(n)) == n, "Wrong id"); + check(values.find(G.id(n)) == values.end(), "Wrong id"); + check(G.id(n) <= G.maxNodeId(), "Wrong maximum id"); + values.insert(G.id(n)); + } + } + + template <typename Graph> + void checkArcIds(const Graph& G) { + std::set<int> values; + for (typename Graph::ArcIt a(G); a != INVALID; ++a) { + check(G.arcFromId(G.id(a)) == a, "Wrong id"); + check(values.find(G.id(a)) == values.end(), "Wrong id"); + check(G.id(a) <= G.maxArcId(), "Wrong maximum id"); + values.insert(G.id(a)); + } + } + + template <typename Graph> + void checkEdgeIds(const Graph& G) { + std::set<int> values; + for (typename Graph::EdgeIt e(G); e != INVALID; ++e) { + check(G.edgeFromId(G.id(e)) == e, "Wrong id"); + check(values.find(G.id(e)) == values.end(), "Wrong id"); + check(G.id(e) <= G.maxEdgeId(), "Wrong maximum id"); + values.insert(G.id(e)); + } + } + + template <typename Graph> + void checkGraphNodeMap(const Graph& G) { + typedef typename Graph::Node Node; + typedef typename Graph::NodeIt NodeIt; + + typedef typename Graph::template NodeMap<int> IntNodeMap; + IntNodeMap map(G, 42); + for (NodeIt it(G); it != INVALID; ++it) { + check(map[it] == 42, "Wrong map constructor."); + } + int s = 0; + for (NodeIt it(G); it != INVALID; ++it) { + map[it] = 0; + check(map[it] == 0, "Wrong operator[]."); + map.set(it, s); + check(map[it] == s, "Wrong set."); + ++s; + } + s = s * (s - 1) / 2; + for (NodeIt it(G); it != INVALID; ++it) { + s -= map[it]; + } + check(s == 0, "Wrong sum."); + + // map = constMap<Node>(12); + // for (NodeIt it(G); it != INVALID; ++it) { + // check(map[it] == 12, "Wrong operator[]."); + // } + } + + template <typename Graph> + void checkGraphArcMap(const Graph& G) { + typedef typename Graph::Arc Arc; + typedef typename Graph::ArcIt ArcIt; + + typedef typename Graph::template ArcMap<int> IntArcMap; + IntArcMap map(G, 42); + for (ArcIt it(G); it != INVALID; ++it) { + check(map[it] == 42, "Wrong map constructor."); + } + int s = 0; + for (ArcIt it(G); it != INVALID; ++it) { + map[it] = 0; + check(map[it] == 0, "Wrong operator[]."); + map.set(it, s); + check(map[it] == s, "Wrong set."); + ++s; + } + s = s * (s - 1) / 2; + for (ArcIt it(G); it != INVALID; ++it) { + s -= map[it]; + } + check(s == 0, "Wrong sum."); + + // map = constMap<Arc>(12); + // for (ArcIt it(G); it != INVALID; ++it) { + // check(map[it] == 12, "Wrong operator[]."); + // } + } + + template <typename Graph> + void checkGraphEdgeMap(const Graph& G) { + typedef typename Graph::Edge Edge; + typedef typename Graph::EdgeIt EdgeIt; + + typedef typename Graph::template EdgeMap<int> IntEdgeMap; + IntEdgeMap map(G, 42); + for (EdgeIt it(G); it != INVALID; ++it) { + check(map[it] == 42, "Wrong map constructor."); + } + int s = 0; + for (EdgeIt it(G); it != INVALID; ++it) { + map[it] = 0; + check(map[it] == 0, "Wrong operator[]."); + map.set(it, s); + check(map[it] == s, "Wrong set."); + ++s; + } + s = s * (s - 1) / 2; + for (EdgeIt it(G); it != INVALID; ++it) { + s -= map[it]; + } + check(s == 0, "Wrong sum."); + + // map = constMap<Edge>(12); + // for (EdgeIt it(G); it != INVALID; ++it) { + // check(map[it] == 12, "Wrong operator[]."); + // } + } + + +} //namespace lemon + +#endif diff --git a/lemon/test/graph_utils_test.cc b/lemon/test/graph_utils_test.cc new file mode 100644 index 0000000..19a934a --- /dev/null +++ b/lemon/test/graph_utils_test.cc @@ -0,0 +1,217 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2009 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <cstdlib> +#include <ctime> + +#include <lemon/random.h> +#include <lemon/list_graph.h> +#include <lemon/smart_graph.h> +#include <lemon/maps.h> + +#include "graph_test.h" +#include "test_tools.h" + +using namespace lemon; + +template <typename Digraph> +void checkFindArcs() { + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + + { + Digraph digraph; + for (int i = 0; i < 10; ++i) { + digraph.addNode(); + } + RangeIdMap<Digraph, Node> nodes(digraph); + typename RangeIdMap<Digraph, Node>::InverseMap invNodes(nodes); + for (int i = 0; i < 100; ++i) { + int src = rnd[invNodes.size()]; + int trg = rnd[invNodes.size()]; + digraph.addArc(invNodes[src], invNodes[trg]); + } + typename Digraph::template ArcMap<bool> found(digraph, false); + RangeIdMap<Digraph, Arc> arcs(digraph); + for (NodeIt src(digraph); src != INVALID; ++src) { + for (NodeIt trg(digraph); trg != INVALID; ++trg) { + for (ConArcIt<Digraph> con(digraph, src, trg); con != INVALID; ++con) { + check(digraph.source(con) == src, "Wrong source."); + check(digraph.target(con) == trg, "Wrong target."); + check(found[con] == false, "The arc found already."); + found[con] = true; + } + } + } + for (ArcIt it(digraph); it != INVALID; ++it) { + check(found[it] == true, "The arc is not found."); + } + } + + { + int num = 5; + Digraph fg; + std::vector<Node> nodes; + for (int i = 0; i < num; ++i) { + nodes.push_back(fg.addNode()); + } + for (int i = 0; i < num * num; ++i) { + fg.addArc(nodes[i / num], nodes[i % num]); + } + check(countNodes(fg) == num, "Wrong node number."); + check(countArcs(fg) == num*num, "Wrong arc number."); + for (NodeIt src(fg); src != INVALID; ++src) { + for (NodeIt trg(fg); trg != INVALID; ++trg) { + ConArcIt<Digraph> con(fg, src, trg); + check(con != INVALID, "There is no connecting arc."); + check(fg.source(con) == src, "Wrong source."); + check(fg.target(con) == trg, "Wrong target."); + check(++con == INVALID, "There is more connecting arc."); + } + } + ArcLookUp<Digraph> al1(fg); + DynArcLookUp<Digraph> al2(fg); + AllArcLookUp<Digraph> al3(fg); + for (NodeIt src(fg); src != INVALID; ++src) { + for (NodeIt trg(fg); trg != INVALID; ++trg) { + Arc con1 = al1(src, trg); + Arc con2 = al2(src, trg); + Arc con3 = al3(src, trg); + Arc con4 = findArc(fg, src, trg); + check(con1 == con2 && con2 == con3 && con3 == con4, + "Different results.") + check(con1 != INVALID, "There is no connecting arc."); + check(fg.source(con1) == src, "Wrong source."); + check(fg.target(con1) == trg, "Wrong target."); + check(al3(src, trg, con3) == INVALID, + "There is more connecting arc."); + check(findArc(fg, src, trg, con4) == INVALID, + "There is more connecting arc."); + } + } + } +} + +template <typename Graph> +void checkFindEdges() { + TEMPLATE_GRAPH_TYPEDEFS(Graph); + Graph graph; + for (int i = 0; i < 10; ++i) { + graph.addNode(); + } + RangeIdMap<Graph, Node> nodes(graph); + typename RangeIdMap<Graph, Node>::InverseMap invNodes(nodes); + for (int i = 0; i < 100; ++i) { + int src = rnd[invNodes.size()]; + int trg = rnd[invNodes.size()]; + graph.addEdge(invNodes[src], invNodes[trg]); + } + typename Graph::template EdgeMap<int> found(graph, 0); + RangeIdMap<Graph, Edge> edges(graph); + for (NodeIt src(graph); src != INVALID; ++src) { + for (NodeIt trg(graph); trg != INVALID; ++trg) { + for (ConEdgeIt<Graph> con(graph, src, trg); con != INVALID; ++con) { + check( (graph.u(con) == src && graph.v(con) == trg) || + (graph.v(con) == src && graph.u(con) == trg), + "Wrong end nodes."); + ++found[con]; + check(found[con] <= 2, "The edge found more than twice."); + } + } + } + for (EdgeIt it(graph); it != INVALID; ++it) { + check( (graph.u(it) != graph.v(it) && found[it] == 2) || + (graph.u(it) == graph.v(it) && found[it] == 1), + "The edge is not found correctly."); + } +} + +template <class Digraph> +void checkDeg() +{ + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + + const int nodeNum = 10; + const int arcNum = 100; + Digraph digraph; + InDegMap<Digraph> inDeg(digraph); + OutDegMap<Digraph> outDeg(digraph); + std::vector<Node> nodes(nodeNum); + for (int i = 0; i < nodeNum; ++i) { + nodes[i] = digraph.addNode(); + } + std::vector<Arc> arcs(arcNum); + for (int i = 0; i < arcNum; ++i) { + arcs[i] = digraph.addArc(nodes[rnd[nodeNum]], nodes[rnd[nodeNum]]); + } + for (int i = 0; i < nodeNum; ++i) { + check(inDeg[nodes[i]] == countInArcs(digraph, nodes[i]), + "Wrong in degree map"); + } + for (int i = 0; i < nodeNum; ++i) { + check(outDeg[nodes[i]] == countOutArcs(digraph, nodes[i]), + "Wrong out degree map"); + } +} + +template <class Digraph> +void checkSnapDeg() +{ + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + + Digraph g; + Node n1=g.addNode(); + Node n2=g.addNode(); + + InDegMap<Digraph> ind(g); + + g.addArc(n1,n2); + + typename Digraph::Snapshot snap(g); + + OutDegMap<Digraph> outd(g); + + check(ind[n1]==0 && ind[n2]==1, "Wrong InDegMap value."); + check(outd[n1]==1 && outd[n2]==0, "Wrong OutDegMap value."); + + g.addArc(n1,n2); + g.addArc(n2,n1); + + check(ind[n1]==1 && ind[n2]==2, "Wrong InDegMap value."); + check(outd[n1]==2 && outd[n2]==1, "Wrong OutDegMap value."); + + snap.restore(); + + check(ind[n1]==0 && ind[n2]==1, "Wrong InDegMap value."); + check(outd[n1]==1 && outd[n2]==0, "Wrong OutDegMap value."); +} + +int main() { + // Checking ConArcIt, ConEdgeIt, ArcLookUp, AllArcLookUp, and DynArcLookUp + checkFindArcs<ListDigraph>(); + checkFindArcs<SmartDigraph>(); + checkFindEdges<ListGraph>(); + checkFindEdges<SmartGraph>(); + + // Checking In/OutDegMap (and Snapshot feature) + checkDeg<ListDigraph>(); + checkDeg<SmartDigraph>(); + checkSnapDeg<ListDigraph>(); + checkSnapDeg<SmartDigraph>(); + + return 0; +} diff --git a/lemon/test/hao_orlin_test.cc b/lemon/test/hao_orlin_test.cc new file mode 100644 index 0000000..bdd3968 --- /dev/null +++ b/lemon/test/hao_orlin_test.cc @@ -0,0 +1,163 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <sstream> + +#include <lemon/smart_graph.h> +#include <lemon/adaptors.h> +#include <lemon/concepts/digraph.h> +#include <lemon/concepts/maps.h> +#include <lemon/lgf_reader.h> +#include <lemon/hao_orlin.h> + +#include "test_tools.h" + +using namespace lemon; +using namespace std; + +const std::string lgf = + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "5\n" + "@edges\n" + " cap1 cap2 cap3\n" + "0 1 1 1 1 \n" + "0 2 2 2 4 \n" + "1 2 4 4 4 \n" + "3 4 1 1 1 \n" + "3 5 2 2 4 \n" + "4 5 4 4 4 \n" + "5 4 4 4 4 \n" + "2 3 1 6 6 \n" + "4 0 1 6 6 \n"; + +void checkHaoOrlinCompile() +{ + typedef int Value; + typedef concepts::Digraph Digraph; + + typedef Digraph::Node Node; + typedef Digraph::Arc Arc; + typedef concepts::ReadMap<Arc, Value> CapMap; + typedef concepts::WriteMap<Node, bool> CutMap; + + Digraph g; + Node n; + CapMap cap; + CutMap cut; + Value v; + + HaoOrlin<Digraph, CapMap> ho_test(g, cap); + const HaoOrlin<Digraph, CapMap>& + const_ho_test = ho_test; + + ho_test.init(); + ho_test.init(n); + ho_test.calculateOut(); + ho_test.calculateIn(); + ho_test.run(); + ho_test.run(n); + + v = const_ho_test.minCutValue(); + v = const_ho_test.minCutMap(cut); +} + +template <typename Graph, typename CapMap, typename CutMap> +typename CapMap::Value + cutValue(const Graph& graph, const CapMap& cap, const CutMap& cut) +{ + typename CapMap::Value sum = 0; + for (typename Graph::ArcIt a(graph); a != INVALID; ++a) { + if (cut[graph.source(a)] && !cut[graph.target(a)]) + sum += cap[a]; + } + return sum; +} + +int main() { + SmartDigraph graph; + SmartDigraph::ArcMap<int> cap1(graph), cap2(graph), cap3(graph); + SmartDigraph::NodeMap<bool> cut(graph); + + istringstream input(lgf); + digraphReader(graph, input) + .arcMap("cap1", cap1) + .arcMap("cap2", cap2) + .arcMap("cap3", cap3) + .run(); + + { + HaoOrlin<SmartDigraph> ho(graph, cap1); + ho.run(); + ho.minCutMap(cut); + + check(ho.minCutValue() == 1, "Wrong cut value"); + check(ho.minCutValue() == cutValue(graph, cap1, cut), "Wrong cut value"); + } + { + HaoOrlin<SmartDigraph> ho(graph, cap2); + ho.run(); + ho.minCutMap(cut); + + check(ho.minCutValue() == 1, "Wrong cut value"); + check(ho.minCutValue() == cutValue(graph, cap2, cut), "Wrong cut value"); + } + { + HaoOrlin<SmartDigraph> ho(graph, cap3); + ho.run(); + ho.minCutMap(cut); + + check(ho.minCutValue() == 1, "Wrong cut value"); + check(ho.minCutValue() == cutValue(graph, cap3, cut), "Wrong cut value"); + } + + typedef Undirector<SmartDigraph> UGraph; + UGraph ugraph(graph); + + { + HaoOrlin<UGraph, SmartDigraph::ArcMap<int> > ho(ugraph, cap1); + ho.run(); + ho.minCutMap(cut); + + check(ho.minCutValue() == 2, "Wrong cut value"); + check(ho.minCutValue() == cutValue(ugraph, cap1, cut), "Wrong cut value"); + } + { + HaoOrlin<UGraph, SmartDigraph::ArcMap<int> > ho(ugraph, cap2); + ho.run(); + ho.minCutMap(cut); + + check(ho.minCutValue() == 5, "Wrong cut value"); + check(ho.minCutValue() == cutValue(ugraph, cap2, cut), "Wrong cut value"); + } + { + HaoOrlin<UGraph, SmartDigraph::ArcMap<int> > ho(ugraph, cap3); + ho.run(); + ho.minCutMap(cut); + + check(ho.minCutValue() == 5, "Wrong cut value"); + check(ho.minCutValue() == cutValue(ugraph, cap3, cut), "Wrong cut value"); + } + + return 0; +} diff --git a/lemon/test/heap_test.cc b/lemon/test/heap_test.cc new file mode 100644 index 0000000..4839043 --- /dev/null +++ b/lemon/test/heap_test.cc @@ -0,0 +1,310 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2011 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <iostream> +#include <fstream> +#include <string> +#include <vector> + +#include <lemon/concept_check.h> +#include <lemon/concepts/heap.h> + +#include <lemon/smart_graph.h> +#include <lemon/lgf_reader.h> +#include <lemon/dijkstra.h> +#include <lemon/maps.h> + +#include <lemon/bin_heap.h> +#include <lemon/quad_heap.h> +#include <lemon/dheap.h> +#include <lemon/fib_heap.h> +#include <lemon/pairing_heap.h> +#include <lemon/radix_heap.h> +#include <lemon/binomial_heap.h> +#include <lemon/bucket_heap.h> + +#include "test_tools.h" + +using namespace lemon; +using namespace lemon::concepts; + +typedef ListDigraph Digraph; +DIGRAPH_TYPEDEFS(Digraph); + +char test_lgf[] = + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "5\n" + "6\n" + "7\n" + "8\n" + "9\n" + "@arcs\n" + " label capacity\n" + "0 5 0 94\n" + "3 9 1 11\n" + "8 7 2 83\n" + "1 2 3 94\n" + "5 7 4 35\n" + "7 4 5 84\n" + "9 5 6 38\n" + "0 4 7 96\n" + "6 7 8 6\n" + "3 1 9 27\n" + "5 2 10 77\n" + "5 6 11 69\n" + "6 5 12 41\n" + "4 6 13 70\n" + "3 2 14 45\n" + "7 9 15 93\n" + "5 9 16 50\n" + "9 0 17 94\n" + "9 6 18 67\n" + "0 9 19 86\n" + "@attributes\n" + "source 3\n"; + +int test_seq[] = { 2, 28, 19, 27, 33, 25, 13, 41, 10, 26, 1, 9, 4, 34}; +int test_inc[] = {20, 28, 34, 16, 0, 46, 44, 0, 42, 32, 14, 8, 6, 37}; + +int test_len = sizeof(test_seq) / sizeof(test_seq[0]); + +template <typename Heap> +void heapSortTest() { + RangeMap<int> map(test_len, -1); + Heap heap(map); + + std::vector<int> v(test_len); + for (int i = 0; i < test_len; ++i) { + v[i] = test_seq[i]; + heap.push(i, v[i]); + } + std::sort(v.begin(), v.end()); + for (int i = 0; i < test_len; ++i) { + check(v[i] == heap.prio(), "Wrong order in heap sort."); + heap.pop(); + } +} + +template <typename Heap> +void heapIncreaseTest() { + RangeMap<int> map(test_len, -1); + + Heap heap(map); + + std::vector<int> v(test_len); + for (int i = 0; i < test_len; ++i) { + v[i] = test_seq[i]; + heap.push(i, v[i]); + } + for (int i = 0; i < test_len; ++i) { + v[i] += test_inc[i]; + heap.increase(i, v[i]); + } + std::sort(v.begin(), v.end()); + for (int i = 0; i < test_len; ++i) { + check(v[i] == heap.prio(), "Wrong order in heap increase test."); + heap.pop(); + } +} + +template <typename Heap> +void dijkstraHeapTest(const Digraph& digraph, const IntArcMap& length, + Node source) { + + typename Dijkstra<Digraph, IntArcMap>::template SetStandardHeap<Heap>:: + Create dijkstra(digraph, length); + + dijkstra.run(source); + + for(ArcIt a(digraph); a != INVALID; ++a) { + Node s = digraph.source(a); + Node t = digraph.target(a); + if (dijkstra.reached(s)) { + check( dijkstra.dist(t) - dijkstra.dist(s) <= length[a], + "Error in shortest path tree."); + } + } + + for(NodeIt n(digraph); n != INVALID; ++n) { + if ( dijkstra.reached(n) && dijkstra.predArc(n) != INVALID ) { + Arc a = dijkstra.predArc(n); + Node s = digraph.source(a); + check( dijkstra.dist(n) - dijkstra.dist(s) == length[a], + "Error in shortest path tree."); + } + } + +} + +int main() { + + typedef int Item; + typedef int Prio; + typedef RangeMap<int> ItemIntMap; + + Digraph digraph; + IntArcMap length(digraph); + Node source; + + std::istringstream input(test_lgf); + digraphReader(digraph, input). + arcMap("capacity", length). + node("source", source). + run(); + + // BinHeap + { + typedef BinHeap<Prio, ItemIntMap> IntHeap; + checkConcept<Heap<Prio, ItemIntMap>, IntHeap>(); + heapSortTest<IntHeap>(); + heapIncreaseTest<IntHeap>(); + + typedef BinHeap<Prio, IntNodeMap > NodeHeap; + checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>(); + dijkstraHeapTest<NodeHeap>(digraph, length, source); + } + + // QuadHeap + { + typedef QuadHeap<Prio, ItemIntMap> IntHeap; + checkConcept<Heap<Prio, ItemIntMap>, IntHeap>(); + heapSortTest<IntHeap>(); + heapIncreaseTest<IntHeap>(); + + typedef QuadHeap<Prio, IntNodeMap > NodeHeap; + checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>(); + dijkstraHeapTest<NodeHeap>(digraph, length, source); + } + + // DHeap + { + typedef DHeap<Prio, ItemIntMap> IntHeap; + checkConcept<Heap<Prio, ItemIntMap>, IntHeap>(); + heapSortTest<IntHeap>(); + heapIncreaseTest<IntHeap>(); + + typedef DHeap<Prio, IntNodeMap > NodeHeap; + checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>(); + dijkstraHeapTest<NodeHeap>(digraph, length, source); + } + + // FibHeap + { + typedef FibHeap<Prio, ItemIntMap> IntHeap; + checkConcept<Heap<Prio, ItemIntMap>, IntHeap>(); + heapSortTest<IntHeap>(); + heapIncreaseTest<IntHeap>(); + + typedef FibHeap<Prio, IntNodeMap > NodeHeap; + checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>(); + dijkstraHeapTest<NodeHeap>(digraph, length, source); + } + + // PairingHeap + { + typedef PairingHeap<Prio, ItemIntMap> IntHeap; + checkConcept<Heap<Prio, ItemIntMap>, IntHeap>(); + heapSortTest<IntHeap>(); + heapIncreaseTest<IntHeap>(); + + typedef PairingHeap<Prio, IntNodeMap > NodeHeap; + checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>(); + dijkstraHeapTest<NodeHeap>(digraph, length, source); + } + + // RadixHeap + { + typedef RadixHeap<ItemIntMap> IntHeap; + checkConcept<Heap<Prio, ItemIntMap>, IntHeap>(); + heapSortTest<IntHeap>(); + heapIncreaseTest<IntHeap>(); + + typedef RadixHeap<IntNodeMap > NodeHeap; + checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>(); + dijkstraHeapTest<NodeHeap>(digraph, length, source); + } + + // BinomialHeap + { + typedef BinomialHeap<Prio, ItemIntMap> IntHeap; + checkConcept<Heap<Prio, ItemIntMap>, IntHeap>(); + heapSortTest<IntHeap>(); + heapIncreaseTest<IntHeap>(); + + typedef BinomialHeap<Prio, IntNodeMap > NodeHeap; + checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>(); + dijkstraHeapTest<NodeHeap>(digraph, length, source); + } + + // BucketHeap, SimpleBucketHeap + { + typedef BucketHeap<ItemIntMap> IntHeap; + checkConcept<Heap<Prio, ItemIntMap>, IntHeap>(); + heapSortTest<IntHeap>(); + heapIncreaseTest<IntHeap>(); + + typedef BucketHeap<IntNodeMap > NodeHeap; + checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>(); + dijkstraHeapTest<NodeHeap>(digraph, length, source); + + typedef SimpleBucketHeap<ItemIntMap> SimpleIntHeap; + heapSortTest<SimpleIntHeap>(); + } + + { + typedef FibHeap<Prio, ItemIntMap> IntHeap; + checkConcept<Heap<Prio, ItemIntMap>, IntHeap>(); + heapSortTest<IntHeap>(); + heapIncreaseTest<IntHeap>(); + + typedef FibHeap<Prio, IntNodeMap > NodeHeap; + checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>(); + dijkstraHeapTest<NodeHeap>(digraph, length, source); + } + + { + typedef RadixHeap<ItemIntMap> IntHeap; + checkConcept<Heap<Prio, ItemIntMap>, IntHeap>(); + heapSortTest<IntHeap>(); + heapIncreaseTest<IntHeap>(); + + typedef RadixHeap<IntNodeMap > NodeHeap; + checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>(); + dijkstraHeapTest<NodeHeap>(digraph, length, source); + } + + { + typedef BucketHeap<ItemIntMap> IntHeap; + checkConcept<Heap<Prio, ItemIntMap>, IntHeap>(); + heapSortTest<IntHeap>(); + heapIncreaseTest<IntHeap>(); + + typedef BucketHeap<IntNodeMap > NodeHeap; + checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>(); + dijkstraHeapTest<NodeHeap>(digraph, length, source); + } + + + return 0; +} diff --git a/lemon/test/kruskal_test.cc b/lemon/test/kruskal_test.cc new file mode 100644 index 0000000..af36c72 --- /dev/null +++ b/lemon/test/kruskal_test.cc @@ -0,0 +1,147 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2009 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <iostream> +#include <vector> + +#include "test_tools.h" +#include <lemon/maps.h> +#include <lemon/kruskal.h> +#include <lemon/list_graph.h> + +#include <lemon/concepts/maps.h> +#include <lemon/concepts/digraph.h> +#include <lemon/concepts/graph.h> + +using namespace std; +using namespace lemon; + +void checkCompileKruskal() +{ + concepts::WriteMap<concepts::Digraph::Arc,bool> w; + concepts::WriteMap<concepts::Graph::Edge,bool> uw; + + concepts::ReadMap<concepts::Digraph::Arc,int> r; + concepts::ReadMap<concepts::Graph::Edge,int> ur; + + concepts::Digraph g; + concepts::Graph ug; + + kruskal(g, r, w); + kruskal(ug, ur, uw); + + std::vector<std::pair<concepts::Digraph::Arc, int> > rs; + std::vector<std::pair<concepts::Graph::Edge, int> > urs; + + kruskal(g, rs, w); + kruskal(ug, urs, uw); + + std::vector<concepts::Digraph::Arc> ws; + std::vector<concepts::Graph::Edge> uws; + + kruskal(g, r, ws.begin()); + kruskal(ug, ur, uws.begin()); +} + +int main() { + + typedef ListGraph::Node Node; + typedef ListGraph::Edge Edge; + typedef ListGraph::NodeIt NodeIt; + typedef ListGraph::ArcIt ArcIt; + + ListGraph G; + + Node s=G.addNode(); + Node v1=G.addNode(); + Node v2=G.addNode(); + Node v3=G.addNode(); + Node v4=G.addNode(); + Node t=G.addNode(); + + Edge e1 = G.addEdge(s, v1); + Edge e2 = G.addEdge(s, v2); + Edge e3 = G.addEdge(v1, v2); + Edge e4 = G.addEdge(v2, v1); + Edge e5 = G.addEdge(v1, v3); + Edge e6 = G.addEdge(v3, v2); + Edge e7 = G.addEdge(v2, v4); + Edge e8 = G.addEdge(v4, v3); + Edge e9 = G.addEdge(v3, t); + Edge e10 = G.addEdge(v4, t); + + typedef ListGraph::EdgeMap<int> ECostMap; + typedef ListGraph::EdgeMap<bool> EBoolMap; + + ECostMap edge_cost_map(G, 2); + EBoolMap tree_map(G); + + + //Test with const map. + check(kruskal(G, ConstMap<ListGraph::Edge,int>(2), tree_map)==10, + "Total cost should be 10"); + //Test with an edge map (filled with uniform costs). + check(kruskal(G, edge_cost_map, tree_map)==10, + "Total cost should be 10"); + + edge_cost_map[e1] = -10; + edge_cost_map[e2] = -9; + edge_cost_map[e3] = -8; + edge_cost_map[e4] = -7; + edge_cost_map[e5] = -6; + edge_cost_map[e6] = -5; + edge_cost_map[e7] = -4; + edge_cost_map[e8] = -3; + edge_cost_map[e9] = -2; + edge_cost_map[e10] = -1; + + vector<Edge> tree_edge_vec(5); + + //Test with a edge map and inserter. + check(kruskal(G, edge_cost_map, + tree_edge_vec.begin()) + ==-31, + "Total cost should be -31."); + + tree_edge_vec.clear(); + + check(kruskal(G, edge_cost_map, + back_inserter(tree_edge_vec)) + ==-31, + "Total cost should be -31."); + +// tree_edge_vec.clear(); + +// //The above test could also be coded like this: +// check(kruskal(G, +// makeKruskalMapInput(G, edge_cost_map), +// makeKruskalSequenceOutput(back_inserter(tree_edge_vec))) +// ==-31, +// "Total cost should be -31."); + + check(tree_edge_vec.size()==5,"The tree should have 5 edges."); + + check(tree_edge_vec[0]==e1 && + tree_edge_vec[1]==e2 && + tree_edge_vec[2]==e5 && + tree_edge_vec[3]==e7 && + tree_edge_vec[4]==e9, + "Wrong tree."); + + return 0; +} diff --git a/lemon/test/lgf_test.cc b/lemon/test/lgf_test.cc new file mode 100644 index 0000000..c1f373a --- /dev/null +++ b/lemon/test/lgf_test.cc @@ -0,0 +1,169 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2011 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <lemon/list_graph.h> +#include <lemon/lgf_reader.h> +#include "test_tools.h" + +using namespace lemon; + +char test_lgf[] = + "@nodes\n" + "label\n" + "0\n" + "1\n" + "@arcs\n" + " label\n" + "0 1 0\n" + "1 0 1\n" + "@attributes\n" + "source 0\n" + "target 1\n"; + +char test_lgf_nomap[] = + "@nodes\n" + "label\n" + "0\n" + "1\n" + "@arcs\n" + " -\n" + "0 1\n"; + +char test_lgf_bad1[] = + "@nodes\n" + "label\n" + "0\n" + "1\n" + "@arcs\n" + " - another\n" + "0 1\n"; + +char test_lgf_bad2[] = + "@nodes\n" + "label\n" + "0\n" + "1\n" + "@arcs\n" + " label -\n" + "0 1\n"; + + +int main() +{ + { + ListDigraph d; + ListDigraph::Node s,t; + ListDigraph::ArcMap<int> label(d); + std::istringstream input(test_lgf); + digraphReader(d, input). + node("source", s). + node("target", t). + arcMap("label", label). + run(); + check(countNodes(d) == 2,"There should be 2 nodes"); + check(countArcs(d) == 2,"There should be 2 arcs"); + } + { + ListGraph g; + ListGraph::Node s,t; + ListGraph::EdgeMap<int> label(g); + std::istringstream input(test_lgf); + graphReader(g, input). + node("source", s). + node("target", t). + edgeMap("label", label). + run(); + check(countNodes(g) == 2,"There should be 2 nodes"); + check(countEdges(g) == 2,"There should be 2 arcs"); + } + + { + ListDigraph d; + std::istringstream input(test_lgf_nomap); + digraphReader(d, input). + run(); + check(countNodes(d) == 2,"There should be 2 nodes"); + check(countArcs(d) == 1,"There should be 1 arc"); + } + { + ListGraph g; + std::istringstream input(test_lgf_nomap); + graphReader(g, input). + run(); + check(countNodes(g) == 2,"There should be 2 nodes"); + check(countEdges(g) == 1,"There should be 1 edge"); + } + + { + ListDigraph d; + std::istringstream input(test_lgf_bad1); + bool ok=false; + try { + digraphReader(d, input). + run(); + } + catch (FormatError&) + { + ok = true; + } + check(ok,"FormatError exception should have occured"); + } + { + ListGraph g; + std::istringstream input(test_lgf_bad1); + bool ok=false; + try { + graphReader(g, input). + run(); + } + catch (FormatError&) + { + ok = true; + } + check(ok,"FormatError exception should have occured"); + } + + { + ListDigraph d; + std::istringstream input(test_lgf_bad2); + bool ok=false; + try { + digraphReader(d, input). + run(); + } + catch (FormatError&) + { + ok = true; + } + check(ok,"FormatError exception should have occured"); + } + { + ListGraph g; + std::istringstream input(test_lgf_bad2); + bool ok=false; + try { + graphReader(g, input). + run(); + } + catch (FormatError&) + { + ok = true; + } + check(ok,"FormatError exception should have occured"); + } +} diff --git a/lemon/test/lp_test.cc b/lemon/test/lp_test.cc new file mode 100644 index 0000000..125a909 --- /dev/null +++ b/lemon/test/lp_test.cc @@ -0,0 +1,427 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2011 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <sstream> +#include <lemon/lp_skeleton.h> +#include "test_tools.h" +#include <lemon/tolerance.h> + +#include <lemon/config.h> + +#ifdef LEMON_HAVE_GLPK +#include <lemon/glpk.h> +#endif + +#ifdef LEMON_HAVE_CPLEX +#include <lemon/cplex.h> +#endif + +#ifdef LEMON_HAVE_SOPLEX +#include <lemon/soplex.h> +#endif + +#ifdef LEMON_HAVE_CLP +#include <lemon/clp.h> +#endif + +using namespace lemon; + +void lpTest(LpSolver& lp) +{ + + typedef LpSolver LP; + + std::vector<LP::Col> x(10); + // for(int i=0;i<10;i++) x.push_back(lp.addCol()); + lp.addColSet(x); + lp.colLowerBound(x,1); + lp.colUpperBound(x,1); + lp.colBounds(x,1,2); + + std::vector<LP::Col> y(10); + lp.addColSet(y); + + lp.colLowerBound(y,1); + lp.colUpperBound(y,1); + lp.colBounds(y,1,2); + + std::map<int,LP::Col> z; + + z.insert(std::make_pair(12,INVALID)); + z.insert(std::make_pair(2,INVALID)); + z.insert(std::make_pair(7,INVALID)); + z.insert(std::make_pair(5,INVALID)); + + lp.addColSet(z); + + lp.colLowerBound(z,1); + lp.colUpperBound(z,1); + lp.colBounds(z,1,2); + + { + LP::Expr e,f,g; + LP::Col p1,p2,p3,p4,p5; + LP::Constr c; + + p1=lp.addCol(); + p2=lp.addCol(); + p3=lp.addCol(); + p4=lp.addCol(); + p5=lp.addCol(); + + e[p1]=2; + *e=12; + e[p1]+=2; + *e+=12; + e[p1]-=2; + *e-=12; + + e=2; + e=2.2; + e=p1; + e=f; + + e+=2; + e+=2.2; + e+=p1; + e+=f; + + e-=2; + e-=2.2; + e-=p1; + e-=f; + + e*=2; + e*=2.2; + e/=2; + e/=2.2; + + e=((p1+p2)+(p1-p2)+(p1+12)+(12+p1)+(p1-12)+(12-p1)+ + (f+12)+(12+f)+(p1+f)+(f+p1)+(f+g)+ + (f-12)+(12-f)+(p1-f)+(f-p1)+(f-g)+ + 2.2*f+f*2.2+f/2.2+ + 2*f+f*2+f/2+ + 2.2*p1+p1*2.2+p1/2.2+ + 2*p1+p1*2+p1/2 + ); + + + c = (e <= f ); + c = (e <= 2.2); + c = (e <= 2 ); + c = (e <= p1 ); + c = (2.2<= f ); + c = (2 <= f ); + c = (p1 <= f ); + c = (p1 <= p2 ); + c = (p1 <= 2.2); + c = (p1 <= 2 ); + c = (2.2<= p2 ); + c = (2 <= p2 ); + + c = (e >= f ); + c = (e >= 2.2); + c = (e >= 2 ); + c = (e >= p1 ); + c = (2.2>= f ); + c = (2 >= f ); + c = (p1 >= f ); + c = (p1 >= p2 ); + c = (p1 >= 2.2); + c = (p1 >= 2 ); + c = (2.2>= p2 ); + c = (2 >= p2 ); + + c = (e == f ); + c = (e == 2.2); + c = (e == 2 ); + c = (e == p1 ); + c = (2.2== f ); + c = (2 == f ); + c = (p1 == f ); + //c = (p1 == p2 ); + c = (p1 == 2.2); + c = (p1 == 2 ); + c = (2.2== p2 ); + c = (2 == p2 ); + + c = ((2 <= e) <= 3); + c = ((2 <= p1) <= 3); + + c = ((2 >= e) >= 3); + c = ((2 >= p1) >= 3); + + { //Tests for #430 + LP::Col v=lp.addCol(); + LP::Constr c = v >= -3; + c = c <= 4; + LP::Constr c2; + c2 = -3 <= v <= 4; + } + + e[x[3]]=2; + e[x[3]]=4; + e[x[3]]=1; + *e=12; + + lp.addRow(-LP::INF,e,23); + lp.addRow(-LP::INF,3.0*(x[1]+x[2]/2)-x[3],23); + lp.addRow(-LP::INF,3.0*(x[1]+x[2]*2-5*x[3]+12-x[4]/3)+2*x[4]-4,23); + + lp.addRow(x[1]+x[3]<=x[5]-3); + lp.addRow((-7<=x[1]+x[3]-12)<=3); + lp.addRow(x[1]<=x[5]); + + std::ostringstream buf; + + + e=((p1+p2)+(p1-0.99*p2)); + //e.prettyPrint(std::cout); + //(e<=2).prettyPrint(std::cout); + double tolerance=0.001; + e.simplify(tolerance); + buf << "Coeff. of p2 should be 0.01"; + check(e[p2]>0, buf.str()); + + tolerance=0.02; + e.simplify(tolerance); + buf << "Coeff. of p2 should be 0"; + check(const_cast<const LpSolver::Expr&>(e)[p2]==0, buf.str()); + + //Test for clone/new + LP* lpnew = lp.newSolver(); + LP* lpclone = lp.cloneSolver(); + delete lpnew; + delete lpclone; + + } + + { + LP::DualExpr e,f,g; + LP::Row p1 = INVALID, p2 = INVALID, p3 = INVALID, + p4 = INVALID, p5 = INVALID; + + e[p1]=2; + e[p1]+=2; + e[p1]-=2; + + e=p1; + e=f; + + e+=p1; + e+=f; + + e-=p1; + e-=f; + + e*=2; + e*=2.2; + e/=2; + e/=2.2; + + e=((p1+p2)+(p1-p2)+ + (p1+f)+(f+p1)+(f+g)+ + (p1-f)+(f-p1)+(f-g)+ + 2.2*f+f*2.2+f/2.2+ + 2*f+f*2+f/2+ + 2.2*p1+p1*2.2+p1/2.2+ + 2*p1+p1*2+p1/2 + ); + } + +} + +void solveAndCheck(LpSolver& lp, LpSolver::ProblemType stat, + double exp_opt) { + using std::string; + lp.solve(); + + std::ostringstream buf; + buf << "PrimalType should be: " << int(stat) << int(lp.primalType()); + + check(lp.primalType()==stat, buf.str()); + + if (stat == LpSolver::OPTIMAL) { + std::ostringstream sbuf; + sbuf << "Wrong optimal value (" << lp.primal() <<") with " + << lp.solverName() <<"\n the right optimum is " << exp_opt; + check(std::abs(lp.primal()-exp_opt) < 1e-3, sbuf.str()); + } +} + +void aTest(LpSolver & lp) +{ + typedef LpSolver LP; + + //The following example is very simple + + typedef LpSolver::Row Row; + typedef LpSolver::Col Col; + + + Col x1 = lp.addCol(); + Col x2 = lp.addCol(); + + + //Constraints + Row upright=lp.addRow(x1+2*x2 <=1); + lp.addRow(x1+x2 >=-1); + lp.addRow(x1-x2 <=1); + lp.addRow(x1-x2 >=-1); + //Nonnegativity of the variables + lp.colLowerBound(x1, 0); + lp.colLowerBound(x2, 0); + //Objective function + lp.obj(x1+x2); + + lp.sense(lp.MAX); + + //Testing the problem retrieving routines + check(lp.objCoeff(x1)==1,"First term should be 1 in the obj function!"); + check(lp.sense() == lp.MAX,"This is a maximization!"); + check(lp.coeff(upright,x1)==1,"The coefficient in question is 1!"); + check(lp.colLowerBound(x1)==0, + "The lower bound for variable x1 should be 0."); + check(lp.colUpperBound(x1)==LpSolver::INF, + "The upper bound for variable x1 should be infty."); + check(lp.rowLowerBound(upright) == -LpSolver::INF, + "The lower bound for the first row should be -infty."); + check(lp.rowUpperBound(upright)==1, + "The upper bound for the first row should be 1."); + LpSolver::Expr e = lp.row(upright); + check(e[x1] == 1, "The first coefficient should 1."); + check(e[x2] == 2, "The second coefficient should 1."); + + lp.row(upright, x1+x2 <=1); + e = lp.row(upright); + check(e[x1] == 1, "The first coefficient should 1."); + check(e[x2] == 1, "The second coefficient should 1."); + + LpSolver::DualExpr de = lp.col(x1); + check( de[upright] == 1, "The first coefficient should 1."); + + LpSolver* clp = lp.cloneSolver(); + + //Testing the problem retrieving routines + check(clp->objCoeff(x1)==1,"First term should be 1 in the obj function!"); + check(clp->sense() == clp->MAX,"This is a maximization!"); + check(clp->coeff(upright,x1)==1,"The coefficient in question is 1!"); + // std::cout<<lp.colLowerBound(x1)<<std::endl; + check(clp->colLowerBound(x1)==0, + "The lower bound for variable x1 should be 0."); + check(clp->colUpperBound(x1)==LpSolver::INF, + "The upper bound for variable x1 should be infty."); + + check(lp.rowLowerBound(upright)==-LpSolver::INF, + "The lower bound for the first row should be -infty."); + check(lp.rowUpperBound(upright)==1, + "The upper bound for the first row should be 1."); + e = clp->row(upright); + check(e[x1] == 1, "The first coefficient should 1."); + check(e[x2] == 1, "The second coefficient should 1."); + + de = clp->col(x1); + check(de[upright] == 1, "The first coefficient should 1."); + + delete clp; + + //Maximization of x1+x2 + //over the triangle with vertices (0,0) (0,1) (1,0) + double expected_opt=1; + solveAndCheck(lp, LpSolver::OPTIMAL, expected_opt); + + //Minimization + lp.sense(lp.MIN); + expected_opt=0; + solveAndCheck(lp, LpSolver::OPTIMAL, expected_opt); + + //Vertex (-1,0) instead of (0,0) + lp.colLowerBound(x1, -LpSolver::INF); + expected_opt=-1; + solveAndCheck(lp, LpSolver::OPTIMAL, expected_opt); + + //Erase one constraint and return to maximization + lp.erase(upright); + lp.sense(lp.MAX); + expected_opt=LpSolver::INF; + solveAndCheck(lp, LpSolver::UNBOUNDED, expected_opt); + + //Infeasibilty + lp.addRow(x1+x2 <=-2); + solveAndCheck(lp, LpSolver::INFEASIBLE, expected_opt); + +} + +template<class LP> +void cloneTest() +{ + //Test for clone/new + + LP* lp = new LP(); + LP* lpnew = lp->newSolver(); + LP* lpclone = lp->cloneSolver(); + delete lp; + delete lpnew; + delete lpclone; +} + +int main() +{ + LpSkeleton lp_skel; + lpTest(lp_skel); + +#ifdef LEMON_HAVE_GLPK + { + GlpkLp lp_glpk1,lp_glpk2; + lpTest(lp_glpk1); + aTest(lp_glpk2); + cloneTest<GlpkLp>(); + } +#endif + +#ifdef LEMON_HAVE_CPLEX + try { + CplexLp lp_cplex1,lp_cplex2; + lpTest(lp_cplex1); + aTest(lp_cplex2); + cloneTest<CplexLp>(); + } catch (CplexEnv::LicenseError& error) { + check(false, error.what()); + } +#endif + +#ifdef LEMON_HAVE_SOPLEX + { + SoplexLp lp_soplex1,lp_soplex2; + lpTest(lp_soplex1); + aTest(lp_soplex2); + cloneTest<SoplexLp>(); + } +#endif + +#ifdef LEMON_HAVE_CLP + { + ClpLp lp_clp1,lp_clp2; + lpTest(lp_clp1); + aTest(lp_clp2); + cloneTest<ClpLp>(); + } +#endif + + return 0; +} diff --git a/lemon/test/maps_test.cc b/lemon/test/maps_test.cc new file mode 100644 index 0000000..4b11bf3 --- /dev/null +++ b/lemon/test/maps_test.cc @@ -0,0 +1,1003 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2011 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <deque> +#include <set> + +#include <lemon/concept_check.h> +#include <lemon/concepts/maps.h> +#include <lemon/maps.h> +#include <lemon/list_graph.h> +#include <lemon/smart_graph.h> +#include <lemon/adaptors.h> +#include <lemon/dfs.h> +#include <algorithm> + +#include "test_tools.h" + +using namespace lemon; +using namespace lemon::concepts; + +struct A {}; +inline bool operator<(A, A) { return true; } +struct B {}; + +class C { + int _x; +public: + C(int x) : _x(x) {} + int get() const { return _x; } +}; +inline bool operator<(C c1, C c2) { return c1.get() < c2.get(); } +inline bool operator==(C c1, C c2) { return c1.get() == c2.get(); } + +C createC(int x) { return C(x); } + +template <typename T> +class Less { + T _t; +public: + Less(T t): _t(t) {} + bool operator()(const T& t) const { return t < _t; } +}; + +class F { +public: + typedef A argument_type; + typedef B result_type; + + B operator()(const A&) const { return B(); } +private: + F& operator=(const F&); +}; + +int func(A) { return 3; } + +int binc(int a, B) { return a+1; } + +template <typename T> +class Sum { + T& _sum; +public: + Sum(T& sum) : _sum(sum) {} + void operator()(const T& t) { _sum += t; } +}; + +typedef ReadMap<A, double> DoubleMap; +typedef ReadWriteMap<A, double> DoubleWriteMap; +typedef ReferenceMap<A, double, double&, const double&> DoubleRefMap; + +typedef ReadMap<A, bool> BoolMap; +typedef ReadWriteMap<A, bool> BoolWriteMap; +typedef ReferenceMap<A, bool, bool&, const bool&> BoolRefMap; + +int main() +{ + // Map concepts + checkConcept<ReadMap<A,B>, ReadMap<A,B> >(); + checkConcept<ReadMap<A,C>, ReadMap<A,C> >(); + checkConcept<WriteMap<A,B>, WriteMap<A,B> >(); + checkConcept<WriteMap<A,C>, WriteMap<A,C> >(); + checkConcept<ReadWriteMap<A,B>, ReadWriteMap<A,B> >(); + checkConcept<ReadWriteMap<A,C>, ReadWriteMap<A,C> >(); + checkConcept<ReferenceMap<A,B,B&,const B&>, ReferenceMap<A,B,B&,const B&> >(); + checkConcept<ReferenceMap<A,C,C&,const C&>, ReferenceMap<A,C,C&,const C&> >(); + + // NullMap + { + checkConcept<ReadWriteMap<A,B>, NullMap<A,B> >(); + NullMap<A,B> map1; + NullMap<A,B> map2 = map1; + map1 = nullMap<A,B>(); + } + + // ConstMap + { + checkConcept<ReadWriteMap<A,B>, ConstMap<A,B> >(); + checkConcept<ReadWriteMap<A,C>, ConstMap<A,C> >(); + ConstMap<A,B> map1; + ConstMap<A,B> map2 = B(); + ConstMap<A,B> map3 = map1; + map1 = constMap<A>(B()); + map1 = constMap<A,B>(); + map1.setAll(B()); + ConstMap<A,C> map4(C(1)); + ConstMap<A,C> map5 = map4; + map4 = constMap<A>(C(2)); + map4.setAll(C(3)); + + checkConcept<ReadWriteMap<A,int>, ConstMap<A,int> >(); + check(constMap<A>(10)[A()] == 10, "Something is wrong with ConstMap"); + + checkConcept<ReadWriteMap<A,int>, ConstMap<A,Const<int,10> > >(); + ConstMap<A,Const<int,10> > map6; + ConstMap<A,Const<int,10> > map7 = map6; + map6 = constMap<A,int,10>(); + map7 = constMap<A,Const<int,10> >(); + check(map6[A()] == 10 && map7[A()] == 10, + "Something is wrong with ConstMap"); + } + + // IdentityMap + { + checkConcept<ReadMap<A,A>, IdentityMap<A> >(); + IdentityMap<A> map1; + IdentityMap<A> map2 = map1; + map1 = identityMap<A>(); + + checkConcept<ReadMap<double,double>, IdentityMap<double> >(); + check(identityMap<double>()[1.0] == 1.0 && + identityMap<double>()[3.14] == 3.14, + "Something is wrong with IdentityMap"); + } + + // RangeMap + { + checkConcept<ReferenceMap<int,B,B&,const B&>, RangeMap<B> >(); + RangeMap<B> map1; + RangeMap<B> map2(10); + RangeMap<B> map3(10,B()); + RangeMap<B> map4 = map1; + RangeMap<B> map5 = rangeMap<B>(); + RangeMap<B> map6 = rangeMap<B>(10); + RangeMap<B> map7 = rangeMap(10,B()); + + checkConcept< ReferenceMap<int, double, double&, const double&>, + RangeMap<double> >(); + std::vector<double> v(10, 0); + v[5] = 100; + RangeMap<double> map8(v); + RangeMap<double> map9 = rangeMap(v); + check(map9.size() == 10 && map9[2] == 0 && map9[5] == 100, + "Something is wrong with RangeMap"); + } + + // SparseMap + { + checkConcept<ReferenceMap<A,B,B&,const B&>, SparseMap<A,B> >(); + SparseMap<A,B> map1; + SparseMap<A,B> map2 = B(); + SparseMap<A,B> map3 = sparseMap<A,B>(); + SparseMap<A,B> map4 = sparseMap<A>(B()); + + checkConcept< ReferenceMap<double, int, int&, const int&>, + SparseMap<double, int> >(); + std::map<double, int> m; + SparseMap<double, int> map5(m); + SparseMap<double, int> map6(m,10); + SparseMap<double, int> map7 = sparseMap(m); + SparseMap<double, int> map8 = sparseMap(m,10); + + check(map5[1.0] == 0 && map5[3.14] == 0 && + map6[1.0] == 10 && map6[3.14] == 10, + "Something is wrong with SparseMap"); + map5[1.0] = map6[3.14] = 100; + check(map5[1.0] == 100 && map5[3.14] == 0 && + map6[1.0] == 10 && map6[3.14] == 100, + "Something is wrong with SparseMap"); + } + + // ComposeMap + { + typedef ComposeMap<DoubleMap, ReadMap<B,A> > CompMap; + checkConcept<ReadMap<B,double>, CompMap>(); + CompMap map1 = CompMap(DoubleMap(),ReadMap<B,A>()); + CompMap map2 = composeMap(DoubleMap(), ReadMap<B,A>()); + + SparseMap<double, bool> m1(false); m1[3.14] = true; + RangeMap<double> m2(2); m2[0] = 3.0; m2[1] = 3.14; + check(!composeMap(m1,m2)[0] && composeMap(m1,m2)[1], + "Something is wrong with ComposeMap") + } + + // CombineMap + { + typedef CombineMap<DoubleMap, DoubleMap, std::plus<double> > CombMap; + checkConcept<ReadMap<A,double>, CombMap>(); + CombMap map1 = CombMap(DoubleMap(), DoubleMap()); + CombMap map2 = combineMap(DoubleMap(), DoubleMap(), std::plus<double>()); + + check(combineMap(constMap<B,int,2>(), identityMap<B>(), &binc)[B()] == 3, + "Something is wrong with CombineMap"); + } + + // FunctorToMap, MapToFunctor + { + checkConcept<ReadMap<A,B>, FunctorToMap<F,A,B> >(); + checkConcept<ReadMap<A,B>, FunctorToMap<F> >(); + FunctorToMap<F> map1; + FunctorToMap<F> map2 = FunctorToMap<F>(F()); + B b = functorToMap(F())[A()]; + + checkConcept<ReadMap<A,B>, MapToFunctor<ReadMap<A,B> > >(); + MapToFunctor<ReadMap<A,B> > map = + MapToFunctor<ReadMap<A,B> >(ReadMap<A,B>()); + + check(functorToMap(&func)[A()] == 3, + "Something is wrong with FunctorToMap"); + check(mapToFunctor(constMap<A,int>(2))(A()) == 2, + "Something is wrong with MapToFunctor"); + check(mapToFunctor(functorToMap(&func))(A()) == 3 && + mapToFunctor(functorToMap(&func))[A()] == 3, + "Something is wrong with FunctorToMap or MapToFunctor"); + check(functorToMap(mapToFunctor(constMap<A,int>(2)))[A()] == 2, + "Something is wrong with FunctorToMap or MapToFunctor"); + } + + // ConvertMap + { + checkConcept<ReadMap<double,double>, + ConvertMap<ReadMap<double, int>, double> >(); + ConvertMap<RangeMap<bool>, int> map1(rangeMap(1, true)); + ConvertMap<RangeMap<bool>, int> map2 = convertMap<int>(rangeMap(2, false)); + } + + // ForkMap + { + checkConcept<DoubleWriteMap, ForkMap<DoubleWriteMap, DoubleWriteMap> >(); + + typedef RangeMap<double> RM; + typedef SparseMap<int, double> SM; + RM m1(10, -1); + SM m2(-1); + checkConcept<ReadWriteMap<int, double>, ForkMap<RM, SM> >(); + checkConcept<ReadWriteMap<int, double>, ForkMap<SM, RM> >(); + ForkMap<RM, SM> map1(m1,m2); + ForkMap<SM, RM> map2 = forkMap(m2,m1); + map2.set(5, 10); + check(m1[1] == -1 && m1[5] == 10 && m2[1] == -1 && + m2[5] == 10 && map2[1] == -1 && map2[5] == 10, + "Something is wrong with ForkMap"); + } + + // Arithmetic maps: + // - AddMap, SubMap, MulMap, DivMap + // - ShiftMap, ShiftWriteMap, ScaleMap, ScaleWriteMap + // - NegMap, NegWriteMap, AbsMap + { + checkConcept<DoubleMap, AddMap<DoubleMap,DoubleMap> >(); + checkConcept<DoubleMap, SubMap<DoubleMap,DoubleMap> >(); + checkConcept<DoubleMap, MulMap<DoubleMap,DoubleMap> >(); + checkConcept<DoubleMap, DivMap<DoubleMap,DoubleMap> >(); + + ConstMap<int, double> c1(1.0), c2(3.14); + IdentityMap<int> im; + ConvertMap<IdentityMap<int>, double> id(im); + check(addMap(c1,id)[0] == 1.0 && addMap(c1,id)[10] == 11.0, + "Something is wrong with AddMap"); + check(subMap(id,c1)[0] == -1.0 && subMap(id,c1)[10] == 9.0, + "Something is wrong with SubMap"); + check(mulMap(id,c2)[0] == 0 && mulMap(id,c2)[2] == 6.28, + "Something is wrong with MulMap"); + check(divMap(c2,id)[1] == 3.14 && divMap(c2,id)[2] == 1.57, + "Something is wrong with DivMap"); + + checkConcept<DoubleMap, ShiftMap<DoubleMap> >(); + checkConcept<DoubleWriteMap, ShiftWriteMap<DoubleWriteMap> >(); + checkConcept<DoubleMap, ScaleMap<DoubleMap> >(); + checkConcept<DoubleWriteMap, ScaleWriteMap<DoubleWriteMap> >(); + checkConcept<DoubleMap, NegMap<DoubleMap> >(); + checkConcept<DoubleWriteMap, NegWriteMap<DoubleWriteMap> >(); + checkConcept<DoubleMap, AbsMap<DoubleMap> >(); + + check(shiftMap(id, 2.0)[1] == 3.0 && shiftMap(id, 2.0)[10] == 12.0, + "Something is wrong with ShiftMap"); + check(shiftWriteMap(id, 2.0)[1] == 3.0 && + shiftWriteMap(id, 2.0)[10] == 12.0, + "Something is wrong with ShiftWriteMap"); + check(scaleMap(id, 2.0)[1] == 2.0 && scaleMap(id, 2.0)[10] == 20.0, + "Something is wrong with ScaleMap"); + check(scaleWriteMap(id, 2.0)[1] == 2.0 && + scaleWriteMap(id, 2.0)[10] == 20.0, + "Something is wrong with ScaleWriteMap"); + check(negMap(id)[1] == -1.0 && negMap(id)[-10] == 10.0, + "Something is wrong with NegMap"); + check(negWriteMap(id)[1] == -1.0 && negWriteMap(id)[-10] == 10.0, + "Something is wrong with NegWriteMap"); + check(absMap(id)[1] == 1.0 && absMap(id)[-10] == 10.0, + "Something is wrong with AbsMap"); + } + + // Logical maps: + // - TrueMap, FalseMap + // - AndMap, OrMap + // - NotMap, NotWriteMap + // - EqualMap, LessMap + { + checkConcept<BoolMap, TrueMap<A> >(); + checkConcept<BoolMap, FalseMap<A> >(); + checkConcept<BoolMap, AndMap<BoolMap,BoolMap> >(); + checkConcept<BoolMap, OrMap<BoolMap,BoolMap> >(); + checkConcept<BoolMap, NotMap<BoolMap> >(); + checkConcept<BoolWriteMap, NotWriteMap<BoolWriteMap> >(); + checkConcept<BoolMap, EqualMap<DoubleMap,DoubleMap> >(); + checkConcept<BoolMap, LessMap<DoubleMap,DoubleMap> >(); + + TrueMap<int> tm; + FalseMap<int> fm; + RangeMap<bool> rm(2); + rm[0] = true; rm[1] = false; + check(andMap(tm,rm)[0] && !andMap(tm,rm)[1] && + !andMap(fm,rm)[0] && !andMap(fm,rm)[1], + "Something is wrong with AndMap"); + check(orMap(tm,rm)[0] && orMap(tm,rm)[1] && + orMap(fm,rm)[0] && !orMap(fm,rm)[1], + "Something is wrong with OrMap"); + check(!notMap(rm)[0] && notMap(rm)[1], + "Something is wrong with NotMap"); + check(!notWriteMap(rm)[0] && notWriteMap(rm)[1], + "Something is wrong with NotWriteMap"); + + ConstMap<int, double> cm(2.0); + IdentityMap<int> im; + ConvertMap<IdentityMap<int>, double> id(im); + check(lessMap(id,cm)[1] && !lessMap(id,cm)[2] && !lessMap(id,cm)[3], + "Something is wrong with LessMap"); + check(!equalMap(id,cm)[1] && equalMap(id,cm)[2] && !equalMap(id,cm)[3], + "Something is wrong with EqualMap"); + } + + // LoggerBoolMap + { + typedef std::vector<int> vec; + checkConcept<WriteMap<int, bool>, LoggerBoolMap<vec::iterator> >(); + checkConcept<WriteMap<int, bool>, + LoggerBoolMap<std::back_insert_iterator<vec> > >(); + + vec v1; + vec v2(10); + LoggerBoolMap<std::back_insert_iterator<vec> > + map1(std::back_inserter(v1)); + LoggerBoolMap<vec::iterator> map2(v2.begin()); + map1.set(10, false); + map1.set(20, true); map2.set(20, true); + map1.set(30, false); map2.set(40, false); + map1.set(50, true); map2.set(50, true); + map1.set(60, true); map2.set(60, true); + check(v1.size() == 3 && v2.size() == 10 && + v1[0]==20 && v1[1]==50 && v1[2]==60 && + v2[0]==20 && v2[1]==50 && v2[2]==60, + "Something is wrong with LoggerBoolMap"); + + int i = 0; + for ( LoggerBoolMap<vec::iterator>::Iterator it = map2.begin(); + it != map2.end(); ++it ) + check(v1[i++] == *it, "Something is wrong with LoggerBoolMap"); + + typedef ListDigraph Graph; + DIGRAPH_TYPEDEFS(Graph); + Graph gr; + + Node n0 = gr.addNode(); + Node n1 = gr.addNode(); + Node n2 = gr.addNode(); + Node n3 = gr.addNode(); + + gr.addArc(n3, n0); + gr.addArc(n3, n2); + gr.addArc(n0, n2); + gr.addArc(n2, n1); + gr.addArc(n0, n1); + + { + std::vector<Node> v; + dfs(gr).processedMap(loggerBoolMap(std::back_inserter(v))).run(); + + check(v.size()==4 && v[0]==n1 && v[1]==n2 && v[2]==n0 && v[3]==n3, + "Something is wrong with LoggerBoolMap"); + } + { + std::vector<Node> v(countNodes(gr)); + dfs(gr).processedMap(loggerBoolMap(v.begin())).run(); + + check(v.size()==4 && v[0]==n1 && v[1]==n2 && v[2]==n0 && v[3]==n3, + "Something is wrong with LoggerBoolMap"); + } + } + + // IdMap, RangeIdMap + { + typedef ListDigraph Graph; + DIGRAPH_TYPEDEFS(Graph); + + checkConcept<ReadMap<Node, int>, IdMap<Graph, Node> >(); + checkConcept<ReadMap<Arc, int>, IdMap<Graph, Arc> >(); + checkConcept<ReadMap<Node, int>, RangeIdMap<Graph, Node> >(); + checkConcept<ReadMap<Arc, int>, RangeIdMap<Graph, Arc> >(); + + Graph gr; + IdMap<Graph, Node> nmap(gr); + IdMap<Graph, Arc> amap(gr); + RangeIdMap<Graph, Node> nrmap(gr); + RangeIdMap<Graph, Arc> armap(gr); + + Node n0 = gr.addNode(); + Node n1 = gr.addNode(); + Node n2 = gr.addNode(); + + Arc a0 = gr.addArc(n0, n1); + Arc a1 = gr.addArc(n0, n2); + Arc a2 = gr.addArc(n2, n1); + Arc a3 = gr.addArc(n2, n0); + + check(nmap[n0] == gr.id(n0) && nmap(gr.id(n0)) == n0, "Wrong IdMap"); + check(nmap[n1] == gr.id(n1) && nmap(gr.id(n1)) == n1, "Wrong IdMap"); + check(nmap[n2] == gr.id(n2) && nmap(gr.id(n2)) == n2, "Wrong IdMap"); + + check(amap[a0] == gr.id(a0) && amap(gr.id(a0)) == a0, "Wrong IdMap"); + check(amap[a1] == gr.id(a1) && amap(gr.id(a1)) == a1, "Wrong IdMap"); + check(amap[a2] == gr.id(a2) && amap(gr.id(a2)) == a2, "Wrong IdMap"); + check(amap[a3] == gr.id(a3) && amap(gr.id(a3)) == a3, "Wrong IdMap"); + + check(nmap.inverse()[gr.id(n0)] == n0, "Wrong IdMap::InverseMap"); + check(amap.inverse()[gr.id(a0)] == a0, "Wrong IdMap::InverseMap"); + + check(nrmap.size() == 3 && armap.size() == 4, + "Wrong RangeIdMap::size()"); + + check(nrmap[n0] == 0 && nrmap(0) == n0, "Wrong RangeIdMap"); + check(nrmap[n1] == 1 && nrmap(1) == n1, "Wrong RangeIdMap"); + check(nrmap[n2] == 2 && nrmap(2) == n2, "Wrong RangeIdMap"); + + check(armap[a0] == 0 && armap(0) == a0, "Wrong RangeIdMap"); + check(armap[a1] == 1 && armap(1) == a1, "Wrong RangeIdMap"); + check(armap[a2] == 2 && armap(2) == a2, "Wrong RangeIdMap"); + check(armap[a3] == 3 && armap(3) == a3, "Wrong RangeIdMap"); + + check(nrmap.inverse()[0] == n0, "Wrong RangeIdMap::InverseMap"); + check(armap.inverse()[0] == a0, "Wrong RangeIdMap::InverseMap"); + + gr.erase(n1); + + if (nrmap[n0] == 1) nrmap.swap(n0, n2); + nrmap.swap(n2, n0); + if (armap[a1] == 1) armap.swap(a1, a3); + armap.swap(a3, a1); + + check(nrmap.size() == 2 && armap.size() == 2, + "Wrong RangeIdMap::size()"); + + check(nrmap[n0] == 1 && nrmap(1) == n0, "Wrong RangeIdMap"); + check(nrmap[n2] == 0 && nrmap(0) == n2, "Wrong RangeIdMap"); + + check(armap[a1] == 1 && armap(1) == a1, "Wrong RangeIdMap"); + check(armap[a3] == 0 && armap(0) == a3, "Wrong RangeIdMap"); + + check(nrmap.inverse()[0] == n2, "Wrong RangeIdMap::InverseMap"); + check(armap.inverse()[0] == a3, "Wrong RangeIdMap::InverseMap"); + } + + // SourceMap, TargetMap, ForwardMap, BackwardMap, InDegMap, OutDegMap + { + typedef ListGraph Graph; + GRAPH_TYPEDEFS(Graph); + + checkConcept<ReadMap<Arc, Node>, SourceMap<Graph> >(); + checkConcept<ReadMap<Arc, Node>, TargetMap<Graph> >(); + checkConcept<ReadMap<Edge, Arc>, ForwardMap<Graph> >(); + checkConcept<ReadMap<Edge, Arc>, BackwardMap<Graph> >(); + checkConcept<ReadMap<Node, int>, InDegMap<Graph> >(); + checkConcept<ReadMap<Node, int>, OutDegMap<Graph> >(); + + Graph gr; + Node n0 = gr.addNode(); + Node n1 = gr.addNode(); + Node n2 = gr.addNode(); + + gr.addEdge(n0,n1); + gr.addEdge(n1,n2); + gr.addEdge(n0,n2); + gr.addEdge(n2,n1); + gr.addEdge(n1,n2); + gr.addEdge(n0,n1); + + for (EdgeIt e(gr); e != INVALID; ++e) { + check(forwardMap(gr)[e] == gr.direct(e, true), "Wrong ForwardMap"); + check(backwardMap(gr)[e] == gr.direct(e, false), "Wrong BackwardMap"); + } + + check(mapCompare(gr, + sourceMap(orienter(gr, constMap<Edge, bool>(true))), + targetMap(orienter(gr, constMap<Edge, bool>(false)))), + "Wrong SourceMap or TargetMap"); + + typedef Orienter<Graph, const ConstMap<Edge, bool> > Digraph; + Digraph dgr(gr, constMap<Edge, bool>(true)); + OutDegMap<Digraph> odm(dgr); + InDegMap<Digraph> idm(dgr); + + check(odm[n0] == 3 && odm[n1] == 2 && odm[n2] == 1, "Wrong OutDegMap"); + check(idm[n0] == 0 && idm[n1] == 3 && idm[n2] == 3, "Wrong InDegMap"); + + gr.addEdge(n2, n0); + + check(odm[n0] == 3 && odm[n1] == 2 && odm[n2] == 2, "Wrong OutDegMap"); + check(idm[n0] == 1 && idm[n1] == 3 && idm[n2] == 3, "Wrong InDegMap"); + } + + // CrossRefMap + { + typedef ListDigraph Graph; + DIGRAPH_TYPEDEFS(Graph); + + checkConcept<ReadWriteMap<Node, int>, + CrossRefMap<Graph, Node, int> >(); + checkConcept<ReadWriteMap<Node, bool>, + CrossRefMap<Graph, Node, bool> >(); + checkConcept<ReadWriteMap<Node, double>, + CrossRefMap<Graph, Node, double> >(); + + Graph gr; + typedef CrossRefMap<Graph, Node, char> CRMap; + CRMap map(gr); + + Node n0 = gr.addNode(); + Node n1 = gr.addNode(); + Node n2 = gr.addNode(); + + map.set(n0, 'A'); + map.set(n1, 'B'); + map.set(n2, 'C'); + + check(map[n0] == 'A' && map('A') == n0 && map.inverse()['A'] == n0, + "Wrong CrossRefMap"); + check(map[n1] == 'B' && map('B') == n1 && map.inverse()['B'] == n1, + "Wrong CrossRefMap"); + check(map[n2] == 'C' && map('C') == n2 && map.inverse()['C'] == n2, + "Wrong CrossRefMap"); + check(map.count('A') == 1 && map.count('B') == 1 && map.count('C') == 1, + "Wrong CrossRefMap::count()"); + + CRMap::ValueIt it = map.beginValue(); + check(*it++ == 'A' && *it++ == 'B' && *it++ == 'C' && + it == map.endValue(), "Wrong value iterator"); + + map.set(n2, 'A'); + + check(map[n0] == 'A' && map[n1] == 'B' && map[n2] == 'A', + "Wrong CrossRefMap"); + check(map('A') == n0 && map.inverse()['A'] == n0, "Wrong CrossRefMap"); + check(map('B') == n1 && map.inverse()['B'] == n1, "Wrong CrossRefMap"); + check(map('C') == INVALID && map.inverse()['C'] == INVALID, + "Wrong CrossRefMap"); + check(map.count('A') == 2 && map.count('B') == 1 && map.count('C') == 0, + "Wrong CrossRefMap::count()"); + + it = map.beginValue(); + check(*it++ == 'A' && *it++ == 'A' && *it++ == 'B' && + it == map.endValue(), "Wrong value iterator"); + + map.set(n0, 'C'); + + check(map[n0] == 'C' && map[n1] == 'B' && map[n2] == 'A', + "Wrong CrossRefMap"); + check(map('A') == n2 && map.inverse()['A'] == n2, "Wrong CrossRefMap"); + check(map('B') == n1 && map.inverse()['B'] == n1, "Wrong CrossRefMap"); + check(map('C') == n0 && map.inverse()['C'] == n0, "Wrong CrossRefMap"); + check(map.count('A') == 1 && map.count('B') == 1 && map.count('C') == 1, + "Wrong CrossRefMap::count()"); + + it = map.beginValue(); + check(*it++ == 'A' && *it++ == 'B' && *it++ == 'C' && + it == map.endValue(), "Wrong value iterator"); + } + + // CrossRefMap + { + typedef SmartDigraph Graph; + DIGRAPH_TYPEDEFS(Graph); + + checkConcept<ReadWriteMap<Node, int>, + CrossRefMap<Graph, Node, int> >(); + + Graph gr; + typedef CrossRefMap<Graph, Node, char> CRMap; + typedef CRMap::ValueIterator ValueIt; + CRMap map(gr); + + Node n0 = gr.addNode(); + Node n1 = gr.addNode(); + Node n2 = gr.addNode(); + + map.set(n0, 'A'); + map.set(n1, 'B'); + map.set(n2, 'C'); + map.set(n2, 'A'); + map.set(n0, 'C'); + + check(map[n0] == 'C' && map[n1] == 'B' && map[n2] == 'A', + "Wrong CrossRefMap"); + check(map('A') == n2 && map.inverse()['A'] == n2, "Wrong CrossRefMap"); + check(map('B') == n1 && map.inverse()['B'] == n1, "Wrong CrossRefMap"); + check(map('C') == n0 && map.inverse()['C'] == n0, "Wrong CrossRefMap"); + + ValueIt it = map.beginValue(); + check(*it++ == 'A' && *it++ == 'B' && *it++ == 'C' && + it == map.endValue(), "Wrong value iterator"); + } + + // Iterable bool map + { + typedef SmartGraph Graph; + typedef SmartGraph::Node Item; + + typedef IterableBoolMap<SmartGraph, SmartGraph::Node> Ibm; + checkConcept<ReferenceMap<Item, bool, bool&, const bool&>, Ibm>(); + + const int num = 10; + Graph g; + Ibm map0(g, true); + std::vector<Item> items; + for (int i = 0; i < num; ++i) { + items.push_back(g.addNode()); + } + + Ibm map1(g, true); + int n = 0; + for (Ibm::TrueIt it(map1); it != INVALID; ++it) { + check(map1[static_cast<Item>(it)], "Wrong TrueIt"); + ++n; + } + check(n == num, "Wrong number"); + + n = 0; + for (Ibm::ItemIt it(map1, true); it != INVALID; ++it) { + check(map1[static_cast<Item>(it)], "Wrong ItemIt for true"); + ++n; + } + check(n == num, "Wrong number"); + check(Ibm::FalseIt(map1) == INVALID, "Wrong FalseIt"); + check(Ibm::ItemIt(map1, false) == INVALID, "Wrong ItemIt for false"); + + map1[items[5]] = true; + + n = 0; + for (Ibm::ItemIt it(map1, true); it != INVALID; ++it) { + check(map1[static_cast<Item>(it)], "Wrong ItemIt for true"); + ++n; + } + check(n == num, "Wrong number"); + + map1[items[num / 2]] = false; + check(map1[items[num / 2]] == false, "Wrong map value"); + + n = 0; + for (Ibm::TrueIt it(map1); it != INVALID; ++it) { + check(map1[static_cast<Item>(it)], "Wrong TrueIt for true"); + ++n; + } + check(n == num - 1, "Wrong number"); + + n = 0; + for (Ibm::FalseIt it(map1); it != INVALID; ++it) { + check(!map1[static_cast<Item>(it)], "Wrong FalseIt for true"); + ++n; + } + check(n == 1, "Wrong number"); + + map1[items[0]] = false; + check(map1[items[0]] == false, "Wrong map value"); + + map1[items[num - 1]] = false; + check(map1[items[num - 1]] == false, "Wrong map value"); + + n = 0; + for (Ibm::TrueIt it(map1); it != INVALID; ++it) { + check(map1[static_cast<Item>(it)], "Wrong TrueIt for true"); + ++n; + } + check(n == num - 3, "Wrong number"); + check(map1.trueNum() == num - 3, "Wrong number"); + + n = 0; + for (Ibm::FalseIt it(map1); it != INVALID; ++it) { + check(!map1[static_cast<Item>(it)], "Wrong FalseIt for true"); + ++n; + } + check(n == 3, "Wrong number"); + check(map1.falseNum() == 3, "Wrong number"); + } + + // Iterable int map + { + typedef SmartGraph Graph; + typedef SmartGraph::Node Item; + typedef IterableIntMap<SmartGraph, SmartGraph::Node> Iim; + + checkConcept<ReferenceMap<Item, int, int&, const int&>, Iim>(); + + const int num = 10; + Graph g; + Iim map0(g, 0); + std::vector<Item> items; + for (int i = 0; i < num; ++i) { + items.push_back(g.addNode()); + } + + Iim map1(g); + check(map1.size() == 0, "Wrong size"); + + for (int i = 0; i < num; ++i) { + map1[items[i]] = i; + } + check(map1.size() == num, "Wrong size"); + + for (int i = 0; i < num; ++i) { + Iim::ItemIt it(map1, i); + check(static_cast<Item>(it) == items[i], "Wrong value"); + ++it; + check(static_cast<Item>(it) == INVALID, "Wrong value"); + } + + for (int i = 0; i < num; ++i) { + map1[items[i]] = i % 2; + } + check(map1.size() == 2, "Wrong size"); + + int n = 0; + for (Iim::ItemIt it(map1, 0); it != INVALID; ++it) { + check(map1[static_cast<Item>(it)] == 0, "Wrong value"); + ++n; + } + check(n == (num + 1) / 2, "Wrong number"); + + for (Iim::ItemIt it(map1, 1); it != INVALID; ++it) { + check(map1[static_cast<Item>(it)] == 1, "Wrong value"); + ++n; + } + check(n == num, "Wrong number"); + + } + + // Iterable value map + { + typedef SmartGraph Graph; + typedef SmartGraph::Node Item; + typedef IterableValueMap<SmartGraph, SmartGraph::Node, double> Ivm; + + checkConcept<ReadWriteMap<Item, double>, Ivm>(); + + const int num = 10; + Graph g; + Ivm map0(g, 0.0); + std::vector<Item> items; + for (int i = 0; i < num; ++i) { + items.push_back(g.addNode()); + } + + Ivm map1(g, 0.0); + check(distance(map1.beginValue(), map1.endValue()) == 1, "Wrong size"); + check(*map1.beginValue() == 0.0, "Wrong value"); + + for (int i = 0; i < num; ++i) { + map1.set(items[i], static_cast<double>(i)); + } + check(distance(map1.beginValue(), map1.endValue()) == num, "Wrong size"); + + for (int i = 0; i < num; ++i) { + Ivm::ItemIt it(map1, static_cast<double>(i)); + check(static_cast<Item>(it) == items[i], "Wrong value"); + ++it; + check(static_cast<Item>(it) == INVALID, "Wrong value"); + } + + for (Ivm::ValueIt vit = map1.beginValue(); + vit != map1.endValue(); ++vit) { + check(map1[static_cast<Item>(Ivm::ItemIt(map1, *vit))] == *vit, + "Wrong ValueIt"); + } + + for (int i = 0; i < num; ++i) { + map1.set(items[i], static_cast<double>(i % 2)); + } + check(distance(map1.beginValue(), map1.endValue()) == 2, "Wrong size"); + + int n = 0; + for (Ivm::ItemIt it(map1, 0.0); it != INVALID; ++it) { + check(map1[static_cast<Item>(it)] == 0.0, "Wrong value"); + ++n; + } + check(n == (num + 1) / 2, "Wrong number"); + + for (Ivm::ItemIt it(map1, 1.0); it != INVALID; ++it) { + check(map1[static_cast<Item>(it)] == 1.0, "Wrong value"); + ++n; + } + check(n == num, "Wrong number"); + + } + + // Graph map utilities: + // mapMin(), mapMax(), mapMinValue(), mapMaxValue() + // mapFind(), mapFindIf(), mapCount(), mapCountIf() + // mapCopy(), mapCompare(), mapFill() + { + DIGRAPH_TYPEDEFS(SmartDigraph); + + SmartDigraph g; + Node n1 = g.addNode(); + Node n2 = g.addNode(); + Node n3 = g.addNode(); + + SmartDigraph::NodeMap<int> map1(g); + SmartDigraph::ArcMap<char> map2(g); + ConstMap<Node, A> cmap1 = A(); + ConstMap<Arc, C> cmap2 = C(0); + + map1[n1] = 10; + map1[n2] = 5; + map1[n3] = 12; + + // mapMin(), mapMax(), mapMinValue(), mapMaxValue() + check(mapMin(g, map1) == n2, "Wrong mapMin()"); + check(mapMax(g, map1) == n3, "Wrong mapMax()"); + check(mapMin(g, map1, std::greater<int>()) == n3, "Wrong mapMin()"); + check(mapMax(g, map1, std::greater<int>()) == n2, "Wrong mapMax()"); + check(mapMinValue(g, map1) == 5, "Wrong mapMinValue()"); + check(mapMaxValue(g, map1) == 12, "Wrong mapMaxValue()"); + + check(mapMin(g, map2) == INVALID, "Wrong mapMin()"); + check(mapMax(g, map2) == INVALID, "Wrong mapMax()"); + + check(mapMin(g, cmap1) != INVALID, "Wrong mapMin()"); + check(mapMax(g, cmap2) == INVALID, "Wrong mapMax()"); + + Arc a1 = g.addArc(n1, n2); + Arc a2 = g.addArc(n1, n3); + Arc a3 = g.addArc(n2, n3); + Arc a4 = g.addArc(n3, n1); + + map2[a1] = 'b'; + map2[a2] = 'a'; + map2[a3] = 'b'; + map2[a4] = 'c'; + + // mapMin(), mapMax(), mapMinValue(), mapMaxValue() + check(mapMin(g, map2) == a2, "Wrong mapMin()"); + check(mapMax(g, map2) == a4, "Wrong mapMax()"); + check(mapMin(g, map2, std::greater<int>()) == a4, "Wrong mapMin()"); + check(mapMax(g, map2, std::greater<int>()) == a2, "Wrong mapMax()"); + check(mapMinValue(g, map2, std::greater<int>()) == 'c', + "Wrong mapMinValue()"); + check(mapMaxValue(g, map2, std::greater<int>()) == 'a', + "Wrong mapMaxValue()"); + + check(mapMin(g, cmap1) != INVALID, "Wrong mapMin()"); + check(mapMax(g, cmap2) != INVALID, "Wrong mapMax()"); + check(mapMaxValue(g, cmap2) == C(0), "Wrong mapMaxValue()"); + + check(mapMin(g, composeMap(functorToMap(&createC), map2)) == a2, + "Wrong mapMin()"); + check(mapMax(g, composeMap(functorToMap(&createC), map2)) == a4, + "Wrong mapMax()"); + check(mapMinValue(g, composeMap(functorToMap(&createC), map2)) == C('a'), + "Wrong mapMinValue()"); + check(mapMaxValue(g, composeMap(functorToMap(&createC), map2)) == C('c'), + "Wrong mapMaxValue()"); + + // mapFind(), mapFindIf() + check(mapFind(g, map1, 5) == n2, "Wrong mapFind()"); + check(mapFind(g, map1, 6) == INVALID, "Wrong mapFind()"); + check(mapFind(g, map2, 'a') == a2, "Wrong mapFind()"); + check(mapFind(g, map2, 'e') == INVALID, "Wrong mapFind()"); + check(mapFind(g, cmap2, C(0)) == ArcIt(g), "Wrong mapFind()"); + check(mapFind(g, cmap2, C(1)) == INVALID, "Wrong mapFind()"); + + check(mapFindIf(g, map1, Less<int>(7)) == n2, + "Wrong mapFindIf()"); + check(mapFindIf(g, map1, Less<int>(5)) == INVALID, + "Wrong mapFindIf()"); + check(mapFindIf(g, map2, Less<char>('d')) == ArcIt(g), + "Wrong mapFindIf()"); + check(mapFindIf(g, map2, Less<char>('a')) == INVALID, + "Wrong mapFindIf()"); + + // mapCount(), mapCountIf() + check(mapCount(g, map1, 5) == 1, "Wrong mapCount()"); + check(mapCount(g, map1, 6) == 0, "Wrong mapCount()"); + check(mapCount(g, map2, 'a') == 1, "Wrong mapCount()"); + check(mapCount(g, map2, 'b') == 2, "Wrong mapCount()"); + check(mapCount(g, map2, 'e') == 0, "Wrong mapCount()"); + check(mapCount(g, cmap2, C(0)) == 4, "Wrong mapCount()"); + check(mapCount(g, cmap2, C(1)) == 0, "Wrong mapCount()"); + + check(mapCountIf(g, map1, Less<int>(11)) == 2, + "Wrong mapCountIf()"); + check(mapCountIf(g, map1, Less<int>(13)) == 3, + "Wrong mapCountIf()"); + check(mapCountIf(g, map1, Less<int>(5)) == 0, + "Wrong mapCountIf()"); + check(mapCountIf(g, map2, Less<char>('d')) == 4, + "Wrong mapCountIf()"); + check(mapCountIf(g, map2, Less<char>('c')) == 3, + "Wrong mapCountIf()"); + check(mapCountIf(g, map2, Less<char>('a')) == 0, + "Wrong mapCountIf()"); + + // MapIt, ConstMapIt +/* +These tests can be used after applying bugfix #330 + typedef SmartDigraph::NodeMap<int>::MapIt MapIt; + typedef SmartDigraph::NodeMap<int>::ConstMapIt ConstMapIt; + check(*std::min_element(MapIt(map1), MapIt(INVALID)) == 5, + "Wrong NodeMap<>::MapIt"); + check(*std::max_element(ConstMapIt(map1), ConstMapIt(INVALID)) == 12, + "Wrong NodeMap<>::MapIt"); + + int sum = 0; + std::for_each(MapIt(map1), MapIt(INVALID), Sum<int>(sum)); + check(sum == 27, "Wrong NodeMap<>::MapIt"); + std::for_each(ConstMapIt(map1), ConstMapIt(INVALID), Sum<int>(sum)); + check(sum == 54, "Wrong NodeMap<>::ConstMapIt"); +*/ + + // mapCopy(), mapCompare(), mapFill() + check(mapCompare(g, map1, map1), "Wrong mapCompare()"); + check(mapCompare(g, cmap2, cmap2), "Wrong mapCompare()"); + check(mapCompare(g, map1, shiftMap(map1, 0)), "Wrong mapCompare()"); + check(mapCompare(g, map2, scaleMap(map2, 1)), "Wrong mapCompare()"); + check(!mapCompare(g, map1, shiftMap(map1, 1)), "Wrong mapCompare()"); + + SmartDigraph::NodeMap<int> map3(g, 0); + SmartDigraph::ArcMap<char> map4(g, 'a'); + + check(!mapCompare(g, map1, map3), "Wrong mapCompare()"); + check(!mapCompare(g, map2, map4), "Wrong mapCompare()"); + + mapCopy(g, map1, map3); + mapCopy(g, map2, map4); + + check(mapCompare(g, map1, map3), "Wrong mapCompare() or mapCopy()"); + check(mapCompare(g, map2, map4), "Wrong mapCompare() or mapCopy()"); + + Undirector<SmartDigraph> ug(g); + Undirector<SmartDigraph>::EdgeMap<char> umap1(ug, 'x'); + Undirector<SmartDigraph>::ArcMap<double> umap2(ug, 3.14); + + check(!mapCompare(g, map2, umap1), "Wrong mapCompare() or mapCopy()"); + check(!mapCompare(g, umap1, map2), "Wrong mapCompare() or mapCopy()"); + check(!mapCompare(ug, map2, umap1), "Wrong mapCompare() or mapCopy()"); + check(!mapCompare(ug, umap1, map2), "Wrong mapCompare() or mapCopy()"); + + mapCopy(g, map2, umap1); + + check(mapCompare(g, map2, umap1), "Wrong mapCompare() or mapCopy()"); + check(mapCompare(g, umap1, map2), "Wrong mapCompare() or mapCopy()"); + check(mapCompare(ug, map2, umap1), "Wrong mapCompare() or mapCopy()"); + check(mapCompare(ug, umap1, map2), "Wrong mapCompare() or mapCopy()"); + + mapCopy(g, map2, umap1); + mapCopy(g, umap1, map2); + mapCopy(ug, map2, umap1); + mapCopy(ug, umap1, map2); + + check(!mapCompare(ug, umap1, umap2), "Wrong mapCompare() or mapCopy()"); + mapCopy(ug, umap1, umap2); + check(mapCompare(ug, umap1, umap2), "Wrong mapCompare() or mapCopy()"); + + check(!mapCompare(g, map1, constMap<Node>(2)), "Wrong mapCompare()"); + mapFill(g, map1, 2); + check(mapCompare(g, constMap<Node>(2), map1), "Wrong mapFill()"); + + check(!mapCompare(g, map2, constMap<Arc>('z')), "Wrong mapCompare()"); + mapCopy(g, constMap<Arc>('z'), map2); + check(mapCompare(g, constMap<Arc>('z'), map2), "Wrong mapCopy()"); + } + + return 0; +} diff --git a/lemon/test/matching_test.cc b/lemon/test/matching_test.cc new file mode 100644 index 0000000..7386057 --- /dev/null +++ b/lemon/test/matching_test.cc @@ -0,0 +1,448 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <iostream> +#include <sstream> +#include <vector> +#include <queue> +#include <cstdlib> + +#include <lemon/matching.h> +#include <lemon/smart_graph.h> +#include <lemon/concepts/graph.h> +#include <lemon/concepts/maps.h> +#include <lemon/lgf_reader.h> +#include <lemon/math.h> + +#include "test_tools.h" + +using namespace std; +using namespace lemon; + +GRAPH_TYPEDEFS(SmartGraph); + + +const int lgfn = 3; +const std::string lgf[lgfn] = { + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "5\n" + "6\n" + "7\n" + "@edges\n" + " label weight\n" + "7 4 0 984\n" + "0 7 1 73\n" + "7 1 2 204\n" + "2 3 3 583\n" + "2 7 4 565\n" + "2 1 5 582\n" + "0 4 6 551\n" + "2 5 7 385\n" + "1 5 8 561\n" + "5 3 9 484\n" + "7 5 10 904\n" + "3 6 11 47\n" + "7 6 12 888\n" + "3 0 13 747\n" + "6 1 14 310\n", + + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "5\n" + "6\n" + "7\n" + "@edges\n" + " label weight\n" + "2 5 0 710\n" + "0 5 1 241\n" + "2 4 2 856\n" + "2 6 3 762\n" + "4 1 4 747\n" + "6 1 5 962\n" + "4 7 6 723\n" + "1 7 7 661\n" + "2 3 8 376\n" + "1 0 9 416\n" + "6 7 10 391\n", + + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "5\n" + "6\n" + "7\n" + "@edges\n" + " label weight\n" + "6 2 0 553\n" + "0 7 1 653\n" + "6 3 2 22\n" + "4 7 3 846\n" + "7 2 4 981\n" + "7 6 5 250\n" + "5 2 6 539\n", +}; + +void checkMaxMatchingCompile() +{ + typedef concepts::Graph Graph; + typedef Graph::Node Node; + typedef Graph::Edge Edge; + typedef Graph::EdgeMap<bool> MatMap; + + Graph g; + Node n; + Edge e; + MatMap mat(g); + + MaxMatching<Graph> mat_test(g); + const MaxMatching<Graph>& + const_mat_test = mat_test; + + mat_test.init(); + mat_test.greedyInit(); + mat_test.matchingInit(mat); + mat_test.startSparse(); + mat_test.startDense(); + mat_test.run(); + + const_mat_test.matchingSize(); + const_mat_test.matching(e); + const_mat_test.matching(n); + const MaxMatching<Graph>::MatchingMap& mmap = + const_mat_test.matchingMap(); + e = mmap[n]; + const_mat_test.mate(n); + + MaxMatching<Graph>::Status stat = + const_mat_test.status(n); + const MaxMatching<Graph>::StatusMap& smap = + const_mat_test.statusMap(); + stat = smap[n]; + const_mat_test.barrier(n); +} + +void checkMaxWeightedMatchingCompile() +{ + typedef concepts::Graph Graph; + typedef Graph::Node Node; + typedef Graph::Edge Edge; + typedef Graph::EdgeMap<int> WeightMap; + + Graph g; + Node n; + Edge e; + WeightMap w(g); + + MaxWeightedMatching<Graph> mat_test(g, w); + const MaxWeightedMatching<Graph>& + const_mat_test = mat_test; + + mat_test.init(); + mat_test.start(); + mat_test.run(); + + const_mat_test.matchingWeight(); + const_mat_test.matchingSize(); + const_mat_test.matching(e); + const_mat_test.matching(n); + const MaxWeightedMatching<Graph>::MatchingMap& mmap = + const_mat_test.matchingMap(); + e = mmap[n]; + const_mat_test.mate(n); + + int k = 0; + const_mat_test.dualValue(); + const_mat_test.nodeValue(n); + const_mat_test.blossomNum(); + const_mat_test.blossomSize(k); + const_mat_test.blossomValue(k); +} + +void checkMaxWeightedPerfectMatchingCompile() +{ + typedef concepts::Graph Graph; + typedef Graph::Node Node; + typedef Graph::Edge Edge; + typedef Graph::EdgeMap<int> WeightMap; + + Graph g; + Node n; + Edge e; + WeightMap w(g); + + MaxWeightedPerfectMatching<Graph> mat_test(g, w); + const MaxWeightedPerfectMatching<Graph>& + const_mat_test = mat_test; + + mat_test.init(); + mat_test.start(); + mat_test.run(); + + const_mat_test.matchingWeight(); + const_mat_test.matching(e); + const_mat_test.matching(n); + const MaxWeightedPerfectMatching<Graph>::MatchingMap& mmap = + const_mat_test.matchingMap(); + e = mmap[n]; + const_mat_test.mate(n); + + int k = 0; + const_mat_test.dualValue(); + const_mat_test.nodeValue(n); + const_mat_test.blossomNum(); + const_mat_test.blossomSize(k); + const_mat_test.blossomValue(k); +} + +void checkMatching(const SmartGraph& graph, + const MaxMatching<SmartGraph>& mm) { + int num = 0; + + IntNodeMap comp_index(graph); + UnionFind<IntNodeMap> comp(comp_index); + + int barrier_num = 0; + + for (NodeIt n(graph); n != INVALID; ++n) { + check(mm.status(n) == MaxMatching<SmartGraph>::EVEN || + mm.matching(n) != INVALID, "Wrong Gallai-Edmonds decomposition"); + if (mm.status(n) == MaxMatching<SmartGraph>::ODD) { + ++barrier_num; + } else { + comp.insert(n); + } + } + + for (EdgeIt e(graph); e != INVALID; ++e) { + if (mm.matching(e)) { + check(e == mm.matching(graph.u(e)), "Wrong matching"); + check(e == mm.matching(graph.v(e)), "Wrong matching"); + ++num; + } + check(mm.status(graph.u(e)) != MaxMatching<SmartGraph>::EVEN || + mm.status(graph.v(e)) != MaxMatching<SmartGraph>::MATCHED, + "Wrong Gallai-Edmonds decomposition"); + + check(mm.status(graph.v(e)) != MaxMatching<SmartGraph>::EVEN || + mm.status(graph.u(e)) != MaxMatching<SmartGraph>::MATCHED, + "Wrong Gallai-Edmonds decomposition"); + + if (mm.status(graph.u(e)) != MaxMatching<SmartGraph>::ODD && + mm.status(graph.v(e)) != MaxMatching<SmartGraph>::ODD) { + comp.join(graph.u(e), graph.v(e)); + } + } + + std::set<int> comp_root; + int odd_comp_num = 0; + for (NodeIt n(graph); n != INVALID; ++n) { + if (mm.status(n) != MaxMatching<SmartGraph>::ODD) { + int root = comp.find(n); + if (comp_root.find(root) == comp_root.end()) { + comp_root.insert(root); + if (comp.size(n) % 2 == 1) { + ++odd_comp_num; + } + } + } + } + + check(mm.matchingSize() == num, "Wrong matching"); + check(2 * num == countNodes(graph) - (odd_comp_num - barrier_num), + "Wrong matching"); + return; +} + +void checkWeightedMatching(const SmartGraph& graph, + const SmartGraph::EdgeMap<int>& weight, + const MaxWeightedMatching<SmartGraph>& mwm) { + for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) { + if (graph.u(e) == graph.v(e)) continue; + int rw = mwm.nodeValue(graph.u(e)) + mwm.nodeValue(graph.v(e)); + + for (int i = 0; i < mwm.blossomNum(); ++i) { + bool s = false, t = false; + for (MaxWeightedMatching<SmartGraph>::BlossomIt n(mwm, i); + n != INVALID; ++n) { + if (graph.u(e) == n) s = true; + if (graph.v(e) == n) t = true; + } + if (s == true && t == true) { + rw += mwm.blossomValue(i); + } + } + rw -= weight[e] * mwm.dualScale; + + check(rw >= 0, "Negative reduced weight"); + check(rw == 0 || !mwm.matching(e), + "Non-zero reduced weight on matching edge"); + } + + int pv = 0; + for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { + if (mwm.matching(n) != INVALID) { + check(mwm.nodeValue(n) >= 0, "Invalid node value"); + pv += weight[mwm.matching(n)]; + SmartGraph::Node o = graph.target(mwm.matching(n)); + check(mwm.mate(n) == o, "Invalid matching"); + check(mwm.matching(n) == graph.oppositeArc(mwm.matching(o)), + "Invalid matching"); + } else { + check(mwm.mate(n) == INVALID, "Invalid matching"); + check(mwm.nodeValue(n) == 0, "Invalid matching"); + } + } + + int dv = 0; + for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { + dv += mwm.nodeValue(n); + } + + for (int i = 0; i < mwm.blossomNum(); ++i) { + check(mwm.blossomValue(i) >= 0, "Invalid blossom value"); + check(mwm.blossomSize(i) % 2 == 1, "Even blossom size"); + dv += mwm.blossomValue(i) * ((mwm.blossomSize(i) - 1) / 2); + } + + check(pv * mwm.dualScale == dv * 2, "Wrong duality"); + + return; +} + +void checkWeightedPerfectMatching(const SmartGraph& graph, + const SmartGraph::EdgeMap<int>& weight, + const MaxWeightedPerfectMatching<SmartGraph>& mwpm) { + for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) { + if (graph.u(e) == graph.v(e)) continue; + int rw = mwpm.nodeValue(graph.u(e)) + mwpm.nodeValue(graph.v(e)); + + for (int i = 0; i < mwpm.blossomNum(); ++i) { + bool s = false, t = false; + for (MaxWeightedPerfectMatching<SmartGraph>::BlossomIt n(mwpm, i); + n != INVALID; ++n) { + if (graph.u(e) == n) s = true; + if (graph.v(e) == n) t = true; + } + if (s == true && t == true) { + rw += mwpm.blossomValue(i); + } + } + rw -= weight[e] * mwpm.dualScale; + + check(rw >= 0, "Negative reduced weight"); + check(rw == 0 || !mwpm.matching(e), + "Non-zero reduced weight on matching edge"); + } + + int pv = 0; + for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { + check(mwpm.matching(n) != INVALID, "Non perfect"); + pv += weight[mwpm.matching(n)]; + SmartGraph::Node o = graph.target(mwpm.matching(n)); + check(mwpm.mate(n) == o, "Invalid matching"); + check(mwpm.matching(n) == graph.oppositeArc(mwpm.matching(o)), + "Invalid matching"); + } + + int dv = 0; + for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { + dv += mwpm.nodeValue(n); + } + + for (int i = 0; i < mwpm.blossomNum(); ++i) { + check(mwpm.blossomValue(i) >= 0, "Invalid blossom value"); + check(mwpm.blossomSize(i) % 2 == 1, "Even blossom size"); + dv += mwpm.blossomValue(i) * ((mwpm.blossomSize(i) - 1) / 2); + } + + check(pv * mwpm.dualScale == dv * 2, "Wrong duality"); + + return; +} + + +int main() { + + for (int i = 0; i < lgfn; ++i) { + SmartGraph graph; + SmartGraph::EdgeMap<int> weight(graph); + + istringstream lgfs(lgf[i]); + graphReader(graph, lgfs). + edgeMap("weight", weight).run(); + + bool perfect; + { + MaxMatching<SmartGraph> mm(graph); + mm.run(); + checkMatching(graph, mm); + perfect = 2 * mm.matchingSize() == countNodes(graph); + } + + { + MaxWeightedMatching<SmartGraph> mwm(graph, weight); + mwm.run(); + checkWeightedMatching(graph, weight, mwm); + } + + { + MaxWeightedMatching<SmartGraph> mwm(graph, weight); + mwm.init(); + mwm.start(); + checkWeightedMatching(graph, weight, mwm); + } + + { + MaxWeightedPerfectMatching<SmartGraph> mwpm(graph, weight); + bool result = mwpm.run(); + + check(result == perfect, "Perfect matching found"); + if (perfect) { + checkWeightedPerfectMatching(graph, weight, mwpm); + } + } + + { + MaxWeightedPerfectMatching<SmartGraph> mwpm(graph, weight); + mwpm.init(); + bool result = mwpm.start(); + + check(result == perfect, "Perfect matching found"); + if (perfect) { + checkWeightedPerfectMatching(graph, weight, mwpm); + } + } + } + + return 0; +} diff --git a/lemon/test/min_cost_arborescence_test.cc b/lemon/test/min_cost_arborescence_test.cc new file mode 100644 index 0000000..5bcba83 --- /dev/null +++ b/lemon/test/min_cost_arborescence_test.cc @@ -0,0 +1,206 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <iostream> +#include <set> +#include <vector> +#include <iterator> + +#include <lemon/smart_graph.h> +#include <lemon/min_cost_arborescence.h> +#include <lemon/lgf_reader.h> +#include <lemon/concepts/digraph.h> + +#include "test_tools.h" + +using namespace lemon; +using namespace std; + +const char test_lgf[] = + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "5\n" + "6\n" + "7\n" + "8\n" + "9\n" + "@arcs\n" + " label cost\n" + "1 8 0 107\n" + "0 3 1 70\n" + "2 1 2 46\n" + "4 1 3 28\n" + "4 4 4 91\n" + "3 9 5 76\n" + "9 8 6 61\n" + "8 1 7 39\n" + "9 8 8 74\n" + "8 0 9 39\n" + "4 3 10 45\n" + "2 2 11 34\n" + "0 1 12 100\n" + "6 3 13 95\n" + "4 1 14 22\n" + "1 1 15 31\n" + "7 2 16 51\n" + "2 6 17 29\n" + "8 3 18 115\n" + "6 9 19 32\n" + "1 1 20 60\n" + "0 3 21 40\n" + "@attributes\n" + "source 0\n"; + + +void checkMinCostArborescenceCompile() +{ + typedef double VType; + typedef concepts::Digraph Digraph; + typedef concepts::ReadMap<Digraph::Arc, VType> CostMap; + typedef Digraph::Node Node; + typedef Digraph::Arc Arc; + typedef concepts::WriteMap<Digraph::Arc, bool> ArbMap; + typedef concepts::ReadWriteMap<Digraph::Node, Digraph::Arc> PredMap; + + typedef MinCostArborescence<Digraph, CostMap>:: + SetArborescenceMap<ArbMap>:: + SetPredMap<PredMap>::Create MinCostArbType; + + Digraph g; + Node s, n; + Arc e; + VType c; + bool b; + int i; + CostMap cost; + ArbMap arb; + PredMap pred; + + MinCostArbType mcarb_test(g, cost); + const MinCostArbType& const_mcarb_test = mcarb_test; + + mcarb_test + .arborescenceMap(arb) + .predMap(pred) + .run(s); + + mcarb_test.init(); + mcarb_test.addSource(s); + mcarb_test.start(); + n = mcarb_test.processNextNode(); + b = const_mcarb_test.emptyQueue(); + i = const_mcarb_test.queueSize(); + + c = const_mcarb_test.arborescenceCost(); + b = const_mcarb_test.arborescence(e); + e = const_mcarb_test.pred(n); + const MinCostArbType::ArborescenceMap &am = + const_mcarb_test.arborescenceMap(); + const MinCostArbType::PredMap &pm = + const_mcarb_test.predMap(); + b = const_mcarb_test.reached(n); + b = const_mcarb_test.processed(n); + + i = const_mcarb_test.dualNum(); + c = const_mcarb_test.dualValue(); + i = const_mcarb_test.dualSize(i); + c = const_mcarb_test.dualValue(i); + + ignore_unused_variable_warning(am); + ignore_unused_variable_warning(pm); +} + +int main() { + typedef SmartDigraph Digraph; + DIGRAPH_TYPEDEFS(Digraph); + + typedef Digraph::ArcMap<double> CostMap; + + Digraph digraph; + CostMap cost(digraph); + Node source; + + std::istringstream is(test_lgf); + digraphReader(digraph, is). + arcMap("cost", cost). + node("source", source).run(); + + MinCostArborescence<Digraph, CostMap> mca(digraph, cost); + mca.run(source); + + vector<pair<double, set<Node> > > dualSolution(mca.dualNum()); + + for (int i = 0; i < mca.dualNum(); ++i) { + dualSolution[i].first = mca.dualValue(i); + for (MinCostArborescence<Digraph, CostMap>::DualIt it(mca, i); + it != INVALID; ++it) { + dualSolution[i].second.insert(it); + } + } + + for (ArcIt it(digraph); it != INVALID; ++it) { + if (mca.reached(digraph.source(it))) { + double sum = 0.0; + for (int i = 0; i < int(dualSolution.size()); ++i) { + if (dualSolution[i].second.find(digraph.target(it)) + != dualSolution[i].second.end() && + dualSolution[i].second.find(digraph.source(it)) + == dualSolution[i].second.end()) { + sum += dualSolution[i].first; + } + } + if (mca.arborescence(it)) { + check(sum == cost[it], "Invalid dual solution"); + } + check(sum <= cost[it], "Invalid dual solution"); + } + } + + + check(mca.dualValue() == mca.arborescenceCost(), "Invalid dual solution"); + + check(mca.reached(source), "Invalid arborescence"); + for (ArcIt a(digraph); a != INVALID; ++a) { + check(!mca.reached(digraph.source(a)) || + mca.reached(digraph.target(a)), "Invalid arborescence"); + } + + for (NodeIt n(digraph); n != INVALID; ++n) { + if (!mca.reached(n)) continue; + int cnt = 0; + for (InArcIt a(digraph, n); a != INVALID; ++a) { + if (mca.arborescence(a)) { + check(mca.pred(n) == a, "Invalid arborescence"); + ++cnt; + } + } + check((n == source ? cnt == 0 : cnt == 1), "Invalid arborescence"); + } + + Digraph::ArcMap<bool> arborescence(digraph); + check(mca.arborescenceCost() == + minCostArborescence(digraph, cost, source, arborescence), + "Wrong result of the function interface"); + + return 0; +} diff --git a/lemon/test/min_cost_flow_test.cc b/lemon/test/min_cost_flow_test.cc new file mode 100644 index 0000000..fa975ec --- /dev/null +++ b/lemon/test/min_cost_flow_test.cc @@ -0,0 +1,542 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <iostream> +#include <fstream> +#include <limits> + +#include <lemon/list_graph.h> +#include <lemon/lgf_reader.h> + +#include <lemon/network_simplex.h> +#include <lemon/capacity_scaling.h> +#include <lemon/cost_scaling.h> +#include <lemon/cycle_canceling.h> + +#include <lemon/concepts/digraph.h> +#include <lemon/concepts/heap.h> +#include <lemon/concept_check.h> + +#include "test_tools.h" + +using namespace lemon; + +// Test networks +char test_lgf[] = + "@nodes\n" + "label sup1 sup2 sup3 sup4 sup5 sup6\n" + " 1 20 27 0 30 20 30\n" + " 2 -4 0 0 0 -8 -3\n" + " 3 0 0 0 0 0 0\n" + " 4 0 0 0 0 0 0\n" + " 5 9 0 0 0 6 11\n" + " 6 -6 0 0 0 -5 -6\n" + " 7 0 0 0 0 0 0\n" + " 8 0 0 0 0 0 3\n" + " 9 3 0 0 0 0 0\n" + " 10 -2 0 0 0 -7 -2\n" + " 11 0 0 0 0 -10 0\n" + " 12 -20 -27 0 -30 -30 -20\n" + "\n" + "@arcs\n" + " cost cap low1 low2 low3\n" + " 1 2 70 11 0 8 8\n" + " 1 3 150 3 0 1 0\n" + " 1 4 80 15 0 2 2\n" + " 2 8 80 12 0 0 0\n" + " 3 5 140 5 0 3 1\n" + " 4 6 60 10 0 1 0\n" + " 4 7 80 2 0 0 0\n" + " 4 8 110 3 0 0 0\n" + " 5 7 60 14 0 0 0\n" + " 5 11 120 12 0 0 0\n" + " 6 3 0 3 0 0 0\n" + " 6 9 140 4 0 0 0\n" + " 6 10 90 8 0 0 0\n" + " 7 1 30 5 0 0 -5\n" + " 8 12 60 16 0 4 3\n" + " 9 12 50 6 0 0 0\n" + "10 12 70 13 0 5 2\n" + "10 2 100 7 0 0 0\n" + "10 7 60 10 0 0 -3\n" + "11 10 20 14 0 6 -20\n" + "12 11 30 10 0 0 -10\n" + "\n" + "@attributes\n" + "source 1\n" + "target 12\n"; + +char test_neg1_lgf[] = + "@nodes\n" + "label sup\n" + " 1 100\n" + " 2 0\n" + " 3 0\n" + " 4 -100\n" + " 5 0\n" + " 6 0\n" + " 7 0\n" + "@arcs\n" + " cost low1 low2\n" + "1 2 100 0 0\n" + "1 3 30 0 0\n" + "2 4 20 0 0\n" + "3 4 80 0 0\n" + "3 2 50 0 0\n" + "5 3 10 0 0\n" + "5 6 80 0 1000\n" + "6 7 30 0 -1000\n" + "7 5 -120 0 0\n"; + +char test_neg2_lgf[] = + "@nodes\n" + "label sup\n" + " 1 100\n" + " 2 -300\n" + "@arcs\n" + " cost\n" + "1 2 -1\n"; + + +// Test data +typedef ListDigraph Digraph; +DIGRAPH_TYPEDEFS(ListDigraph); + +Digraph gr; +Digraph::ArcMap<int> c(gr), l1(gr), l2(gr), l3(gr), u(gr); +Digraph::NodeMap<int> s1(gr), s2(gr), s3(gr), s4(gr), s5(gr), s6(gr); +ConstMap<Arc, int> cc(1), cu(std::numeric_limits<int>::max()); +Node v, w; + +Digraph neg1_gr; +Digraph::ArcMap<int> neg1_c(neg1_gr), neg1_l1(neg1_gr), neg1_l2(neg1_gr); +ConstMap<Arc, int> neg1_u1(std::numeric_limits<int>::max()), neg1_u2(5000); +Digraph::NodeMap<int> neg1_s(neg1_gr); + +Digraph neg2_gr; +Digraph::ArcMap<int> neg2_c(neg2_gr); +ConstMap<Arc, int> neg2_l(0), neg2_u(1000); +Digraph::NodeMap<int> neg2_s(neg2_gr); + + +enum SupplyType { + EQ, + GEQ, + LEQ +}; + + +// Check the interface of an MCF algorithm +template <typename GR, typename Value, typename Cost> +class McfClassConcept +{ +public: + + template <typename MCF> + struct Constraints { + void constraints() { + checkConcept<concepts::Digraph, GR>(); + + const Constraints& me = *this; + + MCF mcf(me.g); + const MCF& const_mcf = mcf; + + b = mcf.reset().resetParams() + .lowerMap(me.lower) + .upperMap(me.upper) + .costMap(me.cost) + .supplyMap(me.sup) + .stSupply(me.n, me.n, me.k) + .run(); + + c = const_mcf.totalCost(); + x = const_mcf.template totalCost<double>(); + v = const_mcf.flow(me.a); + c = const_mcf.potential(me.n); + const_mcf.flowMap(fm); + const_mcf.potentialMap(pm); + } + + typedef typename GR::Node Node; + typedef typename GR::Arc Arc; + typedef concepts::ReadMap<Node, Value> NM; + typedef concepts::ReadMap<Arc, Value> VAM; + typedef concepts::ReadMap<Arc, Cost> CAM; + typedef concepts::WriteMap<Arc, Value> FlowMap; + typedef concepts::WriteMap<Node, Cost> PotMap; + + GR g; + VAM lower; + VAM upper; + CAM cost; + NM sup; + Node n; + Arc a; + Value k; + + FlowMap fm; + PotMap pm; + bool b; + double x; + typename MCF::Value v; + typename MCF::Cost c; + }; + +}; + + +// Check the feasibility of the given flow (primal soluiton) +template < typename GR, typename LM, typename UM, + typename SM, typename FM > +bool checkFlow( const GR& gr, const LM& lower, const UM& upper, + const SM& supply, const FM& flow, + SupplyType type = EQ ) +{ + TEMPLATE_DIGRAPH_TYPEDEFS(GR); + + for (ArcIt e(gr); e != INVALID; ++e) { + if (flow[e] < lower[e] || flow[e] > upper[e]) return false; + } + + for (NodeIt n(gr); n != INVALID; ++n) { + typename SM::Value sum = 0; + for (OutArcIt e(gr, n); e != INVALID; ++e) + sum += flow[e]; + for (InArcIt e(gr, n); e != INVALID; ++e) + sum -= flow[e]; + bool b = (type == EQ && sum == supply[n]) || + (type == GEQ && sum >= supply[n]) || + (type == LEQ && sum <= supply[n]); + if (!b) return false; + } + + return true; +} + +// Check the feasibility of the given potentials (dual soluiton) +// using the "Complementary Slackness" optimality condition +template < typename GR, typename LM, typename UM, + typename CM, typename SM, typename FM, typename PM > +bool checkPotential( const GR& gr, const LM& lower, const UM& upper, + const CM& cost, const SM& supply, const FM& flow, + const PM& pi, SupplyType type ) +{ + TEMPLATE_DIGRAPH_TYPEDEFS(GR); + + bool opt = true; + for (ArcIt e(gr); opt && e != INVALID; ++e) { + typename CM::Value red_cost = + cost[e] + pi[gr.source(e)] - pi[gr.target(e)]; + opt = red_cost == 0 || + (red_cost > 0 && flow[e] == lower[e]) || + (red_cost < 0 && flow[e] == upper[e]); + } + + for (NodeIt n(gr); opt && n != INVALID; ++n) { + typename SM::Value sum = 0; + for (OutArcIt e(gr, n); e != INVALID; ++e) + sum += flow[e]; + for (InArcIt e(gr, n); e != INVALID; ++e) + sum -= flow[e]; + if (type != LEQ) { + opt = (pi[n] <= 0) && (sum == supply[n] || pi[n] == 0); + } else { + opt = (pi[n] >= 0) && (sum == supply[n] || pi[n] == 0); + } + } + + return opt; +} + +// Check whether the dual cost is equal to the primal cost +template < typename GR, typename LM, typename UM, + typename CM, typename SM, typename PM > +bool checkDualCost( const GR& gr, const LM& lower, const UM& upper, + const CM& cost, const SM& supply, const PM& pi, + typename CM::Value total ) +{ + TEMPLATE_DIGRAPH_TYPEDEFS(GR); + + typename CM::Value dual_cost = 0; + SM red_supply(gr); + for (NodeIt n(gr); n != INVALID; ++n) { + red_supply[n] = supply[n]; + } + for (ArcIt a(gr); a != INVALID; ++a) { + if (lower[a] != 0) { + dual_cost += lower[a] * cost[a]; + red_supply[gr.source(a)] -= lower[a]; + red_supply[gr.target(a)] += lower[a]; + } + } + + for (NodeIt n(gr); n != INVALID; ++n) { + dual_cost -= red_supply[n] * pi[n]; + } + for (ArcIt a(gr); a != INVALID; ++a) { + typename CM::Value red_cost = + cost[a] + pi[gr.source(a)] - pi[gr.target(a)]; + dual_cost -= (upper[a] - lower[a]) * std::max(-red_cost, 0); + } + + return dual_cost == total; +} + +// Run a minimum cost flow algorithm and check the results +template < typename MCF, typename GR, + typename LM, typename UM, + typename CM, typename SM, + typename PT > +void checkMcf( const MCF& mcf, PT mcf_result, + const GR& gr, const LM& lower, const UM& upper, + const CM& cost, const SM& supply, + PT result, bool optimal, typename CM::Value total, + const std::string &test_id = "", + SupplyType type = EQ ) +{ + check(mcf_result == result, "Wrong result " + test_id); + if (optimal) { + typename GR::template ArcMap<typename SM::Value> flow(gr); + typename GR::template NodeMap<typename CM::Value> pi(gr); + mcf.flowMap(flow); + mcf.potentialMap(pi); + check(checkFlow(gr, lower, upper, supply, flow, type), + "The flow is not feasible " + test_id); + check(mcf.totalCost() == total, "The flow is not optimal " + test_id); + check(checkPotential(gr, lower, upper, cost, supply, flow, pi, type), + "Wrong potentials " + test_id); + check(checkDualCost(gr, lower, upper, cost, supply, pi, total), + "Wrong dual cost " + test_id); + } +} + +template < typename MCF, typename Param > +void runMcfGeqTests( Param param, + const std::string &test_str = "", + bool full_neg_cost_support = false ) +{ + MCF mcf1(gr), mcf2(neg1_gr), mcf3(neg2_gr); + + // Basic tests + mcf1.upperMap(u).costMap(c).supplyMap(s1); + checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s1, + mcf1.OPTIMAL, true, 5240, test_str + "-1"); + mcf1.stSupply(v, w, 27); + checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s2, + mcf1.OPTIMAL, true, 7620, test_str + "-2"); + mcf1.lowerMap(l2).supplyMap(s1); + checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s1, + mcf1.OPTIMAL, true, 5970, test_str + "-3"); + mcf1.stSupply(v, w, 27); + checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s2, + mcf1.OPTIMAL, true, 8010, test_str + "-4"); + mcf1.resetParams().supplyMap(s1); + checkMcf(mcf1, mcf1.run(param), gr, l1, cu, cc, s1, + mcf1.OPTIMAL, true, 74, test_str + "-5"); + mcf1.lowerMap(l2).stSupply(v, w, 27); + checkMcf(mcf1, mcf1.run(param), gr, l2, cu, cc, s2, + mcf1.OPTIMAL, true, 94, test_str + "-6"); + mcf1.reset(); + checkMcf(mcf1, mcf1.run(param), gr, l1, cu, cc, s3, + mcf1.OPTIMAL, true, 0, test_str + "-7"); + mcf1.lowerMap(l2).upperMap(u); + checkMcf(mcf1, mcf1.run(param), gr, l2, u, cc, s3, + mcf1.INFEASIBLE, false, 0, test_str + "-8"); + mcf1.lowerMap(l3).upperMap(u).costMap(c).supplyMap(s4); + checkMcf(mcf1, mcf1.run(param), gr, l3, u, c, s4, + mcf1.OPTIMAL, true, 6360, test_str + "-9"); + + // Tests for the GEQ form + mcf1.resetParams().upperMap(u).costMap(c).supplyMap(s5); + checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s5, + mcf1.OPTIMAL, true, 3530, test_str + "-10", GEQ); + mcf1.lowerMap(l2); + checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s5, + mcf1.OPTIMAL, true, 4540, test_str + "-11", GEQ); + mcf1.supplyMap(s6); + checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s6, + mcf1.INFEASIBLE, false, 0, test_str + "-12", GEQ); + + // Tests with negative costs + mcf2.lowerMap(neg1_l1).costMap(neg1_c).supplyMap(neg1_s); + checkMcf(mcf2, mcf2.run(param), neg1_gr, neg1_l1, neg1_u1, neg1_c, neg1_s, + mcf2.UNBOUNDED, false, 0, test_str + "-13"); + mcf2.upperMap(neg1_u2); + checkMcf(mcf2, mcf2.run(param), neg1_gr, neg1_l1, neg1_u2, neg1_c, neg1_s, + mcf2.OPTIMAL, true, -40000, test_str + "-14"); + mcf2.resetParams().lowerMap(neg1_l2).costMap(neg1_c).supplyMap(neg1_s); + checkMcf(mcf2, mcf2.run(param), neg1_gr, neg1_l2, neg1_u1, neg1_c, neg1_s, + mcf2.UNBOUNDED, false, 0, test_str + "-15"); + + mcf3.costMap(neg2_c).supplyMap(neg2_s); + if (full_neg_cost_support) { + checkMcf(mcf3, mcf3.run(param), neg2_gr, neg2_l, neg2_u, neg2_c, neg2_s, + mcf3.OPTIMAL, true, -300, test_str + "-16", GEQ); + } else { + checkMcf(mcf3, mcf3.run(param), neg2_gr, neg2_l, neg2_u, neg2_c, neg2_s, + mcf3.UNBOUNDED, false, 0, test_str + "-17", GEQ); + } + mcf3.upperMap(neg2_u); + checkMcf(mcf3, mcf3.run(param), neg2_gr, neg2_l, neg2_u, neg2_c, neg2_s, + mcf3.OPTIMAL, true, -300, test_str + "-18", GEQ); +} + +template < typename MCF, typename Param > +void runMcfLeqTests( Param param, + const std::string &test_str = "" ) +{ + // Tests for the LEQ form + MCF mcf1(gr); + mcf1.supplyType(mcf1.LEQ); + mcf1.upperMap(u).costMap(c).supplyMap(s6); + checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s6, + mcf1.OPTIMAL, true, 5080, test_str + "-19", LEQ); + mcf1.lowerMap(l2); + checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s6, + mcf1.OPTIMAL, true, 5930, test_str + "-20", LEQ); + mcf1.supplyMap(s5); + checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s5, + mcf1.INFEASIBLE, false, 0, test_str + "-21", LEQ); +} + + +int main() +{ + // Read the test networks + std::istringstream input(test_lgf); + DigraphReader<Digraph>(gr, input) + .arcMap("cost", c) + .arcMap("cap", u) + .arcMap("low1", l1) + .arcMap("low2", l2) + .arcMap("low3", l3) + .nodeMap("sup1", s1) + .nodeMap("sup2", s2) + .nodeMap("sup3", s3) + .nodeMap("sup4", s4) + .nodeMap("sup5", s5) + .nodeMap("sup6", s6) + .node("source", v) + .node("target", w) + .run(); + + std::istringstream neg_inp1(test_neg1_lgf); + DigraphReader<Digraph>(neg1_gr, neg_inp1) + .arcMap("cost", neg1_c) + .arcMap("low1", neg1_l1) + .arcMap("low2", neg1_l2) + .nodeMap("sup", neg1_s) + .run(); + + std::istringstream neg_inp2(test_neg2_lgf); + DigraphReader<Digraph>(neg2_gr, neg_inp2) + .arcMap("cost", neg2_c) + .nodeMap("sup", neg2_s) + .run(); + + // Check the interface of NetworkSimplex + { + typedef concepts::Digraph GR; + checkConcept< McfClassConcept<GR, int, int>, + NetworkSimplex<GR> >(); + checkConcept< McfClassConcept<GR, double, double>, + NetworkSimplex<GR, double> >(); + checkConcept< McfClassConcept<GR, int, double>, + NetworkSimplex<GR, int, double> >(); + } + + // Check the interface of CapacityScaling + { + typedef concepts::Digraph GR; + checkConcept< McfClassConcept<GR, int, int>, + CapacityScaling<GR> >(); + checkConcept< McfClassConcept<GR, double, double>, + CapacityScaling<GR, double> >(); + checkConcept< McfClassConcept<GR, int, double>, + CapacityScaling<GR, int, double> >(); + typedef CapacityScaling<GR>:: + SetHeap<concepts::Heap<int, RangeMap<int> > >::Create CAS; + checkConcept< McfClassConcept<GR, int, int>, CAS >(); + } + + // Check the interface of CostScaling + { + typedef concepts::Digraph GR; + checkConcept< McfClassConcept<GR, int, int>, + CostScaling<GR> >(); + checkConcept< McfClassConcept<GR, double, double>, + CostScaling<GR, double> >(); + checkConcept< McfClassConcept<GR, int, double>, + CostScaling<GR, int, double> >(); + typedef CostScaling<GR>:: + SetLargeCost<double>::Create COS; + checkConcept< McfClassConcept<GR, int, int>, COS >(); + } + + // Check the interface of CycleCanceling + { + typedef concepts::Digraph GR; + checkConcept< McfClassConcept<GR, int, int>, + CycleCanceling<GR> >(); + checkConcept< McfClassConcept<GR, double, double>, + CycleCanceling<GR, double> >(); + checkConcept< McfClassConcept<GR, int, double>, + CycleCanceling<GR, int, double> >(); + } + + // Test NetworkSimplex + { + typedef NetworkSimplex<Digraph> MCF; + runMcfGeqTests<MCF>(MCF::FIRST_ELIGIBLE, "NS-FE", true); + runMcfLeqTests<MCF>(MCF::FIRST_ELIGIBLE, "NS-FE"); + runMcfGeqTests<MCF>(MCF::BEST_ELIGIBLE, "NS-BE", true); + runMcfLeqTests<MCF>(MCF::BEST_ELIGIBLE, "NS-BE"); + runMcfGeqTests<MCF>(MCF::BLOCK_SEARCH, "NS-BS", true); + runMcfLeqTests<MCF>(MCF::BLOCK_SEARCH, "NS-BS"); + runMcfGeqTests<MCF>(MCF::CANDIDATE_LIST, "NS-CL", true); + runMcfLeqTests<MCF>(MCF::CANDIDATE_LIST, "NS-CL"); + runMcfGeqTests<MCF>(MCF::ALTERING_LIST, "NS-AL", true); + runMcfLeqTests<MCF>(MCF::ALTERING_LIST, "NS-AL"); + } + + // Test CapacityScaling + { + typedef CapacityScaling<Digraph> MCF; + runMcfGeqTests<MCF>(0, "SSP"); + runMcfGeqTests<MCF>(2, "CAS"); + } + + // Test CostScaling + { + typedef CostScaling<Digraph> MCF; + runMcfGeqTests<MCF>(MCF::PUSH, "COS-PR"); + runMcfGeqTests<MCF>(MCF::AUGMENT, "COS-AR"); + runMcfGeqTests<MCF>(MCF::PARTIAL_AUGMENT, "COS-PAR"); + } + + // Test CycleCanceling + { + typedef CycleCanceling<Digraph> MCF; + runMcfGeqTests<MCF>(MCF::SIMPLE_CYCLE_CANCELING, "SCC"); + runMcfGeqTests<MCF>(MCF::MINIMUM_MEAN_CYCLE_CANCELING, "MMCC"); + runMcfGeqTests<MCF>(MCF::CANCEL_AND_TIGHTEN, "CAT"); + } + + return 0; +} diff --git a/lemon/test/min_mean_cycle_test.cc b/lemon/test/min_mean_cycle_test.cc new file mode 100644 index 0000000..e9fb8da --- /dev/null +++ b/lemon/test/min_mean_cycle_test.cc @@ -0,0 +1,216 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <iostream> +#include <sstream> + +#include <lemon/smart_graph.h> +#include <lemon/lgf_reader.h> +#include <lemon/path.h> +#include <lemon/concepts/digraph.h> +#include <lemon/concept_check.h> + +#include <lemon/karp_mmc.h> +#include <lemon/hartmann_orlin_mmc.h> +#include <lemon/howard_mmc.h> + +#include "test_tools.h" + +using namespace lemon; + +char test_lgf[] = + "@nodes\n" + "label\n" + "1\n" + "2\n" + "3\n" + "4\n" + "5\n" + "6\n" + "7\n" + "@arcs\n" + " len1 len2 len3 len4 c1 c2 c3 c4\n" + "1 2 1 1 1 1 0 0 0 0\n" + "2 4 5 5 5 5 1 0 0 0\n" + "2 3 8 8 8 8 0 0 0 0\n" + "3 2 -2 0 0 0 1 0 0 0\n" + "3 4 4 4 4 4 0 0 0 0\n" + "3 7 -4 -4 -4 -4 0 0 0 0\n" + "4 1 2 2 2 2 0 0 0 0\n" + "4 3 3 3 3 3 1 0 0 0\n" + "4 4 3 3 0 0 0 0 1 0\n" + "5 2 4 4 4 4 0 0 0 0\n" + "5 6 3 3 3 3 0 1 0 0\n" + "6 5 2 2 2 2 0 1 0 0\n" + "6 4 -1 -1 -1 -1 0 0 0 0\n" + "6 7 1 1 1 1 0 0 0 0\n" + "7 7 4 4 4 -1 0 0 0 1\n"; + + +// Check the interface of an MMC algorithm +template <typename GR, typename Cost> +struct MmcClassConcept +{ + template <typename MMC> + struct Constraints { + void constraints() { + const Constraints& me = *this; + + typedef typename MMC + ::template SetPath<ListPath<GR> > + ::template SetLargeCost<Cost> + ::Create MmcAlg; + MmcAlg mmc(me.g, me.cost); + const MmcAlg& const_mmc = mmc; + + typename MmcAlg::Tolerance tol = const_mmc.tolerance(); + mmc.tolerance(tol); + + b = mmc.cycle(p).run(); + b = mmc.findCycleMean(); + b = mmc.findCycle(); + + v = const_mmc.cycleCost(); + i = const_mmc.cycleSize(); + d = const_mmc.cycleMean(); + p = const_mmc.cycle(); + } + + typedef concepts::ReadMap<typename GR::Arc, Cost> CM; + + GR g; + CM cost; + ListPath<GR> p; + Cost v; + int i; + double d; + bool b; + }; +}; + +// Perform a test with the given parameters +template <typename MMC> +void checkMmcAlg(const SmartDigraph& gr, + const SmartDigraph::ArcMap<int>& lm, + const SmartDigraph::ArcMap<int>& cm, + int cost, int size) { + MMC alg(gr, lm); + alg.findCycleMean(); + check(alg.cycleMean() == static_cast<double>(cost) / size, + "Wrong cycle mean"); + alg.findCycle(); + check(alg.cycleCost() == cost && alg.cycleSize() == size, + "Wrong path"); + SmartDigraph::ArcMap<int> cycle(gr, 0); + for (typename MMC::Path::ArcIt a(alg.cycle()); a != INVALID; ++a) { + ++cycle[a]; + } + for (SmartDigraph::ArcIt a(gr); a != INVALID; ++a) { + check(cm[a] == cycle[a], "Wrong path"); + } +} + +// Class for comparing types +template <typename T1, typename T2> +struct IsSameType { + static const int result = 0; +}; + +template <typename T> +struct IsSameType<T,T> { + static const int result = 1; +}; + + +int main() { + #ifdef LEMON_HAVE_LONG_LONG + typedef long long long_int; + #else + typedef long long_int; + #endif + + // Check the interface + { + typedef concepts::Digraph GR; + + // KarpMmc + checkConcept< MmcClassConcept<GR, int>, + KarpMmc<GR, concepts::ReadMap<GR::Arc, int> > >(); + checkConcept< MmcClassConcept<GR, float>, + KarpMmc<GR, concepts::ReadMap<GR::Arc, float> > >(); + + // HartmannOrlinMmc + checkConcept< MmcClassConcept<GR, int>, + HartmannOrlinMmc<GR, concepts::ReadMap<GR::Arc, int> > >(); + checkConcept< MmcClassConcept<GR, float>, + HartmannOrlinMmc<GR, concepts::ReadMap<GR::Arc, float> > >(); + + // HowardMmc + checkConcept< MmcClassConcept<GR, int>, + HowardMmc<GR, concepts::ReadMap<GR::Arc, int> > >(); + checkConcept< MmcClassConcept<GR, float>, + HowardMmc<GR, concepts::ReadMap<GR::Arc, float> > >(); + + check((IsSameType<HowardMmc<GR, concepts::ReadMap<GR::Arc, int> > + ::LargeCost, long_int>::result == 1), "Wrong LargeCost type"); + check((IsSameType<HowardMmc<GR, concepts::ReadMap<GR::Arc, float> > + ::LargeCost, double>::result == 1), "Wrong LargeCost type"); + } + + // Run various tests + { + typedef SmartDigraph GR; + DIGRAPH_TYPEDEFS(GR); + + GR gr; + IntArcMap l1(gr), l2(gr), l3(gr), l4(gr); + IntArcMap c1(gr), c2(gr), c3(gr), c4(gr); + + std::istringstream input(test_lgf); + digraphReader(gr, input). + arcMap("len1", l1). + arcMap("len2", l2). + arcMap("len3", l3). + arcMap("len4", l4). + arcMap("c1", c1). + arcMap("c2", c2). + arcMap("c3", c3). + arcMap("c4", c4). + run(); + + // Karp + checkMmcAlg<KarpMmc<GR, IntArcMap> >(gr, l1, c1, 6, 3); + checkMmcAlg<KarpMmc<GR, IntArcMap> >(gr, l2, c2, 5, 2); + checkMmcAlg<KarpMmc<GR, IntArcMap> >(gr, l3, c3, 0, 1); + checkMmcAlg<KarpMmc<GR, IntArcMap> >(gr, l4, c4, -1, 1); + + // HartmannOrlin + checkMmcAlg<HartmannOrlinMmc<GR, IntArcMap> >(gr, l1, c1, 6, 3); + checkMmcAlg<HartmannOrlinMmc<GR, IntArcMap> >(gr, l2, c2, 5, 2); + checkMmcAlg<HartmannOrlinMmc<GR, IntArcMap> >(gr, l3, c3, 0, 1); + checkMmcAlg<HartmannOrlinMmc<GR, IntArcMap> >(gr, l4, c4, -1, 1); + + // Howard + checkMmcAlg<HowardMmc<GR, IntArcMap> >(gr, l1, c1, 6, 3); + checkMmcAlg<HowardMmc<GR, IntArcMap> >(gr, l2, c2, 5, 2); + checkMmcAlg<HowardMmc<GR, IntArcMap> >(gr, l3, c3, 0, 1); + checkMmcAlg<HowardMmc<GR, IntArcMap> >(gr, l4, c4, -1, 1); + } + + return 0; +} diff --git a/lemon/test/mip_test.cc b/lemon/test/mip_test.cc new file mode 100644 index 0000000..6e99b4e --- /dev/null +++ b/lemon/test/mip_test.cc @@ -0,0 +1,159 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2009 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include "test_tools.h" + +#include <lemon/config.h> + +#ifdef LEMON_HAVE_CPLEX +#include <lemon/cplex.h> +#endif + +#ifdef LEMON_HAVE_GLPK +#include <lemon/glpk.h> +#endif + +#ifdef LEMON_HAVE_CBC +#include <lemon/cbc.h> +#endif + + +using namespace lemon; + +void solveAndCheck(MipSolver& mip, MipSolver::ProblemType stat, + double exp_opt) { + using std::string; + + mip.solve(); + //int decimal,sign; + std::ostringstream buf; + buf << "Type should be: " << int(stat)<<" and it is "<<int(mip.type()); + + + // itoa(stat,buf1, 10); + check(mip.type()==stat, buf.str()); + + if (stat == MipSolver::OPTIMAL) { + std::ostringstream sbuf; + sbuf << "Wrong optimal value ("<< mip.solValue() + <<" instead of " << exp_opt << ")"; + check(std::abs(mip.solValue()-exp_opt) < 1e-3, sbuf.str()); + //+ecvt(exp_opt,2) + } +} + +void aTest(MipSolver& mip) +{ + //The following example is very simple + + + typedef MipSolver::Row Row; + typedef MipSolver::Col Col; + + + Col x1 = mip.addCol(); + Col x2 = mip.addCol(); + + + //Objective function + mip.obj(x1); + + mip.max(); + + //Unconstrained optimization + mip.solve(); + //Check it out! + + //Constraints + mip.addRow(2 * x1 + x2 <= 2); + Row y2 = mip.addRow(x1 - 2 * x2 <= 0); + + //Nonnegativity of the variable x1 + mip.colLowerBound(x1, 0); + + + //Maximization of x1 + //over the triangle with vertices (0,0),(4/5,2/5),(0,2) + double expected_opt=4.0/5.0; + solveAndCheck(mip, MipSolver::OPTIMAL, expected_opt); + + + //Restrict x2 to integer + mip.colType(x2,MipSolver::INTEGER); + expected_opt=1.0/2.0; + solveAndCheck(mip, MipSolver::OPTIMAL, expected_opt); + + + //Restrict both to integer + mip.colType(x1,MipSolver::INTEGER); + expected_opt=0; + solveAndCheck(mip, MipSolver::OPTIMAL, expected_opt); + + //Erase a variable + mip.erase(x2); + mip.rowUpperBound(y2, 8); + expected_opt=1; + solveAndCheck(mip, MipSolver::OPTIMAL, expected_opt); + +} + + +template<class MIP> +void cloneTest() +{ + + MIP* mip = new MIP(); + MIP* mipnew = mip->newSolver(); + MIP* mipclone = mip->cloneSolver(); + delete mip; + delete mipnew; + delete mipclone; +} + +int main() +{ + +#ifdef LEMON_HAVE_GLPK + { + GlpkMip mip1; + aTest(mip1); + cloneTest<GlpkMip>(); + } +#endif + +#ifdef LEMON_HAVE_CPLEX + try { + CplexMip mip2; + aTest(mip2); + cloneTest<CplexMip>(); + } catch (CplexEnv::LicenseError& error) { + check(false, error.what()); + } +#endif + +#ifdef LEMON_HAVE_CBC + { + CbcMip mip1; + aTest(mip1); + cloneTest<CbcMip>(); + } +#endif + + return 0; + +} diff --git a/lemon/test/path_test.cc b/lemon/test/path_test.cc new file mode 100644 index 0000000..540dddc --- /dev/null +++ b/lemon/test/path_test.cc @@ -0,0 +1,44 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2009 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <string> +#include <iostream> + +#include <lemon/concepts/path.h> +#include <lemon/concepts/digraph.h> + +#include <lemon/path.h> +#include <lemon/list_graph.h> + +#include "test_tools.h" + +using namespace std; +using namespace lemon; + +void check_concepts() { + checkConcept<concepts::Path<ListDigraph>, concepts::Path<ListDigraph> >(); + checkConcept<concepts::Path<ListDigraph>, Path<ListDigraph> >(); + checkConcept<concepts::Path<ListDigraph>, SimplePath<ListDigraph> >(); + checkConcept<concepts::Path<ListDigraph>, StaticPath<ListDigraph> >(); + checkConcept<concepts::Path<ListDigraph>, ListPath<ListDigraph> >(); +} + +int main() { + check_concepts(); + return 0; +} diff --git a/lemon/test/planarity_test.cc b/lemon/test/planarity_test.cc new file mode 100644 index 0000000..0ac11ee --- /dev/null +++ b/lemon/test/planarity_test.cc @@ -0,0 +1,262 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2009 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <iostream> + +#include <lemon/planarity.h> + +#include <lemon/smart_graph.h> +#include <lemon/lgf_reader.h> +#include <lemon/connectivity.h> +#include <lemon/dim2.h> + +#include "test_tools.h" + +using namespace lemon; +using namespace lemon::dim2; + +const int lgfn = 4; +const std::string lgf[lgfn] = { + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "@edges\n" + " label\n" + "0 1 0\n" + "0 2 0\n" + "0 3 0\n" + "0 4 0\n" + "1 2 0\n" + "1 3 0\n" + "1 4 0\n" + "2 3 0\n" + "2 4 0\n" + "3 4 0\n", + + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "@edges\n" + " label\n" + "0 1 0\n" + "0 2 0\n" + "0 3 0\n" + "0 4 0\n" + "1 2 0\n" + "1 3 0\n" + "2 3 0\n" + "2 4 0\n" + "3 4 0\n", + + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "5\n" + "@edges\n" + " label\n" + "0 3 0\n" + "0 4 0\n" + "0 5 0\n" + "1 3 0\n" + "1 4 0\n" + "1 5 0\n" + "2 3 0\n" + "2 4 0\n" + "2 5 0\n", + + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "5\n" + "@edges\n" + " label\n" + "0 3 0\n" + "0 4 0\n" + "0 5 0\n" + "1 3 0\n" + "1 4 0\n" + "1 5 0\n" + "2 3 0\n" + "2 5 0\n" +}; + + + +typedef SmartGraph Graph; +GRAPH_TYPEDEFS(Graph); + +typedef PlanarEmbedding<SmartGraph> PE; +typedef PlanarDrawing<SmartGraph> PD; +typedef PlanarColoring<SmartGraph> PC; + +void checkEmbedding(const Graph& graph, PE& pe) { + int face_num = 0; + + Graph::ArcMap<int> face(graph, -1); + + for (ArcIt a(graph); a != INVALID; ++a) { + if (face[a] == -1) { + Arc b = a; + while (face[b] == -1) { + face[b] = face_num; + b = pe.next(graph.oppositeArc(b)); + } + check(face[b] == face_num, "Wrong face"); + ++face_num; + } + } + check(face_num + countNodes(graph) - countConnectedComponents(graph) == + countEdges(graph) + 1, "Euler test does not passed"); +} + +void checkKuratowski(const Graph& graph, PE& pe) { + std::map<int, int> degs; + for (NodeIt n(graph); n != INVALID; ++n) { + int deg = 0; + for (IncEdgeIt e(graph, n); e != INVALID; ++e) { + if (pe.kuratowski(e)) { + ++deg; + } + } + ++degs[deg]; + } + for (std::map<int, int>::iterator it = degs.begin(); it != degs.end(); ++it) { + check(it->first == 0 || it->first == 2 || + (it->first == 3 && it->second == 6) || + (it->first == 4 && it->second == 5), + "Wrong degree in Kuratowski graph"); + } + + // Not full test + check((degs[3] == 0) != (degs[4] == 0), "Wrong Kuratowski graph"); +} + +bool intersect(Point<int> e1, Point<int> e2, Point<int> f1, Point<int> f2) { + int l, r; + if (std::min(e1.x, e2.x) > std::max(f1.x, f2.x)) return false; + if (std::max(e1.x, e2.x) < std::min(f1.x, f2.x)) return false; + if (std::min(e1.y, e2.y) > std::max(f1.y, f2.y)) return false; + if (std::max(e1.y, e2.y) < std::min(f1.y, f2.y)) return false; + + l = (e2.x - e1.x) * (f1.y - e1.y) - (e2.y - e1.y) * (f1.x - e1.x); + r = (e2.x - e1.x) * (f2.y - e1.y) - (e2.y - e1.y) * (f2.x - e1.x); + if (!((l >= 0 && r <= 0) || (l <= 0 && r >= 0))) return false; + l = (f2.x - f1.x) * (e1.y - f1.y) - (f2.y - f1.y) * (e1.x - f1.x); + r = (f2.x - f1.x) * (e2.y - f1.y) - (f2.y - f1.y) * (e2.x - f1.x); + if (!((l >= 0 && r <= 0) || (l <= 0 && r >= 0))) return false; + return true; +} + +bool collinear(Point<int> p, Point<int> q, Point<int> r) { + int v; + v = (q.x - p.x) * (r.y - p.y) - (q.y - p.y) * (r.x - p.x); + if (v != 0) return false; + v = (q.x - p.x) * (r.x - p.x) + (q.y - p.y) * (r.y - p.y); + if (v < 0) return false; + return true; +} + +void checkDrawing(const Graph& graph, PD& pd) { + for (Graph::NodeIt n(graph); n != INVALID; ++n) { + Graph::NodeIt m(n); + for (++m; m != INVALID; ++m) { + check(pd[m] != pd[n], "Two nodes with identical coordinates"); + } + } + + for (Graph::EdgeIt e(graph); e != INVALID; ++e) { + for (Graph::EdgeIt f(e); f != e; ++f) { + Point<int> e1 = pd[graph.u(e)]; + Point<int> e2 = pd[graph.v(e)]; + Point<int> f1 = pd[graph.u(f)]; + Point<int> f2 = pd[graph.v(f)]; + + if (graph.u(e) == graph.u(f)) { + check(!collinear(e1, e2, f2), "Wrong drawing"); + } else if (graph.u(e) == graph.v(f)) { + check(!collinear(e1, e2, f1), "Wrong drawing"); + } else if (graph.v(e) == graph.u(f)) { + check(!collinear(e2, e1, f2), "Wrong drawing"); + } else if (graph.v(e) == graph.v(f)) { + check(!collinear(e2, e1, f1), "Wrong drawing"); + } else { + check(!intersect(e1, e2, f1, f2), "Wrong drawing"); + } + } + } +} + +void checkColoring(const Graph& graph, PC& pc, int num) { + for (NodeIt n(graph); n != INVALID; ++n) { + check(pc.colorIndex(n) >= 0 && pc.colorIndex(n) < num, + "Wrong coloring"); + } + for (EdgeIt e(graph); e != INVALID; ++e) { + check(pc.colorIndex(graph.u(e)) != pc.colorIndex(graph.v(e)), + "Wrong coloring"); + } +} + +int main() { + + for (int i = 0; i < lgfn; ++i) { + std::istringstream lgfs(lgf[i]); + + SmartGraph graph; + graphReader(graph, lgfs).run(); + + check(simpleGraph(graph), "Test graphs must be simple"); + + PE pe(graph); + bool planar = pe.run(); + check(checkPlanarity(graph) == planar, "Planarity checking failed"); + + if (planar) { + checkEmbedding(graph, pe); + + PlanarDrawing<Graph> pd(graph); + pd.run(pe.embeddingMap()); + checkDrawing(graph, pd); + + PlanarColoring<Graph> pc(graph); + pc.runFiveColoring(pe.embeddingMap()); + checkColoring(graph, pc, 5); + + } else { + checkKuratowski(graph, pe); + } + } + + return 0; +} diff --git a/lemon/test/preflow_test.cc b/lemon/test/preflow_test.cc new file mode 100644 index 0000000..edf982d --- /dev/null +++ b/lemon/test/preflow_test.cc @@ -0,0 +1,276 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2011 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <iostream> + +#include "test_tools.h" +#include <lemon/smart_graph.h> +#include <lemon/preflow.h> +#include <lemon/concepts/digraph.h> +#include <lemon/concepts/maps.h> +#include <lemon/lgf_reader.h> +#include <lemon/elevator.h> + +using namespace lemon; + +char test_lgf[] = + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "5\n" + "6\n" + "7\n" + "8\n" + "9\n" + "@arcs\n" + " label capacity\n" + "0 1 0 20\n" + "0 2 1 0\n" + "1 1 2 3\n" + "1 2 3 8\n" + "1 3 4 8\n" + "2 5 5 5\n" + "3 2 6 5\n" + "3 5 7 5\n" + "3 6 8 5\n" + "4 3 9 3\n" + "5 7 10 3\n" + "5 6 11 10\n" + "5 8 12 10\n" + "6 8 13 8\n" + "8 9 14 20\n" + "8 1 15 5\n" + "9 5 16 5\n" + "@attributes\n" + "source 1\n" + "target 8\n"; + +void checkPreflowCompile() +{ + typedef int VType; + typedef concepts::Digraph Digraph; + + typedef Digraph::Node Node; + typedef Digraph::Arc Arc; + typedef concepts::ReadMap<Arc,VType> CapMap; + typedef concepts::ReadWriteMap<Arc,VType> FlowMap; + typedef concepts::WriteMap<Node,bool> CutMap; + + typedef Elevator<Digraph, Digraph::Node> Elev; + typedef LinkedElevator<Digraph, Digraph::Node> LinkedElev; + + Digraph g; + Node n; + Arc e; + CapMap cap; + FlowMap flow; + CutMap cut; + VType v; + bool b; + + typedef Preflow<Digraph, CapMap> + ::SetFlowMap<FlowMap> + ::SetElevator<Elev> + ::SetStandardElevator<LinkedElev> + ::Create PreflowType; + PreflowType preflow_test(g, cap, n, n); + const PreflowType& const_preflow_test = preflow_test; + + const PreflowType::Elevator& elev = const_preflow_test.elevator(); + preflow_test.elevator(const_cast<PreflowType::Elevator&>(elev)); + PreflowType::Tolerance tol = const_preflow_test.tolerance(); + preflow_test.tolerance(tol); + + preflow_test + .capacityMap(cap) + .flowMap(flow) + .source(n) + .target(n); + + preflow_test.init(); + preflow_test.init(cap); + preflow_test.startFirstPhase(); + preflow_test.startSecondPhase(); + preflow_test.run(); + preflow_test.runMinCut(); + + v = const_preflow_test.flowValue(); + v = const_preflow_test.flow(e); + const FlowMap& fm = const_preflow_test.flowMap(); + b = const_preflow_test.minCut(n); + const_preflow_test.minCutMap(cut); + + ignore_unused_variable_warning(fm); +} + +int cutValue (const SmartDigraph& g, + const SmartDigraph::NodeMap<bool>& cut, + const SmartDigraph::ArcMap<int>& cap) { + + int c=0; + for(SmartDigraph::ArcIt e(g); e!=INVALID; ++e) { + if (cut[g.source(e)] && !cut[g.target(e)]) c+=cap[e]; + } + return c; +} + +bool checkFlow(const SmartDigraph& g, + const SmartDigraph::ArcMap<int>& flow, + const SmartDigraph::ArcMap<int>& cap, + SmartDigraph::Node s, SmartDigraph::Node t) { + + for (SmartDigraph::ArcIt e(g); e != INVALID; ++e) { + if (flow[e] < 0 || flow[e] > cap[e]) return false; + } + + for (SmartDigraph::NodeIt n(g); n != INVALID; ++n) { + if (n == s || n == t) continue; + int sum = 0; + for (SmartDigraph::OutArcIt e(g, n); e != INVALID; ++e) { + sum += flow[e]; + } + for (SmartDigraph::InArcIt e(g, n); e != INVALID; ++e) { + sum -= flow[e]; + } + if (sum != 0) return false; + } + return true; +} + +void initFlowTest() +{ + DIGRAPH_TYPEDEFS(SmartDigraph); + + SmartDigraph g; + SmartDigraph::ArcMap<int> cap(g),iflow(g); + Node s=g.addNode(); Node t=g.addNode(); + Node n1=g.addNode(); Node n2=g.addNode(); + Arc a; + a=g.addArc(s,n1); cap[a]=20; iflow[a]=20; + a=g.addArc(n1,n2); cap[a]=10; iflow[a]=0; + a=g.addArc(n2,t); cap[a]=20; iflow[a]=0; + + Preflow<SmartDigraph> pre(g,cap,s,t); + pre.init(iflow); + pre.startFirstPhase(); + check(pre.flowValue() == 10, "The incorrect max flow value."); + check(pre.minCut(s), "Wrong min cut (Node s)."); + check(pre.minCut(n1), "Wrong min cut (Node n1)."); + check(!pre.minCut(n2), "Wrong min cut (Node n2)."); + check(!pre.minCut(t), "Wrong min cut (Node t)."); +} + + +int main() { + + typedef SmartDigraph Digraph; + + typedef Digraph::Node Node; + typedef Digraph::NodeIt NodeIt; + typedef Digraph::ArcIt ArcIt; + typedef Digraph::ArcMap<int> CapMap; + typedef Digraph::ArcMap<int> FlowMap; + typedef Digraph::NodeMap<bool> CutMap; + + typedef Preflow<Digraph, CapMap> PType; + + Digraph g; + Node s, t; + CapMap cap(g); + std::istringstream input(test_lgf); + DigraphReader<Digraph>(g,input). + arcMap("capacity", cap). + node("source",s). + node("target",t). + run(); + + PType preflow_test(g, cap, s, t); + preflow_test.run(); + + check(checkFlow(g, preflow_test.flowMap(), cap, s, t), + "The flow is not feasible."); + + CutMap min_cut(g); + preflow_test.minCutMap(min_cut); + int min_cut_value=cutValue(g,min_cut,cap); + + check(preflow_test.flowValue() == min_cut_value, + "The max flow value is not equal to the three min cut values."); + + FlowMap flow(g); + for(ArcIt e(g); e!=INVALID; ++e) flow[e] = preflow_test.flowMap()[e]; + + int flow_value=preflow_test.flowValue(); + + for(ArcIt e(g); e!=INVALID; ++e) cap[e]=2*cap[e]; + preflow_test.init(flow); + preflow_test.startFirstPhase(); + + CutMap min_cut1(g); + preflow_test.minCutMap(min_cut1); + min_cut_value=cutValue(g,min_cut1,cap); + + check(preflow_test.flowValue() == min_cut_value && + min_cut_value == 2*flow_value, + "The max flow value or the min cut value is wrong."); + + preflow_test.startSecondPhase(); + + check(checkFlow(g, preflow_test.flowMap(), cap, s, t), + "The flow is not feasible."); + + CutMap min_cut2(g); + preflow_test.minCutMap(min_cut2); + min_cut_value=cutValue(g,min_cut2,cap); + + check(preflow_test.flowValue() == min_cut_value && + min_cut_value == 2*flow_value, + "The max flow value or the three min cut values were not doubled"); + + + preflow_test.flowMap(flow); + + NodeIt tmp1(g,s); + ++tmp1; + if ( tmp1 != INVALID ) s=tmp1; + + NodeIt tmp2(g,t); + ++tmp2; + if ( tmp2 != INVALID ) t=tmp2; + + preflow_test.source(s); + preflow_test.target(t); + + preflow_test.run(); + + CutMap min_cut3(g); + preflow_test.minCutMap(min_cut3); + min_cut_value=cutValue(g,min_cut3,cap); + + + check(preflow_test.flowValue() == min_cut_value, + "The max flow value or the three min cut values are incorrect."); + + initFlowTest(); + + return 0; +} diff --git a/lemon/test/radix_sort_test.cc b/lemon/test/radix_sort_test.cc new file mode 100644 index 0000000..2a27a7e --- /dev/null +++ b/lemon/test/radix_sort_test.cc @@ -0,0 +1,147 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2009 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <lemon/time_measure.h> +#include <lemon/smart_graph.h> +#include <lemon/maps.h> +#include <lemon/radix_sort.h> +#include <lemon/math.h> + +#include "test_tools.h" + +#include <vector> +#include <algorithm> + +using namespace lemon; + +static const int n = 10000; + +struct Negate { + typedef int argument_type; + typedef int result_type; + int operator()(int a) { return - a; } +}; + +int negate(int a) { return - a; } + + +void generateIntSequence(int n, std::vector<int>& data) { + int prime = 9973; + int root = 136, value = 1; + for (int i = 0; i < n; ++i) { + data.push_back(value - prime / 2); + value = (value * root) % prime; + } +} + +void generateCharSequence(int n, std::vector<unsigned char>& data) { + int prime = 251; + int root = 3, value = root; + for (int i = 0; i < n; ++i) { + data.push_back(static_cast<unsigned char>(value)); + value = (value * root) % prime; + } +} + +void checkRadixSort() { + { + std::vector<int> data1; + generateIntSequence(n, data1); + + std::vector<int> data2(data1); + std::sort(data1.begin(), data1.end()); + + radixSort(data2.begin(), data2.end()); + for (int i = 0; i < n; ++i) { + check(data1[i] == data2[i], "Test failed"); + } + + radixSort(data2.begin(), data2.end(), Negate()); + for (int i = 0; i < n; ++i) { + check(data1[i] == data2[n - 1 - i], "Test failed"); + } + + radixSort(data2.begin(), data2.end(), negate); + for (int i = 0; i < n; ++i) { + check(data1[i] == data2[n - 1 - i], "Test failed"); + } + + } + + { + std::vector<unsigned char> data1(n); + generateCharSequence(n, data1); + + std::vector<unsigned char> data2(data1); + std::sort(data1.begin(), data1.end()); + + radixSort(data2.begin(), data2.end()); + for (int i = 0; i < n; ++i) { + check(data1[i] == data2[i], "Test failed"); + } + + } +} + + +void checkStableRadixSort() { + { + std::vector<int> data1; + generateIntSequence(n, data1); + + std::vector<int> data2(data1); + std::sort(data1.begin(), data1.end()); + + stableRadixSort(data2.begin(), data2.end()); + for (int i = 0; i < n; ++i) { + check(data1[i] == data2[i], "Test failed"); + } + + stableRadixSort(data2.begin(), data2.end(), Negate()); + for (int i = 0; i < n; ++i) { + check(data1[i] == data2[n - 1 - i], "Test failed"); + } + + stableRadixSort(data2.begin(), data2.end(), negate); + for (int i = 0; i < n; ++i) { + check(data1[i] == data2[n - 1 - i], "Test failed"); + } + } + + { + std::vector<unsigned char> data1(n); + generateCharSequence(n, data1); + + std::vector<unsigned char> data2(data1); + std::sort(data1.begin(), data1.end()); + + radixSort(data2.begin(), data2.end()); + for (int i = 0; i < n; ++i) { + check(data1[i] == data2[i], "Test failed"); + } + + } +} + +int main() { + + checkRadixSort(); + checkStableRadixSort(); + + return 0; +} diff --git a/lemon/test/random_test.cc b/lemon/test/random_test.cc new file mode 100644 index 0000000..49dd8b6 --- /dev/null +++ b/lemon/test/random_test.cc @@ -0,0 +1,40 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2009 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <lemon/random.h> +#include "test_tools.h" + +int seed_array[] = {1, 2}; + +int main() +{ + double a=lemon::rnd(); + check(a<1.0&&a>0.0,"This should be in [0,1)"); + a=lemon::rnd.gauss(); + a=lemon::rnd.gamma(3.45,0); + a=lemon::rnd.gamma(4); + //Does gamma work with integer k? + a=lemon::rnd.gamma(4.0,0); + a=lemon::rnd.poisson(.5); + + lemon::rnd.seed(100); + lemon::rnd.seed(seed_array, seed_array + + (sizeof(seed_array) / sizeof(seed_array[0]))); + + return 0; +} diff --git a/lemon/test/suurballe_test.cc b/lemon/test/suurballe_test.cc new file mode 100644 index 0000000..5e3edad --- /dev/null +++ b/lemon/test/suurballe_test.cc @@ -0,0 +1,265 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <iostream> + +#include <lemon/list_graph.h> +#include <lemon/lgf_reader.h> +#include <lemon/path.h> +#include <lemon/suurballe.h> +#include <lemon/concepts/digraph.h> +#include <lemon/concepts/heap.h> + +#include "test_tools.h" + +using namespace lemon; + +char test_lgf[] = + "@nodes\n" + "label\n" + "1\n" + "2\n" + "3\n" + "4\n" + "5\n" + "6\n" + "7\n" + "8\n" + "9\n" + "10\n" + "11\n" + "12\n" + "@arcs\n" + " length\n" + " 1 2 70\n" + " 1 3 150\n" + " 1 4 80\n" + " 2 8 80\n" + " 3 5 140\n" + " 4 6 60\n" + " 4 7 80\n" + " 4 8 110\n" + " 5 7 60\n" + " 5 11 120\n" + " 6 3 0\n" + " 6 9 140\n" + " 6 10 90\n" + " 7 1 30\n" + " 8 12 60\n" + " 9 12 50\n" + "10 12 70\n" + "10 2 100\n" + "10 7 60\n" + "11 10 20\n" + "12 11 30\n" + "@attributes\n" + "source 1\n" + "target 12\n" + "@end\n"; + +// Check the interface of Suurballe +void checkSuurballeCompile() +{ + typedef int VType; + typedef concepts::Digraph Digraph; + + typedef Digraph::Node Node; + typedef Digraph::Arc Arc; + typedef concepts::ReadMap<Arc, VType> LengthMap; + + typedef Suurballe<Digraph, LengthMap> ST; + typedef Suurballe<Digraph, LengthMap> + ::SetFlowMap<ST::FlowMap> + ::SetPotentialMap<ST::PotentialMap> + ::SetPath<SimplePath<Digraph> > + ::SetHeap<concepts::Heap<VType, Digraph::NodeMap<int> > > + ::Create SuurballeType; + + Digraph g; + Node n; + Arc e; + LengthMap len; + SuurballeType::FlowMap flow(g); + SuurballeType::PotentialMap pi(g); + + SuurballeType suurb_test(g, len); + const SuurballeType& const_suurb_test = suurb_test; + + suurb_test + .flowMap(flow) + .potentialMap(pi); + + int k; + k = suurb_test.run(n, n); + k = suurb_test.run(n, n, k); + suurb_test.init(n); + suurb_test.fullInit(n); + suurb_test.start(n); + suurb_test.start(n, k); + k = suurb_test.findFlow(n); + k = suurb_test.findFlow(n, k); + suurb_test.findPaths(); + + int f; + VType c; + c = const_suurb_test.totalLength(); + f = const_suurb_test.flow(e); + const SuurballeType::FlowMap& fm = + const_suurb_test.flowMap(); + c = const_suurb_test.potential(n); + const SuurballeType::PotentialMap& pm = + const_suurb_test.potentialMap(); + k = const_suurb_test.pathNum(); + Path<Digraph> p = const_suurb_test.path(k); + + ignore_unused_variable_warning(fm); + ignore_unused_variable_warning(pm); +} + +// Check the feasibility of the flow +template <typename Digraph, typename FlowMap> +bool checkFlow( const Digraph& gr, const FlowMap& flow, + typename Digraph::Node s, typename Digraph::Node t, + int value ) +{ + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + for (ArcIt e(gr); e != INVALID; ++e) + if (!(flow[e] == 0 || flow[e] == 1)) return false; + + for (NodeIt n(gr); n != INVALID; ++n) { + int sum = 0; + for (OutArcIt e(gr, n); e != INVALID; ++e) + sum += flow[e]; + for (InArcIt e(gr, n); e != INVALID; ++e) + sum -= flow[e]; + if (n == s && sum != value) return false; + if (n == t && sum != -value) return false; + if (n != s && n != t && sum != 0) return false; + } + + return true; +} + +// Check the optimalitiy of the flow +template < typename Digraph, typename CostMap, + typename FlowMap, typename PotentialMap > +bool checkOptimality( const Digraph& gr, const CostMap& cost, + const FlowMap& flow, const PotentialMap& pi ) +{ + // Check the "Complementary Slackness" optimality condition + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + bool opt = true; + for (ArcIt e(gr); e != INVALID; ++e) { + typename CostMap::Value red_cost = + cost[e] + pi[gr.source(e)] - pi[gr.target(e)]; + opt = (flow[e] == 0 && red_cost >= 0) || + (flow[e] == 1 && red_cost <= 0); + if (!opt) break; + } + return opt; +} + +// Check a path +template <typename Digraph, typename Path> +bool checkPath( const Digraph& gr, const Path& path, + typename Digraph::Node s, typename Digraph::Node t) +{ + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + Node n = s; + for (int i = 0; i < path.length(); ++i) { + if (gr.source(path.nth(i)) != n) return false; + n = gr.target(path.nth(i)); + } + return n == t; +} + + +int main() +{ + DIGRAPH_TYPEDEFS(ListDigraph); + + // Read the test digraph + ListDigraph digraph; + ListDigraph::ArcMap<int> length(digraph); + Node s, t; + + std::istringstream input(test_lgf); + DigraphReader<ListDigraph>(digraph, input). + arcMap("length", length). + node("source", s). + node("target", t). + run(); + + // Check run() + { + Suurballe<ListDigraph> suurballe(digraph, length); + + // Find 2 paths + check(suurballe.run(s, t) == 2, "Wrong number of paths"); + check(checkFlow(digraph, suurballe.flowMap(), s, t, 2), + "The flow is not feasible"); + check(suurballe.totalLength() == 510, "The flow is not optimal"); + check(checkOptimality(digraph, length, suurballe.flowMap(), + suurballe.potentialMap()), + "Wrong potentials"); + for (int i = 0; i < suurballe.pathNum(); ++i) + check(checkPath(digraph, suurballe.path(i), s, t), "Wrong path"); + + // Find 3 paths + check(suurballe.run(s, t, 3) == 3, "Wrong number of paths"); + check(checkFlow(digraph, suurballe.flowMap(), s, t, 3), + "The flow is not feasible"); + check(suurballe.totalLength() == 1040, "The flow is not optimal"); + check(checkOptimality(digraph, length, suurballe.flowMap(), + suurballe.potentialMap()), + "Wrong potentials"); + for (int i = 0; i < suurballe.pathNum(); ++i) + check(checkPath(digraph, suurballe.path(i), s, t), "Wrong path"); + + // Find 5 paths (only 3 can be found) + check(suurballe.run(s, t, 5) == 3, "Wrong number of paths"); + check(checkFlow(digraph, suurballe.flowMap(), s, t, 3), + "The flow is not feasible"); + check(suurballe.totalLength() == 1040, "The flow is not optimal"); + check(checkOptimality(digraph, length, suurballe.flowMap(), + suurballe.potentialMap()), + "Wrong potentials"); + for (int i = 0; i < suurballe.pathNum(); ++i) + check(checkPath(digraph, suurballe.path(i), s, t), "Wrong path"); + } + + // Check fullInit() + start() + { + Suurballe<ListDigraph> suurballe(digraph, length); + suurballe.fullInit(s); + + // Find 2 paths + check(suurballe.start(t) == 2, "Wrong number of paths"); + check(suurballe.totalLength() == 510, "The flow is not optimal"); + + // Find 3 paths + check(suurballe.start(t, 3) == 3, "Wrong number of paths"); + check(suurballe.totalLength() == 1040, "The flow is not optimal"); + + // Find 5 paths (only 3 can be found) + check(suurballe.start(t, 5) == 3, "Wrong number of paths"); + check(suurballe.totalLength() == 1040, "The flow is not optimal"); + } + + return 0; +} diff --git a/lemon/test/test_tools.h b/lemon/test/test_tools.h new file mode 100644 index 0000000..3300356 --- /dev/null +++ b/lemon/test/test_tools.h @@ -0,0 +1,50 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#ifndef LEMON_TEST_TEST_TOOLS_H +#define LEMON_TEST_TEST_TOOLS_H + +///\ingroup misc +///\file +///\brief Some utilities to write test programs. + +#include <iostream> +#include <stdlib.h> + +///If \c rc is fail, writes an error message and exits. + +///If \c rc is fail, writes an error message and exits. +///The error message contains the file name and the line number of the +///source code in a standard from, which makes it possible to go there +///using good source browsers like e.g. \c emacs. +/// +///For example +///\code check(0==1,"This is obviously false.");\endcode will +///print something like this (and then exits). +///\verbatim file_name.cc:123: error: This is obviously false. \endverbatim +#define check(rc, msg) \ + { \ + if(!(rc)) { \ + std::cerr << __FILE__ ":" << __LINE__ << ": error: " \ + << msg << std::endl; \ + abort(); \ + } else { } \ + } \ + + +#endif diff --git a/lemon/test/test_tools_fail.cc b/lemon/test/test_tools_fail.cc new file mode 100644 index 0000000..6407cd1 --- /dev/null +++ b/lemon/test/test_tools_fail.cc @@ -0,0 +1,25 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2009 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include "test_tools.h" + +int main() +{ + check(false, "Don't panic. Failing is the right behaviour here."); + return 0; +} diff --git a/lemon/test/test_tools_pass.cc b/lemon/test/test_tools_pass.cc new file mode 100644 index 0000000..b590c15 --- /dev/null +++ b/lemon/test/test_tools_pass.cc @@ -0,0 +1,25 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2009 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include "test_tools.h" + +int main() +{ + check(true, "It should pass."); + return 0; +} diff --git a/lemon/test/time_measure_test.cc b/lemon/test/time_measure_test.cc new file mode 100644 index 0000000..5ae5aa1 --- /dev/null +++ b/lemon/test/time_measure_test.cc @@ -0,0 +1,56 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2009 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <lemon/time_measure.h> + +using namespace lemon; + +void f() +{ + double d=0; + for(int i=0;i<1000;i++) + d+=0.1; +} + +void g() +{ + static Timer T; + + for(int i=0;i<1000;i++) + TimeStamp x(T); +} + +int main() +{ + Timer T; + unsigned int n; + for(n=0;T.realTime()<0.1;n++) ; + std::cout << T << " (" << n << " time queries)\n"; + + TimeStamp full; + TimeStamp t; + t=runningTimeTest(f,0.1,&n,&full); + std::cout << t << " (" << n << " tests)\n"; + std::cout << "Total: " << full << "\n"; + + t=runningTimeTest(g,0.1,&n,&full); + std::cout << t << " (" << n << " tests)\n"; + std::cout << "Total: " << full << "\n"; + + return 0; +} diff --git a/lemon/test/unionfind_test.cc b/lemon/test/unionfind_test.cc new file mode 100644 index 0000000..e82d8e6 --- /dev/null +++ b/lemon/test/unionfind_test.cc @@ -0,0 +1,102 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2009 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include <lemon/list_graph.h> +#include <lemon/maps.h> +#include <lemon/unionfind.h> +#include "test_tools.h" + +using namespace lemon; +using namespace std; + +typedef UnionFindEnum<ListGraph::NodeMap<int> > UFE; + +int main() { + ListGraph g; + ListGraph::NodeMap<int> base(g); + UFE U(base); + vector<ListGraph::Node> n; + + for(int i=0;i<20;i++) n.push_back(g.addNode()); + + U.insert(n[1]); + U.insert(n[2]); + + check(U.join(n[1],n[2]) != -1, "Something is wrong with UnionFindEnum"); + + U.insert(n[3]); + U.insert(n[4]); + U.insert(n[5]); + U.insert(n[6]); + U.insert(n[7]); + + + check(U.join(n[1],n[4]) != -1, "Something is wrong with UnionFindEnum"); + check(U.join(n[2],n[4]) == -1, "Something is wrong with UnionFindEnum"); + check(U.join(n[3],n[5]) != -1, "Something is wrong with UnionFindEnum"); + + + U.insert(n[8],U.find(n[5])); + + + check(U.size(U.find(n[4])) == 3, "Something is wrong with UnionFindEnum"); + check(U.size(U.find(n[5])) == 3, "Something is wrong with UnionFindEnum"); + check(U.size(U.find(n[6])) == 1, "Something is wrong with UnionFindEnum"); + check(U.size(U.find(n[2])) == 3, "Something is wrong with UnionFindEnum"); + + + U.insert(n[9]); + U.insert(n[10],U.find(n[9])); + + + check(U.join(n[8],n[10]) != -1, "Something is wrong with UnionFindEnum"); + + + check(U.size(U.find(n[4])) == 3, "Something is wrong with UnionFindEnum"); + check(U.size(U.find(n[9])) == 5, "Something is wrong with UnionFindEnum"); + + check(U.size(U.find(n[8])) == 5, "Something is wrong with UnionFindEnum"); + + U.erase(n[9]); + U.erase(n[1]); + + check(U.size(U.find(n[10])) == 4, "Something is wrong with UnionFindEnum"); + check(U.size(U.find(n[2])) == 2, "Something is wrong with UnionFindEnum"); + + U.erase(n[6]); + U.split(U.find(n[8])); + + + check(U.size(U.find(n[4])) == 2, "Something is wrong with UnionFindEnum"); + check(U.size(U.find(n[3])) == 1, "Something is wrong with UnionFindEnum"); + check(U.size(U.find(n[2])) == 2, "Something is wrong with UnionFindEnum"); + + + check(U.join(n[3],n[4]) != -1, "Something is wrong with UnionFindEnum"); + check(U.join(n[2],n[4]) == -1, "Something is wrong with UnionFindEnum"); + + + check(U.size(U.find(n[4])) == 3, "Something is wrong with UnionFindEnum"); + check(U.size(U.find(n[3])) == 3, "Something is wrong with UnionFindEnum"); + check(U.size(U.find(n[2])) == 3, "Something is wrong with UnionFindEnum"); + + U.eraseClass(U.find(n[4])); + U.eraseClass(U.find(n[7])); + + return 0; +} |