summaryrefslogtreecommitdiff
path: root/lemon/test
diff options
context:
space:
mode:
authorCarlo Zancanaro <carlo@pc-4w14-0.cs.usyd.edu.au>2012-07-10 13:44:21 +1000
committerCarlo Zancanaro <carlo@pc-4w14-0.cs.usyd.edu.au>2012-07-10 13:44:21 +1000
commitef4a319984d22b88a9024ff523700d657621124d (patch)
tree2821db78ccd6ce61ca64ad6fc98ba825b060ca6a /lemon/test
parentd3f13fdd23e17a8f4bb4083c24fee331a28351eb (diff)
Add the LEMON graph library source to the repo
I'll likely be using it, so this just makes it easier to get to from elsewhere. If I end up not using it then I can just delete it.
Diffstat (limited to 'lemon/test')
-rw-r--r--lemon/test/.deps/adaptors_test.Po1
-rw-r--r--lemon/test/.deps/bellman_ford_test.Po1
-rw-r--r--lemon/test/.deps/bfs_test.Po1
-rw-r--r--lemon/test/.deps/circulation_test.Po1
-rw-r--r--lemon/test/.deps/connectivity_test.Po1
-rw-r--r--lemon/test/.deps/counter_test.Po1
-rw-r--r--lemon/test/.deps/dfs_test.Po1
-rw-r--r--lemon/test/.deps/digraph_test.Po1
-rw-r--r--lemon/test/.deps/dijkstra_test.Po1
-rw-r--r--lemon/test/.deps/dim_test.Po1
-rw-r--r--lemon/test/.deps/edge_set_test.Po1
-rw-r--r--lemon/test/.deps/error_test.Po1
-rw-r--r--lemon/test/.deps/euler_test.Po1
-rw-r--r--lemon/test/.deps/fractional_matching_test.Po1
-rw-r--r--lemon/test/.deps/gomory_hu_test.Po1
-rw-r--r--lemon/test/.deps/graph_copy_test.Po1
-rw-r--r--lemon/test/.deps/graph_test.Po1
-rw-r--r--lemon/test/.deps/graph_utils_test.Po1
-rw-r--r--lemon/test/.deps/hao_orlin_test.Po1
-rw-r--r--lemon/test/.deps/heap_test.Po1
-rw-r--r--lemon/test/.deps/kruskal_test.Po1
-rw-r--r--lemon/test/.deps/lgf_test.Po1
-rw-r--r--lemon/test/.deps/lp_test.Po1
-rw-r--r--lemon/test/.deps/maps_test.Po1
-rw-r--r--lemon/test/.deps/matching_test.Po1
-rw-r--r--lemon/test/.deps/min_cost_arborescence_test.Po1
-rw-r--r--lemon/test/.deps/min_cost_flow_test.Po1
-rw-r--r--lemon/test/.deps/min_mean_cycle_test.Po1
-rw-r--r--lemon/test/.deps/mip_test.Po1
-rw-r--r--lemon/test/.deps/path_test.Po1
-rw-r--r--lemon/test/.deps/planarity_test.Po1
-rw-r--r--lemon/test/.deps/preflow_test.Po1
-rw-r--r--lemon/test/.deps/radix_sort_test.Po1
-rw-r--r--lemon/test/.deps/random_test.Po1
-rw-r--r--lemon/test/.deps/suurballe_test.Po1
-rw-r--r--lemon/test/.deps/test_tools_fail.Po1
-rw-r--r--lemon/test/.deps/test_tools_pass.Po1
-rw-r--r--lemon/test/.deps/time_measure_test.Po1
-rw-r--r--lemon/test/.deps/unionfind_test.Po1
-rw-r--r--lemon/test/CMakeLists.txt151
-rw-r--r--lemon/test/Makefile.am101
-rw-r--r--lemon/test/adaptors_test.cc1463
-rw-r--r--lemon/test/bellman_ford_test.cc285
-rw-r--r--lemon/test/bfs_test.cc236
-rw-r--r--lemon/test/circulation_test.cc168
-rw-r--r--lemon/test/connectivity_test.cc297
-rw-r--r--lemon/test/counter_test.cc118
-rw-r--r--lemon/test/dfs_test.cc234
-rw-r--r--lemon/test/digraph_test.cc562
-rw-r--r--lemon/test/dijkstra_test.cc242
-rw-r--r--lemon/test/dim_test.cc87
-rw-r--r--lemon/test/edge_set_test.cc380
-rw-r--r--lemon/test/error_test.cc90
-rw-r--r--lemon/test/euler_test.cc223
-rw-r--r--lemon/test/fractional_matching_test.cc525
-rw-r--r--lemon/test/gomory_hu_test.cc141
-rw-r--r--lemon/test/graph_copy_test.cc215
-rw-r--r--lemon/test/graph_test.cc597
-rw-r--r--lemon/test/graph_test.h293
-rw-r--r--lemon/test/graph_utils_test.cc217
-rw-r--r--lemon/test/hao_orlin_test.cc163
-rw-r--r--lemon/test/heap_test.cc310
-rw-r--r--lemon/test/kruskal_test.cc147
-rw-r--r--lemon/test/lgf_test.cc169
-rw-r--r--lemon/test/lp_test.cc427
-rw-r--r--lemon/test/maps_test.cc1003
-rw-r--r--lemon/test/matching_test.cc448
-rw-r--r--lemon/test/min_cost_arborescence_test.cc206
-rw-r--r--lemon/test/min_cost_flow_test.cc542
-rw-r--r--lemon/test/min_mean_cycle_test.cc216
-rw-r--r--lemon/test/mip_test.cc159
-rw-r--r--lemon/test/path_test.cc44
-rw-r--r--lemon/test/planarity_test.cc262
-rw-r--r--lemon/test/preflow_test.cc276
-rw-r--r--lemon/test/radix_sort_test.cc147
-rw-r--r--lemon/test/random_test.cc40
-rw-r--r--lemon/test/suurballe_test.cc265
-rw-r--r--lemon/test/test_tools.h50
-rw-r--r--lemon/test/test_tools_fail.cc25
-rw-r--r--lemon/test/test_tools_pass.cc25
-rw-r--r--lemon/test/time_measure_test.cc56
-rw-r--r--lemon/test/unionfind_test.cc102
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;
+}