From 57e55906f04a48a951fbbcfd7c197eef35ad4387 Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Mon, 26 Aug 2019 18:34:11 +0200 Subject: Add QuadriFlow remesher --- extern/CMakeLists.txt | 5 + extern/quadriflow/3rd/lemon-1.3.1/AUTHORS | 26 + extern/quadriflow/3rd/lemon-1.3.1/CMakeLists.txt | 373 ++ extern/quadriflow/3rd/lemon-1.3.1/INSTALL | 167 + extern/quadriflow/3rd/lemon-1.3.1/LICENSE | 32 + extern/quadriflow/3rd/lemon-1.3.1/NEWS | 337 ++ extern/quadriflow/3rd/lemon-1.3.1/README | 50 + .../3rd/lemon-1.3.1/cmake/FindCOIN.cmake | 110 + .../3rd/lemon-1.3.1/cmake/FindGLPK.cmake | 55 + .../3rd/lemon-1.3.1/cmake/FindGhostscript.cmake | 10 + .../3rd/lemon-1.3.1/cmake/FindILOG.cmake | 102 + .../3rd/lemon-1.3.1/cmake/FindSOPLEX.cmake | 23 + .../3rd/lemon-1.3.1/cmake/LEMONConfig.cmake.in | 13 + .../3rd/lemon-1.3.1/cmake/nsis/lemon.ico | Bin 0 -> 22486 bytes .../3rd/lemon-1.3.1/cmake/nsis/uninstall.ico | Bin 0 -> 15086 bytes .../quadriflow/3rd/lemon-1.3.1/cmake/version.cmake | 1 + .../3rd/lemon-1.3.1/cmake/version.cmake.in | 1 + .../3rd/lemon-1.3.1/contrib/CMakeLists.txt | 19 + .../quadriflow/3rd/lemon-1.3.1/demo/CMakeLists.txt | 19 + .../3rd/lemon-1.3.1/demo/arg_parser_demo.cc | 112 + extern/quadriflow/3rd/lemon-1.3.1/demo/digraph.lgf | 29 + .../3rd/lemon-1.3.1/demo/graph_to_eps_demo.cc | 206 + extern/quadriflow/3rd/lemon-1.3.1/demo/lgf_demo.cc | 70 + .../3rd/lemon-1.3.1/lemon/CMakeLists.txt | 91 + extern/quadriflow/3rd/lemon-1.3.1/lemon/adaptors.h | 3638 ++++++++++++++++++ .../quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.cc | 474 +++ .../quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.h | 440 +++ extern/quadriflow/3rd/lemon-1.3.1/lemon/assert.h | 214 ++ extern/quadriflow/3rd/lemon-1.3.1/lemon/base.cc | 37 + .../3rd/lemon-1.3.1/lemon/bellman_ford.h | 1116 ++++++ extern/quadriflow/3rd/lemon-1.3.1/lemon/bfs.h | 1754 +++++++++ extern/quadriflow/3rd/lemon-1.3.1/lemon/bin_heap.h | 347 ++ .../3rd/lemon-1.3.1/lemon/binomial_heap.h | 445 +++ .../lemon-1.3.1/lemon/bits/alteration_notifier.h | 472 +++ .../3rd/lemon-1.3.1/lemon/bits/array_map.h | 351 ++ .../quadriflow/3rd/lemon-1.3.1/lemon/bits/bezier.h | 174 + .../3rd/lemon-1.3.1/lemon/bits/default_map.h | 182 + .../3rd/lemon-1.3.1/lemon/bits/edge_set_extender.h | 627 +++ .../3rd/lemon-1.3.1/lemon/bits/enable_if.h | 131 + .../lemon/bits/graph_adaptor_extender.h | 401 ++ .../3rd/lemon-1.3.1/lemon/bits/graph_extender.h | 1332 +++++++ .../quadriflow/3rd/lemon-1.3.1/lemon/bits/lock.h | 65 + .../3rd/lemon-1.3.1/lemon/bits/map_extender.h | 332 ++ .../3rd/lemon-1.3.1/lemon/bits/path_dump.h | 177 + .../3rd/lemon-1.3.1/lemon/bits/solver_bits.h | 194 + .../quadriflow/3rd/lemon-1.3.1/lemon/bits/traits.h | 388 ++ .../3rd/lemon-1.3.1/lemon/bits/variant.h | 494 +++ .../3rd/lemon-1.3.1/lemon/bits/vector_map.h | 244 ++ .../3rd/lemon-1.3.1/lemon/bits/windows.cc | 166 + .../3rd/lemon-1.3.1/lemon/bits/windows.h | 44 + .../quadriflow/3rd/lemon-1.3.1/lemon/bucket_heap.h | 594 +++ .../3rd/lemon-1.3.1/lemon/capacity_scaling.h | 1014 +++++ extern/quadriflow/3rd/lemon-1.3.1/lemon/cbc.cc | 460 +++ extern/quadriflow/3rd/lemon-1.3.1/lemon/cbc.h | 129 + .../3rd/lemon-1.3.1/lemon/christofides_tsp.h | 254 ++ .../quadriflow/3rd/lemon-1.3.1/lemon/circulation.h | 807 ++++ extern/quadriflow/3rd/lemon-1.3.1/lemon/clp.cc | 464 +++ extern/quadriflow/3rd/lemon-1.3.1/lemon/clp.h | 164 + extern/quadriflow/3rd/lemon-1.3.1/lemon/color.cc | 44 + extern/quadriflow/3rd/lemon-1.3.1/lemon/color.h | 204 + .../3rd/lemon-1.3.1/lemon/concept_check.h | 77 + .../3rd/lemon-1.3.1/lemon/concepts/bpgraph.h | 1029 +++++ .../3rd/lemon-1.3.1/lemon/concepts/digraph.h | 491 +++ .../3rd/lemon-1.3.1/lemon/concepts/graph.h | 788 ++++ .../lemon-1.3.1/lemon/concepts/graph_components.h | 2134 ++++++++++ .../3rd/lemon-1.3.1/lemon/concepts/heap.h | 324 ++ .../3rd/lemon-1.3.1/lemon/concepts/maps.h | 223 ++ .../3rd/lemon-1.3.1/lemon/concepts/path.h | 312 ++ extern/quadriflow/3rd/lemon-1.3.1/lemon/config.h | 22 + .../quadriflow/3rd/lemon-1.3.1/lemon/config.h.in | 22 + .../3rd/lemon-1.3.1/lemon/connectivity.h | 1688 ++++++++ extern/quadriflow/3rd/lemon-1.3.1/lemon/core.h | 2506 ++++++++++++ .../3rd/lemon-1.3.1/lemon/cost_scaling.h | 1607 ++++++++ extern/quadriflow/3rd/lemon-1.3.1/lemon/counter.h | 249 ++ extern/quadriflow/3rd/lemon-1.3.1/lemon/cplex.cc | 994 +++++ extern/quadriflow/3rd/lemon-1.3.1/lemon/cplex.h | 292 ++ .../3rd/lemon-1.3.1/lemon/cycle_canceling.h | 1230 ++++++ extern/quadriflow/3rd/lemon-1.3.1/lemon/dfs.h | 1637 ++++++++ extern/quadriflow/3rd/lemon-1.3.1/lemon/dheap.h | 352 ++ extern/quadriflow/3rd/lemon-1.3.1/lemon/dijkstra.h | 1303 +++++++ extern/quadriflow/3rd/lemon-1.3.1/lemon/dim2.h | 726 ++++ extern/quadriflow/3rd/lemon-1.3.1/lemon/dimacs.h | 448 +++ extern/quadriflow/3rd/lemon-1.3.1/lemon/edge_set.h | 1420 +++++++ .../3rd/lemon-1.3.1/lemon/edmonds_karp.h | 556 +++ extern/quadriflow/3rd/lemon-1.3.1/lemon/elevator.h | 982 +++++ extern/quadriflow/3rd/lemon-1.3.1/lemon/error.h | 276 ++ extern/quadriflow/3rd/lemon-1.3.1/lemon/euler.h | 287 ++ extern/quadriflow/3rd/lemon-1.3.1/lemon/fib_heap.h | 475 +++ .../3rd/lemon-1.3.1/lemon/fractional_matching.h | 2139 +++++++++++ .../quadriflow/3rd/lemon-1.3.1/lemon/full_graph.h | 1082 ++++++ extern/quadriflow/3rd/lemon-1.3.1/lemon/glpk.cc | 1012 +++++ extern/quadriflow/3rd/lemon-1.3.1/lemon/glpk.h | 263 ++ .../quadriflow/3rd/lemon-1.3.1/lemon/gomory_hu.h | 568 +++ .../3rd/lemon-1.3.1/lemon/graph_to_eps.h | 1186 ++++++ .../quadriflow/3rd/lemon-1.3.1/lemon/greedy_tsp.h | 251 ++ .../quadriflow/3rd/lemon-1.3.1/lemon/grid_graph.h | 699 ++++ .../lemon-1.3.1/lemon/grosso_locatelli_pullan_mc.h | 840 ++++ .../quadriflow/3rd/lemon-1.3.1/lemon/hao_orlin.h | 1015 +++++ .../3rd/lemon-1.3.1/lemon/hartmann_orlin_mmc.h | 654 ++++ .../quadriflow/3rd/lemon-1.3.1/lemon/howard_mmc.h | 651 ++++ .../3rd/lemon-1.3.1/lemon/hypercube_graph.h | 459 +++ .../3rd/lemon-1.3.1/lemon/insertion_tsp.h | 533 +++ extern/quadriflow/3rd/lemon-1.3.1/lemon/karp_mmc.h | 590 +++ extern/quadriflow/3rd/lemon-1.3.1/lemon/kruskal.h | 324 ++ .../quadriflow/3rd/lemon-1.3.1/lemon/lemon.pc.in | 10 + .../quadriflow/3rd/lemon-1.3.1/lemon/lgf_reader.h | 3854 +++++++++++++++++++ .../quadriflow/3rd/lemon-1.3.1/lemon/lgf_writer.h | 2687 +++++++++++++ .../quadriflow/3rd/lemon-1.3.1/lemon/list_graph.h | 2510 ++++++++++++ extern/quadriflow/3rd/lemon-1.3.1/lemon/lp.h | 95 + extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_base.cc | 30 + extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_base.h | 2147 +++++++++++ .../3rd/lemon-1.3.1/lemon/lp_skeleton.cc | 143 + .../quadriflow/3rd/lemon-1.3.1/lemon/lp_skeleton.h | 234 ++ extern/quadriflow/3rd/lemon-1.3.1/lemon/maps.h | 4057 ++++++++++++++++++++ extern/quadriflow/3rd/lemon-1.3.1/lemon/matching.h | 3505 +++++++++++++++++ extern/quadriflow/3rd/lemon-1.3.1/lemon/math.h | 77 + .../3rd/lemon-1.3.1/lemon/max_cardinality_search.h | 794 ++++ .../3rd/lemon-1.3.1/lemon/min_cost_arborescence.h | 808 ++++ .../3rd/lemon-1.3.1/lemon/nagamochi_ibaraki.h | 702 ++++ .../3rd/lemon-1.3.1/lemon/nauty_reader.h | 113 + .../3rd/lemon-1.3.1/lemon/nearest_neighbor_tsp.h | 238 ++ .../3rd/lemon-1.3.1/lemon/network_simplex.h | 1659 ++++++++ extern/quadriflow/3rd/lemon-1.3.1/lemon/opt2_tsp.h | 367 ++ .../3rd/lemon-1.3.1/lemon/pairing_heap.h | 474 +++ extern/quadriflow/3rd/lemon-1.3.1/lemon/path.h | 1164 ++++++ .../quadriflow/3rd/lemon-1.3.1/lemon/planarity.h | 2754 +++++++++++++ extern/quadriflow/3rd/lemon-1.3.1/lemon/preflow.h | 985 +++++ .../quadriflow/3rd/lemon-1.3.1/lemon/quad_heap.h | 343 ++ .../quadriflow/3rd/lemon-1.3.1/lemon/radix_heap.h | 438 +++ .../quadriflow/3rd/lemon-1.3.1/lemon/radix_sort.h | 487 +++ extern/quadriflow/3rd/lemon-1.3.1/lemon/random.cc | 29 + extern/quadriflow/3rd/lemon-1.3.1/lemon/random.h | 1005 +++++ .../quadriflow/3rd/lemon-1.3.1/lemon/smart_graph.h | 1344 +++++++ extern/quadriflow/3rd/lemon-1.3.1/lemon/soplex.cc | 465 +++ extern/quadriflow/3rd/lemon-1.3.1/lemon/soplex.h | 158 + .../3rd/lemon-1.3.1/lemon/static_graph.h | 476 +++ .../quadriflow/3rd/lemon-1.3.1/lemon/suurballe.h | 776 ++++ .../3rd/lemon-1.3.1/lemon/time_measure.h | 610 +++ .../quadriflow/3rd/lemon-1.3.1/lemon/tolerance.h | 242 ++ .../quadriflow/3rd/lemon-1.3.1/lemon/unionfind.h | 1824 +++++++++ .../3rd/lemon-1.3.1/scripts/unify-sources.sh | 390 ++ .../3rd/lemon-1.3.1/scripts/valgrind-wrapper.sh | 22 + .../quadriflow/3rd/lemon-1.3.1/test/CMakeLists.txt | 161 + .../3rd/lemon-1.3.1/test/adaptors_test.cc | 1468 +++++++ .../3rd/lemon-1.3.1/test/arc_look_up_test.cc | 84 + .../3rd/lemon-1.3.1/test/bellman_ford_test.cc | 289 ++ extern/quadriflow/3rd/lemon-1.3.1/test/bfs_test.cc | 239 ++ .../3rd/lemon-1.3.1/test/bpgraph_test.cc | 456 +++ .../3rd/lemon-1.3.1/test/circulation_test.cc | 169 + .../3rd/lemon-1.3.1/test/connectivity_test.cc | 316 ++ .../3rd/lemon-1.3.1/test/counter_test.cc | 118 + extern/quadriflow/3rd/lemon-1.3.1/test/dfs_test.cc | 238 ++ .../3rd/lemon-1.3.1/test/digraph_test.cc | 569 +++ .../3rd/lemon-1.3.1/test/dijkstra_test.cc | 246 ++ extern/quadriflow/3rd/lemon-1.3.1/test/dim_test.cc | 87 + .../3rd/lemon-1.3.1/test/edge_set_test.cc | 396 ++ .../quadriflow/3rd/lemon-1.3.1/test/error_test.cc | 90 + .../quadriflow/3rd/lemon-1.3.1/test/euler_test.cc | 225 ++ .../lemon-1.3.1/test/fractional_matching_test.cc | 527 +++ .../3rd/lemon-1.3.1/test/gomory_hu_test.cc | 142 + .../3rd/lemon-1.3.1/test/graph_copy_test.cc | 388 ++ .../quadriflow/3rd/lemon-1.3.1/test/graph_test.cc | 603 +++ .../quadriflow/3rd/lemon-1.3.1/test/graph_test.h | 421 ++ .../3rd/lemon-1.3.1/test/graph_utils_test.cc | 217 ++ .../3rd/lemon-1.3.1/test/hao_orlin_test.cc | 164 + .../quadriflow/3rd/lemon-1.3.1/test/heap_test.cc | 310 ++ .../3rd/lemon-1.3.1/test/kruskal_test.cc | 147 + .../3rd/lemon-1.3.1/test/lgf_reader_writer_test.cc | 578 +++ extern/quadriflow/3rd/lemon-1.3.1/test/lgf_test.cc | 169 + extern/quadriflow/3rd/lemon-1.3.1/test/lp_test.cc | 470 +++ .../quadriflow/3rd/lemon-1.3.1/test/maps_test.cc | 1022 +++++ .../3rd/lemon-1.3.1/test/matching_test.cc | 449 +++ .../test/max_cardinality_search_test.cc | 162 + .../3rd/lemon-1.3.1/test/max_clique_test.cc | 188 + .../3rd/lemon-1.3.1/test/max_flow_test.cc | 395 ++ .../lemon-1.3.1/test/min_cost_arborescence_test.cc | 207 + .../3rd/lemon-1.3.1/test/min_cost_flow_test.cc | 548 +++ .../3rd/lemon-1.3.1/test/min_mean_cycle_test.cc | 223 ++ extern/quadriflow/3rd/lemon-1.3.1/test/mip_test.cc | 171 + .../3rd/lemon-1.3.1/test/nagamochi_ibaraki_test.cc | 142 + .../quadriflow/3rd/lemon-1.3.1/test/path_test.cc | 339 ++ .../3rd/lemon-1.3.1/test/planarity_test.cc | 262 ++ .../3rd/lemon-1.3.1/test/radix_sort_test.cc | 266 ++ .../quadriflow/3rd/lemon-1.3.1/test/random_test.cc | 40 + .../3rd/lemon-1.3.1/test/suurballe_test.cc | 267 ++ .../quadriflow/3rd/lemon-1.3.1/test/test_tools.h | 50 + .../3rd/lemon-1.3.1/test/test_tools_fail.cc | 25 + .../3rd/lemon-1.3.1/test/test_tools_pass.cc | 25 + .../3rd/lemon-1.3.1/test/time_measure_test.cc | 60 + extern/quadriflow/3rd/lemon-1.3.1/test/tsp_test.cc | 287 ++ .../3rd/lemon-1.3.1/test/unionfind_test.cc | 102 + .../3rd/lemon-1.3.1/tools/CMakeLists.txt | 31 + .../3rd/lemon-1.3.1/tools/dimacs-solver.cc | 279 ++ .../3rd/lemon-1.3.1/tools/dimacs-to-lgf.cc | 148 + .../3rd/lemon-1.3.1/tools/lemon-0.x-to-1.x.sh | 134 + extern/quadriflow/3rd/lemon-1.3.1/tools/lgf-gen.cc | 847 ++++ extern/quadriflow/3rd/pcg32/pcg32/pcg32.h | 209 + .../quadriflow/3rd/pss/pss/parallel_stable_sort.h | 140 + extern/quadriflow/3rd/pss/pss/pss_common.h | 106 + extern/quadriflow/CMakeLists.txt | 105 + extern/quadriflow/LICENSE.txt | 37 + extern/quadriflow/README.md | 134 + extern/quadriflow/src/Optimizer.cu | 281 ++ extern/quadriflow/src/adjacent-matrix.cpp | 35 + extern/quadriflow/src/adjacent-matrix.hpp | 37 + extern/quadriflow/src/compare-key.hpp | 102 + extern/quadriflow/src/config.hpp | 34 + extern/quadriflow/src/dedge.cpp | 487 +++ extern/quadriflow/src/dedge.hpp | 25 + extern/quadriflow/src/disajoint-tree.hpp | 151 + extern/quadriflow/src/dset.hpp | 163 + extern/quadriflow/src/field-math.hpp | 483 +++ extern/quadriflow/src/flow.hpp | 375 ++ extern/quadriflow/src/hierarchy.cpp | 1343 +++++++ extern/quadriflow/src/hierarchy.hpp | 99 + extern/quadriflow/src/loader.cpp | 159 + extern/quadriflow/src/loader.hpp | 15 + extern/quadriflow/src/localsat.cpp | 295 ++ extern/quadriflow/src/localsat.hpp | 31 + extern/quadriflow/src/main.cpp | 127 + extern/quadriflow/src/merge-vertex.cpp | 44 + extern/quadriflow/src/merge-vertex.hpp | 14 + extern/quadriflow/src/optimizer.cpp | 1419 +++++++ extern/quadriflow/src/optimizer.hpp | 56 + extern/quadriflow/src/parametrizer-flip.cpp | 583 +++ extern/quadriflow/src/parametrizer-int.cpp | 425 ++ extern/quadriflow/src/parametrizer-mesh.cpp | 615 +++ extern/quadriflow/src/parametrizer-scale.cpp | 119 + extern/quadriflow/src/parametrizer-sing.cpp | 142 + extern/quadriflow/src/parametrizer.cpp | 247 ++ extern/quadriflow/src/parametrizer.hpp | 177 + extern/quadriflow/src/post-solver.cpp | 427 ++ extern/quadriflow/src/post-solver.hpp | 64 + extern/quadriflow/src/serialize.hpp | 127 + extern/quadriflow/src/subdivide.cpp | 516 +++ extern/quadriflow/src/subdivide.hpp | 17 + 236 files changed, 118877 insertions(+) create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/AUTHORS create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/CMakeLists.txt create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/INSTALL create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/LICENSE create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/NEWS create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/README create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/cmake/FindCOIN.cmake create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/cmake/FindGLPK.cmake create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/cmake/FindGhostscript.cmake create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/cmake/FindILOG.cmake create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/cmake/FindSOPLEX.cmake create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/cmake/LEMONConfig.cmake.in create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/cmake/nsis/lemon.ico create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/cmake/nsis/uninstall.ico create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/cmake/version.cmake create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/cmake/version.cmake.in create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/contrib/CMakeLists.txt create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/demo/CMakeLists.txt create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/demo/arg_parser_demo.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/demo/digraph.lgf create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/demo/graph_to_eps_demo.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/demo/lgf_demo.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/CMakeLists.txt create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/adaptors.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/assert.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/base.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/bellman_ford.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/bfs.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/bin_heap.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/binomial_heap.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/alteration_notifier.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/array_map.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/bezier.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/default_map.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/edge_set_extender.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/enable_if.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/graph_adaptor_extender.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/graph_extender.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/lock.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/map_extender.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/path_dump.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/solver_bits.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/traits.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/variant.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/vector_map.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/windows.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/windows.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/bucket_heap.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/capacity_scaling.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/cbc.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/cbc.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/christofides_tsp.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/circulation.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/clp.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/clp.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/color.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/color.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/concept_check.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/bpgraph.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/digraph.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/graph.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/graph_components.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/heap.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/maps.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/path.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/config.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/config.h.in create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/connectivity.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/core.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/cost_scaling.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/counter.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/cplex.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/cplex.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/cycle_canceling.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/dfs.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/dheap.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/dijkstra.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/dim2.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/dimacs.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/edge_set.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/edmonds_karp.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/elevator.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/error.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/euler.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/fib_heap.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/fractional_matching.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/full_graph.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/glpk.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/glpk.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/gomory_hu.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/graph_to_eps.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/greedy_tsp.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/grid_graph.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/grosso_locatelli_pullan_mc.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/hao_orlin.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/hartmann_orlin_mmc.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/howard_mmc.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/hypercube_graph.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/insertion_tsp.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/karp_mmc.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/kruskal.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/lemon.pc.in create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/lgf_reader.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/lgf_writer.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/list_graph.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/lp.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_base.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_base.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_skeleton.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_skeleton.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/maps.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/matching.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/math.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/max_cardinality_search.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/min_cost_arborescence.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/nagamochi_ibaraki.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/nauty_reader.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/nearest_neighbor_tsp.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/network_simplex.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/opt2_tsp.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/pairing_heap.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/path.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/planarity.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/preflow.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/quad_heap.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/radix_heap.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/radix_sort.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/random.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/random.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/smart_graph.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/soplex.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/soplex.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/static_graph.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/suurballe.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/time_measure.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/tolerance.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/lemon/unionfind.h create mode 100755 extern/quadriflow/3rd/lemon-1.3.1/scripts/unify-sources.sh create mode 100755 extern/quadriflow/3rd/lemon-1.3.1/scripts/valgrind-wrapper.sh create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/CMakeLists.txt create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/adaptors_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/arc_look_up_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/bellman_ford_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/bfs_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/bpgraph_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/circulation_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/connectivity_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/counter_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/dfs_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/digraph_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/dijkstra_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/dim_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/edge_set_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/error_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/euler_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/fractional_matching_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/gomory_hu_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/graph_copy_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/graph_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/graph_test.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/graph_utils_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/hao_orlin_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/heap_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/kruskal_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/lgf_reader_writer_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/lgf_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/lp_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/maps_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/matching_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/max_cardinality_search_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/max_clique_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/max_flow_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/min_cost_arborescence_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/min_cost_flow_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/min_mean_cycle_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/mip_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/nagamochi_ibaraki_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/path_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/planarity_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/radix_sort_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/random_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/suurballe_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/test_tools.h create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/test_tools_fail.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/test_tools_pass.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/time_measure_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/tsp_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/test/unionfind_test.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/tools/CMakeLists.txt create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/tools/dimacs-solver.cc create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/tools/dimacs-to-lgf.cc create mode 100755 extern/quadriflow/3rd/lemon-1.3.1/tools/lemon-0.x-to-1.x.sh create mode 100644 extern/quadriflow/3rd/lemon-1.3.1/tools/lgf-gen.cc create mode 100644 extern/quadriflow/3rd/pcg32/pcg32/pcg32.h create mode 100644 extern/quadriflow/3rd/pss/pss/parallel_stable_sort.h create mode 100644 extern/quadriflow/3rd/pss/pss/pss_common.h create mode 100644 extern/quadriflow/CMakeLists.txt create mode 100644 extern/quadriflow/LICENSE.txt create mode 100644 extern/quadriflow/README.md create mode 100644 extern/quadriflow/src/Optimizer.cu create mode 100644 extern/quadriflow/src/adjacent-matrix.cpp create mode 100644 extern/quadriflow/src/adjacent-matrix.hpp create mode 100644 extern/quadriflow/src/compare-key.hpp create mode 100644 extern/quadriflow/src/config.hpp create mode 100644 extern/quadriflow/src/dedge.cpp create mode 100644 extern/quadriflow/src/dedge.hpp create mode 100644 extern/quadriflow/src/disajoint-tree.hpp create mode 100644 extern/quadriflow/src/dset.hpp create mode 100644 extern/quadriflow/src/field-math.hpp create mode 100644 extern/quadriflow/src/flow.hpp create mode 100644 extern/quadriflow/src/hierarchy.cpp create mode 100644 extern/quadriflow/src/hierarchy.hpp create mode 100644 extern/quadriflow/src/loader.cpp create mode 100644 extern/quadriflow/src/loader.hpp create mode 100644 extern/quadriflow/src/localsat.cpp create mode 100644 extern/quadriflow/src/localsat.hpp create mode 100644 extern/quadriflow/src/main.cpp create mode 100644 extern/quadriflow/src/merge-vertex.cpp create mode 100644 extern/quadriflow/src/merge-vertex.hpp create mode 100644 extern/quadriflow/src/optimizer.cpp create mode 100644 extern/quadriflow/src/optimizer.hpp create mode 100644 extern/quadriflow/src/parametrizer-flip.cpp create mode 100644 extern/quadriflow/src/parametrizer-int.cpp create mode 100644 extern/quadriflow/src/parametrizer-mesh.cpp create mode 100644 extern/quadriflow/src/parametrizer-scale.cpp create mode 100644 extern/quadriflow/src/parametrizer-sing.cpp create mode 100644 extern/quadriflow/src/parametrizer.cpp create mode 100644 extern/quadriflow/src/parametrizer.hpp create mode 100644 extern/quadriflow/src/post-solver.cpp create mode 100644 extern/quadriflow/src/post-solver.hpp create mode 100644 extern/quadriflow/src/serialize.hpp create mode 100644 extern/quadriflow/src/subdivide.cpp create mode 100644 extern/quadriflow/src/subdivide.hpp (limited to 'extern') diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt index 3b2a8c172aa..0d9010b15ea 100644 --- a/extern/CMakeLists.txt +++ b/extern/CMakeLists.txt @@ -105,3 +105,8 @@ if(WITH_AUDASPACE AND NOT WITH_SYSTEM_AUDASPACE) set(AUDASPACE_CMAKE_CFG ${CMAKE_CURRENT_SOURCE_DIR}/audaspace/blender_config.cmake) add_subdirectory(audaspace) endif() + +if(WITH_QUADRIFLOW) + set(QUADRIFLOW_CMAKE_CFG ${CMAKE_CURRENT_SOURCE_DIR}/quadriflow/blender_config.cmake) + add_subdirectory(quadriflow) +endif() diff --git a/extern/quadriflow/3rd/lemon-1.3.1/AUTHORS b/extern/quadriflow/3rd/lemon-1.3.1/AUTHORS new file mode 100644 index 00000000000..4019ca6213a --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/AUTHORS @@ -0,0 +1,26 @@ +The main developers of release series 1.x are + + * Balazs Dezso + * Alpar Juttner + * Peter Kovacs + * Akos Ladanyi + +For more complete list of contributors, please visit the history of +the LEMON source code repository: http://lemon.cs.elte.hu/hg/lemon + +Moreover, this version is heavily based on version 0.x of LEMON. Here +is the list of people who contributed to those versions. + + * Mihaly Barasz + * Johanna Becker + * Attila Bernath + * Balazs Dezso + * Peter Hegyi + * Alpar Juttner + * Peter Kovacs + * Akos Ladanyi + * Marton Makai + * Jacint Szabo + +Again, please visit the history of the old LEMON repository for more +details: http://lemon.cs.elte.hu/hg/lemon-0.x \ No newline at end of file diff --git a/extern/quadriflow/3rd/lemon-1.3.1/CMakeLists.txt b/extern/quadriflow/3rd/lemon-1.3.1/CMakeLists.txt new file mode 100644 index 00000000000..7aa6d430906 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/CMakeLists.txt @@ -0,0 +1,373 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 3.1) + +SET(PROJECT_NAME "LEMON") +PROJECT(${PROJECT_NAME}) + +INCLUDE(FindPythonInterp) +INCLUDE(FindWget) + +IF(EXISTS ${PROJECT_SOURCE_DIR}/cmake/version.cmake) + INCLUDE(${PROJECT_SOURCE_DIR}/cmake/version.cmake) +ELSEIF(DEFINED ENV{LEMON_VERSION}) + SET(LEMON_VERSION $ENV{LEMON_VERSION} CACHE STRING "LEMON version string.") +ELSE() + EXECUTE_PROCESS( + COMMAND + hg log -r. --template "{latesttag}" + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + OUTPUT_VARIABLE HG_REVISION_TAG + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + EXECUTE_PROCESS( + COMMAND + hg log -r. --template "{latesttagdistance}" + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + OUTPUT_VARIABLE HG_REVISION_DIST + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + EXECUTE_PROCESS( + COMMAND + hg log -r. --template "{node|short}" + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + OUTPUT_VARIABLE HG_REVISION_ID + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + IF(HG_REVISION_TAG STREQUAL "") + SET(HG_REVISION_ID "hg-tip") + ELSE() + IF(HG_REVISION_TAG STREQUAL "null") + SET(HG_REVISION_TAG "trunk") + ELSEIF(HG_REVISION_TAG MATCHES "^r") + STRING(SUBSTRING ${HG_REVISION_TAG} 1 -1 HG_REVISION_TAG) + ENDIF() + IF(HG_REVISION_DIST STREQUAL "0") + SET(HG_REVISION ${HG_REVISION_TAG}) + ELSE() + SET(HG_REVISION + "${HG_REVISION_TAG}+${HG_REVISION_DIST}-${HG_REVISION_ID}") + ENDIF() + ENDIF() + + SET(LEMON_VERSION ${HG_REVISION} CACHE STRING "LEMON version string.") +ENDIF() + +SET(PROJECT_VERSION ${LEMON_VERSION}) + +SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) + +FIND_PACKAGE(Doxygen) +FIND_PACKAGE(Ghostscript) + +SET(LEMON_ENABLE_GLPK YES CACHE STRING "Enable GLPK solver backend.") +SET(LEMON_ENABLE_ILOG YES CACHE STRING "Enable ILOG (CPLEX) solver backend.") +SET(LEMON_ENABLE_COIN YES CACHE STRING "Enable COIN solver backend.") +SET(LEMON_ENABLE_SOPLEX YES CACHE STRING "Enable SoPlex solver backend.") + +IF(LEMON_ENABLE_GLPK) + FIND_PACKAGE(GLPK 4.33) +ENDIF(LEMON_ENABLE_GLPK) +IF(LEMON_ENABLE_ILOG) + FIND_PACKAGE(ILOG) +ENDIF(LEMON_ENABLE_ILOG) +IF(LEMON_ENABLE_COIN) + FIND_PACKAGE(COIN) +ENDIF(LEMON_ENABLE_COIN) +IF(LEMON_ENABLE_SOPLEX) + FIND_PACKAGE(SOPLEX) +ENDIF(LEMON_ENABLE_SOPLEX) + +IF(GLPK_FOUND) + SET(LEMON_HAVE_LP TRUE) + SET(LEMON_HAVE_MIP TRUE) + SET(LEMON_HAVE_GLPK TRUE) +ENDIF(GLPK_FOUND) +IF(ILOG_FOUND) + SET(LEMON_HAVE_LP TRUE) + SET(LEMON_HAVE_MIP TRUE) + SET(LEMON_HAVE_CPLEX TRUE) +ENDIF(ILOG_FOUND) +IF(COIN_FOUND) + SET(LEMON_HAVE_LP TRUE) + SET(LEMON_HAVE_MIP TRUE) + SET(LEMON_HAVE_CLP TRUE) + SET(LEMON_HAVE_CBC TRUE) +ENDIF(COIN_FOUND) +IF(SOPLEX_FOUND) + SET(LEMON_HAVE_LP TRUE) + SET(LEMON_HAVE_SOPLEX TRUE) +ENDIF(SOPLEX_FOUND) + +IF(ILOG_FOUND) + SET(DEFAULT_LP "CPLEX") + SET(DEFAULT_MIP "CPLEX") +ELSEIF(COIN_FOUND) + SET(DEFAULT_LP "CLP") + SET(DEFAULT_MIP "CBC") +ELSEIF(GLPK_FOUND) + SET(DEFAULT_LP "GLPK") + SET(DEFAULT_MIP "GLPK") +ELSEIF(SOPLEX_FOUND) + SET(DEFAULT_LP "SOPLEX") +ENDIF() + +IF(NOT LEMON_DEFAULT_LP OR + (NOT ILOG_FOUND AND (LEMON_DEFAULT_LP STREQUAL "CPLEX")) OR + (NOT COIN_FOUND AND (LEMON_DEFAULT_LP STREQUAL "CLP")) OR + (NOT GLPK_FOUND AND (LEMON_DEFAULT_LP STREQUAL "GLPK")) OR + (NOT SOPLEX_FOUND AND (LEMON_DEFAULT_LP STREQUAL "SOPLEX"))) + SET(LEMON_DEFAULT_LP ${DEFAULT_LP} CACHE STRING + "Default LP solver backend (GLPK, CPLEX, CLP or SOPLEX)" FORCE) +ELSE() + SET(LEMON_DEFAULT_LP ${DEFAULT_LP} CACHE STRING + "Default LP solver backend (GLPK, CPLEX, CLP or SOPLEX)") +ENDIF() +IF(NOT LEMON_DEFAULT_MIP OR + (NOT ILOG_FOUND AND (LEMON_DEFAULT_MIP STREQUAL "CPLEX")) OR + (NOT COIN_FOUND AND (LEMON_DEFAULT_MIP STREQUAL "CBC")) OR + (NOT GLPK_FOUND AND (LEMON_DEFAULT_MIP STREQUAL "GLPK"))) + SET(LEMON_DEFAULT_MIP ${DEFAULT_MIP} CACHE STRING + "Default MIP solver backend (GLPK, CPLEX or CBC)" FORCE) +ELSE() + SET(LEMON_DEFAULT_MIP ${DEFAULT_MIP} CACHE STRING + "Default MIP solver backend (GLPK, CPLEX or CBC)") +ENDIF() + + +IF(DEFINED ENV{LEMON_CXX_WARNING}) + SET(CXX_WARNING $ENV{LEMON_CXX_WARNING}) +ELSE() + IF(CMAKE_COMPILER_IS_GNUCXX) + SET(CXX_WARNING "-Wall -W -Wunused -Wformat=2 -Wctor-dtor-privacy -Wnon-virtual-dtor -Wno-char-subscripts -Wwrite-strings -Wno-char-subscripts -Wreturn-type -Wcast-qual -Wcast-align -Wsign-promo -Woverloaded-virtual -fno-strict-aliasing -Wold-style-cast -Wno-unknown-pragmas") + SET(CMAKE_CXX_FLAGS_DEBUG CACHE STRING "-ggdb") + SET(CMAKE_C_FLAGS_DEBUG CACHE STRING "-ggdb") + ELSEIF(MSVC) + # This part is unnecessary 'casue the same is set by the lemon/core.h. + # Still keep it as an example. + SET(CXX_WARNING "/wd4250 /wd4355 /wd4503 /wd4800 /wd4996") + # Suppressed warnings: + # C4250: 'class1' : inherits 'class2::member' via dominance + # C4355: 'this' : used in base member initializer list + # C4503: 'function' : decorated name length exceeded, name was truncated + # C4800: 'type' : forcing value to bool 'true' or 'false' + # (performance warning) + # C4996: 'function': was declared deprecated + ELSE() + SET(CXX_WARNING "-Wall") + ENDIF() +ENDIF() +SET(LEMON_CXX_WARNING_FLAGS ${CXX_WARNING} CACHE STRING "LEMON warning flags.") + +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LEMON_CXX_WARNING_FLAGS}") + +IF(MSVC) + SET( CMAKE_CXX_FLAGS_MAINTAINER "/WX ${CMAKE_CXX_FLAGS_DEBUG}" CACHE STRING + "Flags used by the C++ compiler during maintainer builds." + ) + SET( CMAKE_C_FLAGS_MAINTAINER "/WX ${CMAKE_CXX_FLAGS_DEBUG}" CACHE STRING + "Flags used by the C compiler during maintainer builds." + ) + SET( CMAKE_EXE_LINKER_FLAGS_MAINTAINER + "${CMAKE_EXE_LINKER_FLAGS_DEBUG}" CACHE STRING + "Flags used for linking binaries during maintainer builds." + ) + SET( CMAKE_SHARED_LINKER_FLAGS_MAINTAINER + "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}" CACHE STRING + "Flags used by the shared libraries linker during maintainer builds." + ) +ELSE() + SET( CMAKE_CXX_FLAGS_MAINTAINER "-Werror -ggdb -O0" CACHE STRING + "Flags used by the C++ compiler during maintainer builds." + ) + SET( CMAKE_C_FLAGS_MAINTAINER "-Werror -O0" CACHE STRING + "Flags used by the C compiler during maintainer builds." + ) + SET( CMAKE_EXE_LINKER_FLAGS_MAINTAINER + "${CMAKE_EXE_LINKER_FLAGS_DEBUG}" CACHE STRING + "Flags used for linking binaries during maintainer builds." + ) + SET( CMAKE_SHARED_LINKER_FLAGS_MAINTAINER + "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}" CACHE STRING + "Flags used by the shared libraries linker during maintainer builds." + ) +ENDIF() + +MARK_AS_ADVANCED( + CMAKE_CXX_FLAGS_MAINTAINER + CMAKE_C_FLAGS_MAINTAINER + CMAKE_EXE_LINKER_FLAGS_MAINTAINER + CMAKE_SHARED_LINKER_FLAGS_MAINTAINER ) + +IF(CMAKE_CONFIGURATION_TYPES) + LIST(APPEND CMAKE_CONFIGURATION_TYPES Maintainer) + LIST(REMOVE_DUPLICATES CMAKE_CONFIGURATION_TYPES) + SET(CMAKE_CONFIGURATION_TYPES "${CMAKE_CONFIGURATION_TYPES}" CACHE STRING + "Add the configurations that we need" + FORCE) + endif() + +IF(NOT CMAKE_BUILD_TYPE) + SET(CMAKE_BUILD_TYPE "Release") +ENDIF() + +SET( CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" CACHE STRING + "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel Maintainer." + FORCE ) + + +INCLUDE(CheckTypeSize) +CHECK_TYPE_SIZE("long long" LONG_LONG) +SET(LEMON_HAVE_LONG_LONG ${HAVE_LONG_LONG}) + +INCLUDE(FindThreads) + +IF(NOT LEMON_THREADING) + IF(CMAKE_USE_PTHREADS_INIT) + SET(LEMON_THREADING "Pthread") + ELSEIF(CMAKE_USE_WIN32_THREADS_INIT) + SET(LEMON_THREADING "Win32") + ELSE() + SET(LEMON_THREADING "None") + ENDIF() +ENDIF() + +SET( LEMON_THREADING "${LEMON_THREADING}" CACHE STRING + "Choose the threading library, options are: Pthread Win32 None." + FORCE ) + +IF(LEMON_THREADING STREQUAL "Pthread") + SET(LEMON_USE_PTHREAD TRUE) +ELSEIF(LEMON_THREADING STREQUAL "Win32") + SET(LEMON_USE_WIN32_THREADS TRUE) +ENDIF() + +ENABLE_TESTING() + +IF(${CMAKE_BUILD_TYPE} STREQUAL "Maintainer") + ADD_CUSTOM_TARGET(check ALL COMMAND ${CMAKE_CTEST_COMMAND}) +ELSE() + ADD_CUSTOM_TARGET(check COMMAND ${CMAKE_CTEST_COMMAND}) +ENDIF() + +ADD_SUBDIRECTORY(lemon) +IF(${CMAKE_SOURCE_DIR} STREQUAL ${PROJECT_SOURCE_DIR}) + ADD_SUBDIRECTORY(contrib) + ADD_SUBDIRECTORY(demo) + ADD_SUBDIRECTORY(tools) + ADD_SUBDIRECTORY(doc) + ADD_SUBDIRECTORY(test) +ENDIF() + +CONFIGURE_FILE( + ${PROJECT_SOURCE_DIR}/cmake/LEMONConfig.cmake.in + ${PROJECT_BINARY_DIR}/cmake/LEMONConfig.cmake + @ONLY +) +IF(UNIX) + INSTALL( + FILES ${PROJECT_BINARY_DIR}/cmake/LEMONConfig.cmake + DESTINATION share/lemon/cmake + ) +ELSEIF(WIN32) + INSTALL( + FILES ${PROJECT_BINARY_DIR}/cmake/LEMONConfig.cmake + DESTINATION cmake + ) +ENDIF() + +CONFIGURE_FILE( + ${PROJECT_SOURCE_DIR}/cmake/version.cmake.in + ${PROJECT_BINARY_DIR}/cmake/version.cmake + @ONLY +) + +SET(ARCHIVE_BASE_NAME ${CMAKE_PROJECT_NAME}) +STRING(TOLOWER ${ARCHIVE_BASE_NAME} ARCHIVE_BASE_NAME) +SET(ARCHIVE_NAME ${ARCHIVE_BASE_NAME}-${PROJECT_VERSION}) +ADD_CUSTOM_TARGET(dist + COMMAND cmake -E remove_directory ${ARCHIVE_NAME} + COMMAND hg archive ${ARCHIVE_NAME} + COMMAND cmake -E copy cmake/version.cmake ${ARCHIVE_NAME}/cmake/version.cmake + COMMAND tar -czf ${ARCHIVE_BASE_NAME}-nodoc-${PROJECT_VERSION}.tar.gz ${ARCHIVE_NAME} + COMMAND zip -r ${ARCHIVE_BASE_NAME}-nodoc-${PROJECT_VERSION}.zip ${ARCHIVE_NAME} + COMMAND cmake -E copy_directory doc/html ${ARCHIVE_NAME}/doc/html + COMMAND tar -czf ${ARCHIVE_NAME}.tar.gz ${ARCHIVE_NAME} + COMMAND zip -r ${ARCHIVE_NAME}.zip ${ARCHIVE_NAME} + COMMAND cmake -E copy_directory doc/html ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION} + COMMAND tar -czf ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION}.tar.gz ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION} + COMMAND zip -r ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION}.zip ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION} + COMMAND cmake -E remove_directory ${ARCHIVE_NAME} + COMMAND cmake -E remove_directory ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION} + DEPENDS html + WORKING_DIRECTORY ${PROJECT_BINARY_DIR}) + +# CPACK config (Basically for NSIS) +IF(${CMAKE_SOURCE_DIR} STREQUAL ${PROJECT_SOURCE_DIR}) + SET(CPACK_PACKAGE_NAME ${PROJECT_NAME}) + SET(CPACK_PACKAGE_VENDOR "EGRES") + SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY + "LEMON - Library for Efficient Modeling and Optimization in Networks") + SET(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE") + + SET(CPACK_PACKAGE_VERSION ${PROJECT_VERSION}) + + SET(CPACK_PACKAGE_INSTALL_DIRECTORY + "${PROJECT_NAME} ${PROJECT_VERSION}") + SET(CPACK_PACKAGE_INSTALL_REGISTRY_KEY + "${PROJECT_NAME} ${PROJECT_VERSION}") + + SET(CPACK_COMPONENTS_ALL headers library html_documentation bin) + + SET(CPACK_COMPONENT_HEADERS_DISPLAY_NAME "C++ headers") + SET(CPACK_COMPONENT_LIBRARY_DISPLAY_NAME "Dynamic-link library") + SET(CPACK_COMPONENT_BIN_DISPLAY_NAME "Command line utilities") + SET(CPACK_COMPONENT_HTML_DOCUMENTATION_DISPLAY_NAME "HTML documentation") + + SET(CPACK_COMPONENT_HEADERS_DESCRIPTION + "C++ header files") + SET(CPACK_COMPONENT_LIBRARY_DESCRIPTION + "DLL and import library") + SET(CPACK_COMPONENT_BIN_DESCRIPTION + "Command line utilities") + SET(CPACK_COMPONENT_HTML_DOCUMENTATION_DESCRIPTION + "Doxygen generated documentation") + + SET(CPACK_COMPONENT_HEADERS_DEPENDS library) + + SET(CPACK_COMPONENT_HEADERS_GROUP "Development") + SET(CPACK_COMPONENT_LIBRARY_GROUP "Development") + SET(CPACK_COMPONENT_HTML_DOCUMENTATION_GROUP "Documentation") + + SET(CPACK_COMPONENT_GROUP_DEVELOPMENT_DESCRIPTION + "Components needed to develop software using LEMON") + SET(CPACK_COMPONENT_GROUP_DOCUMENTATION_DESCRIPTION + "Documentation of LEMON") + + SET(CPACK_ALL_INSTALL_TYPES Full Developer) + + SET(CPACK_COMPONENT_HEADERS_INSTALL_TYPES Developer Full) + SET(CPACK_COMPONENT_LIBRARY_INSTALL_TYPES Developer Full) + SET(CPACK_COMPONENT_HTML_DOCUMENTATION_INSTALL_TYPES Full) + + SET(CPACK_GENERATOR "NSIS") + SET(CPACK_NSIS_MUI_ICON "${PROJECT_SOURCE_DIR}/cmake/nsis/lemon.ico") + SET(CPACK_NSIS_MUI_UNIICON "${PROJECT_SOURCE_DIR}/cmake/nsis/uninstall.ico") + #SET(CPACK_PACKAGE_ICON "${PROJECT_SOURCE_DIR}/cmake/nsis\\\\installer.bmp") + SET(CPACK_NSIS_INSTALLED_ICON_NAME "bin\\\\lemon.ico") + SET(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY} ${PROJECT_NAME}") + SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\lemon.cs.elte.hu") + SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\lemon.cs.elte.hu") + SET(CPACK_NSIS_CONTACT "lemon-user@lemon.cs.elte.hu") + SET(CPACK_NSIS_CREATE_ICONS_EXTRA " + CreateShortCut \\\"$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Documentation.lnk\\\" \\\"$INSTDIR\\\\share\\\\doc\\\\index.html\\\" + ") + SET(CPACK_NSIS_DELETE_ICONS_EXTRA " + !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP + Delete \\\"$SMPROGRAMS\\\\$MUI_TEMP\\\\Documentation.lnk\\\" + ") + + INCLUDE(CPack) +ENDIF() diff --git a/extern/quadriflow/3rd/lemon-1.3.1/INSTALL b/extern/quadriflow/3rd/lemon-1.3.1/INSTALL new file mode 100644 index 00000000000..3fba5b263f7 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/INSTALL @@ -0,0 +1,167 @@ +Installation Instructions +========================= + +This file contains instructions for building and installing LEMON from +source on Linux. The process on Windows is similar. + +Note that it is not necessary to install LEMON in order to use +it. Instead, you can easily integrate it with your own code +directly. For instructions, see +https://lemon.cs.elte.hu/trac/lemon/wiki/HowToCompile + + +In order to install LEMON from the extracted source tarball you have to +issue the following commands: + + 1. Step into the root of the source directory. + + $ cd lemon-x.y.z + + 2. Create a build subdirectory and step into it. + + $ mkdir build + $ cd build + + 3. Perform system checks and create the makefiles. + + $ cmake .. + + 4. Build LEMON. + + $ make + + This command compiles the non-template part of LEMON into + libemon.a file. It also compiles the programs in the 'tools' and + 'demo' subdirectories. + + 5. [Optional] Compile and run the self-tests. + + $ make check + + 5. [Optional] Generate the user documentation. + + $ make html + + The release tarballs already include the documentation. + + Note that for this step you need to have the following tools + installed: Python, Doxygen, Graphviz, Ghostscript, LaTeX. + + 6. [Optional] Install LEMON + + $ make install + + This command installs LEMON under /usr/local (you will need root + privileges to be able to do that). If you want to install it to + some other location, then pass the + -DCMAKE_INSTALL_PREFIX=DIRECTORY flag to cmake in Step 3. + For example: + + $ cmake -DCMAKE_INSTALL_PREFIX=/home/username/lemon' + +Configure Options and Variables +=============================== + +In Step 3, you can customize the build process by passing options to CMAKE. + +$ cmake [OPTIONS] .. + +You find a list of the most useful options below. + +-DCMAKE_INSTALL_PREFIX=PREFIX + + Set the installation prefix to PREFIX. By default it is /usr/local. + +-DCMAKE_BUILD_TYPE=[Release|Debug|Maintainer|...] + + This sets the compiler options. The choices are the following + + 'Release': A strong optimization is turned on (-O3 with gcc). This + is the default setting and we strongly recommend using this for + the final compilation. + + 'Debug': Optimization is turned off and debug info is added (-O0 + -ggdb with gcc). If is recommended during the development. + + 'Maintainer': The same as 'Debug' but the compiler warnings are + converted to errors (-Werror with gcc). In addition, 'make' will + also automatically compile and execute the test codes. It is the + best way of ensuring that LEMON codebase is clean and safe. + + 'RelWithDebInfo': Optimized build with debug info. + + 'MinSizeRel': Size optimized build (-Os with gcc) + +-DTEST_WITH_VALGRIND=YES + + Using this, the test codes will be executed using valgrind. It is a + very effective way of identifying indexing problems and memory leaks. + +-DCMAKE_CXX_COMPILER=path-to-compiler + + Change the compiler to be used. + +-DBUILD_SHARED_LIBS=TRUE + + Build shared library instead of static one. Think twice if you + really want to use this option. + +-DLEMON_DOC_SOURCE_BROWSER=YES + + Include the browsable cross referenced LEMON source code into the + doc. It makes the doc quite bloated, but may be useful for + developing LEMON itself. + +-DLEMON_DOC_USE_MATHJAX=YES + + Use MathJax (http://mathjax.org) for rendering the math formulae in + the doc. It of much higher quality compared to the default LaTeX + generated static images and it allows copy&paste of the formulae to + LaTeX, Open Office, MS Word etc. documents. + + On the other hand, it needs either Internet access or a locally + installed version of MathJax to properly render the doc. + +-DLEMON_DOC_MATHJAX_RELPATH=DIRECTORY + + The location of the MathJax library. It defaults to + http://www.mathjax.org/mathjax, which necessitates Internet access + for proper rendering. The easiest way to make it usable offline is + to set this parameter to 'mathjax' and copy all files of the MathJax + library into the 'doc/html/mathjax' subdirectory of the build + location. + + See http://docs.mathjax.org/en/latest/installation.html for more details. + + +-DLEMON_ENABLE_GLPK=NO +-DLEMON_ENABLE_COIN=NO +-DLEMON_ENABLE_ILOG=NO + + Enable optional third party libraries. They are all enabled by default. + +-DLEMON_DEFAULT_LP=GLPK + + Sets the default LP solver backend. The supported values are + CPLEX, CLP and GLPK. By default, it is set to the first one which + is enabled and succesfully discovered. + +-DLEMON_DEFAULT_MIP=GLPK + + Sets the default MIP solver backend. The supported values are + CPLEX, CBC and GLPK. By default, it is set to the first one which + is enabled and succesfully discovered. + +-DGLPK_ROOT_DIR=DIRECTORY +-DCOIN_ROOT_DIR=DIRECTORY +-DILOG_ROOT_DIR=DIRECTORY + + Root directory prefixes of optional third party libraries. + +Makefile Variables +================== + +make VERBOSE=1 + + This results in a more verbose output by showing the full + compiler and linker commands. \ No newline at end of file diff --git a/extern/quadriflow/3rd/lemon-1.3.1/LICENSE b/extern/quadriflow/3rd/lemon-1.3.1/LICENSE new file mode 100644 index 00000000000..5b1c4255062 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/LICENSE @@ -0,0 +1,32 @@ +LEMON code without an explicit copyright notice is covered by the following +copyright/license. + +Copyright (C) 2003-2012 Egervary Jeno Kombinatorikus Optimalizalasi +Kutatocsoport (Egervary Combinatorial Optimization Research Group, +EGRES). + +=========================================================================== +Boost Software License, Version 1.0 +=========================================================================== + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/extern/quadriflow/3rd/lemon-1.3.1/NEWS b/extern/quadriflow/3rd/lemon-1.3.1/NEWS new file mode 100644 index 00000000000..7908ca3a455 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/NEWS @@ -0,0 +1,337 @@ +2014-07-07 Version 1.3.1 released + + Bugfix release. + + #484: Require CMAKE 2.8 + #471, #472, #480: Various clang compatibility fixes + #481, #482: Fix shared lib build and versioning + #476: Fix invalid map query in NearestNeighborTsp + #478: Bugfix in debug checking and lower bound handling + in min cost flow algorithms + #479, #465: Bugfix in default LP/MIP backend settings + #476: Bugfix in tsp_test + #487: Add missing include header and std:: namespace spec. + #474: Fix division by zero error in NetworkSimplex + +2013-08-10 Version 1.3 released + + This is major feature release + + * New data structures + + #69 : Bipartite graph concepts and implementations + + * New algorithms + + #177: Port Edmonds-Karp algorithm + #380, #405: Heuristic algorithm for the max clique problem + #386: Heuristic algorithms for symmetric TSP + ----: Nagamochi-Ibaraki algorithm [5087694945e4] + #397, #56: Max. cardinality search + + * Other new features + + #223: Thread safe graph and graph map implementations + #442: Different TimeStamp print formats + #457: File export functionality to LpBase + #362: Bidirectional iterator support for radixSort() + + * Implementation improvements + + ----: Network Simplex + #391: Better update process, pivot rule and arc mixing + #435: Improved Altering List pivot rule + #417: Various fine tunings in CostScaling + #438: Optional iteration limit in HowardMmc + #436: Ensure strongly polynomial running time for CycleCanceling + while keeping the same performance + ----: Make the CBC interface be compatible with latest CBC releases + [ee581a0ecfbf] + + * CMAKE has become the default build environment (#434) + + ----: Autotool support has been dropped + ----: Improved LP/MIP configuration + #465: Enable/disable options for LP/MIP backends + #446: Better CPLEX discovery + #460: Add cmake config to find SoPlex + ----: Allow CPACK configuration on all platforms + #390: Add 'Maintainer' CMAKE build type + #388: Add 'check' target. + #401: Add contrib dir + #389: Better version string setting in CMAKE + #433: Support shared library build + #416: Support testing with valgrind + + * Doc improvements + + #395: SOURCE_BROWSER Doxygen switch is configurable from CMAKE + update-external-tags CMAKE target + #455: Optionally use MathJax for rendering the math formulae + #402, #437, #459, #456, #463: Various doc improvements + + * Bugfixes (compared to release 1.2): + + #432: Add missing doc/template.h and doc/references.bib to release + tarball + ----: Intel C++ compatibility fixes + #441: Fix buggy reinitialization in _solver_bits::VarIndex::clear() + #444: Bugfix in path copy constructors and assignment operators + #447: Bugfix in AllArcLookUp<> + #448: Bugfix in adaptor_test.cc + #449: Fix clang compilation warnings and errors + #440: Fix a bug + remove redundant typedefs in dimacs-solver + #453: Avoid GCC 4.7 compiler warnings + #445: Fix missing initialization in CplexEnv::CplexEnv() + #428: Add missing lemon/lemon.pc.cmake to the release tarball + #393: Create and install lemon.pc + #429: Fix VS warnings + #430: Fix LpBase::Constr two-side limit bug + #392: Bug fix in Dfs::start(s,t) + #414: Fix wrong initialization in Preflow + #418: Better Win CodeBlock/MinGW support + #419: Build environment improvements + - Build of mip_test and lp_test precede the running of the tests + - Also search for coin libs under ${COIN_ROOT_DIR}/lib/coin + - Do not look for COIN_VOL libraries + #382: Allow lgf file without Arc maps + #417: Bug fix in CostScaling + #366: Fix Pred[Matrix]MapPath::empty() + #371: Bug fix in (di)graphCopy() + The target graph is cleared before adding nodes and arcs/edges. + #364: Add missing UndirectedTags + #368: Fix the usage of std::numeric_limits<>::min() in Network Simplex + #372: Fix a critical bug in preflow + #461: Bugfix in assert.h + #470: Fix compilation issues related to various gcc versions + #446: Fix #define indicating CPLEX availability + #294: Add explicit namespace to + ignore_unused_variable_warning() usages + #420: Bugfix in IterableValueMap + #439: Bugfix in biNodeConnected() + + +2010-03-19 Version 1.2 released + + This is major feature release + + * New algorithms + * Bellman-Ford algorithm (#51) + * Minimum mean cycle algorithms (#179) + * Karp, Hartman-Orlin and Howard algorithms + * New minimum cost flow algorithms (#180) + * Cost Scaling algorithms + * Capacity Scaling algorithm + * Cycle-Canceling algorithms + * Planarity related algorithms (#62) + * Planarity checking algorithm + * Planar embedding algorithm + * Schnyder's planar drawing algorithm + * Coloring planar graphs with five or six colors + * Fractional matching algorithms (#314) + * New data structures + * StaticDigraph structure (#68) + * Several new priority queue structures (#50, #301) + * Fibonacci, Radix, Bucket, Pairing, Binomial + D-ary and fourary heaps (#301) + * Iterable map structures (#73) + * Other new tools and functionality + * Map utility functions (#320) + * Reserve functions are added to ListGraph and SmartGraph (#311) + * A resize() function is added to HypercubeGraph (#311) + * A count() function is added to CrossRefMap (#302) + * Support for multiple targets in Suurballe using fullInit() (#181) + * Traits class and named parameters for Suurballe (#323) + * Separate reset() and resetParams() functions in NetworkSimplex + to handle graph changes (#327) + * tolerance() functions are added to HaoOrlin (#306) + * Implementation improvements + * Improvements in weighted matching algorithms (#314) + * Jumpstart initialization + * ArcIt iteration is based on out-arc lists instead of in-arc lists + in ListDigraph (#311) + * Faster add row operation in CbcMip (#203) + * Better implementation for split() in ListDigraph (#311) + * ArgParser can also throw exception instead of exit(1) (#332) + * Miscellaneous + * A simple interactive bootstrap script + * Doc improvements (#62,#180,#299,#302,#303,#304,#307,#311,#331,#315, + #316,#319) + * BibTeX references in the doc (#184) + * Optionally use valgrind when running tests + * Also check ReferenceMapTag in concept checks (#312) + * dimacs-solver uses long long type by default. + * Several bugfixes (compared to release 1.1): + #295: Suppress MSVC warnings using pragmas + ----: Various CMAKE related improvements + * Remove duplications from doc/CMakeLists.txt + * Rename documentation install folder from 'docs' to 'html' + * Add tools/CMakeLists.txt to the tarball + * Generate and install LEMONConfig.cmake + * Change the label of the html project in Visual Studio + * Fix the check for the 'long long' type + * Put the version string into config.h + * Minor CMake improvements + * Set the version to 'hg-tip' if everything fails + #311: Add missing 'explicit' keywords + #302: Fix the implementation and doc of CrossRefMap + #308: Remove duplicate list_graph.h entry from source list + #307: Bugfix in Preflow and Circulation + #305: Bugfix and extension in the rename script + #312: Also check ReferenceMapTag in concept checks + #250: Bugfix in pathSource() and pathTarget() + #321: Use pathCopy(from,to) instead of copyPath(to,from) + #322: Distribure LEMONConfig.cmake.in + #330: Bug fix in map_extender.h + #336: Fix the date field comment of graphToEps() output + #323: Bug fix in Suurballe + #335: Fix clear() function in ExtendFindEnum + #337: Use void* as the LPX object pointer + #317: Fix (and improve) error message in mip_test.cc + Remove unnecessary OsiCbc dependency + #356: Allow multiple executions of weighted matching algorithms (#356) + +2009-05-13 Version 1.1 released + + This is the second stable release of the 1.x series. It + features a better coverage of the tools available in the 0.x + series, a thoroughly reworked LP/MIP interface plus various + improvements in the existing tools. + + * Much improved M$ Windows support + * Various improvements in the CMAKE build system + * Compilation warnings are fixed/suppressed + * Support IBM xlC compiler + * New algorithms + * Connectivity related algorithms (#61) + * Euler walks (#65) + * Preflow push-relabel max. flow algorithm (#176) + * Circulation algorithm (push-relabel based) (#175) + * Suurballe algorithm (#47) + * Gomory-Hu algorithm (#66) + * Hao-Orlin algorithm (#58) + * Edmond's maximum cardinality and weighted matching algorithms + in general graphs (#48,#265) + * Minimum cost arborescence/branching (#60) + * Network Simplex min. cost flow algorithm (#234) + * New data structures + * Full graph structure (#57) + * Grid graph structure (#57) + * Hypercube graph structure (#57) + * Graph adaptors (#67) + * ArcSet and EdgeSet classes (#67) + * Elevator class (#174) + * Other new tools + * LP/MIP interface (#44) + * Support for GLPK, CPLEX, Soplex, COIN-OR CLP and CBC + * Reader for the Nauty file format (#55) + * DIMACS readers (#167) + * Radix sort algorithms (#72) + * RangeIdMap and CrossRefMap (#160) + * New command line tools + * DIMACS to LGF converter (#182) + * lgf-gen - a graph generator (#45) + * DIMACS solver utility (#226) + * Other code improvements + * Lognormal distribution added to Random (#102) + * Better (i.e. O(1) time) item counting in SmartGraph (#3) + * The standard maps of graphs are guaranteed to be + reference maps (#190) + * Miscellaneous + * Various doc improvements + * Improved 0.x -> 1.x converter script + + * Several bugfixes (compared to release 1.0): + #170: Bugfix SmartDigraph::split() + #171: Bugfix in SmartGraph::restoreSnapshot() + #172: Extended test cases for graphs and digraphs + #173: Bugfix in Random + * operator()s always return a double now + * the faulty real(Num) and real(Num,Num) + have been removed + #187: Remove DijkstraWidestPathOperationTraits + #61: Bugfix in DfsVisit + #193: Bugfix in GraphReader::skipSection() + #195: Bugfix in ConEdgeIt() + #197: Bugfix in heap unionfind + * This bug affects Edmond's general matching algorithms + #207: Fix 'make install' without 'make html' using CMAKE + #208: Suppress or fix VS2008 compilation warnings + ----: Update the LEMON icon + ----: Enable the component-based installer + (in installers made by CPACK) + ----: Set the proper version for CMAKE in the tarballs + (made by autotools) + ----: Minor clarification in the LICENSE file + ----: Add missing unistd.h include to time_measure.h + #204: Compilation bug fixed in graph_to_eps.h with VS2005 + #214,#215: windows.h should never be included by LEMON headers + #230: Build systems check the availability of 'long long' type + #229: Default implementation of Tolerance<> is used for integer types + #211,#212: Various fixes for compiling on AIX + ----: Improvements in CMAKE config + - docs is installed in share/doc/ + - detects newer versions of Ghostscript + #239: Fix missing 'inline' specifier in time_measure.h + #274,#280: Install lemon/config.h + #275: Prefix macro names with LEMON_ in lemon/config.h + ----: Small script for making the release tarballs added + ----: Minor improvement in unify-sources.sh (a76f55d7d397) + +2009-03-27 LEMON joins to the COIN-OR initiative + + COIN-OR (Computational Infrastructure for Operations Research, + http://www.coin-or.org) project is an initiative to spur the + development of open-source software for the operations research + community. + +2008-10-13 Version 1.0 released + + This is the first stable release of LEMON. Compared to the 0.x + release series, it features a considerably smaller but more + matured set of tools. The API has also completely revised and + changed in several places. + + * The major name changes compared to the 0.x series (see the + Migration Guide in the doc for more details) + * Graph -> Digraph, UGraph -> Graph + * Edge -> Arc, UEdge -> Edge + * source(UEdge)/target(UEdge) -> u(Edge)/v(Edge) + * Other improvements + * Better documentation + * Reviewed and cleaned up codebase + * CMake based build system (along with the autotools based one) + * Contents of the library (ported from 0.x) + * Algorithms + * breadth-first search (bfs.h) + * depth-first search (dfs.h) + * Dijkstra's algorithm (dijkstra.h) + * Kruskal's algorithm (kruskal.h) + * Data structures + * graph data structures (list_graph.h, smart_graph.h) + * path data structures (path.h) + * binary heap data structure (bin_heap.h) + * union-find data structures (unionfind.h) + * miscellaneous property maps (maps.h) + * two dimensional vector and bounding box (dim2.h) + * Concepts + * graph structure concepts (concepts/digraph.h, concepts/graph.h, + concepts/graph_components.h) + * concepts for other structures (concepts/heap.h, concepts/maps.h, + concepts/path.h) + * Tools + * Mersenne twister random number generator (random.h) + * tools for measuring cpu and wall clock time (time_measure.h) + * tools for counting steps and events (counter.h) + * tool for parsing command line arguments (arg_parser.h) + * tool for visualizing graphs (graph_to_eps.h) + * tools for reading and writing data in LEMON Graph Format + (lgf_reader.h, lgf_writer.h) + * tools to handle the anomalies of calculations with + floating point numbers (tolerance.h) + * tools to manage RGB colors (color.h) + * Infrastructure + * extended assertion handling (assert.h) + * exception classes and error handling (error.h) + * concept checking (concept_check.h) + * commonly used mathematical constants (math.h) diff --git a/extern/quadriflow/3rd/lemon-1.3.1/README b/extern/quadriflow/3rd/lemon-1.3.1/README new file mode 100644 index 00000000000..52a768c3911 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/README @@ -0,0 +1,50 @@ +===================================================================== +LEMON - a Library for Efficient Modeling and Optimization in Networks +===================================================================== + +LEMON is an open source library written in C++. It provides +easy-to-use implementations of common data structures and algorithms +in the area of optimization and helps implementing new ones. The main +focus is on graphs and graph algorithms, thus it is especially +suitable for solving design and optimization problems of +telecommunication networks. To achieve wide usability its data +structures and algorithms provide generic interfaces. + +Contents +======== + +LICENSE + + Copying, distribution and modification conditions and terms. + +NEWS + + News and version history. + +INSTALL + + General building and installation instructions. + +lemon/ + + Source code of LEMON library. + +doc/ + + Documentation of LEMON. The starting page is doc/html/index.html. + +demo/ + + Some example programs to make you easier to get familiar with LEMON. + +scripts/ + + Scripts that make it easier to develop LEMON. + +test/ + + Programs to check the integrity and correctness of LEMON. + +tools/ + + Various utilities related to LEMON. diff --git a/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindCOIN.cmake b/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindCOIN.cmake new file mode 100644 index 00000000000..d4ed735df94 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindCOIN.cmake @@ -0,0 +1,110 @@ +SET(COIN_ROOT_DIR "" CACHE PATH "COIN root directory") + +FIND_PATH(COIN_INCLUDE_DIR coin/CoinUtilsConfig.h + HINTS ${COIN_ROOT_DIR}/include +) +FIND_LIBRARY(COIN_CBC_LIBRARY + NAMES Cbc libCbc + HINTS ${COIN_ROOT_DIR}/lib/coin + HINTS ${COIN_ROOT_DIR}/lib +) +FIND_LIBRARY(COIN_CBC_SOLVER_LIBRARY + NAMES CbcSolver libCbcSolver + HINTS ${COIN_ROOT_DIR}/lib/coin + HINTS ${COIN_ROOT_DIR}/lib +) +FIND_LIBRARY(COIN_CGL_LIBRARY + NAMES Cgl libCgl + HINTS ${COIN_ROOT_DIR}/lib/coin + HINTS ${COIN_ROOT_DIR}/lib +) +FIND_LIBRARY(COIN_CLP_LIBRARY + NAMES Clp libClp + HINTS ${COIN_ROOT_DIR}/lib/coin + HINTS ${COIN_ROOT_DIR}/lib +) +FIND_LIBRARY(COIN_COIN_UTILS_LIBRARY + NAMES CoinUtils libCoinUtils + HINTS ${COIN_ROOT_DIR}/lib/coin + HINTS ${COIN_ROOT_DIR}/lib +) +FIND_LIBRARY(COIN_OSI_LIBRARY + NAMES Osi libOsi + HINTS ${COIN_ROOT_DIR}/lib/coin + HINTS ${COIN_ROOT_DIR}/lib +) +FIND_LIBRARY(COIN_OSI_CBC_LIBRARY + NAMES OsiCbc libOsiCbc + HINTS ${COIN_ROOT_DIR}/lib/coin + HINTS ${COIN_ROOT_DIR}/lib +) +FIND_LIBRARY(COIN_OSI_CLP_LIBRARY + NAMES OsiClp libOsiClp + HINTS ${COIN_ROOT_DIR}/lib/coin + HINTS ${COIN_ROOT_DIR}/lib +) +FIND_LIBRARY(COIN_OSI_VOL_LIBRARY + NAMES OsiVol libOsiVol + HINTS ${COIN_ROOT_DIR}/lib/coin + HINTS ${COIN_ROOT_DIR}/lib +) +FIND_LIBRARY(COIN_VOL_LIBRARY + NAMES Vol libVol + HINTS ${COIN_ROOT_DIR}/lib/coin + HINTS ${COIN_ROOT_DIR}/lib +) + +FIND_LIBRARY(COIN_ZLIB_LIBRARY + NAMES z libz + HINTS ${COIN_ROOT_DIR}/lib/coin + HINTS ${COIN_ROOT_DIR}/lib +) +FIND_LIBRARY(COIN_BZ2_LIBRARY + NAMES bz2 libbz2 + HINTS ${COIN_ROOT_DIR}/lib/coin + HINTS ${COIN_ROOT_DIR}/lib +) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(COIN DEFAULT_MSG + COIN_INCLUDE_DIR + COIN_CBC_LIBRARY + COIN_CBC_SOLVER_LIBRARY + COIN_CGL_LIBRARY + COIN_CLP_LIBRARY + COIN_COIN_UTILS_LIBRARY + COIN_OSI_LIBRARY + COIN_OSI_CBC_LIBRARY + COIN_OSI_CLP_LIBRARY + # COIN_OSI_VOL_LIBRARY + # COIN_VOL_LIBRARY +) + +IF(COIN_FOUND) + SET(COIN_INCLUDE_DIRS ${COIN_INCLUDE_DIR}) + SET(COIN_CLP_LIBRARIES "${COIN_CLP_LIBRARY};${COIN_COIN_UTILS_LIBRARY};${COIN_ZLIB_LIBRARY};${COIN_BZ2_LIBRARY}") + IF(COIN_ZLIB_LIBRARY) + SET(COIN_CLP_LIBRARIES "${COIN_CLP_LIBRARIES};${COIN_ZLIB_LIBRARY}") + ENDIF(COIN_ZLIB_LIBRARY) + IF(COIN_BZ2_LIBRARY) + SET(COIN_CLP_LIBRARIES "${COIN_CLP_LIBRARIES};${COIN_BZ2_LIBRARY}") + ENDIF(COIN_BZ2_LIBRARY) + SET(COIN_CBC_LIBRARIES "${COIN_CBC_LIBRARY};${COIN_CBC_SOLVER_LIBRARY};${COIN_CGL_LIBRARY};${COIN_OSI_LIBRARY};${COIN_OSI_CBC_LIBRARY};${COIN_OSI_CLP_LIBRARY};${COIN_ZLIB_LIBRARY};${COIN_BZ2_LIBRARY};${COIN_CLP_LIBRARIES}") + SET(COIN_LIBRARIES ${COIN_CBC_LIBRARIES}) +ENDIF(COIN_FOUND) + +MARK_AS_ADVANCED( + COIN_INCLUDE_DIR + COIN_CBC_LIBRARY + COIN_CBC_SOLVER_LIBRARY + COIN_CGL_LIBRARY + COIN_CLP_LIBRARY + COIN_COIN_UTILS_LIBRARY + COIN_OSI_LIBRARY + COIN_OSI_CBC_LIBRARY + COIN_OSI_CLP_LIBRARY + COIN_OSI_VOL_LIBRARY + COIN_VOL_LIBRARY + COIN_ZLIB_LIBRARY + COIN_BZ2_LIBRARY +) diff --git a/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindGLPK.cmake b/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindGLPK.cmake new file mode 100644 index 00000000000..55e5e3ee056 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindGLPK.cmake @@ -0,0 +1,55 @@ +SET(GLPK_ROOT_DIR "" CACHE PATH "GLPK root directory") + +SET(GLPK_REGKEY "[HKEY_LOCAL_MACHINE\\SOFTWARE\\GnuWin32\\Glpk;InstallPath]") +GET_FILENAME_COMPONENT(GLPK_ROOT_PATH ${GLPK_REGKEY} ABSOLUTE) + +FIND_PATH(GLPK_INCLUDE_DIR + glpk.h + PATHS ${GLPK_REGKEY}/include + HINTS ${GLPK_ROOT_DIR}/include +) +FIND_LIBRARY(GLPK_LIBRARY + glpk + PATHS ${GLPK_REGKEY}/lib + HINTS ${GLPK_ROOT_DIR}/lib +) + +IF(GLPK_INCLUDE_DIR AND GLPK_LIBRARY) + FILE(READ ${GLPK_INCLUDE_DIR}/glpk.h GLPK_GLPK_H) + + STRING(REGEX MATCH "define[ ]+GLP_MAJOR_VERSION[ ]+[0-9]+" GLPK_MAJOR_VERSION_LINE "${GLPK_GLPK_H}") + STRING(REGEX REPLACE "define[ ]+GLP_MAJOR_VERSION[ ]+([0-9]+)" "\\1" GLPK_VERSION_MAJOR "${GLPK_MAJOR_VERSION_LINE}") + + STRING(REGEX MATCH "define[ ]+GLP_MINOR_VERSION[ ]+[0-9]+" GLPK_MINOR_VERSION_LINE "${GLPK_GLPK_H}") + STRING(REGEX REPLACE "define[ ]+GLP_MINOR_VERSION[ ]+([0-9]+)" "\\1" GLPK_VERSION_MINOR "${GLPK_MINOR_VERSION_LINE}") + + SET(GLPK_VERSION_STRING "${GLPK_VERSION_MAJOR}.${GLPK_VERSION_MINOR}") + + IF(GLPK_FIND_VERSION) + IF(GLPK_FIND_VERSION_COUNT GREATER 2) + MESSAGE(SEND_ERROR "unexpected version string") + ENDIF(GLPK_FIND_VERSION_COUNT GREATER 2) + + MATH(EXPR GLPK_REQUESTED_VERSION "${GLPK_FIND_VERSION_MAJOR}*100 + ${GLPK_FIND_VERSION_MINOR}") + MATH(EXPR GLPK_FOUND_VERSION "${GLPK_VERSION_MAJOR}*100 + ${GLPK_VERSION_MINOR}") + + IF(GLPK_FOUND_VERSION LESS GLPK_REQUESTED_VERSION) + SET(GLPK_PROPER_VERSION_FOUND FALSE) + ELSE(GLPK_FOUND_VERSION LESS GLPK_REQUESTED_VERSION) + SET(GLPK_PROPER_VERSION_FOUND TRUE) + ENDIF(GLPK_FOUND_VERSION LESS GLPK_REQUESTED_VERSION) + ELSE(GLPK_FIND_VERSION) + SET(GLPK_PROPER_VERSION_FOUND TRUE) + ENDIF(GLPK_FIND_VERSION) +ENDIF(GLPK_INCLUDE_DIR AND GLPK_LIBRARY) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(GLPK DEFAULT_MSG GLPK_LIBRARY GLPK_INCLUDE_DIR GLPK_PROPER_VERSION_FOUND) + +IF(GLPK_FOUND) + SET(GLPK_INCLUDE_DIRS ${GLPK_INCLUDE_DIR}) + SET(GLPK_LIBRARIES ${GLPK_LIBRARY}) + SET(GLPK_BIN_DIR ${GLPK_ROOT_PATH}/bin) +ENDIF(GLPK_FOUND) + +MARK_AS_ADVANCED(GLPK_LIBRARY GLPK_INCLUDE_DIR GLPK_BIN_DIR) diff --git a/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindGhostscript.cmake b/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindGhostscript.cmake new file mode 100644 index 00000000000..3366a000e1b --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindGhostscript.cmake @@ -0,0 +1,10 @@ +INCLUDE(FindPackageHandleStandardArgs) + +FIND_PROGRAM(GHOSTSCRIPT_EXECUTABLE + NAMES gs gswin32c + PATHS "$ENV{ProgramFiles}/gs" + PATH_SUFFIXES gs8.61/bin gs8.62/bin gs8.63/bin gs8.64/bin gs8.65/bin + DOC "Ghostscript: PostScript and PDF language interpreter and previewer." +) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Ghostscript DEFAULT_MSG GHOSTSCRIPT_EXECUTABLE) diff --git a/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindILOG.cmake b/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindILOG.cmake new file mode 100644 index 00000000000..a09fc9a2753 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindILOG.cmake @@ -0,0 +1,102 @@ +FIND_PATH(ILOG_ROOT_DIR + NAMES cplex + DOC "CPLEX STUDIO root directory" + PATHS /opt/ibm/ILOG /usr/local/ibm/ILOG /usr/local/ILOG /usr/local/ilog + PATHS "$ENV{HOME}/ILOG" "$ENV{HOME}/.local/ILOG" + PATHS "$ENV{HOME}/ibm/ILOG" "$ENV{HOME}/.local/ibm/ILOG" + PATHS "C:/Program Files/IBM/ILOG" + PATH_SUFFIXES "CPLEX_Studio126" "CPLEX_Studio125" + "CPLEX_Studio124" "CPLEX_Studio123" "CPLEX_Studio122" + NO_DEFAULT_PATH +) + +IF(WIN32) + IF(MSVC_VERSION STREQUAL "1400") + SET(ILOG_WIN_COMPILER "windows_vs2005") + ELSEIF(MSVC_VERSION STREQUAL "1500") + SET(ILOG_WIN_COMPILER "windows_vs2008") + ELSEIF(MSVC_VERSION STREQUAL "1600") + SET(ILOG_WIN_COMPILER "windows_vs2010") + ELSE() + SET(ILOG_WIN_COMPILER "windows_vs2008") + ENDIF() + IF(CMAKE_CL_64) + SET(ILOG_WIN_COMPILER "x64_${ILOG_WIN_COMPILER}") + SET(ILOG_WIN_PLATFORM "x64_win32") + ELSE() + SET(ILOG_WIN_COMPILER "x86_${ILOG_WIN_COMPILER}") + SET(ILOG_WIN_PLATFORM "x86_win32") + ENDIF() +ENDIF() + +FIND_PATH(ILOG_CPLEX_ROOT_DIR + NAMES include/ilcplex + HINTS ${ILOG_ROOT_DIR}/cplex ${ILOG_ROOT_DIR}/cplex121 + ${ILOG_ROOT_DIR}/cplex122 ${ILOG_ROOT_DIR}/cplex123 + DOC "CPLEX root directory" + NO_DEFAULT_PATH +) + +FIND_PATH(ILOG_CONCERT_ROOT_DIR + NAMES include/ilconcert + HINTS ${ILOG_ROOT_DIR}/concert ${ILOG_ROOT_DIR}/concert29 + DOC "CONCERT root directory" + NO_DEFAULT_PATH +) + +FIND_PATH(ILOG_CPLEX_INCLUDE_DIR + ilcplex/cplex.h + HINTS ${ILOG_CPLEX_ROOT_DIR}/include + NO_DEFAULT_PATH +) + +FIND_PATH(ILOG_CONCERT_INCLUDE_DIR + ilconcert/ilobasic.h + HINTS ${ILOG_CONCERT_ROOT_DIR}/include + NO_DEFAULT_PATH +) + +FIND_LIBRARY(ILOG_CPLEX_LIBRARY + cplex cplex121 cplex122 cplex123 cplex124 + HINTS ${ILOG_CPLEX_ROOT_DIR}/lib/x86_sles10_4.1/static_pic + ${ILOG_CPLEX_ROOT_DIR}/lib/x86-64_sles10_4.1/static_pic + ${ILOG_CPLEX_ROOT_DIR}/lib/x86_debian4.0_4.1/static_pic + ${ILOG_CPLEX_ROOT_DIR}/lib/x86-64_debian4.0_4.1/static_pic + ${ILOG_CPLEX_ROOT_DIR}/lib/${ILOG_WIN_COMPILER}/stat_mda + NO_DEFAULT_PATH + ) + +FIND_LIBRARY(ILOG_CONCERT_LIBRARY + concert + HINTS ${ILOG_CONCERT_ROOT_DIR}/lib/x86_sles10_4.1/static_pic + ${ILOG_CONCERT_ROOT_DIR}/lib/x86-64_sles10_4.1/static_pic + ${ILOG_CONCERT_ROOT_DIR}/lib/x86_debian4.0_4.1/static_pic + ${ILOG_CONCERT_ROOT_DIR}/lib/x86-64_debian4.0_4.1/static_pic + ${ILOG_CONCERT_ROOT_DIR}/lib/${ILOG_WIN_COMPILER}/stat_mda + NO_DEFAULT_PATH + ) + +FIND_FILE(ILOG_CPLEX_DLL + cplex121.dll cplex122.dll cplex123.dll cplex124.dll + HINTS ${ILOG_CPLEX_ROOT_DIR}/bin/${ILOG_WIN_PLATFORM} + NO_DEFAULT_PATH + ) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(ILOG + DEFAULT_MSG ILOG_CPLEX_LIBRARY ILOG_CPLEX_INCLUDE_DIR + ) + +IF(ILOG_FOUND) + SET(ILOG_INCLUDE_DIRS ${ILOG_CPLEX_INCLUDE_DIR} ${ILOG_CONCERT_INCLUDE_DIR}) + SET(ILOG_LIBRARIES ${ILOG_CPLEX_LIBRARY} ${ILOG_CONCERT_LIBRARY}) + IF(CMAKE_SYSTEM_NAME STREQUAL "Linux") + # SET(CPLEX_LIBRARIES "${CPLEX_LIBRARIES};m;pthread") + SET(ILOG_LIBRARIES ${ILOG_LIBRARIES} "m" "pthread") + ENDIF(CMAKE_SYSTEM_NAME STREQUAL "Linux") +ENDIF(ILOG_FOUND) + +MARK_AS_ADVANCED( + ILOG_CPLEX_LIBRARY ILOG_CPLEX_INCLUDE_DIR ILOG_CPLEX_DLL + ILOG_CONCERT_LIBRARY ILOG_CONCERT_INCLUDE_DIR ILOG_CONCERT_DLL + ) diff --git a/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindSOPLEX.cmake b/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindSOPLEX.cmake new file mode 100644 index 00000000000..d27cff0f3e1 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindSOPLEX.cmake @@ -0,0 +1,23 @@ +SET(SOPLEX_ROOT_DIR "" CACHE PATH "SoPlex root directory") + +FIND_PATH(SOPLEX_INCLUDE_DIR + soplex.h + HINTS ${SOPLEX_ROOT_DIR}/src +) +FIND_LIBRARY(SOPLEX_LIBRARY + soplex + HINTS ${SOPLEX_ROOT_DIR}/lib +) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SOPLEX DEFAULT_MSG SOPLEX_LIBRARY SOPLEX_INCLUDE_DIR) + +IF(SOPLEX_FOUND) + SET(SOPLEX_INCLUDE_DIRS ${SOPLEX_INCLUDE_DIR}) + SET(SOPLEX_LIBRARIES ${SOPLEX_LIBRARY}) + IF(CMAKE_SYSTEM_NAME STREQUAL "Linux") + SET(SOPLEX_LIBRARIES "${SOPLEX_LIBRARIES};z") + ENDIF(CMAKE_SYSTEM_NAME STREQUAL "Linux") +ENDIF(SOPLEX_FOUND) + +MARK_AS_ADVANCED(SOPLEX_LIBRARY SOPLEX_INCLUDE_DIR) diff --git a/extern/quadriflow/3rd/lemon-1.3.1/cmake/LEMONConfig.cmake.in b/extern/quadriflow/3rd/lemon-1.3.1/cmake/LEMONConfig.cmake.in new file mode 100644 index 00000000000..b0d2d8b4c3f --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/cmake/LEMONConfig.cmake.in @@ -0,0 +1,13 @@ +SET(LEMON_INCLUDE_DIR "@CMAKE_INSTALL_PREFIX@/include" CACHE PATH "LEMON include directory") +SET(LEMON_INCLUDE_DIRS "${LEMON_INCLUDE_DIR}") + +IF(UNIX) + SET(LEMON_LIB_NAME "libemon.a") +ELSEIF(WIN32) + SET(LEMON_LIB_NAME "lemon.lib") +ENDIF(UNIX) + +SET(LEMON_LIBRARY "@CMAKE_INSTALL_PREFIX@/lib/${LEMON_LIB_NAME}" CACHE FILEPATH "LEMON library") +SET(LEMON_LIBRARIES "${LEMON_LIBRARY}") + +MARK_AS_ADVANCED(LEMON_LIBRARY LEMON_INCLUDE_DIR) diff --git a/extern/quadriflow/3rd/lemon-1.3.1/cmake/nsis/lemon.ico b/extern/quadriflow/3rd/lemon-1.3.1/cmake/nsis/lemon.ico new file mode 100644 index 00000000000..bbfd8c143d9 Binary files /dev/null and b/extern/quadriflow/3rd/lemon-1.3.1/cmake/nsis/lemon.ico differ diff --git a/extern/quadriflow/3rd/lemon-1.3.1/cmake/nsis/uninstall.ico b/extern/quadriflow/3rd/lemon-1.3.1/cmake/nsis/uninstall.ico new file mode 100644 index 00000000000..7495f7c3c27 Binary files /dev/null and b/extern/quadriflow/3rd/lemon-1.3.1/cmake/nsis/uninstall.ico differ diff --git a/extern/quadriflow/3rd/lemon-1.3.1/cmake/version.cmake b/extern/quadriflow/3rd/lemon-1.3.1/cmake/version.cmake new file mode 100644 index 00000000000..91369e1cac7 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/cmake/version.cmake @@ -0,0 +1 @@ +SET(LEMON_VERSION "1.3.1" CACHE STRING "LEMON version string.") diff --git a/extern/quadriflow/3rd/lemon-1.3.1/cmake/version.cmake.in b/extern/quadriflow/3rd/lemon-1.3.1/cmake/version.cmake.in new file mode 100644 index 00000000000..7cd4b689926 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/cmake/version.cmake.in @@ -0,0 +1 @@ +SET(LEMON_VERSION "@LEMON_VERSION@" CACHE STRING "LEMON version string.") diff --git a/extern/quadriflow/3rd/lemon-1.3.1/contrib/CMakeLists.txt b/extern/quadriflow/3rd/lemon-1.3.1/contrib/CMakeLists.txt new file mode 100644 index 00000000000..b6c11e2aad4 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/contrib/CMakeLists.txt @@ -0,0 +1,19 @@ +INCLUDE_DIRECTORIES( + ${PROJECT_SOURCE_DIR} + ${PROJECT_BINARY_DIR} +) + +LINK_DIRECTORIES( + ${PROJECT_BINARY_DIR}/lemon +) + +# Uncomment (and adjust) the following two lines. 'myprog' is the name +# of the final executable ('.exe' will automatically be added to the +# name on Windows) and 'myprog-main.cc' is the source code it is +# compiled from. You can add more source files separated by +# whitespaces. Moreover, you can add multiple similar blocks if you +# want to build more than one executables. + +# ADD_EXECUTABLE(myprog myprog-main.cc) +# TARGET_LINK_LIBRARIES(myprog lemon) + diff --git a/extern/quadriflow/3rd/lemon-1.3.1/demo/CMakeLists.txt b/extern/quadriflow/3rd/lemon-1.3.1/demo/CMakeLists.txt new file mode 100644 index 00000000000..e0566f407f0 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/demo/CMakeLists.txt @@ -0,0 +1,19 @@ +INCLUDE_DIRECTORIES( + ${PROJECT_SOURCE_DIR} + ${PROJECT_BINARY_DIR} +) + +LINK_DIRECTORIES( + ${PROJECT_BINARY_DIR}/lemon +) + +SET(DEMOS + arg_parser_demo + graph_to_eps_demo + lgf_demo +) + +FOREACH(DEMO_NAME ${DEMOS}) + ADD_EXECUTABLE(${DEMO_NAME} ${DEMO_NAME}.cc) + TARGET_LINK_LIBRARIES(${DEMO_NAME} lemon) +ENDFOREACH() diff --git a/extern/quadriflow/3rd/lemon-1.3.1/demo/arg_parser_demo.cc b/extern/quadriflow/3rd/lemon-1.3.1/demo/arg_parser_demo.cc new file mode 100644 index 00000000000..1bafac0c860 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/demo/arg_parser_demo.cc @@ -0,0 +1,112 @@ +/* -*- 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. + * + */ + +///\ingroup demos +///\file +///\brief Argument parser demo +/// +/// This example shows how the argument parser can be used. +/// +/// \include arg_parser_demo.cc + +#include + +using namespace lemon; +int main(int argc, char **argv) +{ + // Initialize the argument parser + ArgParser ap(argc, argv); + int i; + std::string s; + double d = 1.0; + bool b, nh; + bool g1, g2, g3; + + // Add a mandatory integer option with storage reference + ap.refOption("n", "An integer input.", i, true); + // Add a double option with storage reference (the default value is 1.0) + ap.refOption("val", "A double input.", d); + // Add a double option without storage reference (the default value is 3.14) + ap.doubleOption("val2", "A double input.", 3.14); + // Set synonym for -val option + ap.synonym("vals", "val"); + // Add a string option + ap.refOption("name", "A string input.", s); + // Add bool options + ap.refOption("f", "A switch.", b) + .refOption("nohelp", "", nh) + .refOption("gra", "Choice A", g1) + .refOption("grb", "Choice B", g2) + .refOption("grc", "Choice C", g3); + // Bundle -gr* options into a group + ap.optionGroup("gr", "gra") + .optionGroup("gr", "grb") + .optionGroup("gr", "grc"); + // Set the group mandatory + ap.mandatoryGroup("gr"); + // Set the options of the group exclusive (only one option can be given) + ap.onlyOneGroup("gr"); + // Add non-parsed arguments (e.g. input files) + ap.other("infile", "The input file.") + .other("..."); + + // Throw an exception when problems occurs. The default behavior is to + // exit(1) on these cases, but this makes Valgrind falsely warn + // about memory leaks. + ap.throwOnProblems(); + + // Perform the parsing process + // (in case of any error it terminates the program) + // The try {} construct is necessary only if the ap.trowOnProblems() + // setting is in use. + try { + ap.parse(); + } catch (ArgParserException &) { return 1; } + + // Check each option if it has been given and print its value + std::cout << "Parameters of '" << ap.commandName() << "':\n"; + + std::cout << " Value of -n: " << i << std::endl; + if(ap.given("val")) std::cout << " Value of -val: " << d << std::endl; + if(ap.given("val2")) { + d = ap["val2"]; + std::cout << " Value of -val2: " << d << std::endl; + } + if(ap.given("name")) std::cout << " Value of -name: " << s << std::endl; + if(ap.given("f")) std::cout << " -f is given\n"; + if(ap.given("nohelp")) std::cout << " Value of -nohelp: " << nh << std::endl; + if(ap.given("gra")) std::cout << " -gra is given\n"; + if(ap.given("grb")) std::cout << " -grb is given\n"; + if(ap.given("grc")) std::cout << " -grc is given\n"; + + switch(ap.files().size()) { + case 0: + std::cout << " No file argument was given.\n"; + break; + case 1: + std::cout << " 1 file argument was given. It is:\n"; + break; + default: + std::cout << " " + << ap.files().size() << " file arguments were given. They are:\n"; + } + for(unsigned int i=0;i.eps files demonstrating the capability of \ref +/// graphToEps(), and showing how to draw directed graphs, +/// how to handle parallel egdes, how to change the properties (like +/// color, shape, size, title etc.) of nodes and arcs individually +/// using appropriate graph maps. +/// +/// \include graph_to_eps_demo.cc + +#include +#include +#include + +using namespace std; +using namespace lemon; + +int main() +{ + Palette palette; + Palette paletteW(true); + + // Create a small digraph + ListDigraph g; + typedef ListDigraph::Node Node; + typedef ListDigraph::NodeIt NodeIt; + typedef ListDigraph::Arc Arc; + typedef dim2::Point Point; + + Node n1=g.addNode(); + Node n2=g.addNode(); + Node n3=g.addNode(); + Node n4=g.addNode(); + Node n5=g.addNode(); + + ListDigraph::NodeMap coords(g); + ListDigraph::NodeMap sizes(g); + ListDigraph::NodeMap colors(g); + ListDigraph::NodeMap shapes(g); + ListDigraph::ArcMap acolors(g); + ListDigraph::ArcMap widths(g); + + coords[n1]=Point(50,50); sizes[n1]=1; colors[n1]=1; shapes[n1]=0; + coords[n2]=Point(50,70); sizes[n2]=2; colors[n2]=2; shapes[n2]=2; + coords[n3]=Point(70,70); sizes[n3]=1; colors[n3]=3; shapes[n3]=0; + coords[n4]=Point(70,50); sizes[n4]=2; colors[n4]=4; shapes[n4]=1; + coords[n5]=Point(85,60); sizes[n5]=3; colors[n5]=5; shapes[n5]=2; + + Arc a; + + a=g.addArc(n1,n2); acolors[a]=0; widths[a]=1; + a=g.addArc(n2,n3); acolors[a]=0; widths[a]=1; + a=g.addArc(n3,n5); acolors[a]=0; widths[a]=3; + a=g.addArc(n5,n4); acolors[a]=0; widths[a]=1; + a=g.addArc(n4,n1); acolors[a]=0; widths[a]=1; + a=g.addArc(n2,n4); acolors[a]=1; widths[a]=2; + a=g.addArc(n3,n4); acolors[a]=2; widths[a]=1; + + IdMap id(g); + + // Create .eps files showing the digraph with different options + cout << "Create 'graph_to_eps_demo_out_1_pure.eps'" << endl; + graphToEps(g,"graph_to_eps_demo_out_1_pure.eps"). + coords(coords). + title("Sample .eps figure"). + copyright("(C) 2003-2009 LEMON Project"). + run(); + + cout << "Create 'graph_to_eps_demo_out_2.eps'" << endl; + graphToEps(g,"graph_to_eps_demo_out_2.eps"). + coords(coords). + title("Sample .eps figure"). + copyright("(C) 2003-2009 LEMON Project"). + absoluteNodeSizes().absoluteArcWidths(). + nodeScale(2).nodeSizes(sizes). + nodeShapes(shapes). + nodeColors(composeMap(palette,colors)). + arcColors(composeMap(palette,acolors)). + arcWidthScale(.4).arcWidths(widths). + nodeTexts(id).nodeTextSize(3). + run(); + + cout << "Create 'graph_to_eps_demo_out_3_arr.eps'" << endl; + graphToEps(g,"graph_to_eps_demo_out_3_arr.eps"). + title("Sample .eps figure (with arrowheads)"). + copyright("(C) 2003-2009 LEMON Project"). + absoluteNodeSizes().absoluteArcWidths(). + nodeColors(composeMap(palette,colors)). + coords(coords). + nodeScale(2).nodeSizes(sizes). + nodeShapes(shapes). + arcColors(composeMap(palette,acolors)). + arcWidthScale(.4).arcWidths(widths). + nodeTexts(id).nodeTextSize(3). + drawArrows().arrowWidth(2).arrowLength(2). + run(); + + // Add more arcs to the digraph + a=g.addArc(n1,n4); acolors[a]=2; widths[a]=1; + a=g.addArc(n4,n1); acolors[a]=1; widths[a]=2; + + a=g.addArc(n1,n2); acolors[a]=1; widths[a]=1; + a=g.addArc(n1,n2); acolors[a]=2; widths[a]=1; + a=g.addArc(n1,n2); acolors[a]=3; widths[a]=1; + a=g.addArc(n1,n2); acolors[a]=4; widths[a]=1; + a=g.addArc(n1,n2); acolors[a]=5; widths[a]=1; + a=g.addArc(n1,n2); acolors[a]=6; widths[a]=1; + a=g.addArc(n1,n2); acolors[a]=7; widths[a]=1; + + cout << "Create 'graph_to_eps_demo_out_4_par.eps'" << endl; + graphToEps(g,"graph_to_eps_demo_out_4_par.eps"). + title("Sample .eps figure (parallel arcs)"). + copyright("(C) 2003-2009 LEMON Project"). + absoluteNodeSizes().absoluteArcWidths(). + nodeShapes(shapes). + coords(coords). + nodeScale(2).nodeSizes(sizes). + nodeColors(composeMap(palette,colors)). + arcColors(composeMap(palette,acolors)). + arcWidthScale(.4).arcWidths(widths). + nodeTexts(id).nodeTextSize(3). + enableParallel().parArcDist(1.5). + run(); + + cout << "Create 'graph_to_eps_demo_out_5_par_arr.eps'" << endl; + graphToEps(g,"graph_to_eps_demo_out_5_par_arr.eps"). + title("Sample .eps figure (parallel arcs and arrowheads)"). + copyright("(C) 2003-2009 LEMON Project"). + absoluteNodeSizes().absoluteArcWidths(). + nodeScale(2).nodeSizes(sizes). + coords(coords). + nodeShapes(shapes). + nodeColors(composeMap(palette,colors)). + arcColors(composeMap(palette,acolors)). + arcWidthScale(.3).arcWidths(widths). + nodeTexts(id).nodeTextSize(3). + enableParallel().parArcDist(1). + drawArrows().arrowWidth(1).arrowLength(1). + run(); + + cout << "Create 'graph_to_eps_demo_out_6_par_arr_a4.eps'" << endl; + graphToEps(g,"graph_to_eps_demo_out_6_par_arr_a4.eps"). + title("Sample .eps figure (fits to A4)"). + copyright("(C) 2003-2009 LEMON Project"). + scaleToA4(). + absoluteNodeSizes().absoluteArcWidths(). + nodeScale(2).nodeSizes(sizes). + coords(coords). + nodeShapes(shapes). + nodeColors(composeMap(palette,colors)). + arcColors(composeMap(palette,acolors)). + arcWidthScale(.3).arcWidths(widths). + nodeTexts(id).nodeTextSize(3). + enableParallel().parArcDist(1). + drawArrows().arrowWidth(1).arrowLength(1). + run(); + + // Create an .eps file showing the colors of a default Palette + ListDigraph h; + ListDigraph::NodeMap hcolors(h); + ListDigraph::NodeMap hcoords(h); + + int cols=int(std::sqrt(double(palette.size()))); + for(int i=0;i +#include +#include +#include + +using namespace lemon; + +int main() { + SmartDigraph g; + SmartDigraph::ArcMap cap(g); + SmartDigraph::Node s, t; + + try { + digraphReader(g, "digraph.lgf"). // read the directed graph into g + arcMap("capacity", cap). // read the 'capacity' arc map into cap + node("source", s). // read 'source' node to s + node("target", t). // read 'target' node to t + run(); + } catch (Exception& error) { // check if there was any error + std::cerr << "Error: " << error.what() << std::endl; + return -1; + } + + std::cout << "A digraph is read from 'digraph.lgf'." << std::endl; + std::cout << "Number of nodes: " << countNodes(g) << std::endl; + std::cout << "Number of arcs: " << countArcs(g) << std::endl; + + std::cout << "We can write it to the standard output:" << std::endl; + + digraphWriter(g). // write g to the standard output + arcMap("capacity", cap). // write cap into 'capacity' + node("source", s). // write s to 'source' + node("target", t). // write t to 'target' + run(); + + return 0; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/CMakeLists.txt b/extern/quadriflow/3rd/lemon-1.3.1/lemon/CMakeLists.txt new file mode 100644 index 00000000000..4e6567e49c7 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/CMakeLists.txt @@ -0,0 +1,91 @@ +INCLUDE_DIRECTORIES( + ${PROJECT_SOURCE_DIR} + ${PROJECT_BINARY_DIR} +) + +CONFIGURE_FILE( + ${CMAKE_CURRENT_SOURCE_DIR}/config.h.in + ${CMAKE_CURRENT_BINARY_DIR}/config.h +) + +CONFIGURE_FILE( + ${CMAKE_CURRENT_SOURCE_DIR}/lemon.pc.in + ${CMAKE_CURRENT_BINARY_DIR}/lemon.pc + @ONLY +) + +SET(LEMON_SOURCES + arg_parser.cc + base.cc + color.cc + lp_base.cc + lp_skeleton.cc + random.cc + bits/windows.cc +) + +IF(LEMON_HAVE_GLPK) + SET(LEMON_SOURCES ${LEMON_SOURCES} glpk.cc) + INCLUDE_DIRECTORIES(${GLPK_INCLUDE_DIRS}) + IF(WIN32) + INSTALL(FILES ${GLPK_BIN_DIR}/glpk.dll DESTINATION bin) + INSTALL(FILES ${GLPK_BIN_DIR}/libltdl3.dll DESTINATION bin) + INSTALL(FILES ${GLPK_BIN_DIR}/zlib1.dll DESTINATION bin) + ENDIF() +ENDIF() + +IF(LEMON_HAVE_CPLEX) + SET(LEMON_SOURCES ${LEMON_SOURCES} cplex.cc) + INCLUDE_DIRECTORIES(${ILOG_INCLUDE_DIRS}) +ENDIF() + +IF(LEMON_HAVE_CLP) + SET(LEMON_SOURCES ${LEMON_SOURCES} clp.cc) + INCLUDE_DIRECTORIES(${COIN_INCLUDE_DIRS}) +ENDIF() + +IF(LEMON_HAVE_CBC) + SET(LEMON_SOURCES ${LEMON_SOURCES} cbc.cc) + INCLUDE_DIRECTORIES(${COIN_INCLUDE_DIRS}) +ENDIF() + +IF(LEMON_HAVE_SOPLEX) + SET(LEMON_SOURCES ${LEMON_SOURCES} soplex.cc) + INCLUDE_DIRECTORIES(${SOPLEX_INCLUDE_DIRS}) +ENDIF() + +ADD_LIBRARY(lemon ${LEMON_SOURCES}) + +TARGET_LINK_LIBRARIES(lemon + ${GLPK_LIBRARIES} ${COIN_LIBRARIES} ${ILOG_LIBRARIES} ${SOPLEX_LIBRARIES} + ) + +IF(UNIX) + SET_TARGET_PROPERTIES(lemon PROPERTIES OUTPUT_NAME emon VERSION ${LEMON_VERSION} SOVERSION ${LEMON_VERSION}) +ENDIF() + +INSTALL( + TARGETS lemon + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + COMPONENT library +) + +INSTALL( + DIRECTORY . bits concepts + DESTINATION include/lemon + COMPONENT headers + FILES_MATCHING PATTERN "*.h" +) + +INSTALL( + FILES ${CMAKE_CURRENT_BINARY_DIR}/config.h + DESTINATION include/lemon + COMPONENT headers +) + +INSTALL( + FILES ${CMAKE_CURRENT_BINARY_DIR}/lemon.pc + DESTINATION lib/pkgconfig +) + diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/adaptors.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/adaptors.h new file mode 100644 index 00000000000..1a40f8ea2c6 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/adaptors.h @@ -0,0 +1,3638 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_ADAPTORS_H +#define LEMON_ADAPTORS_H + +/// \ingroup graph_adaptors +/// \file +/// \brief Adaptor classes for digraphs and graphs +/// +/// This file contains several useful adaptors for digraphs and graphs. + +#include +#include +#include + +#include +#include +#include + +#include + +namespace lemon { + +#ifdef _MSC_VER +#define LEMON_SCOPE_FIX(OUTER, NESTED) OUTER::NESTED +#else +#define LEMON_SCOPE_FIX(OUTER, NESTED) typename OUTER::template NESTED +#endif + + template + class DigraphAdaptorBase { + public: + typedef DGR Digraph; + typedef DigraphAdaptorBase Adaptor; + + protected: + DGR* _digraph; + DigraphAdaptorBase() : _digraph(0) { } + void initialize(DGR& digraph) { _digraph = &digraph; } + + public: + DigraphAdaptorBase(DGR& digraph) : _digraph(&digraph) { } + + typedef typename DGR::Node Node; + typedef typename DGR::Arc Arc; + + void first(Node& i) const { _digraph->first(i); } + void first(Arc& i) const { _digraph->first(i); } + void firstIn(Arc& i, const Node& n) const { _digraph->firstIn(i, n); } + void firstOut(Arc& i, const Node& n ) const { _digraph->firstOut(i, n); } + + void next(Node& i) const { _digraph->next(i); } + void next(Arc& i) const { _digraph->next(i); } + void nextIn(Arc& i) const { _digraph->nextIn(i); } + void nextOut(Arc& i) const { _digraph->nextOut(i); } + + Node source(const Arc& a) const { return _digraph->source(a); } + Node target(const Arc& a) const { return _digraph->target(a); } + + typedef NodeNumTagIndicator NodeNumTag; + int nodeNum() const { return _digraph->nodeNum(); } + + typedef ArcNumTagIndicator ArcNumTag; + int arcNum() const { return _digraph->arcNum(); } + + typedef FindArcTagIndicator FindArcTag; + Arc findArc(const Node& u, const Node& v, const Arc& prev = INVALID) const { + return _digraph->findArc(u, v, prev); + } + + Node addNode() { return _digraph->addNode(); } + Arc addArc(const Node& u, const Node& v) { return _digraph->addArc(u, v); } + + void erase(const Node& n) { _digraph->erase(n); } + void erase(const Arc& a) { _digraph->erase(a); } + + void clear() { _digraph->clear(); } + + int id(const Node& n) const { return _digraph->id(n); } + int id(const Arc& a) const { return _digraph->id(a); } + + Node nodeFromId(int ix) const { return _digraph->nodeFromId(ix); } + Arc arcFromId(int ix) const { return _digraph->arcFromId(ix); } + + int maxNodeId() const { return _digraph->maxNodeId(); } + int maxArcId() const { return _digraph->maxArcId(); } + + typedef typename ItemSetTraits::ItemNotifier NodeNotifier; + NodeNotifier& notifier(Node) const { return _digraph->notifier(Node()); } + + typedef typename ItemSetTraits::ItemNotifier ArcNotifier; + ArcNotifier& notifier(Arc) const { return _digraph->notifier(Arc()); } + + template + class NodeMap : public DGR::template NodeMap { + typedef typename DGR::template NodeMap Parent; + + public: + explicit NodeMap(const Adaptor& adaptor) + : Parent(*adaptor._digraph) {} + NodeMap(const Adaptor& adaptor, const V& value) + : Parent(*adaptor._digraph, value) { } + + private: + NodeMap& operator=(const NodeMap& cmap) { + return operator=(cmap); + } + + template + NodeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + + }; + + template + class ArcMap : public DGR::template ArcMap { + typedef typename DGR::template ArcMap Parent; + + public: + explicit ArcMap(const DigraphAdaptorBase& adaptor) + : Parent(*adaptor._digraph) {} + ArcMap(const DigraphAdaptorBase& adaptor, const V& value) + : Parent(*adaptor._digraph, value) {} + + private: + ArcMap& operator=(const ArcMap& cmap) { + return operator=(cmap); + } + + template + ArcMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + + }; + + }; + + template + class GraphAdaptorBase { + public: + typedef GR Graph; + + protected: + GR* _graph; + + GraphAdaptorBase() : _graph(0) {} + + void initialize(GR& graph) { _graph = &graph; } + + public: + GraphAdaptorBase(GR& graph) : _graph(&graph) {} + + typedef typename GR::Node Node; + typedef typename GR::Arc Arc; + typedef typename GR::Edge Edge; + + void first(Node& i) const { _graph->first(i); } + void first(Arc& i) const { _graph->first(i); } + void first(Edge& i) const { _graph->first(i); } + void firstIn(Arc& i, const Node& n) const { _graph->firstIn(i, n); } + void firstOut(Arc& i, const Node& n ) const { _graph->firstOut(i, n); } + void firstInc(Edge &i, bool &d, const Node &n) const { + _graph->firstInc(i, d, n); + } + + void next(Node& i) const { _graph->next(i); } + void next(Arc& i) const { _graph->next(i); } + void next(Edge& i) const { _graph->next(i); } + void nextIn(Arc& i) const { _graph->nextIn(i); } + void nextOut(Arc& i) const { _graph->nextOut(i); } + void nextInc(Edge &i, bool &d) const { _graph->nextInc(i, d); } + + Node u(const Edge& e) const { return _graph->u(e); } + Node v(const Edge& e) const { return _graph->v(e); } + + Node source(const Arc& a) const { return _graph->source(a); } + Node target(const Arc& a) const { return _graph->target(a); } + + typedef NodeNumTagIndicator NodeNumTag; + int nodeNum() const { return _graph->nodeNum(); } + + typedef ArcNumTagIndicator ArcNumTag; + int arcNum() const { return _graph->arcNum(); } + + typedef EdgeNumTagIndicator EdgeNumTag; + int edgeNum() const { return _graph->edgeNum(); } + + typedef FindArcTagIndicator FindArcTag; + Arc findArc(const Node& u, const Node& v, + const Arc& prev = INVALID) const { + return _graph->findArc(u, v, prev); + } + + typedef FindEdgeTagIndicator FindEdgeTag; + Edge findEdge(const Node& u, const Node& v, + const Edge& prev = INVALID) const { + return _graph->findEdge(u, v, prev); + } + + Node addNode() { return _graph->addNode(); } + Edge addEdge(const Node& u, const Node& v) { return _graph->addEdge(u, v); } + + void erase(const Node& i) { _graph->erase(i); } + void erase(const Edge& i) { _graph->erase(i); } + + void clear() { _graph->clear(); } + + bool direction(const Arc& a) const { return _graph->direction(a); } + Arc direct(const Edge& e, bool d) const { return _graph->direct(e, d); } + + int id(const Node& v) const { return _graph->id(v); } + int id(const Arc& a) const { return _graph->id(a); } + int id(const Edge& e) const { return _graph->id(e); } + + Node nodeFromId(int ix) const { return _graph->nodeFromId(ix); } + Arc arcFromId(int ix) const { return _graph->arcFromId(ix); } + Edge edgeFromId(int ix) const { return _graph->edgeFromId(ix); } + + int maxNodeId() const { return _graph->maxNodeId(); } + int maxArcId() const { return _graph->maxArcId(); } + int maxEdgeId() const { return _graph->maxEdgeId(); } + + typedef typename ItemSetTraits::ItemNotifier NodeNotifier; + NodeNotifier& notifier(Node) const { return _graph->notifier(Node()); } + + typedef typename ItemSetTraits::ItemNotifier ArcNotifier; + ArcNotifier& notifier(Arc) const { return _graph->notifier(Arc()); } + + typedef typename ItemSetTraits::ItemNotifier EdgeNotifier; + EdgeNotifier& notifier(Edge) const { return _graph->notifier(Edge()); } + + template + class NodeMap : public GR::template NodeMap { + typedef typename GR::template NodeMap Parent; + + public: + explicit NodeMap(const GraphAdaptorBase& adapter) + : Parent(*adapter._graph) {} + NodeMap(const GraphAdaptorBase& adapter, const V& value) + : Parent(*adapter._graph, value) {} + + private: + NodeMap& operator=(const NodeMap& cmap) { + return operator=(cmap); + } + + template + NodeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + + }; + + template + class ArcMap : public GR::template ArcMap { + typedef typename GR::template ArcMap Parent; + + public: + explicit ArcMap(const GraphAdaptorBase& adapter) + : Parent(*adapter._graph) {} + ArcMap(const GraphAdaptorBase& adapter, const V& value) + : Parent(*adapter._graph, value) {} + + private: + ArcMap& operator=(const ArcMap& cmap) { + return operator=(cmap); + } + + template + ArcMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + }; + + template + class EdgeMap : public GR::template EdgeMap { + typedef typename GR::template EdgeMap Parent; + + public: + explicit EdgeMap(const GraphAdaptorBase& adapter) + : Parent(*adapter._graph) {} + EdgeMap(const GraphAdaptorBase& adapter, const V& value) + : Parent(*adapter._graph, value) {} + + private: + EdgeMap& operator=(const EdgeMap& cmap) { + return operator=(cmap); + } + + template + EdgeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + }; + + }; + + template + class ReverseDigraphBase : public DigraphAdaptorBase { + typedef DigraphAdaptorBase Parent; + public: + typedef DGR Digraph; + protected: + ReverseDigraphBase() : Parent() { } + public: + typedef typename Parent::Node Node; + typedef typename Parent::Arc Arc; + + void firstIn(Arc& a, const Node& n) const { Parent::firstOut(a, n); } + void firstOut(Arc& a, const Node& n ) const { Parent::firstIn(a, n); } + + void nextIn(Arc& a) const { Parent::nextOut(a); } + void nextOut(Arc& a) const { Parent::nextIn(a); } + + Node source(const Arc& a) const { return Parent::target(a); } + Node target(const Arc& a) const { return Parent::source(a); } + + Arc addArc(const Node& u, const Node& v) { return Parent::addArc(v, u); } + + typedef FindArcTagIndicator FindArcTag; + Arc findArc(const Node& u, const Node& v, + const Arc& prev = INVALID) const { + return Parent::findArc(v, u, prev); + } + + }; + + /// \ingroup graph_adaptors + /// + /// \brief Adaptor class for reversing the orientation of the arcs in + /// a digraph. + /// + /// ReverseDigraph can be used for reversing the arcs in a digraph. + /// It conforms to the \ref concepts::Digraph "Digraph" concept. + /// + /// The adapted digraph can also be modified through this adaptor + /// by adding or removing nodes or arcs, unless the \c GR template + /// parameter is set to be \c const. + /// + /// This class provides item counting in the same time as the adapted + /// digraph structure. + /// + /// \tparam DGR The type of the adapted digraph. + /// It must conform to the \ref concepts::Digraph "Digraph" concept. + /// It can also be specified to be \c const. + /// + /// \note The \c Node and \c Arc types of this adaptor and the adapted + /// digraph are convertible to each other. + template +#ifdef DOXYGEN + class ReverseDigraph { +#else + class ReverseDigraph : + public DigraphAdaptorExtender > { +#endif + typedef DigraphAdaptorExtender > Parent; + public: + /// The type of the adapted digraph. + typedef DGR Digraph; + protected: + ReverseDigraph() { } + public: + + /// \brief Constructor + /// + /// Creates a reverse digraph adaptor for the given digraph. + explicit ReverseDigraph(DGR& digraph) { + Parent::initialize(digraph); + } + }; + + /// \brief Returns a read-only ReverseDigraph adaptor + /// + /// This function just returns a read-only \ref ReverseDigraph adaptor. + /// \ingroup graph_adaptors + /// \relates ReverseDigraph + template + ReverseDigraph reverseDigraph(const DGR& digraph) { + return ReverseDigraph(digraph); + } + + + template + class SubDigraphBase : public DigraphAdaptorBase { + typedef DigraphAdaptorBase Parent; + public: + typedef DGR Digraph; + typedef NF NodeFilterMap; + typedef AF ArcFilterMap; + + typedef SubDigraphBase Adaptor; + protected: + NF* _node_filter; + AF* _arc_filter; + SubDigraphBase() + : Parent(), _node_filter(0), _arc_filter(0) { } + + void initialize(DGR& digraph, NF& node_filter, AF& arc_filter) { + Parent::initialize(digraph); + _node_filter = &node_filter; + _arc_filter = &arc_filter; + } + + public: + + typedef typename Parent::Node Node; + typedef typename Parent::Arc Arc; + + void first(Node& i) const { + Parent::first(i); + while (i != INVALID && !(*_node_filter)[i]) Parent::next(i); + } + + void first(Arc& i) const { + Parent::first(i); + while (i != INVALID && (!(*_arc_filter)[i] + || !(*_node_filter)[Parent::source(i)] + || !(*_node_filter)[Parent::target(i)])) + Parent::next(i); + } + + void firstIn(Arc& i, const Node& n) const { + Parent::firstIn(i, n); + while (i != INVALID && (!(*_arc_filter)[i] + || !(*_node_filter)[Parent::source(i)])) + Parent::nextIn(i); + } + + void firstOut(Arc& i, const Node& n) const { + Parent::firstOut(i, n); + while (i != INVALID && (!(*_arc_filter)[i] + || !(*_node_filter)[Parent::target(i)])) + Parent::nextOut(i); + } + + void next(Node& i) const { + Parent::next(i); + while (i != INVALID && !(*_node_filter)[i]) Parent::next(i); + } + + void next(Arc& i) const { + Parent::next(i); + while (i != INVALID && (!(*_arc_filter)[i] + || !(*_node_filter)[Parent::source(i)] + || !(*_node_filter)[Parent::target(i)])) + Parent::next(i); + } + + void nextIn(Arc& i) const { + Parent::nextIn(i); + while (i != INVALID && (!(*_arc_filter)[i] + || !(*_node_filter)[Parent::source(i)])) + Parent::nextIn(i); + } + + void nextOut(Arc& i) const { + Parent::nextOut(i); + while (i != INVALID && (!(*_arc_filter)[i] + || !(*_node_filter)[Parent::target(i)])) + Parent::nextOut(i); + } + + void status(const Node& n, bool v) const { _node_filter->set(n, v); } + void status(const Arc& a, bool v) const { _arc_filter->set(a, v); } + + bool status(const Node& n) const { return (*_node_filter)[n]; } + bool status(const Arc& a) const { return (*_arc_filter)[a]; } + + typedef False NodeNumTag; + typedef False ArcNumTag; + + typedef FindArcTagIndicator FindArcTag; + Arc findArc(const Node& source, const Node& target, + const Arc& prev = INVALID) const { + if (!(*_node_filter)[source] || !(*_node_filter)[target]) { + return INVALID; + } + Arc arc = Parent::findArc(source, target, prev); + while (arc != INVALID && !(*_arc_filter)[arc]) { + arc = Parent::findArc(source, target, arc); + } + return arc; + } + + public: + + template + class NodeMap + : public SubMapExtender, + LEMON_SCOPE_FIX(DigraphAdaptorBase, NodeMap)> { + typedef SubMapExtender, + LEMON_SCOPE_FIX(DigraphAdaptorBase, NodeMap)> Parent; + + public: + typedef V Value; + + NodeMap(const SubDigraphBase& adaptor) + : Parent(adaptor) {} + NodeMap(const SubDigraphBase& adaptor, const V& value) + : Parent(adaptor, value) {} + + private: + NodeMap& operator=(const NodeMap& cmap) { + return operator=(cmap); + } + + template + NodeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + }; + + template + class ArcMap + : public SubMapExtender, + LEMON_SCOPE_FIX(DigraphAdaptorBase, ArcMap)> { + typedef SubMapExtender, + LEMON_SCOPE_FIX(DigraphAdaptorBase, ArcMap)> Parent; + + public: + typedef V Value; + + ArcMap(const SubDigraphBase& adaptor) + : Parent(adaptor) {} + ArcMap(const SubDigraphBase& adaptor, const V& value) + : Parent(adaptor, value) {} + + private: + ArcMap& operator=(const ArcMap& cmap) { + return operator=(cmap); + } + + template + ArcMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + }; + + }; + + template + class SubDigraphBase + : public DigraphAdaptorBase { + typedef DigraphAdaptorBase Parent; + public: + typedef DGR Digraph; + typedef NF NodeFilterMap; + typedef AF ArcFilterMap; + + typedef SubDigraphBase Adaptor; + protected: + NF* _node_filter; + AF* _arc_filter; + SubDigraphBase() + : Parent(), _node_filter(0), _arc_filter(0) { } + + void initialize(DGR& digraph, NF& node_filter, AF& arc_filter) { + Parent::initialize(digraph); + _node_filter = &node_filter; + _arc_filter = &arc_filter; + } + + public: + + typedef typename Parent::Node Node; + typedef typename Parent::Arc Arc; + + void first(Node& i) const { + Parent::first(i); + while (i!=INVALID && !(*_node_filter)[i]) Parent::next(i); + } + + void first(Arc& i) const { + Parent::first(i); + while (i!=INVALID && !(*_arc_filter)[i]) Parent::next(i); + } + + void firstIn(Arc& i, const Node& n) const { + Parent::firstIn(i, n); + while (i!=INVALID && !(*_arc_filter)[i]) Parent::nextIn(i); + } + + void firstOut(Arc& i, const Node& n) const { + Parent::firstOut(i, n); + while (i!=INVALID && !(*_arc_filter)[i]) Parent::nextOut(i); + } + + void next(Node& i) const { + Parent::next(i); + while (i!=INVALID && !(*_node_filter)[i]) Parent::next(i); + } + void next(Arc& i) const { + Parent::next(i); + while (i!=INVALID && !(*_arc_filter)[i]) Parent::next(i); + } + void nextIn(Arc& i) const { + Parent::nextIn(i); + while (i!=INVALID && !(*_arc_filter)[i]) Parent::nextIn(i); + } + + void nextOut(Arc& i) const { + Parent::nextOut(i); + while (i!=INVALID && !(*_arc_filter)[i]) Parent::nextOut(i); + } + + void status(const Node& n, bool v) const { _node_filter->set(n, v); } + void status(const Arc& a, bool v) const { _arc_filter->set(a, v); } + + bool status(const Node& n) const { return (*_node_filter)[n]; } + bool status(const Arc& a) const { return (*_arc_filter)[a]; } + + typedef False NodeNumTag; + typedef False ArcNumTag; + + typedef FindArcTagIndicator FindArcTag; + Arc findArc(const Node& source, const Node& target, + const Arc& prev = INVALID) const { + if (!(*_node_filter)[source] || !(*_node_filter)[target]) { + return INVALID; + } + Arc arc = Parent::findArc(source, target, prev); + while (arc != INVALID && !(*_arc_filter)[arc]) { + arc = Parent::findArc(source, target, arc); + } + return arc; + } + + template + class NodeMap + : public SubMapExtender, + LEMON_SCOPE_FIX(DigraphAdaptorBase, NodeMap)> { + typedef SubMapExtender, + LEMON_SCOPE_FIX(DigraphAdaptorBase, NodeMap)> Parent; + + public: + typedef V Value; + + NodeMap(const SubDigraphBase& adaptor) + : Parent(adaptor) {} + NodeMap(const SubDigraphBase& adaptor, const V& value) + : Parent(adaptor, value) {} + + private: + NodeMap& operator=(const NodeMap& cmap) { + return operator=(cmap); + } + + template + NodeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + }; + + template + class ArcMap + : public SubMapExtender, + LEMON_SCOPE_FIX(DigraphAdaptorBase, ArcMap)> { + typedef SubMapExtender, + LEMON_SCOPE_FIX(DigraphAdaptorBase, ArcMap)> Parent; + + public: + typedef V Value; + + ArcMap(const SubDigraphBase& adaptor) + : Parent(adaptor) {} + ArcMap(const SubDigraphBase& adaptor, const V& value) + : Parent(adaptor, value) {} + + private: + ArcMap& operator=(const ArcMap& cmap) { + return operator=(cmap); + } + + template + ArcMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + }; + + }; + + /// \ingroup graph_adaptors + /// + /// \brief Adaptor class for hiding nodes and arcs in a digraph + /// + /// SubDigraph can be used for hiding nodes and arcs in a digraph. + /// A \c bool node map and a \c bool arc map must be specified, which + /// define the filters for nodes and arcs. + /// Only the nodes and arcs with \c true filter value are + /// shown in the subdigraph. The arcs that are incident to hidden + /// nodes are also filtered out. + /// This adaptor conforms to the \ref concepts::Digraph "Digraph" concept. + /// + /// The adapted digraph can also be modified through this adaptor + /// by adding or removing nodes or arcs, unless the \c GR template + /// parameter is set to be \c const. + /// + /// This class provides only linear time counting for nodes and arcs. + /// + /// \tparam DGR The type of the adapted digraph. + /// It must conform to the \ref concepts::Digraph "Digraph" concept. + /// It can also be specified to be \c const. + /// \tparam NF The type of the node filter map. + /// It must be a \c bool (or convertible) node map of the + /// adapted digraph. The default type is + /// \ref concepts::Digraph::NodeMap "DGR::NodeMap". + /// \tparam AF The type of the arc filter map. + /// It must be \c bool (or convertible) arc map of the + /// adapted digraph. The default type is + /// \ref concepts::Digraph::ArcMap "DGR::ArcMap". + /// + /// \note The \c Node and \c Arc types of this adaptor and the adapted + /// digraph are convertible to each other. + /// + /// \see FilterNodes + /// \see FilterArcs +#ifdef DOXYGEN + template + class SubDigraph { +#else + template, + typename AF = typename DGR::template ArcMap > + class SubDigraph : + public DigraphAdaptorExtender > { +#endif + public: + /// The type of the adapted digraph. + typedef DGR Digraph; + /// The type of the node filter map. + typedef NF NodeFilterMap; + /// The type of the arc filter map. + typedef AF ArcFilterMap; + + typedef DigraphAdaptorExtender > + Parent; + + typedef typename Parent::Node Node; + typedef typename Parent::Arc Arc; + + protected: + SubDigraph() { } + public: + + /// \brief Constructor + /// + /// Creates a subdigraph for the given digraph with the + /// given node and arc filter maps. + SubDigraph(DGR& digraph, NF& node_filter, AF& arc_filter) { + Parent::initialize(digraph, node_filter, arc_filter); + } + + /// \brief Sets the status of the given node + /// + /// This function sets the status of the given node. + /// It is done by simply setting the assigned value of \c n + /// to \c v in the node filter map. + void status(const Node& n, bool v) const { Parent::status(n, v); } + + /// \brief Sets the status of the given arc + /// + /// This function sets the status of the given arc. + /// It is done by simply setting the assigned value of \c a + /// to \c v in the arc filter map. + void status(const Arc& a, bool v) const { Parent::status(a, v); } + + /// \brief Returns the status of the given node + /// + /// This function returns the status of the given node. + /// It is \c true if the given node is enabled (i.e. not hidden). + bool status(const Node& n) const { return Parent::status(n); } + + /// \brief Returns the status of the given arc + /// + /// This function returns the status of the given arc. + /// It is \c true if the given arc is enabled (i.e. not hidden). + bool status(const Arc& a) const { return Parent::status(a); } + + /// \brief Disables the given node + /// + /// This function disables the given node in the subdigraph, + /// so the iteration jumps over it. + /// It is the same as \ref status() "status(n, false)". + void disable(const Node& n) const { Parent::status(n, false); } + + /// \brief Disables the given arc + /// + /// This function disables the given arc in the subdigraph, + /// so the iteration jumps over it. + /// It is the same as \ref status() "status(a, false)". + void disable(const Arc& a) const { Parent::status(a, false); } + + /// \brief Enables the given node + /// + /// This function enables the given node in the subdigraph. + /// It is the same as \ref status() "status(n, true)". + void enable(const Node& n) const { Parent::status(n, true); } + + /// \brief Enables the given arc + /// + /// This function enables the given arc in the subdigraph. + /// It is the same as \ref status() "status(a, true)". + void enable(const Arc& a) const { Parent::status(a, true); } + + }; + + /// \brief Returns a read-only SubDigraph adaptor + /// + /// This function just returns a read-only \ref SubDigraph adaptor. + /// \ingroup graph_adaptors + /// \relates SubDigraph + template + SubDigraph + subDigraph(const DGR& digraph, + NF& node_filter, AF& arc_filter) { + return SubDigraph + (digraph, node_filter, arc_filter); + } + + template + SubDigraph + subDigraph(const DGR& digraph, + const NF& node_filter, AF& arc_filter) { + return SubDigraph + (digraph, node_filter, arc_filter); + } + + template + SubDigraph + subDigraph(const DGR& digraph, + NF& node_filter, const AF& arc_filter) { + return SubDigraph + (digraph, node_filter, arc_filter); + } + + template + SubDigraph + subDigraph(const DGR& digraph, + const NF& node_filter, const AF& arc_filter) { + return SubDigraph + (digraph, node_filter, arc_filter); + } + + + template + class SubGraphBase : public GraphAdaptorBase { + typedef GraphAdaptorBase Parent; + public: + typedef GR Graph; + typedef NF NodeFilterMap; + typedef EF EdgeFilterMap; + + typedef SubGraphBase Adaptor; + protected: + + NF* _node_filter; + EF* _edge_filter; + + SubGraphBase() + : Parent(), _node_filter(0), _edge_filter(0) { } + + void initialize(GR& graph, NF& node_filter, EF& edge_filter) { + Parent::initialize(graph); + _node_filter = &node_filter; + _edge_filter = &edge_filter; + } + + public: + + typedef typename Parent::Node Node; + typedef typename Parent::Arc Arc; + typedef typename Parent::Edge Edge; + + void first(Node& i) const { + Parent::first(i); + while (i!=INVALID && !(*_node_filter)[i]) Parent::next(i); + } + + void first(Arc& i) const { + Parent::first(i); + while (i!=INVALID && (!(*_edge_filter)[i] + || !(*_node_filter)[Parent::source(i)] + || !(*_node_filter)[Parent::target(i)])) + Parent::next(i); + } + + void first(Edge& i) const { + Parent::first(i); + while (i!=INVALID && (!(*_edge_filter)[i] + || !(*_node_filter)[Parent::u(i)] + || !(*_node_filter)[Parent::v(i)])) + Parent::next(i); + } + + void firstIn(Arc& i, const Node& n) const { + Parent::firstIn(i, n); + while (i!=INVALID && (!(*_edge_filter)[i] + || !(*_node_filter)[Parent::source(i)])) + Parent::nextIn(i); + } + + void firstOut(Arc& i, const Node& n) const { + Parent::firstOut(i, n); + while (i!=INVALID && (!(*_edge_filter)[i] + || !(*_node_filter)[Parent::target(i)])) + Parent::nextOut(i); + } + + void firstInc(Edge& i, bool& d, const Node& n) const { + Parent::firstInc(i, d, n); + while (i!=INVALID && (!(*_edge_filter)[i] + || !(*_node_filter)[Parent::u(i)] + || !(*_node_filter)[Parent::v(i)])) + Parent::nextInc(i, d); + } + + void next(Node& i) const { + Parent::next(i); + while (i!=INVALID && !(*_node_filter)[i]) Parent::next(i); + } + + void next(Arc& i) const { + Parent::next(i); + while (i!=INVALID && (!(*_edge_filter)[i] + || !(*_node_filter)[Parent::source(i)] + || !(*_node_filter)[Parent::target(i)])) + Parent::next(i); + } + + void next(Edge& i) const { + Parent::next(i); + while (i!=INVALID && (!(*_edge_filter)[i] + || !(*_node_filter)[Parent::u(i)] + || !(*_node_filter)[Parent::v(i)])) + Parent::next(i); + } + + void nextIn(Arc& i) const { + Parent::nextIn(i); + while (i!=INVALID && (!(*_edge_filter)[i] + || !(*_node_filter)[Parent::source(i)])) + Parent::nextIn(i); + } + + void nextOut(Arc& i) const { + Parent::nextOut(i); + while (i!=INVALID && (!(*_edge_filter)[i] + || !(*_node_filter)[Parent::target(i)])) + Parent::nextOut(i); + } + + void nextInc(Edge& i, bool& d) const { + Parent::nextInc(i, d); + while (i!=INVALID && (!(*_edge_filter)[i] + || !(*_node_filter)[Parent::u(i)] + || !(*_node_filter)[Parent::v(i)])) + Parent::nextInc(i, d); + } + + void status(const Node& n, bool v) const { _node_filter->set(n, v); } + void status(const Edge& e, bool v) const { _edge_filter->set(e, v); } + + bool status(const Node& n) const { return (*_node_filter)[n]; } + bool status(const Edge& e) const { return (*_edge_filter)[e]; } + + typedef False NodeNumTag; + typedef False ArcNumTag; + typedef False EdgeNumTag; + + typedef FindArcTagIndicator FindArcTag; + Arc findArc(const Node& u, const Node& v, + const Arc& prev = INVALID) const { + if (!(*_node_filter)[u] || !(*_node_filter)[v]) { + return INVALID; + } + Arc arc = Parent::findArc(u, v, prev); + while (arc != INVALID && !(*_edge_filter)[arc]) { + arc = Parent::findArc(u, v, arc); + } + return arc; + } + + typedef FindEdgeTagIndicator FindEdgeTag; + Edge findEdge(const Node& u, const Node& v, + const Edge& prev = INVALID) const { + if (!(*_node_filter)[u] || !(*_node_filter)[v]) { + return INVALID; + } + Edge edge = Parent::findEdge(u, v, prev); + while (edge != INVALID && !(*_edge_filter)[edge]) { + edge = Parent::findEdge(u, v, edge); + } + return edge; + } + + template + class NodeMap + : public SubMapExtender, + LEMON_SCOPE_FIX(GraphAdaptorBase, NodeMap)> { + typedef SubMapExtender, + LEMON_SCOPE_FIX(GraphAdaptorBase, NodeMap)> Parent; + + public: + typedef V Value; + + NodeMap(const SubGraphBase& adaptor) + : Parent(adaptor) {} + NodeMap(const SubGraphBase& adaptor, const V& value) + : Parent(adaptor, value) {} + + private: + NodeMap& operator=(const NodeMap& cmap) { + return operator=(cmap); + } + + template + NodeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + }; + + template + class ArcMap + : public SubMapExtender, + LEMON_SCOPE_FIX(GraphAdaptorBase, ArcMap)> { + typedef SubMapExtender, + LEMON_SCOPE_FIX(GraphAdaptorBase, ArcMap)> Parent; + + public: + typedef V Value; + + ArcMap(const SubGraphBase& adaptor) + : Parent(adaptor) {} + ArcMap(const SubGraphBase& adaptor, const V& value) + : Parent(adaptor, value) {} + + private: + ArcMap& operator=(const ArcMap& cmap) { + return operator=(cmap); + } + + template + ArcMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + }; + + template + class EdgeMap + : public SubMapExtender, + LEMON_SCOPE_FIX(GraphAdaptorBase, EdgeMap)> { + typedef SubMapExtender, + LEMON_SCOPE_FIX(GraphAdaptorBase, EdgeMap)> Parent; + + public: + typedef V Value; + + EdgeMap(const SubGraphBase& adaptor) + : Parent(adaptor) {} + + EdgeMap(const SubGraphBase& adaptor, const V& value) + : Parent(adaptor, value) {} + + private: + EdgeMap& operator=(const EdgeMap& cmap) { + return operator=(cmap); + } + + template + EdgeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + }; + + }; + + template + class SubGraphBase + : public GraphAdaptorBase { + typedef GraphAdaptorBase Parent; + public: + typedef GR Graph; + typedef NF NodeFilterMap; + typedef EF EdgeFilterMap; + + typedef SubGraphBase Adaptor; + protected: + NF* _node_filter; + EF* _edge_filter; + SubGraphBase() + : Parent(), _node_filter(0), _edge_filter(0) { } + + void initialize(GR& graph, NF& node_filter, EF& edge_filter) { + Parent::initialize(graph); + _node_filter = &node_filter; + _edge_filter = &edge_filter; + } + + public: + + typedef typename Parent::Node Node; + typedef typename Parent::Arc Arc; + typedef typename Parent::Edge Edge; + + void first(Node& i) const { + Parent::first(i); + while (i!=INVALID && !(*_node_filter)[i]) Parent::next(i); + } + + void first(Arc& i) const { + Parent::first(i); + while (i!=INVALID && !(*_edge_filter)[i]) Parent::next(i); + } + + void first(Edge& i) const { + Parent::first(i); + while (i!=INVALID && !(*_edge_filter)[i]) Parent::next(i); + } + + void firstIn(Arc& i, const Node& n) const { + Parent::firstIn(i, n); + while (i!=INVALID && !(*_edge_filter)[i]) Parent::nextIn(i); + } + + void firstOut(Arc& i, const Node& n) const { + Parent::firstOut(i, n); + while (i!=INVALID && !(*_edge_filter)[i]) Parent::nextOut(i); + } + + void firstInc(Edge& i, bool& d, const Node& n) const { + Parent::firstInc(i, d, n); + while (i!=INVALID && !(*_edge_filter)[i]) Parent::nextInc(i, d); + } + + void next(Node& i) const { + Parent::next(i); + while (i!=INVALID && !(*_node_filter)[i]) Parent::next(i); + } + void next(Arc& i) const { + Parent::next(i); + while (i!=INVALID && !(*_edge_filter)[i]) Parent::next(i); + } + void next(Edge& i) const { + Parent::next(i); + while (i!=INVALID && !(*_edge_filter)[i]) Parent::next(i); + } + void nextIn(Arc& i) const { + Parent::nextIn(i); + while (i!=INVALID && !(*_edge_filter)[i]) Parent::nextIn(i); + } + + void nextOut(Arc& i) const { + Parent::nextOut(i); + while (i!=INVALID && !(*_edge_filter)[i]) Parent::nextOut(i); + } + void nextInc(Edge& i, bool& d) const { + Parent::nextInc(i, d); + while (i!=INVALID && !(*_edge_filter)[i]) Parent::nextInc(i, d); + } + + void status(const Node& n, bool v) const { _node_filter->set(n, v); } + void status(const Edge& e, bool v) const { _edge_filter->set(e, v); } + + bool status(const Node& n) const { return (*_node_filter)[n]; } + bool status(const Edge& e) const { return (*_edge_filter)[e]; } + + typedef False NodeNumTag; + typedef False ArcNumTag; + typedef False EdgeNumTag; + + typedef FindArcTagIndicator FindArcTag; + Arc findArc(const Node& u, const Node& v, + const Arc& prev = INVALID) const { + Arc arc = Parent::findArc(u, v, prev); + while (arc != INVALID && !(*_edge_filter)[arc]) { + arc = Parent::findArc(u, v, arc); + } + return arc; + } + + typedef FindEdgeTagIndicator FindEdgeTag; + Edge findEdge(const Node& u, const Node& v, + const Edge& prev = INVALID) const { + Edge edge = Parent::findEdge(u, v, prev); + while (edge != INVALID && !(*_edge_filter)[edge]) { + edge = Parent::findEdge(u, v, edge); + } + return edge; + } + + template + class NodeMap + : public SubMapExtender, + LEMON_SCOPE_FIX(GraphAdaptorBase, NodeMap)> { + typedef SubMapExtender, + LEMON_SCOPE_FIX(GraphAdaptorBase, NodeMap)> Parent; + + public: + typedef V Value; + + NodeMap(const SubGraphBase& adaptor) + : Parent(adaptor) {} + NodeMap(const SubGraphBase& adaptor, const V& value) + : Parent(adaptor, value) {} + + private: + NodeMap& operator=(const NodeMap& cmap) { + return operator=(cmap); + } + + template + NodeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + }; + + template + class ArcMap + : public SubMapExtender, + LEMON_SCOPE_FIX(GraphAdaptorBase, ArcMap)> { + typedef SubMapExtender, + LEMON_SCOPE_FIX(GraphAdaptorBase, ArcMap)> Parent; + + public: + typedef V Value; + + ArcMap(const SubGraphBase& adaptor) + : Parent(adaptor) {} + ArcMap(const SubGraphBase& adaptor, const V& value) + : Parent(adaptor, value) {} + + private: + ArcMap& operator=(const ArcMap& cmap) { + return operator=(cmap); + } + + template + ArcMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + }; + + template + class EdgeMap + : public SubMapExtender, + LEMON_SCOPE_FIX(GraphAdaptorBase, EdgeMap)> { + typedef SubMapExtender, + LEMON_SCOPE_FIX(GraphAdaptorBase, EdgeMap)> Parent; + + public: + typedef V Value; + + EdgeMap(const SubGraphBase& adaptor) + : Parent(adaptor) {} + + EdgeMap(const SubGraphBase& adaptor, const V& value) + : Parent(adaptor, value) {} + + private: + EdgeMap& operator=(const EdgeMap& cmap) { + return operator=(cmap); + } + + template + EdgeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + }; + + }; + + /// \ingroup graph_adaptors + /// + /// \brief Adaptor class for hiding nodes and edges in an undirected + /// graph. + /// + /// SubGraph can be used for hiding nodes and edges in a graph. + /// A \c bool node map and a \c bool edge map must be specified, which + /// define the filters for nodes and edges. + /// Only the nodes and edges with \c true filter value are + /// shown in the subgraph. The edges that are incident to hidden + /// nodes are also filtered out. + /// This adaptor conforms to the \ref concepts::Graph "Graph" concept. + /// + /// The adapted graph can also be modified through this adaptor + /// by adding or removing nodes or edges, unless the \c GR template + /// parameter is set to be \c const. + /// + /// This class provides only linear time counting for nodes, edges and arcs. + /// + /// \tparam GR The type of the adapted graph. + /// It must conform to the \ref concepts::Graph "Graph" concept. + /// It can also be specified to be \c const. + /// \tparam NF The type of the node filter map. + /// It must be a \c bool (or convertible) node map of the + /// adapted graph. The default type is + /// \ref concepts::Graph::NodeMap "GR::NodeMap". + /// \tparam EF The type of the edge filter map. + /// It must be a \c bool (or convertible) edge map of the + /// adapted graph. The default type is + /// \ref concepts::Graph::EdgeMap "GR::EdgeMap". + /// + /// \note The \c Node, \c Edge and \c Arc types of this adaptor and the + /// adapted graph are convertible to each other. + /// + /// \see FilterNodes + /// \see FilterEdges +#ifdef DOXYGEN + template + class SubGraph { +#else + template, + typename EF = typename GR::template EdgeMap > + class SubGraph : + public GraphAdaptorExtender > { +#endif + public: + /// The type of the adapted graph. + typedef GR Graph; + /// The type of the node filter map. + typedef NF NodeFilterMap; + /// The type of the edge filter map. + typedef EF EdgeFilterMap; + + typedef GraphAdaptorExtender > + Parent; + + typedef typename Parent::Node Node; + typedef typename Parent::Edge Edge; + + protected: + SubGraph() { } + public: + + /// \brief Constructor + /// + /// Creates a subgraph for the given graph with the given node + /// and edge filter maps. + SubGraph(GR& graph, NF& node_filter, EF& edge_filter) { + this->initialize(graph, node_filter, edge_filter); + } + + /// \brief Sets the status of the given node + /// + /// This function sets the status of the given node. + /// It is done by simply setting the assigned value of \c n + /// to \c v in the node filter map. + void status(const Node& n, bool v) const { Parent::status(n, v); } + + /// \brief Sets the status of the given edge + /// + /// This function sets the status of the given edge. + /// It is done by simply setting the assigned value of \c e + /// to \c v in the edge filter map. + void status(const Edge& e, bool v) const { Parent::status(e, v); } + + /// \brief Returns the status of the given node + /// + /// This function returns the status of the given node. + /// It is \c true if the given node is enabled (i.e. not hidden). + bool status(const Node& n) const { return Parent::status(n); } + + /// \brief Returns the status of the given edge + /// + /// This function returns the status of the given edge. + /// It is \c true if the given edge is enabled (i.e. not hidden). + bool status(const Edge& e) const { return Parent::status(e); } + + /// \brief Disables the given node + /// + /// This function disables the given node in the subdigraph, + /// so the iteration jumps over it. + /// It is the same as \ref status() "status(n, false)". + void disable(const Node& n) const { Parent::status(n, false); } + + /// \brief Disables the given edge + /// + /// This function disables the given edge in the subgraph, + /// so the iteration jumps over it. + /// It is the same as \ref status() "status(e, false)". + void disable(const Edge& e) const { Parent::status(e, false); } + + /// \brief Enables the given node + /// + /// This function enables the given node in the subdigraph. + /// It is the same as \ref status() "status(n, true)". + void enable(const Node& n) const { Parent::status(n, true); } + + /// \brief Enables the given edge + /// + /// This function enables the given edge in the subgraph. + /// It is the same as \ref status() "status(e, true)". + void enable(const Edge& e) const { Parent::status(e, true); } + + }; + + /// \brief Returns a read-only SubGraph adaptor + /// + /// This function just returns a read-only \ref SubGraph adaptor. + /// \ingroup graph_adaptors + /// \relates SubGraph + template + SubGraph + subGraph(const GR& graph, NF& node_filter, EF& edge_filter) { + return SubGraph + (graph, node_filter, edge_filter); + } + + template + SubGraph + subGraph(const GR& graph, const NF& node_filter, EF& edge_filter) { + return SubGraph + (graph, node_filter, edge_filter); + } + + template + SubGraph + subGraph(const GR& graph, NF& node_filter, const EF& edge_filter) { + return SubGraph + (graph, node_filter, edge_filter); + } + + template + SubGraph + subGraph(const GR& graph, const NF& node_filter, const EF& edge_filter) { + return SubGraph + (graph, node_filter, edge_filter); + } + + + /// \ingroup graph_adaptors + /// + /// \brief Adaptor class for hiding nodes in a digraph or a graph. + /// + /// FilterNodes adaptor can be used for hiding nodes in a digraph or a + /// graph. A \c bool node map must be specified, which defines the filter + /// for the nodes. Only the nodes with \c true filter value and the + /// arcs/edges incident to nodes both with \c true filter value are shown + /// in the subgraph. This adaptor conforms to the \ref concepts::Digraph + /// "Digraph" concept or the \ref concepts::Graph "Graph" concept + /// depending on the \c GR template parameter. + /// + /// The adapted (di)graph can also be modified through this adaptor + /// by adding or removing nodes or arcs/edges, unless the \c GR template + /// parameter is set to be \c const. + /// + /// This class provides only linear time item counting. + /// + /// \tparam GR The type of the adapted digraph or graph. + /// It must conform to the \ref concepts::Digraph "Digraph" concept + /// or the \ref concepts::Graph "Graph" concept. + /// It can also be specified to be \c const. + /// \tparam NF The type of the node filter map. + /// It must be a \c bool (or convertible) node map of the + /// adapted (di)graph. The default type is + /// \ref concepts::Graph::NodeMap "GR::NodeMap". + /// + /// \note The \c Node and Arc/Edge types of this adaptor and the + /// adapted (di)graph are convertible to each other. +#ifdef DOXYGEN + template + class FilterNodes { +#else + template, + typename Enable = void> + class FilterNodes : + public DigraphAdaptorExtender< + SubDigraphBase >, + true> > { +#endif + typedef DigraphAdaptorExtender< + SubDigraphBase >, + true> > Parent; + + public: + + typedef GR Digraph; + typedef NF NodeFilterMap; + + typedef typename Parent::Node Node; + + protected: + ConstMap > const_true_map; + + FilterNodes() : const_true_map() {} + + public: + + /// \brief Constructor + /// + /// Creates a subgraph for the given digraph or graph with the + /// given node filter map. + FilterNodes(GR& graph, NF& node_filter) + : Parent(), const_true_map() + { + Parent::initialize(graph, node_filter, const_true_map); + } + + /// \brief Sets the status of the given node + /// + /// This function sets the status of the given node. + /// It is done by simply setting the assigned value of \c n + /// to \c v in the node filter map. + void status(const Node& n, bool v) const { Parent::status(n, v); } + + /// \brief Returns the status of the given node + /// + /// This function returns the status of the given node. + /// It is \c true if the given node is enabled (i.e. not hidden). + bool status(const Node& n) const { return Parent::status(n); } + + /// \brief Disables the given node + /// + /// This function disables the given node, so the iteration + /// jumps over it. + /// It is the same as \ref status() "status(n, false)". + void disable(const Node& n) const { Parent::status(n, false); } + + /// \brief Enables the given node + /// + /// This function enables the given node. + /// It is the same as \ref status() "status(n, true)". + void enable(const Node& n) const { Parent::status(n, true); } + + }; + + template + class FilterNodes >::type> : + public GraphAdaptorExtender< + SubGraphBase >, + true> > { + + typedef GraphAdaptorExtender< + SubGraphBase >, + true> > Parent; + + public: + + typedef GR Graph; + typedef NF NodeFilterMap; + + typedef typename Parent::Node Node; + + protected: + ConstMap > const_true_map; + + FilterNodes() : const_true_map() {} + + public: + + FilterNodes(GR& graph, NodeFilterMap& node_filter) : + Parent(), const_true_map() { + Parent::initialize(graph, node_filter, const_true_map); + } + + void status(const Node& n, bool v) const { Parent::status(n, v); } + bool status(const Node& n) const { return Parent::status(n); } + void disable(const Node& n) const { Parent::status(n, false); } + void enable(const Node& n) const { Parent::status(n, true); } + + }; + + + /// \brief Returns a read-only FilterNodes adaptor + /// + /// This function just returns a read-only \ref FilterNodes adaptor. + /// \ingroup graph_adaptors + /// \relates FilterNodes + template + FilterNodes + filterNodes(const GR& graph, NF& node_filter) { + return FilterNodes(graph, node_filter); + } + + template + FilterNodes + filterNodes(const GR& graph, const NF& node_filter) { + return FilterNodes(graph, node_filter); + } + + /// \ingroup graph_adaptors + /// + /// \brief Adaptor class for hiding arcs in a digraph. + /// + /// FilterArcs adaptor can be used for hiding arcs in a digraph. + /// A \c bool arc map must be specified, which defines the filter for + /// the arcs. Only the arcs with \c true filter value are shown in the + /// subdigraph. This adaptor conforms to the \ref concepts::Digraph + /// "Digraph" concept. + /// + /// The adapted digraph can also be modified through this adaptor + /// by adding or removing nodes or arcs, unless the \c GR template + /// parameter is set to be \c const. + /// + /// This class provides only linear time counting for nodes and arcs. + /// + /// \tparam DGR The type of the adapted digraph. + /// It must conform to the \ref concepts::Digraph "Digraph" concept. + /// It can also be specified to be \c const. + /// \tparam AF The type of the arc filter map. + /// It must be a \c bool (or convertible) arc map of the + /// adapted digraph. The default type is + /// \ref concepts::Digraph::ArcMap "DGR::ArcMap". + /// + /// \note The \c Node and \c Arc types of this adaptor and the adapted + /// digraph are convertible to each other. +#ifdef DOXYGEN + template + class FilterArcs { +#else + template > + class FilterArcs : + public DigraphAdaptorExtender< + SubDigraphBase >, + AF, false> > { +#endif + typedef DigraphAdaptorExtender< + SubDigraphBase >, + AF, false> > Parent; + + public: + + /// The type of the adapted digraph. + typedef DGR Digraph; + /// The type of the arc filter map. + typedef AF ArcFilterMap; + + typedef typename Parent::Arc Arc; + + protected: + ConstMap > const_true_map; + + FilterArcs() : const_true_map() {} + + public: + + /// \brief Constructor + /// + /// Creates a subdigraph for the given digraph with the given arc + /// filter map. + FilterArcs(DGR& digraph, ArcFilterMap& arc_filter) + : Parent(), const_true_map() { + Parent::initialize(digraph, const_true_map, arc_filter); + } + + /// \brief Sets the status of the given arc + /// + /// This function sets the status of the given arc. + /// It is done by simply setting the assigned value of \c a + /// to \c v in the arc filter map. + void status(const Arc& a, bool v) const { Parent::status(a, v); } + + /// \brief Returns the status of the given arc + /// + /// This function returns the status of the given arc. + /// It is \c true if the given arc is enabled (i.e. not hidden). + bool status(const Arc& a) const { return Parent::status(a); } + + /// \brief Disables the given arc + /// + /// This function disables the given arc in the subdigraph, + /// so the iteration jumps over it. + /// It is the same as \ref status() "status(a, false)". + void disable(const Arc& a) const { Parent::status(a, false); } + + /// \brief Enables the given arc + /// + /// This function enables the given arc in the subdigraph. + /// It is the same as \ref status() "status(a, true)". + void enable(const Arc& a) const { Parent::status(a, true); } + + }; + + /// \brief Returns a read-only FilterArcs adaptor + /// + /// This function just returns a read-only \ref FilterArcs adaptor. + /// \ingroup graph_adaptors + /// \relates FilterArcs + template + FilterArcs + filterArcs(const DGR& digraph, AF& arc_filter) { + return FilterArcs(digraph, arc_filter); + } + + template + FilterArcs + filterArcs(const DGR& digraph, const AF& arc_filter) { + return FilterArcs(digraph, arc_filter); + } + + /// \ingroup graph_adaptors + /// + /// \brief Adaptor class for hiding edges in a graph. + /// + /// FilterEdges adaptor can be used for hiding edges in a graph. + /// A \c bool edge map must be specified, which defines the filter for + /// the edges. Only the edges with \c true filter value are shown in the + /// subgraph. This adaptor conforms to the \ref concepts::Graph + /// "Graph" concept. + /// + /// The adapted graph can also be modified through this adaptor + /// by adding or removing nodes or edges, unless the \c GR template + /// parameter is set to be \c const. + /// + /// This class provides only linear time counting for nodes, edges and arcs. + /// + /// \tparam GR The type of the adapted graph. + /// It must conform to the \ref concepts::Graph "Graph" concept. + /// It can also be specified to be \c const. + /// \tparam EF The type of the edge filter map. + /// It must be a \c bool (or convertible) edge map of the + /// adapted graph. The default type is + /// \ref concepts::Graph::EdgeMap "GR::EdgeMap". + /// + /// \note The \c Node, \c Edge and \c Arc types of this adaptor and the + /// adapted graph are convertible to each other. +#ifdef DOXYGEN + template + class FilterEdges { +#else + template > + class FilterEdges : + public GraphAdaptorExtender< + SubGraphBase >, + EF, false> > { +#endif + typedef GraphAdaptorExtender< + SubGraphBase >, + EF, false> > Parent; + + public: + + /// The type of the adapted graph. + typedef GR Graph; + /// The type of the edge filter map. + typedef EF EdgeFilterMap; + + typedef typename Parent::Edge Edge; + + protected: + ConstMap > const_true_map; + + FilterEdges() : const_true_map(true) { + Parent::setNodeFilterMap(const_true_map); + } + + public: + + /// \brief Constructor + /// + /// Creates a subgraph for the given graph with the given edge + /// filter map. + FilterEdges(GR& graph, EF& edge_filter) + : Parent(), const_true_map() { + Parent::initialize(graph, const_true_map, edge_filter); + } + + /// \brief Sets the status of the given edge + /// + /// This function sets the status of the given edge. + /// It is done by simply setting the assigned value of \c e + /// to \c v in the edge filter map. + void status(const Edge& e, bool v) const { Parent::status(e, v); } + + /// \brief Returns the status of the given edge + /// + /// This function returns the status of the given edge. + /// It is \c true if the given edge is enabled (i.e. not hidden). + bool status(const Edge& e) const { return Parent::status(e); } + + /// \brief Disables the given edge + /// + /// This function disables the given edge in the subgraph, + /// so the iteration jumps over it. + /// It is the same as \ref status() "status(e, false)". + void disable(const Edge& e) const { Parent::status(e, false); } + + /// \brief Enables the given edge + /// + /// This function enables the given edge in the subgraph. + /// It is the same as \ref status() "status(e, true)". + void enable(const Edge& e) const { Parent::status(e, true); } + + }; + + /// \brief Returns a read-only FilterEdges adaptor + /// + /// This function just returns a read-only \ref FilterEdges adaptor. + /// \ingroup graph_adaptors + /// \relates FilterEdges + template + FilterEdges + filterEdges(const GR& graph, EF& edge_filter) { + return FilterEdges(graph, edge_filter); + } + + template + FilterEdges + filterEdges(const GR& graph, const EF& edge_filter) { + return FilterEdges(graph, edge_filter); + } + + + template + class UndirectorBase { + public: + typedef DGR Digraph; + typedef UndirectorBase Adaptor; + + typedef True UndirectedTag; + + typedef typename Digraph::Arc Edge; + typedef typename Digraph::Node Node; + + class Arc { + friend class UndirectorBase; + protected: + Edge _edge; + bool _forward; + + Arc(const Edge& edge, bool forward) + : _edge(edge), _forward(forward) {} + + public: + Arc() {} + + Arc(Invalid) : _edge(INVALID), _forward(true) {} + + operator const Edge&() const { return _edge; } + + bool operator==(const Arc &other) const { + return _forward == other._forward && _edge == other._edge; + } + bool operator!=(const Arc &other) const { + return _forward != other._forward || _edge != other._edge; + } + bool operator<(const Arc &other) const { + return _forward < other._forward || + (_forward == other._forward && _edge < other._edge); + } + }; + + void first(Node& n) const { + _digraph->first(n); + } + + void next(Node& n) const { + _digraph->next(n); + } + + void first(Arc& a) const { + _digraph->first(a._edge); + a._forward = true; + } + + void next(Arc& a) const { + if (a._forward) { + a._forward = false; + } else { + _digraph->next(a._edge); + a._forward = true; + } + } + + void first(Edge& e) const { + _digraph->first(e); + } + + void next(Edge& e) const { + _digraph->next(e); + } + + void firstOut(Arc& a, const Node& n) const { + _digraph->firstIn(a._edge, n); + if (a._edge != INVALID ) { + a._forward = false; + } else { + _digraph->firstOut(a._edge, n); + a._forward = true; + } + } + void nextOut(Arc &a) const { + if (!a._forward) { + Node n = _digraph->target(a._edge); + _digraph->nextIn(a._edge); + if (a._edge == INVALID) { + _digraph->firstOut(a._edge, n); + a._forward = true; + } + } + else { + _digraph->nextOut(a._edge); + } + } + + void firstIn(Arc &a, const Node &n) const { + _digraph->firstOut(a._edge, n); + if (a._edge != INVALID ) { + a._forward = false; + } else { + _digraph->firstIn(a._edge, n); + a._forward = true; + } + } + void nextIn(Arc &a) const { + if (!a._forward) { + Node n = _digraph->source(a._edge); + _digraph->nextOut(a._edge); + if (a._edge == INVALID ) { + _digraph->firstIn(a._edge, n); + a._forward = true; + } + } + else { + _digraph->nextIn(a._edge); + } + } + + void firstInc(Edge &e, bool &d, const Node &n) const { + d = true; + _digraph->firstOut(e, n); + if (e != INVALID) return; + d = false; + _digraph->firstIn(e, n); + } + + void nextInc(Edge &e, bool &d) const { + if (d) { + Node s = _digraph->source(e); + _digraph->nextOut(e); + if (e != INVALID) return; + d = false; + _digraph->firstIn(e, s); + } else { + _digraph->nextIn(e); + } + } + + Node u(const Edge& e) const { + return _digraph->source(e); + } + + Node v(const Edge& e) const { + return _digraph->target(e); + } + + Node source(const Arc &a) const { + return a._forward ? _digraph->source(a._edge) : _digraph->target(a._edge); + } + + Node target(const Arc &a) const { + return a._forward ? _digraph->target(a._edge) : _digraph->source(a._edge); + } + + static Arc direct(const Edge &e, bool d) { + return Arc(e, d); + } + + static bool direction(const Arc &a) { return a._forward; } + + Node nodeFromId(int ix) const { return _digraph->nodeFromId(ix); } + Arc arcFromId(int ix) const { + return direct(_digraph->arcFromId(ix >> 1), bool(ix & 1)); + } + Edge edgeFromId(int ix) const { return _digraph->arcFromId(ix); } + + int id(const Node &n) const { return _digraph->id(n); } + int id(const Arc &a) const { + return (_digraph->id(a) << 1) | (a._forward ? 1 : 0); + } + int id(const Edge &e) const { return _digraph->id(e); } + + int maxNodeId() const { return _digraph->maxNodeId(); } + int maxArcId() const { return (_digraph->maxArcId() << 1) | 1; } + int maxEdgeId() const { return _digraph->maxArcId(); } + + Node addNode() { return _digraph->addNode(); } + Edge addEdge(const Node& u, const Node& v) { + return _digraph->addArc(u, v); + } + + void erase(const Node& i) { _digraph->erase(i); } + void erase(const Edge& i) { _digraph->erase(i); } + + void clear() { _digraph->clear(); } + + typedef NodeNumTagIndicator NodeNumTag; + int nodeNum() const { return _digraph->nodeNum(); } + + typedef ArcNumTagIndicator ArcNumTag; + int arcNum() const { return 2 * _digraph->arcNum(); } + + typedef ArcNumTag EdgeNumTag; + int edgeNum() const { return _digraph->arcNum(); } + + typedef FindArcTagIndicator FindArcTag; + Arc findArc(Node s, Node t, Arc p = INVALID) const { + if (p == INVALID) { + Edge arc = _digraph->findArc(s, t); + if (arc != INVALID) return direct(arc, true); + arc = _digraph->findArc(t, s); + if (arc != INVALID) return direct(arc, false); + } else if (direction(p)) { + Edge arc = _digraph->findArc(s, t, p); + if (arc != INVALID) return direct(arc, true); + arc = _digraph->findArc(t, s); + if (arc != INVALID) return direct(arc, false); + } else { + Edge arc = _digraph->findArc(t, s, p); + if (arc != INVALID) return direct(arc, false); + } + return INVALID; + } + + typedef FindArcTag FindEdgeTag; + Edge findEdge(Node s, Node t, Edge p = INVALID) const { + if (s != t) { + if (p == INVALID) { + Edge arc = _digraph->findArc(s, t); + if (arc != INVALID) return arc; + arc = _digraph->findArc(t, s); + if (arc != INVALID) return arc; + } else if (_digraph->source(p) == s) { + Edge arc = _digraph->findArc(s, t, p); + if (arc != INVALID) return arc; + arc = _digraph->findArc(t, s); + if (arc != INVALID) return arc; + } else { + Edge arc = _digraph->findArc(t, s, p); + if (arc != INVALID) return arc; + } + } else { + return _digraph->findArc(s, t, p); + } + return INVALID; + } + + private: + + template + class ArcMapBase { + private: + + typedef typename DGR::template ArcMap MapImpl; + + public: + + typedef typename MapTraits::ReferenceMapTag ReferenceMapTag; + + typedef V Value; + typedef Arc Key; + typedef typename MapTraits::ConstReturnValue ConstReturnValue; + typedef typename MapTraits::ReturnValue ReturnValue; + typedef typename MapTraits::ConstReturnValue ConstReference; + typedef typename MapTraits::ReturnValue Reference; + + ArcMapBase(const UndirectorBase& adaptor) : + _forward(*adaptor._digraph), _backward(*adaptor._digraph) {} + + ArcMapBase(const UndirectorBase& adaptor, const V& value) + : _forward(*adaptor._digraph, value), + _backward(*adaptor._digraph, value) {} + + void set(const Arc& a, const V& value) { + if (direction(a)) { + _forward.set(a, value); + } else { + _backward.set(a, value); + } + } + + ConstReturnValue operator[](const Arc& a) const { + if (direction(a)) { + return _forward[a]; + } else { + return _backward[a]; + } + } + + ReturnValue operator[](const Arc& a) { + if (direction(a)) { + return _forward[a]; + } else { + return _backward[a]; + } + } + + protected: + + MapImpl _forward, _backward; + + }; + + public: + + template + class NodeMap : public DGR::template NodeMap { + typedef typename DGR::template NodeMap Parent; + + public: + typedef V Value; + + explicit NodeMap(const UndirectorBase& adaptor) + : Parent(*adaptor._digraph) {} + + NodeMap(const UndirectorBase& adaptor, const V& value) + : Parent(*adaptor._digraph, value) { } + + private: + NodeMap& operator=(const NodeMap& cmap) { + return operator=(cmap); + } + + template + NodeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + + }; + + template + class ArcMap + : public SubMapExtender, ArcMapBase > { + typedef SubMapExtender, ArcMapBase > Parent; + + public: + typedef V Value; + + explicit ArcMap(const UndirectorBase& adaptor) + : Parent(adaptor) {} + + ArcMap(const UndirectorBase& adaptor, const V& value) + : Parent(adaptor, value) {} + + private: + ArcMap& operator=(const ArcMap& cmap) { + return operator=(cmap); + } + + template + ArcMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + }; + + template + class EdgeMap : public Digraph::template ArcMap { + typedef typename Digraph::template ArcMap Parent; + + public: + typedef V Value; + + explicit EdgeMap(const UndirectorBase& adaptor) + : Parent(*adaptor._digraph) {} + + EdgeMap(const UndirectorBase& adaptor, const V& value) + : Parent(*adaptor._digraph, value) {} + + private: + EdgeMap& operator=(const EdgeMap& cmap) { + return operator=(cmap); + } + + template + EdgeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + + }; + + typedef typename ItemSetTraits::ItemNotifier NodeNotifier; + NodeNotifier& notifier(Node) const { return _digraph->notifier(Node()); } + + typedef typename ItemSetTraits::ItemNotifier EdgeNotifier; + EdgeNotifier& notifier(Edge) const { return _digraph->notifier(Edge()); } + + typedef EdgeNotifier ArcNotifier; + ArcNotifier& notifier(Arc) const { return _digraph->notifier(Edge()); } + + protected: + + UndirectorBase() : _digraph(0) {} + + DGR* _digraph; + + void initialize(DGR& digraph) { + _digraph = &digraph; + } + + }; + + /// \ingroup graph_adaptors + /// + /// \brief Adaptor class for viewing a digraph as an undirected graph. + /// + /// Undirector adaptor can be used for viewing a digraph as an undirected + /// graph. All arcs of the underlying digraph are showed in the + /// adaptor as an edge (and also as a pair of arcs, of course). + /// This adaptor conforms to the \ref concepts::Graph "Graph" concept. + /// + /// The adapted digraph can also be modified through this adaptor + /// by adding or removing nodes or edges, unless the \c GR template + /// parameter is set to be \c const. + /// + /// This class provides item counting in the same time as the adapted + /// digraph structure. + /// + /// \tparam DGR The type of the adapted digraph. + /// It must conform to the \ref concepts::Digraph "Digraph" concept. + /// It can also be specified to be \c const. + /// + /// \note The \c Node type of this adaptor and the adapted digraph are + /// convertible to each other, moreover the \c Edge type of the adaptor + /// and the \c Arc type of the adapted digraph are also convertible to + /// each other. + /// (Thus the \c Arc type of the adaptor is convertible to the \c Arc type + /// of the adapted digraph.) + template +#ifdef DOXYGEN + class Undirector { +#else + class Undirector : + public GraphAdaptorExtender > { +#endif + typedef GraphAdaptorExtender > Parent; + public: + /// The type of the adapted digraph. + typedef DGR Digraph; + protected: + Undirector() { } + public: + + /// \brief Constructor + /// + /// Creates an undirected graph from the given digraph. + Undirector(DGR& digraph) { + this->initialize(digraph); + } + + /// \brief Arc map combined from two original arc maps + /// + /// This map adaptor class adapts two arc maps of the underlying + /// digraph to get an arc map of the undirected graph. + /// Its value type is inherited from the first arc map type (\c FW). + /// \tparam FW The type of the "foward" arc map. + /// \tparam BK The type of the "backward" arc map. + template + class CombinedArcMap { + public: + + /// The key type of the map + typedef typename Parent::Arc Key; + /// The value type of the map + typedef typename FW::Value Value; + + typedef typename MapTraits::ReferenceMapTag ReferenceMapTag; + + typedef typename MapTraits::ReturnValue ReturnValue; + typedef typename MapTraits::ConstReturnValue ConstReturnValue; + typedef typename MapTraits::ReturnValue Reference; + typedef typename MapTraits::ConstReturnValue ConstReference; + + /// Constructor + CombinedArcMap(FW& forward, BK& backward) + : _forward(&forward), _backward(&backward) {} + + /// Sets the value associated with the given key. + void set(const Key& e, const Value& a) { + if (Parent::direction(e)) { + _forward->set(e, a); + } else { + _backward->set(e, a); + } + } + + /// Returns the value associated with the given key. + ConstReturnValue operator[](const Key& e) const { + if (Parent::direction(e)) { + return (*_forward)[e]; + } else { + return (*_backward)[e]; + } + } + + /// Returns a reference to the value associated with the given key. + ReturnValue operator[](const Key& e) { + if (Parent::direction(e)) { + return (*_forward)[e]; + } else { + return (*_backward)[e]; + } + } + + protected: + + FW* _forward; + BK* _backward; + + }; + + /// \brief Returns a combined arc map + /// + /// This function just returns a combined arc map. + template + static CombinedArcMap + combinedArcMap(FW& forward, BK& backward) { + return CombinedArcMap(forward, backward); + } + + template + static CombinedArcMap + combinedArcMap(const FW& forward, BK& backward) { + return CombinedArcMap(forward, backward); + } + + template + static CombinedArcMap + combinedArcMap(FW& forward, const BK& backward) { + return CombinedArcMap(forward, backward); + } + + template + static CombinedArcMap + combinedArcMap(const FW& forward, const BK& backward) { + return CombinedArcMap(forward, backward); + } + + }; + + /// \brief Returns a read-only Undirector adaptor + /// + /// This function just returns a read-only \ref Undirector adaptor. + /// \ingroup graph_adaptors + /// \relates Undirector + template + Undirector undirector(const DGR& digraph) { + return Undirector(digraph); + } + + + template + class OrienterBase { + public: + + typedef GR Graph; + typedef DM DirectionMap; + + typedef typename GR::Node Node; + typedef typename GR::Edge Arc; + + void reverseArc(const Arc& arc) { + _direction->set(arc, !(*_direction)[arc]); + } + + void first(Node& i) const { _graph->first(i); } + void first(Arc& i) const { _graph->first(i); } + void firstIn(Arc& i, const Node& n) const { + bool d = true; + _graph->firstInc(i, d, n); + while (i != INVALID && d == (*_direction)[i]) _graph->nextInc(i, d); + } + void firstOut(Arc& i, const Node& n ) const { + bool d = true; + _graph->firstInc(i, d, n); + while (i != INVALID && d != (*_direction)[i]) _graph->nextInc(i, d); + } + + void next(Node& i) const { _graph->next(i); } + void next(Arc& i) const { _graph->next(i); } + void nextIn(Arc& i) const { + bool d = !(*_direction)[i]; + _graph->nextInc(i, d); + while (i != INVALID && d == (*_direction)[i]) _graph->nextInc(i, d); + } + void nextOut(Arc& i) const { + bool d = (*_direction)[i]; + _graph->nextInc(i, d); + while (i != INVALID && d != (*_direction)[i]) _graph->nextInc(i, d); + } + + Node source(const Arc& e) const { + return (*_direction)[e] ? _graph->u(e) : _graph->v(e); + } + Node target(const Arc& e) const { + return (*_direction)[e] ? _graph->v(e) : _graph->u(e); + } + + typedef NodeNumTagIndicator NodeNumTag; + int nodeNum() const { return _graph->nodeNum(); } + + typedef EdgeNumTagIndicator ArcNumTag; + int arcNum() const { return _graph->edgeNum(); } + + typedef FindEdgeTagIndicator FindArcTag; + Arc findArc(const Node& u, const Node& v, + const Arc& prev = INVALID) const { + Arc arc = _graph->findEdge(u, v, prev); + while (arc != INVALID && source(arc) != u) { + arc = _graph->findEdge(u, v, arc); + } + return arc; + } + + Node addNode() { + return Node(_graph->addNode()); + } + + Arc addArc(const Node& u, const Node& v) { + Arc arc = _graph->addEdge(u, v); + _direction->set(arc, _graph->u(arc) == u); + return arc; + } + + void erase(const Node& i) { _graph->erase(i); } + void erase(const Arc& i) { _graph->erase(i); } + + void clear() { _graph->clear(); } + + int id(const Node& v) const { return _graph->id(v); } + int id(const Arc& e) const { return _graph->id(e); } + + Node nodeFromId(int idx) const { return _graph->nodeFromId(idx); } + Arc arcFromId(int idx) const { return _graph->edgeFromId(idx); } + + int maxNodeId() const { return _graph->maxNodeId(); } + int maxArcId() const { return _graph->maxEdgeId(); } + + typedef typename ItemSetTraits::ItemNotifier NodeNotifier; + NodeNotifier& notifier(Node) const { return _graph->notifier(Node()); } + + typedef typename ItemSetTraits::ItemNotifier ArcNotifier; + ArcNotifier& notifier(Arc) const { return _graph->notifier(Arc()); } + + template + class NodeMap : public GR::template NodeMap { + typedef typename GR::template NodeMap Parent; + + public: + + explicit NodeMap(const OrienterBase& adapter) + : Parent(*adapter._graph) {} + + NodeMap(const OrienterBase& adapter, const V& value) + : Parent(*adapter._graph, value) {} + + private: + NodeMap& operator=(const NodeMap& cmap) { + return operator=(cmap); + } + + template + NodeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + + }; + + template + class ArcMap : public GR::template EdgeMap { + typedef typename Graph::template EdgeMap Parent; + + public: + + explicit ArcMap(const OrienterBase& adapter) + : Parent(*adapter._graph) { } + + ArcMap(const OrienterBase& adapter, const V& value) + : Parent(*adapter._graph, value) { } + + private: + ArcMap& operator=(const ArcMap& cmap) { + return operator=(cmap); + } + + template + ArcMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + }; + + + + protected: + Graph* _graph; + DM* _direction; + + void initialize(GR& graph, DM& direction) { + _graph = &graph; + _direction = &direction; + } + + }; + + /// \ingroup graph_adaptors + /// + /// \brief Adaptor class for orienting the edges of a graph to get a digraph + /// + /// Orienter adaptor can be used for orienting the edges of a graph to + /// get a digraph. A \c bool edge map of the underlying graph must be + /// specified, which define the direction of the arcs in the adaptor. + /// The arcs can be easily reversed by the \c reverseArc() member function + /// of the adaptor. + /// This class conforms to the \ref concepts::Digraph "Digraph" concept. + /// + /// The adapted graph can also be modified through this adaptor + /// by adding or removing nodes or arcs, unless the \c GR template + /// parameter is set to be \c const. + /// + /// This class provides item counting in the same time as the adapted + /// graph structure. + /// + /// \tparam GR The type of the adapted graph. + /// It must conform to the \ref concepts::Graph "Graph" concept. + /// It can also be specified to be \c const. + /// \tparam DM The type of the direction map. + /// It must be a \c bool (or convertible) edge map of the + /// adapted graph. The default type is + /// \ref concepts::Graph::EdgeMap "GR::EdgeMap". + /// + /// \note The \c Node type of this adaptor and the adapted graph are + /// convertible to each other, moreover the \c Arc type of the adaptor + /// and the \c Edge type of the adapted graph are also convertible to + /// each other. +#ifdef DOXYGEN + template + class Orienter { +#else + template > + class Orienter : + public DigraphAdaptorExtender > { +#endif + typedef DigraphAdaptorExtender > Parent; + public: + + /// The type of the adapted graph. + typedef GR Graph; + /// The type of the direction edge map. + typedef DM DirectionMap; + + typedef typename Parent::Arc Arc; + + protected: + Orienter() { } + + public: + + /// \brief Constructor + /// + /// Constructor of the adaptor. + Orienter(GR& graph, DM& direction) { + Parent::initialize(graph, direction); + } + + /// \brief Reverses the given arc + /// + /// This function reverses the given arc. + /// It is done by simply negate the assigned value of \c a + /// in the direction map. + void reverseArc(const Arc& a) { + Parent::reverseArc(a); + } + }; + + /// \brief Returns a read-only Orienter adaptor + /// + /// This function just returns a read-only \ref Orienter adaptor. + /// \ingroup graph_adaptors + /// \relates Orienter + template + Orienter + orienter(const GR& graph, DM& direction) { + return Orienter(graph, direction); + } + + template + Orienter + orienter(const GR& graph, const DM& direction) { + return Orienter(graph, direction); + } + + namespace _adaptor_bits { + + template + class ResForwardFilter { + public: + + typedef typename DGR::Arc Key; + typedef bool Value; + + private: + + const CM* _capacity; + const FM* _flow; + TL _tolerance; + + public: + + ResForwardFilter(const CM& capacity, const FM& flow, + const TL& tolerance = TL()) + : _capacity(&capacity), _flow(&flow), _tolerance(tolerance) { } + + bool operator[](const typename DGR::Arc& a) const { + return _tolerance.positive((*_capacity)[a] - (*_flow)[a]); + } + }; + + template + class ResBackwardFilter { + public: + + typedef typename DGR::Arc Key; + typedef bool Value; + + private: + + const CM* _capacity; + const FM* _flow; + TL _tolerance; + + public: + + ResBackwardFilter(const CM& capacity, const FM& flow, + const TL& tolerance = TL()) + : _capacity(&capacity), _flow(&flow), _tolerance(tolerance) { } + + bool operator[](const typename DGR::Arc& a) const { + return _tolerance.positive((*_flow)[a]); + } + }; + + } + + /// \ingroup graph_adaptors + /// + /// \brief Adaptor class for composing the residual digraph for directed + /// flow and circulation problems. + /// + /// ResidualDigraph can be used for composing the \e residual digraph + /// for directed flow and circulation problems. Let \f$ G=(V, A) \f$ + /// be a directed graph and let \f$ F \f$ be a number type. + /// Let \f$ flow, cap: A\to F \f$ be functions on the arcs. + /// This adaptor implements a digraph structure with node set \f$ V \f$ + /// and arc set \f$ A_{forward}\cup A_{backward} \f$, + /// where \f$ A_{forward}=\{uv : uv\in A, flow(uv)0\} \f$, i.e. the so + /// called residual digraph. + /// When the union \f$ A_{forward}\cup A_{backward} \f$ is taken, + /// multiplicities are counted, i.e. the adaptor has exactly + /// \f$ |A_{forward}| + |A_{backward}|\f$ arcs (it may have parallel + /// arcs). + /// This class conforms to the \ref concepts::Digraph "Digraph" concept. + /// + /// This class provides only linear time counting for nodes and arcs. + /// + /// \tparam DGR The type of the adapted digraph. + /// It must conform to the \ref concepts::Digraph "Digraph" concept. + /// It is implicitly \c const. + /// \tparam CM The type of the capacity map. + /// It must be an arc map of some numerical type, which defines + /// the capacities in the flow problem. It is implicitly \c const. + /// The default type is + /// \ref concepts::Digraph::ArcMap "GR::ArcMap". + /// \tparam FM The type of the flow map. + /// It must be an arc map of some numerical type, which defines + /// the flow values in the flow problem. The default type is \c CM. + /// \tparam TL The tolerance type for handling inexact computation. + /// The default tolerance type depends on the value type of the + /// capacity map. + /// + /// \note This adaptor is implemented using Undirector and FilterArcs + /// adaptors. + /// + /// \note The \c Node type of this adaptor and the adapted digraph are + /// convertible to each other, moreover the \c Arc type of the adaptor + /// is convertible to the \c Arc type of the adapted digraph. +#ifdef DOXYGEN + template + class ResidualDigraph +#else + template, + typename FM = CM, + typename TL = Tolerance > + class ResidualDigraph + : public SubDigraph< + Undirector, + ConstMap >, + typename Undirector::template CombinedArcMap< + _adaptor_bits::ResForwardFilter, + _adaptor_bits::ResBackwardFilter > > +#endif + { + public: + + /// The type of the underlying digraph. + typedef DGR Digraph; + /// The type of the capacity map. + typedef CM CapacityMap; + /// The type of the flow map. + typedef FM FlowMap; + /// The tolerance type. + typedef TL Tolerance; + + typedef typename CapacityMap::Value Value; + typedef ResidualDigraph Adaptor; + + protected: + + typedef Undirector Undirected; + + typedef ConstMap > NodeFilter; + + typedef _adaptor_bits::ResForwardFilter ForwardFilter; + + typedef _adaptor_bits::ResBackwardFilter BackwardFilter; + + typedef typename Undirected:: + template CombinedArcMap ArcFilter; + + typedef SubDigraph Parent; + + const CapacityMap* _capacity; + FlowMap* _flow; + + Undirected _graph; + NodeFilter _node_filter; + ForwardFilter _forward_filter; + BackwardFilter _backward_filter; + ArcFilter _arc_filter; + + public: + + /// \brief Constructor + /// + /// Constructor of the residual digraph adaptor. The parameters are the + /// digraph, the capacity map, the flow map, and a tolerance object. + ResidualDigraph(const DGR& digraph, const CM& capacity, + FM& flow, const TL& tolerance = Tolerance()) + : Parent(), _capacity(&capacity), _flow(&flow), + _graph(digraph), _node_filter(), + _forward_filter(capacity, flow, tolerance), + _backward_filter(capacity, flow, tolerance), + _arc_filter(_forward_filter, _backward_filter) + { + Parent::initialize(_graph, _node_filter, _arc_filter); + } + + typedef typename Parent::Arc Arc; + + /// \brief Returns the residual capacity of the given arc. + /// + /// Returns the residual capacity of the given arc. + Value residualCapacity(const Arc& a) const { + if (Undirected::direction(a)) { + return (*_capacity)[a] - (*_flow)[a]; + } else { + return (*_flow)[a]; + } + } + + /// \brief Augments on the given arc in the residual digraph. + /// + /// Augments on the given arc in the residual digraph. It increases + /// or decreases the flow value on the original arc according to the + /// direction of the residual arc. + void augment(const Arc& a, const Value& v) const { + if (Undirected::direction(a)) { + _flow->set(a, (*_flow)[a] + v); + } else { + _flow->set(a, (*_flow)[a] - v); + } + } + + /// \brief Returns \c true if the given residual arc is a forward arc. + /// + /// Returns \c true if the given residual arc has the same orientation + /// as the original arc, i.e. it is a so called forward arc. + static bool forward(const Arc& a) { + return Undirected::direction(a); + } + + /// \brief Returns \c true if the given residual arc is a backward arc. + /// + /// Returns \c true if the given residual arc has the opposite orientation + /// than the original arc, i.e. it is a so called backward arc. + static bool backward(const Arc& a) { + return !Undirected::direction(a); + } + + /// \brief Returns the forward oriented residual arc. + /// + /// Returns the forward oriented residual arc related to the given + /// arc of the underlying digraph. + static Arc forward(const typename Digraph::Arc& a) { + return Undirected::direct(a, true); + } + + /// \brief Returns the backward oriented residual arc. + /// + /// Returns the backward oriented residual arc related to the given + /// arc of the underlying digraph. + static Arc backward(const typename Digraph::Arc& a) { + return Undirected::direct(a, false); + } + + /// \brief Residual capacity map. + /// + /// This map adaptor class can be used for obtaining the residual + /// capacities as an arc map of the residual digraph. + /// Its value type is inherited from the capacity map. + class ResidualCapacity { + protected: + const Adaptor* _adaptor; + public: + /// The key type of the map + typedef Arc Key; + /// The value type of the map + typedef typename CapacityMap::Value Value; + + /// Constructor + ResidualCapacity(const ResidualDigraph& adaptor) + : _adaptor(&adaptor) {} + + /// Returns the value associated with the given residual arc + Value operator[](const Arc& a) const { + return _adaptor->residualCapacity(a); + } + + }; + + /// \brief Returns a residual capacity map + /// + /// This function just returns a residual capacity map. + ResidualCapacity residualCapacity() const { + return ResidualCapacity(*this); + } + + }; + + /// \brief Returns a (read-only) Residual adaptor + /// + /// This function just returns a (read-only) \ref ResidualDigraph adaptor. + /// \ingroup graph_adaptors + /// \relates ResidualDigraph + template + ResidualDigraph + residualDigraph(const DGR& digraph, const CM& capacity_map, FM& flow_map) { + return ResidualDigraph (digraph, capacity_map, flow_map); + } + + + template + class SplitNodesBase { + typedef DigraphAdaptorBase Parent; + + public: + + typedef DGR Digraph; + typedef SplitNodesBase Adaptor; + + typedef typename DGR::Node DigraphNode; + typedef typename DGR::Arc DigraphArc; + + class Node; + class Arc; + + private: + + template class NodeMapBase; + template class ArcMapBase; + + public: + + class Node : public DigraphNode { + friend class SplitNodesBase; + template friend class NodeMapBase; + private: + + bool _in; + Node(DigraphNode node, bool in) + : DigraphNode(node), _in(in) {} + + public: + + Node() {} + Node(Invalid) : DigraphNode(INVALID), _in(true) {} + + bool operator==(const Node& node) const { + return DigraphNode::operator==(node) && _in == node._in; + } + + bool operator!=(const Node& node) const { + return !(*this == node); + } + + bool operator<(const Node& node) const { + return DigraphNode::operator<(node) || + (DigraphNode::operator==(node) && _in < node._in); + } + }; + + class Arc { + friend class SplitNodesBase; + template friend class ArcMapBase; + private: + typedef BiVariant ArcImpl; + + explicit Arc(const DigraphArc& arc) : _item(arc) {} + explicit Arc(const DigraphNode& node) : _item(node) {} + + ArcImpl _item; + + public: + Arc() {} + Arc(Invalid) : _item(DigraphArc(INVALID)) {} + + bool operator==(const Arc& arc) const { + if (_item.firstState()) { + if (arc._item.firstState()) { + return _item.first() == arc._item.first(); + } + } else { + if (arc._item.secondState()) { + return _item.second() == arc._item.second(); + } + } + return false; + } + + bool operator!=(const Arc& arc) const { + return !(*this == arc); + } + + bool operator<(const Arc& arc) const { + if (_item.firstState()) { + if (arc._item.firstState()) { + return _item.first() < arc._item.first(); + } + return false; + } else { + if (arc._item.secondState()) { + return _item.second() < arc._item.second(); + } + return true; + } + } + + operator DigraphArc() const { return _item.first(); } + operator DigraphNode() const { return _item.second(); } + + }; + + void first(Node& n) const { + _digraph->first(n); + n._in = true; + } + + void next(Node& n) const { + if (n._in) { + n._in = false; + } else { + n._in = true; + _digraph->next(n); + } + } + + void first(Arc& e) const { + e._item.setSecond(); + _digraph->first(e._item.second()); + if (e._item.second() == INVALID) { + e._item.setFirst(); + _digraph->first(e._item.first()); + } + } + + void next(Arc& e) const { + if (e._item.secondState()) { + _digraph->next(e._item.second()); + if (e._item.second() == INVALID) { + e._item.setFirst(); + _digraph->first(e._item.first()); + } + } else { + _digraph->next(e._item.first()); + } + } + + void firstOut(Arc& e, const Node& n) const { + if (n._in) { + e._item.setSecond(n); + } else { + e._item.setFirst(); + _digraph->firstOut(e._item.first(), n); + } + } + + void nextOut(Arc& e) const { + if (!e._item.firstState()) { + e._item.setFirst(INVALID); + } else { + _digraph->nextOut(e._item.first()); + } + } + + void firstIn(Arc& e, const Node& n) const { + if (!n._in) { + e._item.setSecond(n); + } else { + e._item.setFirst(); + _digraph->firstIn(e._item.first(), n); + } + } + + void nextIn(Arc& e) const { + if (!e._item.firstState()) { + e._item.setFirst(INVALID); + } else { + _digraph->nextIn(e._item.first()); + } + } + + Node source(const Arc& e) const { + if (e._item.firstState()) { + return Node(_digraph->source(e._item.first()), false); + } else { + return Node(e._item.second(), true); + } + } + + Node target(const Arc& e) const { + if (e._item.firstState()) { + return Node(_digraph->target(e._item.first()), true); + } else { + return Node(e._item.second(), false); + } + } + + int id(const Node& n) const { + return (_digraph->id(n) << 1) | (n._in ? 0 : 1); + } + Node nodeFromId(int ix) const { + return Node(_digraph->nodeFromId(ix >> 1), (ix & 1) == 0); + } + int maxNodeId() const { + return 2 * _digraph->maxNodeId() + 1; + } + + int id(const Arc& e) const { + if (e._item.firstState()) { + return _digraph->id(e._item.first()) << 1; + } else { + return (_digraph->id(e._item.second()) << 1) | 1; + } + } + Arc arcFromId(int ix) const { + if ((ix & 1) == 0) { + return Arc(_digraph->arcFromId(ix >> 1)); + } else { + return Arc(_digraph->nodeFromId(ix >> 1)); + } + } + int maxArcId() const { + return std::max(_digraph->maxNodeId() << 1, + (_digraph->maxArcId() << 1) | 1); + } + + static bool inNode(const Node& n) { + return n._in; + } + + static bool outNode(const Node& n) { + return !n._in; + } + + static bool origArc(const Arc& e) { + return e._item.firstState(); + } + + static bool bindArc(const Arc& e) { + return e._item.secondState(); + } + + static Node inNode(const DigraphNode& n) { + return Node(n, true); + } + + static Node outNode(const DigraphNode& n) { + return Node(n, false); + } + + static Arc arc(const DigraphNode& n) { + return Arc(n); + } + + static Arc arc(const DigraphArc& e) { + return Arc(e); + } + + typedef True NodeNumTag; + int nodeNum() const { + return 2 * countNodes(*_digraph); + } + + typedef True ArcNumTag; + int arcNum() const { + return countArcs(*_digraph) + countNodes(*_digraph); + } + + typedef True FindArcTag; + Arc findArc(const Node& u, const Node& v, + const Arc& prev = INVALID) const { + if (inNode(u) && outNode(v)) { + if (static_cast(u) == + static_cast(v) && prev == INVALID) { + return Arc(u); + } + } + else if (outNode(u) && inNode(v)) { + return Arc(::lemon::findArc(*_digraph, u, v, prev)); + } + return INVALID; + } + + private: + + template + class NodeMapBase + : public MapTraits > { + typedef typename Parent::template NodeMap NodeImpl; + public: + typedef Node Key; + typedef V Value; + typedef typename MapTraits::ReferenceMapTag ReferenceMapTag; + typedef typename MapTraits::ReturnValue ReturnValue; + typedef typename MapTraits::ConstReturnValue ConstReturnValue; + typedef typename MapTraits::ReturnValue Reference; + typedef typename MapTraits::ConstReturnValue ConstReference; + + NodeMapBase(const SplitNodesBase& adaptor) + : _in_map(*adaptor._digraph), _out_map(*adaptor._digraph) {} + NodeMapBase(const SplitNodesBase& adaptor, const V& value) + : _in_map(*adaptor._digraph, value), + _out_map(*adaptor._digraph, value) {} + + void set(const Node& key, const V& val) { + if (SplitNodesBase::inNode(key)) { _in_map.set(key, val); } + else {_out_map.set(key, val); } + } + + ReturnValue operator[](const Node& key) { + if (SplitNodesBase::inNode(key)) { return _in_map[key]; } + else { return _out_map[key]; } + } + + ConstReturnValue operator[](const Node& key) const { + if (Adaptor::inNode(key)) { return _in_map[key]; } + else { return _out_map[key]; } + } + + private: + NodeImpl _in_map, _out_map; + }; + + template + class ArcMapBase + : public MapTraits > { + typedef typename Parent::template ArcMap ArcImpl; + typedef typename Parent::template NodeMap NodeImpl; + public: + typedef Arc Key; + typedef V Value; + typedef typename MapTraits::ReferenceMapTag ReferenceMapTag; + typedef typename MapTraits::ReturnValue ReturnValue; + typedef typename MapTraits::ConstReturnValue ConstReturnValue; + typedef typename MapTraits::ReturnValue Reference; + typedef typename MapTraits::ConstReturnValue ConstReference; + + ArcMapBase(const SplitNodesBase& adaptor) + : _arc_map(*adaptor._digraph), _node_map(*adaptor._digraph) {} + ArcMapBase(const SplitNodesBase& adaptor, const V& value) + : _arc_map(*adaptor._digraph, value), + _node_map(*adaptor._digraph, value) {} + + void set(const Arc& key, const V& val) { + if (SplitNodesBase::origArc(key)) { + _arc_map.set(static_cast(key), val); + } else { + _node_map.set(static_cast(key), val); + } + } + + ReturnValue operator[](const Arc& key) { + if (SplitNodesBase::origArc(key)) { + return _arc_map[static_cast(key)]; + } else { + return _node_map[static_cast(key)]; + } + } + + ConstReturnValue operator[](const Arc& key) const { + if (SplitNodesBase::origArc(key)) { + return _arc_map[static_cast(key)]; + } else { + return _node_map[static_cast(key)]; + } + } + + private: + ArcImpl _arc_map; + NodeImpl _node_map; + }; + + public: + + template + class NodeMap + : public SubMapExtender, NodeMapBase > { + typedef SubMapExtender, NodeMapBase > Parent; + + public: + typedef V Value; + + NodeMap(const SplitNodesBase& adaptor) + : Parent(adaptor) {} + + NodeMap(const SplitNodesBase& adaptor, const V& value) + : Parent(adaptor, value) {} + + private: + NodeMap& operator=(const NodeMap& cmap) { + return operator=(cmap); + } + + template + NodeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + }; + + template + class ArcMap + : public SubMapExtender, ArcMapBase > { + typedef SubMapExtender, ArcMapBase > Parent; + + public: + typedef V Value; + + ArcMap(const SplitNodesBase& adaptor) + : Parent(adaptor) {} + + ArcMap(const SplitNodesBase& adaptor, const V& value) + : Parent(adaptor, value) {} + + private: + ArcMap& operator=(const ArcMap& cmap) { + return operator=(cmap); + } + + template + ArcMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + }; + + protected: + + SplitNodesBase() : _digraph(0) {} + + DGR* _digraph; + + void initialize(Digraph& digraph) { + _digraph = &digraph; + } + + }; + + /// \ingroup graph_adaptors + /// + /// \brief Adaptor class for splitting the nodes of a digraph. + /// + /// SplitNodes adaptor can be used for splitting each node into an + /// \e in-node and an \e out-node in a digraph. Formaly, the adaptor + /// replaces each node \f$ u \f$ in the digraph with two nodes, + /// namely node \f$ u_{in} \f$ and node \f$ u_{out} \f$. + /// If there is a \f$ (v, u) \f$ arc in the original digraph, then the + /// new target of the arc will be \f$ u_{in} \f$ and similarly the + /// source of each original \f$ (u, v) \f$ arc will be \f$ u_{out} \f$. + /// The adaptor adds an additional \e bind \e arc from \f$ u_{in} \f$ + /// to \f$ u_{out} \f$ for each node \f$ u \f$ of the original digraph. + /// + /// The aim of this class is running an algorithm with respect to node + /// costs or capacities if the algorithm considers only arc costs or + /// capacities directly. + /// In this case you can use \c SplitNodes adaptor, and set the node + /// costs/capacities of the original digraph to the \e bind \e arcs + /// in the adaptor. + /// + /// This class provides item counting in the same time as the adapted + /// digraph structure. + /// + /// \tparam DGR The type of the adapted digraph. + /// It must conform to the \ref concepts::Digraph "Digraph" concept. + /// It is implicitly \c const. + /// + /// \note The \c Node type of this adaptor is converible to the \c Node + /// type of the adapted digraph. + template +#ifdef DOXYGEN + class SplitNodes { +#else + class SplitNodes + : public DigraphAdaptorExtender > { +#endif + typedef DigraphAdaptorExtender > Parent; + + public: + typedef DGR Digraph; + + typedef typename DGR::Node DigraphNode; + typedef typename DGR::Arc DigraphArc; + + typedef typename Parent::Node Node; + typedef typename Parent::Arc Arc; + + /// \brief Constructor + /// + /// Constructor of the adaptor. + SplitNodes(const DGR& g) { + Parent::initialize(g); + } + + /// \brief Returns \c true if the given node is an in-node. + /// + /// Returns \c true if the given node is an in-node. + static bool inNode(const Node& n) { + return Parent::inNode(n); + } + + /// \brief Returns \c true if the given node is an out-node. + /// + /// Returns \c true if the given node is an out-node. + static bool outNode(const Node& n) { + return Parent::outNode(n); + } + + /// \brief Returns \c true if the given arc is an original arc. + /// + /// Returns \c true if the given arc is one of the arcs in the + /// original digraph. + static bool origArc(const Arc& a) { + return Parent::origArc(a); + } + + /// \brief Returns \c true if the given arc is a bind arc. + /// + /// Returns \c true if the given arc is a bind arc, i.e. it connects + /// an in-node and an out-node. + static bool bindArc(const Arc& a) { + return Parent::bindArc(a); + } + + /// \brief Returns the in-node created from the given original node. + /// + /// Returns the in-node created from the given original node. + static Node inNode(const DigraphNode& n) { + return Parent::inNode(n); + } + + /// \brief Returns the out-node created from the given original node. + /// + /// Returns the out-node created from the given original node. + static Node outNode(const DigraphNode& n) { + return Parent::outNode(n); + } + + /// \brief Returns the bind arc that corresponds to the given + /// original node. + /// + /// Returns the bind arc in the adaptor that corresponds to the given + /// original node, i.e. the arc connecting the in-node and out-node + /// of \c n. + static Arc arc(const DigraphNode& n) { + return Parent::arc(n); + } + + /// \brief Returns the arc that corresponds to the given original arc. + /// + /// Returns the arc in the adaptor that corresponds to the given + /// original arc. + static Arc arc(const DigraphArc& a) { + return Parent::arc(a); + } + + /// \brief Node map combined from two original node maps + /// + /// This map adaptor class adapts two node maps of the original digraph + /// to get a node map of the split digraph. + /// Its value type is inherited from the first node map type (\c IN). + /// \tparam IN The type of the node map for the in-nodes. + /// \tparam OUT The type of the node map for the out-nodes. + template + class CombinedNodeMap { + public: + + /// The key type of the map + typedef Node Key; + /// The value type of the map + typedef typename IN::Value Value; + + typedef typename MapTraits::ReferenceMapTag ReferenceMapTag; + typedef typename MapTraits::ReturnValue ReturnValue; + typedef typename MapTraits::ConstReturnValue ConstReturnValue; + typedef typename MapTraits::ReturnValue Reference; + typedef typename MapTraits::ConstReturnValue ConstReference; + + /// Constructor + CombinedNodeMap(IN& in_map, OUT& out_map) + : _in_map(in_map), _out_map(out_map) {} + + /// Returns the value associated with the given key. + Value operator[](const Key& key) const { + if (SplitNodesBase::inNode(key)) { + return _in_map[key]; + } else { + return _out_map[key]; + } + } + + /// Returns a reference to the value associated with the given key. + Value& operator[](const Key& key) { + if (SplitNodesBase::inNode(key)) { + return _in_map[key]; + } else { + return _out_map[key]; + } + } + + /// Sets the value associated with the given key. + void set(const Key& key, const Value& value) { + if (SplitNodesBase::inNode(key)) { + _in_map.set(key, value); + } else { + _out_map.set(key, value); + } + } + + private: + + IN& _in_map; + OUT& _out_map; + + }; + + + /// \brief Returns a combined node map + /// + /// This function just returns a combined node map. + template + static CombinedNodeMap + combinedNodeMap(IN& in_map, OUT& out_map) { + return CombinedNodeMap(in_map, out_map); + } + + template + static CombinedNodeMap + combinedNodeMap(const IN& in_map, OUT& out_map) { + return CombinedNodeMap(in_map, out_map); + } + + template + static CombinedNodeMap + combinedNodeMap(IN& in_map, const OUT& out_map) { + return CombinedNodeMap(in_map, out_map); + } + + template + static CombinedNodeMap + combinedNodeMap(const IN& in_map, const OUT& out_map) { + return CombinedNodeMap(in_map, out_map); + } + + /// \brief Arc map combined from an arc map and a node map of the + /// original digraph. + /// + /// This map adaptor class adapts an arc map and a node map of the + /// original digraph to get an arc map of the split digraph. + /// Its value type is inherited from the original arc map type (\c AM). + /// \tparam AM The type of the arc map. + /// \tparam NM the type of the node map. + template + class CombinedArcMap { + public: + + /// The key type of the map + typedef Arc Key; + /// The value type of the map + typedef typename AM::Value Value; + + typedef typename MapTraits::ReferenceMapTag ReferenceMapTag; + typedef typename MapTraits::ReturnValue ReturnValue; + typedef typename MapTraits::ConstReturnValue ConstReturnValue; + typedef typename MapTraits::ReturnValue Reference; + typedef typename MapTraits::ConstReturnValue ConstReference; + + /// Constructor + CombinedArcMap(AM& arc_map, NM& node_map) + : _arc_map(arc_map), _node_map(node_map) {} + + /// Returns the value associated with the given key. + Value operator[](const Key& arc) const { + if (SplitNodesBase::origArc(arc)) { + return _arc_map[arc]; + } else { + return _node_map[arc]; + } + } + + /// Returns a reference to the value associated with the given key. + Value& operator[](const Key& arc) { + if (SplitNodesBase::origArc(arc)) { + return _arc_map[arc]; + } else { + return _node_map[arc]; + } + } + + /// Sets the value associated with the given key. + void set(const Arc& arc, const Value& val) { + if (SplitNodesBase::origArc(arc)) { + _arc_map.set(arc, val); + } else { + _node_map.set(arc, val); + } + } + + private: + + AM& _arc_map; + NM& _node_map; + + }; + + /// \brief Returns a combined arc map + /// + /// This function just returns a combined arc map. + template + static CombinedArcMap + combinedArcMap(ArcMap& arc_map, NodeMap& node_map) { + return CombinedArcMap(arc_map, node_map); + } + + template + static CombinedArcMap + combinedArcMap(const ArcMap& arc_map, NodeMap& node_map) { + return CombinedArcMap(arc_map, node_map); + } + + template + static CombinedArcMap + combinedArcMap(ArcMap& arc_map, const NodeMap& node_map) { + return CombinedArcMap(arc_map, node_map); + } + + template + static CombinedArcMap + combinedArcMap(const ArcMap& arc_map, const NodeMap& node_map) { + return CombinedArcMap(arc_map, node_map); + } + + }; + + /// \brief Returns a (read-only) SplitNodes adaptor + /// + /// This function just returns a (read-only) \ref SplitNodes adaptor. + /// \ingroup graph_adaptors + /// \relates SplitNodes + template + SplitNodes + splitNodes(const DGR& digraph) { + return SplitNodes(digraph); + } + +#undef LEMON_SCOPE_FIX + +} //namespace lemon + +#endif //LEMON_ADAPTORS_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.cc b/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.cc new file mode 100644 index 00000000000..35a73d9f308 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.cc @@ -0,0 +1,474 @@ +/* -*- 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 + +namespace lemon { + + void ArgParser::_terminate(ArgParserException::Reason reason) const + { + if(_exit_on_problems) + exit(1); + else throw(ArgParserException(reason)); + } + + + void ArgParser::_showHelp(void *p) + { + (static_cast(p))->showHelp(); + (static_cast(p))->_terminate(ArgParserException::HELP); + } + + ArgParser::ArgParser(int argc, const char * const *argv) + :_argc(argc), _argv(argv), _command_name(argv[0]), + _exit_on_problems(true) { + funcOption("-help","Print a short help message",_showHelp,this); + synonym("help","-help"); + synonym("h","-help"); + } + + ArgParser::~ArgParser() + { + for(Opts::iterator i=_opts.begin();i!=_opts.end();++i) + if(i->second.self_delete) + switch(i->second.type) { + case BOOL: + delete i->second.bool_p; + break; + case STRING: + delete i->second.string_p; + break; + case DOUBLE: + delete i->second.double_p; + break; + case INTEGER: + delete i->second.int_p; + break; + case UNKNOWN: + break; + case FUNC: + break; + } + } + + + ArgParser &ArgParser::intOption(const std::string &name, + const std::string &help, + int value, bool obl) + { + ParData p; + p.int_p=new int(value); + p.self_delete=true; + p.help=help; + p.type=INTEGER; + p.mandatory=obl; + _opts[name]=p; + return *this; + } + + ArgParser &ArgParser::doubleOption(const std::string &name, + const std::string &help, + double value, bool obl) + { + ParData p; + p.double_p=new double(value); + p.self_delete=true; + p.help=help; + p.type=DOUBLE; + p.mandatory=obl; + _opts[name]=p; + return *this; + } + + ArgParser &ArgParser::boolOption(const std::string &name, + const std::string &help, + bool value, bool obl) + { + ParData p; + p.bool_p=new bool(value); + p.self_delete=true; + p.help=help; + p.type=BOOL; + p.mandatory=obl; + _opts[name]=p; + return *this; + } + + ArgParser &ArgParser::stringOption(const std::string &name, + const std::string &help, + std::string value, bool obl) + { + ParData p; + p.string_p=new std::string(value); + p.self_delete=true; + p.help=help; + p.type=STRING; + p.mandatory=obl; + _opts[name]=p; + return *this; + } + + ArgParser &ArgParser::refOption(const std::string &name, + const std::string &help, + int &ref, bool obl) + { + ParData p; + p.int_p=&ref; + p.self_delete=false; + p.help=help; + p.type=INTEGER; + p.mandatory=obl; + _opts[name]=p; + return *this; + } + + ArgParser &ArgParser::refOption(const std::string &name, + const std::string &help, + double &ref, bool obl) + { + ParData p; + p.double_p=&ref; + p.self_delete=false; + p.help=help; + p.type=DOUBLE; + p.mandatory=obl; + _opts[name]=p; + return *this; + } + + ArgParser &ArgParser::refOption(const std::string &name, + const std::string &help, + bool &ref, bool obl) + { + ParData p; + p.bool_p=&ref; + p.self_delete=false; + p.help=help; + p.type=BOOL; + p.mandatory=obl; + _opts[name]=p; + + ref = false; + + return *this; + } + + ArgParser &ArgParser::refOption(const std::string &name, + const std::string &help, + std::string &ref, bool obl) + { + ParData p; + p.string_p=&ref; + p.self_delete=false; + p.help=help; + p.type=STRING; + p.mandatory=obl; + _opts[name]=p; + return *this; + } + + ArgParser &ArgParser::funcOption(const std::string &name, + const std::string &help, + void (*func)(void *),void *data) + { + ParData p; + p.func_p.p=func; + p.func_p.data=data; + p.self_delete=false; + p.help=help; + p.type=FUNC; + p.mandatory=false; + _opts[name]=p; + return *this; + } + + ArgParser &ArgParser::optionGroup(const std::string &group, + const std::string &opt) + { + Opts::iterator i = _opts.find(opt); + LEMON_ASSERT(i!=_opts.end(), "Unknown option: '"+opt+"'"); + LEMON_ASSERT(!(i->second.ingroup), + "Option already in option group: '"+opt+"'"); + GroupData &g=_groups[group]; + g.opts.push_back(opt); + i->second.ingroup=true; + return *this; + } + + ArgParser &ArgParser::onlyOneGroup(const std::string &group) + { + GroupData &g=_groups[group]; + g.only_one=true; + return *this; + } + + ArgParser &ArgParser::synonym(const std::string &syn, + const std::string &opt) + { + Opts::iterator o = _opts.find(opt); + Opts::iterator s = _opts.find(syn); + LEMON_ASSERT(o!=_opts.end(), "Unknown option: '"+opt+"'"); + LEMON_ASSERT(s==_opts.end(), "Option already used: '"+syn+"'"); + ParData p; + p.help=opt; + p.mandatory=false; + p.syn=true; + _opts[syn]=p; + o->second.has_syn=true; + return *this; + } + + ArgParser &ArgParser::mandatoryGroup(const std::string &group) + { + GroupData &g=_groups[group]; + g.mandatory=true; + return *this; + } + + ArgParser &ArgParser::other(const std::string &name, + const std::string &help) + { + _others_help.push_back(OtherArg(name,help)); + return *this; + } + + void ArgParser::show(std::ostream &os,Opts::const_iterator i) const + { + os << "-" << i->first; + if(i->second.has_syn) + for(Opts::const_iterator j=_opts.begin();j!=_opts.end();++j) + if(j->second.syn&&j->second.help==i->first) + os << "|-" << j->first; + switch(i->second.type) { + case STRING: + os << " str"; + break; + case INTEGER: + os << " int"; + break; + case DOUBLE: + os << " num"; + break; + default: + break; + } + } + + void ArgParser::show(std::ostream &os,Groups::const_iterator i) const + { + GroupData::Opts::const_iterator o=i->second.opts.begin(); + while(o!=i->second.opts.end()) { + show(os,_opts.find(*o)); + ++o; + if(o!=i->second.opts.end()) os<<'|'; + } + } + + void ArgParser::showHelp(Opts::const_iterator i) const + { + if(i->second.help.size()==0||i->second.syn) return; + std::cerr << " "; + show(std::cerr,i); + std::cerr << std::endl; + std::cerr << " " << i->second.help << std::endl; + } + void ArgParser::showHelp(std::vector::const_iterator i) + const + { + if(i->help.size()==0) return; + std::cerr << " " << i->name << std::endl + << " " << i->help << std::endl; + } + + void ArgParser::shortHelp() const + { + const unsigned int LINE_LEN=77; + const std::string indent(" "); + std::cerr << "Usage:\n " << _command_name; + int pos=_command_name.size()+2; + for(Groups::const_iterator g=_groups.begin();g!=_groups.end();++g) { + std::ostringstream cstr; + cstr << ' '; + if(!g->second.mandatory) cstr << '['; + show(cstr,g); + if(!g->second.mandatory) cstr << ']'; + if(pos+cstr.str().size()>LINE_LEN) { + std::cerr << std::endl << indent; + pos=indent.size(); + } + std::cerr << cstr.str(); + pos+=cstr.str().size(); + } + for(Opts::const_iterator i=_opts.begin();i!=_opts.end();++i) + if(!i->second.ingroup&&!i->second.syn) { + std::ostringstream cstr; + cstr << ' '; + if(!i->second.mandatory) cstr << '['; + show(cstr,i); + if(!i->second.mandatory) cstr << ']'; + if(pos+cstr.str().size()>LINE_LEN) { + std::cerr << std::endl << indent; + pos=indent.size(); + } + std::cerr << cstr.str(); + pos+=cstr.str().size(); + } + for(std::vector::const_iterator i=_others_help.begin(); + i!=_others_help.end();++i) + { + std::ostringstream cstr; + cstr << ' ' << i->name; + + if(pos+cstr.str().size()>LINE_LEN) { + std::cerr << std::endl << indent; + pos=indent.size(); + } + std::cerr << cstr.str(); + pos+=cstr.str().size(); + } + std::cerr << std::endl; + } + + void ArgParser::showHelp() const + { + shortHelp(); + std::cerr << "Where:\n"; + for(std::vector::const_iterator i=_others_help.begin(); + i!=_others_help.end();++i) showHelp(i); + for(Opts::const_iterator i=_opts.begin();i!=_opts.end();++i) showHelp(i); + _terminate(ArgParserException::HELP); + } + + + void ArgParser::unknownOpt(std::string arg) const + { + std::cerr << "\nUnknown option: " << arg << "\n"; + std::cerr << "\nType '" << _command_name << + " --help' to obtain a short summary on the usage.\n\n"; + _terminate(ArgParserException::UNKNOWN_OPT); + } + + void ArgParser::requiresValue(std::string arg, OptType t) const + { + std::cerr << "Argument '" << arg << "' requires a"; + switch(t) { + case STRING: + std::cerr << " string"; + break; + case INTEGER: + std::cerr << "n integer"; + break; + case DOUBLE: + std::cerr << " floating point"; + break; + default: + break; + } + std::cerr << " value\n\n"; + showHelp(); + } + + + void ArgParser::checkMandatories() const + { + bool ok=true; + for(Opts::const_iterator i=_opts.begin();i!=_opts.end();++i) + if(i->second.mandatory&&!i->second.set) + { + if(ok) + std::cerr << _command_name + << ": The following mandatory arguments are missing.\n"; + ok=false; + showHelp(i); + } + for(Groups::const_iterator i=_groups.begin();i!=_groups.end();++i) + if(i->second.mandatory||i->second.only_one) + { + int set=0; + for(GroupData::Opts::const_iterator o=i->second.opts.begin(); + o!=i->second.opts.end();++o) + if(_opts.find(*o)->second.set) ++set; + if(i->second.mandatory&&!set) { + std::cerr << _command_name << + ": At least one of the following arguments is mandatory.\n"; + ok=false; + for(GroupData::Opts::const_iterator o=i->second.opts.begin(); + o!=i->second.opts.end();++o) + showHelp(_opts.find(*o)); + } + if(i->second.only_one&&set>1) { + std::cerr << _command_name << + ": At most one of the following arguments can be given.\n"; + ok=false; + for(GroupData::Opts::const_iterator o=i->second.opts.begin(); + o!=i->second.opts.end();++o) + showHelp(_opts.find(*o)); + } + } + if(!ok) { + std::cerr << "\nType '" << _command_name << + " --help' to obtain a short summary on the usage.\n\n"; + _terminate(ArgParserException::INVALID_OPT); + } + } + + ArgParser &ArgParser::parse() + { + for(int ar=1; ar<_argc; ++ar) { + std::string arg(_argv[ar]); + if (arg[0] != '-' || arg.size() == 1) { + _file_args.push_back(arg); + } + else { + Opts::iterator i = _opts.find(arg.substr(1)); + if(i==_opts.end()) unknownOpt(arg); + else { + if(i->second.syn) i=_opts.find(i->second.help); + ParData &p(i->second); + if (p.type==BOOL) *p.bool_p=true; + else if (p.type==FUNC) p.func_p.p(p.func_p.data); + else if(++ar==_argc) requiresValue(arg, p.type); + else { + std::string val(_argv[ar]); + std::istringstream vals(val); + switch(p.type) { + case STRING: + *p.string_p=val; + break; + case INTEGER: + vals >> *p.int_p; + break; + case DOUBLE: + vals >> *p.double_p; + break; + default: + break; + } + if(p.type!=STRING&&(!vals||!vals.eof())) + requiresValue(arg, p.type); + } + p.set = true; + } + } + } + checkMandatories(); + + return *this; + } + +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.h new file mode 100644 index 00000000000..3fbe75c97e5 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.h @@ -0,0 +1,440 @@ +/* -*- 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_ARG_PARSER_H +#define LEMON_ARG_PARSER_H + +#include +#include +#include +#include +#include +#include +#include +#include + +///\ingroup misc +///\file +///\brief A tool to parse command line arguments. + +namespace lemon { + + ///Exception used by ArgParser + + ///Exception used by ArgParser. + /// + class ArgParserException : public Exception { + public: + /// Reasons for failure + + /// Reasons for failure. + /// + enum Reason { + HELP, ///< --help option was given. + UNKNOWN_OPT, ///< Unknown option was given. + INVALID_OPT ///< Invalid combination of options. + }; + + private: + Reason _reason; + + public: + ///Constructor + ArgParserException(Reason r) throw() : _reason(r) {} + ///Virtual destructor + virtual ~ArgParserException() throw() {} + ///A short description of the exception + virtual const char* what() const throw() { + switch(_reason) + { + case HELP: + return "lemon::ArgParseException: ask for help"; + break; + case UNKNOWN_OPT: + return "lemon::ArgParseException: unknown option"; + break; + case INVALID_OPT: + return "lemon::ArgParseException: invalid combination of options"; + break; + } + return ""; + } + ///Return the reason for the failure + Reason reason() const {return _reason; } + }; + + + ///Command line arguments parser + + ///\ingroup misc + ///Command line arguments parser. + /// + ///For a complete example see the \ref arg_parser_demo.cc demo file. + class ArgParser { + + static void _showHelp(void *p); + protected: + + int _argc; + const char * const *_argv; + + enum OptType { UNKNOWN=0, BOOL=1, STRING=2, DOUBLE=3, INTEGER=4, FUNC=5 }; + + class ParData { + public: + union { + bool *bool_p; + int *int_p; + double *double_p; + std::string *string_p; + struct { + void (*p)(void *); + void *data; + } func_p; + + }; + std::string help; + bool mandatory; + OptType type; + bool set; + bool ingroup; + bool has_syn; + bool syn; + bool self_delete; + ParData() : mandatory(false), type(UNKNOWN), set(false), ingroup(false), + has_syn(false), syn(false), self_delete(false) {} + }; + + typedef std::map Opts; + Opts _opts; + + class GroupData + { + public: + typedef std::list Opts; + Opts opts; + bool only_one; + bool mandatory; + GroupData() :only_one(false), mandatory(false) {} + }; + + typedef std::map Groups; + Groups _groups; + + struct OtherArg + { + std::string name; + std::string help; + OtherArg(std::string n, std::string h) :name(n), help(h) {} + + }; + + std::vector _others_help; + std::vector _file_args; + std::string _command_name; + + + private: + //Bind a function to an option. + + //\param name The name of the option. The leading '-' must be omitted. + //\param help A help string. + //\retval func The function to be called when the option is given. It + // must be of type "void f(void *)" + //\param data Data to be passed to \c func + ArgParser &funcOption(const std::string &name, + const std::string &help, + void (*func)(void *),void *data); + + bool _exit_on_problems; + + void _terminate(ArgParserException::Reason reason) const; + + public: + + ///Constructor + ArgParser(int argc, const char * const *argv); + + ~ArgParser(); + + ///\name Options + /// + + ///@{ + + ///Add a new integer type option + + ///Add a new integer type option. + ///\param name The name of the option. The leading '-' must be omitted. + ///\param help A help string. + ///\param value A default value for the option. + ///\param obl Indicate if the option is mandatory. + ArgParser &intOption(const std::string &name, + const std::string &help, + int value=0, bool obl=false); + + ///Add a new floating point type option + + ///Add a new floating point type option. + ///\param name The name of the option. The leading '-' must be omitted. + ///\param help A help string. + ///\param value A default value for the option. + ///\param obl Indicate if the option is mandatory. + ArgParser &doubleOption(const std::string &name, + const std::string &help, + double value=0, bool obl=false); + + ///Add a new bool type option + + ///Add a new bool type option. + ///\param name The name of the option. The leading '-' must be omitted. + ///\param help A help string. + ///\param value A default value for the option. + ///\param obl Indicate if the option is mandatory. + ///\note A mandatory bool obtion is of very little use. + ArgParser &boolOption(const std::string &name, + const std::string &help, + bool value=false, bool obl=false); + + ///Add a new string type option + + ///Add a new string type option. + ///\param name The name of the option. The leading '-' must be omitted. + ///\param help A help string. + ///\param value A default value for the option. + ///\param obl Indicate if the option is mandatory. + ArgParser &stringOption(const std::string &name, + const std::string &help, + std::string value="", bool obl=false); + + ///Give help string for non-parsed arguments. + + ///With this function you can give help string for non-parsed arguments. + ///The parameter \c name will be printed in the short usage line, while + ///\c help gives a more detailed description. + ArgParser &other(const std::string &name, + const std::string &help=""); + + ///@} + + ///\name Options with External Storage + ///Using this functions, the value of the option will be directly written + ///into a variable once the option appears in the command line. + + ///@{ + + ///Add a new integer type option with a storage reference + + ///Add a new integer type option with a storage reference. + ///\param name The name of the option. The leading '-' must be omitted. + ///\param help A help string. + ///\param obl Indicate if the option is mandatory. + ///\retval ref The value of the argument will be written to this variable. + ArgParser &refOption(const std::string &name, + const std::string &help, + int &ref, bool obl=false); + + ///Add a new floating type option with a storage reference + + ///Add a new floating type option with a storage reference. + ///\param name The name of the option. The leading '-' must be omitted. + ///\param help A help string. + ///\param obl Indicate if the option is mandatory. + ///\retval ref The value of the argument will be written to this variable. + ArgParser &refOption(const std::string &name, + const std::string &help, + double &ref, bool obl=false); + + ///Add a new bool type option with a storage reference + + ///Add a new bool type option with a storage reference. + ///\param name The name of the option. The leading '-' must be omitted. + ///\param help A help string. + ///\param obl Indicate if the option is mandatory. + ///\retval ref The value of the argument will be written to this variable. + ///\note A mandatory bool obtion is of very little use. + ArgParser &refOption(const std::string &name, + const std::string &help, + bool &ref, bool obl=false); + + ///Add a new string type option with a storage reference + + ///Add a new string type option with a storage reference. + ///\param name The name of the option. The leading '-' must be omitted. + ///\param help A help string. + ///\param obl Indicate if the option is mandatory. + ///\retval ref The value of the argument will be written to this variable. + ArgParser &refOption(const std::string &name, + const std::string &help, + std::string &ref, bool obl=false); + + ///@} + + ///\name Option Groups and Synonyms + /// + + ///@{ + + ///Bundle some options into a group + + /// You can group some option by calling this function repeatedly for each + /// option to be grouped with the same groupname. + ///\param group The group name. + ///\param opt The option name. + ArgParser &optionGroup(const std::string &group, + const std::string &opt); + + ///Make the members of a group exclusive + + ///If you call this function for a group, than at most one of them can be + ///given at the same time. + ArgParser &onlyOneGroup(const std::string &group); + + ///Make a group mandatory + + ///Using this function, at least one of the members of \c group + ///must be given. + ArgParser &mandatoryGroup(const std::string &group); + + ///Create synonym to an option + + ///With this function you can create a synonym \c syn of the + ///option \c opt. + ArgParser &synonym(const std::string &syn, + const std::string &opt); + + ///@} + + private: + void show(std::ostream &os,Opts::const_iterator i) const; + void show(std::ostream &os,Groups::const_iterator i) const; + void showHelp(Opts::const_iterator i) const; + void showHelp(std::vector::const_iterator i) const; + + void unknownOpt(std::string arg) const; + + void requiresValue(std::string arg, OptType t) const; + void checkMandatories() const; + + void shortHelp() const; + void showHelp() const; + public: + + ///Start the parsing process + ArgParser &parse(); + + /// Synonym for parse() + ArgParser &run() + { + return parse(); + } + + ///Give back the command name (the 0th argument) + const std::string &commandName() const { return _command_name; } + + ///Check if an opion has been given to the command. + bool given(std::string op) const + { + Opts::const_iterator i = _opts.find(op); + return i!=_opts.end()?i->second.set:false; + } + + + ///Magic type for operator[] + + ///This is the type of the return value of ArgParser::operator[](). + ///It automatically converts to \c int, \c double, \c bool or + ///\c std::string if the type of the option matches, which is checked + ///with an \ref LEMON_ASSERT "assertion" (i.e. it performs runtime + ///type checking). + class RefType + { + const ArgParser &_parser; + std::string _name; + public: + ///\e + RefType(const ArgParser &p,const std::string &n) :_parser(p),_name(n) {} + ///\e + operator bool() + { + Opts::const_iterator i = _parser._opts.find(_name); + LEMON_ASSERT(i!=_parser._opts.end(), + std::string()+"Unkown option: '"+_name+"'"); + LEMON_ASSERT(i->second.type==ArgParser::BOOL, + std::string()+"'"+_name+"' is a bool option"); + return *(i->second.bool_p); + } + ///\e + operator std::string() + { + Opts::const_iterator i = _parser._opts.find(_name); + LEMON_ASSERT(i!=_parser._opts.end(), + std::string()+"Unkown option: '"+_name+"'"); + LEMON_ASSERT(i->second.type==ArgParser::STRING, + std::string()+"'"+_name+"' is a string option"); + return *(i->second.string_p); + } + ///\e + operator double() + { + Opts::const_iterator i = _parser._opts.find(_name); + LEMON_ASSERT(i!=_parser._opts.end(), + std::string()+"Unkown option: '"+_name+"'"); + LEMON_ASSERT(i->second.type==ArgParser::DOUBLE || + i->second.type==ArgParser::INTEGER, + std::string()+"'"+_name+"' is a floating point option"); + return i->second.type==ArgParser::DOUBLE ? + *(i->second.double_p) : *(i->second.int_p); + } + ///\e + operator int() + { + Opts::const_iterator i = _parser._opts.find(_name); + LEMON_ASSERT(i!=_parser._opts.end(), + std::string()+"Unkown option: '"+_name+"'"); + LEMON_ASSERT(i->second.type==ArgParser::INTEGER, + std::string()+"'"+_name+"' is an integer option"); + return *(i->second.int_p); + } + + }; + + ///Give back the value of an option + + ///Give back the value of an option. + ///\sa RefType + RefType operator[](const std::string &n) const + { + return RefType(*this, n); + } + + ///Give back the non-option type arguments. + + ///Give back a reference to a vector consisting of the program arguments + ///not starting with a '-' character. + const std::vector &files() const { return _file_args; } + + ///Throw instead of exit in case of problems + void throwOnProblems() + { + _exit_on_problems=false; + } + }; +} + +#endif // LEMON_ARG_PARSER_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/assert.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/assert.h new file mode 100644 index 00000000000..f6c1dfc8e59 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/assert.h @@ -0,0 +1,214 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_ASSERT_H +#define LEMON_ASSERT_H + +/// \ingroup exceptions +/// \file +/// \brief Extended assertion handling + +#include + +namespace lemon { + + inline void assert_fail_abort(const char *file, int line, + const char *function, const char* message, + const char *assertion) + { + std::cerr << file << ":" << line << ": "; + if (function) + std::cerr << function << ": "; + std::cerr << message; + if (assertion) + std::cerr << " (assertion '" << assertion << "' failed)"; + std::cerr << std::endl; + std::abort(); + } + + namespace _assert_bits { + + + inline const char* cstringify(const std::string& str) { + return str.c_str(); + } + + inline const char* cstringify(const char* str) { + return str; + } + } +} + +#endif // LEMON_ASSERT_H + +#undef LEMON_ASSERT +#undef LEMON_DEBUG + +#if (defined(LEMON_ASSERT_ABORT) ? 1 : 0) + \ + (defined(LEMON_ASSERT_CUSTOM) ? 1 : 0) > 1 +#error "LEMON assertion system is not set properly" +#endif + +#if ((defined(LEMON_ASSERT_ABORT) ? 1 : 0) + \ + (defined(LEMON_ASSERT_CUSTOM) ? 1 : 0) == 1 || \ + defined(LEMON_ENABLE_ASSERTS)) && \ + (defined(LEMON_DISABLE_ASSERTS) || \ + defined(NDEBUG)) +#error "LEMON assertion system is not set properly" +#endif + + +#if defined LEMON_ASSERT_ABORT +# undef LEMON_ASSERT_HANDLER +# define LEMON_ASSERT_HANDLER ::lemon::assert_fail_abort +#elif defined LEMON_ASSERT_CUSTOM +# undef LEMON_ASSERT_HANDLER +# ifndef LEMON_CUSTOM_ASSERT_HANDLER +# error "LEMON_CUSTOM_ASSERT_HANDLER is not set" +# endif +# define LEMON_ASSERT_HANDLER LEMON_CUSTOM_ASSERT_HANDLER +#elif defined LEMON_DISABLE_ASSERTS +# undef LEMON_ASSERT_HANDLER +#elif defined NDEBUG +# undef LEMON_ASSERT_HANDLER +#else +# define LEMON_ASSERT_HANDLER ::lemon::assert_fail_abort +#endif + +#ifndef LEMON_FUNCTION_NAME +# if defined __GNUC__ +# define LEMON_FUNCTION_NAME (__PRETTY_FUNCTION__) +# elif defined _MSC_VER +# define LEMON_FUNCTION_NAME (__FUNCSIG__) +# elif __STDC_VERSION__ >= 199901L +# define LEMON_FUNCTION_NAME (__func__) +# else +# define LEMON_FUNCTION_NAME ("") +# endif +#endif + +#ifdef DOXYGEN + +/// \ingroup exceptions +/// +/// \brief Macro for assertion with customizable message +/// +/// Macro for assertion with customizable message. +/// \param exp An expression that must be convertible to \c bool. If it is \c +/// false, then an assertion is raised. The concrete behaviour depends on the +/// settings of the assertion system. +/// \param msg A const char* parameter, which can be used to provide +/// information about the circumstances of the failed assertion. +/// +/// The assertions are enabled in the default behaviour. +/// You can disable them with the following code: +/// \code +/// #define LEMON_DISABLE_ASSERTS +/// \endcode +/// or with compilation parameters: +/// \code +/// g++ -DLEMON_DISABLE_ASSERTS +/// make CXXFLAGS='-DLEMON_DISABLE_ASSERTS' +/// \endcode +/// The checking is also disabled when the standard macro \c NDEBUG is defined. +/// +/// As a default behaviour the failed assertion prints a short log message to +/// the standard error and aborts the execution. +/// +/// However, the following modes can be used in the assertion system: +/// - \c LEMON_ASSERT_ABORT The failed assertion prints a short log message to +/// the standard error and aborts the program. It is the default behaviour. +/// - \c LEMON_ASSERT_CUSTOM The user can define own assertion handler +/// function. +/// \code +/// void custom_assert_handler(const char* file, int line, +/// const char* function, const char* message, +/// const char* assertion); +/// \endcode +/// The name of the function should be defined as the \c +/// LEMON_CUSTOM_ASSERT_HANDLER macro name. +/// \code +/// #define LEMON_CUSTOM_ASSERT_HANDLER custom_assert_handler +/// \endcode +/// Whenever an assertion is occured, the custom assertion +/// handler is called with appropiate parameters. +/// +/// The assertion mode can also be changed within one compilation unit. +/// If the macros are redefined with other settings and the +/// \ref lemon/assert.h "assert.h" file is reincluded, then the +/// behaviour is changed appropiately to the new settings. +# define LEMON_ASSERT(exp, msg) \ + (static_cast (!!(exp) ? 0 : ( \ + LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \ + LEMON_FUNCTION_NAME, \ + ::lemon::_assert_bits::cstringify(msg), #exp), 0))) + +/// \ingroup exceptions +/// +/// \brief Macro for internal assertions +/// +/// Macro for internal assertions, it is used in the library to check +/// the consistency of results of algorithms, several pre- and +/// postconditions and invariants. The checking is disabled by +/// default, but it can be turned on with the macro \c +/// LEMON_ENABLE_DEBUG. +/// \code +/// #define LEMON_ENABLE_DEBUG +/// \endcode +/// or with compilation parameters: +/// \code +/// g++ -DLEMON_ENABLE_DEBUG +/// make CXXFLAGS='-DLEMON_ENABLE_DEBUG' +/// \endcode +/// +/// This macro works like the \c LEMON_ASSERT macro, therefore the +/// current behaviour depends on the settings of \c LEMON_ASSERT +/// macro. +/// +/// \see LEMON_ASSERT +# define LEMON_DEBUG(exp, msg) \ + (static_cast (!!(exp) ? 0 : ( \ + LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \ + LEMON_FUNCTION_NAME, \ + ::lemon::_assert_bits::cstringify(msg), #exp), 0))) + +#else + +# ifndef LEMON_ASSERT_HANDLER +# define LEMON_ASSERT(exp, msg) (static_cast(0)) +# define LEMON_DEBUG(exp, msg) (static_cast(0)) +# else +# define LEMON_ASSERT(exp, msg) \ + (static_cast (!!(exp) ? 0 : ( \ + LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \ + LEMON_FUNCTION_NAME, \ + ::lemon::_assert_bits::cstringify(msg), \ + #exp), 0))) +# if defined LEMON_ENABLE_DEBUG +# define LEMON_DEBUG(exp, msg) \ + (static_cast (!!(exp) ? 0 : ( \ + LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \ + LEMON_FUNCTION_NAME, \ + ::lemon::_assert_bits::cstringify(msg), \ + #exp), 0))) +# else +# define LEMON_DEBUG(exp, msg) (static_cast(0)) +# endif +# endif + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/base.cc b/extern/quadriflow/3rd/lemon-1.3.1/lemon/base.cc new file mode 100644 index 00000000000..a057b41cbc0 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/base.cc @@ -0,0 +1,37 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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. + * + */ + +///\file +///\brief Some basic non-inline functions and static global data. + +#include +#include +#include +namespace lemon { + + float Tolerance::def_epsilon = static_cast(1e-4); + double Tolerance::def_epsilon = 1e-10; + long double Tolerance::def_epsilon = 1e-14; + +#ifndef LEMON_ONLY_TEMPLATES + const Invalid INVALID = Invalid(); +#endif + + TimeStamp::Format TimeStamp::_format = TimeStamp::NORMAL; + +} //namespace lemon diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bellman_ford.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bellman_ford.h new file mode 100644 index 00000000000..310758ebb59 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bellman_ford.h @@ -0,0 +1,1116 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_BELLMAN_FORD_H +#define LEMON_BELLMAN_FORD_H + +/// \ingroup shortest_path +/// \file +/// \brief Bellman-Ford algorithm. + +#include +#include +#include +#include +#include +#include + +#include + +namespace lemon { + + /// \brief Default OperationTraits for the BellmanFord algorithm class. + /// + /// This operation traits class defines all computational operations + /// and constants that are used in the Bellman-Ford algorithm. + /// The default implementation is based on the \c numeric_limits class. + /// If the numeric type does not have infinity value, then the maximum + /// value is used as extremal infinity value. + template < + typename V, + bool has_inf = std::numeric_limits::has_infinity> + struct BellmanFordDefaultOperationTraits { + /// \e + typedef V Value; + /// \brief Gives back the zero value of the type. + static Value zero() { + return static_cast(0); + } + /// \brief Gives back the positive infinity value of the type. + static Value infinity() { + return std::numeric_limits::infinity(); + } + /// \brief Gives back the sum of the given two elements. + static Value plus(const Value& left, const Value& right) { + return left + right; + } + /// \brief Gives back \c true only if the first value is less than + /// the second. + static bool less(const Value& left, const Value& right) { + return left < right; + } + }; + + template + struct BellmanFordDefaultOperationTraits { + typedef V Value; + static Value zero() { + return static_cast(0); + } + static Value infinity() { + return std::numeric_limits::max(); + } + static Value plus(const Value& left, const Value& right) { + if (left == infinity() || right == infinity()) return infinity(); + return left + right; + } + static bool less(const Value& left, const Value& right) { + return left < right; + } + }; + + /// \brief Default traits class of BellmanFord class. + /// + /// Default traits class of BellmanFord class. + /// \param GR The type of the digraph. + /// \param LEN The type of the length map. + template + struct BellmanFordDefaultTraits { + /// The type of the digraph the algorithm runs on. + typedef GR Digraph; + + /// \brief The type of the map that stores the arc lengths. + /// + /// The type of the map that stores the arc lengths. + /// It must conform to the \ref concepts::ReadMap "ReadMap" concept. + typedef LEN LengthMap; + + /// The type of the arc lengths. + typedef typename LEN::Value Value; + + /// \brief Operation traits for Bellman-Ford algorithm. + /// + /// It defines the used operations and the infinity value for the + /// given \c Value type. + /// \see BellmanFordDefaultOperationTraits + typedef BellmanFordDefaultOperationTraits OperationTraits; + + /// \brief The type of the map that stores the last arcs of the + /// shortest paths. + /// + /// The type of the map that stores the last + /// arcs of the shortest paths. + /// It must conform to the \ref concepts::WriteMap "WriteMap" concept. + typedef typename GR::template NodeMap PredMap; + + /// \brief Instantiates a \c PredMap. + /// + /// This function instantiates a \ref PredMap. + /// \param g is the digraph to which we would like to define the + /// \ref PredMap. + static PredMap *createPredMap(const GR& g) { + return new PredMap(g); + } + + /// \brief The type of the map that stores the distances of the nodes. + /// + /// The type of the map that stores the distances of the nodes. + /// It must conform to the \ref concepts::WriteMap "WriteMap" concept. + typedef typename GR::template NodeMap DistMap; + + /// \brief Instantiates a \c DistMap. + /// + /// This function instantiates a \ref DistMap. + /// \param g is the digraph to which we would like to define the + /// \ref DistMap. + static DistMap *createDistMap(const GR& g) { + return new DistMap(g); + } + + }; + + /// \brief %BellmanFord algorithm class. + /// + /// \ingroup shortest_path + /// This class provides an efficient implementation of the Bellman-Ford + /// algorithm. The maximum time complexity of the algorithm is + /// O(nm). + /// + /// The Bellman-Ford algorithm solves the single-source shortest path + /// problem when the arcs can have negative lengths, but the digraph + /// should not contain directed cycles with negative total length. + /// If all arc costs are non-negative, consider to use the Dijkstra + /// algorithm instead, since it is more efficient. + /// + /// The arc lengths are passed to the algorithm using a + /// \ref concepts::ReadMap "ReadMap", so it is easy to change it to any + /// kind of length. The type of the length values is determined by the + /// \ref concepts::ReadMap::Value "Value" type of the length map. + /// + /// There is also a \ref bellmanFord() "function-type interface" for the + /// Bellman-Ford algorithm, which is convenient in the simplier cases and + /// it can be used easier. + /// + /// \tparam GR The type of the digraph the algorithm runs on. + /// The default type is \ref ListDigraph. + /// \tparam LEN A \ref concepts::ReadMap "readable" arc map that specifies + /// the lengths of the arcs. The default map type is + /// \ref concepts::Digraph::ArcMap "GR::ArcMap". + /// \tparam TR The traits class that defines various types used by the + /// algorithm. By default, it is \ref BellmanFordDefaultTraits + /// "BellmanFordDefaultTraits". + /// In most cases, this parameter should not be set directly, + /// consider to use the named template parameters instead. +#ifdef DOXYGEN + template +#else + template , + typename TR=BellmanFordDefaultTraits > +#endif + class BellmanFord { + public: + + ///The type of the underlying digraph. + typedef typename TR::Digraph Digraph; + + /// \brief The type of the arc lengths. + typedef typename TR::LengthMap::Value Value; + /// \brief The type of the map that stores the arc lengths. + typedef typename TR::LengthMap LengthMap; + /// \brief The type of the map that stores the last + /// arcs of the shortest paths. + typedef typename TR::PredMap PredMap; + /// \brief The type of the map that stores the distances of the nodes. + typedef typename TR::DistMap DistMap; + /// The type of the paths. + typedef PredMapPath Path; + ///\brief The \ref lemon::BellmanFordDefaultOperationTraits + /// "operation traits class" of the algorithm. + typedef typename TR::OperationTraits OperationTraits; + + ///\brief The \ref lemon::BellmanFordDefaultTraits "traits class" + ///of the algorithm. + typedef TR Traits; + + private: + + typedef typename Digraph::Node Node; + typedef typename Digraph::NodeIt NodeIt; + typedef typename Digraph::Arc Arc; + typedef typename Digraph::OutArcIt OutArcIt; + + // Pointer to the underlying digraph. + const Digraph *_gr; + // Pointer to the length map + const LengthMap *_length; + // Pointer to the map of predecessors arcs. + PredMap *_pred; + // Indicates if _pred is locally allocated (true) or not. + bool _local_pred; + // Pointer to the map of distances. + DistMap *_dist; + // Indicates if _dist is locally allocated (true) or not. + bool _local_dist; + + typedef typename Digraph::template NodeMap MaskMap; + MaskMap *_mask; + + std::vector _process; + + // Creates the maps if necessary. + void create_maps() { + if(!_pred) { + _local_pred = true; + _pred = Traits::createPredMap(*_gr); + } + if(!_dist) { + _local_dist = true; + _dist = Traits::createDistMap(*_gr); + } + if(!_mask) { + _mask = new MaskMap(*_gr); + } + } + + public : + + typedef BellmanFord Create; + + /// \name Named Template Parameters + + ///@{ + + template + struct SetPredMapTraits : public Traits { + typedef T PredMap; + static PredMap *createPredMap(const Digraph&) { + LEMON_ASSERT(false, "PredMap is not initialized"); + return 0; // ignore warnings + } + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c PredMap type. + /// + /// \ref named-templ-param "Named parameter" for setting + /// \c PredMap type. + /// It must conform to the \ref concepts::WriteMap "WriteMap" concept. + template + struct SetPredMap + : public BellmanFord< Digraph, LengthMap, SetPredMapTraits > { + typedef BellmanFord< Digraph, LengthMap, SetPredMapTraits > Create; + }; + + template + struct SetDistMapTraits : public Traits { + typedef T DistMap; + static DistMap *createDistMap(const Digraph&) { + LEMON_ASSERT(false, "DistMap is not initialized"); + return 0; // ignore warnings + } + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c DistMap type. + /// + /// \ref named-templ-param "Named parameter" for setting + /// \c DistMap type. + /// It must conform to the \ref concepts::WriteMap "WriteMap" concept. + template + struct SetDistMap + : public BellmanFord< Digraph, LengthMap, SetDistMapTraits > { + typedef BellmanFord< Digraph, LengthMap, SetDistMapTraits > Create; + }; + + template + struct SetOperationTraitsTraits : public Traits { + typedef T OperationTraits; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c OperationTraits type. + /// + /// \ref named-templ-param "Named parameter" for setting + /// \c OperationTraits type. + /// For more information, see \ref BellmanFordDefaultOperationTraits. + template + struct SetOperationTraits + : public BellmanFord< Digraph, LengthMap, SetOperationTraitsTraits > { + typedef BellmanFord< Digraph, LengthMap, SetOperationTraitsTraits > + Create; + }; + + ///@} + + protected: + + BellmanFord() {} + + public: + + /// \brief Constructor. + /// + /// Constructor. + /// \param g The digraph the algorithm runs on. + /// \param length The length map used by the algorithm. + BellmanFord(const Digraph& g, const LengthMap& length) : + _gr(&g), _length(&length), + _pred(0), _local_pred(false), + _dist(0), _local_dist(false), _mask(0) {} + + ///Destructor. + ~BellmanFord() { + if(_local_pred) delete _pred; + if(_local_dist) delete _dist; + if(_mask) delete _mask; + } + + /// \brief Sets the length map. + /// + /// Sets the length map. + /// \return (*this) + BellmanFord &lengthMap(const LengthMap &map) { + _length = ↦ + return *this; + } + + /// \brief Sets the map that stores the predecessor arcs. + /// + /// Sets the map that stores the predecessor arcs. + /// If you don't use this function before calling \ref run() + /// or \ref init(), an instance will be allocated automatically. + /// The destructor deallocates this automatically allocated map, + /// of course. + /// \return (*this) + BellmanFord &predMap(PredMap &map) { + if(_local_pred) { + delete _pred; + _local_pred=false; + } + _pred = ↦ + return *this; + } + + /// \brief Sets the map that stores the distances of the nodes. + /// + /// Sets the map that stores the distances of the nodes calculated + /// by the algorithm. + /// If you don't use this function before calling \ref run() + /// or \ref init(), an instance will be allocated automatically. + /// The destructor deallocates this automatically allocated map, + /// of course. + /// \return (*this) + BellmanFord &distMap(DistMap &map) { + if(_local_dist) { + delete _dist; + _local_dist=false; + } + _dist = ↦ + return *this; + } + + /// \name Execution Control + /// The simplest way to execute the Bellman-Ford algorithm is to use + /// one of the member functions called \ref run().\n + /// If you need better control on the execution, you have to call + /// \ref init() first, then you can add several source nodes + /// with \ref addSource(). Finally the actual path computation can be + /// performed with \ref start(), \ref checkedStart() or + /// \ref limitedStart(). + + ///@{ + + /// \brief Initializes the internal data structures. + /// + /// Initializes the internal data structures. The optional parameter + /// is the initial distance of each node. + void init(const Value value = OperationTraits::infinity()) { + create_maps(); + for (NodeIt it(*_gr); it != INVALID; ++it) { + _pred->set(it, INVALID); + _dist->set(it, value); + } + _process.clear(); + if (OperationTraits::less(value, OperationTraits::infinity())) { + for (NodeIt it(*_gr); it != INVALID; ++it) { + _process.push_back(it); + _mask->set(it, true); + } + } else { + for (NodeIt it(*_gr); it != INVALID; ++it) { + _mask->set(it, false); + } + } + } + + /// \brief Adds a new source node. + /// + /// This function adds a new source node. The optional second parameter + /// is the initial distance of the node. + void addSource(Node source, Value dst = OperationTraits::zero()) { + _dist->set(source, dst); + if (!(*_mask)[source]) { + _process.push_back(source); + _mask->set(source, true); + } + } + + /// \brief Executes one round from the Bellman-Ford algorithm. + /// + /// If the algoritm calculated the distances in the previous round + /// exactly for the paths of at most \c k arcs, then this function + /// will calculate the distances exactly for the paths of at most + /// k+1 arcs. Performing \c k iterations using this function + /// calculates the shortest path distances exactly for the paths + /// consisting of at most \c k arcs. + /// + /// \warning The paths with limited arc number cannot be retrieved + /// easily with \ref path() or \ref predArc() functions. If you also + /// need the shortest paths and not only the distances, you should + /// store the \ref predMap() "predecessor map" after each iteration + /// and build the path manually. + /// + /// \return \c true when the algorithm have not found more shorter + /// paths. + /// + /// \see ActiveIt + bool processNextRound() { + for (int i = 0; i < int(_process.size()); ++i) { + _mask->set(_process[i], false); + } + std::vector nextProcess; + std::vector values(_process.size()); + for (int i = 0; i < int(_process.size()); ++i) { + values[i] = (*_dist)[_process[i]]; + } + for (int i = 0; i < int(_process.size()); ++i) { + for (OutArcIt it(*_gr, _process[i]); it != INVALID; ++it) { + Node target = _gr->target(it); + Value relaxed = OperationTraits::plus(values[i], (*_length)[it]); + if (OperationTraits::less(relaxed, (*_dist)[target])) { + _pred->set(target, it); + _dist->set(target, relaxed); + if (!(*_mask)[target]) { + _mask->set(target, true); + nextProcess.push_back(target); + } + } + } + } + _process.swap(nextProcess); + return _process.empty(); + } + + /// \brief Executes one weak round from the Bellman-Ford algorithm. + /// + /// If the algorithm calculated the distances in the previous round + /// at least for the paths of at most \c k arcs, then this function + /// will calculate the distances at least for the paths of at most + /// k+1 arcs. + /// This function does not make it possible to calculate the shortest + /// path distances exactly for paths consisting of at most \c k arcs, + /// this is why it is called weak round. + /// + /// \return \c true when the algorithm have not found more shorter + /// paths. + /// + /// \see ActiveIt + bool processNextWeakRound() { + for (int i = 0; i < int(_process.size()); ++i) { + _mask->set(_process[i], false); + } + std::vector nextProcess; + for (int i = 0; i < int(_process.size()); ++i) { + for (OutArcIt it(*_gr, _process[i]); it != INVALID; ++it) { + Node target = _gr->target(it); + Value relaxed = + OperationTraits::plus((*_dist)[_process[i]], (*_length)[it]); + if (OperationTraits::less(relaxed, (*_dist)[target])) { + _pred->set(target, it); + _dist->set(target, relaxed); + if (!(*_mask)[target]) { + _mask->set(target, true); + nextProcess.push_back(target); + } + } + } + } + _process.swap(nextProcess); + return _process.empty(); + } + + /// \brief Executes the algorithm. + /// + /// Executes the algorithm. + /// + /// This method runs the Bellman-Ford algorithm from the root node(s) + /// in order to compute the shortest path to each node. + /// + /// The algorithm computes + /// - the shortest path tree (forest), + /// - the distance of each node from the root(s). + /// + /// \pre init() must be called and at least one root node should be + /// added with addSource() before using this function. + void start() { + int num = countNodes(*_gr) - 1; + for (int i = 0; i < num; ++i) { + if (processNextWeakRound()) break; + } + } + + /// \brief Executes the algorithm and checks the negative cycles. + /// + /// Executes the algorithm and checks the negative cycles. + /// + /// This method runs the Bellman-Ford algorithm from the root node(s) + /// in order to compute the shortest path to each node and also checks + /// if the digraph contains cycles with negative total length. + /// + /// The algorithm computes + /// - the shortest path tree (forest), + /// - the distance of each node from the root(s). + /// + /// \return \c false if there is a negative cycle in the digraph. + /// + /// \pre init() must be called and at least one root node should be + /// added with addSource() before using this function. + bool checkedStart() { + int num = countNodes(*_gr); + for (int i = 0; i < num; ++i) { + if (processNextWeakRound()) return true; + } + return _process.empty(); + } + + /// \brief Executes the algorithm with arc number limit. + /// + /// Executes the algorithm with arc number limit. + /// + /// This method runs the Bellman-Ford algorithm from the root node(s) + /// in order to compute the shortest path distance for each node + /// using only the paths consisting of at most \c num arcs. + /// + /// The algorithm computes + /// - the limited distance of each node from the root(s), + /// - the predecessor arc for each node. + /// + /// \warning The paths with limited arc number cannot be retrieved + /// easily with \ref path() or \ref predArc() functions. If you also + /// need the shortest paths and not only the distances, you should + /// store the \ref predMap() "predecessor map" after each iteration + /// and build the path manually. + /// + /// \pre init() must be called and at least one root node should be + /// added with addSource() before using this function. + void limitedStart(int num) { + for (int i = 0; i < num; ++i) { + if (processNextRound()) break; + } + } + + /// \brief Runs the algorithm from the given root node. + /// + /// This method runs the Bellman-Ford algorithm from the given root + /// node \c s in order to compute the shortest path to each node. + /// + /// The algorithm computes + /// - the shortest path tree (forest), + /// - the distance of each node from the root(s). + /// + /// \note bf.run(s) is just a shortcut of the following code. + /// \code + /// bf.init(); + /// bf.addSource(s); + /// bf.start(); + /// \endcode + void run(Node s) { + init(); + addSource(s); + start(); + } + + /// \brief Runs the algorithm from the given root node with arc + /// number limit. + /// + /// This method runs the Bellman-Ford algorithm from the given root + /// node \c s in order to compute the shortest path distance for each + /// node using only the paths consisting of at most \c num arcs. + /// + /// The algorithm computes + /// - the limited distance of each node from the root(s), + /// - the predecessor arc for each node. + /// + /// \warning The paths with limited arc number cannot be retrieved + /// easily with \ref path() or \ref predArc() functions. If you also + /// need the shortest paths and not only the distances, you should + /// store the \ref predMap() "predecessor map" after each iteration + /// and build the path manually. + /// + /// \note bf.run(s, num) is just a shortcut of the following code. + /// \code + /// bf.init(); + /// bf.addSource(s); + /// bf.limitedStart(num); + /// \endcode + void run(Node s, int num) { + init(); + addSource(s); + limitedStart(num); + } + + ///@} + + /// \brief LEMON iterator for getting the active nodes. + /// + /// This class provides a common style LEMON iterator that traverses + /// the active nodes of the Bellman-Ford algorithm after the last + /// phase. These nodes should be checked in the next phase to + /// find augmenting arcs outgoing from them. + class ActiveIt { + public: + + /// \brief Constructor. + /// + /// Constructor for getting the active nodes of the given BellmanFord + /// instance. + ActiveIt(const BellmanFord& algorithm) : _algorithm(&algorithm) + { + _index = _algorithm->_process.size() - 1; + } + + /// \brief Invalid constructor. + /// + /// Invalid constructor. + ActiveIt(Invalid) : _algorithm(0), _index(-1) {} + + /// \brief Conversion to \c Node. + /// + /// Conversion to \c Node. + operator Node() const { + return _index >= 0 ? _algorithm->_process[_index] : INVALID; + } + + /// \brief Increment operator. + /// + /// Increment operator. + ActiveIt& operator++() { + --_index; + return *this; + } + + bool operator==(const ActiveIt& it) const { + return static_cast(*this) == static_cast(it); + } + bool operator!=(const ActiveIt& it) const { + return static_cast(*this) != static_cast(it); + } + bool operator<(const ActiveIt& it) const { + return static_cast(*this) < static_cast(it); + } + + private: + const BellmanFord* _algorithm; + int _index; + }; + + /// \name Query Functions + /// The result of the Bellman-Ford algorithm can be obtained using these + /// functions.\n + /// Either \ref run() or \ref init() should be called before using them. + + ///@{ + + /// \brief The shortest path to the given node. + /// + /// Gives back the shortest path to the given node from the root(s). + /// + /// \warning \c t should be reached from the root(s). + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + Path path(Node t) const + { + return Path(*_gr, *_pred, t); + } + + /// \brief The distance of the given node from the root(s). + /// + /// Returns the distance of the given node from the root(s). + /// + /// \warning If node \c v is not reached from the root(s), then + /// the return value of this function is undefined. + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + Value dist(Node v) const { return (*_dist)[v]; } + + /// \brief Returns the 'previous arc' of the shortest path tree for + /// the given node. + /// + /// This function returns the 'previous arc' of the shortest path + /// tree for node \c v, i.e. it returns the last arc of a + /// shortest path from a root to \c v. It is \c INVALID if \c v + /// is not reached from the root(s) or if \c v is a root. + /// + /// The shortest path tree used here is equal to the shortest path + /// tree used in \ref predNode() and \ref predMap(). + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + Arc predArc(Node v) const { return (*_pred)[v]; } + + /// \brief Returns the 'previous node' of the shortest path tree for + /// the given node. + /// + /// This function returns the 'previous node' of the shortest path + /// tree for node \c v, i.e. it returns the last but one node of + /// a shortest path from a root to \c v. It is \c INVALID if \c v + /// is not reached from the root(s) or if \c v is a root. + /// + /// The shortest path tree used here is equal to the shortest path + /// tree used in \ref predArc() and \ref predMap(). + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + Node predNode(Node v) const { + return (*_pred)[v] == INVALID ? INVALID : _gr->source((*_pred)[v]); + } + + /// \brief Returns a const reference to the node map that stores the + /// distances of the nodes. + /// + /// Returns a const reference to the node map that stores the distances + /// of the nodes calculated by the algorithm. + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + const DistMap &distMap() const { return *_dist;} + + /// \brief Returns a const reference to the node map that stores the + /// predecessor arcs. + /// + /// Returns a const reference to the node map that stores the predecessor + /// arcs, which form the shortest path tree (forest). + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + const PredMap &predMap() const { return *_pred; } + + /// \brief Checks if a node is reached from the root(s). + /// + /// Returns \c true if \c v is reached from the root(s). + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + bool reached(Node v) const { + return (*_dist)[v] != OperationTraits::infinity(); + } + + /// \brief Gives back a negative cycle. + /// + /// This function gives back a directed cycle with negative total + /// length if the algorithm has already found one. + /// Otherwise it gives back an empty path. + lemon::Path negativeCycle() const { + typename Digraph::template NodeMap state(*_gr, -1); + lemon::Path cycle; + for (int i = 0; i < int(_process.size()); ++i) { + if (state[_process[i]] != -1) continue; + for (Node v = _process[i]; (*_pred)[v] != INVALID; + v = _gr->source((*_pred)[v])) { + if (state[v] == i) { + cycle.addFront((*_pred)[v]); + for (Node u = _gr->source((*_pred)[v]); u != v; + u = _gr->source((*_pred)[u])) { + cycle.addFront((*_pred)[u]); + } + return cycle; + } + else if (state[v] >= 0) { + break; + } + state[v] = i; + } + } + return cycle; + } + + ///@} + }; + + /// \brief Default traits class of bellmanFord() function. + /// + /// Default traits class of bellmanFord() function. + /// \tparam GR The type of the digraph. + /// \tparam LEN The type of the length map. + template + struct BellmanFordWizardDefaultTraits { + /// The type of the digraph the algorithm runs on. + typedef GR Digraph; + + /// \brief The type of the map that stores the arc lengths. + /// + /// The type of the map that stores the arc lengths. + /// It must meet the \ref concepts::ReadMap "ReadMap" concept. + typedef LEN LengthMap; + + /// The type of the arc lengths. + typedef typename LEN::Value Value; + + /// \brief Operation traits for Bellman-Ford algorithm. + /// + /// It defines the used operations and the infinity value for the + /// given \c Value type. + /// \see BellmanFordDefaultOperationTraits + typedef BellmanFordDefaultOperationTraits OperationTraits; + + /// \brief The type of the map that stores the last + /// arcs of the shortest paths. + /// + /// The type of the map that stores the last arcs of the shortest paths. + /// It must conform to the \ref concepts::WriteMap "WriteMap" concept. + typedef typename GR::template NodeMap PredMap; + + /// \brief Instantiates a \c PredMap. + /// + /// This function instantiates a \ref PredMap. + /// \param g is the digraph to which we would like to define the + /// \ref PredMap. + static PredMap *createPredMap(const GR &g) { + return new PredMap(g); + } + + /// \brief The type of the map that stores the distances of the nodes. + /// + /// The type of the map that stores the distances of the nodes. + /// It must conform to the \ref concepts::WriteMap "WriteMap" concept. + typedef typename GR::template NodeMap DistMap; + + /// \brief Instantiates a \c DistMap. + /// + /// This function instantiates a \ref DistMap. + /// \param g is the digraph to which we would like to define the + /// \ref DistMap. + static DistMap *createDistMap(const GR &g) { + return new DistMap(g); + } + + ///The type of the shortest paths. + + ///The type of the shortest paths. + ///It must meet the \ref concepts::Path "Path" concept. + typedef lemon::Path Path; + }; + + /// \brief Default traits class used by BellmanFordWizard. + /// + /// Default traits class used by BellmanFordWizard. + /// \tparam GR The type of the digraph. + /// \tparam LEN The type of the length map. + template + class BellmanFordWizardBase + : public BellmanFordWizardDefaultTraits { + + typedef BellmanFordWizardDefaultTraits Base; + protected: + // Type of the nodes in the digraph. + typedef typename Base::Digraph::Node Node; + + // Pointer to the underlying digraph. + void *_graph; + // Pointer to the length map + void *_length; + // Pointer to the map of predecessors arcs. + void *_pred; + // Pointer to the map of distances. + void *_dist; + //Pointer to the shortest path to the target node. + void *_path; + //Pointer to the distance of the target node. + void *_di; + + public: + /// Constructor. + + /// This constructor does not require parameters, it initiates + /// all of the attributes to default values \c 0. + BellmanFordWizardBase() : + _graph(0), _length(0), _pred(0), _dist(0), _path(0), _di(0) {} + + /// Constructor. + + /// This constructor requires two parameters, + /// others are initiated to \c 0. + /// \param gr The digraph the algorithm runs on. + /// \param len The length map. + BellmanFordWizardBase(const GR& gr, + const LEN& len) : + _graph(reinterpret_cast(const_cast(&gr))), + _length(reinterpret_cast(const_cast(&len))), + _pred(0), _dist(0), _path(0), _di(0) {} + + }; + + /// \brief Auxiliary class for the function-type interface of the + /// \ref BellmanFord "Bellman-Ford" algorithm. + /// + /// This auxiliary class is created to implement the + /// \ref bellmanFord() "function-type interface" of the + /// \ref BellmanFord "Bellman-Ford" algorithm. + /// It does not have own \ref run() method, it uses the + /// functions and features of the plain \ref BellmanFord. + /// + /// This class should only be used through the \ref bellmanFord() + /// function, which makes it easier to use the algorithm. + /// + /// \tparam TR The traits class that defines various types used by the + /// algorithm. + template + class BellmanFordWizard : public TR { + typedef TR Base; + + typedef typename TR::Digraph Digraph; + + typedef typename Digraph::Node Node; + typedef typename Digraph::NodeIt NodeIt; + typedef typename Digraph::Arc Arc; + typedef typename Digraph::OutArcIt ArcIt; + + typedef typename TR::LengthMap LengthMap; + typedef typename LengthMap::Value Value; + typedef typename TR::PredMap PredMap; + typedef typename TR::DistMap DistMap; + typedef typename TR::Path Path; + + public: + /// Constructor. + BellmanFordWizard() : TR() {} + + /// \brief Constructor that requires parameters. + /// + /// Constructor that requires parameters. + /// These parameters will be the default values for the traits class. + /// \param gr The digraph the algorithm runs on. + /// \param len The length map. + BellmanFordWizard(const Digraph& gr, const LengthMap& len) + : TR(gr, len) {} + + /// \brief Copy constructor + BellmanFordWizard(const TR &b) : TR(b) {} + + ~BellmanFordWizard() {} + + /// \brief Runs the Bellman-Ford algorithm from the given source node. + /// + /// This method runs the Bellman-Ford algorithm from the given source + /// node in order to compute the shortest path to each node. + void run(Node s) { + BellmanFord + bf(*reinterpret_cast(Base::_graph), + *reinterpret_cast(Base::_length)); + if (Base::_pred) bf.predMap(*reinterpret_cast(Base::_pred)); + if (Base::_dist) bf.distMap(*reinterpret_cast(Base::_dist)); + bf.run(s); + } + + /// \brief Runs the Bellman-Ford algorithm to find the shortest path + /// between \c s and \c t. + /// + /// This method runs the Bellman-Ford algorithm from node \c s + /// in order to compute the shortest path to node \c t. + /// Actually, it computes the shortest path to each node, but using + /// this function you can retrieve the distance and the shortest path + /// for a single target node easier. + /// + /// \return \c true if \c t is reachable form \c s. + bool run(Node s, Node t) { + BellmanFord + bf(*reinterpret_cast(Base::_graph), + *reinterpret_cast(Base::_length)); + if (Base::_pred) bf.predMap(*reinterpret_cast(Base::_pred)); + if (Base::_dist) bf.distMap(*reinterpret_cast(Base::_dist)); + bf.run(s); + if (Base::_path) *reinterpret_cast(Base::_path) = bf.path(t); + if (Base::_di) *reinterpret_cast(Base::_di) = bf.dist(t); + return bf.reached(t); + } + + template + struct SetPredMapBase : public Base { + typedef T PredMap; + static PredMap *createPredMap(const Digraph &) { return 0; }; + SetPredMapBase(const TR &b) : TR(b) {} + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// the predecessor map. + /// + /// \ref named-templ-param "Named parameter" for setting + /// the map that stores the predecessor arcs of the nodes. + template + BellmanFordWizard > predMap(const T &t) { + Base::_pred=reinterpret_cast(const_cast(&t)); + return BellmanFordWizard >(*this); + } + + template + struct SetDistMapBase : public Base { + typedef T DistMap; + static DistMap *createDistMap(const Digraph &) { return 0; }; + SetDistMapBase(const TR &b) : TR(b) {} + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// the distance map. + /// + /// \ref named-templ-param "Named parameter" for setting + /// the map that stores the distances of the nodes calculated + /// by the algorithm. + template + BellmanFordWizard > distMap(const T &t) { + Base::_dist=reinterpret_cast(const_cast(&t)); + return BellmanFordWizard >(*this); + } + + template + struct SetPathBase : public Base { + typedef T Path; + SetPathBase(const TR &b) : TR(b) {} + }; + + /// \brief \ref named-func-param "Named parameter" for getting + /// the shortest path to the target node. + /// + /// \ref named-func-param "Named parameter" for getting + /// the shortest path to the target node. + template + BellmanFordWizard > path(const T &t) + { + Base::_path=reinterpret_cast(const_cast(&t)); + return BellmanFordWizard >(*this); + } + + /// \brief \ref named-func-param "Named parameter" for getting + /// the distance of the target node. + /// + /// \ref named-func-param "Named parameter" for getting + /// the distance of the target node. + BellmanFordWizard dist(const Value &d) + { + Base::_di=reinterpret_cast(const_cast(&d)); + return *this; + } + + }; + + /// \brief Function type interface for the \ref BellmanFord "Bellman-Ford" + /// algorithm. + /// + /// \ingroup shortest_path + /// Function type interface for the \ref BellmanFord "Bellman-Ford" + /// algorithm. + /// + /// This function also has several \ref named-templ-func-param + /// "named parameters", they are declared as the members of class + /// \ref BellmanFordWizard. + /// The following examples show how to use these parameters. + /// \code + /// // Compute shortest path from node s to each node + /// bellmanFord(g,length).predMap(preds).distMap(dists).run(s); + /// + /// // Compute shortest path from s to t + /// bool reached = bellmanFord(g,length).path(p).dist(d).run(s,t); + /// \endcode + /// \warning Don't forget to put the \ref BellmanFordWizard::run() "run()" + /// to the end of the parameter list. + /// \sa BellmanFordWizard + /// \sa BellmanFord + template + BellmanFordWizard > + bellmanFord(const GR& digraph, + const LEN& length) + { + return BellmanFordWizard >(digraph, length); + } + +} //END OF NAMESPACE LEMON + +#endif + diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bfs.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bfs.h new file mode 100644 index 00000000000..e5f4e5c5a31 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bfs.h @@ -0,0 +1,1754 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_BFS_H +#define LEMON_BFS_H + +///\ingroup search +///\file +///\brief BFS algorithm. + +#include +#include +#include +#include +#include +#include + +namespace lemon { + + ///Default traits class of Bfs class. + + ///Default traits class of Bfs class. + ///\tparam GR Digraph type. + template + struct BfsDefaultTraits + { + ///The type of the digraph the algorithm runs on. + typedef GR Digraph; + + ///\brief The type of the map that stores the predecessor + ///arcs of the shortest paths. + /// + ///The type of the map that stores the predecessor + ///arcs of the shortest paths. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + typedef typename Digraph::template NodeMap PredMap; + ///Instantiates a \c PredMap. + + ///This function instantiates a \ref PredMap. + ///\param g is the digraph, to which we would like to define the + ///\ref PredMap. + static PredMap *createPredMap(const Digraph &g) + { + return new PredMap(g); + } + + ///The type of the map that indicates which nodes are processed. + + ///The type of the map that indicates which nodes are processed. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + ///By default, it is a NullMap. + typedef NullMap ProcessedMap; + ///Instantiates a \c ProcessedMap. + + ///This function instantiates a \ref ProcessedMap. + ///\param g is the digraph, to which + ///we would like to define the \ref ProcessedMap +#ifdef DOXYGEN + static ProcessedMap *createProcessedMap(const Digraph &g) +#else + static ProcessedMap *createProcessedMap(const Digraph &) +#endif + { + return new ProcessedMap(); + } + + ///The type of the map that indicates which nodes are reached. + + ///The type of the map that indicates which nodes are reached. + ///It must conform to + ///the \ref concepts::ReadWriteMap "ReadWriteMap" concept. + typedef typename Digraph::template NodeMap ReachedMap; + ///Instantiates a \c ReachedMap. + + ///This function instantiates a \ref ReachedMap. + ///\param g is the digraph, to which + ///we would like to define the \ref ReachedMap. + static ReachedMap *createReachedMap(const Digraph &g) + { + return new ReachedMap(g); + } + + ///The type of the map that stores the distances of the nodes. + + ///The type of the map that stores the distances of the nodes. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + typedef typename Digraph::template NodeMap DistMap; + ///Instantiates a \c DistMap. + + ///This function instantiates a \ref DistMap. + ///\param g is the digraph, to which we would like to define the + ///\ref DistMap. + static DistMap *createDistMap(const Digraph &g) + { + return new DistMap(g); + } + }; + + ///%BFS algorithm class. + + ///\ingroup search + ///This class provides an efficient implementation of the %BFS algorithm. + /// + ///There is also a \ref bfs() "function-type interface" for the BFS + ///algorithm, which is convenient in the simplier cases and it can be + ///used easier. + /// + ///\tparam GR The type of the digraph the algorithm runs on. + ///The default type is \ref ListDigraph. + ///\tparam TR The traits class that defines various types used by the + ///algorithm. By default, it is \ref BfsDefaultTraits + ///"BfsDefaultTraits". + ///In most cases, this parameter should not be set directly, + ///consider to use the named template parameters instead. +#ifdef DOXYGEN + template +#else + template > +#endif + class Bfs { + public: + + ///The type of the digraph the algorithm runs on. + typedef typename TR::Digraph Digraph; + + ///\brief The type of the map that stores the predecessor arcs of the + ///shortest paths. + typedef typename TR::PredMap PredMap; + ///The type of the map that stores the distances of the nodes. + typedef typename TR::DistMap DistMap; + ///The type of the map that indicates which nodes are reached. + typedef typename TR::ReachedMap ReachedMap; + ///The type of the map that indicates which nodes are processed. + typedef typename TR::ProcessedMap ProcessedMap; + ///The type of the paths. + typedef PredMapPath Path; + + ///The \ref lemon::BfsDefaultTraits "traits class" of the algorithm. + typedef TR Traits; + + private: + + typedef typename Digraph::Node Node; + typedef typename Digraph::NodeIt NodeIt; + typedef typename Digraph::Arc Arc; + typedef typename Digraph::OutArcIt OutArcIt; + + //Pointer to the underlying digraph. + const Digraph *G; + //Pointer to the map of predecessor arcs. + PredMap *_pred; + //Indicates if _pred is locally allocated (true) or not. + bool local_pred; + //Pointer to the map of distances. + DistMap *_dist; + //Indicates if _dist is locally allocated (true) or not. + bool local_dist; + //Pointer to the map of reached status of the nodes. + ReachedMap *_reached; + //Indicates if _reached is locally allocated (true) or not. + bool local_reached; + //Pointer to the map of processed status of the nodes. + ProcessedMap *_processed; + //Indicates if _processed is locally allocated (true) or not. + bool local_processed; + + std::vector _queue; + int _queue_head,_queue_tail,_queue_next_dist; + int _curr_dist; + + //Creates the maps if necessary. + void create_maps() + { + if(!_pred) { + local_pred = true; + _pred = Traits::createPredMap(*G); + } + if(!_dist) { + local_dist = true; + _dist = Traits::createDistMap(*G); + } + if(!_reached) { + local_reached = true; + _reached = Traits::createReachedMap(*G); + } + if(!_processed) { + local_processed = true; + _processed = Traits::createProcessedMap(*G); + } + } + + protected: + + Bfs() {} + + public: + + typedef Bfs Create; + + ///\name Named Template Parameters + + ///@{ + + template + struct SetPredMapTraits : public Traits { + typedef T PredMap; + static PredMap *createPredMap(const Digraph &) + { + LEMON_ASSERT(false, "PredMap is not initialized"); + return 0; // ignore warnings + } + }; + ///\brief \ref named-templ-param "Named parameter" for setting + ///\c PredMap type. + /// + ///\ref named-templ-param "Named parameter" for setting + ///\c PredMap type. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + template + struct SetPredMap : public Bfs< Digraph, SetPredMapTraits > { + typedef Bfs< Digraph, SetPredMapTraits > Create; + }; + + template + struct SetDistMapTraits : public Traits { + typedef T DistMap; + static DistMap *createDistMap(const Digraph &) + { + LEMON_ASSERT(false, "DistMap is not initialized"); + return 0; // ignore warnings + } + }; + ///\brief \ref named-templ-param "Named parameter" for setting + ///\c DistMap type. + /// + ///\ref named-templ-param "Named parameter" for setting + ///\c DistMap type. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + template + struct SetDistMap : public Bfs< Digraph, SetDistMapTraits > { + typedef Bfs< Digraph, SetDistMapTraits > Create; + }; + + template + struct SetReachedMapTraits : public Traits { + typedef T ReachedMap; + static ReachedMap *createReachedMap(const Digraph &) + { + LEMON_ASSERT(false, "ReachedMap is not initialized"); + return 0; // ignore warnings + } + }; + ///\brief \ref named-templ-param "Named parameter" for setting + ///\c ReachedMap type. + /// + ///\ref named-templ-param "Named parameter" for setting + ///\c ReachedMap type. + ///It must conform to + ///the \ref concepts::ReadWriteMap "ReadWriteMap" concept. + template + struct SetReachedMap : public Bfs< Digraph, SetReachedMapTraits > { + typedef Bfs< Digraph, SetReachedMapTraits > Create; + }; + + template + struct SetProcessedMapTraits : public Traits { + typedef T ProcessedMap; + static ProcessedMap *createProcessedMap(const Digraph &) + { + LEMON_ASSERT(false, "ProcessedMap is not initialized"); + return 0; // ignore warnings + } + }; + ///\brief \ref named-templ-param "Named parameter" for setting + ///\c ProcessedMap type. + /// + ///\ref named-templ-param "Named parameter" for setting + ///\c ProcessedMap type. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + template + struct SetProcessedMap : public Bfs< Digraph, SetProcessedMapTraits > { + typedef Bfs< Digraph, SetProcessedMapTraits > Create; + }; + + struct SetStandardProcessedMapTraits : public Traits { + typedef typename Digraph::template NodeMap ProcessedMap; + static ProcessedMap *createProcessedMap(const Digraph &g) + { + return new ProcessedMap(g); + return 0; // ignore warnings + } + }; + ///\brief \ref named-templ-param "Named parameter" for setting + ///\c ProcessedMap type to be Digraph::NodeMap. + /// + ///\ref named-templ-param "Named parameter" for setting + ///\c ProcessedMap type to be Digraph::NodeMap. + ///If you don't set it explicitly, it will be automatically allocated. + struct SetStandardProcessedMap : + public Bfs< Digraph, SetStandardProcessedMapTraits > { + typedef Bfs< Digraph, SetStandardProcessedMapTraits > Create; + }; + + ///@} + + public: + + ///Constructor. + + ///Constructor. + ///\param g The digraph the algorithm runs on. + Bfs(const Digraph &g) : + G(&g), + _pred(NULL), local_pred(false), + _dist(NULL), local_dist(false), + _reached(NULL), local_reached(false), + _processed(NULL), local_processed(false) + { } + + ///Destructor. + ~Bfs() + { + if(local_pred) delete _pred; + if(local_dist) delete _dist; + if(local_reached) delete _reached; + if(local_processed) delete _processed; + } + + ///Sets the map that stores the predecessor arcs. + + ///Sets the map that stores the predecessor arcs. + ///If you don't use this function before calling \ref run(Node) "run()" + ///or \ref init(), an instance will be allocated automatically. + ///The destructor deallocates this automatically allocated map, + ///of course. + ///\return (*this) + Bfs &predMap(PredMap &m) + { + if(local_pred) { + delete _pred; + local_pred=false; + } + _pred = &m; + return *this; + } + + ///Sets the map that indicates which nodes are reached. + + ///Sets the map that indicates which nodes are reached. + ///If you don't use this function before calling \ref run(Node) "run()" + ///or \ref init(), an instance will be allocated automatically. + ///The destructor deallocates this automatically allocated map, + ///of course. + ///\return (*this) + Bfs &reachedMap(ReachedMap &m) + { + if(local_reached) { + delete _reached; + local_reached=false; + } + _reached = &m; + return *this; + } + + ///Sets the map that indicates which nodes are processed. + + ///Sets the map that indicates which nodes are processed. + ///If you don't use this function before calling \ref run(Node) "run()" + ///or \ref init(), an instance will be allocated automatically. + ///The destructor deallocates this automatically allocated map, + ///of course. + ///\return (*this) + Bfs &processedMap(ProcessedMap &m) + { + if(local_processed) { + delete _processed; + local_processed=false; + } + _processed = &m; + return *this; + } + + ///Sets the map that stores the distances of the nodes. + + ///Sets the map that stores the distances of the nodes calculated by + ///the algorithm. + ///If you don't use this function before calling \ref run(Node) "run()" + ///or \ref init(), an instance will be allocated automatically. + ///The destructor deallocates this automatically allocated map, + ///of course. + ///\return (*this) + Bfs &distMap(DistMap &m) + { + if(local_dist) { + delete _dist; + local_dist=false; + } + _dist = &m; + return *this; + } + + public: + + ///\name Execution Control + ///The simplest way to execute the BFS algorithm is to use one of the + ///member functions called \ref run(Node) "run()".\n + ///If you need better control on the execution, you have to call + ///\ref init() first, then you can add several source nodes with + ///\ref addSource(). Finally the actual path computation can be + ///performed with one of the \ref start() functions. + + ///@{ + + ///\brief Initializes the internal data structures. + /// + ///Initializes the internal data structures. + void init() + { + create_maps(); + _queue.resize(countNodes(*G)); + _queue_head=_queue_tail=0; + _curr_dist=1; + for ( NodeIt u(*G) ; u!=INVALID ; ++u ) { + _pred->set(u,INVALID); + _reached->set(u,false); + _processed->set(u,false); + } + } + + ///Adds a new source node. + + ///Adds a new source node to the set of nodes to be processed. + /// + void addSource(Node s) + { + if(!(*_reached)[s]) + { + _reached->set(s,true); + _pred->set(s,INVALID); + _dist->set(s,0); + _queue[_queue_head++]=s; + _queue_next_dist=_queue_head; + } + } + + ///Processes the next node. + + ///Processes the next node. + /// + ///\return The processed node. + /// + ///\pre The queue must not be empty. + Node processNextNode() + { + if(_queue_tail==_queue_next_dist) { + _curr_dist++; + _queue_next_dist=_queue_head; + } + Node n=_queue[_queue_tail++]; + _processed->set(n,true); + Node m; + for(OutArcIt e(*G,n);e!=INVALID;++e) + if(!(*_reached)[m=G->target(e)]) { + _queue[_queue_head++]=m; + _reached->set(m,true); + _pred->set(m,e); + _dist->set(m,_curr_dist); + } + return n; + } + + ///Processes the next node. + + ///Processes the next node and checks if the given target node + ///is reached. If the target node is reachable from the processed + ///node, then the \c reach parameter will be set to \c true. + /// + ///\param target The target node. + ///\retval reach Indicates if the target node is reached. + ///It should be initially \c false. + /// + ///\return The processed node. + /// + ///\pre The queue must not be empty. + Node processNextNode(Node target, bool& reach) + { + if(_queue_tail==_queue_next_dist) { + _curr_dist++; + _queue_next_dist=_queue_head; + } + Node n=_queue[_queue_tail++]; + _processed->set(n,true); + Node m; + for(OutArcIt e(*G,n);e!=INVALID;++e) + if(!(*_reached)[m=G->target(e)]) { + _queue[_queue_head++]=m; + _reached->set(m,true); + _pred->set(m,e); + _dist->set(m,_curr_dist); + reach = reach || (target == m); + } + return n; + } + + ///Processes the next node. + + ///Processes the next node and checks if at least one of reached + ///nodes has \c true value in the \c nm node map. If one node + ///with \c true value is reachable from the processed node, then the + ///\c rnode parameter will be set to the first of such nodes. + /// + ///\param nm A \c bool (or convertible) node map that indicates the + ///possible targets. + ///\retval rnode The reached target node. + ///It should be initially \c INVALID. + /// + ///\return The processed node. + /// + ///\pre The queue must not be empty. + template + Node processNextNode(const NM& nm, Node& rnode) + { + if(_queue_tail==_queue_next_dist) { + _curr_dist++; + _queue_next_dist=_queue_head; + } + Node n=_queue[_queue_tail++]; + _processed->set(n,true); + Node m; + for(OutArcIt e(*G,n);e!=INVALID;++e) + if(!(*_reached)[m=G->target(e)]) { + _queue[_queue_head++]=m; + _reached->set(m,true); + _pred->set(m,e); + _dist->set(m,_curr_dist); + if (nm[m] && rnode == INVALID) rnode = m; + } + return n; + } + + ///The next node to be processed. + + ///Returns the next node to be processed or \c INVALID if the queue + ///is empty. + Node nextNode() const + { + return _queue_tail<_queue_head?_queue[_queue_tail]:INVALID; + } + + ///Returns \c false if there are nodes to be processed. + + ///Returns \c false if there are nodes to be processed + ///in the queue. + bool emptyQueue() const { return _queue_tail==_queue_head; } + + ///Returns the number of the nodes to be processed. + + ///Returns the number of the nodes to be processed + ///in the queue. + int queueSize() const { return _queue_head-_queue_tail; } + + ///Executes the algorithm. + + ///Executes the algorithm. + /// + ///This method runs the %BFS algorithm from the root node(s) + ///in order to compute the shortest path to each node. + /// + ///The algorithm computes + ///- the shortest path tree (forest), + ///- the distance of each node from the root(s). + /// + ///\pre init() must be called and at least one root node should be + ///added with addSource() before using this function. + /// + ///\note b.start() is just a shortcut of the following code. + ///\code + /// while ( !b.emptyQueue() ) { + /// b.processNextNode(); + /// } + ///\endcode + void start() + { + while ( !emptyQueue() ) processNextNode(); + } + + ///Executes the algorithm until the given target node is reached. + + ///Executes the algorithm until the given target node is reached. + /// + ///This method runs the %BFS algorithm from the root node(s) + ///in order to compute the shortest path to \c t. + /// + ///The algorithm computes + ///- the shortest path to \c t, + ///- the distance of \c t from the root(s). + /// + ///\pre init() must be called and at least one root node should be + ///added with addSource() before using this function. + /// + ///\note b.start(t) is just a shortcut of the following code. + ///\code + /// bool reach = false; + /// while ( !b.emptyQueue() && !reach ) { + /// b.processNextNode(t, reach); + /// } + ///\endcode + void start(Node t) + { + bool reach = false; + while ( !emptyQueue() && !reach ) processNextNode(t, reach); + } + + ///Executes the algorithm until a condition is met. + + ///Executes the algorithm until a condition is met. + /// + ///This method runs the %BFS algorithm from the root node(s) in + ///order to compute the shortest path to a node \c v with + /// nm[v] true, if such a node can be found. + /// + ///\param nm A \c bool (or convertible) node map. The algorithm + ///will stop when it reaches a node \c v with nm[v] true. + /// + ///\return The reached node \c v with nm[v] true or + ///\c INVALID if no such node was found. + /// + ///\pre init() must be called and at least one root node should be + ///added with addSource() before using this function. + /// + ///\note b.start(nm) is just a shortcut of the following code. + ///\code + /// Node rnode = INVALID; + /// while ( !b.emptyQueue() && rnode == INVALID ) { + /// b.processNextNode(nm, rnode); + /// } + /// return rnode; + ///\endcode + template + Node start(const NodeBoolMap &nm) + { + Node rnode = INVALID; + while ( !emptyQueue() && rnode == INVALID ) { + processNextNode(nm, rnode); + } + return rnode; + } + + ///Runs the algorithm from the given source node. + + ///This method runs the %BFS algorithm from node \c s + ///in order to compute the shortest path to each node. + /// + ///The algorithm computes + ///- the shortest path tree, + ///- the distance of each node from the root. + /// + ///\note b.run(s) is just a shortcut of the following code. + ///\code + /// b.init(); + /// b.addSource(s); + /// b.start(); + ///\endcode + void run(Node s) { + init(); + addSource(s); + start(); + } + + ///Finds the shortest path between \c s and \c t. + + ///This method runs the %BFS algorithm from node \c s + ///in order to compute the shortest path to node \c t + ///(it stops searching when \c t is processed). + /// + ///\return \c true if \c t is reachable form \c s. + /// + ///\note Apart from the return value, b.run(s,t) is just a + ///shortcut of the following code. + ///\code + /// b.init(); + /// b.addSource(s); + /// b.start(t); + ///\endcode + bool run(Node s,Node t) { + init(); + addSource(s); + start(t); + return reached(t); + } + + ///Runs the algorithm to visit all nodes in the digraph. + + ///This method runs the %BFS algorithm in order to visit all nodes + ///in the digraph. + /// + ///\note b.run(s) is just a shortcut of the following code. + ///\code + /// b.init(); + /// for (NodeIt n(gr); n != INVALID; ++n) { + /// if (!b.reached(n)) { + /// b.addSource(n); + /// b.start(); + /// } + /// } + ///\endcode + void run() { + init(); + for (NodeIt n(*G); n != INVALID; ++n) { + if (!reached(n)) { + addSource(n); + start(); + } + } + } + + ///@} + + ///\name Query Functions + ///The results of the BFS algorithm can be obtained using these + ///functions.\n + ///Either \ref run(Node) "run()" or \ref start() should be called + ///before using them. + + ///@{ + + ///The shortest path to the given node. + + ///Returns the shortest path to the given node from the root(s). + /// + ///\warning \c t should be reached from the root(s). + /// + ///\pre Either \ref run(Node) "run()" or \ref init() + ///must be called before using this function. + Path path(Node t) const { return Path(*G, *_pred, t); } + + ///The distance of the given node from the root(s). + + ///Returns the distance of the given node from the root(s). + /// + ///\warning If node \c v is not reached from the root(s), then + ///the return value of this function is undefined. + /// + ///\pre Either \ref run(Node) "run()" or \ref init() + ///must be called before using this function. + int dist(Node v) const { return (*_dist)[v]; } + + ///\brief Returns the 'previous arc' of the shortest path tree for + ///the given node. + /// + ///This function returns the 'previous arc' of the shortest path + ///tree for the node \c v, i.e. it returns the last arc of a + ///shortest path from a root to \c v. It is \c INVALID if \c v + ///is not reached from the root(s) or if \c v is a root. + /// + ///The shortest path tree used here is equal to the shortest path + ///tree used in \ref predNode() and \ref predMap(). + /// + ///\pre Either \ref run(Node) "run()" or \ref init() + ///must be called before using this function. + Arc predArc(Node v) const { return (*_pred)[v];} + + ///\brief Returns the 'previous node' of the shortest path tree for + ///the given node. + /// + ///This function returns the 'previous node' of the shortest path + ///tree for the node \c v, i.e. it returns the last but one node + ///of a shortest path from a root to \c v. It is \c INVALID + ///if \c v is not reached from the root(s) or if \c v is a root. + /// + ///The shortest path tree used here is equal to the shortest path + ///tree used in \ref predArc() and \ref predMap(). + /// + ///\pre Either \ref run(Node) "run()" or \ref init() + ///must be called before using this function. + Node predNode(Node v) const { return (*_pred)[v]==INVALID ? INVALID: + G->source((*_pred)[v]); } + + ///\brief Returns a const reference to the node map that stores the + /// distances of the nodes. + /// + ///Returns a const reference to the node map that stores the distances + ///of the nodes calculated by the algorithm. + /// + ///\pre Either \ref run(Node) "run()" or \ref init() + ///must be called before using this function. + const DistMap &distMap() const { return *_dist;} + + ///\brief Returns a const reference to the node map that stores the + ///predecessor arcs. + /// + ///Returns a const reference to the node map that stores the predecessor + ///arcs, which form the shortest path tree (forest). + /// + ///\pre Either \ref run(Node) "run()" or \ref init() + ///must be called before using this function. + const PredMap &predMap() const { return *_pred;} + + ///Checks if the given node is reached from the root(s). + + ///Returns \c true if \c v is reached from the root(s). + /// + ///\pre Either \ref run(Node) "run()" or \ref init() + ///must be called before using this function. + bool reached(Node v) const { return (*_reached)[v]; } + + ///@} + }; + + ///Default traits class of bfs() function. + + ///Default traits class of bfs() function. + ///\tparam GR Digraph type. + template + struct BfsWizardDefaultTraits + { + ///The type of the digraph the algorithm runs on. + typedef GR Digraph; + + ///\brief The type of the map that stores the predecessor + ///arcs of the shortest paths. + /// + ///The type of the map that stores the predecessor + ///arcs of the shortest paths. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + typedef typename Digraph::template NodeMap PredMap; + ///Instantiates a PredMap. + + ///This function instantiates a PredMap. + ///\param g is the digraph, to which we would like to define the + ///PredMap. + static PredMap *createPredMap(const Digraph &g) + { + return new PredMap(g); + } + + ///The type of the map that indicates which nodes are processed. + + ///The type of the map that indicates which nodes are processed. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + ///By default, it is a NullMap. + typedef NullMap ProcessedMap; + ///Instantiates a ProcessedMap. + + ///This function instantiates a ProcessedMap. + ///\param g is the digraph, to which + ///we would like to define the ProcessedMap. +#ifdef DOXYGEN + static ProcessedMap *createProcessedMap(const Digraph &g) +#else + static ProcessedMap *createProcessedMap(const Digraph &) +#endif + { + return new ProcessedMap(); + } + + ///The type of the map that indicates which nodes are reached. + + ///The type of the map that indicates which nodes are reached. + ///It must conform to + ///the \ref concepts::ReadWriteMap "ReadWriteMap" concept. + typedef typename Digraph::template NodeMap ReachedMap; + ///Instantiates a ReachedMap. + + ///This function instantiates a ReachedMap. + ///\param g is the digraph, to which + ///we would like to define the ReachedMap. + static ReachedMap *createReachedMap(const Digraph &g) + { + return new ReachedMap(g); + } + + ///The type of the map that stores the distances of the nodes. + + ///The type of the map that stores the distances of the nodes. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + typedef typename Digraph::template NodeMap DistMap; + ///Instantiates a DistMap. + + ///This function instantiates a DistMap. + ///\param g is the digraph, to which we would like to define + ///the DistMap + static DistMap *createDistMap(const Digraph &g) + { + return new DistMap(g); + } + + ///The type of the shortest paths. + + ///The type of the shortest paths. + ///It must conform to the \ref concepts::Path "Path" concept. + typedef lemon::Path Path; + }; + + /// Default traits class used by BfsWizard + + /// Default traits class used by BfsWizard. + /// \tparam GR The type of the digraph. + template + class BfsWizardBase : public BfsWizardDefaultTraits + { + + typedef BfsWizardDefaultTraits Base; + protected: + //The type of the nodes in the digraph. + typedef typename Base::Digraph::Node Node; + + //Pointer to the digraph the algorithm runs on. + void *_g; + //Pointer to the map of reached nodes. + void *_reached; + //Pointer to the map of processed nodes. + void *_processed; + //Pointer to the map of predecessors arcs. + void *_pred; + //Pointer to the map of distances. + void *_dist; + //Pointer to the shortest path to the target node. + void *_path; + //Pointer to the distance of the target node. + int *_di; + + public: + /// Constructor. + + /// This constructor does not require parameters, it initiates + /// all of the attributes to \c 0. + BfsWizardBase() : _g(0), _reached(0), _processed(0), _pred(0), + _dist(0), _path(0), _di(0) {} + + /// Constructor. + + /// This constructor requires one parameter, + /// others are initiated to \c 0. + /// \param g The digraph the algorithm runs on. + BfsWizardBase(const GR &g) : + _g(reinterpret_cast(const_cast(&g))), + _reached(0), _processed(0), _pred(0), _dist(0), _path(0), _di(0) {} + + }; + + /// Auxiliary class for the function-type interface of BFS algorithm. + + /// This auxiliary class is created to implement the + /// \ref bfs() "function-type interface" of \ref Bfs algorithm. + /// It does not have own \ref run(Node) "run()" method, it uses the + /// functions and features of the plain \ref Bfs. + /// + /// This class should only be used through the \ref bfs() function, + /// which makes it easier to use the algorithm. + /// + /// \tparam TR The traits class that defines various types used by the + /// algorithm. + template + class BfsWizard : public TR + { + typedef TR Base; + + typedef typename TR::Digraph Digraph; + + typedef typename Digraph::Node Node; + typedef typename Digraph::NodeIt NodeIt; + typedef typename Digraph::Arc Arc; + typedef typename Digraph::OutArcIt OutArcIt; + + typedef typename TR::PredMap PredMap; + typedef typename TR::DistMap DistMap; + typedef typename TR::ReachedMap ReachedMap; + typedef typename TR::ProcessedMap ProcessedMap; + typedef typename TR::Path Path; + + public: + + /// Constructor. + BfsWizard() : TR() {} + + /// Constructor that requires parameters. + + /// Constructor that requires parameters. + /// These parameters will be the default values for the traits class. + /// \param g The digraph the algorithm runs on. + BfsWizard(const Digraph &g) : + TR(g) {} + + ///Copy constructor + BfsWizard(const TR &b) : TR(b) {} + + ~BfsWizard() {} + + ///Runs BFS algorithm from the given source node. + + ///This method runs BFS algorithm from node \c s + ///in order to compute the shortest path to each node. + void run(Node s) + { + Bfs alg(*reinterpret_cast(Base::_g)); + if (Base::_pred) + alg.predMap(*reinterpret_cast(Base::_pred)); + if (Base::_dist) + alg.distMap(*reinterpret_cast(Base::_dist)); + if (Base::_reached) + alg.reachedMap(*reinterpret_cast(Base::_reached)); + if (Base::_processed) + alg.processedMap(*reinterpret_cast(Base::_processed)); + if (s!=INVALID) + alg.run(s); + else + alg.run(); + } + + ///Finds the shortest path between \c s and \c t. + + ///This method runs BFS algorithm from node \c s + ///in order to compute the shortest path to node \c t + ///(it stops searching when \c t is processed). + /// + ///\return \c true if \c t is reachable form \c s. + bool run(Node s, Node t) + { + Bfs alg(*reinterpret_cast(Base::_g)); + if (Base::_pred) + alg.predMap(*reinterpret_cast(Base::_pred)); + if (Base::_dist) + alg.distMap(*reinterpret_cast(Base::_dist)); + if (Base::_reached) + alg.reachedMap(*reinterpret_cast(Base::_reached)); + if (Base::_processed) + alg.processedMap(*reinterpret_cast(Base::_processed)); + alg.run(s,t); + if (Base::_path) + *reinterpret_cast(Base::_path) = alg.path(t); + if (Base::_di) + *Base::_di = alg.dist(t); + return alg.reached(t); + } + + ///Runs BFS algorithm to visit all nodes in the digraph. + + ///This method runs BFS algorithm in order to visit all nodes + ///in the digraph. + void run() + { + run(INVALID); + } + + template + struct SetPredMapBase : public Base { + typedef T PredMap; + static PredMap *createPredMap(const Digraph &) { return 0; }; + SetPredMapBase(const TR &b) : TR(b) {} + }; + + ///\brief \ref named-templ-param "Named parameter" for setting + ///the predecessor map. + /// + ///\ref named-templ-param "Named parameter" function for setting + ///the map that stores the predecessor arcs of the nodes. + template + BfsWizard > predMap(const T &t) + { + Base::_pred=reinterpret_cast(const_cast(&t)); + return BfsWizard >(*this); + } + + template + struct SetReachedMapBase : public Base { + typedef T ReachedMap; + static ReachedMap *createReachedMap(const Digraph &) { return 0; }; + SetReachedMapBase(const TR &b) : TR(b) {} + }; + + ///\brief \ref named-templ-param "Named parameter" for setting + ///the reached map. + /// + ///\ref named-templ-param "Named parameter" function for setting + ///the map that indicates which nodes are reached. + template + BfsWizard > reachedMap(const T &t) + { + Base::_reached=reinterpret_cast(const_cast(&t)); + return BfsWizard >(*this); + } + + template + struct SetDistMapBase : public Base { + typedef T DistMap; + static DistMap *createDistMap(const Digraph &) { return 0; }; + SetDistMapBase(const TR &b) : TR(b) {} + }; + + ///\brief \ref named-templ-param "Named parameter" for setting + ///the distance map. + /// + ///\ref named-templ-param "Named parameter" function for setting + ///the map that stores the distances of the nodes calculated + ///by the algorithm. + template + BfsWizard > distMap(const T &t) + { + Base::_dist=reinterpret_cast(const_cast(&t)); + return BfsWizard >(*this); + } + + template + struct SetProcessedMapBase : public Base { + typedef T ProcessedMap; + static ProcessedMap *createProcessedMap(const Digraph &) { return 0; }; + SetProcessedMapBase(const TR &b) : TR(b) {} + }; + + ///\brief \ref named-func-param "Named parameter" for setting + ///the processed map. + /// + ///\ref named-templ-param "Named parameter" function for setting + ///the map that indicates which nodes are processed. + template + BfsWizard > processedMap(const T &t) + { + Base::_processed=reinterpret_cast(const_cast(&t)); + return BfsWizard >(*this); + } + + template + struct SetPathBase : public Base { + typedef T Path; + SetPathBase(const TR &b) : TR(b) {} + }; + ///\brief \ref named-func-param "Named parameter" + ///for getting the shortest path to the target node. + /// + ///\ref named-func-param "Named parameter" + ///for getting the shortest path to the target node. + template + BfsWizard > path(const T &t) + { + Base::_path=reinterpret_cast(const_cast(&t)); + return BfsWizard >(*this); + } + + ///\brief \ref named-func-param "Named parameter" + ///for getting the distance of the target node. + /// + ///\ref named-func-param "Named parameter" + ///for getting the distance of the target node. + BfsWizard dist(const int &d) + { + Base::_di=const_cast(&d); + return *this; + } + + }; + + ///Function-type interface for BFS algorithm. + + /// \ingroup search + ///Function-type interface for BFS algorithm. + /// + ///This function also has several \ref named-func-param "named parameters", + ///they are declared as the members of class \ref BfsWizard. + ///The following examples show how to use these parameters. + ///\code + /// // Compute shortest path from node s to each node + /// bfs(g).predMap(preds).distMap(dists).run(s); + /// + /// // Compute shortest path from s to t + /// bool reached = bfs(g).path(p).dist(d).run(s,t); + ///\endcode + ///\warning Don't forget to put the \ref BfsWizard::run(Node) "run()" + ///to the end of the parameter list. + ///\sa BfsWizard + ///\sa Bfs + template + BfsWizard > + bfs(const GR &digraph) + { + return BfsWizard >(digraph); + } + +#ifdef DOXYGEN + /// \brief Visitor class for BFS. + /// + /// This class defines the interface of the BfsVisit events, and + /// it could be the base of a real visitor class. + template + struct BfsVisitor { + typedef GR Digraph; + typedef typename Digraph::Arc Arc; + typedef typename Digraph::Node Node; + /// \brief Called for the source node(s) of the BFS. + /// + /// This function is called for the source node(s) of the BFS. + void start(const Node& node) {} + /// \brief Called when a node is reached first time. + /// + /// This function is called when a node is reached first time. + void reach(const Node& node) {} + /// \brief Called when a node is processed. + /// + /// This function is called when a node is processed. + void process(const Node& node) {} + /// \brief Called when an arc reaches a new node. + /// + /// This function is called when the BFS finds an arc whose target node + /// is not reached yet. + void discover(const Arc& arc) {} + /// \brief Called when an arc is examined but its target node is + /// already discovered. + /// + /// This function is called when an arc is examined but its target node is + /// already discovered. + void examine(const Arc& arc) {} + }; +#else + template + struct BfsVisitor { + typedef GR Digraph; + typedef typename Digraph::Arc Arc; + typedef typename Digraph::Node Node; + void start(const Node&) {} + void reach(const Node&) {} + void process(const Node&) {} + void discover(const Arc&) {} + void examine(const Arc&) {} + + template + struct Constraints { + void constraints() { + Arc arc; + Node node; + visitor.start(node); + visitor.reach(node); + visitor.process(node); + visitor.discover(arc); + visitor.examine(arc); + } + _Visitor& visitor; + Constraints() {} + }; + }; +#endif + + /// \brief Default traits class of BfsVisit class. + /// + /// Default traits class of BfsVisit class. + /// \tparam GR The type of the digraph the algorithm runs on. + template + struct BfsVisitDefaultTraits { + + /// \brief The type of the digraph the algorithm runs on. + typedef GR Digraph; + + /// \brief The type of the map that indicates which nodes are reached. + /// + /// The type of the map that indicates which nodes are reached. + /// It must conform to + ///the \ref concepts::ReadWriteMap "ReadWriteMap" concept. + typedef typename Digraph::template NodeMap ReachedMap; + + /// \brief Instantiates a ReachedMap. + /// + /// This function instantiates a ReachedMap. + /// \param digraph is the digraph, to which + /// we would like to define the ReachedMap. + static ReachedMap *createReachedMap(const Digraph &digraph) { + return new ReachedMap(digraph); + } + + }; + + /// \ingroup search + /// + /// \brief BFS algorithm class with visitor interface. + /// + /// This class provides an efficient implementation of the BFS algorithm + /// with visitor interface. + /// + /// The BfsVisit class provides an alternative interface to the Bfs + /// class. It works with callback mechanism, the BfsVisit object calls + /// the member functions of the \c Visitor class on every BFS event. + /// + /// This interface of the BFS algorithm should be used in special cases + /// when extra actions have to be performed in connection with certain + /// events of the BFS algorithm. Otherwise consider to use Bfs or bfs() + /// instead. + /// + /// \tparam GR The type of the digraph the algorithm runs on. + /// The default type is \ref ListDigraph. + /// The value of GR is not used directly by \ref BfsVisit, + /// it is only passed to \ref BfsVisitDefaultTraits. + /// \tparam VS The Visitor type that is used by the algorithm. + /// \ref BfsVisitor "BfsVisitor" is an empty visitor, which + /// does not observe the BFS events. If you want to observe the BFS + /// events, you should implement your own visitor class. + /// \tparam TR The traits class that defines various types used by the + /// algorithm. By default, it is \ref BfsVisitDefaultTraits + /// "BfsVisitDefaultTraits". + /// In most cases, this parameter should not be set directly, + /// consider to use the named template parameters instead. +#ifdef DOXYGEN + template +#else + template , + typename TR = BfsVisitDefaultTraits > +#endif + class BfsVisit { + public: + + ///The traits class. + typedef TR Traits; + + ///The type of the digraph the algorithm runs on. + typedef typename Traits::Digraph Digraph; + + ///The visitor type used by the algorithm. + typedef VS Visitor; + + ///The type of the map that indicates which nodes are reached. + typedef typename Traits::ReachedMap ReachedMap; + + private: + + typedef typename Digraph::Node Node; + typedef typename Digraph::NodeIt NodeIt; + typedef typename Digraph::Arc Arc; + typedef typename Digraph::OutArcIt OutArcIt; + + //Pointer to the underlying digraph. + const Digraph *_digraph; + //Pointer to the visitor object. + Visitor *_visitor; + //Pointer to the map of reached status of the nodes. + ReachedMap *_reached; + //Indicates if _reached is locally allocated (true) or not. + bool local_reached; + + std::vector _list; + int _list_front, _list_back; + + //Creates the maps if necessary. + void create_maps() { + if(!_reached) { + local_reached = true; + _reached = Traits::createReachedMap(*_digraph); + } + } + + protected: + + BfsVisit() {} + + public: + + typedef BfsVisit Create; + + /// \name Named Template Parameters + + ///@{ + template + struct SetReachedMapTraits : public Traits { + typedef T ReachedMap; + static ReachedMap *createReachedMap(const Digraph &digraph) { + LEMON_ASSERT(false, "ReachedMap is not initialized"); + return 0; // ignore warnings + } + }; + /// \brief \ref named-templ-param "Named parameter" for setting + /// ReachedMap type. + /// + /// \ref named-templ-param "Named parameter" for setting ReachedMap type. + template + struct SetReachedMap : public BfsVisit< Digraph, Visitor, + SetReachedMapTraits > { + typedef BfsVisit< Digraph, Visitor, SetReachedMapTraits > Create; + }; + ///@} + + public: + + /// \brief Constructor. + /// + /// Constructor. + /// + /// \param digraph The digraph the algorithm runs on. + /// \param visitor The visitor object of the algorithm. + BfsVisit(const Digraph& digraph, Visitor& visitor) + : _digraph(&digraph), _visitor(&visitor), + _reached(0), local_reached(false) {} + + /// \brief Destructor. + ~BfsVisit() { + if(local_reached) delete _reached; + } + + /// \brief Sets the map that indicates which nodes are reached. + /// + /// Sets the map that indicates which nodes are reached. + /// If you don't use this function before calling \ref run(Node) "run()" + /// or \ref init(), an instance will be allocated automatically. + /// The destructor deallocates this automatically allocated map, + /// of course. + /// \return (*this) + BfsVisit &reachedMap(ReachedMap &m) { + if(local_reached) { + delete _reached; + local_reached = false; + } + _reached = &m; + return *this; + } + + public: + + /// \name Execution Control + /// The simplest way to execute the BFS algorithm is to use one of the + /// member functions called \ref run(Node) "run()".\n + /// If you need better control on the execution, you have to call + /// \ref init() first, then you can add several source nodes with + /// \ref addSource(). Finally the actual path computation can be + /// performed with one of the \ref start() functions. + + /// @{ + + /// \brief Initializes the internal data structures. + /// + /// Initializes the internal data structures. + void init() { + create_maps(); + _list.resize(countNodes(*_digraph)); + _list_front = _list_back = -1; + for (NodeIt u(*_digraph) ; u != INVALID ; ++u) { + _reached->set(u, false); + } + } + + /// \brief Adds a new source node. + /// + /// Adds a new source node to the set of nodes to be processed. + void addSource(Node s) { + if(!(*_reached)[s]) { + _reached->set(s,true); + _visitor->start(s); + _visitor->reach(s); + _list[++_list_back] = s; + } + } + + /// \brief Processes the next node. + /// + /// Processes the next node. + /// + /// \return The processed node. + /// + /// \pre The queue must not be empty. + Node processNextNode() { + Node n = _list[++_list_front]; + _visitor->process(n); + Arc e; + for (_digraph->firstOut(e, n); e != INVALID; _digraph->nextOut(e)) { + Node m = _digraph->target(e); + if (!(*_reached)[m]) { + _visitor->discover(e); + _visitor->reach(m); + _reached->set(m, true); + _list[++_list_back] = m; + } else { + _visitor->examine(e); + } + } + return n; + } + + /// \brief Processes the next node. + /// + /// Processes the next node and checks if the given target node + /// is reached. If the target node is reachable from the processed + /// node, then the \c reach parameter will be set to \c true. + /// + /// \param target The target node. + /// \retval reach Indicates if the target node is reached. + /// It should be initially \c false. + /// + /// \return The processed node. + /// + /// \pre The queue must not be empty. + Node processNextNode(Node target, bool& reach) { + Node n = _list[++_list_front]; + _visitor->process(n); + Arc e; + for (_digraph->firstOut(e, n); e != INVALID; _digraph->nextOut(e)) { + Node m = _digraph->target(e); + if (!(*_reached)[m]) { + _visitor->discover(e); + _visitor->reach(m); + _reached->set(m, true); + _list[++_list_back] = m; + reach = reach || (target == m); + } else { + _visitor->examine(e); + } + } + return n; + } + + /// \brief Processes the next node. + /// + /// Processes the next node and checks if at least one of reached + /// nodes has \c true value in the \c nm node map. If one node + /// with \c true value is reachable from the processed node, then the + /// \c rnode parameter will be set to the first of such nodes. + /// + /// \param nm A \c bool (or convertible) node map that indicates the + /// possible targets. + /// \retval rnode The reached target node. + /// It should be initially \c INVALID. + /// + /// \return The processed node. + /// + /// \pre The queue must not be empty. + template + Node processNextNode(const NM& nm, Node& rnode) { + Node n = _list[++_list_front]; + _visitor->process(n); + Arc e; + for (_digraph->firstOut(e, n); e != INVALID; _digraph->nextOut(e)) { + Node m = _digraph->target(e); + if (!(*_reached)[m]) { + _visitor->discover(e); + _visitor->reach(m); + _reached->set(m, true); + _list[++_list_back] = m; + if (nm[m] && rnode == INVALID) rnode = m; + } else { + _visitor->examine(e); + } + } + return n; + } + + /// \brief The next node to be processed. + /// + /// Returns the next node to be processed or \c INVALID if the queue + /// is empty. + Node nextNode() const { + return _list_front != _list_back ? _list[_list_front + 1] : INVALID; + } + + /// \brief Returns \c false if there are nodes + /// to be processed. + /// + /// Returns \c false if there are nodes + /// to be processed in the queue. + bool emptyQueue() const { return _list_front == _list_back; } + + /// \brief Returns the number of the nodes to be processed. + /// + /// Returns the number of the nodes to be processed in the queue. + int queueSize() const { return _list_back - _list_front; } + + /// \brief Executes the algorithm. + /// + /// Executes the algorithm. + /// + /// This method runs the %BFS algorithm from the root node(s) + /// in order to compute the shortest path to each node. + /// + /// The algorithm computes + /// - the shortest path tree (forest), + /// - the distance of each node from the root(s). + /// + /// \pre init() must be called and at least one root node should be added + /// with addSource() before using this function. + /// + /// \note b.start() is just a shortcut of the following code. + /// \code + /// while ( !b.emptyQueue() ) { + /// b.processNextNode(); + /// } + /// \endcode + void start() { + while ( !emptyQueue() ) processNextNode(); + } + + /// \brief Executes the algorithm until the given target node is reached. + /// + /// Executes the algorithm until the given target node is reached. + /// + /// This method runs the %BFS algorithm from the root node(s) + /// in order to compute the shortest path to \c t. + /// + /// The algorithm computes + /// - the shortest path to \c t, + /// - the distance of \c t from the root(s). + /// + /// \pre init() must be called and at least one root node should be + /// added with addSource() before using this function. + /// + /// \note b.start(t) is just a shortcut of the following code. + /// \code + /// bool reach = false; + /// while ( !b.emptyQueue() && !reach ) { + /// b.processNextNode(t, reach); + /// } + /// \endcode + void start(Node t) { + bool reach = false; + while ( !emptyQueue() && !reach ) processNextNode(t, reach); + } + + /// \brief Executes the algorithm until a condition is met. + /// + /// Executes the algorithm until a condition is met. + /// + /// This method runs the %BFS algorithm from the root node(s) in + /// order to compute the shortest path to a node \c v with + /// nm[v] true, if such a node can be found. + /// + /// \param nm must be a bool (or convertible) node map. The + /// algorithm will stop when it reaches a node \c v with + /// nm[v] true. + /// + /// \return The reached node \c v with nm[v] true or + /// \c INVALID if no such node was found. + /// + /// \pre init() must be called and at least one root node should be + /// added with addSource() before using this function. + /// + /// \note b.start(nm) is just a shortcut of the following code. + /// \code + /// Node rnode = INVALID; + /// while ( !b.emptyQueue() && rnode == INVALID ) { + /// b.processNextNode(nm, rnode); + /// } + /// return rnode; + /// \endcode + template + Node start(const NM &nm) { + Node rnode = INVALID; + while ( !emptyQueue() && rnode == INVALID ) { + processNextNode(nm, rnode); + } + return rnode; + } + + /// \brief Runs the algorithm from the given source node. + /// + /// This method runs the %BFS algorithm from node \c s + /// in order to compute the shortest path to each node. + /// + /// The algorithm computes + /// - the shortest path tree, + /// - the distance of each node from the root. + /// + /// \note b.run(s) is just a shortcut of the following code. + ///\code + /// b.init(); + /// b.addSource(s); + /// b.start(); + ///\endcode + void run(Node s) { + init(); + addSource(s); + start(); + } + + /// \brief Finds the shortest path between \c s and \c t. + /// + /// This method runs the %BFS algorithm from node \c s + /// in order to compute the shortest path to node \c t + /// (it stops searching when \c t is processed). + /// + /// \return \c true if \c t is reachable form \c s. + /// + /// \note Apart from the return value, b.run(s,t) is just a + /// shortcut of the following code. + ///\code + /// b.init(); + /// b.addSource(s); + /// b.start(t); + ///\endcode + bool run(Node s,Node t) { + init(); + addSource(s); + start(t); + return reached(t); + } + + /// \brief Runs the algorithm to visit all nodes in the digraph. + /// + /// This method runs the %BFS algorithm in order to visit all nodes + /// in the digraph. + /// + /// \note b.run(s) is just a shortcut of the following code. + ///\code + /// b.init(); + /// for (NodeIt n(gr); n != INVALID; ++n) { + /// if (!b.reached(n)) { + /// b.addSource(n); + /// b.start(); + /// } + /// } + ///\endcode + void run() { + init(); + for (NodeIt it(*_digraph); it != INVALID; ++it) { + if (!reached(it)) { + addSource(it); + start(); + } + } + } + + ///@} + + /// \name Query Functions + /// The results of the BFS algorithm can be obtained using these + /// functions.\n + /// Either \ref run(Node) "run()" or \ref start() should be called + /// before using them. + + ///@{ + + /// \brief Checks if the given node is reached from the root(s). + /// + /// Returns \c true if \c v is reached from the root(s). + /// + /// \pre Either \ref run(Node) "run()" or \ref init() + /// must be called before using this function. + bool reached(Node v) const { return (*_reached)[v]; } + + ///@} + + }; + +} //END OF NAMESPACE LEMON + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bin_heap.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bin_heap.h new file mode 100644 index 00000000000..02c66582210 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bin_heap.h @@ -0,0 +1,347 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_BIN_HEAP_H +#define LEMON_BIN_HEAP_H + +///\ingroup heaps +///\file +///\brief Binary heap implementation. + +#include +#include +#include + +namespace lemon { + + /// \ingroup heaps + /// + /// \brief Binary heap data structure. + /// + /// This class implements the \e binary \e heap data structure. + /// It fully conforms to the \ref concepts::Heap "heap concept". + /// + /// \tparam PR Type of the priorities of the items. + /// \tparam IM A read-writable item map with \c int values, used + /// internally to handle the cross references. + /// \tparam CMP A functor class for comparing the priorities. + /// The default is \c std::less. +#ifdef DOXYGEN + template +#else + template > +#endif + class BinHeap { + public: + + /// Type of the item-int map. + typedef IM ItemIntMap; + /// Type of the priorities. + typedef PR Prio; + /// Type of the items stored in the heap. + typedef typename ItemIntMap::Key Item; + /// Type of the item-priority pairs. + typedef std::pair Pair; + /// Functor type for comparing the priorities. + typedef CMP Compare; + + /// \brief Type to represent the states of the items. + /// + /// Each item has a state associated to it. It can be "in heap", + /// "pre-heap" or "post-heap". The latter two are indifferent from the + /// heap's point of view, but may be useful to the user. + /// + /// The item-int map must be initialized in such way that it assigns + /// \c PRE_HEAP (-1) to any element to be put in the heap. + enum State { + IN_HEAP = 0, ///< = 0. + PRE_HEAP = -1, ///< = -1. + POST_HEAP = -2 ///< = -2. + }; + + private: + std::vector _data; + Compare _comp; + ItemIntMap &_iim; + + public: + + /// \brief Constructor. + /// + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. + explicit BinHeap(ItemIntMap &map) : _iim(map) {} + + /// \brief Constructor. + /// + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. + /// \param comp The function object used for comparing the priorities. + BinHeap(ItemIntMap &map, const Compare &comp) + : _iim(map), _comp(comp) {} + + + /// \brief The number of items stored in the heap. + /// + /// This function returns the number of items stored in the heap. + int size() const { return _data.size(); } + + /// \brief Check if the heap is empty. + /// + /// This function returns \c true if the heap is empty. + bool empty() const { return _data.empty(); } + + /// \brief Make the heap empty. + /// + /// This functon makes the heap empty. + /// It does not change the cross reference map. If you want to reuse + /// a heap that is not surely empty, you should first clear it and + /// then you should set the cross reference map to \c PRE_HEAP + /// for each item. + void clear() { + _data.clear(); + } + + private: + static int parent(int i) { return (i-1)/2; } + + static int secondChild(int i) { return 2*i+2; } + bool less(const Pair &p1, const Pair &p2) const { + return _comp(p1.second, p2.second); + } + + int bubbleUp(int hole, Pair p) { + int par = parent(hole); + while( hole>0 && less(p,_data[par]) ) { + move(_data[par],hole); + hole = par; + par = parent(hole); + } + move(p, hole); + return hole; + } + + int bubbleDown(int hole, Pair p, int length) { + int child = secondChild(hole); + while(child < length) { + if( less(_data[child-1], _data[child]) ) { + --child; + } + if( !less(_data[child], p) ) + goto ok; + move(_data[child], hole); + hole = child; + child = secondChild(hole); + } + child--; + if( child 0) { + bubbleDown(0, _data[n], n); + } + _data.pop_back(); + } + + /// \brief Remove the given item from the heap. + /// + /// This function removes the given item from the heap if it is + /// already stored. + /// \param i The item to delete. + /// \pre \e i must be in the heap. + void erase(const Item &i) { + int h = _iim[i]; + int n = _data.size()-1; + _iim.set(_data[h].first, POST_HEAP); + if( h < n ) { + if ( bubbleUp(h, _data[n]) == h) { + bubbleDown(h, _data[n], n); + } + } + _data.pop_back(); + } + + /// \brief The priority of the given item. + /// + /// This function returns the priority of the given item. + /// \param i The item. + /// \pre \e i must be in the heap. + Prio operator[](const Item &i) const { + int idx = _iim[i]; + return _data[idx].second; + } + + /// \brief Set the priority of an item or insert it, if it is + /// not stored in the heap. + /// + /// This method sets the priority of the given item if it is + /// already stored in the heap. Otherwise it inserts the given + /// item into the heap with the given priority. + /// \param i The item. + /// \param p The priority. + void set(const Item &i, const Prio &p) { + int idx = _iim[i]; + if( idx < 0 ) { + push(i,p); + } + else if( _comp(p, _data[idx].second) ) { + bubbleUp(idx, Pair(i,p)); + } + else { + bubbleDown(idx, Pair(i,p), _data.size()); + } + } + + /// \brief Decrease the priority of an item to the given value. + /// + /// This function decreases the priority of an item to the given value. + /// \param i The item. + /// \param p The priority. + /// \pre \e i must be stored in the heap with priority at least \e p. + void decrease(const Item &i, const Prio &p) { + int idx = _iim[i]; + bubbleUp(idx, Pair(i,p)); + } + + /// \brief Increase the priority of an item to the given value. + /// + /// This function increases the priority of an item to the given value. + /// \param i The item. + /// \param p The priority. + /// \pre \e i must be stored in the heap with priority at most \e p. + void increase(const Item &i, const Prio &p) { + int idx = _iim[i]; + bubbleDown(idx, Pair(i,p), _data.size()); + } + + /// \brief Return the state of an item. + /// + /// This method returns \c PRE_HEAP if the given item has never + /// been in the heap, \c IN_HEAP if it is in the heap at the moment, + /// and \c POST_HEAP otherwise. + /// In the latter case it is possible that the item will get back + /// to the heap again. + /// \param i The item. + State state(const Item &i) const { + int s = _iim[i]; + if( s>=0 ) + s=0; + return State(s); + } + + /// \brief Set the state of an item in the heap. + /// + /// This function sets the state of the given item in the heap. + /// It can be used to manually clear the heap when it is important + /// to achive better time complexity. + /// \param i The item. + /// \param st The state. It should not be \c IN_HEAP. + void state(const Item& i, State st) { + switch (st) { + case POST_HEAP: + case PRE_HEAP: + if (state(i) == IN_HEAP) { + erase(i); + } + _iim[i] = st; + break; + case IN_HEAP: + break; + } + } + + /// \brief Replace an item in the heap. + /// + /// This function replaces item \c i with item \c j. + /// Item \c i must be in the heap, while \c j must be out of the heap. + /// After calling this method, item \c i will be out of the + /// heap and \c j will be in the heap with the same prioriority + /// as item \c i had before. + void replace(const Item& i, const Item& j) { + int idx = _iim[i]; + _iim.set(i, _iim[j]); + _iim.set(j, idx); + _data[idx].first = j; + } + + }; // class BinHeap + +} // namespace lemon + +#endif // LEMON_BIN_HEAP_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/binomial_heap.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/binomial_heap.h new file mode 100644 index 00000000000..5bc13787058 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/binomial_heap.h @@ -0,0 +1,445 @@ +/* -*- 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_BINOMIAL_HEAP_H +#define LEMON_BINOMIAL_HEAP_H + +///\file +///\ingroup heaps +///\brief Binomial Heap implementation. + +#include +#include +#include +#include +#include + +namespace lemon { + + /// \ingroup heaps + /// + ///\brief Binomial heap data structure. + /// + /// This class implements the \e binomial \e heap data structure. + /// It fully conforms to the \ref concepts::Heap "heap concept". + /// + /// The methods \ref increase() and \ref erase() are not efficient + /// in a binomial heap. In case of many calls of these operations, + /// it is better to use other heap structure, e.g. \ref BinHeap + /// "binary heap". + /// + /// \tparam PR Type of the priorities of the items. + /// \tparam IM A read-writable item map with \c int values, used + /// internally to handle the cross references. + /// \tparam CMP A functor class for comparing the priorities. + /// The default is \c std::less. +#ifdef DOXYGEN + template +#else + template > +#endif + class BinomialHeap { + public: + /// Type of the item-int map. + typedef IM ItemIntMap; + /// Type of the priorities. + typedef PR Prio; + /// Type of the items stored in the heap. + typedef typename ItemIntMap::Key Item; + /// Functor type for comparing the priorities. + typedef CMP Compare; + + /// \brief Type to represent the states of the items. + /// + /// Each item has a state associated to it. It can be "in heap", + /// "pre-heap" or "post-heap". The latter two are indifferent from the + /// heap's point of view, but may be useful to the user. + /// + /// The item-int map must be initialized in such way that it assigns + /// \c PRE_HEAP (-1) to any element to be put in the heap. + enum State { + IN_HEAP = 0, ///< = 0. + PRE_HEAP = -1, ///< = -1. + POST_HEAP = -2 ///< = -2. + }; + + private: + class Store; + + std::vector _data; + int _min, _head; + ItemIntMap &_iim; + Compare _comp; + int _num_items; + + public: + /// \brief Constructor. + /// + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. + explicit BinomialHeap(ItemIntMap &map) + : _min(0), _head(-1), _iim(map), _num_items(0) {} + + /// \brief Constructor. + /// + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. + /// \param comp The function object used for comparing the priorities. + BinomialHeap(ItemIntMap &map, const Compare &comp) + : _min(0), _head(-1), _iim(map), _comp(comp), _num_items(0) {} + + /// \brief The number of items stored in the heap. + /// + /// This function returns the number of items stored in the heap. + int size() const { return _num_items; } + + /// \brief Check if the heap is empty. + /// + /// This function returns \c true if the heap is empty. + bool empty() const { return _num_items==0; } + + /// \brief Make the heap empty. + /// + /// This functon makes the heap empty. + /// It does not change the cross reference map. If you want to reuse + /// a heap that is not surely empty, you should first clear it and + /// then you should set the cross reference map to \c PRE_HEAP + /// for each item. + void clear() { + _data.clear(); _min=0; _num_items=0; _head=-1; + } + + /// \brief Set the priority of an item or insert it, if it is + /// not stored in the heap. + /// + /// This method sets the priority of the given item if it is + /// already stored in the heap. Otherwise it inserts the given + /// item into the heap with the given priority. + /// \param item The item. + /// \param value The priority. + void set (const Item& item, const Prio& value) { + int i=_iim[item]; + if ( i >= 0 && _data[i].in ) { + if ( _comp(value, _data[i].prio) ) decrease(item, value); + if ( _comp(_data[i].prio, value) ) increase(item, value); + } else push(item, value); + } + + /// \brief Insert an item into the heap with the given priority. + /// + /// This function inserts the given item into the heap with the + /// given priority. + /// \param item The item to insert. + /// \param value The priority of the item. + /// \pre \e item must not be stored in the heap. + void push (const Item& item, const Prio& value) { + int i=_iim[item]; + if ( i<0 ) { + int s=_data.size(); + _iim.set( item,s ); + Store st; + st.name=item; + st.prio=value; + _data.push_back(st); + i=s; + } + else { + _data[i].parent=_data[i].right_neighbor=_data[i].child=-1; + _data[i].degree=0; + _data[i].in=true; + _data[i].prio=value; + } + + if( 0==_num_items ) { + _head=i; + _min=i; + } else { + merge(i); + if( _comp(_data[i].prio, _data[_min].prio) ) _min=i; + } + ++_num_items; + } + + /// \brief Return the item having minimum priority. + /// + /// This function returns the item having minimum priority. + /// \pre The heap must be non-empty. + Item top() const { return _data[_min].name; } + + /// \brief The minimum priority. + /// + /// This function returns the minimum priority. + /// \pre The heap must be non-empty. + Prio prio() const { return _data[_min].prio; } + + /// \brief The priority of the given item. + /// + /// This function returns the priority of the given item. + /// \param item The item. + /// \pre \e item must be in the heap. + const Prio& operator[](const Item& item) const { + return _data[_iim[item]].prio; + } + + /// \brief Remove the item having minimum priority. + /// + /// This function removes the item having minimum priority. + /// \pre The heap must be non-empty. + void pop() { + _data[_min].in=false; + + int head_child=-1; + if ( _data[_min].child!=-1 ) { + int child=_data[_min].child; + int neighb; + while( child!=-1 ) { + neighb=_data[child].right_neighbor; + _data[child].parent=-1; + _data[child].right_neighbor=head_child; + head_child=child; + child=neighb; + } + } + + if ( _data[_head].right_neighbor==-1 ) { + // there was only one root + _head=head_child; + } + else { + // there were more roots + if( _head!=_min ) { unlace(_min); } + else { _head=_data[_head].right_neighbor; } + merge(head_child); + } + _min=findMin(); + --_num_items; + } + + /// \brief Remove the given item from the heap. + /// + /// This function removes the given item from the heap if it is + /// already stored. + /// \param item The item to delete. + /// \pre \e item must be in the heap. + void erase (const Item& item) { + int i=_iim[item]; + if ( i >= 0 && _data[i].in ) { + decrease( item, _data[_min].prio-1 ); + pop(); + } + } + + /// \brief Decrease the priority of an item to the given value. + /// + /// This function decreases the priority of an item to the given value. + /// \param item The item. + /// \param value The priority. + /// \pre \e item must be stored in the heap with priority at least \e value. + void decrease (Item item, const Prio& value) { + int i=_iim[item]; + int p=_data[i].parent; + _data[i].prio=value; + + while( p!=-1 && _comp(value, _data[p].prio) ) { + _data[i].name=_data[p].name; + _data[i].prio=_data[p].prio; + _data[p].name=item; + _data[p].prio=value; + _iim[_data[i].name]=i; + i=p; + p=_data[p].parent; + } + _iim[item]=i; + if ( _comp(value, _data[_min].prio) ) _min=i; + } + + /// \brief Increase the priority of an item to the given value. + /// + /// This function increases the priority of an item to the given value. + /// \param item The item. + /// \param value The priority. + /// \pre \e item must be stored in the heap with priority at most \e value. + void increase (Item item, const Prio& value) { + erase(item); + push(item, value); + } + + /// \brief Return the state of an item. + /// + /// This method returns \c PRE_HEAP if the given item has never + /// been in the heap, \c IN_HEAP if it is in the heap at the moment, + /// and \c POST_HEAP otherwise. + /// In the latter case it is possible that the item will get back + /// to the heap again. + /// \param item The item. + State state(const Item &item) const { + int i=_iim[item]; + if( i>=0 ) { + if ( _data[i].in ) i=0; + else i=-2; + } + return State(i); + } + + /// \brief Set the state of an item in the heap. + /// + /// This function sets the state of the given item in the heap. + /// It can be used to manually clear the heap when it is important + /// to achive better time complexity. + /// \param i The item. + /// \param st The state. It should not be \c IN_HEAP. + void state(const Item& i, State st) { + switch (st) { + case POST_HEAP: + case PRE_HEAP: + if (state(i) == IN_HEAP) { + erase(i); + } + _iim[i] = st; + break; + case IN_HEAP: + break; + } + } + + private: + + // Find the minimum of the roots + int findMin() { + if( _head!=-1 ) { + int min_loc=_head, min_val=_data[_head].prio; + for( int x=_data[_head].right_neighbor; x!=-1; + x=_data[x].right_neighbor ) { + if( _comp( _data[x].prio,min_val ) ) { + min_val=_data[x].prio; + min_loc=x; + } + } + return min_loc; + } + else return -1; + } + + // Merge the heap with another heap starting at the given position + void merge(int a) { + if( _head==-1 || a==-1 ) return; + if( _data[a].right_neighbor==-1 && + _data[a].degree<=_data[_head].degree ) { + _data[a].right_neighbor=_head; + _head=a; + } else { + interleave(a); + } + if( _data[_head].right_neighbor==-1 ) return; + + int x=_head; + int x_prev=-1, x_next=_data[x].right_neighbor; + while( x_next!=-1 ) { + if( _data[x].degree!=_data[x_next].degree || + ( _data[x_next].right_neighbor!=-1 && + _data[_data[x_next].right_neighbor].degree==_data[x].degree ) ) { + x_prev=x; + x=x_next; + } + else { + if( _comp(_data[x_next].prio,_data[x].prio) ) { + if( x_prev==-1 ) { + _head=x_next; + } else { + _data[x_prev].right_neighbor=x_next; + } + fuse(x,x_next); + x=x_next; + } + else { + _data[x].right_neighbor=_data[x_next].right_neighbor; + fuse(x_next,x); + } + } + x_next=_data[x].right_neighbor; + } + } + + // Interleave the elements of the given list into the list of the roots + void interleave(int a) { + int p=_head, q=a; + int curr=_data.size(); + _data.push_back(Store()); + + while( p!=-1 || q!=-1 ) { + if( q==-1 || ( p!=-1 && _data[p].degree<_data[q].degree ) ) { + _data[curr].right_neighbor=p; + curr=p; + p=_data[p].right_neighbor; + } + else { + _data[curr].right_neighbor=q; + curr=q; + q=_data[q].right_neighbor; + } + } + + _head=_data.back().right_neighbor; + _data.pop_back(); + } + + // Lace node a under node b + void fuse(int a, int b) { + _data[a].parent=b; + _data[a].right_neighbor=_data[b].child; + _data[b].child=a; + + ++_data[b].degree; + } + + // Unlace node a (if it has siblings) + void unlace(int a) { + int neighb=_data[a].right_neighbor; + int other=_head; + + while( _data[other].right_neighbor!=a ) + other=_data[other].right_neighbor; + _data[other].right_neighbor=neighb; + } + + private: + + class Store { + friend class BinomialHeap; + + Item name; + int parent; + int right_neighbor; + int child; + int degree; + bool in; + Prio prio; + + Store() : parent(-1), right_neighbor(-1), child(-1), degree(0), + in(true) {} + }; + }; + +} //namespace lemon + +#endif //LEMON_BINOMIAL_HEAP_H + diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/alteration_notifier.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/alteration_notifier.h new file mode 100644 index 00000000000..d14fe3634dd --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/alteration_notifier.h @@ -0,0 +1,472 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_BITS_ALTERATION_NOTIFIER_H +#define LEMON_BITS_ALTERATION_NOTIFIER_H + +#include +#include + +#include +#include + +//\ingroup graphbits +//\file +//\brief Observer notifier for graph alteration observers. + +namespace lemon { + + // \ingroup graphbits + // + // \brief Notifier class to notify observes about alterations in + // a container. + // + // The simple graphs can be refered as two containers: a node container + // and an edge container. But they do not store values directly, they + // are just key continars for more value containers, which are the + // node and edge maps. + // + // The node and edge sets of the graphs can be changed as we add or erase + // nodes and edges in the graph. LEMON would like to handle easily + // that the node and edge maps should contain values for all nodes or + // edges. If we want to check on every indicing if the map contains + // the current indicing key that cause a drawback in the performance + // in the library. We use another solution: we notify all maps about + // an alteration in the graph, which cause only drawback on the + // alteration of the graph. + // + // This class provides an interface to a node or edge container. + // The first() and next() member functions make possible + // to iterate on the keys of the container. + // The id() function returns an integer id for each key. + // The maxId() function gives back an upper bound of the ids. + // + // For the proper functonality of this class, we should notify it + // about each alteration in the container. The alterations have four type: + // add(), erase(), build() and clear(). The add() and + // erase() signal that only one or few items added or erased to or + // from the graph. If all items are erased from the graph or if a new graph + // is built from an empty graph, then it can be signaled with the + // clear() and build() members. Important rule that if we erase items + // from graphs we should first signal the alteration and after that erase + // them from the container, on the other way on item addition we should + // first extend the container and just after that signal the alteration. + // + // The alteration can be observed with a class inherited from the + // ObserverBase nested class. The signals can be handled with + // overriding the virtual functions defined in the base class. The + // observer base can be attached to the notifier with the + // attach() member and can be detached with detach() function. The + // alteration handlers should not call any function which signals + // an other alteration in the same notifier and should not + // detach any observer from the notifier. + // + // Alteration observers try to be exception safe. If an add() or + // a clear() function throws an exception then the remaining + // observeres will not be notified and the fulfilled additions will + // be rolled back by calling the erase() or clear() functions. + // Hence erase() and clear() should not throw exception. + // Actullay, they can throw only \ref ImmediateDetach exception, + // which detach the observer from the notifier. + // + // There are some cases, when the alteration observing is not completly + // reliable. If we want to carry out the node degree in the graph + // as in the \ref InDegMap and we use the reverseArc(), then it cause + // unreliable functionality. Because the alteration observing signals + // only erasing and adding but not the reversing, it will stores bad + // degrees. Apart form that the subgraph adaptors cannot even signal + // the alterations because just a setting in the filter map can modify + // the graph and this cannot be watched in any way. + // + // \param _Container The container which is observed. + // \param _Item The item type which is obserbved. + + template + class AlterationNotifier { + public: + + typedef True Notifier; + + typedef _Container Container; + typedef _Item Item; + + // \brief Exception which can be called from clear() and + // erase(). + // + // From the clear() and erase() function only this + // exception is allowed to throw. The exception immediatly + // detaches the current observer from the notifier. Because the + // clear() and erase() should not throw other exceptions + // it can be used to invalidate the observer. + struct ImmediateDetach {}; + + // \brief ObserverBase is the base class for the observers. + // + // ObserverBase is the abstract base class for the observers. + // It will be notified about an item was inserted into or + // erased from the graph. + // + // The observer interface contains some pure virtual functions + // to override. The add() and erase() functions are + // to notify the oberver when one item is added or erased. + // + // The build() and clear() members are to notify the observer + // about the container is built from an empty container or + // is cleared to an empty container. + class ObserverBase { + protected: + typedef AlterationNotifier Notifier; + + friend class AlterationNotifier; + + // \brief Default constructor. + // + // Default constructor for ObserverBase. + ObserverBase() : _notifier(0) {} + + // \brief Constructor which attach the observer into notifier. + // + // Constructor which attach the observer into notifier. + ObserverBase(AlterationNotifier& nf) { + attach(nf); + } + + // \brief Constructor which attach the obserever to the same notifier. + // + // Constructor which attach the obserever to the same notifier as + // the other observer is attached to. + ObserverBase(const ObserverBase& copy) { + if (copy.attached()) { + attach(*copy.notifier()); + } + } + + // \brief Destructor + virtual ~ObserverBase() { + if (attached()) { + detach(); + } + } + + // \brief Attaches the observer into an AlterationNotifier. + // + // This member attaches the observer into an AlterationNotifier. + void attach(AlterationNotifier& nf) { + nf.attach(*this); + } + + // \brief Detaches the observer into an AlterationNotifier. + // + // This member detaches the observer from an AlterationNotifier. + void detach() { + _notifier->detach(*this); + } + + // \brief Gives back a pointer to the notifier which the map + // attached into. + // + // This function gives back a pointer to the notifier which the map + // attached into. + Notifier* notifier() const { return const_cast(_notifier); } + + // Gives back true when the observer is attached into a notifier. + bool attached() const { return _notifier != 0; } + + private: + + ObserverBase& operator=(const ObserverBase& copy); + + protected: + + Notifier* _notifier; + typename std::list::iterator _index; + + // \brief The member function to notificate the observer about an + // item is added to the container. + // + // The add() member function notificates the observer about an item + // is added to the container. It have to be overrided in the + // subclasses. + virtual void add(const Item&) = 0; + + // \brief The member function to notificate the observer about + // more item is added to the container. + // + // The add() member function notificates the observer about more item + // is added to the container. It have to be overrided in the + // subclasses. + virtual void add(const std::vector& items) = 0; + + // \brief The member function to notificate the observer about an + // item is erased from the container. + // + // The erase() member function notificates the observer about an + // item is erased from the container. It have to be overrided in + // the subclasses. + virtual void erase(const Item&) = 0; + + // \brief The member function to notificate the observer about + // more item is erased from the container. + // + // The erase() member function notificates the observer about more item + // is erased from the container. It have to be overrided in the + // subclasses. + virtual void erase(const std::vector& items) = 0; + + // \brief The member function to notificate the observer about the + // container is built. + // + // The build() member function notificates the observer about the + // container is built from an empty container. It have to be + // overrided in the subclasses. + virtual void build() = 0; + + // \brief The member function to notificate the observer about all + // items are erased from the container. + // + // The clear() member function notificates the observer about all + // items are erased from the container. It have to be overrided in + // the subclasses. + virtual void clear() = 0; + + }; + + protected: + + const Container* container; + + typedef std::list Observers; + Observers _observers; + lemon::bits::Lock _lock; + + public: + + // \brief Default constructor. + // + // The default constructor of the AlterationNotifier. + // It creates an empty notifier. + AlterationNotifier() + : container(0) {} + + // \brief Constructor. + // + // Constructor with the observed container parameter. + AlterationNotifier(const Container& _container) + : container(&_container) {} + + // \brief Copy Constructor of the AlterationNotifier. + // + // Copy constructor of the AlterationNotifier. + // It creates only an empty notifier because the copiable + // notifier's observers have to be registered still into that notifier. + AlterationNotifier(const AlterationNotifier& _notifier) + : container(_notifier.container) {} + + // \brief Destructor. + // + // Destructor of the AlterationNotifier. + ~AlterationNotifier() { + typename Observers::iterator it; + for (it = _observers.begin(); it != _observers.end(); ++it) { + (*it)->_notifier = 0; + } + } + + // \brief Sets the container. + // + // Sets the container. + void setContainer(const Container& _container) { + container = &_container; + } + + protected: + + AlterationNotifier& operator=(const AlterationNotifier&); + + public: + + // \brief First item in the container. + // + // Returns the first item in the container. It is + // for start the iteration on the container. + void first(Item& item) const { + container->first(item); + } + + // \brief Next item in the container. + // + // Returns the next item in the container. It is + // for iterate on the container. + void next(Item& item) const { + container->next(item); + } + + // \brief Returns the id of the item. + // + // Returns the id of the item provided by the container. + int id(const Item& item) const { + return container->id(item); + } + + // \brief Returns the maximum id of the container. + // + // Returns the maximum id of the container. + int maxId() const { + return container->maxId(Item()); + } + + protected: + + void attach(ObserverBase& observer) { + _lock.lock(); + observer._index = _observers.insert(_observers.begin(), &observer); + observer._notifier = this; + _lock.unlock(); + } + + void detach(ObserverBase& observer) { + _lock.lock(); + _observers.erase(observer._index); + observer._index = _observers.end(); + observer._notifier = 0; + _lock.unlock(); + } + + public: + + // \brief Notifies all the registed observers about an item added to + // the container. + // + // It notifies all the registed observers about an item added to + // the container. + void add(const Item& item) { + typename Observers::reverse_iterator it; + try { + for (it = _observers.rbegin(); it != _observers.rend(); ++it) { + (*it)->add(item); + } + } catch (...) { + typename Observers::iterator jt; + for (jt = it.base(); jt != _observers.end(); ++jt) { + (*jt)->erase(item); + } + throw; + } + } + + // \brief Notifies all the registed observers about more item added to + // the container. + // + // It notifies all the registed observers about more item added to + // the container. + void add(const std::vector& items) { + typename Observers::reverse_iterator it; + try { + for (it = _observers.rbegin(); it != _observers.rend(); ++it) { + (*it)->add(items); + } + } catch (...) { + typename Observers::iterator jt; + for (jt = it.base(); jt != _observers.end(); ++jt) { + (*jt)->erase(items); + } + throw; + } + } + + // \brief Notifies all the registed observers about an item erased from + // the container. + // + // It notifies all the registed observers about an item erased from + // the container. + void erase(const Item& item) throw() { + typename Observers::iterator it = _observers.begin(); + while (it != _observers.end()) { + try { + (*it)->erase(item); + ++it; + } catch (const ImmediateDetach&) { + (*it)->_index = _observers.end(); + (*it)->_notifier = 0; + it = _observers.erase(it); + } + } + } + + // \brief Notifies all the registed observers about more item erased + // from the container. + // + // It notifies all the registed observers about more item erased from + // the container. + void erase(const std::vector& items) { + typename Observers::iterator it = _observers.begin(); + while (it != _observers.end()) { + try { + (*it)->erase(items); + ++it; + } catch (const ImmediateDetach&) { + (*it)->_index = _observers.end(); + (*it)->_notifier = 0; + it = _observers.erase(it); + } + } + } + + // \brief Notifies all the registed observers about the container is + // built. + // + // Notifies all the registed observers about the container is built + // from an empty container. + void build() { + typename Observers::reverse_iterator it; + try { + for (it = _observers.rbegin(); it != _observers.rend(); ++it) { + (*it)->build(); + } + } catch (...) { + typename Observers::iterator jt; + for (jt = it.base(); jt != _observers.end(); ++jt) { + (*jt)->clear(); + } + throw; + } + } + + // \brief Notifies all the registed observers about all items are + // erased. + // + // Notifies all the registed observers about all items are erased + // from the container. + void clear() { + typename Observers::iterator it = _observers.begin(); + while (it != _observers.end()) { + try { + (*it)->clear(); + ++it; + } catch (const ImmediateDetach&) { + (*it)->_index = _observers.end(); + (*it)->_notifier = 0; + it = _observers.erase(it); + } + } + } + }; + +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/array_map.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/array_map.h new file mode 100644 index 00000000000..355ee008246 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/array_map.h @@ -0,0 +1,351 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_BITS_ARRAY_MAP_H +#define LEMON_BITS_ARRAY_MAP_H + +#include + +#include +#include +#include +#include + +// \ingroup graphbits +// \file +// \brief Graph map based on the array storage. + +namespace lemon { + + // \ingroup graphbits + // + // \brief Graph map based on the array storage. + // + // The ArrayMap template class is graph map structure that automatically + // updates the map when a key is added to or erased from the graph. + // This map uses the allocators to implement the container functionality. + // + // The template parameters are the Graph, the current Item type and + // the Value type of the map. + template + class ArrayMap + : public ItemSetTraits<_Graph, _Item>::ItemNotifier::ObserverBase { + public: + // The graph type. + typedef _Graph GraphType; + // The item type. + typedef _Item Item; + // The reference map tag. + typedef True ReferenceMapTag; + + // The key type of the map. + typedef _Item Key; + // The value type of the map. + typedef _Value Value; + + // The const reference type of the map. + typedef const _Value& ConstReference; + // The reference type of the map. + typedef _Value& Reference; + + // The map type. + typedef ArrayMap Map; + + // The notifier type. + typedef typename ItemSetTraits<_Graph, _Item>::ItemNotifier Notifier; + + private: + + // The MapBase of the Map which imlements the core regisitry function. + typedef typename Notifier::ObserverBase Parent; + + typedef std::allocator Allocator; + + public: + + // \brief Graph initialized map constructor. + // + // Graph initialized map constructor. + explicit ArrayMap(const GraphType& graph) { + Parent::attach(graph.notifier(Item())); + allocate_memory(); + Notifier* nf = Parent::notifier(); + Item it; + for (nf->first(it); it != INVALID; nf->next(it)) { + int id = nf->id(it);; + allocator.construct(&(values[id]), Value()); + } + } + + // \brief Constructor to use default value to initialize the map. + // + // It constructs a map and initialize all of the the map. + ArrayMap(const GraphType& graph, const Value& value) { + Parent::attach(graph.notifier(Item())); + allocate_memory(); + Notifier* nf = Parent::notifier(); + Item it; + for (nf->first(it); it != INVALID; nf->next(it)) { + int id = nf->id(it);; + allocator.construct(&(values[id]), value); + } + } + + private: + // \brief Constructor to copy a map of the same map type. + // + // Constructor to copy a map of the same map type. + ArrayMap(const ArrayMap& copy) : Parent() { + if (copy.attached()) { + attach(*copy.notifier()); + } + capacity = copy.capacity; + if (capacity == 0) return; + values = allocator.allocate(capacity); + Notifier* nf = Parent::notifier(); + Item it; + for (nf->first(it); it != INVALID; nf->next(it)) { + int id = nf->id(it);; + allocator.construct(&(values[id]), copy.values[id]); + } + } + + // \brief Assign operator. + // + // This operator assigns for each item in the map the + // value mapped to the same item in the copied map. + // The parameter map should be indiced with the same + // itemset because this assign operator does not change + // the container of the map. + ArrayMap& operator=(const ArrayMap& cmap) { + return operator=(cmap); + } + + + // \brief Template assign operator. + // + // The given parameter should conform to the ReadMap + // concecpt and could be indiced by the current item set of + // the NodeMap. In this case the value for each item + // is assigned by the value of the given ReadMap. + template + ArrayMap& operator=(const CMap& cmap) { + checkConcept, CMap>(); + const typename Parent::Notifier* nf = Parent::notifier(); + Item it; + for (nf->first(it); it != INVALID; nf->next(it)) { + set(it, cmap[it]); + } + return *this; + } + + public: + // \brief The destructor of the map. + // + // The destructor of the map. + virtual ~ArrayMap() { + if (attached()) { + clear(); + detach(); + } + } + + protected: + + using Parent::attach; + using Parent::detach; + using Parent::attached; + + public: + + // \brief The subscript operator. + // + // The subscript operator. The map can be subscripted by the + // actual keys of the graph. + Value& operator[](const Key& key) { + int id = Parent::notifier()->id(key); + return values[id]; + } + + // \brief The const subscript operator. + // + // The const subscript operator. The map can be subscripted by the + // actual keys of the graph. + const Value& operator[](const Key& key) const { + int id = Parent::notifier()->id(key); + return values[id]; + } + + // \brief Setter function of the map. + // + // Setter function of the map. Equivalent with map[key] = val. + // This is a compatibility feature with the not dereferable maps. + void set(const Key& key, const Value& val) { + (*this)[key] = val; + } + + protected: + + // \brief Adds a new key to the map. + // + // It adds a new key to the map. It is called by the observer notifier + // and it overrides the add() member function of the observer base. + virtual void add(const Key& key) { + Notifier* nf = Parent::notifier(); + int id = nf->id(key); + if (id >= capacity) { + int new_capacity = (capacity == 0 ? 1 : capacity); + while (new_capacity <= id) { + new_capacity <<= 1; + } + Value* new_values = allocator.allocate(new_capacity); + Item it; + for (nf->first(it); it != INVALID; nf->next(it)) { + int jd = nf->id(it);; + if (id != jd) { + allocator.construct(&(new_values[jd]), values[jd]); + allocator.destroy(&(values[jd])); + } + } + if (capacity != 0) allocator.deallocate(values, capacity); + values = new_values; + capacity = new_capacity; + } + allocator.construct(&(values[id]), Value()); + } + + // \brief Adds more new keys to the map. + // + // It adds more new keys to the map. It is called by the observer notifier + // and it overrides the add() member function of the observer base. + virtual void add(const std::vector& keys) { + Notifier* nf = Parent::notifier(); + int max_id = -1; + for (int i = 0; i < int(keys.size()); ++i) { + int id = nf->id(keys[i]); + if (id > max_id) { + max_id = id; + } + } + if (max_id >= capacity) { + int new_capacity = (capacity == 0 ? 1 : capacity); + while (new_capacity <= max_id) { + new_capacity <<= 1; + } + Value* new_values = allocator.allocate(new_capacity); + Item it; + for (nf->first(it); it != INVALID; nf->next(it)) { + int id = nf->id(it); + bool found = false; + for (int i = 0; i < int(keys.size()); ++i) { + int jd = nf->id(keys[i]); + if (id == jd) { + found = true; + break; + } + } + if (found) continue; + allocator.construct(&(new_values[id]), values[id]); + allocator.destroy(&(values[id])); + } + if (capacity != 0) allocator.deallocate(values, capacity); + values = new_values; + capacity = new_capacity; + } + for (int i = 0; i < int(keys.size()); ++i) { + int id = nf->id(keys[i]); + allocator.construct(&(values[id]), Value()); + } + } + + // \brief Erase a key from the map. + // + // Erase a key from the map. It is called by the observer notifier + // and it overrides the erase() member function of the observer base. + virtual void erase(const Key& key) { + int id = Parent::notifier()->id(key); + allocator.destroy(&(values[id])); + } + + // \brief Erase more keys from the map. + // + // Erase more keys from the map. It is called by the observer notifier + // and it overrides the erase() member function of the observer base. + virtual void erase(const std::vector& keys) { + for (int i = 0; i < int(keys.size()); ++i) { + int id = Parent::notifier()->id(keys[i]); + allocator.destroy(&(values[id])); + } + } + + // \brief Builds the map. + // + // It builds the map. It is called by the observer notifier + // and it overrides the build() member function of the observer base. + virtual void build() { + Notifier* nf = Parent::notifier(); + allocate_memory(); + Item it; + for (nf->first(it); it != INVALID; nf->next(it)) { + int id = nf->id(it);; + allocator.construct(&(values[id]), Value()); + } + } + + // \brief Clear the map. + // + // It erase all items from the map. It is called by the observer notifier + // and it overrides the clear() member function of the observer base. + virtual void clear() { + Notifier* nf = Parent::notifier(); + if (capacity != 0) { + Item it; + for (nf->first(it); it != INVALID; nf->next(it)) { + int id = nf->id(it); + allocator.destroy(&(values[id])); + } + allocator.deallocate(values, capacity); + capacity = 0; + } + } + + private: + + void allocate_memory() { + int max_id = Parent::notifier()->maxId(); + if (max_id == -1) { + capacity = 0; + values = 0; + return; + } + capacity = 1; + while (capacity <= max_id) { + capacity <<= 1; + } + values = allocator.allocate(capacity); + } + + int capacity; + Value* values; + Allocator allocator; + + }; + +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/bezier.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/bezier.h new file mode 100644 index 00000000000..9d8d1413d07 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/bezier.h @@ -0,0 +1,174 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_BEZIER_H +#define LEMON_BEZIER_H + +//\ingroup misc +//\file +//\brief Classes to compute with Bezier curves. +// +//Up to now this file is used internally by \ref graph_to_eps.h + +#include + +namespace lemon { + namespace dim2 { + +class BezierBase { +public: + typedef lemon::dim2::Point Point; +protected: + static Point conv(Point x,Point y,double t) {return (1-t)*x+t*y;} +}; + +class Bezier1 : public BezierBase +{ +public: + Point p1,p2; + + Bezier1() {} + Bezier1(Point _p1, Point _p2) :p1(_p1), p2(_p2) {} + + Point operator()(double t) const + { + // return conv(conv(p1,p2,t),conv(p2,p3,t),t); + return conv(p1,p2,t); + } + Bezier1 before(double t) const + { + return Bezier1(p1,conv(p1,p2,t)); + } + + Bezier1 after(double t) const + { + return Bezier1(conv(p1,p2,t),p2); + } + + Bezier1 revert() const { return Bezier1(p2,p1);} + Bezier1 operator()(double a,double b) const { return before(b).after(a/b); } + Point grad() const { return p2-p1; } + Point norm() const { return rot90(p2-p1); } + Point grad(double) const { return grad(); } + Point norm(double t) const { return rot90(grad(t)); } +}; + +class Bezier2 : public BezierBase +{ +public: + Point p1,p2,p3; + + Bezier2() {} + Bezier2(Point _p1, Point _p2, Point _p3) :p1(_p1), p2(_p2), p3(_p3) {} + Bezier2(const Bezier1 &b) : p1(b.p1), p2(conv(b.p1,b.p2,.5)), p3(b.p2) {} + Point operator()(double t) const + { + // return conv(conv(p1,p2,t),conv(p2,p3,t),t); + return ((1-t)*(1-t))*p1+(2*(1-t)*t)*p2+(t*t)*p3; + } + Bezier2 before(double t) const + { + Point q(conv(p1,p2,t)); + Point r(conv(p2,p3,t)); + return Bezier2(p1,q,conv(q,r,t)); + } + + Bezier2 after(double t) const + { + Point q(conv(p1,p2,t)); + Point r(conv(p2,p3,t)); + return Bezier2(conv(q,r,t),r,p3); + } + Bezier2 revert() const { return Bezier2(p3,p2,p1);} + Bezier2 operator()(double a,double b) const { return before(b).after(a/b); } + Bezier1 grad() const { return Bezier1(2.0*(p2-p1),2.0*(p3-p2)); } + Bezier1 norm() const { return Bezier1(2.0*rot90(p2-p1),2.0*rot90(p3-p2)); } + Point grad(double t) const { return grad()(t); } + Point norm(double t) const { return rot90(grad(t)); } +}; + +class Bezier3 : public BezierBase +{ +public: + Point p1,p2,p3,p4; + + Bezier3() {} + Bezier3(Point _p1, Point _p2, Point _p3, Point _p4) + : p1(_p1), p2(_p2), p3(_p3), p4(_p4) {} + Bezier3(const Bezier1 &b) : p1(b.p1), p2(conv(b.p1,b.p2,1.0/3.0)), + p3(conv(b.p1,b.p2,2.0/3.0)), p4(b.p2) {} + Bezier3(const Bezier2 &b) : p1(b.p1), p2(conv(b.p1,b.p2,2.0/3.0)), + p3(conv(b.p2,b.p3,1.0/3.0)), p4(b.p3) {} + + Point operator()(double t) const + { + // return Bezier2(conv(p1,p2,t),conv(p2,p3,t),conv(p3,p4,t))(t); + return ((1-t)*(1-t)*(1-t))*p1+(3*t*(1-t)*(1-t))*p2+ + (3*t*t*(1-t))*p3+(t*t*t)*p4; + } + Bezier3 before(double t) const + { + Point p(conv(p1,p2,t)); + Point q(conv(p2,p3,t)); + Point r(conv(p3,p4,t)); + Point a(conv(p,q,t)); + Point b(conv(q,r,t)); + Point c(conv(a,b,t)); + return Bezier3(p1,p,a,c); + } + + Bezier3 after(double t) const + { + Point p(conv(p1,p2,t)); + Point q(conv(p2,p3,t)); + Point r(conv(p3,p4,t)); + Point a(conv(p,q,t)); + Point b(conv(q,r,t)); + Point c(conv(a,b,t)); + return Bezier3(c,b,r,p4); + } + Bezier3 revert() const { return Bezier3(p4,p3,p2,p1);} + Bezier3 operator()(double a,double b) const { return before(b).after(a/b); } + Bezier2 grad() const { return Bezier2(3.0*(p2-p1),3.0*(p3-p2),3.0*(p4-p3)); } + Bezier2 norm() const { return Bezier2(3.0*rot90(p2-p1), + 3.0*rot90(p3-p2), + 3.0*rot90(p4-p3)); } + Point grad(double t) const { return grad()(t); } + Point norm(double t) const { return rot90(grad(t)); } + + template + R recSplit(F &_f,const S &_s,D _d) const + { + const Point a=(p1+p2)/2; + const Point b=(p2+p3)/2; + const Point c=(p3+p4)/2; + const Point d=(a+b)/2; + const Point e=(b+c)/2; + // const Point f=(d+e)/2; + R f1=_f(Bezier3(p1,a,d,e),_d); + R f2=_f(Bezier3(e,d,c,p4),_d); + return _s(f1,f2); + } + +}; + + +} //END OF NAMESPACE dim2 +} //END OF NAMESPACE lemon + +#endif // LEMON_BEZIER_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/default_map.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/default_map.h new file mode 100644 index 00000000000..23728e427ad --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/default_map.h @@ -0,0 +1,182 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_BITS_DEFAULT_MAP_H +#define LEMON_BITS_DEFAULT_MAP_H + +#include +#include +#include +//#include + +//\ingroup graphbits +//\file +//\brief Graph maps that construct and destruct their elements dynamically. + +namespace lemon { + + + //#ifndef LEMON_USE_DEBUG_MAP + + template + struct DefaultMapSelector { + typedef ArrayMap<_Graph, _Item, _Value> Map; + }; + + // bool + template + struct DefaultMapSelector<_Graph, _Item, bool> { + typedef VectorMap<_Graph, _Item, bool> Map; + }; + + // char + template + struct DefaultMapSelector<_Graph, _Item, char> { + typedef VectorMap<_Graph, _Item, char> Map; + }; + + template + struct DefaultMapSelector<_Graph, _Item, signed char> { + typedef VectorMap<_Graph, _Item, signed char> Map; + }; + + template + struct DefaultMapSelector<_Graph, _Item, unsigned char> { + typedef VectorMap<_Graph, _Item, unsigned char> Map; + }; + + + // int + template + struct DefaultMapSelector<_Graph, _Item, signed int> { + typedef VectorMap<_Graph, _Item, signed int> Map; + }; + + template + struct DefaultMapSelector<_Graph, _Item, unsigned int> { + typedef VectorMap<_Graph, _Item, unsigned int> Map; + }; + + + // short + template + struct DefaultMapSelector<_Graph, _Item, signed short> { + typedef VectorMap<_Graph, _Item, signed short> Map; + }; + + template + struct DefaultMapSelector<_Graph, _Item, unsigned short> { + typedef VectorMap<_Graph, _Item, unsigned short> Map; + }; + + + // long + template + struct DefaultMapSelector<_Graph, _Item, signed long> { + typedef VectorMap<_Graph, _Item, signed long> Map; + }; + + template + struct DefaultMapSelector<_Graph, _Item, unsigned long> { + typedef VectorMap<_Graph, _Item, unsigned long> Map; + }; + + +#if defined LEMON_HAVE_LONG_LONG + + // long long + template + struct DefaultMapSelector<_Graph, _Item, signed long long> { + typedef VectorMap<_Graph, _Item, signed long long> Map; + }; + + template + struct DefaultMapSelector<_Graph, _Item, unsigned long long> { + typedef VectorMap<_Graph, _Item, unsigned long long> Map; + }; + +#endif + + + // float + template + struct DefaultMapSelector<_Graph, _Item, float> { + typedef VectorMap<_Graph, _Item, float> Map; + }; + + + // double + template + struct DefaultMapSelector<_Graph, _Item, double> { + typedef VectorMap<_Graph, _Item, double> Map; + }; + + + // long double + template + struct DefaultMapSelector<_Graph, _Item, long double> { + typedef VectorMap<_Graph, _Item, long double> Map; + }; + + + // pointer + template + struct DefaultMapSelector<_Graph, _Item, _Ptr*> { + typedef VectorMap<_Graph, _Item, _Ptr*> Map; + }; + +// #else + +// template +// struct DefaultMapSelector { +// typedef DebugMap<_Graph, _Item, _Value> Map; +// }; + +// #endif + + // DefaultMap class + template + class DefaultMap + : public DefaultMapSelector<_Graph, _Item, _Value>::Map { + typedef typename DefaultMapSelector<_Graph, _Item, _Value>::Map Parent; + + public: + typedef DefaultMap<_Graph, _Item, _Value> Map; + + typedef typename Parent::GraphType GraphType; + typedef typename Parent::Value Value; + + explicit DefaultMap(const GraphType& graph) : Parent(graph) {} + DefaultMap(const GraphType& graph, const Value& value) + : Parent(graph, value) {} + + DefaultMap& operator=(const DefaultMap& cmap) { + return operator=(cmap); + } + + template + DefaultMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + + }; + +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/edge_set_extender.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/edge_set_extender.h new file mode 100644 index 00000000000..364ca2ee6a9 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/edge_set_extender.h @@ -0,0 +1,627 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_BITS_EDGE_SET_EXTENDER_H +#define LEMON_BITS_EDGE_SET_EXTENDER_H + +#include +#include +#include +#include + +//\ingroup digraphbits +//\file +//\brief Extenders for the arc set types +namespace lemon { + + // \ingroup digraphbits + // + // \brief Extender for the ArcSets + template + class ArcSetExtender : public Base { + typedef Base Parent; + + public: + + typedef ArcSetExtender Digraph; + + // Base extensions + + typedef typename Parent::Node Node; + typedef typename Parent::Arc Arc; + + int maxId(Node) const { + return Parent::maxNodeId(); + } + + int maxId(Arc) const { + return Parent::maxArcId(); + } + + Node fromId(int id, Node) const { + return Parent::nodeFromId(id); + } + + Arc fromId(int id, Arc) const { + return Parent::arcFromId(id); + } + + Node oppositeNode(const Node &n, const Arc &e) const { + if (n == Parent::source(e)) + return Parent::target(e); + else if(n==Parent::target(e)) + return Parent::source(e); + else + return INVALID; + } + + + // Alteration notifier extensions + + // The arc observer registry. + typedef AlterationNotifier ArcNotifier; + + protected: + + mutable ArcNotifier arc_notifier; + + public: + + using Parent::notifier; + + // Gives back the arc alteration notifier. + ArcNotifier& notifier(Arc) const { + return arc_notifier; + } + + // Iterable extensions + + class NodeIt : public Node { + const Digraph* digraph; + public: + + NodeIt() {} + + NodeIt(Invalid i) : Node(i) { } + + explicit NodeIt(const Digraph& _graph) : digraph(&_graph) { + _graph.first(static_cast(*this)); + } + + NodeIt(const Digraph& _graph, const Node& node) + : Node(node), digraph(&_graph) {} + + NodeIt& operator++() { + digraph->next(*this); + return *this; + } + + }; + + + class ArcIt : public Arc { + const Digraph* digraph; + public: + + ArcIt() { } + + ArcIt(Invalid i) : Arc(i) { } + + explicit ArcIt(const Digraph& _graph) : digraph(&_graph) { + _graph.first(static_cast(*this)); + } + + ArcIt(const Digraph& _graph, const Arc& e) : + Arc(e), digraph(&_graph) { } + + ArcIt& operator++() { + digraph->next(*this); + return *this; + } + + }; + + + class OutArcIt : public Arc { + const Digraph* digraph; + public: + + OutArcIt() { } + + OutArcIt(Invalid i) : Arc(i) { } + + OutArcIt(const Digraph& _graph, const Node& node) + : digraph(&_graph) { + _graph.firstOut(*this, node); + } + + OutArcIt(const Digraph& _graph, const Arc& arc) + : Arc(arc), digraph(&_graph) {} + + OutArcIt& operator++() { + digraph->nextOut(*this); + return *this; + } + + }; + + + class InArcIt : public Arc { + const Digraph* digraph; + public: + + InArcIt() { } + + InArcIt(Invalid i) : Arc(i) { } + + InArcIt(const Digraph& _graph, const Node& node) + : digraph(&_graph) { + _graph.firstIn(*this, node); + } + + InArcIt(const Digraph& _graph, const Arc& arc) : + Arc(arc), digraph(&_graph) {} + + InArcIt& operator++() { + digraph->nextIn(*this); + return *this; + } + + }; + + // \brief Base node of the iterator + // + // Returns the base node (ie. the source in this case) of the iterator + Node baseNode(const OutArcIt &e) const { + return Parent::source(static_cast(e)); + } + // \brief Running node of the iterator + // + // Returns the running node (ie. the target in this case) of the + // iterator + Node runningNode(const OutArcIt &e) const { + return Parent::target(static_cast(e)); + } + + // \brief Base node of the iterator + // + // Returns the base node (ie. the target in this case) of the iterator + Node baseNode(const InArcIt &e) const { + return Parent::target(static_cast(e)); + } + // \brief Running node of the iterator + // + // Returns the running node (ie. the source in this case) of the + // iterator + Node runningNode(const InArcIt &e) const { + return Parent::source(static_cast(e)); + } + + using Parent::first; + + // Mappable extension + + template + class ArcMap + : public MapExtender > { + typedef MapExtender > Parent; + + public: + explicit ArcMap(const Digraph& _g) + : Parent(_g) {} + ArcMap(const Digraph& _g, const _Value& _v) + : Parent(_g, _v) {} + + ArcMap& operator=(const ArcMap& cmap) { + return operator=(cmap); + } + + template + ArcMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + + }; + + + // Alteration extension + + Arc addArc(const Node& from, const Node& to) { + Arc arc = Parent::addArc(from, to); + notifier(Arc()).add(arc); + return arc; + } + + void clear() { + notifier(Arc()).clear(); + Parent::clear(); + } + + void erase(const Arc& arc) { + notifier(Arc()).erase(arc); + Parent::erase(arc); + } + + ArcSetExtender() { + arc_notifier.setContainer(*this); + } + + ~ArcSetExtender() { + arc_notifier.clear(); + } + + }; + + + // \ingroup digraphbits + // + // \brief Extender for the EdgeSets + template + class EdgeSetExtender : public Base { + typedef Base Parent; + + public: + + typedef EdgeSetExtender Graph; + + typedef True UndirectedTag; + + typedef typename Parent::Node Node; + typedef typename Parent::Arc Arc; + typedef typename Parent::Edge Edge; + + int maxId(Node) const { + return Parent::maxNodeId(); + } + + int maxId(Arc) const { + return Parent::maxArcId(); + } + + int maxId(Edge) const { + return Parent::maxEdgeId(); + } + + Node fromId(int id, Node) const { + return Parent::nodeFromId(id); + } + + Arc fromId(int id, Arc) const { + return Parent::arcFromId(id); + } + + Edge fromId(int id, Edge) const { + return Parent::edgeFromId(id); + } + + Node oppositeNode(const Node &n, const Edge &e) const { + if( n == Parent::u(e)) + return Parent::v(e); + else if( n == Parent::v(e)) + return Parent::u(e); + else + return INVALID; + } + + Arc oppositeArc(const Arc &e) const { + return Parent::direct(e, !Parent::direction(e)); + } + + using Parent::direct; + Arc direct(const Edge &e, const Node &s) const { + return Parent::direct(e, Parent::u(e) == s); + } + + typedef AlterationNotifier ArcNotifier; + typedef AlterationNotifier EdgeNotifier; + + + protected: + + mutable ArcNotifier arc_notifier; + mutable EdgeNotifier edge_notifier; + + public: + + using Parent::notifier; + + ArcNotifier& notifier(Arc) const { + return arc_notifier; + } + + EdgeNotifier& notifier(Edge) const { + return edge_notifier; + } + + + class NodeIt : public Node { + const Graph* graph; + public: + + NodeIt() {} + + NodeIt(Invalid i) : Node(i) { } + + explicit NodeIt(const Graph& _graph) : graph(&_graph) { + _graph.first(static_cast(*this)); + } + + NodeIt(const Graph& _graph, const Node& node) + : Node(node), graph(&_graph) {} + + NodeIt& operator++() { + graph->next(*this); + return *this; + } + + }; + + + class ArcIt : public Arc { + const Graph* graph; + public: + + ArcIt() { } + + ArcIt(Invalid i) : Arc(i) { } + + explicit ArcIt(const Graph& _graph) : graph(&_graph) { + _graph.first(static_cast(*this)); + } + + ArcIt(const Graph& _graph, const Arc& e) : + Arc(e), graph(&_graph) { } + + ArcIt& operator++() { + graph->next(*this); + return *this; + } + + }; + + + class OutArcIt : public Arc { + const Graph* graph; + public: + + OutArcIt() { } + + OutArcIt(Invalid i) : Arc(i) { } + + OutArcIt(const Graph& _graph, const Node& node) + : graph(&_graph) { + _graph.firstOut(*this, node); + } + + OutArcIt(const Graph& _graph, const Arc& arc) + : Arc(arc), graph(&_graph) {} + + OutArcIt& operator++() { + graph->nextOut(*this); + return *this; + } + + }; + + + class InArcIt : public Arc { + const Graph* graph; + public: + + InArcIt() { } + + InArcIt(Invalid i) : Arc(i) { } + + InArcIt(const Graph& _graph, const Node& node) + : graph(&_graph) { + _graph.firstIn(*this, node); + } + + InArcIt(const Graph& _graph, const Arc& arc) : + Arc(arc), graph(&_graph) {} + + InArcIt& operator++() { + graph->nextIn(*this); + return *this; + } + + }; + + + class EdgeIt : public Parent::Edge { + const Graph* graph; + public: + + EdgeIt() { } + + EdgeIt(Invalid i) : Edge(i) { } + + explicit EdgeIt(const Graph& _graph) : graph(&_graph) { + _graph.first(static_cast(*this)); + } + + EdgeIt(const Graph& _graph, const Edge& e) : + Edge(e), graph(&_graph) { } + + EdgeIt& operator++() { + graph->next(*this); + return *this; + } + + }; + + class IncEdgeIt : public Parent::Edge { + friend class EdgeSetExtender; + const Graph* graph; + bool direction; + public: + + IncEdgeIt() { } + + IncEdgeIt(Invalid i) : Edge(i), direction(false) { } + + IncEdgeIt(const Graph& _graph, const Node &n) : graph(&_graph) { + _graph.firstInc(*this, direction, n); + } + + IncEdgeIt(const Graph& _graph, const Edge &ue, const Node &n) + : graph(&_graph), Edge(ue) { + direction = (_graph.source(ue) == n); + } + + IncEdgeIt& operator++() { + graph->nextInc(*this, direction); + return *this; + } + }; + + // \brief Base node of the iterator + // + // Returns the base node (ie. the source in this case) of the iterator + Node baseNode(const OutArcIt &e) const { + return Parent::source(static_cast(e)); + } + // \brief Running node of the iterator + // + // Returns the running node (ie. the target in this case) of the + // iterator + Node runningNode(const OutArcIt &e) const { + return Parent::target(static_cast(e)); + } + + // \brief Base node of the iterator + // + // Returns the base node (ie. the target in this case) of the iterator + Node baseNode(const InArcIt &e) const { + return Parent::target(static_cast(e)); + } + // \brief Running node of the iterator + // + // Returns the running node (ie. the source in this case) of the + // iterator + Node runningNode(const InArcIt &e) const { + return Parent::source(static_cast(e)); + } + + // Base node of the iterator + // + // Returns the base node of the iterator + Node baseNode(const IncEdgeIt &e) const { + return e.direction ? this->u(e) : this->v(e); + } + // Running node of the iterator + // + // Returns the running node of the iterator + Node runningNode(const IncEdgeIt &e) const { + return e.direction ? this->v(e) : this->u(e); + } + + + template + class ArcMap + : public MapExtender > { + typedef MapExtender > Parent; + + public: + explicit ArcMap(const Graph& _g) + : Parent(_g) {} + ArcMap(const Graph& _g, const _Value& _v) + : Parent(_g, _v) {} + + ArcMap& operator=(const ArcMap& cmap) { + return operator=(cmap); + } + + template + ArcMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + + }; + + + template + class EdgeMap + : public MapExtender > { + typedef MapExtender > Parent; + + public: + explicit EdgeMap(const Graph& _g) + : Parent(_g) {} + + EdgeMap(const Graph& _g, const _Value& _v) + : Parent(_g, _v) {} + + EdgeMap& operator=(const EdgeMap& cmap) { + return operator=(cmap); + } + + template + EdgeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + + }; + + + // Alteration extension + + Edge addEdge(const Node& from, const Node& to) { + Edge edge = Parent::addEdge(from, to); + notifier(Edge()).add(edge); + std::vector arcs; + arcs.push_back(Parent::direct(edge, true)); + arcs.push_back(Parent::direct(edge, false)); + notifier(Arc()).add(arcs); + return edge; + } + + void clear() { + notifier(Arc()).clear(); + notifier(Edge()).clear(); + Parent::clear(); + } + + void erase(const Edge& edge) { + std::vector arcs; + arcs.push_back(Parent::direct(edge, true)); + arcs.push_back(Parent::direct(edge, false)); + notifier(Arc()).erase(arcs); + notifier(Edge()).erase(edge); + Parent::erase(edge); + } + + + EdgeSetExtender() { + arc_notifier.setContainer(*this); + edge_notifier.setContainer(*this); + } + + ~EdgeSetExtender() { + edge_notifier.clear(); + arc_notifier.clear(); + } + + }; + +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/enable_if.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/enable_if.h new file mode 100644 index 00000000000..f0d8de4d3cc --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/enable_if.h @@ -0,0 +1,131 @@ +/* -*- 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. + * + */ + +// This file contains a modified version of the enable_if library from BOOST. +// See the appropriate copyright notice below. + +// Boost enable_if library + +// Copyright 2003 (c) The Trustees of Indiana University. + +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Authors: Jaakko Jarvi (jajarvi at osl.iu.edu) +// Jeremiah Willcock (jewillco at osl.iu.edu) +// Andrew Lumsdaine (lums at osl.iu.edu) + + +#ifndef LEMON_BITS_ENABLE_IF_H +#define LEMON_BITS_ENABLE_IF_H + +//\file +//\brief Miscellaneous basic utilities + +namespace lemon +{ + + // Basic type for defining "tags". A "YES" condition for \c enable_if. + + // Basic type for defining "tags". A "YES" condition for \c enable_if. + // + //\sa False + struct True { + //\e + static const bool value = true; + }; + + // Basic type for defining "tags". A "NO" condition for \c enable_if. + + // Basic type for defining "tags". A "NO" condition for \c enable_if. + // + //\sa True + struct False { + //\e + static const bool value = false; + }; + + + + template + struct Wrap { + const T &value; + Wrap(const T &t) : value(t) {} + }; + + /**************** dummy class to avoid ambiguity ****************/ + + template struct dummy { dummy(int) {} }; + + /**************** enable_if from BOOST ****************/ + + template + struct exists { + typedef T type; + }; + + + template + struct enable_if_c { + typedef T type; + }; + + template + struct enable_if_c {}; + + template + struct enable_if : public enable_if_c {}; + + template + struct lazy_enable_if_c { + typedef typename T::type type; + }; + + template + struct lazy_enable_if_c {}; + + template + struct lazy_enable_if : public lazy_enable_if_c {}; + + + template + struct disable_if_c { + typedef T type; + }; + + template + struct disable_if_c {}; + + template + struct disable_if : public disable_if_c {}; + + template + struct lazy_disable_if_c { + typedef typename T::type type; + }; + + template + struct lazy_disable_if_c {}; + + template + struct lazy_disable_if : public lazy_disable_if_c {}; + +} // namespace lemon + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/graph_adaptor_extender.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/graph_adaptor_extender.h new file mode 100644 index 00000000000..c38c8e1d608 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/graph_adaptor_extender.h @@ -0,0 +1,401 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_BITS_GRAPH_ADAPTOR_EXTENDER_H +#define LEMON_BITS_GRAPH_ADAPTOR_EXTENDER_H + +#include +#include + +namespace lemon { + + template + class DigraphAdaptorExtender : public _Digraph { + typedef _Digraph Parent; + + public: + + typedef _Digraph Digraph; + typedef DigraphAdaptorExtender Adaptor; + + // Base extensions + + typedef typename Parent::Node Node; + typedef typename Parent::Arc Arc; + + int maxId(Node) const { + return Parent::maxNodeId(); + } + + int maxId(Arc) const { + return Parent::maxArcId(); + } + + Node fromId(int id, Node) const { + return Parent::nodeFromId(id); + } + + Arc fromId(int id, Arc) const { + return Parent::arcFromId(id); + } + + Node oppositeNode(const Node &n, const Arc &e) const { + if (n == Parent::source(e)) + return Parent::target(e); + else if(n==Parent::target(e)) + return Parent::source(e); + else + return INVALID; + } + + class NodeIt : public Node { + const Adaptor* _adaptor; + public: + + NodeIt() {} + + NodeIt(Invalid i) : Node(i) { } + + explicit NodeIt(const Adaptor& adaptor) : _adaptor(&adaptor) { + _adaptor->first(static_cast(*this)); + } + + NodeIt(const Adaptor& adaptor, const Node& node) + : Node(node), _adaptor(&adaptor) {} + + NodeIt& operator++() { + _adaptor->next(*this); + return *this; + } + + }; + + + class ArcIt : public Arc { + const Adaptor* _adaptor; + public: + + ArcIt() { } + + ArcIt(Invalid i) : Arc(i) { } + + explicit ArcIt(const Adaptor& adaptor) : _adaptor(&adaptor) { + _adaptor->first(static_cast(*this)); + } + + ArcIt(const Adaptor& adaptor, const Arc& e) : + Arc(e), _adaptor(&adaptor) { } + + ArcIt& operator++() { + _adaptor->next(*this); + return *this; + } + + }; + + + class OutArcIt : public Arc { + const Adaptor* _adaptor; + public: + + OutArcIt() { } + + OutArcIt(Invalid i) : Arc(i) { } + + OutArcIt(const Adaptor& adaptor, const Node& node) + : _adaptor(&adaptor) { + _adaptor->firstOut(*this, node); + } + + OutArcIt(const Adaptor& adaptor, const Arc& arc) + : Arc(arc), _adaptor(&adaptor) {} + + OutArcIt& operator++() { + _adaptor->nextOut(*this); + return *this; + } + + }; + + + class InArcIt : public Arc { + const Adaptor* _adaptor; + public: + + InArcIt() { } + + InArcIt(Invalid i) : Arc(i) { } + + InArcIt(const Adaptor& adaptor, const Node& node) + : _adaptor(&adaptor) { + _adaptor->firstIn(*this, node); + } + + InArcIt(const Adaptor& adaptor, const Arc& arc) : + Arc(arc), _adaptor(&adaptor) {} + + InArcIt& operator++() { + _adaptor->nextIn(*this); + return *this; + } + + }; + + Node baseNode(const OutArcIt &e) const { + return Parent::source(e); + } + Node runningNode(const OutArcIt &e) const { + return Parent::target(e); + } + + Node baseNode(const InArcIt &e) const { + return Parent::target(e); + } + Node runningNode(const InArcIt &e) const { + return Parent::source(e); + } + + }; + + template + class GraphAdaptorExtender : public _Graph { + typedef _Graph Parent; + + public: + + typedef _Graph Graph; + typedef GraphAdaptorExtender Adaptor; + + typedef True UndirectedTag; + + typedef typename Parent::Node Node; + typedef typename Parent::Arc Arc; + typedef typename Parent::Edge Edge; + + // Graph extension + + int maxId(Node) const { + return Parent::maxNodeId(); + } + + int maxId(Arc) const { + return Parent::maxArcId(); + } + + int maxId(Edge) const { + return Parent::maxEdgeId(); + } + + Node fromId(int id, Node) const { + return Parent::nodeFromId(id); + } + + Arc fromId(int id, Arc) const { + return Parent::arcFromId(id); + } + + Edge fromId(int id, Edge) const { + return Parent::edgeFromId(id); + } + + Node oppositeNode(const Node &n, const Edge &e) const { + if( n == Parent::u(e)) + return Parent::v(e); + else if( n == Parent::v(e)) + return Parent::u(e); + else + return INVALID; + } + + Arc oppositeArc(const Arc &a) const { + return Parent::direct(a, !Parent::direction(a)); + } + + using Parent::direct; + Arc direct(const Edge &e, const Node &s) const { + return Parent::direct(e, Parent::u(e) == s); + } + + + class NodeIt : public Node { + const Adaptor* _adaptor; + public: + + NodeIt() {} + + NodeIt(Invalid i) : Node(i) { } + + explicit NodeIt(const Adaptor& adaptor) : _adaptor(&adaptor) { + _adaptor->first(static_cast(*this)); + } + + NodeIt(const Adaptor& adaptor, const Node& node) + : Node(node), _adaptor(&adaptor) {} + + NodeIt& operator++() { + _adaptor->next(*this); + return *this; + } + + }; + + + class ArcIt : public Arc { + const Adaptor* _adaptor; + public: + + ArcIt() { } + + ArcIt(Invalid i) : Arc(i) { } + + explicit ArcIt(const Adaptor& adaptor) : _adaptor(&adaptor) { + _adaptor->first(static_cast(*this)); + } + + ArcIt(const Adaptor& adaptor, const Arc& e) : + Arc(e), _adaptor(&adaptor) { } + + ArcIt& operator++() { + _adaptor->next(*this); + return *this; + } + + }; + + + class OutArcIt : public Arc { + const Adaptor* _adaptor; + public: + + OutArcIt() { } + + OutArcIt(Invalid i) : Arc(i) { } + + OutArcIt(const Adaptor& adaptor, const Node& node) + : _adaptor(&adaptor) { + _adaptor->firstOut(*this, node); + } + + OutArcIt(const Adaptor& adaptor, const Arc& arc) + : Arc(arc), _adaptor(&adaptor) {} + + OutArcIt& operator++() { + _adaptor->nextOut(*this); + return *this; + } + + }; + + + class InArcIt : public Arc { + const Adaptor* _adaptor; + public: + + InArcIt() { } + + InArcIt(Invalid i) : Arc(i) { } + + InArcIt(const Adaptor& adaptor, const Node& node) + : _adaptor(&adaptor) { + _adaptor->firstIn(*this, node); + } + + InArcIt(const Adaptor& adaptor, const Arc& arc) : + Arc(arc), _adaptor(&adaptor) {} + + InArcIt& operator++() { + _adaptor->nextIn(*this); + return *this; + } + + }; + + class EdgeIt : public Parent::Edge { + const Adaptor* _adaptor; + public: + + EdgeIt() { } + + EdgeIt(Invalid i) : Edge(i) { } + + explicit EdgeIt(const Adaptor& adaptor) : _adaptor(&adaptor) { + _adaptor->first(static_cast(*this)); + } + + EdgeIt(const Adaptor& adaptor, const Edge& e) : + Edge(e), _adaptor(&adaptor) { } + + EdgeIt& operator++() { + _adaptor->next(*this); + return *this; + } + + }; + + class IncEdgeIt : public Edge { + friend class GraphAdaptorExtender; + const Adaptor* _adaptor; + bool direction; + public: + + IncEdgeIt() { } + + IncEdgeIt(Invalid i) : Edge(i), direction(false) { } + + IncEdgeIt(const Adaptor& adaptor, const Node &n) : _adaptor(&adaptor) { + _adaptor->firstInc(static_cast(*this), direction, n); + } + + IncEdgeIt(const Adaptor& adaptor, const Edge &e, const Node &n) + : _adaptor(&adaptor), Edge(e) { + direction = (_adaptor->u(e) == n); + } + + IncEdgeIt& operator++() { + _adaptor->nextInc(*this, direction); + return *this; + } + }; + + Node baseNode(const OutArcIt &a) const { + return Parent::source(a); + } + Node runningNode(const OutArcIt &a) const { + return Parent::target(a); + } + + Node baseNode(const InArcIt &a) const { + return Parent::target(a); + } + Node runningNode(const InArcIt &a) const { + return Parent::source(a); + } + + Node baseNode(const IncEdgeIt &e) const { + return e.direction ? Parent::u(e) : Parent::v(e); + } + Node runningNode(const IncEdgeIt &e) const { + return e.direction ? Parent::v(e) : Parent::u(e); + } + + }; + +} + + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/graph_extender.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/graph_extender.h new file mode 100644 index 00000000000..755a8907f50 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/graph_extender.h @@ -0,0 +1,1332 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_BITS_GRAPH_EXTENDER_H +#define LEMON_BITS_GRAPH_EXTENDER_H + +#include + +#include +#include + +#include +#include + +//\ingroup graphbits +//\file +//\brief Extenders for the graph types +namespace lemon { + + // \ingroup graphbits + // + // \brief Extender for the digraph implementations + template + class DigraphExtender : public Base { + typedef Base Parent; + + public: + + typedef DigraphExtender Digraph; + + // Base extensions + + typedef typename Parent::Node Node; + typedef typename Parent::Arc Arc; + + int maxId(Node) const { + return Parent::maxNodeId(); + } + + int maxId(Arc) const { + return Parent::maxArcId(); + } + + static Node fromId(int id, Node) { + return Parent::nodeFromId(id); + } + + static Arc fromId(int id, Arc) { + return Parent::arcFromId(id); + } + + Node oppositeNode(const Node &node, const Arc &arc) const { + if (node == Parent::source(arc)) + return Parent::target(arc); + else if(node == Parent::target(arc)) + return Parent::source(arc); + else + return INVALID; + } + + // Alterable extension + + typedef AlterationNotifier NodeNotifier; + typedef AlterationNotifier ArcNotifier; + + + protected: + + mutable NodeNotifier node_notifier; + mutable ArcNotifier arc_notifier; + + public: + + NodeNotifier& notifier(Node) const { + return node_notifier; + } + + ArcNotifier& notifier(Arc) const { + return arc_notifier; + } + + class NodeIt : public Node { + const Digraph* _digraph; + public: + + NodeIt() {} + + NodeIt(Invalid i) : Node(i) { } + + explicit NodeIt(const Digraph& digraph) : _digraph(&digraph) { + _digraph->first(static_cast(*this)); + } + + NodeIt(const Digraph& digraph, const Node& node) + : Node(node), _digraph(&digraph) {} + + NodeIt& operator++() { + _digraph->next(*this); + return *this; + } + + }; + + + class ArcIt : public Arc { + const Digraph* _digraph; + public: + + ArcIt() { } + + ArcIt(Invalid i) : Arc(i) { } + + explicit ArcIt(const Digraph& digraph) : _digraph(&digraph) { + _digraph->first(static_cast(*this)); + } + + ArcIt(const Digraph& digraph, const Arc& arc) : + Arc(arc), _digraph(&digraph) { } + + ArcIt& operator++() { + _digraph->next(*this); + return *this; + } + + }; + + + class OutArcIt : public Arc { + const Digraph* _digraph; + public: + + OutArcIt() { } + + OutArcIt(Invalid i) : Arc(i) { } + + OutArcIt(const Digraph& digraph, const Node& node) + : _digraph(&digraph) { + _digraph->firstOut(*this, node); + } + + OutArcIt(const Digraph& digraph, const Arc& arc) + : Arc(arc), _digraph(&digraph) {} + + OutArcIt& operator++() { + _digraph->nextOut(*this); + return *this; + } + + }; + + + class InArcIt : public Arc { + const Digraph* _digraph; + public: + + InArcIt() { } + + InArcIt(Invalid i) : Arc(i) { } + + InArcIt(const Digraph& digraph, const Node& node) + : _digraph(&digraph) { + _digraph->firstIn(*this, node); + } + + InArcIt(const Digraph& digraph, const Arc& arc) : + Arc(arc), _digraph(&digraph) {} + + InArcIt& operator++() { + _digraph->nextIn(*this); + return *this; + } + + }; + + // \brief Base node of the iterator + // + // Returns the base node (i.e. the source in this case) of the iterator + Node baseNode(const OutArcIt &arc) const { + return Parent::source(arc); + } + // \brief Running node of the iterator + // + // Returns the running node (i.e. the target in this case) of the + // iterator + Node runningNode(const OutArcIt &arc) const { + return Parent::target(arc); + } + + // \brief Base node of the iterator + // + // Returns the base node (i.e. the target in this case) of the iterator + Node baseNode(const InArcIt &arc) const { + return Parent::target(arc); + } + // \brief Running node of the iterator + // + // Returns the running node (i.e. the source in this case) of the + // iterator + Node runningNode(const InArcIt &arc) const { + return Parent::source(arc); + } + + + template + class NodeMap + : public MapExtender > { + typedef MapExtender > Parent; + + public: + explicit NodeMap(const Digraph& digraph) + : Parent(digraph) {} + NodeMap(const Digraph& digraph, const _Value& value) + : Parent(digraph, value) {} + + private: + NodeMap& operator=(const NodeMap& cmap) { + return operator=(cmap); + } + + template + NodeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + + }; + + template + class ArcMap + : public MapExtender > { + typedef MapExtender > Parent; + + public: + explicit ArcMap(const Digraph& digraph) + : Parent(digraph) {} + ArcMap(const Digraph& digraph, const _Value& value) + : Parent(digraph, value) {} + + private: + ArcMap& operator=(const ArcMap& cmap) { + return operator=(cmap); + } + + template + ArcMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + }; + + + Node addNode() { + Node node = Parent::addNode(); + notifier(Node()).add(node); + return node; + } + + Arc addArc(const Node& from, const Node& to) { + Arc arc = Parent::addArc(from, to); + notifier(Arc()).add(arc); + return arc; + } + + void clear() { + notifier(Arc()).clear(); + notifier(Node()).clear(); + Parent::clear(); + } + + template + void build(const Digraph& digraph, NodeRefMap& nodeRef, ArcRefMap& arcRef) { + Parent::build(digraph, nodeRef, arcRef); + notifier(Node()).build(); + notifier(Arc()).build(); + } + + void erase(const Node& node) { + Arc arc; + Parent::firstOut(arc, node); + while (arc != INVALID ) { + erase(arc); + Parent::firstOut(arc, node); + } + + Parent::firstIn(arc, node); + while (arc != INVALID ) { + erase(arc); + Parent::firstIn(arc, node); + } + + notifier(Node()).erase(node); + Parent::erase(node); + } + + void erase(const Arc& arc) { + notifier(Arc()).erase(arc); + Parent::erase(arc); + } + + DigraphExtender() { + node_notifier.setContainer(*this); + arc_notifier.setContainer(*this); + } + + + ~DigraphExtender() { + arc_notifier.clear(); + node_notifier.clear(); + } + }; + + // \ingroup _graphbits + // + // \brief Extender for the Graphs + template + class GraphExtender : public Base { + typedef Base Parent; + + public: + + typedef GraphExtender Graph; + + typedef True UndirectedTag; + + typedef typename Parent::Node Node; + typedef typename Parent::Arc Arc; + typedef typename Parent::Edge Edge; + + // Graph extension + + int maxId(Node) const { + return Parent::maxNodeId(); + } + + int maxId(Arc) const { + return Parent::maxArcId(); + } + + int maxId(Edge) const { + return Parent::maxEdgeId(); + } + + static Node fromId(int id, Node) { + return Parent::nodeFromId(id); + } + + static Arc fromId(int id, Arc) { + return Parent::arcFromId(id); + } + + static Edge fromId(int id, Edge) { + return Parent::edgeFromId(id); + } + + Node oppositeNode(const Node &n, const Edge &e) const { + if( n == Parent::u(e)) + return Parent::v(e); + else if( n == Parent::v(e)) + return Parent::u(e); + else + return INVALID; + } + + Arc oppositeArc(const Arc &arc) const { + return Parent::direct(arc, !Parent::direction(arc)); + } + + using Parent::direct; + Arc direct(const Edge &edge, const Node &node) const { + return Parent::direct(edge, Parent::u(edge) == node); + } + + // Alterable extension + + typedef AlterationNotifier NodeNotifier; + typedef AlterationNotifier ArcNotifier; + typedef AlterationNotifier EdgeNotifier; + + + protected: + + mutable NodeNotifier node_notifier; + mutable ArcNotifier arc_notifier; + mutable EdgeNotifier edge_notifier; + + public: + + NodeNotifier& notifier(Node) const { + return node_notifier; + } + + ArcNotifier& notifier(Arc) const { + return arc_notifier; + } + + EdgeNotifier& notifier(Edge) const { + return edge_notifier; + } + + + + class NodeIt : public Node { + const Graph* _graph; + public: + + NodeIt() {} + + NodeIt(Invalid i) : Node(i) { } + + explicit NodeIt(const Graph& graph) : _graph(&graph) { + _graph->first(static_cast(*this)); + } + + NodeIt(const Graph& graph, const Node& node) + : Node(node), _graph(&graph) {} + + NodeIt& operator++() { + _graph->next(*this); + return *this; + } + + }; + + + class ArcIt : public Arc { + const Graph* _graph; + public: + + ArcIt() { } + + ArcIt(Invalid i) : Arc(i) { } + + explicit ArcIt(const Graph& graph) : _graph(&graph) { + _graph->first(static_cast(*this)); + } + + ArcIt(const Graph& graph, const Arc& arc) : + Arc(arc), _graph(&graph) { } + + ArcIt& operator++() { + _graph->next(*this); + return *this; + } + + }; + + + class OutArcIt : public Arc { + const Graph* _graph; + public: + + OutArcIt() { } + + OutArcIt(Invalid i) : Arc(i) { } + + OutArcIt(const Graph& graph, const Node& node) + : _graph(&graph) { + _graph->firstOut(*this, node); + } + + OutArcIt(const Graph& graph, const Arc& arc) + : Arc(arc), _graph(&graph) {} + + OutArcIt& operator++() { + _graph->nextOut(*this); + return *this; + } + + }; + + + class InArcIt : public Arc { + const Graph* _graph; + public: + + InArcIt() { } + + InArcIt(Invalid i) : Arc(i) { } + + InArcIt(const Graph& graph, const Node& node) + : _graph(&graph) { + _graph->firstIn(*this, node); + } + + InArcIt(const Graph& graph, const Arc& arc) : + Arc(arc), _graph(&graph) {} + + InArcIt& operator++() { + _graph->nextIn(*this); + return *this; + } + + }; + + + class EdgeIt : public Parent::Edge { + const Graph* _graph; + public: + + EdgeIt() { } + + EdgeIt(Invalid i) : Edge(i) { } + + explicit EdgeIt(const Graph& graph) : _graph(&graph) { + _graph->first(static_cast(*this)); + } + + EdgeIt(const Graph& graph, const Edge& edge) : + Edge(edge), _graph(&graph) { } + + EdgeIt& operator++() { + _graph->next(*this); + return *this; + } + + }; + + class IncEdgeIt : public Parent::Edge { + friend class GraphExtender; + const Graph* _graph; + bool _direction; + public: + + IncEdgeIt() { } + + IncEdgeIt(Invalid i) : Edge(i), _direction(false) { } + + IncEdgeIt(const Graph& graph, const Node &node) : _graph(&graph) { + _graph->firstInc(*this, _direction, node); + } + + IncEdgeIt(const Graph& graph, const Edge &edge, const Node &node) + : _graph(&graph), Edge(edge) { + _direction = (_graph->source(edge) == node); + } + + IncEdgeIt& operator++() { + _graph->nextInc(*this, _direction); + return *this; + } + }; + + // \brief Base node of the iterator + // + // Returns the base node (ie. the source in this case) of the iterator + Node baseNode(const OutArcIt &arc) const { + return Parent::source(static_cast(arc)); + } + // \brief Running node of the iterator + // + // Returns the running node (ie. the target in this case) of the + // iterator + Node runningNode(const OutArcIt &arc) const { + return Parent::target(static_cast(arc)); + } + + // \brief Base node of the iterator + // + // Returns the base node (ie. the target in this case) of the iterator + Node baseNode(const InArcIt &arc) const { + return Parent::target(static_cast(arc)); + } + // \brief Running node of the iterator + // + // Returns the running node (ie. the source in this case) of the + // iterator + Node runningNode(const InArcIt &arc) const { + return Parent::source(static_cast(arc)); + } + + // Base node of the iterator + // + // Returns the base node of the iterator + Node baseNode(const IncEdgeIt &edge) const { + return edge._direction ? this->u(edge) : this->v(edge); + } + // Running node of the iterator + // + // Returns the running node of the iterator + Node runningNode(const IncEdgeIt &edge) const { + return edge._direction ? this->v(edge) : this->u(edge); + } + + // Mappable extension + + template + class NodeMap + : public MapExtender > { + typedef MapExtender > Parent; + + public: + explicit NodeMap(const Graph& graph) + : Parent(graph) {} + NodeMap(const Graph& graph, const _Value& value) + : Parent(graph, value) {} + + private: + NodeMap& operator=(const NodeMap& cmap) { + return operator=(cmap); + } + + template + NodeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + + }; + + template + class ArcMap + : public MapExtender > { + typedef MapExtender > Parent; + + public: + explicit ArcMap(const Graph& graph) + : Parent(graph) {} + ArcMap(const Graph& graph, const _Value& value) + : Parent(graph, value) {} + + private: + ArcMap& operator=(const ArcMap& cmap) { + return operator=(cmap); + } + + template + ArcMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + }; + + + template + class EdgeMap + : public MapExtender > { + typedef MapExtender > Parent; + + public: + explicit EdgeMap(const Graph& graph) + : Parent(graph) {} + + EdgeMap(const Graph& graph, const _Value& value) + : Parent(graph, value) {} + + private: + EdgeMap& operator=(const EdgeMap& cmap) { + return operator=(cmap); + } + + template + EdgeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + + }; + + // Alteration extension + + Node addNode() { + Node node = Parent::addNode(); + notifier(Node()).add(node); + return node; + } + + Edge addEdge(const Node& from, const Node& to) { + Edge edge = Parent::addEdge(from, to); + notifier(Edge()).add(edge); + std::vector ev; + ev.push_back(Parent::direct(edge, true)); + ev.push_back(Parent::direct(edge, false)); + notifier(Arc()).add(ev); + return edge; + } + + void clear() { + notifier(Arc()).clear(); + notifier(Edge()).clear(); + notifier(Node()).clear(); + Parent::clear(); + } + + template + void build(const Graph& graph, NodeRefMap& nodeRef, + EdgeRefMap& edgeRef) { + Parent::build(graph, nodeRef, edgeRef); + notifier(Node()).build(); + notifier(Edge()).build(); + notifier(Arc()).build(); + } + + void erase(const Node& node) { + Arc arc; + Parent::firstOut(arc, node); + while (arc != INVALID ) { + erase(arc); + Parent::firstOut(arc, node); + } + + Parent::firstIn(arc, node); + while (arc != INVALID ) { + erase(arc); + Parent::firstIn(arc, node); + } + + notifier(Node()).erase(node); + Parent::erase(node); + } + + void erase(const Edge& edge) { + std::vector av; + av.push_back(Parent::direct(edge, true)); + av.push_back(Parent::direct(edge, false)); + notifier(Arc()).erase(av); + notifier(Edge()).erase(edge); + Parent::erase(edge); + } + + GraphExtender() { + node_notifier.setContainer(*this); + arc_notifier.setContainer(*this); + edge_notifier.setContainer(*this); + } + + ~GraphExtender() { + edge_notifier.clear(); + arc_notifier.clear(); + node_notifier.clear(); + } + + }; + + // \ingroup _graphbits + // + // \brief Extender for the BpGraphs + template + class BpGraphExtender : public Base { + typedef Base Parent; + + public: + + typedef BpGraphExtender BpGraph; + + typedef True UndirectedTag; + + typedef typename Parent::Node Node; + typedef typename Parent::RedNode RedNode; + typedef typename Parent::BlueNode BlueNode; + typedef typename Parent::Arc Arc; + typedef typename Parent::Edge Edge; + + // BpGraph extension + + using Parent::first; + using Parent::next; + using Parent::id; + + int maxId(Node) const { + return Parent::maxNodeId(); + } + + int maxId(RedNode) const { + return Parent::maxRedId(); + } + + int maxId(BlueNode) const { + return Parent::maxBlueId(); + } + + int maxId(Arc) const { + return Parent::maxArcId(); + } + + int maxId(Edge) const { + return Parent::maxEdgeId(); + } + + static Node fromId(int id, Node) { + return Parent::nodeFromId(id); + } + + static Arc fromId(int id, Arc) { + return Parent::arcFromId(id); + } + + static Edge fromId(int id, Edge) { + return Parent::edgeFromId(id); + } + + Node u(Edge e) const { return this->redNode(e); } + Node v(Edge e) const { return this->blueNode(e); } + + Node oppositeNode(const Node &n, const Edge &e) const { + if( n == u(e)) + return v(e); + else if( n == v(e)) + return u(e); + else + return INVALID; + } + + Arc oppositeArc(const Arc &arc) const { + return Parent::direct(arc, !Parent::direction(arc)); + } + + using Parent::direct; + Arc direct(const Edge &edge, const Node &node) const { + return Parent::direct(edge, Parent::redNode(edge) == node); + } + + RedNode asRedNode(const Node& node) const { + if (node == INVALID || Parent::blue(node)) { + return INVALID; + } else { + return Parent::asRedNodeUnsafe(node); + } + } + + BlueNode asBlueNode(const Node& node) const { + if (node == INVALID || Parent::red(node)) { + return INVALID; + } else { + return Parent::asBlueNodeUnsafe(node); + } + } + + // Alterable extension + + typedef AlterationNotifier NodeNotifier; + typedef AlterationNotifier RedNodeNotifier; + typedef AlterationNotifier BlueNodeNotifier; + typedef AlterationNotifier ArcNotifier; + typedef AlterationNotifier EdgeNotifier; + + + protected: + + mutable NodeNotifier node_notifier; + mutable RedNodeNotifier red_node_notifier; + mutable BlueNodeNotifier blue_node_notifier; + mutable ArcNotifier arc_notifier; + mutable EdgeNotifier edge_notifier; + + public: + + NodeNotifier& notifier(Node) const { + return node_notifier; + } + + RedNodeNotifier& notifier(RedNode) const { + return red_node_notifier; + } + + BlueNodeNotifier& notifier(BlueNode) const { + return blue_node_notifier; + } + + ArcNotifier& notifier(Arc) const { + return arc_notifier; + } + + EdgeNotifier& notifier(Edge) const { + return edge_notifier; + } + + + + class NodeIt : public Node { + const BpGraph* _graph; + public: + + NodeIt() {} + + NodeIt(Invalid i) : Node(i) { } + + explicit NodeIt(const BpGraph& graph) : _graph(&graph) { + _graph->first(static_cast(*this)); + } + + NodeIt(const BpGraph& graph, const Node& node) + : Node(node), _graph(&graph) {} + + NodeIt& operator++() { + _graph->next(*this); + return *this; + } + + }; + + class RedNodeIt : public RedNode { + const BpGraph* _graph; + public: + + RedNodeIt() {} + + RedNodeIt(Invalid i) : RedNode(i) { } + + explicit RedNodeIt(const BpGraph& graph) : _graph(&graph) { + _graph->first(static_cast(*this)); + } + + RedNodeIt(const BpGraph& graph, const RedNode& node) + : RedNode(node), _graph(&graph) {} + + RedNodeIt& operator++() { + _graph->next(static_cast(*this)); + return *this; + } + + }; + + class BlueNodeIt : public BlueNode { + const BpGraph* _graph; + public: + + BlueNodeIt() {} + + BlueNodeIt(Invalid i) : BlueNode(i) { } + + explicit BlueNodeIt(const BpGraph& graph) : _graph(&graph) { + _graph->first(static_cast(*this)); + } + + BlueNodeIt(const BpGraph& graph, const BlueNode& node) + : BlueNode(node), _graph(&graph) {} + + BlueNodeIt& operator++() { + _graph->next(static_cast(*this)); + return *this; + } + + }; + + + class ArcIt : public Arc { + const BpGraph* _graph; + public: + + ArcIt() { } + + ArcIt(Invalid i) : Arc(i) { } + + explicit ArcIt(const BpGraph& graph) : _graph(&graph) { + _graph->first(static_cast(*this)); + } + + ArcIt(const BpGraph& graph, const Arc& arc) : + Arc(arc), _graph(&graph) { } + + ArcIt& operator++() { + _graph->next(*this); + return *this; + } + + }; + + + class OutArcIt : public Arc { + const BpGraph* _graph; + public: + + OutArcIt() { } + + OutArcIt(Invalid i) : Arc(i) { } + + OutArcIt(const BpGraph& graph, const Node& node) + : _graph(&graph) { + _graph->firstOut(*this, node); + } + + OutArcIt(const BpGraph& graph, const Arc& arc) + : Arc(arc), _graph(&graph) {} + + OutArcIt& operator++() { + _graph->nextOut(*this); + return *this; + } + + }; + + + class InArcIt : public Arc { + const BpGraph* _graph; + public: + + InArcIt() { } + + InArcIt(Invalid i) : Arc(i) { } + + InArcIt(const BpGraph& graph, const Node& node) + : _graph(&graph) { + _graph->firstIn(*this, node); + } + + InArcIt(const BpGraph& graph, const Arc& arc) : + Arc(arc), _graph(&graph) {} + + InArcIt& operator++() { + _graph->nextIn(*this); + return *this; + } + + }; + + + class EdgeIt : public Parent::Edge { + const BpGraph* _graph; + public: + + EdgeIt() { } + + EdgeIt(Invalid i) : Edge(i) { } + + explicit EdgeIt(const BpGraph& graph) : _graph(&graph) { + _graph->first(static_cast(*this)); + } + + EdgeIt(const BpGraph& graph, const Edge& edge) : + Edge(edge), _graph(&graph) { } + + EdgeIt& operator++() { + _graph->next(*this); + return *this; + } + + }; + + class IncEdgeIt : public Parent::Edge { + friend class BpGraphExtender; + const BpGraph* _graph; + bool _direction; + public: + + IncEdgeIt() { } + + IncEdgeIt(Invalid i) : Edge(i), _direction(false) { } + + IncEdgeIt(const BpGraph& graph, const Node &node) : _graph(&graph) { + _graph->firstInc(*this, _direction, node); + } + + IncEdgeIt(const BpGraph& graph, const Edge &edge, const Node &node) + : _graph(&graph), Edge(edge) { + _direction = (_graph->source(edge) == node); + } + + IncEdgeIt& operator++() { + _graph->nextInc(*this, _direction); + return *this; + } + }; + + // \brief Base node of the iterator + // + // Returns the base node (ie. the source in this case) of the iterator + Node baseNode(const OutArcIt &arc) const { + return Parent::source(static_cast(arc)); + } + // \brief Running node of the iterator + // + // Returns the running node (ie. the target in this case) of the + // iterator + Node runningNode(const OutArcIt &arc) const { + return Parent::target(static_cast(arc)); + } + + // \brief Base node of the iterator + // + // Returns the base node (ie. the target in this case) of the iterator + Node baseNode(const InArcIt &arc) const { + return Parent::target(static_cast(arc)); + } + // \brief Running node of the iterator + // + // Returns the running node (ie. the source in this case) of the + // iterator + Node runningNode(const InArcIt &arc) const { + return Parent::source(static_cast(arc)); + } + + // Base node of the iterator + // + // Returns the base node of the iterator + Node baseNode(const IncEdgeIt &edge) const { + return edge._direction ? this->u(edge) : this->v(edge); + } + // Running node of the iterator + // + // Returns the running node of the iterator + Node runningNode(const IncEdgeIt &edge) const { + return edge._direction ? this->v(edge) : this->u(edge); + } + + // Mappable extension + + template + class NodeMap + : public MapExtender > { + typedef MapExtender > Parent; + + public: + explicit NodeMap(const BpGraph& bpgraph) + : Parent(bpgraph) {} + NodeMap(const BpGraph& bpgraph, const _Value& value) + : Parent(bpgraph, value) {} + + private: + NodeMap& operator=(const NodeMap& cmap) { + return operator=(cmap); + } + + template + NodeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + + }; + + template + class RedNodeMap + : public MapExtender > { + typedef MapExtender > Parent; + + public: + explicit RedNodeMap(const BpGraph& bpgraph) + : Parent(bpgraph) {} + RedNodeMap(const BpGraph& bpgraph, const _Value& value) + : Parent(bpgraph, value) {} + + private: + RedNodeMap& operator=(const RedNodeMap& cmap) { + return operator=(cmap); + } + + template + RedNodeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + + }; + + template + class BlueNodeMap + : public MapExtender > { + typedef MapExtender > Parent; + + public: + explicit BlueNodeMap(const BpGraph& bpgraph) + : Parent(bpgraph) {} + BlueNodeMap(const BpGraph& bpgraph, const _Value& value) + : Parent(bpgraph, value) {} + + private: + BlueNodeMap& operator=(const BlueNodeMap& cmap) { + return operator=(cmap); + } + + template + BlueNodeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + + }; + + template + class ArcMap + : public MapExtender > { + typedef MapExtender > Parent; + + public: + explicit ArcMap(const BpGraph& graph) + : Parent(graph) {} + ArcMap(const BpGraph& graph, const _Value& value) + : Parent(graph, value) {} + + private: + ArcMap& operator=(const ArcMap& cmap) { + return operator=(cmap); + } + + template + ArcMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + }; + + + template + class EdgeMap + : public MapExtender > { + typedef MapExtender > Parent; + + public: + explicit EdgeMap(const BpGraph& graph) + : Parent(graph) {} + + EdgeMap(const BpGraph& graph, const _Value& value) + : Parent(graph, value) {} + + private: + EdgeMap& operator=(const EdgeMap& cmap) { + return operator=(cmap); + } + + template + EdgeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + + }; + + // Alteration extension + + RedNode addRedNode() { + RedNode node = Parent::addRedNode(); + notifier(RedNode()).add(node); + notifier(Node()).add(node); + return node; + } + + BlueNode addBlueNode() { + BlueNode node = Parent::addBlueNode(); + notifier(BlueNode()).add(node); + notifier(Node()).add(node); + return node; + } + + Edge addEdge(const RedNode& from, const BlueNode& to) { + Edge edge = Parent::addEdge(from, to); + notifier(Edge()).add(edge); + std::vector av; + av.push_back(Parent::direct(edge, true)); + av.push_back(Parent::direct(edge, false)); + notifier(Arc()).add(av); + return edge; + } + + void clear() { + notifier(Arc()).clear(); + notifier(Edge()).clear(); + notifier(Node()).clear(); + notifier(BlueNode()).clear(); + notifier(RedNode()).clear(); + Parent::clear(); + } + + template + void build(const BpGraph& graph, NodeRefMap& nodeRef, + EdgeRefMap& edgeRef) { + Parent::build(graph, nodeRef, edgeRef); + notifier(RedNode()).build(); + notifier(BlueNode()).build(); + notifier(Node()).build(); + notifier(Edge()).build(); + notifier(Arc()).build(); + } + + void erase(const Node& node) { + Arc arc; + Parent::firstOut(arc, node); + while (arc != INVALID ) { + erase(arc); + Parent::firstOut(arc, node); + } + + Parent::firstIn(arc, node); + while (arc != INVALID ) { + erase(arc); + Parent::firstIn(arc, node); + } + + if (Parent::red(node)) { + notifier(RedNode()).erase(this->asRedNodeUnsafe(node)); + } else { + notifier(BlueNode()).erase(this->asBlueNodeUnsafe(node)); + } + + notifier(Node()).erase(node); + Parent::erase(node); + } + + void erase(const Edge& edge) { + std::vector av; + av.push_back(Parent::direct(edge, true)); + av.push_back(Parent::direct(edge, false)); + notifier(Arc()).erase(av); + notifier(Edge()).erase(edge); + Parent::erase(edge); + } + + BpGraphExtender() { + red_node_notifier.setContainer(*this); + blue_node_notifier.setContainer(*this); + node_notifier.setContainer(*this); + arc_notifier.setContainer(*this); + edge_notifier.setContainer(*this); + } + + ~BpGraphExtender() { + edge_notifier.clear(); + arc_notifier.clear(); + node_notifier.clear(); + blue_node_notifier.clear(); + red_node_notifier.clear(); + } + + }; + +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/lock.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/lock.h new file mode 100644 index 00000000000..09069998cdb --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/lock.h @@ -0,0 +1,65 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_BITS_LOCK_H +#define LEMON_BITS_LOCK_H + +#include +#if defined(LEMON_USE_PTHREAD) +#include +#elif defined(LEMON_USE_WIN32_THREADS) +#include +#endif + +namespace lemon { + namespace bits { + +#if defined(LEMON_USE_PTHREAD) + class Lock { + public: + Lock() { + pthread_mutex_init(&_lock, 0); + } + ~Lock() { + pthread_mutex_destroy(&_lock); + } + void lock() { + pthread_mutex_lock(&_lock); + } + void unlock() { + pthread_mutex_unlock(&_lock); + } + + private: + pthread_mutex_t _lock; + }; +#elif defined(LEMON_USE_WIN32_THREADS) + class Lock : public WinLock {}; +#else + class Lock { + public: + Lock() {} + ~Lock() {} + void lock() {} + void unlock() {} + }; +#endif + } +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/map_extender.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/map_extender.h new file mode 100644 index 00000000000..f32403e65ae --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/map_extender.h @@ -0,0 +1,332 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_BITS_MAP_EXTENDER_H +#define LEMON_BITS_MAP_EXTENDER_H + +#include + +#include + +#include +#include + +//\file +//\brief Extenders for iterable maps. + +namespace lemon { + + // \ingroup graphbits + // + // \brief Extender for maps + template + class MapExtender : public _Map { + typedef _Map Parent; + typedef typename Parent::GraphType GraphType; + + public: + + typedef MapExtender Map; + typedef typename Parent::Key Item; + + typedef typename Parent::Key Key; + typedef typename Parent::Value Value; + typedef typename Parent::Reference Reference; + typedef typename Parent::ConstReference ConstReference; + + typedef typename Parent::ReferenceMapTag ReferenceMapTag; + + class MapIt; + class ConstMapIt; + + friend class MapIt; + friend class ConstMapIt; + + public: + + MapExtender(const GraphType& graph) + : Parent(graph) {} + + MapExtender(const GraphType& graph, const Value& value) + : Parent(graph, value) {} + + private: + MapExtender& operator=(const MapExtender& cmap) { + return operator=(cmap); + } + + template + MapExtender& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + + public: + class MapIt : public Item { + typedef Item Parent; + + public: + + typedef typename Map::Value Value; + + MapIt() : map(NULL) {} + + MapIt(Invalid i) : Parent(i), map(NULL) {} + + explicit MapIt(Map& _map) : map(&_map) { + map->notifier()->first(*this); + } + + MapIt(const Map& _map, const Item& item) + : Parent(item), map(&_map) {} + + MapIt& operator++() { + map->notifier()->next(*this); + return *this; + } + + typename MapTraits::ConstReturnValue operator*() const { + return (*map)[*this]; + } + + typename MapTraits::ReturnValue operator*() { + return (*map)[*this]; + } + + void set(const Value& value) { + map->set(*this, value); + } + + protected: + Map* map; + + }; + + class ConstMapIt : public Item { + typedef Item Parent; + + public: + + typedef typename Map::Value Value; + + ConstMapIt() : map(NULL) {} + + ConstMapIt(Invalid i) : Parent(i), map(NULL) {} + + explicit ConstMapIt(Map& _map) : map(&_map) { + map->notifier()->first(*this); + } + + ConstMapIt(const Map& _map, const Item& item) + : Parent(item), map(_map) {} + + ConstMapIt& operator++() { + map->notifier()->next(*this); + return *this; + } + + typename MapTraits::ConstReturnValue operator*() const { + return map[*this]; + } + + protected: + const Map* map; + }; + + class ItemIt : public Item { + typedef Item Parent; + + public: + ItemIt() : map(NULL) {} + + + ItemIt(Invalid i) : Parent(i), map(NULL) {} + + explicit ItemIt(Map& _map) : map(&_map) { + map->notifier()->first(*this); + } + + ItemIt(const Map& _map, const Item& item) + : Parent(item), map(&_map) {} + + ItemIt& operator++() { + map->notifier()->next(*this); + return *this; + } + + protected: + const Map* map; + + }; + }; + + // \ingroup graphbits + // + // \brief Extender for maps which use a subset of the items. + template + class SubMapExtender : public _Map { + typedef _Map Parent; + typedef _Graph GraphType; + + public: + + typedef SubMapExtender Map; + typedef typename Parent::Key Item; + + typedef typename Parent::Key Key; + typedef typename Parent::Value Value; + typedef typename Parent::Reference Reference; + typedef typename Parent::ConstReference ConstReference; + + typedef typename Parent::ReferenceMapTag ReferenceMapTag; + + class MapIt; + class ConstMapIt; + + friend class MapIt; + friend class ConstMapIt; + + public: + + SubMapExtender(const GraphType& _graph) + : Parent(_graph), graph(_graph) {} + + SubMapExtender(const GraphType& _graph, const Value& _value) + : Parent(_graph, _value), graph(_graph) {} + + private: + SubMapExtender& operator=(const SubMapExtender& cmap) { + return operator=(cmap); + } + + template + SubMapExtender& operator=(const CMap& cmap) { + checkConcept, CMap>(); + Item it; + for (graph.first(it); it != INVALID; graph.next(it)) { + Parent::set(it, cmap[it]); + } + return *this; + } + + public: + class MapIt : public Item { + typedef Item Parent; + + public: + typedef typename Map::Value Value; + + MapIt() : map(NULL) {} + + MapIt(Invalid i) : Parent(i), map(NULL) { } + + explicit MapIt(Map& _map) : map(&_map) { + map->graph.first(*this); + } + + MapIt(const Map& _map, const Item& item) + : Parent(item), map(&_map) {} + + MapIt& operator++() { + map->graph.next(*this); + return *this; + } + + typename MapTraits::ConstReturnValue operator*() const { + return (*map)[*this]; + } + + typename MapTraits::ReturnValue operator*() { + return (*map)[*this]; + } + + void set(const Value& value) { + map->set(*this, value); + } + + protected: + Map* map; + + }; + + class ConstMapIt : public Item { + typedef Item Parent; + + public: + + typedef typename Map::Value Value; + + ConstMapIt() : map(NULL) {} + + ConstMapIt(Invalid i) : Parent(i), map(NULL) { } + + explicit ConstMapIt(Map& _map) : map(&_map) { + map->graph.first(*this); + } + + ConstMapIt(const Map& _map, const Item& item) + : Parent(item), map(&_map) {} + + ConstMapIt& operator++() { + map->graph.next(*this); + return *this; + } + + typename MapTraits::ConstReturnValue operator*() const { + return (*map)[*this]; + } + + protected: + const Map* map; + }; + + class ItemIt : public Item { + typedef Item Parent; + + public: + ItemIt() : map(NULL) {} + + + ItemIt(Invalid i) : Parent(i), map(NULL) { } + + explicit ItemIt(Map& _map) : map(&_map) { + map->graph.first(*this); + } + + ItemIt(const Map& _map, const Item& item) + : Parent(item), map(&_map) {} + + ItemIt& operator++() { + map->graph.next(*this); + return *this; + } + + protected: + const Map* map; + + }; + + private: + + const GraphType& graph; + + }; + +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/path_dump.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/path_dump.h new file mode 100644 index 00000000000..3e8cb8dd58c --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/path_dump.h @@ -0,0 +1,177 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_BITS_PATH_DUMP_H +#define LEMON_BITS_PATH_DUMP_H + +#include +#include + +namespace lemon { + + template + class PredMapPath { + public: + typedef True RevPathTag; + + typedef _Digraph Digraph; + typedef typename Digraph::Arc Arc; + typedef _PredMap PredMap; + + PredMapPath(const Digraph& _digraph, const PredMap& _predMap, + typename Digraph::Node _target) + : digraph(_digraph), predMap(_predMap), target(_target) {} + + int length() const { + int len = 0; + typename Digraph::Node node = target; + typename Digraph::Arc arc; + while ((arc = predMap[node]) != INVALID) { + node = digraph.source(arc); + ++len; + } + return len; + } + + bool empty() const { + return predMap[target] == INVALID; + } + + class RevArcIt { + public: + RevArcIt() {} + RevArcIt(Invalid) : path(0), current(INVALID) {} + RevArcIt(const PredMapPath& _path) + : path(&_path), current(_path.target) { + if (path->predMap[current] == INVALID) current = INVALID; + } + + operator const typename Digraph::Arc() const { + return path->predMap[current]; + } + + RevArcIt& operator++() { + current = path->digraph.source(path->predMap[current]); + if (path->predMap[current] == INVALID) current = INVALID; + return *this; + } + + bool operator==(const RevArcIt& e) const { + return current == e.current; + } + + bool operator!=(const RevArcIt& e) const { + return current != e.current; + } + + bool operator<(const RevArcIt& e) const { + return current < e.current; + } + + private: + const PredMapPath* path; + typename Digraph::Node current; + }; + + private: + const Digraph& digraph; + const PredMap& predMap; + typename Digraph::Node target; + }; + + + template + class PredMatrixMapPath { + public: + typedef True RevPathTag; + + typedef _Digraph Digraph; + typedef typename Digraph::Arc Arc; + typedef _PredMatrixMap PredMatrixMap; + + PredMatrixMapPath(const Digraph& _digraph, + const PredMatrixMap& _predMatrixMap, + typename Digraph::Node _source, + typename Digraph::Node _target) + : digraph(_digraph), predMatrixMap(_predMatrixMap), + source(_source), target(_target) {} + + int length() const { + int len = 0; + typename Digraph::Node node = target; + typename Digraph::Arc arc; + while ((arc = predMatrixMap(source, node)) != INVALID) { + node = digraph.source(arc); + ++len; + } + return len; + } + + bool empty() const { + return predMatrixMap(source, target) == INVALID; + } + + class RevArcIt { + public: + RevArcIt() {} + RevArcIt(Invalid) : path(0), current(INVALID) {} + RevArcIt(const PredMatrixMapPath& _path) + : path(&_path), current(_path.target) { + if (path->predMatrixMap(path->source, current) == INVALID) + current = INVALID; + } + + operator const typename Digraph::Arc() const { + return path->predMatrixMap(path->source, current); + } + + RevArcIt& operator++() { + current = + path->digraph.source(path->predMatrixMap(path->source, current)); + if (path->predMatrixMap(path->source, current) == INVALID) + current = INVALID; + return *this; + } + + bool operator==(const RevArcIt& e) const { + return current == e.current; + } + + bool operator!=(const RevArcIt& e) const { + return current != e.current; + } + + bool operator<(const RevArcIt& e) const { + return current < e.current; + } + + private: + const PredMatrixMapPath* path; + typename Digraph::Node current; + }; + + private: + const Digraph& digraph; + const PredMatrixMap& predMatrixMap; + typename Digraph::Node source; + typename Digraph::Node target; + }; + +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/solver_bits.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/solver_bits.h new file mode 100644 index 00000000000..c34212be8cd --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/solver_bits.h @@ -0,0 +1,194 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_BITS_SOLVER_BITS_H +#define LEMON_BITS_SOLVER_BITS_H + +#include + +namespace lemon { + + namespace _solver_bits { + + class VarIndex { + private: + struct ItemT { + int prev, next; + int index; + }; + std::vector items; + int first_item, last_item, first_free_item; + + std::vector cross; + + public: + + VarIndex() + : first_item(-1), last_item(-1), first_free_item(-1) { + } + + void clear() { + first_item = -1; + last_item = -1; + first_free_item = -1; + items.clear(); + cross.clear(); + } + + int addIndex(int idx) { + int n; + if (first_free_item == -1) { + n = items.size(); + items.push_back(ItemT()); + } else { + n = first_free_item; + first_free_item = items[n].next; + if (first_free_item != -1) { + items[first_free_item].prev = -1; + } + } + items[n].index = idx; + if (static_cast(cross.size()) <= idx) { + cross.resize(idx + 1, -1); + } + cross[idx] = n; + + items[n].prev = last_item; + items[n].next = -1; + if (last_item != -1) { + items[last_item].next = n; + } else { + first_item = n; + } + last_item = n; + + return n; + } + + int addIndex(int idx, int n) { + while (n >= static_cast(items.size())) { + items.push_back(ItemT()); + items.back().prev = -1; + items.back().next = first_free_item; + if (first_free_item != -1) { + items[first_free_item].prev = items.size() - 1; + } + first_free_item = items.size() - 1; + } + if (items[n].next != -1) { + items[items[n].next].prev = items[n].prev; + } + if (items[n].prev != -1) { + items[items[n].prev].next = items[n].next; + } else { + first_free_item = items[n].next; + } + + items[n].index = idx; + if (static_cast(cross.size()) <= idx) { + cross.resize(idx + 1, -1); + } + cross[idx] = n; + + items[n].prev = last_item; + items[n].next = -1; + if (last_item != -1) { + items[last_item].next = n; + } else { + first_item = n; + } + last_item = n; + + return n; + } + + void eraseIndex(int idx) { + int n = cross[idx]; + + if (items[n].prev != -1) { + items[items[n].prev].next = items[n].next; + } else { + first_item = items[n].next; + } + if (items[n].next != -1) { + items[items[n].next].prev = items[n].prev; + } else { + last_item = items[n].prev; + } + + if (first_free_item != -1) { + items[first_free_item].prev = n; + } + items[n].next = first_free_item; + items[n].prev = -1; + first_free_item = n; + + while (!cross.empty() && cross.back() == -1) { + cross.pop_back(); + } + } + + int maxIndex() const { + return cross.size() - 1; + } + + void shiftIndices(int idx) { + for (int i = idx + 1; i < static_cast(cross.size()); ++i) { + cross[i - 1] = cross[i]; + if (cross[i] != -1) { + --items[cross[i]].index; + } + } + cross.back() = -1; + cross.pop_back(); + while (!cross.empty() && cross.back() == -1) { + cross.pop_back(); + } + } + + void relocateIndex(int idx, int jdx) { + cross[idx] = cross[jdx]; + items[cross[jdx]].index = idx; + cross[jdx] = -1; + + while (!cross.empty() && cross.back() == -1) { + cross.pop_back(); + } + } + + int operator[](int idx) const { + return cross[idx]; + } + + int operator()(int fdx) const { + return items[fdx].index; + } + + void firstItem(int& fdx) const { + fdx = first_item; + } + + void nextItem(int& fdx) const { + fdx = items[fdx].next; + } + + }; + } +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/traits.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/traits.h new file mode 100644 index 00000000000..53fbd45647a --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/traits.h @@ -0,0 +1,388 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_BITS_TRAITS_H +#define LEMON_BITS_TRAITS_H + +//\file +//\brief Traits for graphs and maps +// + +#include + +namespace lemon { + + struct InvalidType {}; + + template + class ItemSetTraits {}; + + + template + struct NodeNotifierIndicator { + typedef InvalidType Type; + }; + template + struct NodeNotifierIndicator< + GR, + typename enable_if::type + > { + typedef typename GR::NodeNotifier Type; + }; + + template + class ItemSetTraits { + public: + + typedef GR Graph; + typedef GR Digraph; + + typedef typename GR::Node Item; + typedef typename GR::NodeIt ItemIt; + + typedef typename NodeNotifierIndicator::Type ItemNotifier; + + template + class Map : public GR::template NodeMap { + typedef typename GR::template NodeMap Parent; + + public: + typedef typename GR::template NodeMap Type; + typedef typename Parent::Value Value; + + Map(const GR& _digraph) : Parent(_digraph) {} + Map(const GR& _digraph, const Value& _value) + : Parent(_digraph, _value) {} + + }; + + }; + + template + struct ArcNotifierIndicator { + typedef InvalidType Type; + }; + template + struct ArcNotifierIndicator< + GR, + typename enable_if::type + > { + typedef typename GR::ArcNotifier Type; + }; + + template + class ItemSetTraits { + public: + + typedef GR Graph; + typedef GR Digraph; + + typedef typename GR::Arc Item; + typedef typename GR::ArcIt ItemIt; + + typedef typename ArcNotifierIndicator::Type ItemNotifier; + + template + class Map : public GR::template ArcMap { + typedef typename GR::template ArcMap Parent; + + public: + typedef typename GR::template ArcMap Type; + typedef typename Parent::Value Value; + + Map(const GR& _digraph) : Parent(_digraph) {} + Map(const GR& _digraph, const Value& _value) + : Parent(_digraph, _value) {} + }; + + }; + + template + struct EdgeNotifierIndicator { + typedef InvalidType Type; + }; + template + struct EdgeNotifierIndicator< + GR, + typename enable_if::type + > { + typedef typename GR::EdgeNotifier Type; + }; + + template + class ItemSetTraits { + public: + + typedef GR Graph; + typedef GR Digraph; + + typedef typename GR::Edge Item; + typedef typename GR::EdgeIt ItemIt; + + typedef typename EdgeNotifierIndicator::Type ItemNotifier; + + template + class Map : public GR::template EdgeMap { + typedef typename GR::template EdgeMap Parent; + + public: + typedef typename GR::template EdgeMap Type; + typedef typename Parent::Value Value; + + Map(const GR& _digraph) : Parent(_digraph) {} + Map(const GR& _digraph, const Value& _value) + : Parent(_digraph, _value) {} + }; + + }; + + template + struct RedNodeNotifierIndicator { + typedef InvalidType Type; + }; + template + struct RedNodeNotifierIndicator< + GR, + typename enable_if::type + > { + typedef typename GR::RedNodeNotifier Type; + }; + + template + class ItemSetTraits { + public: + + typedef GR BpGraph; + typedef GR Graph; + typedef GR Digraph; + + typedef typename GR::RedNode Item; + typedef typename GR::RedNodeIt ItemIt; + + typedef typename RedNodeNotifierIndicator::Type ItemNotifier; + + template + class Map : public GR::template RedNodeMap { + typedef typename GR::template RedNodeMap Parent; + + public: + typedef typename GR::template RedNodeMap Type; + typedef typename Parent::Value Value; + + Map(const GR& _bpgraph) : Parent(_bpgraph) {} + Map(const GR& _bpgraph, const Value& _value) + : Parent(_bpgraph, _value) {} + + }; + + }; + + template + struct BlueNodeNotifierIndicator { + typedef InvalidType Type; + }; + template + struct BlueNodeNotifierIndicator< + GR, + typename enable_if::type + > { + typedef typename GR::BlueNodeNotifier Type; + }; + + template + class ItemSetTraits { + public: + + typedef GR BpGraph; + typedef GR Graph; + typedef GR Digraph; + + typedef typename GR::BlueNode Item; + typedef typename GR::BlueNodeIt ItemIt; + + typedef typename BlueNodeNotifierIndicator::Type ItemNotifier; + + template + class Map : public GR::template BlueNodeMap { + typedef typename GR::template BlueNodeMap Parent; + + public: + typedef typename GR::template BlueNodeMap Type; + typedef typename Parent::Value Value; + + Map(const GR& _bpgraph) : Parent(_bpgraph) {} + Map(const GR& _bpgraph, const Value& _value) + : Parent(_bpgraph, _value) {} + + }; + + }; + + template + struct MapTraits { + typedef False ReferenceMapTag; + + typedef typename Map::Key Key; + typedef typename Map::Value Value; + + typedef Value ConstReturnValue; + typedef Value ReturnValue; + }; + + template + struct MapTraits< + Map, typename enable_if::type > + { + typedef True ReferenceMapTag; + + typedef typename Map::Key Key; + typedef typename Map::Value Value; + + typedef typename Map::ConstReference ConstReturnValue; + typedef typename Map::Reference ReturnValue; + + typedef typename Map::ConstReference ConstReference; + typedef typename Map::Reference Reference; + }; + + template + struct MatrixMapTraits { + typedef False ReferenceMapTag; + + typedef typename MatrixMap::FirstKey FirstKey; + typedef typename MatrixMap::SecondKey SecondKey; + typedef typename MatrixMap::Value Value; + + typedef Value ConstReturnValue; + typedef Value ReturnValue; + }; + + template + struct MatrixMapTraits< + MatrixMap, typename enable_if::type > + { + typedef True ReferenceMapTag; + + typedef typename MatrixMap::FirstKey FirstKey; + typedef typename MatrixMap::SecondKey SecondKey; + typedef typename MatrixMap::Value Value; + + typedef typename MatrixMap::ConstReference ConstReturnValue; + typedef typename MatrixMap::Reference ReturnValue; + + typedef typename MatrixMap::ConstReference ConstReference; + typedef typename MatrixMap::Reference Reference; + }; + + // Indicators for the tags + + template + struct NodeNumTagIndicator { + static const bool value = false; + }; + + template + struct NodeNumTagIndicator< + GR, + typename enable_if::type + > { + static const bool value = true; + }; + + template + struct ArcNumTagIndicator { + static const bool value = false; + }; + + template + struct ArcNumTagIndicator< + GR, + typename enable_if::type + > { + static const bool value = true; + }; + + template + struct EdgeNumTagIndicator { + static const bool value = false; + }; + + template + struct EdgeNumTagIndicator< + GR, + typename enable_if::type + > { + static const bool value = true; + }; + + template + struct FindArcTagIndicator { + static const bool value = false; + }; + + template + struct FindArcTagIndicator< + GR, + typename enable_if::type + > { + static const bool value = true; + }; + + template + struct FindEdgeTagIndicator { + static const bool value = false; + }; + + template + struct FindEdgeTagIndicator< + GR, + typename enable_if::type + > { + static const bool value = true; + }; + + template + struct UndirectedTagIndicator { + static const bool value = false; + }; + + template + struct UndirectedTagIndicator< + GR, + typename enable_if::type + > { + static const bool value = true; + }; + + template + struct BuildTagIndicator { + static const bool value = false; + }; + + template + struct BuildTagIndicator< + GR, + typename enable_if::type + > { + static const bool value = true; + }; + +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/variant.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/variant.h new file mode 100644 index 00000000000..b8301892e61 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/variant.h @@ -0,0 +1,494 @@ +/* -*- 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_BITS_VARIANT_H +#define LEMON_BITS_VARIANT_H + +#include + +// \file +// \brief Variant types + +namespace lemon { + + namespace _variant_bits { + + template + struct CTMax { + static const int value = left < right ? right : left; + }; + + } + + + // \brief Simple Variant type for two types + // + // Simple Variant type for two types. The Variant type is a type-safe + // union. C++ has strong limitations for using unions, for + // example you cannot store a type with non-default constructor or + // destructor in a union. This class always knowns the current + // state of the variant and it cares for the proper construction + // and destruction. + template + class BiVariant { + public: + + // \brief The \c First type. + typedef _First First; + // \brief The \c Second type. + typedef _Second Second; + + // \brief Constructor + // + // This constructor initalizes to the default value of the \c First + // type. + BiVariant() { + flag = true; + new(reinterpret_cast(data)) First(); + } + + // \brief Constructor + // + // This constructor initalizes to the given value of the \c First + // type. + BiVariant(const First& f) { + flag = true; + new(reinterpret_cast(data)) First(f); + } + + // \brief Constructor + // + // This constructor initalizes to the given value of the \c + // Second type. + BiVariant(const Second& s) { + flag = false; + new(reinterpret_cast(data)) Second(s); + } + + // \brief Copy constructor + // + // Copy constructor + BiVariant(const BiVariant& bivariant) { + flag = bivariant.flag; + if (flag) { + new(reinterpret_cast(data)) First(bivariant.first()); + } else { + new(reinterpret_cast(data)) Second(bivariant.second()); + } + } + + // \brief Destrcutor + // + // Destructor + ~BiVariant() { + destroy(); + } + + // \brief Set to the default value of the \c First type. + // + // This function sets the variant to the default value of the \c + // First type. + BiVariant& setFirst() { + destroy(); + flag = true; + new(reinterpret_cast(data)) First(); + return *this; + } + + // \brief Set to the given value of the \c First type. + // + // This function sets the variant to the given value of the \c + // First type. + BiVariant& setFirst(const First& f) { + destroy(); + flag = true; + new(reinterpret_cast(data)) First(f); + return *this; + } + + // \brief Set to the default value of the \c Second type. + // + // This function sets the variant to the default value of the \c + // Second type. + BiVariant& setSecond() { + destroy(); + flag = false; + new(reinterpret_cast(data)) Second(); + return *this; + } + + // \brief Set to the given value of the \c Second type. + // + // This function sets the variant to the given value of the \c + // Second type. + BiVariant& setSecond(const Second& s) { + destroy(); + flag = false; + new(reinterpret_cast(data)) Second(s); + return *this; + } + + // \brief Operator form of the \c setFirst() + BiVariant& operator=(const First& f) { + return setFirst(f); + } + + // \brief Operator form of the \c setSecond() + BiVariant& operator=(const Second& s) { + return setSecond(s); + } + + // \brief Assign operator + BiVariant& operator=(const BiVariant& bivariant) { + if (this == &bivariant) return *this; + destroy(); + flag = bivariant.flag; + if (flag) { + new(reinterpret_cast(data)) First(bivariant.first()); + } else { + new(reinterpret_cast(data)) Second(bivariant.second()); + } + return *this; + } + + // \brief Reference to the value + // + // Reference to the value of the \c First type. + // \pre The BiVariant should store value of \c First type. + First& first() { + LEMON_DEBUG(flag, "Variant wrong state"); + return *reinterpret_cast(data); + } + + // \brief Const reference to the value + // + // Const reference to the value of the \c First type. + // \pre The BiVariant should store value of \c First type. + const First& first() const { + LEMON_DEBUG(flag, "Variant wrong state"); + return *reinterpret_cast(data); + } + + // \brief Operator form of the \c first() + operator First&() { return first(); } + // \brief Operator form of the const \c first() + operator const First&() const { return first(); } + + // \brief Reference to the value + // + // Reference to the value of the \c Second type. + // \pre The BiVariant should store value of \c Second type. + Second& second() { + LEMON_DEBUG(!flag, "Variant wrong state"); + return *reinterpret_cast(data); + } + + // \brief Const reference to the value + // + // Const reference to the value of the \c Second type. + // \pre The BiVariant should store value of \c Second type. + const Second& second() const { + LEMON_DEBUG(!flag, "Variant wrong state"); + return *reinterpret_cast(data); + } + + // \brief Operator form of the \c second() + operator Second&() { return second(); } + // \brief Operator form of the const \c second() + operator const Second&() const { return second(); } + + // \brief %True when the variant is in the first state + // + // %True when the variant stores value of the \c First type. + bool firstState() const { return flag; } + + // \brief %True when the variant is in the second state + // + // %True when the variant stores value of the \c Second type. + bool secondState() const { return !flag; } + + private: + + void destroy() { + if (flag) { + reinterpret_cast(data)->~First(); + } else { + reinterpret_cast(data)->~Second(); + } + } + + char data[_variant_bits::CTMax::value]; + bool flag; + }; + + namespace _variant_bits { + + template + struct Memory { + + typedef typename _TypeMap::template Map<_idx>::Type Current; + + static void destroy(int index, char* place) { + if (index == _idx) { + reinterpret_cast(place)->~Current(); + } else { + Memory<_idx - 1, _TypeMap>::destroy(index, place); + } + } + + static void copy(int index, char* to, const char* from) { + if (index == _idx) { + new (reinterpret_cast(to)) + Current(reinterpret_cast(from)); + } else { + Memory<_idx - 1, _TypeMap>::copy(index, to, from); + } + } + + }; + + template + struct Memory<-1, _TypeMap> { + + static void destroy(int, char*) { + LEMON_DEBUG(false, "Variant wrong index."); + } + + static void copy(int, char*, const char*) { + LEMON_DEBUG(false, "Variant wrong index."); + } + }; + + template + struct Size { + static const int value = + CTMax::Type), + Size<_idx - 1, _TypeMap>::value>::value; + }; + + template + struct Size<0, _TypeMap> { + static const int value = + sizeof(typename _TypeMap::template Map<0>::Type); + }; + + } + + // \brief Variant type + // + // Simple Variant type. The Variant type is a type-safe union. + // C++ has strong limitations for using unions, for example you + // cannot store type with non-default constructor or destructor in + // a union. This class always knowns the current state of the + // variant and it cares for the proper construction and + // destruction. + // + // \param _num The number of the types which can be stored in the + // variant type. + // \param _TypeMap This class describes the types of the Variant. The + // _TypeMap::Map::Type should be a valid type for each index + // in the range {0, 1, ..., _num - 1}. The \c VariantTypeMap is helper + // class to define such type mappings up to 10 types. + // + // And the usage of the class: + //\code + // typedef Variant<3, VariantTypeMap > MyVariant; + // MyVariant var; + // var.set<0>(12); + // std::cout << var.get<0>() << std::endl; + // var.set<1>("alpha"); + // std::cout << var.get<1>() << std::endl; + // var.set<2>(0.75); + // std::cout << var.get<2>() << std::endl; + //\endcode + // + // The result of course: + //\code + // 12 + // alpha + // 0.75 + //\endcode + template + class Variant { + public: + + static const int num = _num; + + typedef _TypeMap TypeMap; + + // \brief Constructor + // + // This constructor initalizes to the default value of the \c type + // with 0 index. + Variant() { + flag = 0; + new(reinterpret_cast::Type*>(data)) + typename TypeMap::template Map<0>::Type(); + } + + + // \brief Copy constructor + // + // Copy constructor + Variant(const Variant& variant) { + flag = variant.flag; + _variant_bits::Memory::copy(flag, data, variant.data); + } + + // \brief Assign operator + // + // Assign operator + Variant& operator=(const Variant& variant) { + if (this == &variant) return *this; + _variant_bits::Memory:: + destroy(flag, data); + flag = variant.flag; + _variant_bits::Memory:: + copy(flag, data, variant.data); + return *this; + } + + // \brief Destrcutor + // + // Destructor + ~Variant() { + _variant_bits::Memory::destroy(flag, data); + } + + // \brief Set to the default value of the type with \c _idx index. + // + // This function sets the variant to the default value of the + // type with \c _idx index. + template + Variant& set() { + _variant_bits::Memory::destroy(flag, data); + flag = _idx; + new(reinterpret_cast::Type*>(data)) + typename TypeMap::template Map<_idx>::Type(); + return *this; + } + + // \brief Set to the given value of the type with \c _idx index. + // + // This function sets the variant to the given value of the type + // with \c _idx index. + template + Variant& set(const typename _TypeMap::template Map<_idx>::Type& init) { + _variant_bits::Memory::destroy(flag, data); + flag = _idx; + new(reinterpret_cast::Type*>(data)) + typename TypeMap::template Map<_idx>::Type(init); + return *this; + } + + // \brief Gets the current value of the type with \c _idx index. + // + // Gets the current value of the type with \c _idx index. + template + const typename TypeMap::template Map<_idx>::Type& get() const { + LEMON_DEBUG(_idx == flag, "Variant wrong index"); + return *reinterpret_cast::Type*>(data); + } + + // \brief Gets the current value of the type with \c _idx index. + // + // Gets the current value of the type with \c _idx index. + template + typename _TypeMap::template Map<_idx>::Type& get() { + LEMON_DEBUG(_idx == flag, "Variant wrong index"); + return *reinterpret_cast::Type*> + (data); + } + + // \brief Returns the current state of the variant. + // + // Returns the current state of the variant. + int state() const { + return flag; + } + + private: + + char data[_variant_bits::Size::value]; + int flag; + }; + + namespace _variant_bits { + + template + struct Get { + typedef typename Get<_index - 1, typename _List::Next>::Type Type; + }; + + template + struct Get<0, _List> { + typedef typename _List::Type Type; + }; + + struct List {}; + + template + struct Insert { + typedef _List Next; + typedef _Type Type; + }; + + template + struct Mapper { + typedef List L10; + typedef Insert<_T9, L10> L9; + typedef Insert<_T8, L9> L8; + typedef Insert<_T7, L8> L7; + typedef Insert<_T6, L7> L6; + typedef Insert<_T5, L6> L5; + typedef Insert<_T4, L5> L4; + typedef Insert<_T3, L4> L3; + typedef Insert<_T2, L3> L2; + typedef Insert<_T1, L2> L1; + typedef Insert<_T0, L1> L0; + typedef typename Get<_idx, L0>::Type Type; + }; + + } + + // \brief Helper class for Variant + // + // Helper class to define type mappings for Variant. This class + // converts the template parameters to be mappable by integer. + // \see Variant + template < + typename _T0, + typename _T1 = void, typename _T2 = void, typename _T3 = void, + typename _T4 = void, typename _T5 = void, typename _T6 = void, + typename _T7 = void, typename _T8 = void, typename _T9 = void> + struct VariantTypeMap { + template + struct Map { + typedef typename _variant_bits:: + Mapper<_idx, _T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9>::Type + Type; + }; + }; + +} + + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/vector_map.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/vector_map.h new file mode 100644 index 00000000000..d60841defbd --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/vector_map.h @@ -0,0 +1,244 @@ +/* -*- 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_BITS_VECTOR_MAP_H +#define LEMON_BITS_VECTOR_MAP_H + +#include +#include + +#include +#include + +#include +#include + +//\ingroup graphbits +// +//\file +//\brief Vector based graph maps. +namespace lemon { + + // \ingroup graphbits + // + // \brief Graph map based on the std::vector storage. + // + // The VectorMap template class is graph map structure that automatically + // updates the map when a key is added to or erased from the graph. + // This map type uses std::vector to store the values. + // + // \tparam _Graph The graph this map is attached to. + // \tparam _Item The item type of the graph items. + // \tparam _Value The value type of the map. + template + class VectorMap + : public ItemSetTraits<_Graph, _Item>::ItemNotifier::ObserverBase { + private: + + // The container type of the map. + typedef std::vector<_Value> Container; + + public: + + // The graph type of the map. + typedef _Graph GraphType; + // The item type of the map. + typedef _Item Item; + // The reference map tag. + typedef True ReferenceMapTag; + + // The key type of the map. + typedef _Item Key; + // The value type of the map. + typedef _Value Value; + + // The notifier type. + typedef typename ItemSetTraits<_Graph, _Item>::ItemNotifier Notifier; + + // The map type. + typedef VectorMap Map; + + // The reference type of the map; + typedef typename Container::reference Reference; + // The const reference type of the map; + typedef typename Container::const_reference ConstReference; + + private: + + // The base class of the map. + typedef typename Notifier::ObserverBase Parent; + + public: + + // \brief Constructor to attach the new map into the notifier. + // + // It constructs a map and attachs it into the notifier. + // It adds all the items of the graph to the map. + VectorMap(const GraphType& graph) { + Parent::attach(graph.notifier(Item())); + container.resize(Parent::notifier()->maxId() + 1); + } + + // \brief Constructor uses given value to initialize the map. + // + // It constructs a map uses a given value to initialize the map. + // It adds all the items of the graph to the map. + VectorMap(const GraphType& graph, const Value& value) { + Parent::attach(graph.notifier(Item())); + container.resize(Parent::notifier()->maxId() + 1, value); + } + + private: + // \brief Copy constructor + // + // Copy constructor. + VectorMap(const VectorMap& _copy) : Parent() { + if (_copy.attached()) { + Parent::attach(*_copy.notifier()); + container = _copy.container; + } + } + + // \brief Assign operator. + // + // This operator assigns for each item in the map the + // value mapped to the same item in the copied map. + // The parameter map should be indiced with the same + // itemset because this assign operator does not change + // the container of the map. + VectorMap& operator=(const VectorMap& cmap) { + return operator=(cmap); + } + + + // \brief Template assign operator. + // + // The given parameter should conform to the ReadMap + // concecpt and could be indiced by the current item set of + // the NodeMap. In this case the value for each item + // is assigned by the value of the given ReadMap. + template + VectorMap& operator=(const CMap& cmap) { + checkConcept, CMap>(); + const typename Parent::Notifier* nf = Parent::notifier(); + Item it; + for (nf->first(it); it != INVALID; nf->next(it)) { + set(it, cmap[it]); + } + return *this; + } + + public: + + // \brief The subcript operator. + // + // The subscript operator. The map can be subscripted by the + // actual items of the graph. + Reference operator[](const Key& key) { + return container[Parent::notifier()->id(key)]; + } + + // \brief The const subcript operator. + // + // The const subscript operator. The map can be subscripted by the + // actual items of the graph. + ConstReference operator[](const Key& key) const { + return container[Parent::notifier()->id(key)]; + } + + + // \brief The setter function of the map. + // + // It the same as operator[](key) = value expression. + void set(const Key& key, const Value& value) { + (*this)[key] = value; + } + + protected: + + // \brief Adds a new key to the map. + // + // It adds a new key to the map. It is called by the observer notifier + // and it overrides the add() member function of the observer base. + virtual void add(const Key& key) { + int id = Parent::notifier()->id(key); + if (id >= int(container.size())) { + container.resize(id + 1); + } + } + + // \brief Adds more new keys to the map. + // + // It adds more new keys to the map. It is called by the observer notifier + // and it overrides the add() member function of the observer base. + virtual void add(const std::vector& keys) { + int max = container.size() - 1; + for (int i = 0; i < int(keys.size()); ++i) { + int id = Parent::notifier()->id(keys[i]); + if (id >= max) { + max = id; + } + } + container.resize(max + 1); + } + + // \brief Erase a key from the map. + // + // Erase a key from the map. It is called by the observer notifier + // and it overrides the erase() member function of the observer base. + virtual void erase(const Key& key) { + container[Parent::notifier()->id(key)] = Value(); + } + + // \brief Erase more keys from the map. + // + // It erases more keys from the map. It is called by the observer notifier + // and it overrides the erase() member function of the observer base. + virtual void erase(const std::vector& keys) { + for (int i = 0; i < int(keys.size()); ++i) { + container[Parent::notifier()->id(keys[i])] = Value(); + } + } + + // \brief Build the map. + // + // It builds the map. It is called by the observer notifier + // and it overrides the build() member function of the observer base. + virtual void build() { + int size = Parent::notifier()->maxId() + 1; + container.reserve(size); + container.resize(size); + } + + // \brief Clear the map. + // + // It erases all items from the map. It is called by the observer notifier + // and it overrides the clear() member function of the observer base. + virtual void clear() { + container.clear(); + } + + private: + + Container container; + + }; + +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/windows.cc b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/windows.cc new file mode 100644 index 00000000000..7ad901c619c --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/windows.cc @@ -0,0 +1,166 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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. + * + */ + +///\file +///\brief Some basic non-inline functions and static global data. + +#include + +#ifdef WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOMINMAX +#define NOMINMAX +#endif +#ifdef UNICODE +#undef UNICODE +#endif +#include +#ifdef LOCALE_INVARIANT +#define MY_LOCALE LOCALE_INVARIANT +#else +#define MY_LOCALE LOCALE_NEUTRAL +#endif +#else +#include +#include +#ifndef WIN32 +#include +#endif +#include +#endif + +#include +#include + +namespace lemon { + namespace bits { + void getWinProcTimes(double &rtime, + double &utime, double &stime, + double &cutime, double &cstime) + { +#ifdef WIN32 + static const double ch = 4294967296.0e-7; + static const double cl = 1.0e-7; + + FILETIME system; + GetSystemTimeAsFileTime(&system); + rtime = ch * system.dwHighDateTime + cl * system.dwLowDateTime; + + FILETIME create, exit, kernel, user; + if (GetProcessTimes(GetCurrentProcess(),&create, &exit, &kernel, &user)) { + utime = ch * user.dwHighDateTime + cl * user.dwLowDateTime; + stime = ch * kernel.dwHighDateTime + cl * kernel.dwLowDateTime; + cutime = 0; + cstime = 0; + } else { + rtime = 0; + utime = 0; + stime = 0; + cutime = 0; + cstime = 0; + } +#else + timeval tv; + gettimeofday(&tv, 0); + rtime=tv.tv_sec+double(tv.tv_usec)/1e6; + + tms ts; + double tck=sysconf(_SC_CLK_TCK); + times(&ts); + utime=ts.tms_utime/tck; + stime=ts.tms_stime/tck; + cutime=ts.tms_cutime/tck; + cstime=ts.tms_cstime/tck; +#endif + } + + std::string getWinFormattedDate() + { + std::ostringstream os; +#ifdef WIN32 + SYSTEMTIME time; + GetSystemTime(&time); + char buf1[11], buf2[9], buf3[5]; + if (GetDateFormat(MY_LOCALE, 0, &time, + ("ddd MMM dd"), buf1, 11) && + GetTimeFormat(MY_LOCALE, 0, &time, + ("HH':'mm':'ss"), buf2, 9) && + GetDateFormat(MY_LOCALE, 0, &time, + ("yyyy"), buf3, 5)) { + os << buf1 << ' ' << buf2 << ' ' << buf3; + } + else os << "unknown"; +#else + timeval tv; + gettimeofday(&tv, 0); + + char cbuf[26]; + ctime_r(&tv.tv_sec,cbuf); + os << cbuf; +#endif + return os.str(); + } + + int getWinRndSeed() + { +#ifdef WIN32 + FILETIME time; + GetSystemTimeAsFileTime(&time); + return GetCurrentProcessId() + time.dwHighDateTime + time.dwLowDateTime; +#else + timeval tv; + gettimeofday(&tv, 0); + return getpid() + tv.tv_sec + tv.tv_usec; +#endif + } + + WinLock::WinLock() { +#ifdef WIN32 + CRITICAL_SECTION *lock = new CRITICAL_SECTION; + InitializeCriticalSection(lock); + _repr = lock; +#else + _repr = 0; //Just to avoid 'unused variable' warning with clang +#endif + } + + WinLock::~WinLock() { +#ifdef WIN32 + CRITICAL_SECTION *lock = static_cast(_repr); + DeleteCriticalSection(lock); + delete lock; +#endif + } + + void WinLock::lock() { +#ifdef WIN32 + CRITICAL_SECTION *lock = static_cast(_repr); + EnterCriticalSection(lock); +#endif + } + + void WinLock::unlock() { +#ifdef WIN32 + CRITICAL_SECTION *lock = static_cast(_repr); + LeaveCriticalSection(lock); +#endif + } + } +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/windows.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/windows.h new file mode 100644 index 00000000000..c09bb1284c5 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/windows.h @@ -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-2013 + * 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_BITS_WINDOWS_H +#define LEMON_BITS_WINDOWS_H + +#include + +namespace lemon { + namespace bits { + void getWinProcTimes(double &rtime, + double &utime, double &stime, + double &cutime, double &cstime); + std::string getWinFormattedDate(); + int getWinRndSeed(); + + class WinLock { + public: + WinLock(); + ~WinLock(); + void lock(); + void unlock(); + private: + void *_repr; + }; + } +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bucket_heap.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bucket_heap.h new file mode 100644 index 00000000000..92dbc08f011 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bucket_heap.h @@ -0,0 +1,594 @@ +/* -*- 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_BUCKET_HEAP_H +#define LEMON_BUCKET_HEAP_H + +///\ingroup heaps +///\file +///\brief Bucket heap implementation. + +#include +#include +#include + +namespace lemon { + + namespace _bucket_heap_bits { + + template + struct DirectionTraits { + static bool less(int left, int right) { + return left < right; + } + static void increase(int& value) { + ++value; + } + }; + + template <> + struct DirectionTraits { + static bool less(int left, int right) { + return left > right; + } + static void increase(int& value) { + --value; + } + }; + + } + + /// \ingroup heaps + /// + /// \brief Bucket heap data structure. + /// + /// This class implements the \e bucket \e heap data structure. + /// It practically conforms to the \ref concepts::Heap "heap concept", + /// but it has some limitations. + /// + /// The bucket heap is a very simple structure. It can store only + /// \c int priorities and it maintains a list of items for each priority + /// in the range [0..C). So it should only be used when the + /// priorities are small. It is not intended to use as a Dijkstra heap. + /// + /// \tparam IM A read-writable item map with \c int values, used + /// internally to handle the cross references. + /// \tparam MIN Indicate if the heap is a \e min-heap or a \e max-heap. + /// The default is \e min-heap. If this parameter is set to \c false, + /// then the comparison is reversed, so the top(), prio() and pop() + /// functions deal with the item having maximum priority instead of the + /// minimum. + /// + /// \sa SimpleBucketHeap + template + class BucketHeap { + + public: + + /// Type of the item-int map. + typedef IM ItemIntMap; + /// Type of the priorities. + typedef int Prio; + /// Type of the items stored in the heap. + typedef typename ItemIntMap::Key Item; + /// Type of the item-priority pairs. + typedef std::pair Pair; + + private: + + typedef _bucket_heap_bits::DirectionTraits Direction; + + public: + + /// \brief Type to represent the states of the items. + /// + /// Each item has a state associated to it. It can be "in heap", + /// "pre-heap" or "post-heap". The latter two are indifferent from the + /// heap's point of view, but may be useful to the user. + /// + /// The item-int map must be initialized in such way that it assigns + /// \c PRE_HEAP (-1) to any element to be put in the heap. + enum State { + IN_HEAP = 0, ///< = 0. + PRE_HEAP = -1, ///< = -1. + POST_HEAP = -2 ///< = -2. + }; + + public: + + /// \brief Constructor. + /// + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. + explicit BucketHeap(ItemIntMap &map) : _iim(map), _minimum(0) {} + + /// \brief The number of items stored in the heap. + /// + /// This function returns the number of items stored in the heap. + int size() const { return _data.size(); } + + /// \brief Check if the heap is empty. + /// + /// This function returns \c true if the heap is empty. + bool empty() const { return _data.empty(); } + + /// \brief Make the heap empty. + /// + /// This functon makes the heap empty. + /// It does not change the cross reference map. If you want to reuse + /// a heap that is not surely empty, you should first clear it and + /// then you should set the cross reference map to \c PRE_HEAP + /// for each item. + void clear() { + _data.clear(); _first.clear(); _minimum = 0; + } + + private: + + void relocateLast(int idx) { + if (idx + 1 < int(_data.size())) { + _data[idx] = _data.back(); + if (_data[idx].prev != -1) { + _data[_data[idx].prev].next = idx; + } else { + _first[_data[idx].value] = idx; + } + if (_data[idx].next != -1) { + _data[_data[idx].next].prev = idx; + } + _iim[_data[idx].item] = idx; + } + _data.pop_back(); + } + + void unlace(int idx) { + if (_data[idx].prev != -1) { + _data[_data[idx].prev].next = _data[idx].next; + } else { + _first[_data[idx].value] = _data[idx].next; + } + if (_data[idx].next != -1) { + _data[_data[idx].next].prev = _data[idx].prev; + } + } + + void lace(int idx) { + if (int(_first.size()) <= _data[idx].value) { + _first.resize(_data[idx].value + 1, -1); + } + _data[idx].next = _first[_data[idx].value]; + if (_data[idx].next != -1) { + _data[_data[idx].next].prev = idx; + } + _first[_data[idx].value] = idx; + _data[idx].prev = -1; + } + + public: + + /// \brief Insert a pair of item and priority into the heap. + /// + /// This function inserts \c p.first to the heap with priority + /// \c p.second. + /// \param p The pair to insert. + /// \pre \c p.first must not be stored in the heap. + void push(const Pair& p) { + push(p.first, p.second); + } + + /// \brief Insert an item into the heap with the given priority. + /// + /// This function inserts the given item into the heap with the + /// given priority. + /// \param i The item to insert. + /// \param p The priority of the item. + /// \pre \e i must not be stored in the heap. + void push(const Item &i, const Prio &p) { + int idx = _data.size(); + _iim[i] = idx; + _data.push_back(BucketItem(i, p)); + lace(idx); + if (Direction::less(p, _minimum)) { + _minimum = p; + } + } + + /// \brief Return the item having minimum priority. + /// + /// This function returns the item having minimum priority. + /// \pre The heap must be non-empty. + Item top() const { + while (_first[_minimum] == -1) { + Direction::increase(_minimum); + } + return _data[_first[_minimum]].item; + } + + /// \brief The minimum priority. + /// + /// This function returns the minimum priority. + /// \pre The heap must be non-empty. + Prio prio() const { + while (_first[_minimum] == -1) { + Direction::increase(_minimum); + } + return _minimum; + } + + /// \brief Remove the item having minimum priority. + /// + /// This function removes the item having minimum priority. + /// \pre The heap must be non-empty. + void pop() { + while (_first[_minimum] == -1) { + Direction::increase(_minimum); + } + int idx = _first[_minimum]; + _iim[_data[idx].item] = -2; + unlace(idx); + relocateLast(idx); + } + + /// \brief Remove the given item from the heap. + /// + /// This function removes the given item from the heap if it is + /// already stored. + /// \param i The item to delete. + /// \pre \e i must be in the heap. + void erase(const Item &i) { + int idx = _iim[i]; + _iim[_data[idx].item] = -2; + unlace(idx); + relocateLast(idx); + } + + /// \brief The priority of the given item. + /// + /// This function returns the priority of the given item. + /// \param i The item. + /// \pre \e i must be in the heap. + Prio operator[](const Item &i) const { + int idx = _iim[i]; + return _data[idx].value; + } + + /// \brief Set the priority of an item or insert it, if it is + /// not stored in the heap. + /// + /// This method sets the priority of the given item if it is + /// already stored in the heap. Otherwise it inserts the given + /// item into the heap with the given priority. + /// \param i The item. + /// \param p The priority. + void set(const Item &i, const Prio &p) { + int idx = _iim[i]; + if (idx < 0) { + push(i, p); + } else if (Direction::less(p, _data[idx].value)) { + decrease(i, p); + } else { + increase(i, p); + } + } + + /// \brief Decrease the priority of an item to the given value. + /// + /// This function decreases the priority of an item to the given value. + /// \param i The item. + /// \param p The priority. + /// \pre \e i must be stored in the heap with priority at least \e p. + void decrease(const Item &i, const Prio &p) { + int idx = _iim[i]; + unlace(idx); + _data[idx].value = p; + if (Direction::less(p, _minimum)) { + _minimum = p; + } + lace(idx); + } + + /// \brief Increase the priority of an item to the given value. + /// + /// This function increases the priority of an item to the given value. + /// \param i The item. + /// \param p The priority. + /// \pre \e i must be stored in the heap with priority at most \e p. + void increase(const Item &i, const Prio &p) { + int idx = _iim[i]; + unlace(idx); + _data[idx].value = p; + lace(idx); + } + + /// \brief Return the state of an item. + /// + /// This method returns \c PRE_HEAP if the given item has never + /// been in the heap, \c IN_HEAP if it is in the heap at the moment, + /// and \c POST_HEAP otherwise. + /// In the latter case it is possible that the item will get back + /// to the heap again. + /// \param i The item. + State state(const Item &i) const { + int idx = _iim[i]; + if (idx >= 0) idx = 0; + return State(idx); + } + + /// \brief Set the state of an item in the heap. + /// + /// This function sets the state of the given item in the heap. + /// It can be used to manually clear the heap when it is important + /// to achive better time complexity. + /// \param i The item. + /// \param st The state. It should not be \c IN_HEAP. + void state(const Item& i, State st) { + switch (st) { + case POST_HEAP: + case PRE_HEAP: + if (state(i) == IN_HEAP) { + erase(i); + } + _iim[i] = st; + break; + case IN_HEAP: + break; + } + } + + private: + + struct BucketItem { + BucketItem(const Item& _item, int _value) + : item(_item), value(_value) {} + + Item item; + int value; + + int prev, next; + }; + + ItemIntMap& _iim; + std::vector _first; + std::vector _data; + mutable int _minimum; + + }; // class BucketHeap + + /// \ingroup heaps + /// + /// \brief Simplified bucket heap data structure. + /// + /// This class implements a simplified \e bucket \e heap data + /// structure. It does not provide some functionality, but it is + /// faster and simpler than BucketHeap. The main difference is + /// that BucketHeap stores a doubly-linked list for each key while + /// this class stores only simply-linked lists. It supports erasing + /// only for the item having minimum priority and it does not support + /// key increasing and decreasing. + /// + /// Note that this implementation does not conform to the + /// \ref concepts::Heap "heap concept" due to the lack of some + /// functionality. + /// + /// \tparam IM A read-writable item map with \c int values, used + /// internally to handle the cross references. + /// \tparam MIN Indicate if the heap is a \e min-heap or a \e max-heap. + /// The default is \e min-heap. If this parameter is set to \c false, + /// then the comparison is reversed, so the top(), prio() and pop() + /// functions deal with the item having maximum priority instead of the + /// minimum. + /// + /// \sa BucketHeap + template + class SimpleBucketHeap { + + public: + + /// Type of the item-int map. + typedef IM ItemIntMap; + /// Type of the priorities. + typedef int Prio; + /// Type of the items stored in the heap. + typedef typename ItemIntMap::Key Item; + /// Type of the item-priority pairs. + typedef std::pair Pair; + + private: + + typedef _bucket_heap_bits::DirectionTraits Direction; + + public: + + /// \brief Type to represent the states of the items. + /// + /// Each item has a state associated to it. It can be "in heap", + /// "pre-heap" or "post-heap". The latter two are indifferent from the + /// heap's point of view, but may be useful to the user. + /// + /// The item-int map must be initialized in such way that it assigns + /// \c PRE_HEAP (-1) to any element to be put in the heap. + enum State { + IN_HEAP = 0, ///< = 0. + PRE_HEAP = -1, ///< = -1. + POST_HEAP = -2 ///< = -2. + }; + + public: + + /// \brief Constructor. + /// + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. + explicit SimpleBucketHeap(ItemIntMap &map) + : _iim(map), _free(-1), _num(0), _minimum(0) {} + + /// \brief The number of items stored in the heap. + /// + /// This function returns the number of items stored in the heap. + int size() const { return _num; } + + /// \brief Check if the heap is empty. + /// + /// This function returns \c true if the heap is empty. + bool empty() const { return _num == 0; } + + /// \brief Make the heap empty. + /// + /// This functon makes the heap empty. + /// It does not change the cross reference map. If you want to reuse + /// a heap that is not surely empty, you should first clear it and + /// then you should set the cross reference map to \c PRE_HEAP + /// for each item. + void clear() { + _data.clear(); _first.clear(); _free = -1; _num = 0; _minimum = 0; + } + + /// \brief Insert a pair of item and priority into the heap. + /// + /// This function inserts \c p.first to the heap with priority + /// \c p.second. + /// \param p The pair to insert. + /// \pre \c p.first must not be stored in the heap. + void push(const Pair& p) { + push(p.first, p.second); + } + + /// \brief Insert an item into the heap with the given priority. + /// + /// This function inserts the given item into the heap with the + /// given priority. + /// \param i The item to insert. + /// \param p The priority of the item. + /// \pre \e i must not be stored in the heap. + void push(const Item &i, const Prio &p) { + int idx; + if (_free == -1) { + idx = _data.size(); + _data.push_back(BucketItem(i)); + } else { + idx = _free; + _free = _data[idx].next; + _data[idx].item = i; + } + _iim[i] = idx; + if (p >= int(_first.size())) _first.resize(p + 1, -1); + _data[idx].next = _first[p]; + _first[p] = idx; + if (Direction::less(p, _minimum)) { + _minimum = p; + } + ++_num; + } + + /// \brief Return the item having minimum priority. + /// + /// This function returns the item having minimum priority. + /// \pre The heap must be non-empty. + Item top() const { + while (_first[_minimum] == -1) { + Direction::increase(_minimum); + } + return _data[_first[_minimum]].item; + } + + /// \brief The minimum priority. + /// + /// This function returns the minimum priority. + /// \pre The heap must be non-empty. + Prio prio() const { + while (_first[_minimum] == -1) { + Direction::increase(_minimum); + } + return _minimum; + } + + /// \brief Remove the item having minimum priority. + /// + /// This function removes the item having minimum priority. + /// \pre The heap must be non-empty. + void pop() { + while (_first[_minimum] == -1) { + Direction::increase(_minimum); + } + int idx = _first[_minimum]; + _iim[_data[idx].item] = -2; + _first[_minimum] = _data[idx].next; + _data[idx].next = _free; + _free = idx; + --_num; + } + + /// \brief The priority of the given item. + /// + /// This function returns the priority of the given item. + /// \param i The item. + /// \pre \e i must be in the heap. + /// \warning This operator is not a constant time function because + /// it scans the whole data structure to find the proper value. + Prio operator[](const Item &i) const { + for (int k = 0; k < int(_first.size()); ++k) { + int idx = _first[k]; + while (idx != -1) { + if (_data[idx].item == i) { + return k; + } + idx = _data[idx].next; + } + } + return -1; + } + + /// \brief Return the state of an item. + /// + /// This method returns \c PRE_HEAP if the given item has never + /// been in the heap, \c IN_HEAP if it is in the heap at the moment, + /// and \c POST_HEAP otherwise. + /// In the latter case it is possible that the item will get back + /// to the heap again. + /// \param i The item. + State state(const Item &i) const { + int idx = _iim[i]; + if (idx >= 0) idx = 0; + return State(idx); + } + + private: + + struct BucketItem { + BucketItem(const Item& _item) + : item(_item) {} + + Item item; + int next; + }; + + ItemIntMap& _iim; + std::vector _first; + std::vector _data; + int _free, _num; + mutable int _minimum; + + }; // class SimpleBucketHeap + +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/capacity_scaling.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/capacity_scaling.h new file mode 100644 index 00000000000..ca64b56d3b3 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/capacity_scaling.h @@ -0,0 +1,1014 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_CAPACITY_SCALING_H +#define LEMON_CAPACITY_SCALING_H + +/// \ingroup min_cost_flow_algs +/// +/// \file +/// \brief Capacity Scaling algorithm for finding a minimum cost flow. + +#include +#include +#include +#include + +namespace lemon { + + /// \brief Default traits class of CapacityScaling algorithm. + /// + /// Default traits class of CapacityScaling algorithm. + /// \tparam GR Digraph type. + /// \tparam V The number type used for flow amounts, capacity bounds + /// and supply values. By default it is \c int. + /// \tparam C The number type used for costs and potentials. + /// By default it is the same as \c V. + template + struct CapacityScalingDefaultTraits + { + /// The type of the digraph + typedef GR Digraph; + /// The type of the flow amounts, capacity bounds and supply values + typedef V Value; + /// The type of the arc costs + typedef C Cost; + + /// \brief The type of the heap used for internal Dijkstra computations. + /// + /// The type of the heap used for internal Dijkstra computations. + /// It must conform to the \ref lemon::concepts::Heap "Heap" concept, + /// its priority type must be \c Cost and its cross reference type + /// must be \ref RangeMap "RangeMap". + typedef BinHeap > Heap; + }; + + /// \addtogroup min_cost_flow_algs + /// @{ + + /// \brief Implementation of the Capacity Scaling algorithm for + /// finding a \ref min_cost_flow "minimum cost flow". + /// + /// \ref CapacityScaling implements the capacity scaling version + /// of the successive shortest path algorithm for finding a + /// \ref min_cost_flow "minimum cost flow" \cite amo93networkflows, + /// \cite edmondskarp72theoretical. It is an efficient dual + /// solution method, which runs in polynomial time + /// \f$O(m\log U (n+m)\log n)\f$, where U denotes the maximum + /// of node supply and arc capacity values. + /// + /// This algorithm is typically slower than \ref CostScaling and + /// \ref NetworkSimplex, but in special cases, it can be more + /// efficient than them. + /// (For more information, see \ref min_cost_flow_algs "the module page".) + /// + /// Most of the parameters of the problem (except for the digraph) + /// can be given using separate functions, and the algorithm can be + /// executed using the \ref run() function. If some parameters are not + /// specified, then default values will be used. + /// + /// \tparam GR The digraph type the algorithm runs on. + /// \tparam V The number type used for flow amounts, capacity bounds + /// and supply values in the algorithm. By default, it is \c int. + /// \tparam C The number type used for costs and potentials in the + /// algorithm. By default, it is the same as \c V. + /// \tparam TR The traits class that defines various types used by the + /// algorithm. By default, it is \ref CapacityScalingDefaultTraits + /// "CapacityScalingDefaultTraits". + /// In most cases, this parameter should not be set directly, + /// consider to use the named template parameters instead. + /// + /// \warning Both \c V and \c C must be signed number types. + /// \warning Capacity bounds and supply values must be integer, but + /// arc costs can be arbitrary real numbers. + /// \warning This algorithm does not support negative costs for + /// arcs having infinite upper bound. +#ifdef DOXYGEN + template +#else + template < typename GR, typename V = int, typename C = V, + typename TR = CapacityScalingDefaultTraits > +#endif + class CapacityScaling + { + public: + + /// The type of the digraph + typedef typename TR::Digraph Digraph; + /// The type of the flow amounts, capacity bounds and supply values + typedef typename TR::Value Value; + /// The type of the arc costs + typedef typename TR::Cost Cost; + + /// The type of the heap used for internal Dijkstra computations + typedef typename TR::Heap Heap; + + /// \brief The \ref lemon::CapacityScalingDefaultTraits "traits class" + /// of the algorithm + typedef TR Traits; + + public: + + /// \brief Problem type constants for the \c run() function. + /// + /// Enum type containing the problem type constants that can be + /// returned by the \ref run() function of the algorithm. + enum ProblemType { + /// The problem has no feasible solution (flow). + INFEASIBLE, + /// The problem has optimal solution (i.e. it is feasible and + /// bounded), and the algorithm has found optimal flow and node + /// potentials (primal and dual solutions). + OPTIMAL, + /// The digraph contains an arc of negative cost and infinite + /// upper bound. It means that the objective function is unbounded + /// on that arc, however, note that it could actually be bounded + /// over the feasible flows, but this algroithm cannot handle + /// these cases. + UNBOUNDED + }; + + private: + + TEMPLATE_DIGRAPH_TYPEDEFS(GR); + + typedef std::vector IntVector; + typedef std::vector ValueVector; + typedef std::vector CostVector; + typedef std::vector BoolVector; + // Note: vector is used instead of vector for efficiency reasons + + private: + + // Data related to the underlying digraph + const GR &_graph; + int _node_num; + int _arc_num; + int _res_arc_num; + int _root; + + // Parameters of the problem + bool _has_lower; + Value _sum_supply; + + // Data structures for storing the digraph + IntNodeMap _node_id; + IntArcMap _arc_idf; + IntArcMap _arc_idb; + IntVector _first_out; + BoolVector _forward; + IntVector _source; + IntVector _target; + IntVector _reverse; + + // Node and arc data + ValueVector _lower; + ValueVector _upper; + CostVector _cost; + ValueVector _supply; + + ValueVector _res_cap; + CostVector _pi; + ValueVector _excess; + IntVector _excess_nodes; + IntVector _deficit_nodes; + + Value _delta; + int _factor; + IntVector _pred; + + public: + + /// \brief Constant for infinite upper bounds (capacities). + /// + /// Constant for infinite upper bounds (capacities). + /// It is \c std::numeric_limits::infinity() if available, + /// \c std::numeric_limits::max() otherwise. + const Value INF; + + private: + + // Special implementation of the Dijkstra algorithm for finding + // shortest paths in the residual network of the digraph with + // respect to the reduced arc costs and modifying the node + // potentials according to the found distance labels. + class ResidualDijkstra + { + private: + + int _node_num; + bool _geq; + const IntVector &_first_out; + const IntVector &_target; + const CostVector &_cost; + const ValueVector &_res_cap; + const ValueVector &_excess; + CostVector &_pi; + IntVector &_pred; + + IntVector _proc_nodes; + CostVector _dist; + + public: + + ResidualDijkstra(CapacityScaling& cs) : + _node_num(cs._node_num), _geq(cs._sum_supply < 0), + _first_out(cs._first_out), _target(cs._target), _cost(cs._cost), + _res_cap(cs._res_cap), _excess(cs._excess), _pi(cs._pi), + _pred(cs._pred), _dist(cs._node_num) + {} + + int run(int s, Value delta = 1) { + RangeMap heap_cross_ref(_node_num, Heap::PRE_HEAP); + Heap heap(heap_cross_ref); + heap.push(s, 0); + _pred[s] = -1; + _proc_nodes.clear(); + + // Process nodes + while (!heap.empty() && _excess[heap.top()] > -delta) { + int u = heap.top(), v; + Cost d = heap.prio() + _pi[u], dn; + _dist[u] = heap.prio(); + _proc_nodes.push_back(u); + heap.pop(); + + // Traverse outgoing residual arcs + int last_out = _geq ? _first_out[u+1] : _first_out[u+1] - 1; + for (int a = _first_out[u]; a != last_out; ++a) { + if (_res_cap[a] < delta) continue; + v = _target[a]; + switch (heap.state(v)) { + case Heap::PRE_HEAP: + heap.push(v, d + _cost[a] - _pi[v]); + _pred[v] = a; + break; + case Heap::IN_HEAP: + dn = d + _cost[a] - _pi[v]; + if (dn < heap[v]) { + heap.decrease(v, dn); + _pred[v] = a; + } + break; + case Heap::POST_HEAP: + break; + } + } + } + if (heap.empty()) return -1; + + // Update potentials of processed nodes + int t = heap.top(); + Cost dt = heap.prio(); + for (int i = 0; i < int(_proc_nodes.size()); ++i) { + _pi[_proc_nodes[i]] += _dist[_proc_nodes[i]] - dt; + } + + return t; + } + + }; //class ResidualDijkstra + + public: + + /// \name Named Template Parameters + /// @{ + + template + struct SetHeapTraits : public Traits { + typedef T Heap; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c Heap type. + /// + /// \ref named-templ-param "Named parameter" for setting \c Heap + /// type, which is used for internal Dijkstra computations. + /// It must conform to the \ref lemon::concepts::Heap "Heap" concept, + /// its priority type must be \c Cost and its cross reference type + /// must be \ref RangeMap "RangeMap". + template + struct SetHeap + : public CapacityScaling > { + typedef CapacityScaling > Create; + }; + + /// @} + + protected: + + CapacityScaling() {} + + public: + + /// \brief Constructor. + /// + /// The constructor of the class. + /// + /// \param graph The digraph the algorithm runs on. + CapacityScaling(const GR& graph) : + _graph(graph), _node_id(graph), _arc_idf(graph), _arc_idb(graph), + INF(std::numeric_limits::has_infinity ? + std::numeric_limits::infinity() : + std::numeric_limits::max()) + { + // Check the number types + LEMON_ASSERT(std::numeric_limits::is_signed, + "The flow type of CapacityScaling must be signed"); + LEMON_ASSERT(std::numeric_limits::is_signed, + "The cost type of CapacityScaling must be signed"); + + // Reset data structures + reset(); + } + + /// \name Parameters + /// The parameters of the algorithm can be specified using these + /// functions. + + /// @{ + + /// \brief Set the lower bounds on the arcs. + /// + /// This function sets the lower bounds on the arcs. + /// If it is not used before calling \ref run(), the lower bounds + /// will be set to zero on all arcs. + /// + /// \param map An arc map storing the lower bounds. + /// Its \c Value type must be convertible to the \c Value type + /// of the algorithm. + /// + /// \return (*this) + template + CapacityScaling& lowerMap(const LowerMap& map) { + _has_lower = true; + for (ArcIt a(_graph); a != INVALID; ++a) { + _lower[_arc_idf[a]] = map[a]; + } + return *this; + } + + /// \brief Set the upper bounds (capacities) on the arcs. + /// + /// This function sets the upper bounds (capacities) on the arcs. + /// If it is not used before calling \ref run(), the upper bounds + /// will be set to \ref INF on all arcs (i.e. the flow value will be + /// unbounded from above). + /// + /// \param map An arc map storing the upper bounds. + /// Its \c Value type must be convertible to the \c Value type + /// of the algorithm. + /// + /// \return (*this) + template + CapacityScaling& upperMap(const UpperMap& map) { + for (ArcIt a(_graph); a != INVALID; ++a) { + _upper[_arc_idf[a]] = map[a]; + } + return *this; + } + + /// \brief Set the costs of the arcs. + /// + /// This function sets the costs of the arcs. + /// If it is not used before calling \ref run(), the costs + /// will be set to \c 1 on all arcs. + /// + /// \param map An arc map storing the costs. + /// Its \c Value type must be convertible to the \c Cost type + /// of the algorithm. + /// + /// \return (*this) + template + CapacityScaling& costMap(const CostMap& map) { + for (ArcIt a(_graph); a != INVALID; ++a) { + _cost[_arc_idf[a]] = map[a]; + _cost[_arc_idb[a]] = -map[a]; + } + return *this; + } + + /// \brief Set the supply values of the nodes. + /// + /// This function sets the supply values of the nodes. + /// If neither this function nor \ref stSupply() is used before + /// calling \ref run(), the supply of each node will be set to zero. + /// + /// \param map A node map storing the supply values. + /// Its \c Value type must be convertible to the \c Value type + /// of the algorithm. + /// + /// \return (*this) + template + CapacityScaling& supplyMap(const SupplyMap& map) { + for (NodeIt n(_graph); n != INVALID; ++n) { + _supply[_node_id[n]] = map[n]; + } + return *this; + } + + /// \brief Set single source and target nodes and a supply value. + /// + /// This function sets a single source node and a single target node + /// and the required flow value. + /// If neither this function nor \ref supplyMap() is used before + /// calling \ref run(), the supply of each node will be set to zero. + /// + /// Using this function has the same effect as using \ref supplyMap() + /// with a map in which \c k is assigned to \c s, \c -k is + /// assigned to \c t and all other nodes have zero supply value. + /// + /// \param s The source node. + /// \param t The target node. + /// \param k The required amount of flow from node \c s to node \c t + /// (i.e. the supply of \c s and the demand of \c t). + /// + /// \return (*this) + CapacityScaling& stSupply(const Node& s, const Node& t, Value k) { + for (int i = 0; i != _node_num; ++i) { + _supply[i] = 0; + } + _supply[_node_id[s]] = k; + _supply[_node_id[t]] = -k; + return *this; + } + + /// @} + + /// \name Execution control + /// The algorithm can be executed using \ref run(). + + /// @{ + + /// \brief Run the algorithm. + /// + /// This function runs the algorithm. + /// The paramters can be specified using functions \ref lowerMap(), + /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply(). + /// For example, + /// \code + /// CapacityScaling cs(graph); + /// cs.lowerMap(lower).upperMap(upper).costMap(cost) + /// .supplyMap(sup).run(); + /// \endcode + /// + /// This function can be called more than once. All the given parameters + /// are kept for the next call, unless \ref resetParams() or \ref reset() + /// is used, thus only the modified parameters have to be set again. + /// If the underlying digraph was also modified after the construction + /// of the class (or the last \ref reset() call), then the \ref reset() + /// function must be called. + /// + /// \param factor The capacity scaling factor. It must be larger than + /// one to use scaling. If it is less or equal to one, then scaling + /// will be disabled. + /// + /// \return \c INFEASIBLE if no feasible flow exists, + /// \n \c OPTIMAL if the problem has optimal solution + /// (i.e. it is feasible and bounded), and the algorithm has found + /// optimal flow and node potentials (primal and dual solutions), + /// \n \c UNBOUNDED if the digraph contains an arc of negative cost + /// and infinite upper bound. It means that the objective function + /// is unbounded on that arc, however, note that it could actually be + /// bounded over the feasible flows, but this algroithm cannot handle + /// these cases. + /// + /// \see ProblemType + /// \see resetParams(), reset() + ProblemType run(int factor = 4) { + _factor = factor; + ProblemType pt = init(); + if (pt != OPTIMAL) return pt; + return start(); + } + + /// \brief Reset all the parameters that have been given before. + /// + /// This function resets all the paramaters that have been given + /// before using functions \ref lowerMap(), \ref upperMap(), + /// \ref costMap(), \ref supplyMap(), \ref stSupply(). + /// + /// It is useful for multiple \ref run() calls. Basically, all the given + /// parameters are kept for the next \ref run() call, unless + /// \ref resetParams() or \ref reset() is used. + /// If the underlying digraph was also modified after the construction + /// of the class or the last \ref reset() call, then the \ref reset() + /// function must be used, otherwise \ref resetParams() is sufficient. + /// + /// For example, + /// \code + /// CapacityScaling cs(graph); + /// + /// // First run + /// cs.lowerMap(lower).upperMap(upper).costMap(cost) + /// .supplyMap(sup).run(); + /// + /// // Run again with modified cost map (resetParams() is not called, + /// // so only the cost map have to be set again) + /// cost[e] += 100; + /// cs.costMap(cost).run(); + /// + /// // Run again from scratch using resetParams() + /// // (the lower bounds will be set to zero on all arcs) + /// cs.resetParams(); + /// cs.upperMap(capacity).costMap(cost) + /// .supplyMap(sup).run(); + /// \endcode + /// + /// \return (*this) + /// + /// \see reset(), run() + CapacityScaling& resetParams() { + for (int i = 0; i != _node_num; ++i) { + _supply[i] = 0; + } + for (int j = 0; j != _res_arc_num; ++j) { + _lower[j] = 0; + _upper[j] = INF; + _cost[j] = _forward[j] ? 1 : -1; + } + _has_lower = false; + return *this; + } + + /// \brief Reset the internal data structures and all the parameters + /// that have been given before. + /// + /// This function resets the internal data structures and all the + /// paramaters that have been given before using functions \ref lowerMap(), + /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply(). + /// + /// It is useful for multiple \ref run() calls. Basically, all the given + /// parameters are kept for the next \ref run() call, unless + /// \ref resetParams() or \ref reset() is used. + /// If the underlying digraph was also modified after the construction + /// of the class or the last \ref reset() call, then the \ref reset() + /// function must be used, otherwise \ref resetParams() is sufficient. + /// + /// See \ref resetParams() for examples. + /// + /// \return (*this) + /// + /// \see resetParams(), run() + CapacityScaling& reset() { + // Resize vectors + _node_num = countNodes(_graph); + _arc_num = countArcs(_graph); + _res_arc_num = 2 * (_arc_num + _node_num); + _root = _node_num; + ++_node_num; + + _first_out.resize(_node_num + 1); + _forward.resize(_res_arc_num); + _source.resize(_res_arc_num); + _target.resize(_res_arc_num); + _reverse.resize(_res_arc_num); + + _lower.resize(_res_arc_num); + _upper.resize(_res_arc_num); + _cost.resize(_res_arc_num); + _supply.resize(_node_num); + + _res_cap.resize(_res_arc_num); + _pi.resize(_node_num); + _excess.resize(_node_num); + _pred.resize(_node_num); + + // Copy the graph + int i = 0, j = 0, k = 2 * _arc_num + _node_num - 1; + for (NodeIt n(_graph); n != INVALID; ++n, ++i) { + _node_id[n] = i; + } + i = 0; + for (NodeIt n(_graph); n != INVALID; ++n, ++i) { + _first_out[i] = j; + for (OutArcIt a(_graph, n); a != INVALID; ++a, ++j) { + _arc_idf[a] = j; + _forward[j] = true; + _source[j] = i; + _target[j] = _node_id[_graph.runningNode(a)]; + } + for (InArcIt a(_graph, n); a != INVALID; ++a, ++j) { + _arc_idb[a] = j; + _forward[j] = false; + _source[j] = i; + _target[j] = _node_id[_graph.runningNode(a)]; + } + _forward[j] = false; + _source[j] = i; + _target[j] = _root; + _reverse[j] = k; + _forward[k] = true; + _source[k] = _root; + _target[k] = i; + _reverse[k] = j; + ++j; ++k; + } + _first_out[i] = j; + _first_out[_node_num] = k; + for (ArcIt a(_graph); a != INVALID; ++a) { + int fi = _arc_idf[a]; + int bi = _arc_idb[a]; + _reverse[fi] = bi; + _reverse[bi] = fi; + } + + // Reset parameters + resetParams(); + return *this; + } + + /// @} + + /// \name Query Functions + /// The results of the algorithm can be obtained using these + /// functions.\n + /// The \ref run() function must be called before using them. + + /// @{ + + /// \brief Return the total cost of the found flow. + /// + /// This function returns the total cost of the found flow. + /// Its complexity is O(m). + /// + /// \note The return type of the function can be specified as a + /// template parameter. For example, + /// \code + /// cs.totalCost(); + /// \endcode + /// It is useful if the total cost cannot be stored in the \c Cost + /// type of the algorithm, which is the default return type of the + /// function. + /// + /// \pre \ref run() must be called before using this function. + template + Number totalCost() const { + Number c = 0; + for (ArcIt a(_graph); a != INVALID; ++a) { + int i = _arc_idb[a]; + c += static_cast(_res_cap[i]) * + (-static_cast(_cost[i])); + } + return c; + } + +#ifndef DOXYGEN + Cost totalCost() const { + return totalCost(); + } +#endif + + /// \brief Return the flow on the given arc. + /// + /// This function returns the flow on the given arc. + /// + /// \pre \ref run() must be called before using this function. + Value flow(const Arc& a) const { + return _res_cap[_arc_idb[a]]; + } + + /// \brief Copy the flow values (the primal solution) into the + /// given map. + /// + /// This function copies the flow value on each arc into the given + /// map. The \c Value type of the algorithm must be convertible to + /// the \c Value type of the map. + /// + /// \pre \ref run() must be called before using this function. + template + void flowMap(FlowMap &map) const { + for (ArcIt a(_graph); a != INVALID; ++a) { + map.set(a, _res_cap[_arc_idb[a]]); + } + } + + /// \brief Return the potential (dual value) of the given node. + /// + /// This function returns the potential (dual value) of the + /// given node. + /// + /// \pre \ref run() must be called before using this function. + Cost potential(const Node& n) const { + return _pi[_node_id[n]]; + } + + /// \brief Copy the potential values (the dual solution) into the + /// given map. + /// + /// This function copies the potential (dual value) of each node + /// into the given map. + /// The \c Cost type of the algorithm must be convertible to the + /// \c Value type of the map. + /// + /// \pre \ref run() must be called before using this function. + template + void potentialMap(PotentialMap &map) const { + for (NodeIt n(_graph); n != INVALID; ++n) { + map.set(n, _pi[_node_id[n]]); + } + } + + /// @} + + private: + + // Initialize the algorithm + ProblemType init() { + if (_node_num <= 1) return INFEASIBLE; + + // Check the sum of supply values + _sum_supply = 0; + for (int i = 0; i != _root; ++i) { + _sum_supply += _supply[i]; + } + if (_sum_supply > 0) return INFEASIBLE; + + // Check lower and upper bounds + LEMON_DEBUG(checkBoundMaps(), + "Upper bounds must be greater or equal to the lower bounds"); + + + // Initialize vectors + for (int i = 0; i != _root; ++i) { + _pi[i] = 0; + _excess[i] = _supply[i]; + } + + // Remove non-zero lower bounds + const Value MAX = std::numeric_limits::max(); + int last_out; + if (_has_lower) { + for (int i = 0; i != _root; ++i) { + last_out = _first_out[i+1]; + for (int j = _first_out[i]; j != last_out; ++j) { + if (_forward[j]) { + Value c = _lower[j]; + if (c >= 0) { + _res_cap[j] = _upper[j] < MAX ? _upper[j] - c : INF; + } else { + _res_cap[j] = _upper[j] < MAX + c ? _upper[j] - c : INF; + } + _excess[i] -= c; + _excess[_target[j]] += c; + } else { + _res_cap[j] = 0; + } + } + } + } else { + for (int j = 0; j != _res_arc_num; ++j) { + _res_cap[j] = _forward[j] ? _upper[j] : 0; + } + } + + // Handle negative costs + for (int i = 0; i != _root; ++i) { + last_out = _first_out[i+1] - 1; + for (int j = _first_out[i]; j != last_out; ++j) { + Value rc = _res_cap[j]; + if (_cost[j] < 0 && rc > 0) { + if (rc >= MAX) return UNBOUNDED; + _excess[i] -= rc; + _excess[_target[j]] += rc; + _res_cap[j] = 0; + _res_cap[_reverse[j]] += rc; + } + } + } + + // Handle GEQ supply type + if (_sum_supply < 0) { + _pi[_root] = 0; + _excess[_root] = -_sum_supply; + for (int a = _first_out[_root]; a != _res_arc_num; ++a) { + int ra = _reverse[a]; + _res_cap[a] = -_sum_supply + 1; + _res_cap[ra] = 0; + _cost[a] = 0; + _cost[ra] = 0; + } + } else { + _pi[_root] = 0; + _excess[_root] = 0; + for (int a = _first_out[_root]; a != _res_arc_num; ++a) { + int ra = _reverse[a]; + _res_cap[a] = 1; + _res_cap[ra] = 0; + _cost[a] = 0; + _cost[ra] = 0; + } + } + + // Initialize delta value + if (_factor > 1) { + // With scaling + Value max_sup = 0, max_dem = 0, max_cap = 0; + for (int i = 0; i != _root; ++i) { + Value ex = _excess[i]; + if ( ex > max_sup) max_sup = ex; + if (-ex > max_dem) max_dem = -ex; + int last_out = _first_out[i+1] - 1; + for (int j = _first_out[i]; j != last_out; ++j) { + if (_res_cap[j] > max_cap) max_cap = _res_cap[j]; + } + } + max_sup = std::min(std::min(max_sup, max_dem), max_cap); + for (_delta = 1; 2 * _delta <= max_sup; _delta *= 2) ; + } else { + // Without scaling + _delta = 1; + } + + return OPTIMAL; + } + + // Check if the upper bound is greater than or equal to the lower bound + // on each forward arc. + bool checkBoundMaps() { + for (int j = 0; j != _res_arc_num; ++j) { + if (_forward[j] && _upper[j] < _lower[j]) return false; + } + return true; + } + + ProblemType start() { + // Execute the algorithm + ProblemType pt; + if (_delta > 1) + pt = startWithScaling(); + else + pt = startWithoutScaling(); + + // Handle non-zero lower bounds + if (_has_lower) { + int limit = _first_out[_root]; + for (int j = 0; j != limit; ++j) { + if (_forward[j]) _res_cap[_reverse[j]] += _lower[j]; + } + } + + // Shift potentials if necessary + Cost pr = _pi[_root]; + if (_sum_supply < 0 || pr > 0) { + for (int i = 0; i != _node_num; ++i) { + _pi[i] -= pr; + } + } + + return pt; + } + + // Execute the capacity scaling algorithm + ProblemType startWithScaling() { + // Perform capacity scaling phases + int s, t; + ResidualDijkstra _dijkstra(*this); + while (true) { + // Saturate all arcs not satisfying the optimality condition + int last_out; + for (int u = 0; u != _node_num; ++u) { + last_out = _sum_supply < 0 ? + _first_out[u+1] : _first_out[u+1] - 1; + for (int a = _first_out[u]; a != last_out; ++a) { + int v = _target[a]; + Cost c = _cost[a] + _pi[u] - _pi[v]; + Value rc = _res_cap[a]; + if (c < 0 && rc >= _delta) { + _excess[u] -= rc; + _excess[v] += rc; + _res_cap[a] = 0; + _res_cap[_reverse[a]] += rc; + } + } + } + + // Find excess nodes and deficit nodes + _excess_nodes.clear(); + _deficit_nodes.clear(); + for (int u = 0; u != _node_num; ++u) { + Value ex = _excess[u]; + if (ex >= _delta) _excess_nodes.push_back(u); + if (ex <= -_delta) _deficit_nodes.push_back(u); + } + int next_node = 0, next_def_node = 0; + + // Find augmenting shortest paths + while (next_node < int(_excess_nodes.size())) { + // Check deficit nodes + if (_delta > 1) { + bool delta_deficit = false; + for ( ; next_def_node < int(_deficit_nodes.size()); + ++next_def_node ) { + if (_excess[_deficit_nodes[next_def_node]] <= -_delta) { + delta_deficit = true; + break; + } + } + if (!delta_deficit) break; + } + + // Run Dijkstra in the residual network + s = _excess_nodes[next_node]; + if ((t = _dijkstra.run(s, _delta)) == -1) { + if (_delta > 1) { + ++next_node; + continue; + } + return INFEASIBLE; + } + + // Augment along a shortest path from s to t + Value d = std::min(_excess[s], -_excess[t]); + int u = t; + int a; + if (d > _delta) { + while ((a = _pred[u]) != -1) { + if (_res_cap[a] < d) d = _res_cap[a]; + u = _source[a]; + } + } + u = t; + while ((a = _pred[u]) != -1) { + _res_cap[a] -= d; + _res_cap[_reverse[a]] += d; + u = _source[a]; + } + _excess[s] -= d; + _excess[t] += d; + + if (_excess[s] < _delta) ++next_node; + } + + if (_delta == 1) break; + _delta = _delta <= _factor ? 1 : _delta / _factor; + } + + return OPTIMAL; + } + + // Execute the successive shortest path algorithm + ProblemType startWithoutScaling() { + // Find excess nodes + _excess_nodes.clear(); + for (int i = 0; i != _node_num; ++i) { + if (_excess[i] > 0) _excess_nodes.push_back(i); + } + if (_excess_nodes.size() == 0) return OPTIMAL; + int next_node = 0; + + // Find shortest paths + int s, t; + ResidualDijkstra _dijkstra(*this); + while ( _excess[_excess_nodes[next_node]] > 0 || + ++next_node < int(_excess_nodes.size()) ) + { + // Run Dijkstra in the residual network + s = _excess_nodes[next_node]; + if ((t = _dijkstra.run(s)) == -1) return INFEASIBLE; + + // Augment along a shortest path from s to t + Value d = std::min(_excess[s], -_excess[t]); + int u = t; + int a; + if (d > 1) { + while ((a = _pred[u]) != -1) { + if (_res_cap[a] < d) d = _res_cap[a]; + u = _source[a]; + } + } + u = t; + while ((a = _pred[u]) != -1) { + _res_cap[a] -= d; + _res_cap[_reverse[a]] += d; + u = _source[a]; + } + _excess[s] -= d; + _excess[t] += d; + } + + return OPTIMAL; + } + + }; //class CapacityScaling + + ///@} + +} //namespace lemon + +#endif //LEMON_CAPACITY_SCALING_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/cbc.cc b/extern/quadriflow/3rd/lemon-1.3.1/lemon/cbc.cc new file mode 100644 index 00000000000..62331b1e2e1 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/cbc.cc @@ -0,0 +1,460 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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. + * + */ + +///\file +///\brief Implementation of the CBC MIP solver interface. + +#include "cbc.h" + +#include +#include +#include + +#include "coin/OsiClpSolverInterface.hpp" + +#include "coin/CbcCutGenerator.hpp" +#include "coin/CbcHeuristicLocal.hpp" +#include "coin/CbcHeuristicGreedy.hpp" +#include "coin/CbcHeuristicFPump.hpp" +#include "coin/CbcHeuristicRINS.hpp" + +#include "coin/CglGomory.hpp" +#include "coin/CglProbing.hpp" +#include "coin/CglKnapsackCover.hpp" +#include "coin/CglOddHole.hpp" +#include "coin/CglClique.hpp" +#include "coin/CglFlowCover.hpp" +#include "coin/CglMixedIntegerRounding.hpp" + +#include "coin/CbcHeuristic.hpp" + +namespace lemon { + + CbcMip::CbcMip() { + _prob = new CoinModel(); + _prob->setProblemName("LEMON"); + _osi_solver = 0; + _cbc_model = 0; + messageLevel(MESSAGE_NOTHING); + } + + CbcMip::CbcMip(const CbcMip& other) { + _prob = new CoinModel(*other._prob); + _prob->setProblemName("LEMON"); + _osi_solver = 0; + _cbc_model = 0; + messageLevel(MESSAGE_NOTHING); + } + + CbcMip::~CbcMip() { + delete _prob; + if (_osi_solver) delete _osi_solver; + if (_cbc_model) delete _cbc_model; + } + + const char* CbcMip::_solverName() const { return "CbcMip"; } + + int CbcMip::_addCol() { + _prob->addColumn(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX, 0.0, 0, false); + return _prob->numberColumns() - 1; + } + + CbcMip* CbcMip::newSolver() const { + CbcMip* newlp = new CbcMip; + return newlp; + } + + CbcMip* CbcMip::cloneSolver() const { + CbcMip* copylp = new CbcMip(*this); + return copylp; + } + + int CbcMip::_addRow() { + _prob->addRow(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX); + return _prob->numberRows() - 1; + } + + int CbcMip::_addRow(Value l, ExprIterator b, ExprIterator e, Value u) { + std::vector indexes; + std::vector values; + + for(ExprIterator it = b; it != e; ++it) { + indexes.push_back(it->first); + values.push_back(it->second); + } + + _prob->addRow(values.size(), &indexes.front(), &values.front(), l, u); + return _prob->numberRows() - 1; + } + + void CbcMip::_eraseCol(int i) { + _prob->deleteColumn(i); + } + + void CbcMip::_eraseRow(int i) { + _prob->deleteRow(i); + } + + void CbcMip::_eraseColId(int i) { + cols.eraseIndex(i); + } + + void CbcMip::_eraseRowId(int i) { + rows.eraseIndex(i); + } + + void CbcMip::_getColName(int c, std::string& name) const { + name = _prob->getColumnName(c); + } + + void CbcMip::_setColName(int c, const std::string& name) { + _prob->setColumnName(c, name.c_str()); + } + + int CbcMip::_colByName(const std::string& name) const { + return _prob->column(name.c_str()); + } + + void CbcMip::_getRowName(int r, std::string& name) const { + name = _prob->getRowName(r); + } + + void CbcMip::_setRowName(int r, const std::string& name) { + _prob->setRowName(r, name.c_str()); + } + + int CbcMip::_rowByName(const std::string& name) const { + return _prob->row(name.c_str()); + } + + void CbcMip::_setRowCoeffs(int i, ExprIterator b, ExprIterator e) { + for (ExprIterator it = b; it != e; ++it) { + _prob->setElement(i, it->first, it->second); + } + } + + void CbcMip::_getRowCoeffs(int ix, InsertIterator b) const { + int length = _prob->numberRows(); + + std::vector indices(length); + std::vector values(length); + + length = _prob->getRow(ix, &indices[0], &values[0]); + + for (int i = 0; i < length; ++i) { + *b = std::make_pair(indices[i], values[i]); + ++b; + } + } + + void CbcMip::_setColCoeffs(int ix, ExprIterator b, ExprIterator e) { + for (ExprIterator it = b; it != e; ++it) { + _prob->setElement(it->first, ix, it->second); + } + } + + void CbcMip::_getColCoeffs(int ix, InsertIterator b) const { + int length = _prob->numberColumns(); + + std::vector indices(length); + std::vector values(length); + + length = _prob->getColumn(ix, &indices[0], &values[0]); + + for (int i = 0; i < length; ++i) { + *b = std::make_pair(indices[i], values[i]); + ++b; + } + } + + void CbcMip::_setCoeff(int ix, int jx, Value value) { + _prob->setElement(ix, jx, value); + } + + CbcMip::Value CbcMip::_getCoeff(int ix, int jx) const { + return _prob->getElement(ix, jx); + } + + + void CbcMip::_setColLowerBound(int i, Value lo) { + LEMON_ASSERT(lo != INF, "Invalid bound"); + _prob->setColumnLower(i, lo == - INF ? - COIN_DBL_MAX : lo); + } + + CbcMip::Value CbcMip::_getColLowerBound(int i) const { + double val = _prob->getColumnLower(i); + return val == - COIN_DBL_MAX ? - INF : val; + } + + void CbcMip::_setColUpperBound(int i, Value up) { + LEMON_ASSERT(up != -INF, "Invalid bound"); + _prob->setColumnUpper(i, up == INF ? COIN_DBL_MAX : up); + } + + CbcMip::Value CbcMip::_getColUpperBound(int i) const { + double val = _prob->getColumnUpper(i); + return val == COIN_DBL_MAX ? INF : val; + } + + void CbcMip::_setRowLowerBound(int i, Value lo) { + LEMON_ASSERT(lo != INF, "Invalid bound"); + _prob->setRowLower(i, lo == - INF ? - COIN_DBL_MAX : lo); + } + + CbcMip::Value CbcMip::_getRowLowerBound(int i) const { + double val = _prob->getRowLower(i); + return val == - COIN_DBL_MAX ? - INF : val; + } + + void CbcMip::_setRowUpperBound(int i, Value up) { + LEMON_ASSERT(up != -INF, "Invalid bound"); + _prob->setRowUpper(i, up == INF ? COIN_DBL_MAX : up); + } + + CbcMip::Value CbcMip::_getRowUpperBound(int i) const { + double val = _prob->getRowUpper(i); + return val == COIN_DBL_MAX ? INF : val; + } + + void CbcMip::_setObjCoeffs(ExprIterator b, ExprIterator e) { + int num = _prob->numberColumns(); + for (int i = 0; i < num; ++i) { + _prob->setColumnObjective(i, 0.0); + } + for (ExprIterator it = b; it != e; ++it) { + _prob->setColumnObjective(it->first, it->second); + } + } + + void CbcMip::_getObjCoeffs(InsertIterator b) const { + int num = _prob->numberColumns(); + for (int i = 0; i < num; ++i) { + Value coef = _prob->getColumnObjective(i); + if (coef != 0.0) { + *b = std::make_pair(i, coef); + ++b; + } + } + } + + void CbcMip::_setObjCoeff(int i, Value obj_coef) { + _prob->setColumnObjective(i, obj_coef); + } + + CbcMip::Value CbcMip::_getObjCoeff(int i) const { + return _prob->getColumnObjective(i); + } + + CbcMip::SolveExitStatus CbcMip::_solve() { + + if (_osi_solver) { + delete _osi_solver; + } + _osi_solver = new OsiClpSolverInterface(); + + _osi_solver->loadFromCoinModel(*_prob); + + if (_cbc_model) { + delete _cbc_model; + } + _cbc_model= new CbcModel(*_osi_solver); + + _osi_solver->messageHandler()->setLogLevel(_message_level); + _cbc_model->setLogLevel(_message_level); + + _cbc_model->initialSolve(); + _cbc_model->solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry); + + if (!_cbc_model->isInitialSolveAbandoned() && + _cbc_model->isInitialSolveProvenOptimal() && + !_cbc_model->isInitialSolveProvenPrimalInfeasible() && + !_cbc_model->isInitialSolveProvenDualInfeasible()) { + + CglProbing generator1; + generator1.setUsingObjective(true); + generator1.setMaxPass(3); + generator1.setMaxProbe(100); + generator1.setMaxLook(50); + generator1.setRowCuts(3); + _cbc_model->addCutGenerator(&generator1, -1, "Probing"); + + CglGomory generator2; + generator2.setLimit(300); + _cbc_model->addCutGenerator(&generator2, -1, "Gomory"); + + CglKnapsackCover generator3; + _cbc_model->addCutGenerator(&generator3, -1, "Knapsack"); + + CglOddHole generator4; + generator4.setMinimumViolation(0.005); + generator4.setMinimumViolationPer(0.00002); + generator4.setMaximumEntries(200); + _cbc_model->addCutGenerator(&generator4, -1, "OddHole"); + + CglClique generator5; + generator5.setStarCliqueReport(false); + generator5.setRowCliqueReport(false); + _cbc_model->addCutGenerator(&generator5, -1, "Clique"); + + CglMixedIntegerRounding mixedGen; + _cbc_model->addCutGenerator(&mixedGen, -1, "MixedIntegerRounding"); + + CglFlowCover flowGen; + _cbc_model->addCutGenerator(&flowGen, -1, "FlowCover"); + + OsiClpSolverInterface* osiclp = + dynamic_cast(_cbc_model->solver()); + if (osiclp->getNumRows() < 300 && osiclp->getNumCols() < 500) { + osiclp->setupForRepeatedUse(2, 0); + } + + CbcRounding heuristic1(*_cbc_model); + heuristic1.setWhen(3); + _cbc_model->addHeuristic(&heuristic1); + + CbcHeuristicLocal heuristic2(*_cbc_model); + heuristic2.setWhen(3); + _cbc_model->addHeuristic(&heuristic2); + + CbcHeuristicGreedyCover heuristic3(*_cbc_model); + heuristic3.setAlgorithm(11); + heuristic3.setWhen(3); + _cbc_model->addHeuristic(&heuristic3); + + CbcHeuristicFPump heuristic4(*_cbc_model); + heuristic4.setWhen(3); + _cbc_model->addHeuristic(&heuristic4); + + CbcHeuristicRINS heuristic5(*_cbc_model); + heuristic5.setWhen(3); + _cbc_model->addHeuristic(&heuristic5); + + if (_cbc_model->getNumCols() < 500) { + _cbc_model->setMaximumCutPassesAtRoot(-100); + } else if (_cbc_model->getNumCols() < 5000) { + _cbc_model->setMaximumCutPassesAtRoot(100); + } else { + _cbc_model->setMaximumCutPassesAtRoot(20); + } + + if (_cbc_model->getNumCols() < 5000) { + _cbc_model->setNumberStrong(10); + } + + _cbc_model->solver()->setIntParam(OsiMaxNumIterationHotStart, 100); + _cbc_model->branchAndBound(); + } + + if (_cbc_model->isAbandoned()) { + return UNSOLVED; + } else { + return SOLVED; + } + } + + CbcMip::Value CbcMip::_getSol(int i) const { + return _cbc_model->getColSolution()[i]; + } + + CbcMip::Value CbcMip::_getSolValue() const { + return _cbc_model->getObjValue(); + } + + CbcMip::ProblemType CbcMip::_getType() const { + if (_cbc_model->isProvenOptimal()) { + return OPTIMAL; + } else if (_cbc_model->isContinuousUnbounded()) { + return UNBOUNDED; + } + return FEASIBLE; + } + + void CbcMip::_setSense(Sense sense) { + switch (sense) { + case MIN: + _prob->setOptimizationDirection(1.0); + break; + case MAX: + _prob->setOptimizationDirection(- 1.0); + break; + } + } + + CbcMip::Sense CbcMip::_getSense() const { + if (_prob->optimizationDirection() > 0.0) { + return MIN; + } else if (_prob->optimizationDirection() < 0.0) { + return MAX; + } else { + LEMON_ASSERT(false, "Wrong sense"); + return CbcMip::Sense(); + } + } + + void CbcMip::_setColType(int i, CbcMip::ColTypes col_type) { + switch (col_type){ + case INTEGER: + _prob->setInteger(i); + break; + case REAL: + _prob->setContinuous(i); + break; + default:; + LEMON_ASSERT(false, "Wrong sense"); + } + } + + CbcMip::ColTypes CbcMip::_getColType(int i) const { + return _prob->getColumnIsInteger(i) ? INTEGER : REAL; + } + + void CbcMip::_clear() { + delete _prob; + if (_osi_solver) { + delete _osi_solver; + _osi_solver = 0; + } + if (_cbc_model) { + delete _cbc_model; + _cbc_model = 0; + } + + _prob = new CoinModel(); + } + + void CbcMip::_messageLevel(MessageLevel level) { + switch (level) { + case MESSAGE_NOTHING: + _message_level = 0; + break; + case MESSAGE_ERROR: + _message_level = 1; + break; + case MESSAGE_WARNING: + _message_level = 1; + break; + case MESSAGE_NORMAL: + _message_level = 2; + break; + case MESSAGE_VERBOSE: + _message_level = 3; + break; + } + } + +} //END OF NAMESPACE LEMON diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/cbc.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/cbc.h new file mode 100644 index 00000000000..968e504ac35 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/cbc.h @@ -0,0 +1,129 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_CBC_H +#define LEMON_CBC_H + +///\file +///\brief Header of the LEMON-CBC mip solver interface. +///\ingroup lp_group + +#include + +class CoinModel; +class OsiSolverInterface; +class CbcModel; + +namespace lemon { + + /// \brief Interface for the CBC MIP solver + /// + /// This class implements an interface for the CBC MIP solver. + ///\ingroup lp_group + class CbcMip : public MipSolver { + protected: + + CoinModel *_prob; + OsiSolverInterface *_osi_solver; + CbcModel *_cbc_model; + + public: + + /// \e + CbcMip(); + /// \e + CbcMip(const CbcMip&); + /// \e + ~CbcMip(); + /// \e + virtual CbcMip* newSolver() const; + /// \e + virtual CbcMip* cloneSolver() const; + + protected: + + virtual const char* _solverName() const; + + virtual int _addCol(); + virtual int _addRow(); + virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u); + + virtual void _eraseCol(int i); + virtual void _eraseRow(int i); + + virtual void _eraseColId(int i); + virtual void _eraseRowId(int i); + + virtual void _getColName(int col, std::string& name) const; + virtual void _setColName(int col, const std::string& name); + virtual int _colByName(const std::string& name) const; + + virtual void _getRowName(int row, std::string& name) const; + virtual void _setRowName(int row, const std::string& name); + virtual int _rowByName(const std::string& name) const; + + virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e); + virtual void _getRowCoeffs(int i, InsertIterator b) const; + + virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e); + virtual void _getColCoeffs(int i, InsertIterator b) const; + + virtual void _setCoeff(int row, int col, Value value); + virtual Value _getCoeff(int row, int col) const; + + virtual void _setColLowerBound(int i, Value value); + virtual Value _getColLowerBound(int i) const; + virtual void _setColUpperBound(int i, Value value); + virtual Value _getColUpperBound(int i) const; + + virtual void _setRowLowerBound(int i, Value value); + virtual Value _getRowLowerBound(int i) const; + virtual void _setRowUpperBound(int i, Value value); + virtual Value _getRowUpperBound(int i) const; + + virtual void _setObjCoeffs(ExprIterator b, ExprIterator e); + virtual void _getObjCoeffs(InsertIterator b) const; + + virtual void _setObjCoeff(int i, Value obj_coef); + virtual Value _getObjCoeff(int i) const; + + virtual void _setSense(Sense sense); + virtual Sense _getSense() const; + + virtual ColTypes _getColType(int col) const; + virtual void _setColType(int col, ColTypes col_type); + + virtual SolveExitStatus _solve(); + virtual ProblemType _getType() const; + virtual Value _getSol(int i) const; + virtual Value _getSolValue() const; + + virtual void _clear(); + + virtual void _messageLevel(MessageLevel level); + void _applyMessageLevel(); + + int _message_level; + + + + }; + +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/christofides_tsp.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/christofides_tsp.h new file mode 100644 index 00000000000..2997567a689 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/christofides_tsp.h @@ -0,0 +1,254 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_CHRISTOFIDES_TSP_H +#define LEMON_CHRISTOFIDES_TSP_H + +/// \ingroup tsp +/// \file +/// \brief Christofides algorithm for symmetric TSP + +#include +#include +#include +#include +#include + +namespace lemon { + + /// \ingroup tsp + /// + /// \brief Christofides algorithm for symmetric TSP. + /// + /// ChristofidesTsp implements Christofides' heuristic for solving + /// symmetric \ref tsp "TSP". + /// + /// This a well-known approximation method for the TSP problem with + /// metric cost function. + /// It has a guaranteed approximation factor of 3/2 (i.e. it finds a tour + /// whose total cost is at most 3/2 of the optimum), but it usually + /// provides better solutions in practice. + /// This implementation runs in O(n3log(n)) time. + /// + /// The algorithm starts with a \ref spantree "minimum cost spanning tree" and + /// finds a \ref MaxWeightedPerfectMatching "minimum cost perfect matching" + /// in the subgraph induced by the nodes that have odd degree in the + /// spanning tree. + /// Finally, it constructs the tour from the \ref EulerIt "Euler traversal" + /// of the union of the spanning tree and the matching. + /// During this last step, the algorithm simply skips the visited nodes + /// (i.e. creates shortcuts) assuming that the triangle inequality holds + /// for the cost function. + /// + /// \tparam CM Type of the cost map. + /// + /// \warning CM::Value must be a signed number type. + template + class ChristofidesTsp + { + public: + + /// Type of the cost map + typedef CM CostMap; + /// Type of the edge costs + typedef typename CM::Value Cost; + + private: + + GRAPH_TYPEDEFS(FullGraph); + + const FullGraph &_gr; + const CostMap &_cost; + std::vector _path; + Cost _sum; + + public: + + /// \brief Constructor + /// + /// Constructor. + /// \param gr The \ref FullGraph "full graph" the algorithm runs on. + /// \param cost The cost map. + ChristofidesTsp(const FullGraph &gr, const CostMap &cost) + : _gr(gr), _cost(cost) {} + + /// \name Execution Control + /// @{ + + /// \brief Runs the algorithm. + /// + /// This function runs the algorithm. + /// + /// \return The total cost of the found tour. + Cost run() { + _path.clear(); + + if (_gr.nodeNum() == 0) return _sum = 0; + else if (_gr.nodeNum() == 1) { + _path.push_back(_gr(0)); + return _sum = 0; + } + else if (_gr.nodeNum() == 2) { + _path.push_back(_gr(0)); + _path.push_back(_gr(1)); + return _sum = 2 * _cost[_gr.edge(_gr(0), _gr(1))]; + } + + // Compute min. cost spanning tree + std::vector tree; + kruskal(_gr, _cost, std::back_inserter(tree)); + + FullGraph::NodeMap deg(_gr, 0); + for (int i = 0; i != int(tree.size()); ++i) { + Edge e = tree[i]; + ++deg[_gr.u(e)]; + ++deg[_gr.v(e)]; + } + + // Copy the induced subgraph of odd nodes + std::vector odd_nodes; + for (NodeIt u(_gr); u != INVALID; ++u) { + if (deg[u] % 2 == 1) odd_nodes.push_back(u); + } + + SmartGraph sgr; + SmartGraph::EdgeMap scost(sgr); + for (int i = 0; i != int(odd_nodes.size()); ++i) { + sgr.addNode(); + } + for (int i = 0; i != int(odd_nodes.size()); ++i) { + for (int j = 0; j != int(odd_nodes.size()); ++j) { + if (j == i) continue; + SmartGraph::Edge e = + sgr.addEdge(sgr.nodeFromId(i), sgr.nodeFromId(j)); + scost[e] = -_cost[_gr.edge(odd_nodes[i], odd_nodes[j])]; + } + } + + // Compute min. cost perfect matching + MaxWeightedPerfectMatching > + mwpm(sgr, scost); + mwpm.run(); + + for (SmartGraph::EdgeIt e(sgr); e != INVALID; ++e) { + if (mwpm.matching(e)) { + tree.push_back( _gr.edge(odd_nodes[sgr.id(sgr.u(e))], + odd_nodes[sgr.id(sgr.v(e))]) ); + } + } + + // Join the spanning tree and the matching + sgr.clear(); + for (int i = 0; i != _gr.nodeNum(); ++i) { + sgr.addNode(); + } + for (int i = 0; i != int(tree.size()); ++i) { + int ui = _gr.id(_gr.u(tree[i])), + vi = _gr.id(_gr.v(tree[i])); + sgr.addEdge(sgr.nodeFromId(ui), sgr.nodeFromId(vi)); + } + + // Compute the tour from the Euler traversal + SmartGraph::NodeMap visited(sgr, false); + for (EulerIt e(sgr); e != INVALID; ++e) { + SmartGraph::Node n = sgr.target(e); + if (!visited[n]) { + _path.push_back(_gr(sgr.id(n))); + visited[n] = true; + } + } + + _sum = _cost[_gr.edge(_path.back(), _path.front())]; + for (int i = 0; i < int(_path.size())-1; ++i) { + _sum += _cost[_gr.edge(_path[i], _path[i+1])]; + } + + return _sum; + } + + /// @} + + /// \name Query Functions + /// @{ + + /// \brief The total cost of the found tour. + /// + /// This function returns the total cost of the found tour. + /// + /// \pre run() must be called before using this function. + Cost tourCost() const { + return _sum; + } + + /// \brief Returns a const reference to the node sequence of the + /// found tour. + /// + /// This function returns a const reference to a vector + /// that stores the node sequence of the found tour. + /// + /// \pre run() must be called before using this function. + const std::vector& tourNodes() const { + return _path; + } + + /// \brief Gives back the node sequence of the found tour. + /// + /// This function copies the node sequence of the found tour into + /// an STL container through the given output iterator. The + /// value_type of the container must be FullGraph::Node. + /// For example, + /// \code + /// std::vector nodes(countNodes(graph)); + /// tsp.tourNodes(nodes.begin()); + /// \endcode + /// or + /// \code + /// std::list nodes; + /// tsp.tourNodes(std::back_inserter(nodes)); + /// \endcode + /// + /// \pre run() must be called before using this function. + template + void tourNodes(Iterator out) const { + std::copy(_path.begin(), _path.end(), out); + } + + /// \brief Gives back the found tour as a path. + /// + /// This function copies the found tour as a list of arcs/edges into + /// the given \ref lemon::concepts::Path "path structure". + /// + /// \pre run() must be called before using this function. + template + void tour(Path &path) const { + path.clear(); + for (int i = 0; i < int(_path.size()) - 1; ++i) { + path.addBack(_gr.arc(_path[i], _path[i+1])); + } + if (int(_path.size()) >= 2) { + path.addBack(_gr.arc(_path.back(), _path.front())); + } + } + + /// @} + + }; + +}; // namespace lemon + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/circulation.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/circulation.h new file mode 100644 index 00000000000..b0f717b2615 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/circulation.h @@ -0,0 +1,807 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_CIRCULATION_H +#define LEMON_CIRCULATION_H + +#include +#include +#include + +///\ingroup max_flow +///\file +///\brief Push-relabel algorithm for finding a feasible circulation. +/// +namespace lemon { + + /// \brief Default traits class of Circulation class. + /// + /// Default traits class of Circulation class. + /// + /// \tparam GR Type of the digraph the algorithm runs on. + /// \tparam LM The type of the lower bound map. + /// \tparam UM The type of the upper bound (capacity) map. + /// \tparam SM The type of the supply map. + template + struct CirculationDefaultTraits { + + /// \brief The type of the digraph the algorithm runs on. + typedef GR Digraph; + + /// \brief The type of the lower bound map. + /// + /// The type of the map that stores the lower bounds on the arcs. + /// It must conform to the \ref concepts::ReadMap "ReadMap" concept. + typedef LM LowerMap; + + /// \brief The type of the upper bound (capacity) map. + /// + /// The type of the map that stores the upper bounds (capacities) + /// on the arcs. + /// It must conform to the \ref concepts::ReadMap "ReadMap" concept. + typedef UM UpperMap; + + /// \brief The type of supply map. + /// + /// The type of the map that stores the signed supply values of the + /// nodes. + /// It must conform to the \ref concepts::ReadMap "ReadMap" concept. + typedef SM SupplyMap; + + /// \brief The type of the flow and supply values. + typedef typename SupplyMap::Value Value; + + /// \brief The type of the map that stores the flow values. + /// + /// The type of the map that stores the flow values. + /// It must conform to the \ref concepts::ReadWriteMap "ReadWriteMap" + /// concept. +#ifdef DOXYGEN + typedef GR::ArcMap FlowMap; +#else + typedef typename Digraph::template ArcMap FlowMap; +#endif + + /// \brief Instantiates a FlowMap. + /// + /// This function instantiates a \ref FlowMap. + /// \param digraph The digraph for which we would like to define + /// the flow map. + static FlowMap* createFlowMap(const Digraph& digraph) { + return new FlowMap(digraph); + } + + /// \brief The elevator type used by the algorithm. + /// + /// The elevator type used by the algorithm. + /// + /// \sa Elevator, LinkedElevator +#ifdef DOXYGEN + typedef lemon::Elevator Elevator; +#else + typedef lemon::Elevator Elevator; +#endif + + /// \brief Instantiates an Elevator. + /// + /// This function instantiates an \ref Elevator. + /// \param digraph The digraph for which we would like to define + /// the elevator. + /// \param max_level The maximum level of the elevator. + static Elevator* createElevator(const Digraph& digraph, int max_level) { + return new Elevator(digraph, max_level); + } + + /// \brief The tolerance used by the algorithm + /// + /// The tolerance used by the algorithm to handle inexact computation. + typedef lemon::Tolerance Tolerance; + + }; + + /** + \brief Push-relabel algorithm for the network circulation problem. + + \ingroup max_flow + This class implements a push-relabel algorithm for the \e network + \e circulation problem. + It is to find a feasible circulation when lower and upper bounds + are given for the flow values on the arcs and lower bounds are + given for the difference between the outgoing and incoming flow + at the nodes. + + The exact formulation of this problem is the following. + Let \f$G=(V,A)\f$ be a digraph, \f$lower: A\rightarrow\mathbf{R}\f$ + \f$upper: A\rightarrow\mathbf{R}\cup\{\infty\}\f$ denote the lower and + upper bounds on the arcs, for which \f$lower(uv) \leq upper(uv)\f$ + holds for all \f$uv\in A\f$, and \f$sup: V\rightarrow\mathbf{R}\f$ + denotes the signed supply values of the nodes. + If \f$sup(u)>0\f$, then \f$u\f$ is a supply node with \f$sup(u)\f$ + supply, if \f$sup(u)<0\f$, then \f$u\f$ is a demand node with + \f$-sup(u)\f$ demand. + A feasible circulation is an \f$f: A\rightarrow\mathbf{R}\f$ + solution of the following problem. + + \f[ \sum_{uv\in A} f(uv) - \sum_{vu\in A} f(vu) + \geq sup(u) \quad \forall u\in V, \f] + \f[ lower(uv) \leq f(uv) \leq upper(uv) \quad \forall uv\in A. \f] + + The sum of the supply values, i.e. \f$\sum_{u\in V} sup(u)\f$ must be + zero or negative in order to have a feasible solution (since the sum + of the expressions on the left-hand side of the inequalities is zero). + It means that the total demand must be greater or equal to the total + supply and all the supplies have to be carried out from the supply nodes, + but there could be demands that are not satisfied. + If \f$\sum_{u\in V} sup(u)\f$ is zero, then all the supply/demand + constraints have to be satisfied with equality, i.e. all demands + have to be satisfied and all supplies have to be used. + + If you need the opposite inequalities in the supply/demand constraints + (i.e. the total demand is less than the total supply and all the demands + have to be satisfied while there could be supplies that are not used), + then you could easily transform the problem to the above form by reversing + the direction of the arcs and taking the negative of the supply values + (e.g. using \ref ReverseDigraph and \ref NegMap adaptors). + + This algorithm either calculates a feasible circulation, or provides + a \ref barrier() "barrier", which prooves that a feasible soultion + cannot exist. + + Note that this algorithm also provides a feasible solution for the + \ref min_cost_flow "minimum cost flow problem". + + \tparam GR The type of the digraph the algorithm runs on. + \tparam LM The type of the lower bound map. The default + map type is \ref concepts::Digraph::ArcMap "GR::ArcMap". + \tparam UM The type of the upper bound (capacity) map. + The default map type is \c LM. + \tparam SM The type of the supply map. The default map type is + \ref concepts::Digraph::NodeMap "GR::NodeMap". + \tparam TR The traits class that defines various types used by the + algorithm. By default, it is \ref CirculationDefaultTraits + "CirculationDefaultTraits". + In most cases, this parameter should not be set directly, + consider to use the named template parameters instead. + */ +#ifdef DOXYGEN +template< typename GR, + typename LM, + typename UM, + typename SM, + typename TR > +#else +template< typename GR, + typename LM = typename GR::template ArcMap, + typename UM = LM, + typename SM = typename GR::template NodeMap, + typename TR = CirculationDefaultTraits > +#endif + class Circulation { + public: + + /// \brief The \ref lemon::CirculationDefaultTraits "traits class" + /// of the algorithm. + typedef TR Traits; + ///The type of the digraph the algorithm runs on. + typedef typename Traits::Digraph Digraph; + ///The type of the flow and supply values. + typedef typename Traits::Value Value; + + ///The type of the lower bound map. + typedef typename Traits::LowerMap LowerMap; + ///The type of the upper bound (capacity) map. + typedef typename Traits::UpperMap UpperMap; + ///The type of the supply map. + typedef typename Traits::SupplyMap SupplyMap; + ///The type of the flow map. + typedef typename Traits::FlowMap FlowMap; + + ///The type of the elevator. + typedef typename Traits::Elevator Elevator; + ///The type of the tolerance. + typedef typename Traits::Tolerance Tolerance; + + private: + + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + + const Digraph &_g; + int _node_num; + + const LowerMap *_lo; + const UpperMap *_up; + const SupplyMap *_supply; + + FlowMap *_flow; + bool _local_flow; + + Elevator* _level; + bool _local_level; + + typedef typename Digraph::template NodeMap ExcessMap; + ExcessMap* _excess; + + Tolerance _tol; + int _el; + + public: + + typedef Circulation Create; + + ///\name Named Template Parameters + + ///@{ + + template + struct SetFlowMapTraits : public Traits { + typedef T FlowMap; + static FlowMap *createFlowMap(const Digraph&) { + LEMON_ASSERT(false, "FlowMap is not initialized"); + return 0; // ignore warnings + } + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// FlowMap type + /// + /// \ref named-templ-param "Named parameter" for setting FlowMap + /// type. + template + struct SetFlowMap + : public Circulation > { + typedef Circulation > Create; + }; + + template + struct SetElevatorTraits : public Traits { + typedef T Elevator; + static Elevator *createElevator(const Digraph&, int) { + LEMON_ASSERT(false, "Elevator is not initialized"); + return 0; // ignore warnings + } + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// Elevator type + /// + /// \ref named-templ-param "Named parameter" for setting Elevator + /// type. If this named parameter is used, then an external + /// elevator object must be passed to the algorithm using the + /// \ref elevator(Elevator&) "elevator()" function before calling + /// \ref run() or \ref init(). + /// \sa SetStandardElevator + template + struct SetElevator + : public Circulation > { + typedef Circulation > Create; + }; + + template + struct SetStandardElevatorTraits : public Traits { + typedef T Elevator; + static Elevator *createElevator(const Digraph& digraph, int max_level) { + return new Elevator(digraph, max_level); + } + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// Elevator type with automatic allocation + /// + /// \ref named-templ-param "Named parameter" for setting Elevator + /// type with automatic allocation. + /// The Elevator should have standard constructor interface to be + /// able to automatically created by the algorithm (i.e. the + /// digraph and the maximum level should be passed to it). + /// However, an external elevator object could also be passed to the + /// algorithm with the \ref elevator(Elevator&) "elevator()" function + /// before calling \ref run() or \ref init(). + /// \sa SetElevator + template + struct SetStandardElevator + : public Circulation > { + typedef Circulation > Create; + }; + + /// @} + + protected: + + Circulation() {} + + public: + + /// Constructor. + + /// The constructor of the class. + /// + /// \param graph The digraph the algorithm runs on. + /// \param lower The lower bounds for the flow values on the arcs. + /// \param upper The upper bounds (capacities) for the flow values + /// on the arcs. + /// \param supply The signed supply values of the nodes. + Circulation(const Digraph &graph, const LowerMap &lower, + const UpperMap &upper, const SupplyMap &supply) + : _g(graph), _lo(&lower), _up(&upper), _supply(&supply), + _flow(NULL), _local_flow(false), _level(NULL), _local_level(false), + _excess(NULL) {} + + /// Destructor. + ~Circulation() { + destroyStructures(); + } + + + private: + + bool checkBoundMaps() { + for (ArcIt e(_g);e!=INVALID;++e) { + if (_tol.less((*_up)[e], (*_lo)[e])) return false; + } + return true; + } + + void createStructures() { + _node_num = _el = countNodes(_g); + + if (!_flow) { + _flow = Traits::createFlowMap(_g); + _local_flow = true; + } + if (!_level) { + _level = Traits::createElevator(_g, _node_num); + _local_level = true; + } + if (!_excess) { + _excess = new ExcessMap(_g); + } + } + + void destroyStructures() { + if (_local_flow) { + delete _flow; + } + if (_local_level) { + delete _level; + } + if (_excess) { + delete _excess; + } + } + + public: + + /// Sets the lower bound map. + + /// Sets the lower bound map. + /// \return (*this) + Circulation& lowerMap(const LowerMap& map) { + _lo = ↦ + return *this; + } + + /// Sets the upper bound (capacity) map. + + /// Sets the upper bound (capacity) map. + /// \return (*this) + Circulation& upperMap(const UpperMap& map) { + _up = ↦ + return *this; + } + + /// Sets the supply map. + + /// Sets the supply map. + /// \return (*this) + Circulation& supplyMap(const SupplyMap& map) { + _supply = ↦ + return *this; + } + + /// \brief Sets the flow map. + /// + /// Sets the flow map. + /// If you don't use this function before calling \ref run() or + /// \ref init(), an instance will be allocated automatically. + /// The destructor deallocates this automatically allocated map, + /// of course. + /// \return (*this) + Circulation& flowMap(FlowMap& map) { + if (_local_flow) { + delete _flow; + _local_flow = false; + } + _flow = ↦ + return *this; + } + + /// \brief Sets the elevator used by algorithm. + /// + /// Sets the elevator used by algorithm. + /// If you don't use this function before calling \ref run() or + /// \ref init(), an instance will be allocated automatically. + /// The destructor deallocates this automatically allocated elevator, + /// of course. + /// \return (*this) + Circulation& elevator(Elevator& elevator) { + if (_local_level) { + delete _level; + _local_level = false; + } + _level = &elevator; + return *this; + } + + /// \brief Returns a const reference to the elevator. + /// + /// Returns a const reference to the elevator. + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + const Elevator& elevator() const { + return *_level; + } + + /// \brief Sets the tolerance used by the algorithm. + /// + /// Sets the tolerance object used by the algorithm. + /// \return (*this) + Circulation& tolerance(const Tolerance& tolerance) { + _tol = tolerance; + return *this; + } + + /// \brief Returns a const reference to the tolerance. + /// + /// Returns a const reference to the tolerance object used by + /// the algorithm. + const Tolerance& tolerance() const { + return _tol; + } + + /// \name Execution Control + /// The simplest way to execute the algorithm is to call \ref run().\n + /// If you need better control on the initial solution or the execution, + /// you have to call one of the \ref init() functions first, then + /// the \ref start() function. + + ///@{ + + /// Initializes the internal data structures. + + /// Initializes the internal data structures and sets all flow values + /// to the lower bound. + void init() + { + LEMON_DEBUG(checkBoundMaps(), + "Upper bounds must be greater or equal to the lower bounds"); + + createStructures(); + + for(NodeIt n(_g);n!=INVALID;++n) { + (*_excess)[n] = (*_supply)[n]; + } + + for (ArcIt e(_g);e!=INVALID;++e) { + _flow->set(e, (*_lo)[e]); + (*_excess)[_g.target(e)] += (*_flow)[e]; + (*_excess)[_g.source(e)] -= (*_flow)[e]; + } + + // global relabeling tested, but in general case it provides + // worse performance for random digraphs + _level->initStart(); + for(NodeIt n(_g);n!=INVALID;++n) + _level->initAddItem(n); + _level->initFinish(); + for(NodeIt n(_g);n!=INVALID;++n) + if(_tol.positive((*_excess)[n])) + _level->activate(n); + } + + /// Initializes the internal data structures using a greedy approach. + + /// Initializes the internal data structures using a greedy approach + /// to construct the initial solution. + void greedyInit() + { + LEMON_DEBUG(checkBoundMaps(), + "Upper bounds must be greater or equal to the lower bounds"); + + createStructures(); + + for(NodeIt n(_g);n!=INVALID;++n) { + (*_excess)[n] = (*_supply)[n]; + } + + for (ArcIt e(_g);e!=INVALID;++e) { + if (!_tol.less(-(*_excess)[_g.target(e)], (*_up)[e])) { + _flow->set(e, (*_up)[e]); + (*_excess)[_g.target(e)] += (*_up)[e]; + (*_excess)[_g.source(e)] -= (*_up)[e]; + } else if (_tol.less(-(*_excess)[_g.target(e)], (*_lo)[e])) { + _flow->set(e, (*_lo)[e]); + (*_excess)[_g.target(e)] += (*_lo)[e]; + (*_excess)[_g.source(e)] -= (*_lo)[e]; + } else { + Value fc = -(*_excess)[_g.target(e)]; + _flow->set(e, fc); + (*_excess)[_g.target(e)] = 0; + (*_excess)[_g.source(e)] -= fc; + } + } + + _level->initStart(); + for(NodeIt n(_g);n!=INVALID;++n) + _level->initAddItem(n); + _level->initFinish(); + for(NodeIt n(_g);n!=INVALID;++n) + if(_tol.positive((*_excess)[n])) + _level->activate(n); + } + + ///Executes the algorithm + + ///This function executes the algorithm. + /// + ///\return \c true if a feasible circulation is found. + /// + ///\sa barrier() + ///\sa barrierMap() + bool start() + { + + Node act; + while((act=_level->highestActive())!=INVALID) { + int actlevel=(*_level)[act]; + int mlevel=_node_num; + Value exc=(*_excess)[act]; + + for(OutArcIt e(_g,act);e!=INVALID; ++e) { + Node v = _g.target(e); + Value fc=(*_up)[e]-(*_flow)[e]; + if(!_tol.positive(fc)) continue; + if((*_level)[v]set(e, (*_flow)[e] + exc); + (*_excess)[v] += exc; + if(!_level->active(v) && _tol.positive((*_excess)[v])) + _level->activate(v); + (*_excess)[act] = 0; + _level->deactivate(act); + goto next_l; + } + else { + _flow->set(e, (*_up)[e]); + (*_excess)[v] += fc; + if(!_level->active(v) && _tol.positive((*_excess)[v])) + _level->activate(v); + exc-=fc; + } + } + else if((*_level)[v]set(e, (*_flow)[e] - exc); + (*_excess)[v] += exc; + if(!_level->active(v) && _tol.positive((*_excess)[v])) + _level->activate(v); + (*_excess)[act] = 0; + _level->deactivate(act); + goto next_l; + } + else { + _flow->set(e, (*_lo)[e]); + (*_excess)[v] += fc; + if(!_level->active(v) && _tol.positive((*_excess)[v])) + _level->activate(v); + exc-=fc; + } + } + else if((*_level)[v]deactivate(act); + else if(mlevel==_node_num) { + _level->liftHighestActiveToTop(); + _el = _node_num; + return false; + } + else { + _level->liftHighestActive(mlevel+1); + if(_level->onLevel(actlevel)==0) { + _el = actlevel; + return false; + } + } + next_l: + ; + } + return true; + } + + /// Runs the algorithm. + + /// This function runs the algorithm. + /// + /// \return \c true if a feasible circulation is found. + /// + /// \note Apart from the return value, c.run() is just a shortcut of + /// the following code. + /// \code + /// c.greedyInit(); + /// c.start(); + /// \endcode + bool run() { + greedyInit(); + return start(); + } + + /// @} + + /// \name Query Functions + /// The results of the circulation algorithm can be obtained using + /// these functions.\n + /// Either \ref run() or \ref start() should be called before + /// using them. + + ///@{ + + /// \brief Returns the flow value on the given arc. + /// + /// Returns the flow value on the given arc. + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + Value flow(const Arc& arc) const { + return (*_flow)[arc]; + } + + /// \brief Returns a const reference to the flow map. + /// + /// Returns a const reference to the arc map storing the found flow. + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + const FlowMap& flowMap() const { + return *_flow; + } + + /** + \brief Returns \c true if the given node is in a barrier. + + Barrier is a set \e B of nodes for which + + \f[ \sum_{uv\in A: u\in B} upper(uv) - + \sum_{uv\in A: v\in B} lower(uv) < \sum_{v\in B} sup(v) \f] + + holds. The existence of a set with this property prooves that a + feasible circualtion cannot exist. + + This function returns \c true if the given node is in the found + barrier. If a feasible circulation is found, the function + gives back \c false for every node. + + \pre Either \ref run() or \ref init() must be called before + using this function. + + \sa barrierMap() + \sa checkBarrier() + */ + bool barrier(const Node& node) const + { + return (*_level)[node] >= _el; + } + + /// \brief Gives back a barrier. + /// + /// This function sets \c bar to the characteristic vector of the + /// found barrier. \c bar should be a \ref concepts::WriteMap "writable" + /// node map with \c bool (or convertible) value type. + /// + /// If a feasible circulation is found, the function gives back an + /// empty set, so \c bar[v] will be \c false for all nodes \c v. + /// + /// \note This function calls \ref barrier() for each node, + /// so it runs in O(n) time. + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + /// + /// \sa barrier() + /// \sa checkBarrier() + template + void barrierMap(BarrierMap &bar) const + { + for(NodeIt n(_g);n!=INVALID;++n) + bar.set(n, (*_level)[n] >= _el); + } + + /// @} + + /// \name Checker Functions + /// The feasibility of the results can be checked using + /// these functions.\n + /// Either \ref run() or \ref start() should be called before + /// using them. + + ///@{ + + ///Check if the found flow is a feasible circulation + + ///Check if the found flow is a feasible circulation, + /// + bool checkFlow() const { + for(ArcIt e(_g);e!=INVALID;++e) + if((*_flow)[e]<(*_lo)[e]||(*_flow)[e]>(*_up)[e]) return false; + for(NodeIt n(_g);n!=INVALID;++n) + { + Value dif=-(*_supply)[n]; + for(InArcIt e(_g,n);e!=INVALID;++e) dif-=(*_flow)[e]; + for(OutArcIt e(_g,n);e!=INVALID;++e) dif+=(*_flow)[e]; + if(_tol.negative(dif)) return false; + } + return true; + } + + ///Check whether or not the last execution provides a barrier + + ///Check whether or not the last execution provides a barrier. + ///\sa barrier() + ///\sa barrierMap() + bool checkBarrier() const + { + Value delta=0; + Value inf_cap = std::numeric_limits::has_infinity ? + std::numeric_limits::infinity() : + std::numeric_limits::max(); + for(NodeIt n(_g);n!=INVALID;++n) + if(barrier(n)) + delta-=(*_supply)[n]; + for(ArcIt e(_g);e!=INVALID;++e) + { + Node s=_g.source(e); + Node t=_g.target(e); + if(barrier(s)&&!barrier(t)) { + if (_tol.less(inf_cap - (*_up)[e], delta)) return false; + delta+=(*_up)[e]; + } + else if(barrier(t)&&!barrier(s)) delta-=(*_lo)[e]; + } + return _tol.negative(delta); + } + + /// @} + + }; + +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/clp.cc b/extern/quadriflow/3rd/lemon-1.3.1/lemon/clp.cc new file mode 100644 index 00000000000..7c0ea74f22c --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/clp.cc @@ -0,0 +1,464 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 +#include + +namespace lemon { + + ClpLp::ClpLp() { + _prob = new ClpSimplex(); + _init_temporals(); + messageLevel(MESSAGE_NOTHING); + } + + ClpLp::ClpLp(const ClpLp& other) { + _prob = new ClpSimplex(*other._prob); + rows = other.rows; + cols = other.cols; + _init_temporals(); + messageLevel(MESSAGE_NOTHING); + } + + ClpLp::~ClpLp() { + delete _prob; + _clear_temporals(); + } + + void ClpLp::_init_temporals() { + _primal_ray = 0; + _dual_ray = 0; + } + + void ClpLp::_clear_temporals() { + if (_primal_ray) { + delete[] _primal_ray; + _primal_ray = 0; + } + if (_dual_ray) { + delete[] _dual_ray; + _dual_ray = 0; + } + } + + ClpLp* ClpLp::newSolver() const { + ClpLp* newlp = new ClpLp; + return newlp; + } + + ClpLp* ClpLp::cloneSolver() const { + ClpLp* copylp = new ClpLp(*this); + return copylp; + } + + const char* ClpLp::_solverName() const { return "ClpLp"; } + + int ClpLp::_addCol() { + _prob->addColumn(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX, 0.0); + return _prob->numberColumns() - 1; + } + + int ClpLp::_addRow() { + _prob->addRow(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX); + return _prob->numberRows() - 1; + } + + int ClpLp::_addRow(Value l, ExprIterator b, ExprIterator e, Value u) { + std::vector indexes; + std::vector values; + + for(ExprIterator it = b; it != e; ++it) { + indexes.push_back(it->first); + values.push_back(it->second); + } + + _prob->addRow(values.size(), &indexes.front(), &values.front(), l, u); + return _prob->numberRows() - 1; + } + + + void ClpLp::_eraseCol(int c) { + _col_names_ref.erase(_prob->getColumnName(c)); + _prob->deleteColumns(1, &c); + } + + void ClpLp::_eraseRow(int r) { + _row_names_ref.erase(_prob->getRowName(r)); + _prob->deleteRows(1, &r); + } + + void ClpLp::_eraseColId(int i) { + cols.eraseIndex(i); + cols.shiftIndices(i); + } + + void ClpLp::_eraseRowId(int i) { + rows.eraseIndex(i); + rows.shiftIndices(i); + } + + void ClpLp::_getColName(int c, std::string& name) const { + name = _prob->getColumnName(c); + } + + void ClpLp::_setColName(int c, const std::string& name) { + _prob->setColumnName(c, const_cast(name)); + _col_names_ref[name] = c; + } + + int ClpLp::_colByName(const std::string& name) const { + std::map::const_iterator it = _col_names_ref.find(name); + return it != _col_names_ref.end() ? it->second : -1; + } + + void ClpLp::_getRowName(int r, std::string& name) const { + name = _prob->getRowName(r); + } + + void ClpLp::_setRowName(int r, const std::string& name) { + _prob->setRowName(r, const_cast(name)); + _row_names_ref[name] = r; + } + + int ClpLp::_rowByName(const std::string& name) const { + std::map::const_iterator it = _row_names_ref.find(name); + return it != _row_names_ref.end() ? it->second : -1; + } + + + void ClpLp::_setRowCoeffs(int ix, ExprIterator b, ExprIterator e) { + std::map coeffs; + + int n = _prob->clpMatrix()->getNumCols(); + + const int* indices = _prob->clpMatrix()->getIndices(); + const double* elements = _prob->clpMatrix()->getElements(); + + for (int i = 0; i < n; ++i) { + CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[i]; + CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[i]; + + const int* it = std::lower_bound(indices + begin, indices + end, ix); + if (it != indices + end && *it == ix && elements[it - indices] != 0.0) { + coeffs[i] = 0.0; + } + } + + for (ExprIterator it = b; it != e; ++it) { + coeffs[it->first] = it->second; + } + + for (std::map::iterator it = coeffs.begin(); + it != coeffs.end(); ++it) { + _prob->modifyCoefficient(ix, it->first, it->second); + } + } + + void ClpLp::_getRowCoeffs(int ix, InsertIterator b) const { + int n = _prob->clpMatrix()->getNumCols(); + + const int* indices = _prob->clpMatrix()->getIndices(); + const double* elements = _prob->clpMatrix()->getElements(); + + for (int i = 0; i < n; ++i) { + CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[i]; + CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[i]; + + const int* it = std::lower_bound(indices + begin, indices + end, ix); + if (it != indices + end && *it == ix) { + *b = std::make_pair(i, elements[it - indices]); + } + } + } + + void ClpLp::_setColCoeffs(int ix, ExprIterator b, ExprIterator e) { + std::map coeffs; + + CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[ix]; + CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[ix]; + + const int* indices = _prob->clpMatrix()->getIndices(); + const double* elements = _prob->clpMatrix()->getElements(); + + for (CoinBigIndex i = begin; i != end; ++i) { + if (elements[i] != 0.0) { + coeffs[indices[i]] = 0.0; + } + } + for (ExprIterator it = b; it != e; ++it) { + coeffs[it->first] = it->second; + } + for (std::map::iterator it = coeffs.begin(); + it != coeffs.end(); ++it) { + _prob->modifyCoefficient(it->first, ix, it->second); + } + } + + void ClpLp::_getColCoeffs(int ix, InsertIterator b) const { + CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[ix]; + CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[ix]; + + const int* indices = _prob->clpMatrix()->getIndices(); + const double* elements = _prob->clpMatrix()->getElements(); + + for (CoinBigIndex i = begin; i != end; ++i) { + *b = std::make_pair(indices[i], elements[i]); + ++b; + } + } + + void ClpLp::_setCoeff(int ix, int jx, Value value) { + _prob->modifyCoefficient(ix, jx, value); + } + + ClpLp::Value ClpLp::_getCoeff(int ix, int jx) const { + CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[ix]; + CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[ix]; + + const int* indices = _prob->clpMatrix()->getIndices(); + const double* elements = _prob->clpMatrix()->getElements(); + + const int* it = std::lower_bound(indices + begin, indices + end, jx); + if (it != indices + end && *it == jx) { + return elements[it - indices]; + } else { + return 0.0; + } + } + + void ClpLp::_setColLowerBound(int i, Value lo) { + _prob->setColumnLower(i, lo == - INF ? - COIN_DBL_MAX : lo); + } + + ClpLp::Value ClpLp::_getColLowerBound(int i) const { + double val = _prob->getColLower()[i]; + return val == - COIN_DBL_MAX ? - INF : val; + } + + void ClpLp::_setColUpperBound(int i, Value up) { + _prob->setColumnUpper(i, up == INF ? COIN_DBL_MAX : up); + } + + ClpLp::Value ClpLp::_getColUpperBound(int i) const { + double val = _prob->getColUpper()[i]; + return val == COIN_DBL_MAX ? INF : val; + } + + void ClpLp::_setRowLowerBound(int i, Value lo) { + _prob->setRowLower(i, lo == - INF ? - COIN_DBL_MAX : lo); + } + + ClpLp::Value ClpLp::_getRowLowerBound(int i) const { + double val = _prob->getRowLower()[i]; + return val == - COIN_DBL_MAX ? - INF : val; + } + + void ClpLp::_setRowUpperBound(int i, Value up) { + _prob->setRowUpper(i, up == INF ? COIN_DBL_MAX : up); + } + + ClpLp::Value ClpLp::_getRowUpperBound(int i) const { + double val = _prob->getRowUpper()[i]; + return val == COIN_DBL_MAX ? INF : val; + } + + void ClpLp::_setObjCoeffs(ExprIterator b, ExprIterator e) { + int num = _prob->clpMatrix()->getNumCols(); + for (int i = 0; i < num; ++i) { + _prob->setObjectiveCoefficient(i, 0.0); + } + for (ExprIterator it = b; it != e; ++it) { + _prob->setObjectiveCoefficient(it->first, it->second); + } + } + + void ClpLp::_getObjCoeffs(InsertIterator b) const { + int num = _prob->clpMatrix()->getNumCols(); + for (int i = 0; i < num; ++i) { + Value coef = _prob->getObjCoefficients()[i]; + if (coef != 0.0) { + *b = std::make_pair(i, coef); + ++b; + } + } + } + + void ClpLp::_setObjCoeff(int i, Value obj_coef) { + _prob->setObjectiveCoefficient(i, obj_coef); + } + + ClpLp::Value ClpLp::_getObjCoeff(int i) const { + return _prob->getObjCoefficients()[i]; + } + + ClpLp::SolveExitStatus ClpLp::_solve() { + return _prob->primal() >= 0 ? SOLVED : UNSOLVED; + } + + ClpLp::SolveExitStatus ClpLp::solvePrimal() { + return _prob->primal() >= 0 ? SOLVED : UNSOLVED; + } + + ClpLp::SolveExitStatus ClpLp::solveDual() { + return _prob->dual() >= 0 ? SOLVED : UNSOLVED; + } + + ClpLp::SolveExitStatus ClpLp::solveBarrier() { + return _prob->barrier() >= 0 ? SOLVED : UNSOLVED; + } + + ClpLp::Value ClpLp::_getPrimal(int i) const { + return _prob->primalColumnSolution()[i]; + } + ClpLp::Value ClpLp::_getPrimalValue() const { + return _prob->objectiveValue(); + } + + ClpLp::Value ClpLp::_getDual(int i) const { + return _prob->dualRowSolution()[i]; + } + + ClpLp::Value ClpLp::_getPrimalRay(int i) const { + if (!_primal_ray) { + _primal_ray = _prob->unboundedRay(); + LEMON_ASSERT(_primal_ray != 0, "Primal ray is not provided"); + } + return _primal_ray[i]; + } + + ClpLp::Value ClpLp::_getDualRay(int i) const { + if (!_dual_ray) { + _dual_ray = _prob->infeasibilityRay(); + LEMON_ASSERT(_dual_ray != 0, "Dual ray is not provided"); + } + return _dual_ray[i]; + } + + ClpLp::VarStatus ClpLp::_getColStatus(int i) const { + switch (_prob->getColumnStatus(i)) { + case ClpSimplex::basic: + return BASIC; + case ClpSimplex::isFree: + return FREE; + case ClpSimplex::atUpperBound: + return UPPER; + case ClpSimplex::atLowerBound: + return LOWER; + case ClpSimplex::isFixed: + return FIXED; + case ClpSimplex::superBasic: + return FREE; + default: + LEMON_ASSERT(false, "Wrong column status"); + return VarStatus(); + } + } + + ClpLp::VarStatus ClpLp::_getRowStatus(int i) const { + switch (_prob->getColumnStatus(i)) { + case ClpSimplex::basic: + return BASIC; + case ClpSimplex::isFree: + return FREE; + case ClpSimplex::atUpperBound: + return UPPER; + case ClpSimplex::atLowerBound: + return LOWER; + case ClpSimplex::isFixed: + return FIXED; + case ClpSimplex::superBasic: + return FREE; + default: + LEMON_ASSERT(false, "Wrong row status"); + return VarStatus(); + } + } + + + ClpLp::ProblemType ClpLp::_getPrimalType() const { + if (_prob->isProvenOptimal()) { + return OPTIMAL; + } else if (_prob->isProvenPrimalInfeasible()) { + return INFEASIBLE; + } else if (_prob->isProvenDualInfeasible()) { + return UNBOUNDED; + } else { + return UNDEFINED; + } + } + + ClpLp::ProblemType ClpLp::_getDualType() const { + if (_prob->isProvenOptimal()) { + return OPTIMAL; + } else if (_prob->isProvenDualInfeasible()) { + return INFEASIBLE; + } else if (_prob->isProvenPrimalInfeasible()) { + return INFEASIBLE; + } else { + return UNDEFINED; + } + } + + void ClpLp::_setSense(ClpLp::Sense sense) { + switch (sense) { + case MIN: + _prob->setOptimizationDirection(1); + break; + case MAX: + _prob->setOptimizationDirection(-1); + break; + } + } + + ClpLp::Sense ClpLp::_getSense() const { + double dir = _prob->optimizationDirection(); + if (dir > 0.0) { + return MIN; + } else { + return MAX; + } + } + + void ClpLp::_clear() { + delete _prob; + _prob = new ClpSimplex(); + _col_names_ref.clear(); + _clear_temporals(); + } + + void ClpLp::_messageLevel(MessageLevel level) { + switch (level) { + case MESSAGE_NOTHING: + _prob->setLogLevel(0); + break; + case MESSAGE_ERROR: + _prob->setLogLevel(1); + break; + case MESSAGE_WARNING: + _prob->setLogLevel(2); + break; + case MESSAGE_NORMAL: + _prob->setLogLevel(3); + break; + case MESSAGE_VERBOSE: + _prob->setLogLevel(4); + break; + } + } + +} //END OF NAMESPACE LEMON diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/clp.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/clp.h new file mode 100644 index 00000000000..fd331ac1354 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/clp.h @@ -0,0 +1,164 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_CLP_H +#define LEMON_CLP_H + +///\file +///\brief Header of the LEMON-CLP lp solver interface. + +#include +#include + +#include + +class ClpSimplex; + +namespace lemon { + + /// \ingroup lp_group + /// + /// \brief Interface for the CLP solver + /// + /// This class implements an interface for the Clp LP solver. The + /// Clp library is an object oriented lp solver library developed at + /// the IBM. The CLP is part of the COIN-OR package and it can be + /// used with Common Public License. + class ClpLp : public LpSolver { + protected: + + ClpSimplex* _prob; + + std::map _col_names_ref; + std::map _row_names_ref; + + public: + + /// \e + ClpLp(); + /// \e + ClpLp(const ClpLp&); + /// \e + ~ClpLp(); + + /// \e + virtual ClpLp* newSolver() const; + /// \e + virtual ClpLp* cloneSolver() const; + + protected: + + mutable double* _primal_ray; + mutable double* _dual_ray; + + void _init_temporals(); + void _clear_temporals(); + + protected: + + virtual const char* _solverName() const; + + virtual int _addCol(); + virtual int _addRow(); + virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u); + + virtual void _eraseCol(int i); + virtual void _eraseRow(int i); + + virtual void _eraseColId(int i); + virtual void _eraseRowId(int i); + + virtual void _getColName(int col, std::string& name) const; + virtual void _setColName(int col, const std::string& name); + virtual int _colByName(const std::string& name) const; + + virtual void _getRowName(int row, std::string& name) const; + virtual void _setRowName(int row, const std::string& name); + virtual int _rowByName(const std::string& name) const; + + virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e); + virtual void _getRowCoeffs(int i, InsertIterator b) const; + + virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e); + virtual void _getColCoeffs(int i, InsertIterator b) const; + + virtual void _setCoeff(int row, int col, Value value); + virtual Value _getCoeff(int row, int col) const; + + virtual void _setColLowerBound(int i, Value value); + virtual Value _getColLowerBound(int i) const; + virtual void _setColUpperBound(int i, Value value); + virtual Value _getColUpperBound(int i) const; + + virtual void _setRowLowerBound(int i, Value value); + virtual Value _getRowLowerBound(int i) const; + virtual void _setRowUpperBound(int i, Value value); + virtual Value _getRowUpperBound(int i) const; + + virtual void _setObjCoeffs(ExprIterator, ExprIterator); + virtual void _getObjCoeffs(InsertIterator) const; + + virtual void _setObjCoeff(int i, Value obj_coef); + virtual Value _getObjCoeff(int i) const; + + virtual void _setSense(Sense sense); + virtual Sense _getSense() const; + + virtual SolveExitStatus _solve(); + + virtual Value _getPrimal(int i) const; + virtual Value _getDual(int i) const; + + virtual Value _getPrimalValue() const; + + virtual Value _getPrimalRay(int i) const; + virtual Value _getDualRay(int i) const; + + virtual VarStatus _getColStatus(int i) const; + virtual VarStatus _getRowStatus(int i) const; + + virtual ProblemType _getPrimalType() const; + virtual ProblemType _getDualType() const; + + virtual void _clear(); + + virtual void _messageLevel(MessageLevel); + + public: + + ///Solves LP with primal simplex method. + SolveExitStatus solvePrimal(); + + ///Solves LP with dual simplex method. + SolveExitStatus solveDual(); + + ///Solves LP with barrier method. + SolveExitStatus solveBarrier(); + + ///Returns the constraint identifier understood by CLP. + int clpRow(Row r) const { return rows(id(r)); } + + ///Returns the variable identifier understood by CLP. + int clpCol(Col c) const { return cols(id(c)); } + + }; + +} //END OF NAMESPACE LEMON + +#endif //LEMON_CLP_H + diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/color.cc b/extern/quadriflow/3rd/lemon-1.3.1/lemon/color.cc new file mode 100644 index 00000000000..a49167b5cc7 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/color.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. + * + */ + +///\file +///\brief Color constants + +#include + +namespace lemon { + + const Color WHITE(1,1,1); + + const Color BLACK(0,0,0); + const Color RED(1,0,0); + const Color GREEN(0,1,0); + const Color BLUE(0,0,1); + const Color YELLOW(1,1,0); + const Color MAGENTA(1,0,1); + const Color CYAN(0,1,1); + + const Color GREY(0,0,0); + const Color DARK_RED(.5,0,0); + const Color DARK_GREEN(0,.5,0); + const Color DARK_BLUE(0,0,.5); + const Color DARK_YELLOW(.5,.5,0); + const Color DARK_MAGENTA(.5,0,.5); + const Color DARK_CYAN(0,.5,.5); + +} //namespace lemon diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/color.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/color.h new file mode 100644 index 00000000000..02357910ff7 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/color.h @@ -0,0 +1,204 @@ +/* -*- 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_COLOR_H +#define LEMON_COLOR_H + +#include +#include +#include + + +///\ingroup misc +///\file +///\brief Tools to manage RGB colors. + +namespace lemon { + + + /// \addtogroup misc + /// @{ + + ///Data structure representing RGB colors. + + ///Data structure representing RGB colors. + class Color + { + double _r,_g,_b; + public: + ///Default constructor + Color() {} + ///Constructor + Color(double r,double g,double b) :_r(r),_g(g),_b(b) {}; + ///Set the red component + double & red() {return _r;} + ///Return the red component + const double & red() const {return _r;} + ///Set the green component + double & green() {return _g;} + ///Return the green component + const double & green() const {return _g;} + ///Set the blue component + double & blue() {return _b;} + ///Return the blue component + const double & blue() const {return _b;} + ///Set the color components + void set(double r,double g,double b) { _r=r;_g=g;_b=b; }; + }; + + /// White color constant + extern const Color WHITE; + /// Black color constant + extern const Color BLACK; + /// Red color constant + extern const Color RED; + /// Green color constant + extern const Color GREEN; + /// Blue color constant + extern const Color BLUE; + /// Yellow color constant + extern const Color YELLOW; + /// Magenta color constant + extern const Color MAGENTA; + /// Cyan color constant + extern const Color CYAN; + /// Grey color constant + extern const Color GREY; + /// Dark red color constant + extern const Color DARK_RED; + /// Dark green color constant + extern const Color DARK_GREEN; + /// Drak blue color constant + extern const Color DARK_BLUE; + /// Dark yellow color constant + extern const Color DARK_YELLOW; + /// Dark magenta color constant + extern const Color DARK_MAGENTA; + /// Dark cyan color constant + extern const Color DARK_CYAN; + + ///Map ints to different Colors + + ///This map assigns one of the predefined \ref Color "Color"s to + ///each int. It is possible to change the colors as well as + ///their number. The integer range is cyclically mapped to the + ///provided set of colors. + /// + ///This is a true \ref concepts::ReferenceMap "reference map", so + ///you can also change the actual colors. + + class Palette : public MapBase + { + std::vector colors; + public: + ///Constructor + + ///Constructor. + ///\param have_white Indicates whether white is among the + ///provided initial colors (\c true) or not (\c false). If it is true, + ///white will be assigned to \c 0. + ///\param num The number of the allocated colors. If it is \c -1, + ///the default color configuration is set up (26 color plus optionaly the + ///white). If \c num is less then 26/27 then the default color + ///list is cut. Otherwise the color list is filled repeatedly with + ///the default color list. (The colors can be changed later on.) + Palette(bool have_white=false,int num=-1) + { + if (num==0) return; + do { + if(have_white) colors.push_back(Color(1,1,1)); + + colors.push_back(Color(0,0,0)); + colors.push_back(Color(1,0,0)); + colors.push_back(Color(0,1,0)); + colors.push_back(Color(0,0,1)); + colors.push_back(Color(1,1,0)); + colors.push_back(Color(1,0,1)); + colors.push_back(Color(0,1,1)); + + colors.push_back(Color(.5,0,0)); + colors.push_back(Color(0,.5,0)); + colors.push_back(Color(0,0,.5)); + colors.push_back(Color(.5,.5,0)); + colors.push_back(Color(.5,0,.5)); + colors.push_back(Color(0,.5,.5)); + + colors.push_back(Color(.5,.5,.5)); + colors.push_back(Color(1,.5,.5)); + colors.push_back(Color(.5,1,.5)); + colors.push_back(Color(.5,.5,1)); + colors.push_back(Color(1,1,.5)); + colors.push_back(Color(1,.5,1)); + colors.push_back(Color(.5,1,1)); + + colors.push_back(Color(1,.5,0)); + colors.push_back(Color(.5,1,0)); + colors.push_back(Color(1,0,.5)); + colors.push_back(Color(0,1,.5)); + colors.push_back(Color(0,.5,1)); + colors.push_back(Color(.5,0,1)); + } while(int(colors.size())=0) colors.resize(num); + } + ///\e + Color &operator[](int i) + { + return colors[i%colors.size()]; + } + ///\e + const Color &operator[](int i) const + { + return colors[i%colors.size()]; + } + ///\e + void set(int i,const Color &c) + { + colors[i%colors.size()]=c; + } + ///Adds a new color to the end of the color list. + void add(const Color &c) + { + colors.push_back(c); + } + + ///Sets the number of the existing colors. + void resize(int s) { colors.resize(s);} + ///Returns the number of the existing colors. + int size() const { return int(colors.size());} + }; + + ///Returns a visibly distinct \ref Color + + ///Returns a \ref Color which is as different from the given parameter + ///as it is possible. + inline Color distantColor(const Color &c) + { + return Color(c.red()<.5?1:0,c.green()<.5?1:0,c.blue()<.5?1:0); + } + ///Returns black for light colors and white for the dark ones. + + ///Returns black for light colors and white for the dark ones. + inline Color distantBW(const Color &c){ + return (.2125*c.red()+.7154*c.green()+.0721*c.blue())<.5 ? WHITE : BLACK; + } + + /// @} + +} //END OF NAMESPACE LEMON + +#endif // LEMON_COLOR_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/concept_check.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concept_check.h new file mode 100644 index 00000000000..38355b0f228 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concept_check.h @@ -0,0 +1,77 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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. + * + */ + +// The contents of this file was inspired by the concept checking +// utility of the BOOST library (http://www.boost.org). + +///\file +///\brief Basic utilities for concept checking. +/// + +#ifndef LEMON_CONCEPT_CHECK_H +#define LEMON_CONCEPT_CHECK_H + +namespace lemon { + + /* + "inline" is used for ignore_unused_variable_warning() + and function_requires() to make sure there is no + overtarget with g++. + */ + + template inline void ignore_unused_variable_warning(const T&) { } + template + inline void ignore_unused_variable_warning(const T1&, const T2&) { } + template + inline void ignore_unused_variable_warning(const T1&, const T2&, + const T3&) { } + template + inline void ignore_unused_variable_warning(const T1&, const T2&, + const T3&, const T4&) { } + template + inline void ignore_unused_variable_warning(const T1&, const T2&, + const T3&, const T4&, + const T5&) { } + template + inline void ignore_unused_variable_warning(const T1&, const T2&, + const T3&, const T4&, + const T5&, const T6&) { } + + ///\e + template + inline void function_requires() + { +#if !defined(NDEBUG) + void (Concept::*x)() = & Concept::constraints; + ::lemon::ignore_unused_variable_warning(x); +#endif + } + + ///\e + template + inline void checkConcept() { +#if !defined(NDEBUG) + typedef typename Concept::template Constraints ConceptCheck; + void (ConceptCheck::*x)() = & ConceptCheck::constraints; + ::lemon::ignore_unused_variable_warning(x); +#endif + } + +} // namespace lemon + +#endif // LEMON_CONCEPT_CHECK_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/bpgraph.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/bpgraph.h new file mode 100644 index 00000000000..2ebdeaf8b2f --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/bpgraph.h @@ -0,0 +1,1029 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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. + * + */ + +///\ingroup graph_concepts +///\file +///\brief The concept of undirected graphs. + +#ifndef LEMON_CONCEPTS_BPGRAPH_H +#define LEMON_CONCEPTS_BPGRAPH_H + +#include +#include +#include +#include + +namespace lemon { + namespace concepts { + + /// \ingroup graph_concepts + /// + /// \brief Class describing the concept of undirected bipartite graphs. + /// + /// This class describes the common interface of all undirected + /// bipartite graphs. + /// + /// Like all concept classes, it only provides an interface + /// without any sensible implementation. So any general algorithm for + /// undirected bipartite graphs should compile with this class, + /// but it will not run properly, of course. + /// An actual graph implementation like \ref ListBpGraph or + /// \ref SmartBpGraph may have additional functionality. + /// + /// The bipartite graphs also fulfill the concept of \ref Graph + /// "undirected graphs". Bipartite graphs provide a bipartition of + /// the node set, namely a red and blue set of the nodes. The + /// nodes can be iterated with the RedNodeIt and BlueNodeIt in the + /// two node sets. With RedNodeMap and BlueNodeMap values can be + /// assigned to the nodes in the two sets. + /// + /// The edges of the graph cannot connect two nodes of the same + /// set. The edges inherent orientation is from the red nodes to + /// the blue nodes. + /// + /// \sa Graph + class BpGraph { + private: + /// BpGraphs are \e not copy constructible. Use bpGraphCopy instead. + BpGraph(const BpGraph&) {} + /// \brief Assignment of a graph to another one is \e not allowed. + /// Use bpGraphCopy instead. + void operator=(const BpGraph&) {} + + public: + /// Default constructor. + BpGraph() {} + + /// \brief Undirected graphs should be tagged with \c UndirectedTag. + /// + /// Undirected graphs should be tagged with \c UndirectedTag. + /// + /// This tag helps the \c enable_if technics to make compile time + /// specializations for undirected graphs. + typedef True UndirectedTag; + + /// The node type of the graph + + /// This class identifies a node of the graph. It also serves + /// as a base class of the node iterators, + /// thus they convert to this type. + class Node { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the object to an undefined value. + Node() { } + /// Copy constructor. + + /// Copy constructor. + /// + Node(const Node&) { } + + /// %Invalid constructor \& conversion. + + /// Initializes the object to be invalid. + /// \sa Invalid for more details. + Node(Invalid) { } + /// Equality operator + + /// Equality operator. + /// + /// Two iterators are equal if and only if they point to the + /// same object or both are \c INVALID. + bool operator==(Node) const { return true; } + + /// Inequality operator + + /// Inequality operator. + bool operator!=(Node) const { return true; } + + /// Artificial ordering operator. + + /// Artificial ordering operator. + /// + /// \note This operator only has to define some strict ordering of + /// the items; this order has nothing to do with the iteration + /// ordering of the items. + bool operator<(Node) const { return false; } + + }; + + /// Class to represent red nodes. + + /// This class represents the red nodes of the graph. It does + /// not supposed to be used directly, because the nodes can be + /// represented as Node instances. This class can be used as + /// template parameter for special map classes. + class RedNode : public Node { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the object to an undefined value. + RedNode() { } + /// Copy constructor. + + /// Copy constructor. + /// + RedNode(const RedNode&) : Node() { } + + /// %Invalid constructor \& conversion. + + /// Initializes the object to be invalid. + /// \sa Invalid for more details. + RedNode(Invalid) { } + + }; + + /// Class to represent blue nodes. + + /// This class represents the blue nodes of the graph. It does + /// not supposed to be used directly, because the nodes can be + /// represented as Node instances. This class can be used as + /// template parameter for special map classes. + class BlueNode : public Node { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the object to an undefined value. + BlueNode() { } + /// Copy constructor. + + /// Copy constructor. + /// + BlueNode(const BlueNode&) : Node() { } + + /// %Invalid constructor \& conversion. + + /// Initializes the object to be invalid. + /// \sa Invalid for more details. + BlueNode(Invalid) { } + + }; + + /// Iterator class for the red nodes. + + /// This iterator goes through each red node of the graph. + /// Its usage is quite simple, for example, you can count the number + /// of red nodes in a graph \c g of type \c %BpGraph like this: + ///\code + /// int count=0; + /// for (BpGraph::RedNodeIt n(g); n!=INVALID; ++n) ++count; + ///\endcode + class RedNodeIt : public RedNode { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the iterator to an undefined value. + RedNodeIt() { } + /// Copy constructor. + + /// Copy constructor. + /// + RedNodeIt(const RedNodeIt& n) : RedNode(n) { } + /// %Invalid constructor \& conversion. + + /// Initializes the iterator to be invalid. + /// \sa Invalid for more details. + RedNodeIt(Invalid) { } + /// Sets the iterator to the first red node. + + /// Sets the iterator to the first red node of the given + /// digraph. + explicit RedNodeIt(const BpGraph&) { } + /// Sets the iterator to the given red node. + + /// Sets the iterator to the given red node of the given + /// digraph. + RedNodeIt(const BpGraph&, const RedNode&) { } + /// Next node. + + /// Assign the iterator to the next red node. + /// + RedNodeIt& operator++() { return *this; } + }; + + /// Iterator class for the blue nodes. + + /// This iterator goes through each blue node of the graph. + /// Its usage is quite simple, for example, you can count the number + /// of blue nodes in a graph \c g of type \c %BpGraph like this: + ///\code + /// int count=0; + /// for (BpGraph::BlueNodeIt n(g); n!=INVALID; ++n) ++count; + ///\endcode + class BlueNodeIt : public BlueNode { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the iterator to an undefined value. + BlueNodeIt() { } + /// Copy constructor. + + /// Copy constructor. + /// + BlueNodeIt(const BlueNodeIt& n) : BlueNode(n) { } + /// %Invalid constructor \& conversion. + + /// Initializes the iterator to be invalid. + /// \sa Invalid for more details. + BlueNodeIt(Invalid) { } + /// Sets the iterator to the first blue node. + + /// Sets the iterator to the first blue node of the given + /// digraph. + explicit BlueNodeIt(const BpGraph&) { } + /// Sets the iterator to the given blue node. + + /// Sets the iterator to the given blue node of the given + /// digraph. + BlueNodeIt(const BpGraph&, const BlueNode&) { } + /// Next node. + + /// Assign the iterator to the next blue node. + /// + BlueNodeIt& operator++() { return *this; } + }; + + /// Iterator class for the nodes. + + /// This iterator goes through each node of the graph. + /// Its usage is quite simple, for example, you can count the number + /// of nodes in a graph \c g of type \c %BpGraph like this: + ///\code + /// int count=0; + /// for (BpGraph::NodeIt n(g); n!=INVALID; ++n) ++count; + ///\endcode + class NodeIt : public Node { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the iterator to an undefined value. + NodeIt() { } + /// Copy constructor. + + /// Copy constructor. + /// + NodeIt(const NodeIt& n) : Node(n) { } + /// %Invalid constructor \& conversion. + + /// Initializes the iterator to be invalid. + /// \sa Invalid for more details. + NodeIt(Invalid) { } + /// Sets the iterator to the first node. + + /// Sets the iterator to the first node of the given digraph. + /// + explicit NodeIt(const BpGraph&) { } + /// Sets the iterator to the given node. + + /// Sets the iterator to the given node of the given digraph. + /// + NodeIt(const BpGraph&, const Node&) { } + /// Next node. + + /// Assign the iterator to the next node. + /// + NodeIt& operator++() { return *this; } + }; + + + /// The edge type of the graph + + /// This class identifies an edge of the graph. It also serves + /// as a base class of the edge iterators, + /// thus they will convert to this type. + class Edge { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the object to an undefined value. + Edge() { } + /// Copy constructor. + + /// Copy constructor. + /// + Edge(const Edge&) { } + /// %Invalid constructor \& conversion. + + /// Initializes the object to be invalid. + /// \sa Invalid for more details. + Edge(Invalid) { } + /// Equality operator + + /// Equality operator. + /// + /// Two iterators are equal if and only if they point to the + /// same object or both are \c INVALID. + bool operator==(Edge) const { return true; } + /// Inequality operator + + /// Inequality operator. + bool operator!=(Edge) const { return true; } + + /// Artificial ordering operator. + + /// Artificial ordering operator. + /// + /// \note This operator only has to define some strict ordering of + /// the edges; this order has nothing to do with the iteration + /// ordering of the edges. + bool operator<(Edge) const { return false; } + }; + + /// Iterator class for the edges. + + /// This iterator goes through each edge of the graph. + /// Its usage is quite simple, for example, you can count the number + /// of edges in a graph \c g of type \c %BpGraph as follows: + ///\code + /// int count=0; + /// for(BpGraph::EdgeIt e(g); e!=INVALID; ++e) ++count; + ///\endcode + class EdgeIt : public Edge { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the iterator to an undefined value. + EdgeIt() { } + /// Copy constructor. + + /// Copy constructor. + /// + EdgeIt(const EdgeIt& e) : Edge(e) { } + /// %Invalid constructor \& conversion. + + /// Initializes the iterator to be invalid. + /// \sa Invalid for more details. + EdgeIt(Invalid) { } + /// Sets the iterator to the first edge. + + /// Sets the iterator to the first edge of the given graph. + /// + explicit EdgeIt(const BpGraph&) { } + /// Sets the iterator to the given edge. + + /// Sets the iterator to the given edge of the given graph. + /// + EdgeIt(const BpGraph&, const Edge&) { } + /// Next edge + + /// Assign the iterator to the next edge. + /// + EdgeIt& operator++() { return *this; } + }; + + /// Iterator class for the incident edges of a node. + + /// This iterator goes trough the incident undirected edges + /// of a certain node of a graph. + /// Its usage is quite simple, for example, you can compute the + /// degree (i.e. the number of incident edges) of a node \c n + /// in a graph \c g of type \c %BpGraph as follows. + /// + ///\code + /// int count=0; + /// for(BpGraph::IncEdgeIt e(g, n); e!=INVALID; ++e) ++count; + ///\endcode + /// + /// \warning Loop edges will be iterated twice. + class IncEdgeIt : public Edge { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the iterator to an undefined value. + IncEdgeIt() { } + /// Copy constructor. + + /// Copy constructor. + /// + IncEdgeIt(const IncEdgeIt& e) : Edge(e) { } + /// %Invalid constructor \& conversion. + + /// Initializes the iterator to be invalid. + /// \sa Invalid for more details. + IncEdgeIt(Invalid) { } + /// Sets the iterator to the first incident edge. + + /// Sets the iterator to the first incident edge of the given node. + /// + IncEdgeIt(const BpGraph&, const Node&) { } + /// Sets the iterator to the given edge. + + /// Sets the iterator to the given edge of the given graph. + /// + IncEdgeIt(const BpGraph&, const Edge&) { } + /// Next incident edge + + /// Assign the iterator to the next incident edge + /// of the corresponding node. + IncEdgeIt& operator++() { return *this; } + }; + + /// The arc type of the graph + + /// This class identifies a directed arc of the graph. It also serves + /// as a base class of the arc iterators, + /// thus they will convert to this type. + class Arc { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the object to an undefined value. + Arc() { } + /// Copy constructor. + + /// Copy constructor. + /// + Arc(const Arc&) { } + /// %Invalid constructor \& conversion. + + /// Initializes the object to be invalid. + /// \sa Invalid for more details. + Arc(Invalid) { } + /// Equality operator + + /// Equality operator. + /// + /// Two iterators are equal if and only if they point to the + /// same object or both are \c INVALID. + bool operator==(Arc) const { return true; } + /// Inequality operator + + /// Inequality operator. + bool operator!=(Arc) const { return true; } + + /// Artificial ordering operator. + + /// Artificial ordering operator. + /// + /// \note This operator only has to define some strict ordering of + /// the arcs; this order has nothing to do with the iteration + /// ordering of the arcs. + bool operator<(Arc) const { return false; } + + /// Converison to \c Edge + + /// Converison to \c Edge. + /// + operator Edge() const { return Edge(); } + }; + + /// Iterator class for the arcs. + + /// This iterator goes through each directed arc of the graph. + /// Its usage is quite simple, for example, you can count the number + /// of arcs in a graph \c g of type \c %BpGraph as follows: + ///\code + /// int count=0; + /// for(BpGraph::ArcIt a(g); a!=INVALID; ++a) ++count; + ///\endcode + class ArcIt : public Arc { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the iterator to an undefined value. + ArcIt() { } + /// Copy constructor. + + /// Copy constructor. + /// + ArcIt(const ArcIt& e) : Arc(e) { } + /// %Invalid constructor \& conversion. + + /// Initializes the iterator to be invalid. + /// \sa Invalid for more details. + ArcIt(Invalid) { } + /// Sets the iterator to the first arc. + + /// Sets the iterator to the first arc of the given graph. + /// + explicit ArcIt(const BpGraph &g) + { + ::lemon::ignore_unused_variable_warning(g); + } + /// Sets the iterator to the given arc. + + /// Sets the iterator to the given arc of the given graph. + /// + ArcIt(const BpGraph&, const Arc&) { } + /// Next arc + + /// Assign the iterator to the next arc. + /// + ArcIt& operator++() { return *this; } + }; + + /// Iterator class for the outgoing arcs of a node. + + /// This iterator goes trough the \e outgoing directed arcs of a + /// certain node of a graph. + /// Its usage is quite simple, for example, you can count the number + /// of outgoing arcs of a node \c n + /// in a graph \c g of type \c %BpGraph as follows. + ///\code + /// int count=0; + /// for (Digraph::OutArcIt a(g, n); a!=INVALID; ++a) ++count; + ///\endcode + class OutArcIt : public Arc { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the iterator to an undefined value. + OutArcIt() { } + /// Copy constructor. + + /// Copy constructor. + /// + OutArcIt(const OutArcIt& e) : Arc(e) { } + /// %Invalid constructor \& conversion. + + /// Initializes the iterator to be invalid. + /// \sa Invalid for more details. + OutArcIt(Invalid) { } + /// Sets the iterator to the first outgoing arc. + + /// Sets the iterator to the first outgoing arc of the given node. + /// + OutArcIt(const BpGraph& n, const Node& g) { + ::lemon::ignore_unused_variable_warning(n); + ::lemon::ignore_unused_variable_warning(g); + } + /// Sets the iterator to the given arc. + + /// Sets the iterator to the given arc of the given graph. + /// + OutArcIt(const BpGraph&, const Arc&) { } + /// Next outgoing arc + + /// Assign the iterator to the next + /// outgoing arc of the corresponding node. + OutArcIt& operator++() { return *this; } + }; + + /// Iterator class for the incoming arcs of a node. + + /// This iterator goes trough the \e incoming directed arcs of a + /// certain node of a graph. + /// Its usage is quite simple, for example, you can count the number + /// of incoming arcs of a node \c n + /// in a graph \c g of type \c %BpGraph as follows. + ///\code + /// int count=0; + /// for (Digraph::InArcIt a(g, n); a!=INVALID; ++a) ++count; + ///\endcode + class InArcIt : public Arc { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the iterator to an undefined value. + InArcIt() { } + /// Copy constructor. + + /// Copy constructor. + /// + InArcIt(const InArcIt& e) : Arc(e) { } + /// %Invalid constructor \& conversion. + + /// Initializes the iterator to be invalid. + /// \sa Invalid for more details. + InArcIt(Invalid) { } + /// Sets the iterator to the first incoming arc. + + /// Sets the iterator to the first incoming arc of the given node. + /// + InArcIt(const BpGraph& g, const Node& n) { + ::lemon::ignore_unused_variable_warning(n); + ::lemon::ignore_unused_variable_warning(g); + } + /// Sets the iterator to the given arc. + + /// Sets the iterator to the given arc of the given graph. + /// + InArcIt(const BpGraph&, const Arc&) { } + /// Next incoming arc + + /// Assign the iterator to the next + /// incoming arc of the corresponding node. + InArcIt& operator++() { return *this; } + }; + + /// \brief Standard graph map type for the nodes. + /// + /// Standard graph map type for the nodes. + /// It conforms to the ReferenceMap concept. + template + class NodeMap : public ReferenceMap + { + public: + + /// Constructor + explicit NodeMap(const BpGraph&) { } + /// Constructor with given initial value + NodeMap(const BpGraph&, T) { } + + private: + ///Copy constructor + NodeMap(const NodeMap& nm) : + ReferenceMap(nm) { } + ///Assignment operator + template + NodeMap& operator=(const CMap&) { + checkConcept, CMap>(); + return *this; + } + }; + + /// \brief Standard graph map type for the red nodes. + /// + /// Standard graph map type for the red nodes. + /// It conforms to the ReferenceMap concept. + template + class RedNodeMap : public ReferenceMap + { + public: + + /// Constructor + explicit RedNodeMap(const BpGraph&) { } + /// Constructor with given initial value + RedNodeMap(const BpGraph&, T) { } + + private: + ///Copy constructor + RedNodeMap(const RedNodeMap& nm) : + ReferenceMap(nm) { } + ///Assignment operator + template + RedNodeMap& operator=(const CMap&) { + checkConcept, CMap>(); + return *this; + } + }; + + /// \brief Standard graph map type for the blue nodes. + /// + /// Standard graph map type for the blue nodes. + /// It conforms to the ReferenceMap concept. + template + class BlueNodeMap : public ReferenceMap + { + public: + + /// Constructor + explicit BlueNodeMap(const BpGraph&) { } + /// Constructor with given initial value + BlueNodeMap(const BpGraph&, T) { } + + private: + ///Copy constructor + BlueNodeMap(const BlueNodeMap& nm) : + ReferenceMap(nm) { } + ///Assignment operator + template + BlueNodeMap& operator=(const CMap&) { + checkConcept, CMap>(); + return *this; + } + }; + + /// \brief Standard graph map type for the arcs. + /// + /// Standard graph map type for the arcs. + /// It conforms to the ReferenceMap concept. + template + class ArcMap : public ReferenceMap + { + public: + + /// Constructor + explicit ArcMap(const BpGraph&) { } + /// Constructor with given initial value + ArcMap(const BpGraph&, T) { } + + private: + ///Copy constructor + ArcMap(const ArcMap& em) : + ReferenceMap(em) { } + ///Assignment operator + template + ArcMap& operator=(const CMap&) { + checkConcept, CMap>(); + return *this; + } + }; + + /// \brief Standard graph map type for the edges. + /// + /// Standard graph map type for the edges. + /// It conforms to the ReferenceMap concept. + template + class EdgeMap : public ReferenceMap + { + public: + + /// Constructor + explicit EdgeMap(const BpGraph&) { } + /// Constructor with given initial value + EdgeMap(const BpGraph&, T) { } + + private: + ///Copy constructor + EdgeMap(const EdgeMap& em) : + ReferenceMap(em) {} + ///Assignment operator + template + EdgeMap& operator=(const CMap&) { + checkConcept, CMap>(); + return *this; + } + }; + + /// \brief Gives back %true for red nodes. + /// + /// Gives back %true for red nodes. + bool red(const Node&) const { return true; } + + /// \brief Gives back %true for blue nodes. + /// + /// Gives back %true for blue nodes. + bool blue(const Node&) const { return true; } + + /// \brief Converts the node to red node object. + /// + /// This function converts unsafely the node to red node + /// object. It should be called only if the node is from the red + /// partition or INVALID. + RedNode asRedNodeUnsafe(const Node&) const { return RedNode(); } + + /// \brief Converts the node to blue node object. + /// + /// This function converts unsafely the node to blue node + /// object. It should be called only if the node is from the red + /// partition or INVALID. + BlueNode asBlueNodeUnsafe(const Node&) const { return BlueNode(); } + + /// \brief Converts the node to red node object. + /// + /// This function converts safely the node to red node + /// object. If the node is not from the red partition, then it + /// returns INVALID. + RedNode asRedNode(const Node&) const { return RedNode(); } + + /// \brief Converts the node to blue node object. + /// + /// This function converts unsafely the node to blue node + /// object. If the node is not from the blue partition, then it + /// returns INVALID. + BlueNode asBlueNode(const Node&) const { return BlueNode(); } + + /// \brief Gives back the red end node of the edge. + /// + /// Gives back the red end node of the edge. + RedNode redNode(const Edge&) const { return RedNode(); } + + /// \brief Gives back the blue end node of the edge. + /// + /// Gives back the blue end node of the edge. + BlueNode blueNode(const Edge&) const { return BlueNode(); } + + /// \brief The first node of the edge. + /// + /// It is a synonim for the \c redNode(). + Node u(Edge) const { return INVALID; } + + /// \brief The second node of the edge. + /// + /// It is a synonim for the \c blueNode(). + Node v(Edge) const { return INVALID; } + + /// \brief The source node of the arc. + /// + /// Returns the source node of the given arc. + Node source(Arc) const { return INVALID; } + + /// \brief The target node of the arc. + /// + /// Returns the target node of the given arc. + Node target(Arc) const { return INVALID; } + + /// \brief The ID of the node. + /// + /// Returns the ID of the given node. + int id(Node) const { return -1; } + + /// \brief The red ID of the node. + /// + /// Returns the red ID of the given node. + int id(RedNode) const { return -1; } + + /// \brief The blue ID of the node. + /// + /// Returns the blue ID of the given node. + int id(BlueNode) const { return -1; } + + /// \brief The ID of the edge. + /// + /// Returns the ID of the given edge. + int id(Edge) const { return -1; } + + /// \brief The ID of the arc. + /// + /// Returns the ID of the given arc. + int id(Arc) const { return -1; } + + /// \brief The node with the given ID. + /// + /// Returns the node with the given ID. + /// \pre The argument should be a valid node ID in the graph. + Node nodeFromId(int) const { return INVALID; } + + /// \brief The edge with the given ID. + /// + /// Returns the edge with the given ID. + /// \pre The argument should be a valid edge ID in the graph. + Edge edgeFromId(int) const { return INVALID; } + + /// \brief The arc with the given ID. + /// + /// Returns the arc with the given ID. + /// \pre The argument should be a valid arc ID in the graph. + Arc arcFromId(int) const { return INVALID; } + + /// \brief An upper bound on the node IDs. + /// + /// Returns an upper bound on the node IDs. + int maxNodeId() const { return -1; } + + /// \brief An upper bound on the red IDs. + /// + /// Returns an upper bound on the red IDs. + int maxRedId() const { return -1; } + + /// \brief An upper bound on the blue IDs. + /// + /// Returns an upper bound on the blue IDs. + int maxBlueId() const { return -1; } + + /// \brief An upper bound on the edge IDs. + /// + /// Returns an upper bound on the edge IDs. + int maxEdgeId() const { return -1; } + + /// \brief An upper bound on the arc IDs. + /// + /// Returns an upper bound on the arc IDs. + int maxArcId() const { return -1; } + + /// \brief The direction of the arc. + /// + /// Returns \c true if the given arc goes from a red node to a blue node. + bool direction(Arc) const { return true; } + + /// \brief Direct the edge. + /// + /// Direct the given edge. The returned arc + /// represents the given edge and its direction comes + /// from the bool parameter. If it is \c true, then the source of the node + /// will be a red node. + Arc direct(Edge, bool) const { + return INVALID; + } + + /// \brief Direct the edge. + /// + /// Direct the given edge. The returned arc represents the given + /// edge and its source node is the given node. + Arc direct(Edge, Node) const { + return INVALID; + } + + /// \brief The oppositely directed arc. + /// + /// Returns the oppositely directed arc representing the same edge. + Arc oppositeArc(Arc) const { return INVALID; } + + /// \brief The opposite node on the edge. + /// + /// Returns the opposite node on the given edge. + Node oppositeNode(Node, Edge) const { return INVALID; } + + void first(Node&) const {} + void next(Node&) const {} + + void firstRed(RedNode&) const {} + void nextRed(RedNode&) const {} + + void firstBlue(BlueNode&) const {} + void nextBlue(BlueNode&) const {} + + void first(Edge&) const {} + void next(Edge&) const {} + + void first(Arc&) const {} + void next(Arc&) const {} + + void firstOut(Arc&, Node) const {} + void nextOut(Arc&) const {} + + void firstIn(Arc&, Node) const {} + void nextIn(Arc&) const {} + + void firstInc(Edge &, bool &, const Node &) const {} + void nextInc(Edge &, bool &) const {} + + // The second parameter is dummy. + Node fromId(int, Node) const { return INVALID; } + // The second parameter is dummy. + Edge fromId(int, Edge) const { return INVALID; } + // The second parameter is dummy. + Arc fromId(int, Arc) const { return INVALID; } + + // Dummy parameter. + int maxId(Node) const { return -1; } + // Dummy parameter. + int maxId(RedNode) const { return -1; } + // Dummy parameter. + int maxId(BlueNode) const { return -1; } + // Dummy parameter. + int maxId(Edge) const { return -1; } + // Dummy parameter. + int maxId(Arc) const { return -1; } + + /// \brief The base node of the iterator. + /// + /// Returns the base node of the given incident edge iterator. + Node baseNode(IncEdgeIt) const { return INVALID; } + + /// \brief The running node of the iterator. + /// + /// Returns the running node of the given incident edge iterator. + Node runningNode(IncEdgeIt) const { return INVALID; } + + /// \brief The base node of the iterator. + /// + /// Returns the base node of the given outgoing arc iterator + /// (i.e. the source node of the corresponding arc). + Node baseNode(OutArcIt) const { return INVALID; } + + /// \brief The running node of the iterator. + /// + /// Returns the running node of the given outgoing arc iterator + /// (i.e. the target node of the corresponding arc). + Node runningNode(OutArcIt) const { return INVALID; } + + /// \brief The base node of the iterator. + /// + /// Returns the base node of the given incoming arc iterator + /// (i.e. the target node of the corresponding arc). + Node baseNode(InArcIt) const { return INVALID; } + + /// \brief The running node of the iterator. + /// + /// Returns the running node of the given incoming arc iterator + /// (i.e. the source node of the corresponding arc). + Node runningNode(InArcIt) const { return INVALID; } + + template + struct Constraints { + void constraints() { + checkConcept(); + checkConcept, _BpGraph>(); + checkConcept, _BpGraph>(); + checkConcept, _BpGraph>(); + } + }; + + }; + + } + +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/digraph.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/digraph.h new file mode 100644 index 00000000000..dc3c36bbbc0 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/digraph.h @@ -0,0 +1,491 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_CONCEPTS_DIGRAPH_H +#define LEMON_CONCEPTS_DIGRAPH_H + +///\ingroup graph_concepts +///\file +///\brief The concept of directed graphs. + +#include +#include +#include +#include + +namespace lemon { + namespace concepts { + + /// \ingroup graph_concepts + /// + /// \brief Class describing the concept of directed graphs. + /// + /// This class describes the common interface of all directed + /// graphs (digraphs). + /// + /// Like all concept classes, it only provides an interface + /// without any sensible implementation. So any general algorithm for + /// directed graphs should compile with this class, but it will not + /// run properly, of course. + /// An actual digraph implementation like \ref ListDigraph or + /// \ref SmartDigraph may have additional functionality. + /// + /// \sa Graph + class Digraph { + private: + /// Diraphs are \e not copy constructible. Use DigraphCopy instead. + Digraph(const Digraph &) {} + /// \brief Assignment of a digraph to another one is \e not allowed. + /// Use DigraphCopy instead. + void operator=(const Digraph &) {} + + public: + /// Default constructor. + Digraph() { } + + /// The node type of the digraph + + /// This class identifies a node of the digraph. It also serves + /// as a base class of the node iterators, + /// thus they convert to this type. + class Node { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the object to an undefined value. + Node() { } + /// Copy constructor. + + /// Copy constructor. + /// + Node(const Node&) { } + + /// %Invalid constructor \& conversion. + + /// Initializes the object to be invalid. + /// \sa Invalid for more details. + Node(Invalid) { } + /// Equality operator + + /// Equality operator. + /// + /// Two iterators are equal if and only if they point to the + /// same object or both are \c INVALID. + bool operator==(Node) const { return true; } + + /// Inequality operator + + /// Inequality operator. + bool operator!=(Node) const { return true; } + + /// Artificial ordering operator. + + /// Artificial ordering operator. + /// + /// \note This operator only has to define some strict ordering of + /// the nodes; this order has nothing to do with the iteration + /// ordering of the nodes. + bool operator<(Node) const { return false; } + }; + + /// Iterator class for the nodes. + + /// This iterator goes through each node of the digraph. + /// Its usage is quite simple, for example, you can count the number + /// of nodes in a digraph \c g of type \c %Digraph like this: + ///\code + /// int count=0; + /// for (Digraph::NodeIt n(g); n!=INVALID; ++n) ++count; + ///\endcode + class NodeIt : public Node { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the iterator to an undefined value. + NodeIt() { } + /// Copy constructor. + + /// Copy constructor. + /// + NodeIt(const NodeIt& n) : Node(n) { } + /// %Invalid constructor \& conversion. + + /// Initializes the iterator to be invalid. + /// \sa Invalid for more details. + NodeIt(Invalid) { } + /// Sets the iterator to the first node. + + /// Sets the iterator to the first node of the given digraph. + /// + explicit NodeIt(const Digraph&) { } + /// Sets the iterator to the given node. + + /// Sets the iterator to the given node of the given digraph. + /// + NodeIt(const Digraph&, const Node&) { } + /// Next node. + + /// Assign the iterator to the next node. + /// + NodeIt& operator++() { return *this; } + }; + + + /// The arc type of the digraph + + /// This class identifies an arc of the digraph. It also serves + /// as a base class of the arc iterators, + /// thus they will convert to this type. + class Arc { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the object to an undefined value. + Arc() { } + /// Copy constructor. + + /// Copy constructor. + /// + Arc(const Arc&) { } + /// %Invalid constructor \& conversion. + + /// Initializes the object to be invalid. + /// \sa Invalid for more details. + Arc(Invalid) { } + /// Equality operator + + /// Equality operator. + /// + /// Two iterators are equal if and only if they point to the + /// same object or both are \c INVALID. + bool operator==(Arc) const { return true; } + /// Inequality operator + + /// Inequality operator. + bool operator!=(Arc) const { return true; } + + /// Artificial ordering operator. + + /// Artificial ordering operator. + /// + /// \note This operator only has to define some strict ordering of + /// the arcs; this order has nothing to do with the iteration + /// ordering of the arcs. + bool operator<(Arc) const { return false; } + }; + + /// Iterator class for the outgoing arcs of a node. + + /// This iterator goes trough the \e outgoing arcs of a certain node + /// of a digraph. + /// Its usage is quite simple, for example, you can count the number + /// of outgoing arcs of a node \c n + /// in a digraph \c g of type \c %Digraph as follows. + ///\code + /// int count=0; + /// for (Digraph::OutArcIt a(g, n); a!=INVALID; ++a) ++count; + ///\endcode + class OutArcIt : public Arc { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the iterator to an undefined value. + OutArcIt() { } + /// Copy constructor. + + /// Copy constructor. + /// + OutArcIt(const OutArcIt& e) : Arc(e) { } + /// %Invalid constructor \& conversion. + + /// Initializes the iterator to be invalid. + /// \sa Invalid for more details. + OutArcIt(Invalid) { } + /// Sets the iterator to the first outgoing arc. + + /// Sets the iterator to the first outgoing arc of the given node. + /// + OutArcIt(const Digraph&, const Node&) { } + /// Sets the iterator to the given arc. + + /// Sets the iterator to the given arc of the given digraph. + /// + OutArcIt(const Digraph&, const Arc&) { } + /// Next outgoing arc + + /// Assign the iterator to the next + /// outgoing arc of the corresponding node. + OutArcIt& operator++() { return *this; } + }; + + /// Iterator class for the incoming arcs of a node. + + /// This iterator goes trough the \e incoming arcs of a certain node + /// of a digraph. + /// Its usage is quite simple, for example, you can count the number + /// of incoming arcs of a node \c n + /// in a digraph \c g of type \c %Digraph as follows. + ///\code + /// int count=0; + /// for(Digraph::InArcIt a(g, n); a!=INVALID; ++a) ++count; + ///\endcode + class InArcIt : public Arc { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the iterator to an undefined value. + InArcIt() { } + /// Copy constructor. + + /// Copy constructor. + /// + InArcIt(const InArcIt& e) : Arc(e) { } + /// %Invalid constructor \& conversion. + + /// Initializes the iterator to be invalid. + /// \sa Invalid for more details. + InArcIt(Invalid) { } + /// Sets the iterator to the first incoming arc. + + /// Sets the iterator to the first incoming arc of the given node. + /// + InArcIt(const Digraph&, const Node&) { } + /// Sets the iterator to the given arc. + + /// Sets the iterator to the given arc of the given digraph. + /// + InArcIt(const Digraph&, const Arc&) { } + /// Next incoming arc + + /// Assign the iterator to the next + /// incoming arc of the corresponding node. + InArcIt& operator++() { return *this; } + }; + + /// Iterator class for the arcs. + + /// This iterator goes through each arc of the digraph. + /// Its usage is quite simple, for example, you can count the number + /// of arcs in a digraph \c g of type \c %Digraph as follows: + ///\code + /// int count=0; + /// for(Digraph::ArcIt a(g); a!=INVALID; ++a) ++count; + ///\endcode + class ArcIt : public Arc { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the iterator to an undefined value. + ArcIt() { } + /// Copy constructor. + + /// Copy constructor. + /// + ArcIt(const ArcIt& e) : Arc(e) { } + /// %Invalid constructor \& conversion. + + /// Initializes the iterator to be invalid. + /// \sa Invalid for more details. + ArcIt(Invalid) { } + /// Sets the iterator to the first arc. + + /// Sets the iterator to the first arc of the given digraph. + /// + explicit ArcIt(const Digraph& g) { + ::lemon::ignore_unused_variable_warning(g); + } + /// Sets the iterator to the given arc. + + /// Sets the iterator to the given arc of the given digraph. + /// + ArcIt(const Digraph&, const Arc&) { } + /// Next arc + + /// Assign the iterator to the next arc. + /// + ArcIt& operator++() { return *this; } + }; + + /// \brief The source node of the arc. + /// + /// Returns the source node of the given arc. + Node source(Arc) const { return INVALID; } + + /// \brief The target node of the arc. + /// + /// Returns the target node of the given arc. + Node target(Arc) const { return INVALID; } + + /// \brief The ID of the node. + /// + /// Returns the ID of the given node. + int id(Node) const { return -1; } + + /// \brief The ID of the arc. + /// + /// Returns the ID of the given arc. + int id(Arc) const { return -1; } + + /// \brief The node with the given ID. + /// + /// Returns the node with the given ID. + /// \pre The argument should be a valid node ID in the digraph. + Node nodeFromId(int) const { return INVALID; } + + /// \brief The arc with the given ID. + /// + /// Returns the arc with the given ID. + /// \pre The argument should be a valid arc ID in the digraph. + Arc arcFromId(int) const { return INVALID; } + + /// \brief An upper bound on the node IDs. + /// + /// Returns an upper bound on the node IDs. + int maxNodeId() const { return -1; } + + /// \brief An upper bound on the arc IDs. + /// + /// Returns an upper bound on the arc IDs. + int maxArcId() const { return -1; } + + void first(Node&) const {} + void next(Node&) const {} + + void first(Arc&) const {} + void next(Arc&) const {} + + + void firstIn(Arc&, const Node&) const {} + void nextIn(Arc&) const {} + + void firstOut(Arc&, const Node&) const {} + void nextOut(Arc&) const {} + + // The second parameter is dummy. + Node fromId(int, Node) const { return INVALID; } + // The second parameter is dummy. + Arc fromId(int, Arc) const { return INVALID; } + + // Dummy parameter. + int maxId(Node) const { return -1; } + // Dummy parameter. + int maxId(Arc) const { return -1; } + + /// \brief The opposite node on the arc. + /// + /// Returns the opposite node on the given arc. + Node oppositeNode(Node, Arc) const { return INVALID; } + + /// \brief The base node of the iterator. + /// + /// Returns the base node of the given outgoing arc iterator + /// (i.e. the source node of the corresponding arc). + Node baseNode(OutArcIt) const { return INVALID; } + + /// \brief The running node of the iterator. + /// + /// Returns the running node of the given outgoing arc iterator + /// (i.e. the target node of the corresponding arc). + Node runningNode(OutArcIt) const { return INVALID; } + + /// \brief The base node of the iterator. + /// + /// Returns the base node of the given incoming arc iterator + /// (i.e. the target node of the corresponding arc). + Node baseNode(InArcIt) const { return INVALID; } + + /// \brief The running node of the iterator. + /// + /// Returns the running node of the given incoming arc iterator + /// (i.e. the source node of the corresponding arc). + Node runningNode(InArcIt) const { return INVALID; } + + /// \brief Standard graph map type for the nodes. + /// + /// Standard graph map type for the nodes. + /// It conforms to the ReferenceMap concept. + template + class NodeMap : public ReferenceMap { + public: + + /// Constructor + explicit NodeMap(const Digraph&) { } + /// Constructor with given initial value + NodeMap(const Digraph&, T) { } + + private: + ///Copy constructor + NodeMap(const NodeMap& nm) : + ReferenceMap(nm) { } + ///Assignment operator + template + NodeMap& operator=(const CMap&) { + checkConcept, CMap>(); + return *this; + } + }; + + /// \brief Standard graph map type for the arcs. + /// + /// Standard graph map type for the arcs. + /// It conforms to the ReferenceMap concept. + template + class ArcMap : public ReferenceMap { + public: + + /// Constructor + explicit ArcMap(const Digraph&) { } + /// Constructor with given initial value + ArcMap(const Digraph&, T) { } + + private: + ///Copy constructor + ArcMap(const ArcMap& em) : + ReferenceMap(em) { } + ///Assignment operator + template + ArcMap& operator=(const CMap&) { + checkConcept, CMap>(); + return *this; + } + }; + + template + struct Constraints { + void constraints() { + checkConcept(); + checkConcept, _Digraph>(); + checkConcept, _Digraph>(); + checkConcept, _Digraph>(); + } + }; + + }; + + } //namespace concepts +} //namespace lemon + + + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/graph.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/graph.h new file mode 100644 index 00000000000..76e43da0680 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/graph.h @@ -0,0 +1,788 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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. + * + */ + +///\ingroup graph_concepts +///\file +///\brief The concept of undirected graphs. + +#ifndef LEMON_CONCEPTS_GRAPH_H +#define LEMON_CONCEPTS_GRAPH_H + +#include +#include +#include +#include + +namespace lemon { + namespace concepts { + + /// \ingroup graph_concepts + /// + /// \brief Class describing the concept of undirected graphs. + /// + /// This class describes the common interface of all undirected + /// graphs. + /// + /// Like all concept classes, it only provides an interface + /// without any sensible implementation. So any general algorithm for + /// undirected graphs should compile with this class, but it will not + /// run properly, of course. + /// An actual graph implementation like \ref ListGraph or + /// \ref SmartGraph may have additional functionality. + /// + /// The undirected graphs also fulfill the concept of \ref Digraph + /// "directed graphs", since each edge can also be regarded as two + /// oppositely directed arcs. + /// Undirected graphs provide an Edge type for the undirected edges and + /// an Arc type for the directed arcs. The Arc type is convertible to + /// Edge or inherited from it, i.e. the corresponding edge can be + /// obtained from an arc. + /// EdgeIt and EdgeMap classes can be used for the edges, while ArcIt + /// and ArcMap classes can be used for the arcs (just like in digraphs). + /// Both InArcIt and OutArcIt iterates on the same edges but with + /// opposite direction. IncEdgeIt also iterates on the same edges + /// as OutArcIt and InArcIt, but it is not convertible to Arc, + /// only to Edge. + /// + /// In LEMON, each undirected edge has an inherent orientation. + /// Thus it can defined if an arc is forward or backward oriented in + /// an undirected graph with respect to this default oriantation of + /// the represented edge. + /// With the direction() and direct() functions the direction + /// of an arc can be obtained and set, respectively. + /// + /// Only nodes and edges can be added to or removed from an undirected + /// graph and the corresponding arcs are added or removed automatically. + /// + /// \sa Digraph + class Graph { + private: + /// Graphs are \e not copy constructible. Use GraphCopy instead. + Graph(const Graph&) {} + /// \brief Assignment of a graph to another one is \e not allowed. + /// Use GraphCopy instead. + void operator=(const Graph&) {} + + public: + /// Default constructor. + Graph() {} + + /// \brief Undirected graphs should be tagged with \c UndirectedTag. + /// + /// Undirected graphs should be tagged with \c UndirectedTag. + /// + /// This tag helps the \c enable_if technics to make compile time + /// specializations for undirected graphs. + typedef True UndirectedTag; + + /// The node type of the graph + + /// This class identifies a node of the graph. It also serves + /// as a base class of the node iterators, + /// thus they convert to this type. + class Node { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the object to an undefined value. + Node() { } + /// Copy constructor. + + /// Copy constructor. + /// + Node(const Node&) { } + + /// %Invalid constructor \& conversion. + + /// Initializes the object to be invalid. + /// \sa Invalid for more details. + Node(Invalid) { } + /// Equality operator + + /// Equality operator. + /// + /// Two iterators are equal if and only if they point to the + /// same object or both are \c INVALID. + bool operator==(Node) const { return true; } + + /// Inequality operator + + /// Inequality operator. + bool operator!=(Node) const { return true; } + + /// Artificial ordering operator. + + /// Artificial ordering operator. + /// + /// \note This operator only has to define some strict ordering of + /// the items; this order has nothing to do with the iteration + /// ordering of the items. + bool operator<(Node) const { return false; } + + }; + + /// Iterator class for the nodes. + + /// This iterator goes through each node of the graph. + /// Its usage is quite simple, for example, you can count the number + /// of nodes in a graph \c g of type \c %Graph like this: + ///\code + /// int count=0; + /// for (Graph::NodeIt n(g); n!=INVALID; ++n) ++count; + ///\endcode + class NodeIt : public Node { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the iterator to an undefined value. + NodeIt() { } + /// Copy constructor. + + /// Copy constructor. + /// + NodeIt(const NodeIt& n) : Node(n) { } + /// %Invalid constructor \& conversion. + + /// Initializes the iterator to be invalid. + /// \sa Invalid for more details. + NodeIt(Invalid) { } + /// Sets the iterator to the first node. + + /// Sets the iterator to the first node of the given digraph. + /// + explicit NodeIt(const Graph&) { } + /// Sets the iterator to the given node. + + /// Sets the iterator to the given node of the given digraph. + /// + NodeIt(const Graph&, const Node&) { } + /// Next node. + + /// Assign the iterator to the next node. + /// + NodeIt& operator++() { return *this; } + }; + + + /// The edge type of the graph + + /// This class identifies an edge of the graph. It also serves + /// as a base class of the edge iterators, + /// thus they will convert to this type. + class Edge { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the object to an undefined value. + Edge() { } + /// Copy constructor. + + /// Copy constructor. + /// + Edge(const Edge&) { } + /// %Invalid constructor \& conversion. + + /// Initializes the object to be invalid. + /// \sa Invalid for more details. + Edge(Invalid) { } + /// Equality operator + + /// Equality operator. + /// + /// Two iterators are equal if and only if they point to the + /// same object or both are \c INVALID. + bool operator==(Edge) const { return true; } + /// Inequality operator + + /// Inequality operator. + bool operator!=(Edge) const { return true; } + + /// Artificial ordering operator. + + /// Artificial ordering operator. + /// + /// \note This operator only has to define some strict ordering of + /// the edges; this order has nothing to do with the iteration + /// ordering of the edges. + bool operator<(Edge) const { return false; } + }; + + /// Iterator class for the edges. + + /// This iterator goes through each edge of the graph. + /// Its usage is quite simple, for example, you can count the number + /// of edges in a graph \c g of type \c %Graph as follows: + ///\code + /// int count=0; + /// for(Graph::EdgeIt e(g); e!=INVALID; ++e) ++count; + ///\endcode + class EdgeIt : public Edge { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the iterator to an undefined value. + EdgeIt() { } + /// Copy constructor. + + /// Copy constructor. + /// + EdgeIt(const EdgeIt& e) : Edge(e) { } + /// %Invalid constructor \& conversion. + + /// Initializes the iterator to be invalid. + /// \sa Invalid for more details. + EdgeIt(Invalid) { } + /// Sets the iterator to the first edge. + + /// Sets the iterator to the first edge of the given graph. + /// + explicit EdgeIt(const Graph&) { } + /// Sets the iterator to the given edge. + + /// Sets the iterator to the given edge of the given graph. + /// + EdgeIt(const Graph&, const Edge&) { } + /// Next edge + + /// Assign the iterator to the next edge. + /// + EdgeIt& operator++() { return *this; } + }; + + /// Iterator class for the incident edges of a node. + + /// This iterator goes trough the incident undirected edges + /// of a certain node of a graph. + /// Its usage is quite simple, for example, you can compute the + /// degree (i.e. the number of incident edges) of a node \c n + /// in a graph \c g of type \c %Graph as follows. + /// + ///\code + /// int count=0; + /// for(Graph::IncEdgeIt e(g, n); e!=INVALID; ++e) ++count; + ///\endcode + /// + /// \warning Loop edges will be iterated twice. + class IncEdgeIt : public Edge { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the iterator to an undefined value. + IncEdgeIt() { } + /// Copy constructor. + + /// Copy constructor. + /// + IncEdgeIt(const IncEdgeIt& e) : Edge(e) { } + /// %Invalid constructor \& conversion. + + /// Initializes the iterator to be invalid. + /// \sa Invalid for more details. + IncEdgeIt(Invalid) { } + /// Sets the iterator to the first incident edge. + + /// Sets the iterator to the first incident edge of the given node. + /// + IncEdgeIt(const Graph&, const Node&) { } + /// Sets the iterator to the given edge. + + /// Sets the iterator to the given edge of the given graph. + /// + IncEdgeIt(const Graph&, const Edge&) { } + /// Next incident edge + + /// Assign the iterator to the next incident edge + /// of the corresponding node. + IncEdgeIt& operator++() { return *this; } + }; + + /// The arc type of the graph + + /// This class identifies a directed arc of the graph. It also serves + /// as a base class of the arc iterators, + /// thus they will convert to this type. + class Arc { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the object to an undefined value. + Arc() { } + /// Copy constructor. + + /// Copy constructor. + /// + Arc(const Arc&) { } + /// %Invalid constructor \& conversion. + + /// Initializes the object to be invalid. + /// \sa Invalid for more details. + Arc(Invalid) { } + /// Equality operator + + /// Equality operator. + /// + /// Two iterators are equal if and only if they point to the + /// same object or both are \c INVALID. + bool operator==(Arc) const { return true; } + /// Inequality operator + + /// Inequality operator. + bool operator!=(Arc) const { return true; } + + /// Artificial ordering operator. + + /// Artificial ordering operator. + /// + /// \note This operator only has to define some strict ordering of + /// the arcs; this order has nothing to do with the iteration + /// ordering of the arcs. + bool operator<(Arc) const { return false; } + + /// Converison to \c Edge + + /// Converison to \c Edge. + /// + operator Edge() const { return Edge(); } + }; + + /// Iterator class for the arcs. + + /// This iterator goes through each directed arc of the graph. + /// Its usage is quite simple, for example, you can count the number + /// of arcs in a graph \c g of type \c %Graph as follows: + ///\code + /// int count=0; + /// for(Graph::ArcIt a(g); a!=INVALID; ++a) ++count; + ///\endcode + class ArcIt : public Arc { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the iterator to an undefined value. + ArcIt() { } + /// Copy constructor. + + /// Copy constructor. + /// + ArcIt(const ArcIt& e) : Arc(e) { } + /// %Invalid constructor \& conversion. + + /// Initializes the iterator to be invalid. + /// \sa Invalid for more details. + ArcIt(Invalid) { } + /// Sets the iterator to the first arc. + + /// Sets the iterator to the first arc of the given graph. + /// + explicit ArcIt(const Graph &g) { + ::lemon::ignore_unused_variable_warning(g); + } + /// Sets the iterator to the given arc. + + /// Sets the iterator to the given arc of the given graph. + /// + ArcIt(const Graph&, const Arc&) { } + /// Next arc + + /// Assign the iterator to the next arc. + /// + ArcIt& operator++() { return *this; } + }; + + /// Iterator class for the outgoing arcs of a node. + + /// This iterator goes trough the \e outgoing directed arcs of a + /// certain node of a graph. + /// Its usage is quite simple, for example, you can count the number + /// of outgoing arcs of a node \c n + /// in a graph \c g of type \c %Graph as follows. + ///\code + /// int count=0; + /// for (Digraph::OutArcIt a(g, n); a!=INVALID; ++a) ++count; + ///\endcode + class OutArcIt : public Arc { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the iterator to an undefined value. + OutArcIt() { } + /// Copy constructor. + + /// Copy constructor. + /// + OutArcIt(const OutArcIt& e) : Arc(e) { } + /// %Invalid constructor \& conversion. + + /// Initializes the iterator to be invalid. + /// \sa Invalid for more details. + OutArcIt(Invalid) { } + /// Sets the iterator to the first outgoing arc. + + /// Sets the iterator to the first outgoing arc of the given node. + /// + OutArcIt(const Graph& n, const Node& g) { + ::lemon::ignore_unused_variable_warning(n); + ::lemon::ignore_unused_variable_warning(g); + } + /// Sets the iterator to the given arc. + + /// Sets the iterator to the given arc of the given graph. + /// + OutArcIt(const Graph&, const Arc&) { } + /// Next outgoing arc + + /// Assign the iterator to the next + /// outgoing arc of the corresponding node. + OutArcIt& operator++() { return *this; } + }; + + /// Iterator class for the incoming arcs of a node. + + /// This iterator goes trough the \e incoming directed arcs of a + /// certain node of a graph. + /// Its usage is quite simple, for example, you can count the number + /// of incoming arcs of a node \c n + /// in a graph \c g of type \c %Graph as follows. + ///\code + /// int count=0; + /// for (Digraph::InArcIt a(g, n); a!=INVALID; ++a) ++count; + ///\endcode + class InArcIt : public Arc { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the iterator to an undefined value. + InArcIt() { } + /// Copy constructor. + + /// Copy constructor. + /// + InArcIt(const InArcIt& e) : Arc(e) { } + /// %Invalid constructor \& conversion. + + /// Initializes the iterator to be invalid. + /// \sa Invalid for more details. + InArcIt(Invalid) { } + /// Sets the iterator to the first incoming arc. + + /// Sets the iterator to the first incoming arc of the given node. + /// + InArcIt(const Graph& g, const Node& n) { + ::lemon::ignore_unused_variable_warning(n); + ::lemon::ignore_unused_variable_warning(g); + } + /// Sets the iterator to the given arc. + + /// Sets the iterator to the given arc of the given graph. + /// + InArcIt(const Graph&, const Arc&) { } + /// Next incoming arc + + /// Assign the iterator to the next + /// incoming arc of the corresponding node. + InArcIt& operator++() { return *this; } + }; + + /// \brief Standard graph map type for the nodes. + /// + /// Standard graph map type for the nodes. + /// It conforms to the ReferenceMap concept. + template + class NodeMap : public ReferenceMap + { + public: + + /// Constructor + explicit NodeMap(const Graph&) { } + /// Constructor with given initial value + NodeMap(const Graph&, T) { } + + private: + ///Copy constructor + NodeMap(const NodeMap& nm) : + ReferenceMap(nm) { } + ///Assignment operator + template + NodeMap& operator=(const CMap&) { + checkConcept, CMap>(); + return *this; + } + }; + + /// \brief Standard graph map type for the arcs. + /// + /// Standard graph map type for the arcs. + /// It conforms to the ReferenceMap concept. + template + class ArcMap : public ReferenceMap + { + public: + + /// Constructor + explicit ArcMap(const Graph&) { } + /// Constructor with given initial value + ArcMap(const Graph&, T) { } + + private: + ///Copy constructor + ArcMap(const ArcMap& em) : + ReferenceMap(em) { } + ///Assignment operator + template + ArcMap& operator=(const CMap&) { + checkConcept, CMap>(); + return *this; + } + }; + + /// \brief Standard graph map type for the edges. + /// + /// Standard graph map type for the edges. + /// It conforms to the ReferenceMap concept. + template + class EdgeMap : public ReferenceMap + { + public: + + /// Constructor + explicit EdgeMap(const Graph&) { } + /// Constructor with given initial value + EdgeMap(const Graph&, T) { } + + private: + ///Copy constructor + EdgeMap(const EdgeMap& em) : + ReferenceMap(em) {} + ///Assignment operator + template + EdgeMap& operator=(const CMap&) { + checkConcept, CMap>(); + return *this; + } + }; + + /// \brief The first node of the edge. + /// + /// Returns the first node of the given edge. + /// + /// Edges don't have source and target nodes, however, methods + /// u() and v() are used to query the two end-nodes of an edge. + /// The orientation of an edge that arises this way is called + /// the inherent direction, it is used to define the default + /// direction for the corresponding arcs. + /// \sa v() + /// \sa direction() + Node u(Edge) const { return INVALID; } + + /// \brief The second node of the edge. + /// + /// Returns the second node of the given edge. + /// + /// Edges don't have source and target nodes, however, methods + /// u() and v() are used to query the two end-nodes of an edge. + /// The orientation of an edge that arises this way is called + /// the inherent direction, it is used to define the default + /// direction for the corresponding arcs. + /// \sa u() + /// \sa direction() + Node v(Edge) const { return INVALID; } + + /// \brief The source node of the arc. + /// + /// Returns the source node of the given arc. + Node source(Arc) const { return INVALID; } + + /// \brief The target node of the arc. + /// + /// Returns the target node of the given arc. + Node target(Arc) const { return INVALID; } + + /// \brief The ID of the node. + /// + /// Returns the ID of the given node. + int id(Node) const { return -1; } + + /// \brief The ID of the edge. + /// + /// Returns the ID of the given edge. + int id(Edge) const { return -1; } + + /// \brief The ID of the arc. + /// + /// Returns the ID of the given arc. + int id(Arc) const { return -1; } + + /// \brief The node with the given ID. + /// + /// Returns the node with the given ID. + /// \pre The argument should be a valid node ID in the graph. + Node nodeFromId(int) const { return INVALID; } + + /// \brief The edge with the given ID. + /// + /// Returns the edge with the given ID. + /// \pre The argument should be a valid edge ID in the graph. + Edge edgeFromId(int) const { return INVALID; } + + /// \brief The arc with the given ID. + /// + /// Returns the arc with the given ID. + /// \pre The argument should be a valid arc ID in the graph. + Arc arcFromId(int) const { return INVALID; } + + /// \brief An upper bound on the node IDs. + /// + /// Returns an upper bound on the node IDs. + int maxNodeId() const { return -1; } + + /// \brief An upper bound on the edge IDs. + /// + /// Returns an upper bound on the edge IDs. + int maxEdgeId() const { return -1; } + + /// \brief An upper bound on the arc IDs. + /// + /// Returns an upper bound on the arc IDs. + int maxArcId() const { return -1; } + + /// \brief The direction of the arc. + /// + /// Returns \c true if the direction of the given arc is the same as + /// the inherent orientation of the represented edge. + bool direction(Arc) const { return true; } + + /// \brief Direct the edge. + /// + /// Direct the given edge. The returned arc + /// represents the given edge and its direction comes + /// from the bool parameter. If it is \c true, then the direction + /// of the arc is the same as the inherent orientation of the edge. + Arc direct(Edge, bool) const { + return INVALID; + } + + /// \brief Direct the edge. + /// + /// Direct the given edge. The returned arc represents the given + /// edge and its source node is the given node. + Arc direct(Edge, Node) const { + return INVALID; + } + + /// \brief The oppositely directed arc. + /// + /// Returns the oppositely directed arc representing the same edge. + Arc oppositeArc(Arc) const { return INVALID; } + + /// \brief The opposite node on the edge. + /// + /// Returns the opposite node on the given edge. + Node oppositeNode(Node, Edge) const { return INVALID; } + + void first(Node&) const {} + void next(Node&) const {} + + void first(Edge&) const {} + void next(Edge&) const {} + + void first(Arc&) const {} + void next(Arc&) const {} + + void firstOut(Arc&, Node) const {} + void nextOut(Arc&) const {} + + void firstIn(Arc&, Node) const {} + void nextIn(Arc&) const {} + + void firstInc(Edge &, bool &, const Node &) const {} + void nextInc(Edge &, bool &) const {} + + // The second parameter is dummy. + Node fromId(int, Node) const { return INVALID; } + // The second parameter is dummy. + Edge fromId(int, Edge) const { return INVALID; } + // The second parameter is dummy. + Arc fromId(int, Arc) const { return INVALID; } + + // Dummy parameter. + int maxId(Node) const { return -1; } + // Dummy parameter. + int maxId(Edge) const { return -1; } + // Dummy parameter. + int maxId(Arc) const { return -1; } + + /// \brief The base node of the iterator. + /// + /// Returns the base node of the given incident edge iterator. + Node baseNode(IncEdgeIt) const { return INVALID; } + + /// \brief The running node of the iterator. + /// + /// Returns the running node of the given incident edge iterator. + Node runningNode(IncEdgeIt) const { return INVALID; } + + /// \brief The base node of the iterator. + /// + /// Returns the base node of the given outgoing arc iterator + /// (i.e. the source node of the corresponding arc). + Node baseNode(OutArcIt) const { return INVALID; } + + /// \brief The running node of the iterator. + /// + /// Returns the running node of the given outgoing arc iterator + /// (i.e. the target node of the corresponding arc). + Node runningNode(OutArcIt) const { return INVALID; } + + /// \brief The base node of the iterator. + /// + /// Returns the base node of the given incoming arc iterator + /// (i.e. the target node of the corresponding arc). + Node baseNode(InArcIt) const { return INVALID; } + + /// \brief The running node of the iterator. + /// + /// Returns the running node of the given incoming arc iterator + /// (i.e. the source node of the corresponding arc). + Node runningNode(InArcIt) const { return INVALID; } + + template + struct Constraints { + void constraints() { + checkConcept(); + checkConcept, _Graph>(); + checkConcept, _Graph>(); + checkConcept, _Graph>(); + } + }; + + }; + + } + +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/graph_components.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/graph_components.h new file mode 100644 index 00000000000..9df28f37e61 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/graph_components.h @@ -0,0 +1,2134 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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. + * + */ + +///\ingroup graph_concepts +///\file +///\brief The concepts of graph components. + +#ifndef LEMON_CONCEPTS_GRAPH_COMPONENTS_H +#define LEMON_CONCEPTS_GRAPH_COMPONENTS_H + +#include +#include + +#include + +namespace lemon { + namespace concepts { + + /// \brief Concept class for \c Node, \c Arc and \c Edge types. + /// + /// This class describes the concept of \c Node, \c Arc and \c Edge + /// subtypes of digraph and graph types. + /// + /// \note This class is a template class so that we can use it to + /// create graph skeleton classes. The reason for this is that \c Node + /// and \c Arc (or \c Edge) types should \e not derive from the same + /// base class. For \c Node you should instantiate it with character + /// \c 'n', for \c Arc with \c 'a' and for \c Edge with \c 'e'. +#ifndef DOXYGEN + template +#endif + class GraphItem { + public: + /// \brief Default constructor. + /// + /// Default constructor. + /// \warning The default constructor is not required to set + /// the item to some well-defined value. So you should consider it + /// as uninitialized. + GraphItem() {} + + /// \brief Copy constructor. + /// + /// Copy constructor. + GraphItem(const GraphItem &) {} + + /// \brief Constructor for conversion from \c INVALID. + /// + /// Constructor for conversion from \c INVALID. + /// It initializes the item to be invalid. + /// \sa Invalid for more details. + GraphItem(Invalid) {} + + /// \brief Assignment operator. + /// + /// Assignment operator for the item. + GraphItem& operator=(const GraphItem&) { return *this; } + + /// \brief Assignment operator for INVALID. + /// + /// This operator makes the item invalid. + GraphItem& operator=(Invalid) { return *this; } + + /// \brief Equality operator. + /// + /// Equality operator. + bool operator==(const GraphItem&) const { return false; } + + /// \brief Inequality operator. + /// + /// Inequality operator. + bool operator!=(const GraphItem&) const { return false; } + + /// \brief Ordering operator. + /// + /// This operator defines an ordering of the items. + /// It makes possible to use graph item types as key types in + /// associative containers (e.g. \c std::map). + /// + /// \note This operator only has to define some strict ordering of + /// the items; this order has nothing to do with the iteration + /// ordering of the items. + bool operator<(const GraphItem&) const { return false; } + + template + struct Constraints { + void constraints() { + _GraphItem i1; + i1=INVALID; + _GraphItem i2 = i1; + _GraphItem i3 = INVALID; + + i1 = i2 = i3; + + bool b; + ::lemon::ignore_unused_variable_warning(b); + + b = (ia == ib) && (ia != ib); + b = (ia == INVALID) && (ib != INVALID); + b = (ia < ib); + } + + const _GraphItem &ia; + const _GraphItem &ib; + Constraints() {} + }; + }; + + /// \brief Base skeleton class for directed graphs. + /// + /// This class describes the base interface of directed graph types. + /// All digraph %concepts have to conform to this class. + /// It just provides types for nodes and arcs and functions + /// to get the source and the target nodes of arcs. + class BaseDigraphComponent { + public: + + typedef BaseDigraphComponent Digraph; + + /// \brief Node class of the digraph. + /// + /// This class represents the nodes of the digraph. + typedef GraphItem<'n'> Node; + + /// \brief Arc class of the digraph. + /// + /// This class represents the arcs of the digraph. + typedef GraphItem<'a'> Arc; + + /// \brief Return the source node of an arc. + /// + /// This function returns the source node of an arc. + Node source(const Arc&) const { return INVALID; } + + /// \brief Return the target node of an arc. + /// + /// This function returns the target node of an arc. + Node target(const Arc&) const { return INVALID; } + + /// \brief Return the opposite node on the given arc. + /// + /// This function returns the opposite node on the given arc. + Node oppositeNode(const Node&, const Arc&) const { + return INVALID; + } + + template + struct Constraints { + typedef typename _Digraph::Node Node; + typedef typename _Digraph::Arc Arc; + + void constraints() { + checkConcept, Node>(); + checkConcept, Arc>(); + { + Node n; + Arc e(INVALID); + n = digraph.source(e); + n = digraph.target(e); + n = digraph.oppositeNode(n, e); + } + } + + const _Digraph& digraph; + Constraints() {} + }; + }; + + /// \brief Base skeleton class for undirected graphs. + /// + /// This class describes the base interface of undirected graph types. + /// All graph %concepts have to conform to this class. + /// It extends the interface of \ref BaseDigraphComponent with an + /// \c Edge type and functions to get the end nodes of edges, + /// to convert from arcs to edges and to get both direction of edges. + class BaseGraphComponent : public BaseDigraphComponent { + public: + + typedef BaseGraphComponent Graph; + + typedef BaseDigraphComponent::Node Node; + typedef BaseDigraphComponent::Arc Arc; + + /// \brief Undirected edge class of the graph. + /// + /// This class represents the undirected edges of the graph. + /// Undirected graphs can be used as directed graphs, each edge is + /// represented by two opposite directed arcs. + class Edge : public GraphItem<'e'> { + typedef GraphItem<'e'> Parent; + + public: + /// \brief Default constructor. + /// + /// Default constructor. + /// \warning The default constructor is not required to set + /// the item to some well-defined value. So you should consider it + /// as uninitialized. + Edge() {} + + /// \brief Copy constructor. + /// + /// Copy constructor. + Edge(const Edge &) : Parent() {} + + /// \brief Constructor for conversion from \c INVALID. + /// + /// Constructor for conversion from \c INVALID. + /// It initializes the item to be invalid. + /// \sa Invalid for more details. + Edge(Invalid) {} + + /// \brief Constructor for conversion from an arc. + /// + /// Constructor for conversion from an arc. + /// Besides the core graph item functionality each arc should + /// be convertible to the represented edge. + Edge(const Arc&) {} + }; + + /// \brief Return one end node of an edge. + /// + /// This function returns one end node of an edge. + Node u(const Edge&) const { return INVALID; } + + /// \brief Return the other end node of an edge. + /// + /// This function returns the other end node of an edge. + Node v(const Edge&) const { return INVALID; } + + /// \brief Return a directed arc related to an edge. + /// + /// This function returns a directed arc from its direction and the + /// represented edge. + Arc direct(const Edge&, bool) const { return INVALID; } + + /// \brief Return a directed arc related to an edge. + /// + /// This function returns a directed arc from its source node and the + /// represented edge. + Arc direct(const Edge&, const Node&) const { return INVALID; } + + /// \brief Return the direction of the arc. + /// + /// Returns the direction of the arc. Each arc represents an + /// edge with a direction. It gives back the + /// direction. + bool direction(const Arc&) const { return true; } + + /// \brief Return the opposite arc. + /// + /// This function returns the opposite arc, i.e. the arc representing + /// the same edge and has opposite direction. + Arc oppositeArc(const Arc&) const { return INVALID; } + + template + struct Constraints { + typedef typename _Graph::Node Node; + typedef typename _Graph::Arc Arc; + typedef typename _Graph::Edge Edge; + + void constraints() { + checkConcept(); + checkConcept, Edge>(); + { + Node n; + Edge ue(INVALID); + Arc e; + n = graph.u(ue); + n = graph.v(ue); + e = graph.direct(ue, true); + e = graph.direct(ue, false); + e = graph.direct(ue, n); + e = graph.oppositeArc(e); + ue = e; + bool d = graph.direction(e); + ::lemon::ignore_unused_variable_warning(d); + } + } + + const _Graph& graph; + Constraints() {} + }; + + }; + + /// \brief Base skeleton class for undirected bipartite graphs. + /// + /// This class describes the base interface of undirected + /// bipartite graph types. All bipartite graph %concepts have to + /// conform to this class. It extends the interface of \ref + /// BaseGraphComponent with an \c Edge type and functions to get + /// the end nodes of edges, to convert from arcs to edges and to + /// get both direction of edges. + class BaseBpGraphComponent : public BaseGraphComponent { + public: + + typedef BaseBpGraphComponent BpGraph; + + typedef BaseDigraphComponent::Node Node; + typedef BaseDigraphComponent::Arc Arc; + + /// \brief Class to represent red nodes. + /// + /// This class represents the red nodes of the graph. The red + /// nodes can also be used as normal nodes. + class RedNode : public Node { + typedef Node Parent; + + public: + /// \brief Default constructor. + /// + /// Default constructor. + /// \warning The default constructor is not required to set + /// the item to some well-defined value. So you should consider it + /// as uninitialized. + RedNode() {} + + /// \brief Copy constructor. + /// + /// Copy constructor. + RedNode(const RedNode &) : Parent() {} + + /// \brief Constructor for conversion from \c INVALID. + /// + /// Constructor for conversion from \c INVALID. + /// It initializes the item to be invalid. + /// \sa Invalid for more details. + RedNode(Invalid) {} + }; + + /// \brief Class to represent blue nodes. + /// + /// This class represents the blue nodes of the graph. The blue + /// nodes can also be used as normal nodes. + class BlueNode : public Node { + typedef Node Parent; + + public: + /// \brief Default constructor. + /// + /// Default constructor. + /// \warning The default constructor is not required to set + /// the item to some well-defined value. So you should consider it + /// as uninitialized. + BlueNode() {} + + /// \brief Copy constructor. + /// + /// Copy constructor. + BlueNode(const BlueNode &) : Parent() {} + + /// \brief Constructor for conversion from \c INVALID. + /// + /// Constructor for conversion from \c INVALID. + /// It initializes the item to be invalid. + /// \sa Invalid for more details. + BlueNode(Invalid) {} + + /// \brief Constructor for conversion from a node. + /// + /// Constructor for conversion from a node. The conversion can + /// be invalid, since the Node can be member of the red + /// set. + BlueNode(const Node&) {} + }; + + /// \brief Gives back %true for red nodes. + /// + /// Gives back %true for red nodes. + bool red(const Node&) const { return true; } + + /// \brief Gives back %true for blue nodes. + /// + /// Gives back %true for blue nodes. + bool blue(const Node&) const { return true; } + + /// \brief Gives back the red end node of the edge. + /// + /// Gives back the red end node of the edge. + RedNode redNode(const Edge&) const { return RedNode(); } + + /// \brief Gives back the blue end node of the edge. + /// + /// Gives back the blue end node of the edge. + BlueNode blueNode(const Edge&) const { return BlueNode(); } + + /// \brief Converts the node to red node object. + /// + /// This function converts unsafely the node to red node + /// object. It should be called only if the node is from the red + /// partition or INVALID. + RedNode asRedNodeUnsafe(const Node&) const { return RedNode(); } + + /// \brief Converts the node to blue node object. + /// + /// This function converts unsafely the node to blue node + /// object. It should be called only if the node is from the red + /// partition or INVALID. + BlueNode asBlueNodeUnsafe(const Node&) const { return BlueNode(); } + + /// \brief Converts the node to red node object. + /// + /// This function converts safely the node to red node + /// object. If the node is not from the red partition, then it + /// returns INVALID. + RedNode asRedNode(const Node&) const { return RedNode(); } + + /// \brief Converts the node to blue node object. + /// + /// This function converts unsafely the node to blue node + /// object. If the node is not from the blue partition, then it + /// returns INVALID. + BlueNode asBlueNode(const Node&) const { return BlueNode(); } + + template + struct Constraints { + typedef typename _BpGraph::Node Node; + typedef typename _BpGraph::RedNode RedNode; + typedef typename _BpGraph::BlueNode BlueNode; + typedef typename _BpGraph::Arc Arc; + typedef typename _BpGraph::Edge Edge; + + void constraints() { + checkConcept(); + checkConcept, RedNode>(); + checkConcept, BlueNode>(); + { + Node n; + RedNode rn; + BlueNode bn; + Node rnan = rn; + Node bnan = bn; + Edge e; + bool b; + b = bpgraph.red(rnan); + b = bpgraph.blue(bnan); + rn = bpgraph.redNode(e); + bn = bpgraph.blueNode(e); + rn = bpgraph.asRedNodeUnsafe(rnan); + bn = bpgraph.asBlueNodeUnsafe(bnan); + rn = bpgraph.asRedNode(rnan); + bn = bpgraph.asBlueNode(bnan); + ::lemon::ignore_unused_variable_warning(b); + } + } + + const _BpGraph& bpgraph; + }; + + }; + + /// \brief Skeleton class for \e idable directed graphs. + /// + /// This class describes the interface of \e idable directed graphs. + /// It extends \ref BaseDigraphComponent with the core ID functions. + /// The ids of the items must be unique and immutable. + /// This concept is part of the Digraph concept. + template + class IDableDigraphComponent : public BAS { + public: + + typedef BAS Base; + typedef typename Base::Node Node; + typedef typename Base::Arc Arc; + + /// \brief Return a unique integer id for the given node. + /// + /// This function returns a unique integer id for the given node. + int id(const Node&) const { return -1; } + + /// \brief Return the node by its unique id. + /// + /// This function returns the node by its unique id. + /// If the digraph does not contain a node with the given id, + /// then the result of the function is undefined. + Node nodeFromId(int) const { return INVALID; } + + /// \brief Return a unique integer id for the given arc. + /// + /// This function returns a unique integer id for the given arc. + int id(const Arc&) const { return -1; } + + /// \brief Return the arc by its unique id. + /// + /// This function returns the arc by its unique id. + /// If the digraph does not contain an arc with the given id, + /// then the result of the function is undefined. + Arc arcFromId(int) const { return INVALID; } + + /// \brief Return an integer greater or equal to the maximum + /// node id. + /// + /// This function returns an integer greater or equal to the + /// maximum node id. + int maxNodeId() const { return -1; } + + /// \brief Return an integer greater or equal to the maximum + /// arc id. + /// + /// This function returns an integer greater or equal to the + /// maximum arc id. + int maxArcId() const { return -1; } + + template + struct Constraints { + + void constraints() { + checkConcept(); + typename _Digraph::Node node; + node=INVALID; + int nid = digraph.id(node); + nid = digraph.id(node); + node = digraph.nodeFromId(nid); + typename _Digraph::Arc arc; + arc=INVALID; + int eid = digraph.id(arc); + eid = digraph.id(arc); + arc = digraph.arcFromId(eid); + + nid = digraph.maxNodeId(); + ::lemon::ignore_unused_variable_warning(nid); + eid = digraph.maxArcId(); + ::lemon::ignore_unused_variable_warning(eid); + } + + const _Digraph& digraph; + Constraints() {} + }; + }; + + /// \brief Skeleton class for \e idable undirected graphs. + /// + /// This class describes the interface of \e idable undirected + /// graphs. It extends \ref IDableDigraphComponent with the core ID + /// functions of undirected graphs. + /// The ids of the items must be unique and immutable. + /// This concept is part of the Graph concept. + template + class IDableGraphComponent : public IDableDigraphComponent { + public: + + typedef BAS Base; + typedef typename Base::Edge Edge; + + using IDableDigraphComponent::id; + + /// \brief Return a unique integer id for the given edge. + /// + /// This function returns a unique integer id for the given edge. + int id(const Edge&) const { return -1; } + + /// \brief Return the edge by its unique id. + /// + /// This function returns the edge by its unique id. + /// If the graph does not contain an edge with the given id, + /// then the result of the function is undefined. + Edge edgeFromId(int) const { return INVALID; } + + /// \brief Return an integer greater or equal to the maximum + /// edge id. + /// + /// This function returns an integer greater or equal to the + /// maximum edge id. + int maxEdgeId() const { return -1; } + + template + struct Constraints { + + void constraints() { + checkConcept, _Graph >(); + typename _Graph::Edge edge; + int ueid = graph.id(edge); + ueid = graph.id(edge); + edge = graph.edgeFromId(ueid); + ueid = graph.maxEdgeId(); + ::lemon::ignore_unused_variable_warning(ueid); + } + + const _Graph& graph; + Constraints() {} + }; + }; + + /// \brief Skeleton class for \e idable undirected bipartite graphs. + /// + /// This class describes the interface of \e idable undirected + /// bipartite graphs. It extends \ref IDableGraphComponent with + /// the core ID functions of undirected bipartite graphs. Beside + /// the regular node ids, this class also provides ids within the + /// the red and blue sets of the nodes. This concept is part of + /// the BpGraph concept. + template + class IDableBpGraphComponent : public IDableGraphComponent { + public: + + typedef BAS Base; + typedef IDableGraphComponent Parent; + typedef typename Base::Node Node; + typedef typename Base::RedNode RedNode; + typedef typename Base::BlueNode BlueNode; + + using Parent::id; + + /// \brief Return a unique integer id for the given node in the red set. + /// + /// Return a unique integer id for the given node in the red set. + int id(const RedNode&) const { return -1; } + + /// \brief Return a unique integer id for the given node in the blue set. + /// + /// Return a unique integer id for the given node in the blue set. + int id(const BlueNode&) const { return -1; } + + /// \brief Return an integer greater or equal to the maximum + /// node id in the red set. + /// + /// Return an integer greater or equal to the maximum + /// node id in the red set. + int maxRedId() const { return -1; } + + /// \brief Return an integer greater or equal to the maximum + /// node id in the blue set. + /// + /// Return an integer greater or equal to the maximum + /// node id in the blue set. + int maxBlueId() const { return -1; } + + template + struct Constraints { + + void constraints() { + checkConcept, _BpGraph>(); + typename _BpGraph::Node node; + typename _BpGraph::RedNode red; + typename _BpGraph::BlueNode blue; + int rid = bpgraph.id(red); + int bid = bpgraph.id(blue); + rid = bpgraph.maxRedId(); + bid = bpgraph.maxBlueId(); + ::lemon::ignore_unused_variable_warning(rid); + ::lemon::ignore_unused_variable_warning(bid); + } + + const _BpGraph& bpgraph; + }; + }; + + /// \brief Concept class for \c NodeIt, \c ArcIt and \c EdgeIt types. + /// + /// This class describes the concept of \c NodeIt, \c ArcIt and + /// \c EdgeIt subtypes of digraph and graph types. + template + class GraphItemIt : public Item { + public: + /// \brief Default constructor. + /// + /// Default constructor. + /// \warning The default constructor is not required to set + /// the iterator to some well-defined value. So you should consider it + /// as uninitialized. + GraphItemIt() {} + + /// \brief Copy constructor. + /// + /// Copy constructor. + GraphItemIt(const GraphItemIt& it) : Item(it) {} + + /// \brief Constructor that sets the iterator to the first item. + /// + /// Constructor that sets the iterator to the first item. + explicit GraphItemIt(const GR&) {} + + /// \brief Constructor for conversion from \c INVALID. + /// + /// Constructor for conversion from \c INVALID. + /// It initializes the iterator to be invalid. + /// \sa Invalid for more details. + GraphItemIt(Invalid) {} + + /// \brief Assignment operator. + /// + /// Assignment operator for the iterator. + GraphItemIt& operator=(const GraphItemIt&) { return *this; } + + /// \brief Increment the iterator. + /// + /// This operator increments the iterator, i.e. assigns it to the + /// next item. + GraphItemIt& operator++() { return *this; } + + /// \brief Equality operator + /// + /// Equality operator. + /// Two iterators are equal if and only if they point to the + /// same object or both are invalid. + bool operator==(const GraphItemIt&) const { return true;} + + /// \brief Inequality operator + /// + /// Inequality operator. + /// Two iterators are equal if and only if they point to the + /// same object or both are invalid. + bool operator!=(const GraphItemIt&) const { return true;} + + template + struct Constraints { + void constraints() { + checkConcept, _GraphItemIt>(); + _GraphItemIt it1(g); + _GraphItemIt it2; + _GraphItemIt it3 = it1; + _GraphItemIt it4 = INVALID; + ::lemon::ignore_unused_variable_warning(it3); + ::lemon::ignore_unused_variable_warning(it4); + + it2 = ++it1; + ++it2 = it1; + ++(++it1); + + Item bi = it1; + bi = it2; + } + const GR& g; + Constraints() {} + }; + }; + + /// \brief Concept class for \c InArcIt, \c OutArcIt and + /// \c IncEdgeIt types. + /// + /// This class describes the concept of \c InArcIt, \c OutArcIt + /// and \c IncEdgeIt subtypes of digraph and graph types. + /// + /// \note Since these iterator classes do not inherit from the same + /// base class, there is an additional template parameter (selector) + /// \c sel. For \c InArcIt you should instantiate it with character + /// \c 'i', for \c OutArcIt with \c 'o' and for \c IncEdgeIt with \c 'e'. + template + class GraphIncIt : public Item { + public: + /// \brief Default constructor. + /// + /// Default constructor. + /// \warning The default constructor is not required to set + /// the iterator to some well-defined value. So you should consider it + /// as uninitialized. + GraphIncIt() {} + + /// \brief Copy constructor. + /// + /// Copy constructor. + GraphIncIt(const GraphIncIt& it) : Item(it) {} + + /// \brief Constructor that sets the iterator to the first + /// incoming or outgoing arc. + /// + /// Constructor that sets the iterator to the first arc + /// incoming to or outgoing from the given node. + explicit GraphIncIt(const GR&, const Base&) {} + + /// \brief Constructor for conversion from \c INVALID. + /// + /// Constructor for conversion from \c INVALID. + /// It initializes the iterator to be invalid. + /// \sa Invalid for more details. + GraphIncIt(Invalid) {} + + /// \brief Assignment operator. + /// + /// Assignment operator for the iterator. + GraphIncIt& operator=(const GraphIncIt&) { return *this; } + + /// \brief Increment the iterator. + /// + /// This operator increments the iterator, i.e. assigns it to the + /// next arc incoming to or outgoing from the given node. + GraphIncIt& operator++() { return *this; } + + /// \brief Equality operator + /// + /// Equality operator. + /// Two iterators are equal if and only if they point to the + /// same object or both are invalid. + bool operator==(const GraphIncIt&) const { return true;} + + /// \brief Inequality operator + /// + /// Inequality operator. + /// Two iterators are equal if and only if they point to the + /// same object or both are invalid. + bool operator!=(const GraphIncIt&) const { return true;} + + template + struct Constraints { + void constraints() { + checkConcept, _GraphIncIt>(); + _GraphIncIt it1(graph, node); + _GraphIncIt it2; + _GraphIncIt it3 = it1; + _GraphIncIt it4 = INVALID; + ::lemon::ignore_unused_variable_warning(it3); + ::lemon::ignore_unused_variable_warning(it4); + + it2 = ++it1; + ++it2 = it1; + ++(++it1); + Item e = it1; + e = it2; + } + const Base& node; + const GR& graph; + Constraints() {} + }; + }; + + /// \brief Skeleton class for iterable directed graphs. + /// + /// This class describes the interface of iterable directed + /// graphs. It extends \ref BaseDigraphComponent with the core + /// iterable interface. + /// This concept is part of the Digraph concept. + template + class IterableDigraphComponent : public BAS { + + public: + + typedef BAS Base; + typedef typename Base::Node Node; + typedef typename Base::Arc Arc; + + typedef IterableDigraphComponent Digraph; + + /// \name Base Iteration + /// + /// This interface provides functions for iteration on digraph items. + /// + /// @{ + + /// \brief Return the first node. + /// + /// This function gives back the first node in the iteration order. + void first(Node&) const {} + + /// \brief Return the next node. + /// + /// This function gives back the next node in the iteration order. + void next(Node&) const {} + + /// \brief Return the first arc. + /// + /// This function gives back the first arc in the iteration order. + void first(Arc&) const {} + + /// \brief Return the next arc. + /// + /// This function gives back the next arc in the iteration order. + void next(Arc&) const {} + + /// \brief Return the first arc incoming to the given node. + /// + /// This function gives back the first arc incoming to the + /// given node. + void firstIn(Arc&, const Node&) const {} + + /// \brief Return the next arc incoming to the given node. + /// + /// This function gives back the next arc incoming to the + /// given node. + void nextIn(Arc&) const {} + + /// \brief Return the first arc outgoing form the given node. + /// + /// This function gives back the first arc outgoing form the + /// given node. + void firstOut(Arc&, const Node&) const {} + + /// \brief Return the next arc outgoing form the given node. + /// + /// This function gives back the next arc outgoing form the + /// given node. + void nextOut(Arc&) const {} + + /// @} + + /// \name Class Based Iteration + /// + /// This interface provides iterator classes for digraph items. + /// + /// @{ + + /// \brief This iterator goes through each node. + /// + /// This iterator goes through each node. + /// + typedef GraphItemIt NodeIt; + + /// \brief This iterator goes through each arc. + /// + /// This iterator goes through each arc. + /// + typedef GraphItemIt ArcIt; + + /// \brief This iterator goes trough the incoming arcs of a node. + /// + /// This iterator goes trough the \e incoming arcs of a certain node + /// of a digraph. + typedef GraphIncIt InArcIt; + + /// \brief This iterator goes trough the outgoing arcs of a node. + /// + /// This iterator goes trough the \e outgoing arcs of a certain node + /// of a digraph. + typedef GraphIncIt OutArcIt; + + /// \brief The base node of the iterator. + /// + /// This function gives back the base node of the iterator. + /// It is always the target node of the pointed arc. + Node baseNode(const InArcIt&) const { return INVALID; } + + /// \brief The running node of the iterator. + /// + /// This function gives back the running node of the iterator. + /// It is always the source node of the pointed arc. + Node runningNode(const InArcIt&) const { return INVALID; } + + /// \brief The base node of the iterator. + /// + /// This function gives back the base node of the iterator. + /// It is always the source node of the pointed arc. + Node baseNode(const OutArcIt&) const { return INVALID; } + + /// \brief The running node of the iterator. + /// + /// This function gives back the running node of the iterator. + /// It is always the target node of the pointed arc. + Node runningNode(const OutArcIt&) const { return INVALID; } + + /// @} + + template + struct Constraints { + void constraints() { + checkConcept(); + + { + typename _Digraph::Node node(INVALID); + typename _Digraph::Arc arc(INVALID); + { + digraph.first(node); + digraph.next(node); + } + { + digraph.first(arc); + digraph.next(arc); + } + { + digraph.firstIn(arc, node); + digraph.nextIn(arc); + } + { + digraph.firstOut(arc, node); + digraph.nextOut(arc); + } + } + + { + checkConcept, + typename _Digraph::ArcIt >(); + checkConcept, + typename _Digraph::NodeIt >(); + checkConcept, typename _Digraph::InArcIt>(); + checkConcept, typename _Digraph::OutArcIt>(); + + typename _Digraph::Node n; + const typename _Digraph::InArcIt iait(INVALID); + const typename _Digraph::OutArcIt oait(INVALID); + n = digraph.baseNode(iait); + n = digraph.runningNode(iait); + n = digraph.baseNode(oait); + n = digraph.runningNode(oait); + ::lemon::ignore_unused_variable_warning(n); + } + } + + const _Digraph& digraph; + Constraints() {} + }; + }; + + /// \brief Skeleton class for iterable undirected graphs. + /// + /// This class describes the interface of iterable undirected + /// graphs. It extends \ref IterableDigraphComponent with the core + /// iterable interface of undirected graphs. + /// This concept is part of the Graph concept. + template + class IterableGraphComponent : public IterableDigraphComponent { + public: + + typedef BAS Base; + typedef typename Base::Node Node; + typedef typename Base::Arc Arc; + typedef typename Base::Edge Edge; + + + typedef IterableGraphComponent Graph; + + /// \name Base Iteration + /// + /// This interface provides functions for iteration on edges. + /// + /// @{ + + using IterableDigraphComponent::first; + using IterableDigraphComponent::next; + + /// \brief Return the first edge. + /// + /// This function gives back the first edge in the iteration order. + void first(Edge&) const {} + + /// \brief Return the next edge. + /// + /// This function gives back the next edge in the iteration order. + void next(Edge&) const {} + + /// \brief Return the first edge incident to the given node. + /// + /// This function gives back the first edge incident to the given + /// node. The bool parameter gives back the direction for which the + /// source node of the directed arc representing the edge is the + /// given node. + void firstInc(Edge&, bool&, const Node&) const {} + + /// \brief Gives back the next of the edges from the + /// given node. + /// + /// This function gives back the next edge incident to the given + /// node. The bool parameter should be used as \c firstInc() use it. + void nextInc(Edge&, bool&) const {} + + using IterableDigraphComponent::baseNode; + using IterableDigraphComponent::runningNode; + + /// @} + + /// \name Class Based Iteration + /// + /// This interface provides iterator classes for edges. + /// + /// @{ + + /// \brief This iterator goes through each edge. + /// + /// This iterator goes through each edge. + typedef GraphItemIt EdgeIt; + + /// \brief This iterator goes trough the incident edges of a + /// node. + /// + /// This iterator goes trough the incident edges of a certain + /// node of a graph. + typedef GraphIncIt IncEdgeIt; + + /// \brief The base node of the iterator. + /// + /// This function gives back the base node of the iterator. + Node baseNode(const IncEdgeIt&) const { return INVALID; } + + /// \brief The running node of the iterator. + /// + /// This function gives back the running node of the iterator. + Node runningNode(const IncEdgeIt&) const { return INVALID; } + + /// @} + + template + struct Constraints { + void constraints() { + checkConcept, _Graph>(); + + { + typename _Graph::Node node(INVALID); + typename _Graph::Edge edge(INVALID); + bool dir; + { + graph.first(edge); + graph.next(edge); + } + { + graph.firstInc(edge, dir, node); + graph.nextInc(edge, dir); + } + + } + + { + checkConcept, + typename _Graph::EdgeIt >(); + checkConcept, typename _Graph::IncEdgeIt>(); + + typename _Graph::Node n; + const typename _Graph::IncEdgeIt ieit(INVALID); + n = graph.baseNode(ieit); + n = graph.runningNode(ieit); + } + } + + const _Graph& graph; + Constraints() {} + }; + }; + + /// \brief Skeleton class for iterable undirected bipartite graphs. + /// + /// This class describes the interface of iterable undirected + /// bipartite graphs. It extends \ref IterableGraphComponent with + /// the core iterable interface of undirected bipartite graphs. + /// This concept is part of the BpGraph concept. + template + class IterableBpGraphComponent : public IterableGraphComponent { + public: + + typedef BAS Base; + typedef typename Base::Node Node; + typedef typename Base::RedNode RedNode; + typedef typename Base::BlueNode BlueNode; + typedef typename Base::Arc Arc; + typedef typename Base::Edge Edge; + + typedef IterableBpGraphComponent BpGraph; + + using IterableGraphComponent::first; + using IterableGraphComponent::next; + + /// \name Base Iteration + /// + /// This interface provides functions for iteration on red and blue nodes. + /// + /// @{ + + /// \brief Return the first red node. + /// + /// This function gives back the first red node in the iteration order. + void first(RedNode&) const {} + + /// \brief Return the next red node. + /// + /// This function gives back the next red node in the iteration order. + void next(RedNode&) const {} + + /// \brief Return the first blue node. + /// + /// This function gives back the first blue node in the iteration order. + void first(BlueNode&) const {} + + /// \brief Return the next blue node. + /// + /// This function gives back the next blue node in the iteration order. + void next(BlueNode&) const {} + + + /// @} + + /// \name Class Based Iteration + /// + /// This interface provides iterator classes for red and blue nodes. + /// + /// @{ + + /// \brief This iterator goes through each red node. + /// + /// This iterator goes through each red node. + typedef GraphItemIt RedNodeIt; + + /// \brief This iterator goes through each blue node. + /// + /// This iterator goes through each blue node. + typedef GraphItemIt BlueNodeIt; + + /// @} + + template + struct Constraints { + void constraints() { + checkConcept, _BpGraph>(); + + typename _BpGraph::RedNode rn(INVALID); + bpgraph.first(rn); + bpgraph.next(rn); + typename _BpGraph::BlueNode bn(INVALID); + bpgraph.first(bn); + bpgraph.next(bn); + + checkConcept, + typename _BpGraph::RedNodeIt>(); + checkConcept, + typename _BpGraph::BlueNodeIt>(); + } + + const _BpGraph& bpgraph; + }; + }; + + /// \brief Skeleton class for alterable directed graphs. + /// + /// This class describes the interface of alterable directed + /// graphs. It extends \ref BaseDigraphComponent with the alteration + /// notifier interface. It implements + /// an observer-notifier pattern for each digraph item. More + /// obsevers can be registered into the notifier and whenever an + /// alteration occured in the digraph all the observers will be + /// notified about it. + template + class AlterableDigraphComponent : public BAS { + public: + + typedef BAS Base; + typedef typename Base::Node Node; + typedef typename Base::Arc Arc; + + + /// Node alteration notifier class. + typedef AlterationNotifier + NodeNotifier; + /// Arc alteration notifier class. + typedef AlterationNotifier + ArcNotifier; + + mutable NodeNotifier node_notifier; + mutable ArcNotifier arc_notifier; + + /// \brief Return the node alteration notifier. + /// + /// This function gives back the node alteration notifier. + NodeNotifier& notifier(Node) const { + return node_notifier; + } + + /// \brief Return the arc alteration notifier. + /// + /// This function gives back the arc alteration notifier. + ArcNotifier& notifier(Arc) const { + return arc_notifier; + } + + template + struct Constraints { + void constraints() { + checkConcept(); + typename _Digraph::NodeNotifier& nn + = digraph.notifier(typename _Digraph::Node()); + + typename _Digraph::ArcNotifier& en + = digraph.notifier(typename _Digraph::Arc()); + + ::lemon::ignore_unused_variable_warning(nn); + ::lemon::ignore_unused_variable_warning(en); + } + + const _Digraph& digraph; + Constraints() {} + }; + }; + + /// \brief Skeleton class for alterable undirected graphs. + /// + /// This class describes the interface of alterable undirected + /// graphs. It extends \ref AlterableDigraphComponent with the alteration + /// notifier interface of undirected graphs. It implements + /// an observer-notifier pattern for the edges. More + /// obsevers can be registered into the notifier and whenever an + /// alteration occured in the graph all the observers will be + /// notified about it. + template + class AlterableGraphComponent : public AlterableDigraphComponent { + public: + + typedef BAS Base; + typedef AlterableDigraphComponent Parent; + typedef typename Base::Edge Edge; + + + /// Edge alteration notifier class. + typedef AlterationNotifier + EdgeNotifier; + + mutable EdgeNotifier edge_notifier; + + using Parent::notifier; + + /// \brief Return the edge alteration notifier. + /// + /// This function gives back the edge alteration notifier. + EdgeNotifier& notifier(Edge) const { + return edge_notifier; + } + + template + struct Constraints { + void constraints() { + checkConcept, _Graph>(); + typename _Graph::EdgeNotifier& uen + = graph.notifier(typename _Graph::Edge()); + ::lemon::ignore_unused_variable_warning(uen); + } + + const _Graph& graph; + Constraints() {} + }; + }; + + /// \brief Skeleton class for alterable undirected bipartite graphs. + /// + /// This class describes the interface of alterable undirected + /// bipartite graphs. It extends \ref AlterableGraphComponent with + /// the alteration notifier interface of bipartite graphs. It + /// implements an observer-notifier pattern for the red and blue + /// nodes. More obsevers can be registered into the notifier and + /// whenever an alteration occured in the graph all the observers + /// will be notified about it. + template + class AlterableBpGraphComponent : public AlterableGraphComponent { + public: + + typedef BAS Base; + typedef AlterableGraphComponent Parent; + typedef typename Base::RedNode RedNode; + typedef typename Base::BlueNode BlueNode; + + + /// Red node alteration notifier class. + typedef AlterationNotifier + RedNodeNotifier; + + /// Blue node alteration notifier class. + typedef AlterationNotifier + BlueNodeNotifier; + + mutable RedNodeNotifier red_node_notifier; + mutable BlueNodeNotifier blue_node_notifier; + + using Parent::notifier; + + /// \brief Return the red node alteration notifier. + /// + /// This function gives back the red node alteration notifier. + RedNodeNotifier& notifier(RedNode) const { + return red_node_notifier; + } + + /// \brief Return the blue node alteration notifier. + /// + /// This function gives back the blue node alteration notifier. + BlueNodeNotifier& notifier(BlueNode) const { + return blue_node_notifier; + } + + template + struct Constraints { + void constraints() { + checkConcept, _BpGraph>(); + typename _BpGraph::RedNodeNotifier& rnn + = bpgraph.notifier(typename _BpGraph::RedNode()); + typename _BpGraph::BlueNodeNotifier& bnn + = bpgraph.notifier(typename _BpGraph::BlueNode()); + ::lemon::ignore_unused_variable_warning(rnn); + ::lemon::ignore_unused_variable_warning(bnn); + } + + const _BpGraph& bpgraph; + }; + }; + + /// \brief Concept class for standard graph maps. + /// + /// This class describes the concept of standard graph maps, i.e. + /// the \c NodeMap, \c ArcMap and \c EdgeMap subtypes of digraph and + /// graph types, which can be used for associating data to graph items. + /// The standard graph maps must conform to the ReferenceMap concept. + template + class GraphMap : public ReferenceMap { + typedef ReferenceMap Parent; + + public: + + /// The key type of the map. + typedef K Key; + /// The value type of the map. + typedef V Value; + /// The reference type of the map. + typedef Value& Reference; + /// The const reference type of the map. + typedef const Value& ConstReference; + + // The reference map tag. + typedef True ReferenceMapTag; + + /// \brief Construct a new map. + /// + /// Construct a new map for the graph. + explicit GraphMap(const GR&) {} + /// \brief Construct a new map with default value. + /// + /// Construct a new map for the graph and initalize the values. + GraphMap(const GR&, const Value&) {} + + private: + /// \brief Copy constructor. + /// + /// Copy Constructor. + GraphMap(const GraphMap&) : Parent() {} + + /// \brief Assignment operator. + /// + /// Assignment operator. It does not mofify the underlying graph, + /// it just iterates on the current item set and set the map + /// with the value returned by the assigned map. + template + GraphMap& operator=(const CMap&) { + checkConcept, CMap>(); + return *this; + } + + public: + template + struct Constraints { + void constraints() { + checkConcept + , _Map>(); + _Map m1(g); + _Map m2(g,t); + + // Copy constructor + // _Map m3(m); + + // Assignment operator + // ReadMap cmap; + // m3 = cmap; + + ::lemon::ignore_unused_variable_warning(m1); + ::lemon::ignore_unused_variable_warning(m2); + // ::lemon::ignore_unused_variable_warning(m3); + } + + const _Map &m; + const GR &g; + const typename GraphMap::Value &t; + Constraints() {} + }; + + }; + + /// \brief Skeleton class for mappable directed graphs. + /// + /// This class describes the interface of mappable directed graphs. + /// It extends \ref BaseDigraphComponent with the standard digraph + /// map classes, namely \c NodeMap and \c ArcMap. + /// This concept is part of the Digraph concept. + template + class MappableDigraphComponent : public BAS { + public: + + typedef BAS Base; + typedef typename Base::Node Node; + typedef typename Base::Arc Arc; + + typedef MappableDigraphComponent Digraph; + + /// \brief Standard graph map for the nodes. + /// + /// Standard graph map for the nodes. + /// It conforms to the ReferenceMap concept. + template + class NodeMap : public GraphMap { + typedef GraphMap Parent; + + public: + /// \brief Construct a new map. + /// + /// Construct a new map for the digraph. + explicit NodeMap(const MappableDigraphComponent& digraph) + : Parent(digraph) {} + + /// \brief Construct a new map with default value. + /// + /// Construct a new map for the digraph and initalize the values. + NodeMap(const MappableDigraphComponent& digraph, const V& value) + : Parent(digraph, value) {} + + private: + /// \brief Copy constructor. + /// + /// Copy Constructor. + NodeMap(const NodeMap& nm) : Parent(nm) {} + + /// \brief Assignment operator. + /// + /// Assignment operator. + template + NodeMap& operator=(const CMap&) { + checkConcept, CMap>(); + return *this; + } + + }; + + /// \brief Standard graph map for the arcs. + /// + /// Standard graph map for the arcs. + /// It conforms to the ReferenceMap concept. + template + class ArcMap : public GraphMap { + typedef GraphMap Parent; + + public: + /// \brief Construct a new map. + /// + /// Construct a new map for the digraph. + explicit ArcMap(const MappableDigraphComponent& digraph) + : Parent(digraph) {} + + /// \brief Construct a new map with default value. + /// + /// Construct a new map for the digraph and initalize the values. + ArcMap(const MappableDigraphComponent& digraph, const V& value) + : Parent(digraph, value) {} + + private: + /// \brief Copy constructor. + /// + /// Copy Constructor. + ArcMap(const ArcMap& nm) : Parent(nm) {} + + /// \brief Assignment operator. + /// + /// Assignment operator. + template + ArcMap& operator=(const CMap&) { + checkConcept, CMap>(); + return *this; + } + + }; + + + template + struct Constraints { + + struct Dummy { + int value; + Dummy() : value(0) {} + Dummy(int _v) : value(_v) {} + }; + + void constraints() { + checkConcept(); + { // int map test + typedef typename _Digraph::template NodeMap IntNodeMap; + checkConcept, + IntNodeMap >(); + } { // bool map test + typedef typename _Digraph::template NodeMap BoolNodeMap; + checkConcept, + BoolNodeMap >(); + } { // Dummy map test + typedef typename _Digraph::template NodeMap DummyNodeMap; + checkConcept, + DummyNodeMap >(); + } + + { // int map test + typedef typename _Digraph::template ArcMap IntArcMap; + checkConcept, + IntArcMap >(); + } { // bool map test + typedef typename _Digraph::template ArcMap BoolArcMap; + checkConcept, + BoolArcMap >(); + } { // Dummy map test + typedef typename _Digraph::template ArcMap DummyArcMap; + checkConcept, + DummyArcMap >(); + } + } + + const _Digraph& digraph; + Constraints() {} + }; + }; + + /// \brief Skeleton class for mappable undirected graphs. + /// + /// This class describes the interface of mappable undirected graphs. + /// It extends \ref MappableDigraphComponent with the standard graph + /// map class for edges (\c EdgeMap). + /// This concept is part of the Graph concept. + template + class MappableGraphComponent : public MappableDigraphComponent { + public: + + typedef BAS Base; + typedef typename Base::Edge Edge; + + typedef MappableGraphComponent Graph; + + /// \brief Standard graph map for the edges. + /// + /// Standard graph map for the edges. + /// It conforms to the ReferenceMap concept. + template + class EdgeMap : public GraphMap { + typedef GraphMap Parent; + + public: + /// \brief Construct a new map. + /// + /// Construct a new map for the graph. + explicit EdgeMap(const MappableGraphComponent& graph) + : Parent(graph) {} + + /// \brief Construct a new map with default value. + /// + /// Construct a new map for the graph and initalize the values. + EdgeMap(const MappableGraphComponent& graph, const V& value) + : Parent(graph, value) {} + + private: + /// \brief Copy constructor. + /// + /// Copy Constructor. + EdgeMap(const EdgeMap& nm) : Parent(nm) {} + + /// \brief Assignment operator. + /// + /// Assignment operator. + template + EdgeMap& operator=(const CMap&) { + checkConcept, CMap>(); + return *this; + } + + }; + + + template + struct Constraints { + + struct Dummy { + int value; + Dummy() : value(0) {} + Dummy(int _v) : value(_v) {} + }; + + void constraints() { + checkConcept, _Graph>(); + + { // int map test + typedef typename _Graph::template EdgeMap IntEdgeMap; + checkConcept, + IntEdgeMap >(); + } { // bool map test + typedef typename _Graph::template EdgeMap BoolEdgeMap; + checkConcept, + BoolEdgeMap >(); + } { // Dummy map test + typedef typename _Graph::template EdgeMap DummyEdgeMap; + checkConcept, + DummyEdgeMap >(); + } + } + + const _Graph& graph; + Constraints() {} + }; + }; + + /// \brief Skeleton class for mappable undirected bipartite graphs. + /// + /// This class describes the interface of mappable undirected + /// bipartite graphs. It extends \ref MappableGraphComponent with + /// the standard graph map class for red and blue nodes (\c + /// RedNodeMap and BlueNodeMap). This concept is part of the + /// BpGraph concept. + template + class MappableBpGraphComponent : public MappableGraphComponent { + public: + + typedef BAS Base; + typedef typename Base::Node Node; + + typedef MappableBpGraphComponent BpGraph; + + /// \brief Standard graph map for the red nodes. + /// + /// Standard graph map for the red nodes. + /// It conforms to the ReferenceMap concept. + template + class RedNodeMap : public GraphMap { + typedef GraphMap Parent; + + public: + /// \brief Construct a new map. + /// + /// Construct a new map for the graph. + explicit RedNodeMap(const MappableBpGraphComponent& graph) + : Parent(graph) {} + + /// \brief Construct a new map with default value. + /// + /// Construct a new map for the graph and initalize the values. + RedNodeMap(const MappableBpGraphComponent& graph, const V& value) + : Parent(graph, value) {} + + private: + /// \brief Copy constructor. + /// + /// Copy Constructor. + RedNodeMap(const RedNodeMap& nm) : Parent(nm) {} + + /// \brief Assignment operator. + /// + /// Assignment operator. + template + RedNodeMap& operator=(const CMap&) { + checkConcept, CMap>(); + return *this; + } + + }; + + /// \brief Standard graph map for the blue nodes. + /// + /// Standard graph map for the blue nodes. + /// It conforms to the ReferenceMap concept. + template + class BlueNodeMap : public GraphMap { + typedef GraphMap Parent; + + public: + /// \brief Construct a new map. + /// + /// Construct a new map for the graph. + explicit BlueNodeMap(const MappableBpGraphComponent& graph) + : Parent(graph) {} + + /// \brief Construct a new map with default value. + /// + /// Construct a new map for the graph and initalize the values. + BlueNodeMap(const MappableBpGraphComponent& graph, const V& value) + : Parent(graph, value) {} + + private: + /// \brief Copy constructor. + /// + /// Copy Constructor. + BlueNodeMap(const BlueNodeMap& nm) : Parent(nm) {} + + /// \brief Assignment operator. + /// + /// Assignment operator. + template + BlueNodeMap& operator=(const CMap&) { + checkConcept, CMap>(); + return *this; + } + + }; + + + template + struct Constraints { + + struct Dummy { + int value; + Dummy() : value(0) {} + Dummy(int _v) : value(_v) {} + }; + + void constraints() { + checkConcept, _BpGraph>(); + + { // int map test + typedef typename _BpGraph::template RedNodeMap + IntRedNodeMap; + checkConcept, + IntRedNodeMap >(); + } { // bool map test + typedef typename _BpGraph::template RedNodeMap + BoolRedNodeMap; + checkConcept, + BoolRedNodeMap >(); + } { // Dummy map test + typedef typename _BpGraph::template RedNodeMap + DummyRedNodeMap; + checkConcept, + DummyRedNodeMap >(); + } + + { // int map test + typedef typename _BpGraph::template BlueNodeMap + IntBlueNodeMap; + checkConcept, + IntBlueNodeMap >(); + } { // bool map test + typedef typename _BpGraph::template BlueNodeMap + BoolBlueNodeMap; + checkConcept, + BoolBlueNodeMap >(); + } { // Dummy map test + typedef typename _BpGraph::template BlueNodeMap + DummyBlueNodeMap; + checkConcept, + DummyBlueNodeMap >(); + } + } + + const _BpGraph& bpgraph; + }; + }; + + /// \brief Skeleton class for extendable directed graphs. + /// + /// This class describes the interface of extendable directed graphs. + /// It extends \ref BaseDigraphComponent with functions for adding + /// nodes and arcs to the digraph. + /// This concept requires \ref AlterableDigraphComponent. + template + class ExtendableDigraphComponent : public BAS { + public: + typedef BAS Base; + + typedef typename Base::Node Node; + typedef typename Base::Arc Arc; + + /// \brief Add a new node to the digraph. + /// + /// This function adds a new node to the digraph. + Node addNode() { + return INVALID; + } + + /// \brief Add a new arc connecting the given two nodes. + /// + /// This function adds a new arc connecting the given two nodes + /// of the digraph. + Arc addArc(const Node&, const Node&) { + return INVALID; + } + + template + struct Constraints { + void constraints() { + checkConcept(); + typename _Digraph::Node node_a, node_b; + node_a = digraph.addNode(); + node_b = digraph.addNode(); + typename _Digraph::Arc arc; + arc = digraph.addArc(node_a, node_b); + } + + _Digraph& digraph; + Constraints() {} + }; + }; + + /// \brief Skeleton class for extendable undirected graphs. + /// + /// This class describes the interface of extendable undirected graphs. + /// It extends \ref BaseGraphComponent with functions for adding + /// nodes and edges to the graph. + /// This concept requires \ref AlterableGraphComponent. + template + class ExtendableGraphComponent : public BAS { + public: + + typedef BAS Base; + typedef typename Base::Node Node; + typedef typename Base::Edge Edge; + + /// \brief Add a new node to the digraph. + /// + /// This function adds a new node to the digraph. + Node addNode() { + return INVALID; + } + + /// \brief Add a new edge connecting the given two nodes. + /// + /// This function adds a new edge connecting the given two nodes + /// of the graph. + Edge addEdge(const Node&, const Node&) { + return INVALID; + } + + template + struct Constraints { + void constraints() { + checkConcept(); + typename _Graph::Node node_a, node_b; + node_a = graph.addNode(); + node_b = graph.addNode(); + typename _Graph::Edge edge; + edge = graph.addEdge(node_a, node_b); + } + + _Graph& graph; + Constraints() {} + }; + }; + + /// \brief Skeleton class for extendable undirected bipartite graphs. + /// + /// This class describes the interface of extendable undirected + /// bipartite graphs. It extends \ref BaseGraphComponent with + /// functions for adding nodes and edges to the graph. This + /// concept requires \ref AlterableBpGraphComponent. + template + class ExtendableBpGraphComponent : public BAS { + public: + + typedef BAS Base; + typedef typename Base::Node Node; + typedef typename Base::RedNode RedNode; + typedef typename Base::BlueNode BlueNode; + typedef typename Base::Edge Edge; + + /// \brief Add a new red node to the digraph. + /// + /// This function adds a red new node to the digraph. + RedNode addRedNode() { + return INVALID; + } + + /// \brief Add a new blue node to the digraph. + /// + /// This function adds a blue new node to the digraph. + BlueNode addBlueNode() { + return INVALID; + } + + /// \brief Add a new edge connecting the given two nodes. + /// + /// This function adds a new edge connecting the given two nodes + /// of the graph. The first node has to be a red node, and the + /// second one a blue node. + Edge addEdge(const RedNode&, const BlueNode&) { + return INVALID; + } + Edge addEdge(const BlueNode&, const RedNode&) { + return INVALID; + } + + template + struct Constraints { + void constraints() { + checkConcept(); + typename _BpGraph::RedNode red_node; + typename _BpGraph::BlueNode blue_node; + red_node = bpgraph.addRedNode(); + blue_node = bpgraph.addBlueNode(); + typename _BpGraph::Edge edge; + edge = bpgraph.addEdge(red_node, blue_node); + edge = bpgraph.addEdge(blue_node, red_node); + } + + _BpGraph& bpgraph; + }; + }; + + /// \brief Skeleton class for erasable directed graphs. + /// + /// This class describes the interface of erasable directed graphs. + /// It extends \ref BaseDigraphComponent with functions for removing + /// nodes and arcs from the digraph. + /// This concept requires \ref AlterableDigraphComponent. + template + class ErasableDigraphComponent : public BAS { + public: + + typedef BAS Base; + typedef typename Base::Node Node; + typedef typename Base::Arc Arc; + + /// \brief Erase a node from the digraph. + /// + /// This function erases the given node from the digraph and all arcs + /// connected to the node. + void erase(const Node&) {} + + /// \brief Erase an arc from the digraph. + /// + /// This function erases the given arc from the digraph. + void erase(const Arc&) {} + + template + struct Constraints { + void constraints() { + checkConcept(); + const typename _Digraph::Node node(INVALID); + digraph.erase(node); + const typename _Digraph::Arc arc(INVALID); + digraph.erase(arc); + } + + _Digraph& digraph; + Constraints() {} + }; + }; + + /// \brief Skeleton class for erasable undirected graphs. + /// + /// This class describes the interface of erasable undirected graphs. + /// It extends \ref BaseGraphComponent with functions for removing + /// nodes and edges from the graph. + /// This concept requires \ref AlterableGraphComponent. + template + class ErasableGraphComponent : public BAS { + public: + + typedef BAS Base; + typedef typename Base::Node Node; + typedef typename Base::Edge Edge; + + /// \brief Erase a node from the graph. + /// + /// This function erases the given node from the graph and all edges + /// connected to the node. + void erase(const Node&) {} + + /// \brief Erase an edge from the digraph. + /// + /// This function erases the given edge from the digraph. + void erase(const Edge&) {} + + template + struct Constraints { + void constraints() { + checkConcept(); + const typename _Graph::Node node(INVALID); + graph.erase(node); + const typename _Graph::Edge edge(INVALID); + graph.erase(edge); + } + + _Graph& graph; + Constraints() {} + }; + }; + + /// \brief Skeleton class for erasable undirected graphs. + /// + /// This class describes the interface of erasable undirected + /// bipartite graphs. It extends \ref BaseBpGraphComponent with + /// functions for removing nodes and edges from the graph. This + /// concept requires \ref AlterableBpGraphComponent. + template + class ErasableBpGraphComponent : public ErasableGraphComponent {}; + + /// \brief Skeleton class for clearable directed graphs. + /// + /// This class describes the interface of clearable directed graphs. + /// It extends \ref BaseDigraphComponent with a function for clearing + /// the digraph. + /// This concept requires \ref AlterableDigraphComponent. + template + class ClearableDigraphComponent : public BAS { + public: + + typedef BAS Base; + + /// \brief Erase all nodes and arcs from the digraph. + /// + /// This function erases all nodes and arcs from the digraph. + void clear() {} + + template + struct Constraints { + void constraints() { + checkConcept(); + digraph.clear(); + } + + _Digraph& digraph; + Constraints() {} + }; + }; + + /// \brief Skeleton class for clearable undirected graphs. + /// + /// This class describes the interface of clearable undirected graphs. + /// It extends \ref BaseGraphComponent with a function for clearing + /// the graph. + /// This concept requires \ref AlterableGraphComponent. + template + class ClearableGraphComponent : public ClearableDigraphComponent {}; + + /// \brief Skeleton class for clearable undirected biparite graphs. + /// + /// This class describes the interface of clearable undirected + /// bipartite graphs. It extends \ref BaseBpGraphComponent with a + /// function for clearing the graph. This concept requires \ref + /// AlterableBpGraphComponent. + template + class ClearableBpGraphComponent : public ClearableGraphComponent {}; + + } + +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/heap.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/heap.h new file mode 100644 index 00000000000..8c7a2512144 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/heap.h @@ -0,0 +1,324 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_CONCEPTS_HEAP_H +#define LEMON_CONCEPTS_HEAP_H + +///\ingroup concept +///\file +///\brief The concept of heaps. + +#include +#include + +namespace lemon { + + namespace concepts { + + /// \addtogroup concept + /// @{ + + /// \brief The heap concept. + /// + /// This concept class describes the main interface of heaps. + /// The various \ref heaps "heap structures" are efficient + /// implementations of the abstract data type \e priority \e queue. + /// They store items with specified values called \e priorities + /// in such a way that finding and removing the item with minimum + /// priority are efficient. The basic operations are adding and + /// erasing items, changing the priority of an item, etc. + /// + /// Heaps are crucial in several algorithms, such as Dijkstra and Prim. + /// Any class that conforms to this concept can be used easily in such + /// algorithms. + /// + /// \tparam PR Type of the priorities of the items. + /// \tparam IM A read-writable item map with \c int values, used + /// internally to handle the cross references. + /// \tparam CMP A functor class for comparing the priorities. + /// The default is \c std::less. +#ifdef DOXYGEN + template +#else + template > +#endif + class Heap { + public: + + /// Type of the item-int map. + typedef IM ItemIntMap; + /// Type of the priorities. + typedef PR Prio; + /// Type of the items stored in the heap. + typedef typename ItemIntMap::Key Item; + + /// \brief Type to represent the states of the items. + /// + /// Each item has a state associated to it. It can be "in heap", + /// "pre-heap" or "post-heap". The latter two are indifferent from the + /// heap's point of view, but may be useful to the user. + /// + /// The item-int map must be initialized in such way that it assigns + /// \c PRE_HEAP (-1) to any element to be put in the heap. + enum State { + IN_HEAP = 0, ///< = 0. The "in heap" state constant. + PRE_HEAP = -1, ///< = -1. The "pre-heap" state constant. + POST_HEAP = -2 ///< = -2. The "post-heap" state constant. + }; + + /// \brief Constructor. + /// + /// Constructor. + /// \param map A map that assigns \c int values to keys of type + /// \c Item. It is used internally by the heap implementations to + /// handle the cross references. The assigned value must be + /// \c PRE_HEAP (-1) for each item. +#ifdef DOXYGEN + explicit Heap(ItemIntMap &map) {} +#else + explicit Heap(ItemIntMap&) {} +#endif + + /// \brief Constructor. + /// + /// Constructor. + /// \param map A map that assigns \c int values to keys of type + /// \c Item. It is used internally by the heap implementations to + /// handle the cross references. The assigned value must be + /// \c PRE_HEAP (-1) for each item. + /// \param comp The function object used for comparing the priorities. +#ifdef DOXYGEN + explicit Heap(ItemIntMap &map, const CMP &comp) {} +#else + explicit Heap(ItemIntMap&, const CMP&) {} +#endif + + /// \brief The number of items stored in the heap. + /// + /// This function returns the number of items stored in the heap. + int size() const { return 0; } + + /// \brief Check if the heap is empty. + /// + /// This function returns \c true if the heap is empty. + bool empty() const { return false; } + + /// \brief Make the heap empty. + /// + /// This functon makes the heap empty. + /// It does not change the cross reference map. If you want to reuse + /// a heap that is not surely empty, you should first clear it and + /// then you should set the cross reference map to \c PRE_HEAP + /// for each item. + void clear() {} + + /// \brief Insert an item into the heap with the given priority. + /// + /// This function inserts the given item into the heap with the + /// given priority. + /// \param i The item to insert. + /// \param p The priority of the item. + /// \pre \e i must not be stored in the heap. +#ifdef DOXYGEN + void push(const Item &i, const Prio &p) {} +#else + void push(const Item&, const Prio&) {} +#endif + + /// \brief Return the item having minimum priority. + /// + /// This function returns the item having minimum priority. + /// \pre The heap must be non-empty. + Item top() const { return Item(); } + + /// \brief The minimum priority. + /// + /// This function returns the minimum priority. + /// \pre The heap must be non-empty. + Prio prio() const { return Prio(); } + + /// \brief Remove the item having minimum priority. + /// + /// This function removes the item having minimum priority. + /// \pre The heap must be non-empty. + void pop() {} + + /// \brief Remove the given item from the heap. + /// + /// This function removes the given item from the heap if it is + /// already stored. + /// \param i The item to delete. + /// \pre \e i must be in the heap. +#ifdef DOXYGEN + void erase(const Item &i) {} +#else + void erase(const Item&) {} +#endif + + /// \brief The priority of the given item. + /// + /// This function returns the priority of the given item. + /// \param i The item. + /// \pre \e i must be in the heap. +#ifdef DOXYGEN + Prio operator[](const Item &i) const {} +#else + Prio operator[](const Item&) const { return Prio(); } +#endif + + /// \brief Set the priority of an item or insert it, if it is + /// not stored in the heap. + /// + /// This method sets the priority of the given item if it is + /// already stored in the heap. Otherwise it inserts the given + /// item into the heap with the given priority. + /// + /// \param i The item. + /// \param p The priority. +#ifdef DOXYGEN + void set(const Item &i, const Prio &p) {} +#else + void set(const Item&, const Prio&) {} +#endif + + /// \brief Decrease the priority of an item to the given value. + /// + /// This function decreases the priority of an item to the given value. + /// \param i The item. + /// \param p The priority. + /// \pre \e i must be stored in the heap with priority at least \e p. +#ifdef DOXYGEN + void decrease(const Item &i, const Prio &p) {} +#else + void decrease(const Item&, const Prio&) {} +#endif + + /// \brief Increase the priority of an item to the given value. + /// + /// This function increases the priority of an item to the given value. + /// \param i The item. + /// \param p The priority. + /// \pre \e i must be stored in the heap with priority at most \e p. +#ifdef DOXYGEN + void increase(const Item &i, const Prio &p) {} +#else + void increase(const Item&, const Prio&) {} +#endif + + /// \brief Return the state of an item. + /// + /// This method returns \c PRE_HEAP if the given item has never + /// been in the heap, \c IN_HEAP if it is in the heap at the moment, + /// and \c POST_HEAP otherwise. + /// In the latter case it is possible that the item will get back + /// to the heap again. + /// \param i The item. +#ifdef DOXYGEN + State state(const Item &i) const {} +#else + State state(const Item&) const { return PRE_HEAP; } +#endif + + /// \brief Set the state of an item in the heap. + /// + /// This function sets the state of the given item in the heap. + /// It can be used to manually clear the heap when it is important + /// to achive better time complexity. + /// \param i The item. + /// \param st The state. It should not be \c IN_HEAP. +#ifdef DOXYGEN + void state(const Item& i, State st) {} +#else + void state(const Item&, State) {} +#endif + + + template + struct Constraints { + public: + void constraints() { + typedef typename _Heap::Item OwnItem; + typedef typename _Heap::Prio OwnPrio; + typedef typename _Heap::State OwnState; + + Item item; + Prio prio; + item=Item(); + prio=Prio(); + ::lemon::ignore_unused_variable_warning(item); + ::lemon::ignore_unused_variable_warning(prio); + + OwnItem own_item; + OwnPrio own_prio; + OwnState own_state; + own_item=Item(); + own_prio=Prio(); + ::lemon::ignore_unused_variable_warning(own_item); + ::lemon::ignore_unused_variable_warning(own_prio); + ::lemon::ignore_unused_variable_warning(own_state); + + _Heap heap1(map); + _Heap heap2 = heap1; + ::lemon::ignore_unused_variable_warning(heap1); + ::lemon::ignore_unused_variable_warning(heap2); + + int s = heap.size(); + ::lemon::ignore_unused_variable_warning(s); + bool e = heap.empty(); + ::lemon::ignore_unused_variable_warning(e); + + prio = heap.prio(); + item = heap.top(); + prio = heap[item]; + own_prio = heap.prio(); + own_item = heap.top(); + own_prio = heap[own_item]; + + heap.push(item, prio); + heap.push(own_item, own_prio); + heap.pop(); + + heap.set(item, prio); + heap.decrease(item, prio); + heap.increase(item, prio); + heap.set(own_item, own_prio); + heap.decrease(own_item, own_prio); + heap.increase(own_item, own_prio); + + heap.erase(item); + heap.erase(own_item); + heap.clear(); + + own_state = heap.state(own_item); + heap.state(own_item, own_state); + + own_state = _Heap::PRE_HEAP; + own_state = _Heap::IN_HEAP; + own_state = _Heap::POST_HEAP; + } + + _Heap& heap; + ItemIntMap& map; + Constraints() {} + }; + }; + + /// @} + } // namespace lemon +} +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/maps.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/maps.h new file mode 100644 index 00000000000..88b66b51118 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/maps.h @@ -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-2013 + * 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_CONCEPTS_MAPS_H +#define LEMON_CONCEPTS_MAPS_H + +#include +#include + +///\ingroup map_concepts +///\file +///\brief The concept of maps. + +namespace lemon { + + namespace concepts { + + /// \addtogroup map_concepts + /// @{ + + /// Readable map concept + + /// Readable map concept. + /// + template + class ReadMap + { + public: + /// The key type of the map. + typedef K Key; + /// \brief The value type of the map. + /// (The type of objects associated with the keys). + typedef T Value; + + /// Returns the value associated with the given key. + Value operator[](const Key &) const { + return *(static_cast(0)+1); + } + + template + struct Constraints { + void constraints() { + Value val = m[key]; + val = m[key]; + typename _ReadMap::Value own_val = m[own_key]; + own_val = m[own_key]; + + ::lemon::ignore_unused_variable_warning(key); + ::lemon::ignore_unused_variable_warning(val); + ::lemon::ignore_unused_variable_warning(own_key); + ::lemon::ignore_unused_variable_warning(own_val); + } + const Key& key; + const typename _ReadMap::Key& own_key; + const _ReadMap& m; + Constraints() {} + }; + + }; + + + /// Writable map concept + + /// Writable map concept. + /// + template + class WriteMap + { + public: + /// The key type of the map. + typedef K Key; + /// \brief The value type of the map. + /// (The type of objects associated with the keys). + typedef T Value; + + /// Sets the value associated with the given key. + void set(const Key &, const Value &) {} + + /// Default constructor. + WriteMap() {} + + template + struct Constraints { + void constraints() { + m.set(key, val); + m.set(own_key, own_val); + + ::lemon::ignore_unused_variable_warning(key); + ::lemon::ignore_unused_variable_warning(val); + ::lemon::ignore_unused_variable_warning(own_key); + ::lemon::ignore_unused_variable_warning(own_val); + } + const Key& key; + const Value& val; + const typename _WriteMap::Key& own_key; + const typename _WriteMap::Value& own_val; + _WriteMap& m; + Constraints() {} + }; + }; + + /// Read/writable map concept + + /// Read/writable map concept. + /// + template + class ReadWriteMap : public ReadMap, + public WriteMap + { + public: + /// The key type of the map. + typedef K Key; + /// \brief The value type of the map. + /// (The type of objects associated with the keys). + typedef T Value; + + /// Returns the value associated with the given key. + Value operator[](const Key &) const { + Value *r = 0; + return *r; + } + + /// Sets the value associated with the given key. + void set(const Key &, const Value &) {} + + template + struct Constraints { + void constraints() { + checkConcept, _ReadWriteMap >(); + checkConcept, _ReadWriteMap >(); + } + }; + }; + + + /// Dereferable map concept + + /// Dereferable map concept. + /// + template + class ReferenceMap : public ReadWriteMap + { + public: + /// Tag for reference maps. + typedef True ReferenceMapTag; + /// The key type of the map. + typedef K Key; + /// \brief The value type of the map. + /// (The type of objects associated with the keys). + typedef T Value; + /// The reference type of the map. + typedef R Reference; + /// The const reference type of the map. + typedef CR ConstReference; + + public: + + /// Returns a reference to the value associated with the given key. + Reference operator[](const Key &) { + Value *r = 0; + return *r; + } + + /// Returns a const reference to the value associated with the given key. + ConstReference operator[](const Key &) const { + Value *r = 0; + return *r; + } + + /// Sets the value associated with the given key. + void set(const Key &k,const Value &t) { operator[](k)=t; } + + template + struct Constraints { + typename enable_if::type + constraints() { + checkConcept, _ReferenceMap >(); + ref = m[key]; + m[key] = val; + m[key] = ref; + m[key] = cref; + own_ref = m[own_key]; + m[own_key] = own_val; + m[own_key] = own_ref; + m[own_key] = own_cref; + m[key] = m[own_key]; + m[own_key] = m[key]; + } + const Key& key; + Value& val; + Reference ref; + ConstReference cref; + const typename _ReferenceMap::Key& own_key; + typename _ReferenceMap::Value& own_val; + typename _ReferenceMap::Reference own_ref; + typename _ReferenceMap::ConstReference own_cref; + _ReferenceMap& m; + Constraints() {} + }; + }; + + // @} + + } //namespace concepts + +} //namespace lemon + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/path.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/path.h new file mode 100644 index 00000000000..18e4b01803d --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/concepts/path.h @@ -0,0 +1,312 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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. + * + */ + +///\ingroup concept +///\file +///\brief The concept of paths +/// + +#ifndef LEMON_CONCEPTS_PATH_H +#define LEMON_CONCEPTS_PATH_H + +#include +#include + +namespace lemon { + namespace concepts { + + /// \addtogroup concept + /// @{ + + /// \brief A skeleton structure for representing directed paths in + /// a digraph. + /// + /// A skeleton structure for representing directed paths in a + /// digraph. + /// In a sense, a path can be treated as a list of arcs. + /// LEMON path types just store this list. As a consequence, they cannot + /// enumerate the nodes on the path directly and a zero length path + /// cannot store its source node. + /// + /// The arcs of a path should be stored in the order of their directions, + /// i.e. the target node of each arc should be the same as the source + /// node of the next arc. This consistency could be checked using + /// \ref checkPath(). + /// The source and target nodes of a (consistent) path can be obtained + /// using \ref pathSource() and \ref pathTarget(). + /// + /// A path can be constructed from another path of any type using the + /// copy constructor or the assignment operator. + /// + /// \tparam GR The digraph type in which the path is. + template + class Path { + public: + + /// Type of the underlying digraph. + typedef GR Digraph; + /// Arc type of the underlying digraph. + typedef typename Digraph::Arc Arc; + + class ArcIt; + + /// \brief Default constructor + Path() {} + + /// \brief Template copy constructor + template + Path(const CPath& cpath) {} + + /// \brief Template assigment operator + template + Path& operator=(const CPath& cpath) { + ::lemon::ignore_unused_variable_warning(cpath); + return *this; + } + + /// Length of the path, i.e. the number of arcs on the path. + int length() const { return 0;} + + /// Returns whether the path is empty. + bool empty() const { return true;} + + /// Resets the path to an empty path. + void clear() {} + + /// \brief LEMON style iterator for enumerating the arcs of a path. + /// + /// LEMON style iterator class for enumerating the arcs of a path. + class ArcIt { + public: + /// Default constructor + ArcIt() {} + /// Invalid constructor + ArcIt(Invalid) {} + /// Sets the iterator to the first arc of the given path + ArcIt(const Path &) {} + + /// Conversion to \c Arc + operator Arc() const { return INVALID; } + + /// Next arc + ArcIt& operator++() {return *this;} + + /// Comparison operator + bool operator==(const ArcIt&) const {return true;} + /// Comparison operator + bool operator!=(const ArcIt&) const {return true;} + /// Comparison operator + bool operator<(const ArcIt&) const {return false;} + + }; + + template + struct Constraints { + void constraints() { + Path pc; + _Path p, pp(pc); + int l = p.length(); + int e = p.empty(); + p.clear(); + + p = pc; + + typename _Path::ArcIt id, ii(INVALID), i(p); + + ++i; + typename Digraph::Arc ed = i; + + e = (i == ii); + e = (i != ii); + e = (i < ii); + + ::lemon::ignore_unused_variable_warning(l); + ::lemon::ignore_unused_variable_warning(pp); + ::lemon::ignore_unused_variable_warning(e); + ::lemon::ignore_unused_variable_warning(id); + ::lemon::ignore_unused_variable_warning(ii); + ::lemon::ignore_unused_variable_warning(ed); + } + }; + + }; + + namespace _path_bits { + + template + struct PathDumperConstraints { + void constraints() { + int l = p.length(); + int e = p.empty(); + + typename _Path::ArcIt id, i(p); + + ++i; + typename _Digraph::Arc ed = i; + + e = (i == INVALID); + e = (i != INVALID); + + ::lemon::ignore_unused_variable_warning(l); + ::lemon::ignore_unused_variable_warning(e); + ::lemon::ignore_unused_variable_warning(id); + ::lemon::ignore_unused_variable_warning(ed); + } + _Path& p; + PathDumperConstraints() {} + }; + + template + struct PathDumperConstraints< + _Digraph, _Path, + typename enable_if::type + > { + void constraints() { + int l = p.length(); + int e = p.empty(); + + typename _Path::RevArcIt id, i(p); + + ++i; + typename _Digraph::Arc ed = i; + + e = (i == INVALID); + e = (i != INVALID); + + ::lemon::ignore_unused_variable_warning(l); + ::lemon::ignore_unused_variable_warning(e); + ::lemon::ignore_unused_variable_warning(id); + ::lemon::ignore_unused_variable_warning(ed); + } + _Path& p; + PathDumperConstraints() {} + }; + + } + + + /// \brief A skeleton structure for path dumpers. + /// + /// A skeleton structure for path dumpers. The path dumpers are + /// the generalization of the paths, they can enumerate the arcs + /// of the path either in forward or in backward order. + /// These classes are typically not used directly, they are rather + /// used to be assigned to a real path type. + /// + /// The main purpose of this concept is that the shortest path + /// algorithms can enumerate the arcs easily in reverse order. + /// In LEMON, such algorithms give back a (reverse) path dumper that + /// can be assigned to a real path. The dumpers can be implemented as + /// an adaptor class to the predecessor map. + /// + /// \tparam GR The digraph type in which the path is. + template + class PathDumper { + public: + + /// Type of the underlying digraph. + typedef GR Digraph; + /// Arc type of the underlying digraph. + typedef typename Digraph::Arc Arc; + + /// Length of the path, i.e. the number of arcs on the path. + int length() const { return 0;} + + /// Returns whether the path is empty. + bool empty() const { return true;} + + /// \brief Forward or reverse dumping + /// + /// If this tag is defined to be \c True, then reverse dumping + /// is provided in the path dumper. In this case, \c RevArcIt + /// iterator should be implemented instead of \c ArcIt iterator. + typedef False RevPathTag; + + /// \brief LEMON style iterator for enumerating the arcs of a path. + /// + /// LEMON style iterator class for enumerating the arcs of a path. + class ArcIt { + public: + /// Default constructor + ArcIt() {} + /// Invalid constructor + ArcIt(Invalid) {} + /// Sets the iterator to the first arc of the given path + ArcIt(const PathDumper&) {} + + /// Conversion to \c Arc + operator Arc() const { return INVALID; } + + /// Next arc + ArcIt& operator++() {return *this;} + + /// Comparison operator + bool operator==(const ArcIt&) const {return true;} + /// Comparison operator + bool operator!=(const ArcIt&) const {return true;} + /// Comparison operator + bool operator<(const ArcIt&) const {return false;} + + }; + + /// \brief LEMON style iterator for enumerating the arcs of a path + /// in reverse direction. + /// + /// LEMON style iterator class for enumerating the arcs of a path + /// in reverse direction. + class RevArcIt { + public: + /// Default constructor + RevArcIt() {} + /// Invalid constructor + RevArcIt(Invalid) {} + /// Sets the iterator to the last arc of the given path + RevArcIt(const PathDumper &) {} + + /// Conversion to \c Arc + operator Arc() const { return INVALID; } + + /// Next arc + RevArcIt& operator++() {return *this;} + + /// Comparison operator + bool operator==(const RevArcIt&) const {return true;} + /// Comparison operator + bool operator!=(const RevArcIt&) const {return true;} + /// Comparison operator + bool operator<(const RevArcIt&) const {return false;} + + }; + + template + struct Constraints { + void constraints() { + function_requires<_path_bits:: + PathDumperConstraints >(); + } + }; + + }; + + + ///@} + } + +} // namespace lemon + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/config.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/config.h new file mode 100644 index 00000000000..b9699a223fb --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/config.h @@ -0,0 +1,22 @@ +#define LEMON_VERSION "" +/* #undef LEMON_HAVE_LONG_LONG */ + +/* #undef LEMON_HAVE_LP */ +/* #undef LEMON_HAVE_MIP */ +/* #undef LEMON_HAVE_GLPK */ +/* #undef LEMON_HAVE_CPLEX */ +/* #undef LEMON_HAVE_SOPLEX */ +/* #undef LEMON_HAVE_CLP */ +/* #undef LEMON_HAVE_CBC */ + +#define _LEMON_CPLEX 1 +#define _LEMON_CLP 2 +#define _LEMON_GLPK 3 +#define _LEMON_SOPLEX 4 +#define _LEMON_CBC 5 + +/* #undef LEMON_DEFAULT_LP */ +/* #undef LEMON_DEFAULT_MIP */ + +/* #undef LEMON_USE_PTHREAD */ +/* #undef LEMON_USE_WIN32_THREADS */ diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/config.h.in b/extern/quadriflow/3rd/lemon-1.3.1/lemon/config.h.in new file mode 100644 index 00000000000..37d8c04d733 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/config.h.in @@ -0,0 +1,22 @@ +#define LEMON_VERSION "@PROJECT_VERSION@" +#cmakedefine LEMON_HAVE_LONG_LONG 1 + +#cmakedefine LEMON_HAVE_LP 1 +#cmakedefine LEMON_HAVE_MIP 1 +#cmakedefine LEMON_HAVE_GLPK 1 +#cmakedefine LEMON_HAVE_CPLEX 1 +#cmakedefine LEMON_HAVE_SOPLEX 1 +#cmakedefine LEMON_HAVE_CLP 1 +#cmakedefine LEMON_HAVE_CBC 1 + +#define _LEMON_CPLEX 1 +#define _LEMON_CLP 2 +#define _LEMON_GLPK 3 +#define _LEMON_SOPLEX 4 +#define _LEMON_CBC 5 + +#cmakedefine LEMON_DEFAULT_LP _LEMON_@LEMON_DEFAULT_LP@ +#cmakedefine LEMON_DEFAULT_MIP _LEMON_@LEMON_DEFAULT_MIP@ + +#cmakedefine LEMON_USE_PTHREAD 1 +#cmakedefine LEMON_USE_WIN32_THREADS 1 diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/connectivity.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/connectivity.h new file mode 100644 index 00000000000..6bd85a18818 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/connectivity.h @@ -0,0 +1,1688 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_CONNECTIVITY_H +#define LEMON_CONNECTIVITY_H + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +/// \ingroup graph_properties +/// \file +/// \brief Connectivity algorithms +/// +/// Connectivity algorithms + +namespace lemon { + + /// \ingroup graph_properties + /// + /// \brief Check whether an undirected graph is connected. + /// + /// This function checks whether the given undirected graph is connected, + /// i.e. there is a path between any two nodes in the graph. + /// + /// \return \c true if the graph is connected. + /// \note By definition, the empty graph is connected. + /// + /// \see countConnectedComponents(), connectedComponents() + /// \see stronglyConnected() + template + bool connected(const Graph& graph) { + checkConcept(); + typedef typename Graph::NodeIt NodeIt; + if (NodeIt(graph) == INVALID) return true; + Dfs dfs(graph); + dfs.run(NodeIt(graph)); + for (NodeIt it(graph); it != INVALID; ++it) { + if (!dfs.reached(it)) { + return false; + } + } + return true; + } + + /// \ingroup graph_properties + /// + /// \brief Count the number of connected components of an undirected graph + /// + /// This function counts the number of connected components of the given + /// undirected graph. + /// + /// The connected components are the classes of an equivalence relation + /// on the nodes of an undirected graph. Two nodes are in the same class + /// if they are connected with a path. + /// + /// \return The number of connected components. + /// \note By definition, the empty graph consists + /// of zero connected components. + /// + /// \see connected(), connectedComponents() + template + int countConnectedComponents(const Graph &graph) { + checkConcept(); + typedef typename Graph::Node Node; + typedef typename Graph::Arc Arc; + + typedef NullMap PredMap; + typedef NullMap DistMap; + + int compNum = 0; + typename Bfs:: + template SetPredMap:: + template SetDistMap:: + Create bfs(graph); + + PredMap predMap; + bfs.predMap(predMap); + + DistMap distMap; + bfs.distMap(distMap); + + bfs.init(); + for(typename Graph::NodeIt n(graph); n != INVALID; ++n) { + if (!bfs.reached(n)) { + bfs.addSource(n); + bfs.start(); + ++compNum; + } + } + return compNum; + } + + /// \ingroup graph_properties + /// + /// \brief Find the connected components of an undirected graph + /// + /// This function finds the connected components of the given undirected + /// graph. + /// + /// The connected components are the classes of an equivalence relation + /// on the nodes of an undirected graph. Two nodes are in the same class + /// if they are connected with a path. + /// + /// \image html connected_components.png + /// \image latex connected_components.eps "Connected components" width=\textwidth + /// + /// \param graph The undirected graph. + /// \retval compMap A writable node map. The values will be set from 0 to + /// the number of the connected components minus one. Each value of the map + /// will be set exactly once, and the values of a certain component will be + /// set continuously. + /// \return The number of connected components. + /// \note By definition, the empty graph consists + /// of zero connected components. + /// + /// \see connected(), countConnectedComponents() + template + int connectedComponents(const Graph &graph, NodeMap &compMap) { + checkConcept(); + typedef typename Graph::Node Node; + typedef typename Graph::Arc Arc; + checkConcept, NodeMap>(); + + typedef NullMap PredMap; + typedef NullMap DistMap; + + int compNum = 0; + typename Bfs:: + template SetPredMap:: + template SetDistMap:: + Create bfs(graph); + + PredMap predMap; + bfs.predMap(predMap); + + DistMap distMap; + bfs.distMap(distMap); + + bfs.init(); + for(typename Graph::NodeIt n(graph); n != INVALID; ++n) { + if(!bfs.reached(n)) { + bfs.addSource(n); + while (!bfs.emptyQueue()) { + compMap.set(bfs.nextNode(), compNum); + bfs.processNextNode(); + } + ++compNum; + } + } + return compNum; + } + + namespace _connectivity_bits { + + template + struct LeaveOrderVisitor : public DfsVisitor { + public: + typedef typename Digraph::Node Node; + LeaveOrderVisitor(Iterator it) : _it(it) {} + + void leave(const Node& node) { + *(_it++) = node; + } + + private: + Iterator _it; + }; + + template + struct FillMapVisitor : public DfsVisitor { + public: + typedef typename Digraph::Node Node; + typedef typename Map::Value Value; + + FillMapVisitor(Map& map, Value& value) + : _map(map), _value(value) {} + + void reach(const Node& node) { + _map.set(node, _value); + } + private: + Map& _map; + Value& _value; + }; + + template + struct StronglyConnectedCutArcsVisitor : public DfsVisitor { + public: + typedef typename Digraph::Node Node; + typedef typename Digraph::Arc Arc; + + StronglyConnectedCutArcsVisitor(const Digraph& digraph, + ArcMap& cutMap, + int& cutNum) + : _digraph(digraph), _cutMap(cutMap), _cutNum(cutNum), + _compMap(digraph, -1), _num(-1) { + } + + void start(const Node&) { + ++_num; + } + + void reach(const Node& node) { + _compMap.set(node, _num); + } + + void examine(const Arc& arc) { + if (_compMap[_digraph.source(arc)] != + _compMap[_digraph.target(arc)]) { + _cutMap.set(arc, true); + ++_cutNum; + } + } + private: + const Digraph& _digraph; + ArcMap& _cutMap; + int& _cutNum; + + typename Digraph::template NodeMap _compMap; + int _num; + }; + + } + + + /// \ingroup graph_properties + /// + /// \brief Check whether a directed graph is strongly connected. + /// + /// This function checks whether the given directed graph is strongly + /// connected, i.e. any two nodes of the digraph are + /// connected with directed paths in both direction. + /// + /// \return \c true if the digraph is strongly connected. + /// \note By definition, the empty digraph is strongly connected. + /// + /// \see countStronglyConnectedComponents(), stronglyConnectedComponents() + /// \see connected() + template + bool stronglyConnected(const Digraph& digraph) { + checkConcept(); + + typedef typename Digraph::Node Node; + typedef typename Digraph::NodeIt NodeIt; + + typename Digraph::Node source = NodeIt(digraph); + if (source == INVALID) return true; + + using namespace _connectivity_bits; + + typedef DfsVisitor Visitor; + Visitor visitor; + + DfsVisit dfs(digraph, visitor); + dfs.init(); + dfs.addSource(source); + dfs.start(); + + for (NodeIt it(digraph); it != INVALID; ++it) { + if (!dfs.reached(it)) { + return false; + } + } + + typedef ReverseDigraph RDigraph; + typedef typename RDigraph::NodeIt RNodeIt; + RDigraph rdigraph(digraph); + + typedef DfsVisitor RVisitor; + RVisitor rvisitor; + + DfsVisit rdfs(rdigraph, rvisitor); + rdfs.init(); + rdfs.addSource(source); + rdfs.start(); + + for (RNodeIt it(rdigraph); it != INVALID; ++it) { + if (!rdfs.reached(it)) { + return false; + } + } + + return true; + } + + /// \ingroup graph_properties + /// + /// \brief Count the number of strongly connected components of a + /// directed graph + /// + /// This function counts the number of strongly connected components of + /// the given directed graph. + /// + /// The strongly connected components are the classes of an + /// equivalence relation on the nodes of a digraph. Two nodes are in + /// the same class if they are connected with directed paths in both + /// direction. + /// + /// \return The number of strongly connected components. + /// \note By definition, the empty digraph has zero + /// strongly connected components. + /// + /// \see stronglyConnected(), stronglyConnectedComponents() + template + int countStronglyConnectedComponents(const Digraph& digraph) { + checkConcept(); + + using namespace _connectivity_bits; + + typedef typename Digraph::Node Node; + typedef typename Digraph::Arc Arc; + typedef typename Digraph::NodeIt NodeIt; + typedef typename Digraph::ArcIt ArcIt; + + typedef std::vector Container; + typedef typename Container::iterator Iterator; + + Container nodes(countNodes(digraph)); + typedef LeaveOrderVisitor Visitor; + Visitor visitor(nodes.begin()); + + DfsVisit dfs(digraph, visitor); + dfs.init(); + for (NodeIt it(digraph); it != INVALID; ++it) { + if (!dfs.reached(it)) { + dfs.addSource(it); + dfs.start(); + } + } + + typedef typename Container::reverse_iterator RIterator; + typedef ReverseDigraph RDigraph; + + RDigraph rdigraph(digraph); + + typedef DfsVisitor RVisitor; + RVisitor rvisitor; + + DfsVisit rdfs(rdigraph, rvisitor); + + int compNum = 0; + + rdfs.init(); + for (RIterator it = nodes.rbegin(); it != nodes.rend(); ++it) { + if (!rdfs.reached(*it)) { + rdfs.addSource(*it); + rdfs.start(); + ++compNum; + } + } + return compNum; + } + + /// \ingroup graph_properties + /// + /// \brief Find the strongly connected components of a directed graph + /// + /// This function finds the strongly connected components of the given + /// directed graph. In addition, the numbering of the components will + /// satisfy that there is no arc going from a higher numbered component + /// to a lower one (i.e. it provides a topological order of the components). + /// + /// The strongly connected components are the classes of an + /// equivalence relation on the nodes of a digraph. Two nodes are in + /// the same class if they are connected with directed paths in both + /// direction. + /// + /// \image html strongly_connected_components.png + /// \image latex strongly_connected_components.eps "Strongly connected components" width=\textwidth + /// + /// \param digraph The digraph. + /// \retval compMap A writable node map. The values will be set from 0 to + /// the number of the strongly connected components minus one. Each value + /// of the map will be set exactly once, and the values of a certain + /// component will be set continuously. + /// \return The number of strongly connected components. + /// \note By definition, the empty digraph has zero + /// strongly connected components. + /// + /// \see stronglyConnected(), countStronglyConnectedComponents() + template + int stronglyConnectedComponents(const Digraph& digraph, NodeMap& compMap) { + checkConcept(); + typedef typename Digraph::Node Node; + typedef typename Digraph::NodeIt NodeIt; + checkConcept, NodeMap>(); + + using namespace _connectivity_bits; + + typedef std::vector Container; + typedef typename Container::iterator Iterator; + + Container nodes(countNodes(digraph)); + typedef LeaveOrderVisitor Visitor; + Visitor visitor(nodes.begin()); + + DfsVisit dfs(digraph, visitor); + dfs.init(); + for (NodeIt it(digraph); it != INVALID; ++it) { + if (!dfs.reached(it)) { + dfs.addSource(it); + dfs.start(); + } + } + + typedef typename Container::reverse_iterator RIterator; + typedef ReverseDigraph RDigraph; + + RDigraph rdigraph(digraph); + + int compNum = 0; + + typedef FillMapVisitor RVisitor; + RVisitor rvisitor(compMap, compNum); + + DfsVisit rdfs(rdigraph, rvisitor); + + rdfs.init(); + for (RIterator it = nodes.rbegin(); it != nodes.rend(); ++it) { + if (!rdfs.reached(*it)) { + rdfs.addSource(*it); + rdfs.start(); + ++compNum; + } + } + return compNum; + } + + /// \ingroup graph_properties + /// + /// \brief Find the cut arcs of the strongly connected components. + /// + /// This function finds the cut arcs of the strongly connected components + /// of the given digraph. + /// + /// The strongly connected components are the classes of an + /// equivalence relation on the nodes of a digraph. Two nodes are in + /// the same class if they are connected with directed paths in both + /// direction. + /// The strongly connected components are separated by the cut arcs. + /// + /// \param digraph The digraph. + /// \retval cutMap A writable arc map. The values will be set to \c true + /// for the cut arcs (exactly once for each cut arc), and will not be + /// changed for other arcs. + /// \return The number of cut arcs. + /// + /// \see stronglyConnected(), stronglyConnectedComponents() + template + int stronglyConnectedCutArcs(const Digraph& digraph, ArcMap& cutMap) { + checkConcept(); + typedef typename Digraph::Node Node; + typedef typename Digraph::Arc Arc; + typedef typename Digraph::NodeIt NodeIt; + checkConcept, ArcMap>(); + + using namespace _connectivity_bits; + + typedef std::vector Container; + typedef typename Container::iterator Iterator; + + Container nodes(countNodes(digraph)); + typedef LeaveOrderVisitor Visitor; + Visitor visitor(nodes.begin()); + + DfsVisit dfs(digraph, visitor); + dfs.init(); + for (NodeIt it(digraph); it != INVALID; ++it) { + if (!dfs.reached(it)) { + dfs.addSource(it); + dfs.start(); + } + } + + typedef typename Container::reverse_iterator RIterator; + typedef ReverseDigraph RDigraph; + + RDigraph rdigraph(digraph); + + int cutNum = 0; + + typedef StronglyConnectedCutArcsVisitor RVisitor; + RVisitor rvisitor(rdigraph, cutMap, cutNum); + + DfsVisit rdfs(rdigraph, rvisitor); + + rdfs.init(); + for (RIterator it = nodes.rbegin(); it != nodes.rend(); ++it) { + if (!rdfs.reached(*it)) { + rdfs.addSource(*it); + rdfs.start(); + } + } + return cutNum; + } + + namespace _connectivity_bits { + + template + class CountBiNodeConnectedComponentsVisitor : public DfsVisitor { + public: + typedef typename Digraph::Node Node; + typedef typename Digraph::Arc Arc; + typedef typename Digraph::Edge Edge; + + CountBiNodeConnectedComponentsVisitor(const Digraph& graph, int &compNum) + : _graph(graph), _compNum(compNum), + _numMap(graph), _retMap(graph), _predMap(graph), _num(0) {} + + void start(const Node& node) { + _predMap.set(node, INVALID); + } + + void reach(const Node& node) { + _numMap.set(node, _num); + _retMap.set(node, _num); + ++_num; + } + + void discover(const Arc& edge) { + _predMap.set(_graph.target(edge), _graph.source(edge)); + } + + void examine(const Arc& edge) { + if (_graph.source(edge) == _graph.target(edge) && + _graph.direction(edge)) { + ++_compNum; + return; + } + if (_predMap[_graph.source(edge)] == _graph.target(edge)) { + return; + } + if (_retMap[_graph.source(edge)] > _numMap[_graph.target(edge)]) { + _retMap.set(_graph.source(edge), _numMap[_graph.target(edge)]); + } + } + + void backtrack(const Arc& edge) { + if (_retMap[_graph.source(edge)] > _retMap[_graph.target(edge)]) { + _retMap.set(_graph.source(edge), _retMap[_graph.target(edge)]); + } + if (_numMap[_graph.source(edge)] <= _retMap[_graph.target(edge)]) { + ++_compNum; + } + } + + private: + const Digraph& _graph; + int& _compNum; + + typename Digraph::template NodeMap _numMap; + typename Digraph::template NodeMap _retMap; + typename Digraph::template NodeMap _predMap; + int _num; + }; + + template + class BiNodeConnectedComponentsVisitor : public DfsVisitor { + public: + typedef typename Digraph::Node Node; + typedef typename Digraph::Arc Arc; + typedef typename Digraph::Edge Edge; + + BiNodeConnectedComponentsVisitor(const Digraph& graph, + ArcMap& compMap, int &compNum) + : _graph(graph), _compMap(compMap), _compNum(compNum), + _numMap(graph), _retMap(graph), _predMap(graph), _num(0) {} + + void start(const Node& node) { + _predMap.set(node, INVALID); + } + + void reach(const Node& node) { + _numMap.set(node, _num); + _retMap.set(node, _num); + ++_num; + } + + void discover(const Arc& edge) { + Node target = _graph.target(edge); + _predMap.set(target, edge); + _edgeStack.push(edge); + } + + void examine(const Arc& edge) { + Node source = _graph.source(edge); + Node target = _graph.target(edge); + if (source == target && _graph.direction(edge)) { + _compMap.set(edge, _compNum); + ++_compNum; + return; + } + if (_numMap[target] < _numMap[source]) { + if (_predMap[source] != _graph.oppositeArc(edge)) { + _edgeStack.push(edge); + } + } + if (_predMap[source] != INVALID && + target == _graph.source(_predMap[source])) { + return; + } + if (_retMap[source] > _numMap[target]) { + _retMap.set(source, _numMap[target]); + } + } + + void backtrack(const Arc& edge) { + Node source = _graph.source(edge); + Node target = _graph.target(edge); + if (_retMap[source] > _retMap[target]) { + _retMap.set(source, _retMap[target]); + } + if (_numMap[source] <= _retMap[target]) { + while (_edgeStack.top() != edge) { + _compMap.set(_edgeStack.top(), _compNum); + _edgeStack.pop(); + } + _compMap.set(edge, _compNum); + _edgeStack.pop(); + ++_compNum; + } + } + + private: + const Digraph& _graph; + ArcMap& _compMap; + int& _compNum; + + typename Digraph::template NodeMap _numMap; + typename Digraph::template NodeMap _retMap; + typename Digraph::template NodeMap _predMap; + std::stack _edgeStack; + int _num; + }; + + + template + class BiNodeConnectedCutNodesVisitor : public DfsVisitor { + public: + typedef typename Digraph::Node Node; + typedef typename Digraph::Arc Arc; + typedef typename Digraph::Edge Edge; + + BiNodeConnectedCutNodesVisitor(const Digraph& graph, NodeMap& cutMap, + int& cutNum) + : _graph(graph), _cutMap(cutMap), _cutNum(cutNum), + _numMap(graph), _retMap(graph), _predMap(graph), _num(0) {} + + void start(const Node& node) { + _predMap.set(node, INVALID); + rootCut = false; + } + + void reach(const Node& node) { + _numMap.set(node, _num); + _retMap.set(node, _num); + ++_num; + } + + void discover(const Arc& edge) { + _predMap.set(_graph.target(edge), _graph.source(edge)); + } + + void examine(const Arc& edge) { + if (_graph.source(edge) == _graph.target(edge) && + _graph.direction(edge)) { + if (!_cutMap[_graph.source(edge)]) { + _cutMap.set(_graph.source(edge), true); + ++_cutNum; + } + return; + } + if (_predMap[_graph.source(edge)] == _graph.target(edge)) return; + if (_retMap[_graph.source(edge)] > _numMap[_graph.target(edge)]) { + _retMap.set(_graph.source(edge), _numMap[_graph.target(edge)]); + } + } + + void backtrack(const Arc& edge) { + if (_retMap[_graph.source(edge)] > _retMap[_graph.target(edge)]) { + _retMap.set(_graph.source(edge), _retMap[_graph.target(edge)]); + } + if (_numMap[_graph.source(edge)] <= _retMap[_graph.target(edge)]) { + if (_predMap[_graph.source(edge)] != INVALID) { + if (!_cutMap[_graph.source(edge)]) { + _cutMap.set(_graph.source(edge), true); + ++_cutNum; + } + } else if (rootCut) { + if (!_cutMap[_graph.source(edge)]) { + _cutMap.set(_graph.source(edge), true); + ++_cutNum; + } + } else { + rootCut = true; + } + } + } + + private: + const Digraph& _graph; + NodeMap& _cutMap; + int& _cutNum; + + typename Digraph::template NodeMap _numMap; + typename Digraph::template NodeMap _retMap; + typename Digraph::template NodeMap _predMap; + std::stack _edgeStack; + int _num; + bool rootCut; + }; + + } + + template + int countBiNodeConnectedComponents(const Graph& graph); + + /// \ingroup graph_properties + /// + /// \brief Check whether an undirected graph is bi-node-connected. + /// + /// This function checks whether the given undirected graph is + /// bi-node-connected, i.e. a connected graph without articulation + /// node. + /// + /// \return \c true if the graph bi-node-connected. + /// + /// \note By definition, + /// \li a graph consisting of zero or one node is bi-node-connected, + /// \li a graph consisting of two isolated nodes + /// is \e not bi-node-connected and + /// \li a graph consisting of two nodes connected by an edge + /// is bi-node-connected. + /// + /// \see countBiNodeConnectedComponents(), biNodeConnectedComponents() + template + bool biNodeConnected(const Graph& graph) { + bool hasNonIsolated = false, hasIsolated = false; + for (typename Graph::NodeIt n(graph); n != INVALID; ++n) { + if (typename Graph::OutArcIt(graph, n) == INVALID) { + if (hasIsolated || hasNonIsolated) { + return false; + } else { + hasIsolated = true; + } + } else { + if (hasIsolated) { + return false; + } else { + hasNonIsolated = true; + } + } + } + return countBiNodeConnectedComponents(graph) <= 1; + } + + /// \ingroup graph_properties + /// + /// \brief Count the number of bi-node-connected components of an + /// undirected graph. + /// + /// This function counts the number of bi-node-connected components of + /// the given undirected graph. + /// + /// The bi-node-connected components are the classes of an equivalence + /// relation on the edges of a undirected graph. Two edges are in the + /// same class if they are on same circle. + /// + /// \return The number of bi-node-connected components. + /// + /// \see biNodeConnected(), biNodeConnectedComponents() + template + int countBiNodeConnectedComponents(const Graph& graph) { + checkConcept(); + typedef typename Graph::NodeIt NodeIt; + + using namespace _connectivity_bits; + + typedef CountBiNodeConnectedComponentsVisitor Visitor; + + int compNum = 0; + Visitor visitor(graph, compNum); + + DfsVisit dfs(graph, visitor); + dfs.init(); + + for (NodeIt it(graph); it != INVALID; ++it) { + if (!dfs.reached(it)) { + dfs.addSource(it); + dfs.start(); + } + } + return compNum; + } + + /// \ingroup graph_properties + /// + /// \brief Find the bi-node-connected components of an undirected graph. + /// + /// This function finds the bi-node-connected components of the given + /// undirected graph. + /// + /// The bi-node-connected components are the classes of an equivalence + /// relation on the edges of a undirected graph. Two edges are in the + /// same class if they are on same circle. + /// + /// \image html node_biconnected_components.png + /// \image latex node_biconnected_components.eps "bi-node-connected components" width=\textwidth + /// + /// \param graph The undirected graph. + /// \retval compMap A writable edge map. The values will be set from 0 + /// to the number of the bi-node-connected components minus one. Each + /// value of the map will be set exactly once, and the values of a + /// certain component will be set continuously. + /// \return The number of bi-node-connected components. + /// + /// \see biNodeConnected(), countBiNodeConnectedComponents() + template + int biNodeConnectedComponents(const Graph& graph, + EdgeMap& compMap) { + checkConcept(); + typedef typename Graph::NodeIt NodeIt; + typedef typename Graph::Edge Edge; + checkConcept, EdgeMap>(); + + using namespace _connectivity_bits; + + typedef BiNodeConnectedComponentsVisitor Visitor; + + int compNum = 0; + Visitor visitor(graph, compMap, compNum); + + DfsVisit dfs(graph, visitor); + dfs.init(); + + for (NodeIt it(graph); it != INVALID; ++it) { + if (!dfs.reached(it)) { + dfs.addSource(it); + dfs.start(); + } + } + return compNum; + } + + /// \ingroup graph_properties + /// + /// \brief Find the bi-node-connected cut nodes in an undirected graph. + /// + /// This function finds the bi-node-connected cut nodes in the given + /// undirected graph. + /// + /// The bi-node-connected components are the classes of an equivalence + /// relation on the edges of a undirected graph. Two edges are in the + /// same class if they are on same circle. + /// The bi-node-connected components are separted by the cut nodes of + /// the components. + /// + /// \param graph The undirected graph. + /// \retval cutMap A writable node map. The values will be set to + /// \c true for the nodes that separate two or more components + /// (exactly once for each cut node), and will not be changed for + /// other nodes. + /// \return The number of the cut nodes. + /// + /// \see biNodeConnected(), biNodeConnectedComponents() + template + int biNodeConnectedCutNodes(const Graph& graph, NodeMap& cutMap) { + checkConcept(); + typedef typename Graph::Node Node; + typedef typename Graph::NodeIt NodeIt; + checkConcept, NodeMap>(); + + using namespace _connectivity_bits; + + typedef BiNodeConnectedCutNodesVisitor Visitor; + + int cutNum = 0; + Visitor visitor(graph, cutMap, cutNum); + + DfsVisit dfs(graph, visitor); + dfs.init(); + + for (NodeIt it(graph); it != INVALID; ++it) { + if (!dfs.reached(it)) { + dfs.addSource(it); + dfs.start(); + } + } + return cutNum; + } + + namespace _connectivity_bits { + + template + class CountBiEdgeConnectedComponentsVisitor : public DfsVisitor { + public: + typedef typename Digraph::Node Node; + typedef typename Digraph::Arc Arc; + typedef typename Digraph::Edge Edge; + + CountBiEdgeConnectedComponentsVisitor(const Digraph& graph, int &compNum) + : _graph(graph), _compNum(compNum), + _numMap(graph), _retMap(graph), _predMap(graph), _num(0) {} + + void start(const Node& node) { + _predMap.set(node, INVALID); + } + + void reach(const Node& node) { + _numMap.set(node, _num); + _retMap.set(node, _num); + ++_num; + } + + void leave(const Node& node) { + if (_numMap[node] <= _retMap[node]) { + ++_compNum; + } + } + + void discover(const Arc& edge) { + _predMap.set(_graph.target(edge), edge); + } + + void examine(const Arc& edge) { + if (_predMap[_graph.source(edge)] == _graph.oppositeArc(edge)) { + return; + } + if (_retMap[_graph.source(edge)] > _retMap[_graph.target(edge)]) { + _retMap.set(_graph.source(edge), _retMap[_graph.target(edge)]); + } + } + + void backtrack(const Arc& edge) { + if (_retMap[_graph.source(edge)] > _retMap[_graph.target(edge)]) { + _retMap.set(_graph.source(edge), _retMap[_graph.target(edge)]); + } + } + + private: + const Digraph& _graph; + int& _compNum; + + typename Digraph::template NodeMap _numMap; + typename Digraph::template NodeMap _retMap; + typename Digraph::template NodeMap _predMap; + int _num; + }; + + template + class BiEdgeConnectedComponentsVisitor : public DfsVisitor { + public: + typedef typename Digraph::Node Node; + typedef typename Digraph::Arc Arc; + typedef typename Digraph::Edge Edge; + + BiEdgeConnectedComponentsVisitor(const Digraph& graph, + NodeMap& compMap, int &compNum) + : _graph(graph), _compMap(compMap), _compNum(compNum), + _numMap(graph), _retMap(graph), _predMap(graph), _num(0) {} + + void start(const Node& node) { + _predMap.set(node, INVALID); + } + + void reach(const Node& node) { + _numMap.set(node, _num); + _retMap.set(node, _num); + _nodeStack.push(node); + ++_num; + } + + void leave(const Node& node) { + if (_numMap[node] <= _retMap[node]) { + while (_nodeStack.top() != node) { + _compMap.set(_nodeStack.top(), _compNum); + _nodeStack.pop(); + } + _compMap.set(node, _compNum); + _nodeStack.pop(); + ++_compNum; + } + } + + void discover(const Arc& edge) { + _predMap.set(_graph.target(edge), edge); + } + + void examine(const Arc& edge) { + if (_predMap[_graph.source(edge)] == _graph.oppositeArc(edge)) { + return; + } + if (_retMap[_graph.source(edge)] > _retMap[_graph.target(edge)]) { + _retMap.set(_graph.source(edge), _retMap[_graph.target(edge)]); + } + } + + void backtrack(const Arc& edge) { + if (_retMap[_graph.source(edge)] > _retMap[_graph.target(edge)]) { + _retMap.set(_graph.source(edge), _retMap[_graph.target(edge)]); + } + } + + private: + const Digraph& _graph; + NodeMap& _compMap; + int& _compNum; + + typename Digraph::template NodeMap _numMap; + typename Digraph::template NodeMap _retMap; + typename Digraph::template NodeMap _predMap; + std::stack _nodeStack; + int _num; + }; + + + template + class BiEdgeConnectedCutEdgesVisitor : public DfsVisitor { + public: + typedef typename Digraph::Node Node; + typedef typename Digraph::Arc Arc; + typedef typename Digraph::Edge Edge; + + BiEdgeConnectedCutEdgesVisitor(const Digraph& graph, + ArcMap& cutMap, int &cutNum) + : _graph(graph), _cutMap(cutMap), _cutNum(cutNum), + _numMap(graph), _retMap(graph), _predMap(graph), _num(0) {} + + void start(const Node& node) { + _predMap[node] = INVALID; + } + + void reach(const Node& node) { + _numMap.set(node, _num); + _retMap.set(node, _num); + ++_num; + } + + void leave(const Node& node) { + if (_numMap[node] <= _retMap[node]) { + if (_predMap[node] != INVALID) { + _cutMap.set(_predMap[node], true); + ++_cutNum; + } + } + } + + void discover(const Arc& edge) { + _predMap.set(_graph.target(edge), edge); + } + + void examine(const Arc& edge) { + if (_predMap[_graph.source(edge)] == _graph.oppositeArc(edge)) { + return; + } + if (_retMap[_graph.source(edge)] > _retMap[_graph.target(edge)]) { + _retMap.set(_graph.source(edge), _retMap[_graph.target(edge)]); + } + } + + void backtrack(const Arc& edge) { + if (_retMap[_graph.source(edge)] > _retMap[_graph.target(edge)]) { + _retMap.set(_graph.source(edge), _retMap[_graph.target(edge)]); + } + } + + private: + const Digraph& _graph; + ArcMap& _cutMap; + int& _cutNum; + + typename Digraph::template NodeMap _numMap; + typename Digraph::template NodeMap _retMap; + typename Digraph::template NodeMap _predMap; + int _num; + }; + } + + template + int countBiEdgeConnectedComponents(const Graph& graph); + + /// \ingroup graph_properties + /// + /// \brief Check whether an undirected graph is bi-edge-connected. + /// + /// This function checks whether the given undirected graph is + /// bi-edge-connected, i.e. any two nodes are connected with at least + /// two edge-disjoint paths. + /// + /// \return \c true if the graph is bi-edge-connected. + /// \note By definition, the empty graph is bi-edge-connected. + /// + /// \see countBiEdgeConnectedComponents(), biEdgeConnectedComponents() + template + bool biEdgeConnected(const Graph& graph) { + return countBiEdgeConnectedComponents(graph) <= 1; + } + + /// \ingroup graph_properties + /// + /// \brief Count the number of bi-edge-connected components of an + /// undirected graph. + /// + /// This function counts the number of bi-edge-connected components of + /// the given undirected graph. + /// + /// The bi-edge-connected components are the classes of an equivalence + /// relation on the nodes of an undirected graph. Two nodes are in the + /// same class if they are connected with at least two edge-disjoint + /// paths. + /// + /// \return The number of bi-edge-connected components. + /// + /// \see biEdgeConnected(), biEdgeConnectedComponents() + template + int countBiEdgeConnectedComponents(const Graph& graph) { + checkConcept(); + typedef typename Graph::NodeIt NodeIt; + + using namespace _connectivity_bits; + + typedef CountBiEdgeConnectedComponentsVisitor Visitor; + + int compNum = 0; + Visitor visitor(graph, compNum); + + DfsVisit dfs(graph, visitor); + dfs.init(); + + for (NodeIt it(graph); it != INVALID; ++it) { + if (!dfs.reached(it)) { + dfs.addSource(it); + dfs.start(); + } + } + return compNum; + } + + /// \ingroup graph_properties + /// + /// \brief Find the bi-edge-connected components of an undirected graph. + /// + /// This function finds the bi-edge-connected components of the given + /// undirected graph. + /// + /// The bi-edge-connected components are the classes of an equivalence + /// relation on the nodes of an undirected graph. Two nodes are in the + /// same class if they are connected with at least two edge-disjoint + /// paths. + /// + /// \image html edge_biconnected_components.png + /// \image latex edge_biconnected_components.eps "bi-edge-connected components" width=\textwidth + /// + /// \param graph The undirected graph. + /// \retval compMap A writable node map. The values will be set from 0 to + /// the number of the bi-edge-connected components minus one. Each value + /// of the map will be set exactly once, and the values of a certain + /// component will be set continuously. + /// \return The number of bi-edge-connected components. + /// + /// \see biEdgeConnected(), countBiEdgeConnectedComponents() + template + int biEdgeConnectedComponents(const Graph& graph, NodeMap& compMap) { + checkConcept(); + typedef typename Graph::NodeIt NodeIt; + typedef typename Graph::Node Node; + checkConcept, NodeMap>(); + + using namespace _connectivity_bits; + + typedef BiEdgeConnectedComponentsVisitor Visitor; + + int compNum = 0; + Visitor visitor(graph, compMap, compNum); + + DfsVisit dfs(graph, visitor); + dfs.init(); + + for (NodeIt it(graph); it != INVALID; ++it) { + if (!dfs.reached(it)) { + dfs.addSource(it); + dfs.start(); + } + } + return compNum; + } + + /// \ingroup graph_properties + /// + /// \brief Find the bi-edge-connected cut edges in an undirected graph. + /// + /// This function finds the bi-edge-connected cut edges in the given + /// undirected graph. + /// + /// The bi-edge-connected components are the classes of an equivalence + /// relation on the nodes of an undirected graph. Two nodes are in the + /// same class if they are connected with at least two edge-disjoint + /// paths. + /// The bi-edge-connected components are separted by the cut edges of + /// the components. + /// + /// \param graph The undirected graph. + /// \retval cutMap A writable edge map. The values will be set to \c true + /// for the cut edges (exactly once for each cut edge), and will not be + /// changed for other edges. + /// \return The number of cut edges. + /// + /// \see biEdgeConnected(), biEdgeConnectedComponents() + template + int biEdgeConnectedCutEdges(const Graph& graph, EdgeMap& cutMap) { + checkConcept(); + typedef typename Graph::NodeIt NodeIt; + typedef typename Graph::Edge Edge; + checkConcept, EdgeMap>(); + + using namespace _connectivity_bits; + + typedef BiEdgeConnectedCutEdgesVisitor Visitor; + + int cutNum = 0; + Visitor visitor(graph, cutMap, cutNum); + + DfsVisit dfs(graph, visitor); + dfs.init(); + + for (NodeIt it(graph); it != INVALID; ++it) { + if (!dfs.reached(it)) { + dfs.addSource(it); + dfs.start(); + } + } + return cutNum; + } + + + namespace _connectivity_bits { + + template + class TopologicalSortVisitor : public DfsVisitor { + public: + typedef typename Digraph::Node Node; + typedef typename Digraph::Arc edge; + + TopologicalSortVisitor(IntNodeMap& order, int num) + : _order(order), _num(num) {} + + void leave(const Node& node) { + _order.set(node, --_num); + } + + private: + IntNodeMap& _order; + int _num; + }; + + } + + /// \ingroup graph_properties + /// + /// \brief Check whether a digraph is DAG. + /// + /// This function checks whether the given digraph is DAG, i.e. + /// \e Directed \e Acyclic \e Graph. + /// \return \c true if there is no directed cycle in the digraph. + /// \see acyclic() + template + bool dag(const Digraph& digraph) { + + checkConcept(); + + typedef typename Digraph::Node Node; + typedef typename Digraph::NodeIt NodeIt; + typedef typename Digraph::Arc Arc; + + typedef typename Digraph::template NodeMap ProcessedMap; + + typename Dfs::template SetProcessedMap:: + Create dfs(digraph); + + ProcessedMap processed(digraph); + dfs.processedMap(processed); + + dfs.init(); + for (NodeIt it(digraph); it != INVALID; ++it) { + if (!dfs.reached(it)) { + dfs.addSource(it); + while (!dfs.emptyQueue()) { + Arc arc = dfs.nextArc(); + Node target = digraph.target(arc); + if (dfs.reached(target) && !processed[target]) { + return false; + } + dfs.processNextArc(); + } + } + } + return true; + } + + /// \ingroup graph_properties + /// + /// \brief Sort the nodes of a DAG into topolgical order. + /// + /// This function sorts the nodes of the given acyclic digraph (DAG) + /// into topolgical order. + /// + /// \param digraph The digraph, which must be DAG. + /// \retval order A writable node map. The values will be set from 0 to + /// the number of the nodes in the digraph minus one. Each value of the + /// map will be set exactly once, and the values will be set descending + /// order. + /// + /// \see dag(), checkedTopologicalSort() + template + void topologicalSort(const Digraph& digraph, NodeMap& order) { + using namespace _connectivity_bits; + + checkConcept(); + checkConcept, NodeMap>(); + + typedef typename Digraph::Node Node; + typedef typename Digraph::NodeIt NodeIt; + typedef typename Digraph::Arc Arc; + + TopologicalSortVisitor + visitor(order, countNodes(digraph)); + + DfsVisit > + dfs(digraph, visitor); + + dfs.init(); + for (NodeIt it(digraph); it != INVALID; ++it) { + if (!dfs.reached(it)) { + dfs.addSource(it); + dfs.start(); + } + } + } + + /// \ingroup graph_properties + /// + /// \brief Sort the nodes of a DAG into topolgical order. + /// + /// This function sorts the nodes of the given acyclic digraph (DAG) + /// into topolgical order and also checks whether the given digraph + /// is DAG. + /// + /// \param digraph The digraph. + /// \retval order A readable and writable node map. The values will be + /// set from 0 to the number of the nodes in the digraph minus one. + /// Each value of the map will be set exactly once, and the values will + /// be set descending order. + /// \return \c false if the digraph is not DAG. + /// + /// \see dag(), topologicalSort() + template + bool checkedTopologicalSort(const Digraph& digraph, NodeMap& order) { + using namespace _connectivity_bits; + + checkConcept(); + checkConcept, + NodeMap>(); + + typedef typename Digraph::Node Node; + typedef typename Digraph::NodeIt NodeIt; + typedef typename Digraph::Arc Arc; + + for (NodeIt it(digraph); it != INVALID; ++it) { + order.set(it, -1); + } + + TopologicalSortVisitor + visitor(order, countNodes(digraph)); + + DfsVisit > + dfs(digraph, visitor); + + dfs.init(); + for (NodeIt it(digraph); it != INVALID; ++it) { + if (!dfs.reached(it)) { + dfs.addSource(it); + while (!dfs.emptyQueue()) { + Arc arc = dfs.nextArc(); + Node target = digraph.target(arc); + if (dfs.reached(target) && order[target] == -1) { + return false; + } + dfs.processNextArc(); + } + } + } + return true; + } + + /// \ingroup graph_properties + /// + /// \brief Check whether an undirected graph is acyclic. + /// + /// This function checks whether the given undirected graph is acyclic. + /// \return \c true if there is no cycle in the graph. + /// \see dag() + template + bool acyclic(const Graph& graph) { + checkConcept(); + typedef typename Graph::Node Node; + typedef typename Graph::NodeIt NodeIt; + typedef typename Graph::Arc Arc; + Dfs dfs(graph); + dfs.init(); + for (NodeIt it(graph); it != INVALID; ++it) { + if (!dfs.reached(it)) { + dfs.addSource(it); + while (!dfs.emptyQueue()) { + Arc arc = dfs.nextArc(); + Node source = graph.source(arc); + Node target = graph.target(arc); + if (dfs.reached(target) && + dfs.predArc(source) != graph.oppositeArc(arc)) { + return false; + } + dfs.processNextArc(); + } + } + } + return true; + } + + /// \ingroup graph_properties + /// + /// \brief Check whether an undirected graph is tree. + /// + /// This function checks whether the given undirected graph is tree. + /// \return \c true if the graph is acyclic and connected. + /// \see acyclic(), connected() + template + bool tree(const Graph& graph) { + checkConcept(); + typedef typename Graph::Node Node; + typedef typename Graph::NodeIt NodeIt; + typedef typename Graph::Arc Arc; + if (NodeIt(graph) == INVALID) return true; + Dfs dfs(graph); + dfs.init(); + dfs.addSource(NodeIt(graph)); + while (!dfs.emptyQueue()) { + Arc arc = dfs.nextArc(); + Node source = graph.source(arc); + Node target = graph.target(arc); + if (dfs.reached(target) && + dfs.predArc(source) != graph.oppositeArc(arc)) { + return false; + } + dfs.processNextArc(); + } + for (NodeIt it(graph); it != INVALID; ++it) { + if (!dfs.reached(it)) { + return false; + } + } + return true; + } + + namespace _connectivity_bits { + + template + class BipartiteVisitor : public BfsVisitor { + public: + typedef typename Digraph::Arc Arc; + typedef typename Digraph::Node Node; + + BipartiteVisitor(const Digraph& graph, bool& bipartite) + : _graph(graph), _part(graph), _bipartite(bipartite) {} + + void start(const Node& node) { + _part[node] = true; + } + void discover(const Arc& edge) { + _part.set(_graph.target(edge), !_part[_graph.source(edge)]); + } + void examine(const Arc& edge) { + _bipartite = _bipartite && + _part[_graph.target(edge)] != _part[_graph.source(edge)]; + } + + private: + + const Digraph& _graph; + typename Digraph::template NodeMap _part; + bool& _bipartite; + }; + + template + class BipartitePartitionsVisitor : public BfsVisitor { + public: + typedef typename Digraph::Arc Arc; + typedef typename Digraph::Node Node; + + BipartitePartitionsVisitor(const Digraph& graph, + PartMap& part, bool& bipartite) + : _graph(graph), _part(part), _bipartite(bipartite) {} + + void start(const Node& node) { + _part.set(node, true); + } + void discover(const Arc& edge) { + _part.set(_graph.target(edge), !_part[_graph.source(edge)]); + } + void examine(const Arc& edge) { + _bipartite = _bipartite && + _part[_graph.target(edge)] != _part[_graph.source(edge)]; + } + + private: + + const Digraph& _graph; + PartMap& _part; + bool& _bipartite; + }; + } + + /// \ingroup graph_properties + /// + /// \brief Check whether an undirected graph is bipartite. + /// + /// The function checks whether the given undirected graph is bipartite. + /// \return \c true if the graph is bipartite. + /// + /// \see bipartitePartitions() + template + bool bipartite(const Graph &graph){ + using namespace _connectivity_bits; + + checkConcept(); + + typedef typename Graph::NodeIt NodeIt; + typedef typename Graph::ArcIt ArcIt; + + bool bipartite = true; + + BipartiteVisitor + visitor(graph, bipartite); + BfsVisit > + bfs(graph, visitor); + bfs.init(); + for(NodeIt it(graph); it != INVALID; ++it) { + if(!bfs.reached(it)){ + bfs.addSource(it); + while (!bfs.emptyQueue()) { + bfs.processNextNode(); + if (!bipartite) return false; + } + } + } + return true; + } + + /// \ingroup graph_properties + /// + /// \brief Find the bipartite partitions of an undirected graph. + /// + /// This function checks whether the given undirected graph is bipartite + /// and gives back the bipartite partitions. + /// + /// \image html bipartite_partitions.png + /// \image latex bipartite_partitions.eps "Bipartite partititions" width=\textwidth + /// + /// \param graph The undirected graph. + /// \retval partMap A writable node map of \c bool (or convertible) value + /// type. The values will be set to \c true for one component and + /// \c false for the other one. + /// \return \c true if the graph is bipartite, \c false otherwise. + /// + /// \see bipartite() + template + bool bipartitePartitions(const Graph &graph, NodeMap &partMap){ + using namespace _connectivity_bits; + + checkConcept(); + checkConcept, NodeMap>(); + + typedef typename Graph::Node Node; + typedef typename Graph::NodeIt NodeIt; + typedef typename Graph::ArcIt ArcIt; + + bool bipartite = true; + + BipartitePartitionsVisitor + visitor(graph, partMap, bipartite); + BfsVisit > + bfs(graph, visitor); + bfs.init(); + for(NodeIt it(graph); it != INVALID; ++it) { + if(!bfs.reached(it)){ + bfs.addSource(it); + while (!bfs.emptyQueue()) { + bfs.processNextNode(); + if (!bipartite) return false; + } + } + } + return true; + } + + /// \ingroup graph_properties + /// + /// \brief Check whether the given graph contains no loop arcs/edges. + /// + /// This function returns \c true if there are no loop arcs/edges in + /// the given graph. It works for both directed and undirected graphs. + template + bool loopFree(const Graph& graph) { + for (typename Graph::ArcIt it(graph); it != INVALID; ++it) { + if (graph.source(it) == graph.target(it)) return false; + } + return true; + } + + /// \ingroup graph_properties + /// + /// \brief Check whether the given graph contains no parallel arcs/edges. + /// + /// This function returns \c true if there are no parallel arcs/edges in + /// the given graph. It works for both directed and undirected graphs. + template + bool parallelFree(const Graph& graph) { + typename Graph::template NodeMap reached(graph, 0); + int cnt = 1; + for (typename Graph::NodeIt n(graph); n != INVALID; ++n) { + for (typename Graph::OutArcIt a(graph, n); a != INVALID; ++a) { + if (reached[graph.target(a)] == cnt) return false; + reached[graph.target(a)] = cnt; + } + ++cnt; + } + return true; + } + + /// \ingroup graph_properties + /// + /// \brief Check whether the given graph is simple. + /// + /// This function returns \c true if the given graph is simple, i.e. + /// it contains no loop arcs/edges and no parallel arcs/edges. + /// The function works for both directed and undirected graphs. + /// \see loopFree(), parallelFree() + template + bool simpleGraph(const Graph& graph) { + typename Graph::template NodeMap reached(graph, 0); + int cnt = 1; + for (typename Graph::NodeIt n(graph); n != INVALID; ++n) { + reached[n] = cnt; + for (typename Graph::OutArcIt a(graph, n); a != INVALID; ++a) { + if (reached[graph.target(a)] == cnt) return false; + reached[graph.target(a)] = cnt; + } + ++cnt; + } + return true; + } + +} //namespace lemon + +#endif //LEMON_CONNECTIVITY_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/core.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/core.h new file mode 100644 index 00000000000..507943db1c3 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/core.h @@ -0,0 +1,2506 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_CORE_H +#define LEMON_CORE_H + +#include +#include + +#include +#include +#include +#include + +// Disable the following warnings when compiling with MSVC: +// C4250: 'class1' : inherits 'class2::member' via dominance +// C4355: 'this' : used in base member initializer list +// C4503: 'function' : decorated name length exceeded, name was truncated +// C4800: 'type' : forcing value to bool 'true' or 'false' (performance warning) +// C4996: 'function': was declared deprecated +#ifdef _MSC_VER +#pragma warning( disable : 4250 4355 4503 4800 4996 ) +#endif + +#ifdef __GNUC__ +#define GCC_VERSION (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__) +#endif + +#if GCC_VERSION >= 40800 +// Needed by the [DI]GRAPH_TYPEDEFS marcos for gcc 4.8 +#pragma GCC diagnostic ignored "-Wunused-local-typedefs" +#endif + +///\file +///\brief LEMON core utilities. +/// +///This header file contains core utilities for LEMON. +///It is automatically included by all graph types, therefore it usually +///do not have to be included directly. + +namespace lemon { + + /// \brief Dummy type to make it easier to create invalid iterators. + /// + /// Dummy type to make it easier to create invalid iterators. + /// See \ref INVALID for the usage. + struct Invalid { + public: + bool operator==(Invalid) { return true; } + bool operator!=(Invalid) { return false; } + bool operator< (Invalid) { return false; } + }; + + /// \brief Invalid iterators. + /// + /// \ref Invalid is a global type that converts to each iterator + /// in such a way that the value of the target iterator will be invalid. +#ifdef LEMON_ONLY_TEMPLATES + const Invalid INVALID = Invalid(); +#else + extern const Invalid INVALID; +#endif + + /// \addtogroup gutils + /// @{ + + ///Create convenience typedefs for the digraph types and iterators + + ///This \c \#define creates convenient type definitions for the following + ///types of \c Digraph: \c Node, \c NodeIt, \c Arc, \c ArcIt, \c InArcIt, + ///\c OutArcIt, \c BoolNodeMap, \c IntNodeMap, \c DoubleNodeMap, + ///\c BoolArcMap, \c IntArcMap, \c DoubleArcMap. + /// + ///\note If the graph type is a dependent type, ie. the graph type depend + ///on a template parameter, then use \c TEMPLATE_DIGRAPH_TYPEDEFS() + ///macro. +#define DIGRAPH_TYPEDEFS(Digraph) \ + typedef Digraph::Node Node; \ + typedef Digraph::NodeIt NodeIt; \ + typedef Digraph::Arc Arc; \ + typedef Digraph::ArcIt ArcIt; \ + typedef Digraph::InArcIt InArcIt; \ + typedef Digraph::OutArcIt OutArcIt; \ + typedef Digraph::NodeMap BoolNodeMap; \ + typedef Digraph::NodeMap IntNodeMap; \ + typedef Digraph::NodeMap DoubleNodeMap; \ + typedef Digraph::ArcMap BoolArcMap; \ + typedef Digraph::ArcMap IntArcMap; \ + typedef Digraph::ArcMap DoubleArcMap + + ///Create convenience typedefs for the digraph types and iterators + + ///\see DIGRAPH_TYPEDEFS + /// + ///\note Use this macro, if the graph type is a dependent type, + ///ie. the graph type depend on a template parameter. +#define TEMPLATE_DIGRAPH_TYPEDEFS(Digraph) \ + typedef typename Digraph::Node Node; \ + typedef typename Digraph::NodeIt NodeIt; \ + typedef typename Digraph::Arc Arc; \ + typedef typename Digraph::ArcIt ArcIt; \ + typedef typename Digraph::InArcIt InArcIt; \ + typedef typename Digraph::OutArcIt OutArcIt; \ + typedef typename Digraph::template NodeMap BoolNodeMap; \ + typedef typename Digraph::template NodeMap IntNodeMap; \ + typedef typename Digraph::template NodeMap DoubleNodeMap; \ + typedef typename Digraph::template ArcMap BoolArcMap; \ + typedef typename Digraph::template ArcMap IntArcMap; \ + typedef typename Digraph::template ArcMap DoubleArcMap + + ///Create convenience typedefs for the graph types and iterators + + ///This \c \#define creates the same convenient type definitions as defined + ///by \ref DIGRAPH_TYPEDEFS(Graph) and six more, namely it creates + ///\c Edge, \c EdgeIt, \c IncEdgeIt, \c BoolEdgeMap, \c IntEdgeMap, + ///\c DoubleEdgeMap. + /// + ///\note If the graph type is a dependent type, ie. the graph type depend + ///on a template parameter, then use \c TEMPLATE_GRAPH_TYPEDEFS() + ///macro. +#define GRAPH_TYPEDEFS(Graph) \ + DIGRAPH_TYPEDEFS(Graph); \ + typedef Graph::Edge Edge; \ + typedef Graph::EdgeIt EdgeIt; \ + typedef Graph::IncEdgeIt IncEdgeIt; \ + typedef Graph::EdgeMap BoolEdgeMap; \ + typedef Graph::EdgeMap IntEdgeMap; \ + typedef Graph::EdgeMap DoubleEdgeMap + + ///Create convenience typedefs for the graph types and iterators + + ///\see GRAPH_TYPEDEFS + /// + ///\note Use this macro, if the graph type is a dependent type, + ///ie. the graph type depend on a template parameter. +#define TEMPLATE_GRAPH_TYPEDEFS(Graph) \ + TEMPLATE_DIGRAPH_TYPEDEFS(Graph); \ + typedef typename Graph::Edge Edge; \ + typedef typename Graph::EdgeIt EdgeIt; \ + typedef typename Graph::IncEdgeIt IncEdgeIt; \ + typedef typename Graph::template EdgeMap BoolEdgeMap; \ + typedef typename Graph::template EdgeMap IntEdgeMap; \ + typedef typename Graph::template EdgeMap DoubleEdgeMap + + ///Create convenience typedefs for the bipartite graph types and iterators + + ///This \c \#define creates the same convenient type definitions as + ///defined by \ref GRAPH_TYPEDEFS(BpGraph) and ten more, namely it + ///creates \c RedNode, \c RedNodeIt, \c BoolRedNodeMap, + ///\c IntRedNodeMap, \c DoubleRedNodeMap, \c BlueNode, \c BlueNodeIt, + ///\c BoolBlueNodeMap, \c IntBlueNodeMap, \c DoubleBlueNodeMap. + /// + ///\note If the graph type is a dependent type, ie. the graph type depend + ///on a template parameter, then use \c TEMPLATE_BPGRAPH_TYPEDEFS() + ///macro. +#define BPGRAPH_TYPEDEFS(BpGraph) \ + GRAPH_TYPEDEFS(BpGraph); \ + typedef BpGraph::RedNode RedNode; \ + typedef BpGraph::RedNodeIt RedNodeIt; \ + typedef BpGraph::RedNodeMap BoolRedNodeMap; \ + typedef BpGraph::RedNodeMap IntRedNodeMap; \ + typedef BpGraph::RedNodeMap DoubleRedNodeMap; \ + typedef BpGraph::BlueNode BlueNode; \ + typedef BpGraph::BlueNodeIt BlueNodeIt; \ + typedef BpGraph::BlueNodeMap BoolBlueNodeMap; \ + typedef BpGraph::BlueNodeMap IntBlueNodeMap; \ + typedef BpGraph::BlueNodeMap DoubleBlueNodeMap + + ///Create convenience typedefs for the bipartite graph types and iterators + + ///\see BPGRAPH_TYPEDEFS + /// + ///\note Use this macro, if the graph type is a dependent type, + ///ie. the graph type depend on a template parameter. +#define TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph) \ + TEMPLATE_GRAPH_TYPEDEFS(BpGraph); \ + typedef typename BpGraph::RedNode RedNode; \ + typedef typename BpGraph::RedNodeIt RedNodeIt; \ + typedef typename BpGraph::template RedNodeMap BoolRedNodeMap; \ + typedef typename BpGraph::template RedNodeMap IntRedNodeMap; \ + typedef typename BpGraph::template RedNodeMap DoubleRedNodeMap; \ + typedef typename BpGraph::BlueNode BlueNode; \ + typedef typename BpGraph::BlueNodeIt BlueNodeIt; \ + typedef typename BpGraph::template BlueNodeMap BoolBlueNodeMap; \ + typedef typename BpGraph::template BlueNodeMap IntBlueNodeMap; \ + typedef typename BpGraph::template BlueNodeMap DoubleBlueNodeMap + + /// \brief Function to count the items in a graph. + /// + /// This function counts the items (nodes, arcs etc.) in a graph. + /// The complexity of the function is linear because + /// it iterates on all of the items. + template + inline int countItems(const Graph& g) { + typedef typename ItemSetTraits::ItemIt ItemIt; + int num = 0; + for (ItemIt it(g); it != INVALID; ++it) { + ++num; + } + return num; + } + + // Node counting: + + namespace _core_bits { + + template + struct CountNodesSelector { + static int count(const Graph &g) { + return countItems(g); + } + }; + + template + struct CountNodesSelector< + Graph, typename + enable_if::type> + { + static int count(const Graph &g) { + return g.nodeNum(); + } + }; + } + + /// \brief Function to count the nodes in the graph. + /// + /// This function counts the nodes in the graph. + /// The complexity of the function is O(n), but for some + /// graph structures it is specialized to run in O(1). + /// + /// \note If the graph contains a \c nodeNum() member function and a + /// \c NodeNumTag tag then this function calls directly the member + /// function to query the cardinality of the node set. + template + inline int countNodes(const Graph& g) { + return _core_bits::CountNodesSelector::count(g); + } + + namespace _graph_utils_bits { + + template + struct CountRedNodesSelector { + static int count(const Graph &g) { + return countItems(g); + } + }; + + template + struct CountRedNodesSelector< + Graph, typename + enable_if::type> + { + static int count(const Graph &g) { + return g.redNum(); + } + }; + } + + /// \brief Function to count the red nodes in the graph. + /// + /// This function counts the red nodes in the graph. + /// The complexity of the function is O(n) but for some + /// graph structures it is specialized to run in O(1). + /// + /// If the graph contains a \e redNum() member function and a + /// \e NodeNumTag tag then this function calls directly the member + /// function to query the cardinality of the node set. + template + inline int countRedNodes(const Graph& g) { + return _graph_utils_bits::CountRedNodesSelector::count(g); + } + + namespace _graph_utils_bits { + + template + struct CountBlueNodesSelector { + static int count(const Graph &g) { + return countItems(g); + } + }; + + template + struct CountBlueNodesSelector< + Graph, typename + enable_if::type> + { + static int count(const Graph &g) { + return g.blueNum(); + } + }; + } + + /// \brief Function to count the blue nodes in the graph. + /// + /// This function counts the blue nodes in the graph. + /// The complexity of the function is O(n) but for some + /// graph structures it is specialized to run in O(1). + /// + /// If the graph contains a \e blueNum() member function and a + /// \e NodeNumTag tag then this function calls directly the member + /// function to query the cardinality of the node set. + template + inline int countBlueNodes(const Graph& g) { + return _graph_utils_bits::CountBlueNodesSelector::count(g); + } + + // Arc counting: + + namespace _core_bits { + + template + struct CountArcsSelector { + static int count(const Graph &g) { + return countItems(g); + } + }; + + template + struct CountArcsSelector< + Graph, + typename enable_if::type> + { + static int count(const Graph &g) { + return g.arcNum(); + } + }; + } + + /// \brief Function to count the arcs in the graph. + /// + /// This function counts the arcs in the graph. + /// The complexity of the function is O(m), but for some + /// graph structures it is specialized to run in O(1). + /// + /// \note If the graph contains a \c arcNum() member function and a + /// \c ArcNumTag tag then this function calls directly the member + /// function to query the cardinality of the arc set. + template + inline int countArcs(const Graph& g) { + return _core_bits::CountArcsSelector::count(g); + } + + // Edge counting: + + namespace _core_bits { + + template + struct CountEdgesSelector { + static int count(const Graph &g) { + return countItems(g); + } + }; + + template + struct CountEdgesSelector< + Graph, + typename enable_if::type> + { + static int count(const Graph &g) { + return g.edgeNum(); + } + }; + } + + /// \brief Function to count the edges in the graph. + /// + /// This function counts the edges in the graph. + /// The complexity of the function is O(m), but for some + /// graph structures it is specialized to run in O(1). + /// + /// \note If the graph contains a \c edgeNum() member function and a + /// \c EdgeNumTag tag then this function calls directly the member + /// function to query the cardinality of the edge set. + template + inline int countEdges(const Graph& g) { + return _core_bits::CountEdgesSelector::count(g); + + } + + + template + inline int countNodeDegree(const Graph& _g, const typename Graph::Node& _n) { + int num = 0; + for (DegIt it(_g, _n); it != INVALID; ++it) { + ++num; + } + return num; + } + + /// \brief Function to count the number of the out-arcs from node \c n. + /// + /// This function counts the number of the out-arcs from node \c n + /// in the graph \c g. + template + inline int countOutArcs(const Graph& g, const typename Graph::Node& n) { + return countNodeDegree(g, n); + } + + /// \brief Function to count the number of the in-arcs to node \c n. + /// + /// This function counts the number of the in-arcs to node \c n + /// in the graph \c g. + template + inline int countInArcs(const Graph& g, const typename Graph::Node& n) { + return countNodeDegree(g, n); + } + + /// \brief Function to count the number of the inc-edges to node \c n. + /// + /// This function counts the number of the inc-edges to node \c n + /// in the undirected graph \c g. + template + inline int countIncEdges(const Graph& g, const typename Graph::Node& n) { + return countNodeDegree(g, n); + } + + namespace _core_bits { + + template + class MapCopyBase { + public: + virtual void copy(const Digraph& from, const RefMap& refMap) = 0; + + virtual ~MapCopyBase() {} + }; + + template + class MapCopy : public MapCopyBase { + public: + + MapCopy(const FromMap& map, ToMap& tmap) + : _map(map), _tmap(tmap) {} + + virtual void copy(const Digraph& digraph, const RefMap& refMap) { + typedef typename ItemSetTraits::ItemIt ItemIt; + for (ItemIt it(digraph); it != INVALID; ++it) { + _tmap.set(refMap[it], _map[it]); + } + } + + private: + const FromMap& _map; + ToMap& _tmap; + }; + + template + class ItemCopy : public MapCopyBase { + public: + + ItemCopy(const Item& item, It& it) : _item(item), _it(it) {} + + virtual void copy(const Digraph&, const RefMap& refMap) { + _it = refMap[_item]; + } + + private: + Item _item; + It& _it; + }; + + template + class RefCopy : public MapCopyBase { + public: + + RefCopy(Ref& map) : _map(map) {} + + virtual void copy(const Digraph& digraph, const RefMap& refMap) { + typedef typename ItemSetTraits::ItemIt ItemIt; + for (ItemIt it(digraph); it != INVALID; ++it) { + _map.set(it, refMap[it]); + } + } + + private: + Ref& _map; + }; + + template + class CrossRefCopy : public MapCopyBase { + public: + + CrossRefCopy(CrossRef& cmap) : _cmap(cmap) {} + + virtual void copy(const Digraph& digraph, const RefMap& refMap) { + typedef typename ItemSetTraits::ItemIt ItemIt; + for (ItemIt it(digraph); it != INVALID; ++it) { + _cmap.set(refMap[it], it); + } + } + + private: + CrossRef& _cmap; + }; + + template + struct DigraphCopySelector { + template + static void copy(const From& from, Digraph &to, + NodeRefMap& nodeRefMap, ArcRefMap& arcRefMap) { + to.clear(); + for (typename From::NodeIt it(from); it != INVALID; ++it) { + nodeRefMap[it] = to.addNode(); + } + for (typename From::ArcIt it(from); it != INVALID; ++it) { + arcRefMap[it] = to.addArc(nodeRefMap[from.source(it)], + nodeRefMap[from.target(it)]); + } + } + }; + + template + struct DigraphCopySelector< + Digraph, + typename enable_if::type> + { + template + static void copy(const From& from, Digraph &to, + NodeRefMap& nodeRefMap, ArcRefMap& arcRefMap) { + to.build(from, nodeRefMap, arcRefMap); + } + }; + + template + struct GraphCopySelector { + template + static void copy(const From& from, Graph &to, + NodeRefMap& nodeRefMap, EdgeRefMap& edgeRefMap) { + to.clear(); + for (typename From::NodeIt it(from); it != INVALID; ++it) { + nodeRefMap[it] = to.addNode(); + } + for (typename From::EdgeIt it(from); it != INVALID; ++it) { + edgeRefMap[it] = to.addEdge(nodeRefMap[from.u(it)], + nodeRefMap[from.v(it)]); + } + } + }; + + template + struct GraphCopySelector< + Graph, + typename enable_if::type> + { + template + static void copy(const From& from, Graph &to, + NodeRefMap& nodeRefMap, + EdgeRefMap& edgeRefMap) { + to.build(from, nodeRefMap, edgeRefMap); + } + }; + + template + struct BpGraphCopySelector { + template + static void copy(const From& from, BpGraph &to, + RedNodeRefMap& redNodeRefMap, + BlueNodeRefMap& blueNodeRefMap, + EdgeRefMap& edgeRefMap) { + to.clear(); + for (typename From::RedNodeIt it(from); it != INVALID; ++it) { + redNodeRefMap[it] = to.addRedNode(); + } + for (typename From::BlueNodeIt it(from); it != INVALID; ++it) { + blueNodeRefMap[it] = to.addBlueNode(); + } + for (typename From::EdgeIt it(from); it != INVALID; ++it) { + edgeRefMap[it] = to.addEdge(redNodeRefMap[from.redNode(it)], + blueNodeRefMap[from.blueNode(it)]); + } + } + }; + + template + struct BpGraphCopySelector< + BpGraph, + typename enable_if::type> + { + template + static void copy(const From& from, BpGraph &to, + RedNodeRefMap& redNodeRefMap, + BlueNodeRefMap& blueNodeRefMap, + EdgeRefMap& edgeRefMap) { + to.build(from, redNodeRefMap, blueNodeRefMap, edgeRefMap); + } + }; + + } + + /// \brief Check whether a graph is undirected. + /// + /// This function returns \c true if the given graph is undirected. +#ifdef DOXYGEN + template + bool undirected(const GR& g) { return false; } +#else + template + typename enable_if, bool>::type + undirected(const GR&) { + return true; + } + template + typename disable_if, bool>::type + undirected(const GR&) { + return false; + } +#endif + + /// \brief Class to copy a digraph. + /// + /// Class to copy a digraph to another digraph (duplicate a digraph). The + /// simplest way of using it is through the \c digraphCopy() function. + /// + /// This class not only make a copy of a digraph, but it can create + /// references and cross references between the nodes and arcs of + /// the two digraphs, and it can copy maps to use with the newly created + /// digraph. + /// + /// To make a copy from a digraph, first an instance of DigraphCopy + /// should be created, then the data belongs to the digraph should + /// assigned to copy. In the end, the \c run() member should be + /// called. + /// + /// The next code copies a digraph with several data: + ///\code + /// DigraphCopy cg(orig_graph, new_graph); + /// // Create references for the nodes + /// OrigGraph::NodeMap nr(orig_graph); + /// cg.nodeRef(nr); + /// // Create cross references (inverse) for the arcs + /// NewGraph::ArcMap acr(new_graph); + /// cg.arcCrossRef(acr); + /// // Copy an arc map + /// OrigGraph::ArcMap oamap(orig_graph); + /// NewGraph::ArcMap namap(new_graph); + /// cg.arcMap(oamap, namap); + /// // Copy a node + /// OrigGraph::Node on; + /// NewGraph::Node nn; + /// cg.node(on, nn); + /// // Execute copying + /// cg.run(); + ///\endcode + template + class DigraphCopy { + private: + + typedef typename From::Node Node; + typedef typename From::NodeIt NodeIt; + typedef typename From::Arc Arc; + typedef typename From::ArcIt ArcIt; + + typedef typename To::Node TNode; + typedef typename To::Arc TArc; + + typedef typename From::template NodeMap NodeRefMap; + typedef typename From::template ArcMap ArcRefMap; + + public: + + /// \brief Constructor of DigraphCopy. + /// + /// Constructor of DigraphCopy for copying the content of the + /// \c from digraph into the \c to digraph. + DigraphCopy(const From& from, To& to) + : _from(from), _to(to) {} + + /// \brief Destructor of DigraphCopy + /// + /// Destructor of DigraphCopy. + ~DigraphCopy() { + for (int i = 0; i < int(_node_maps.size()); ++i) { + delete _node_maps[i]; + } + for (int i = 0; i < int(_arc_maps.size()); ++i) { + delete _arc_maps[i]; + } + + } + + /// \brief Copy the node references into the given map. + /// + /// This function copies the node references into the given map. + /// The parameter should be a map, whose key type is the Node type of + /// the source digraph, while the value type is the Node type of the + /// destination digraph. + template + DigraphCopy& nodeRef(NodeRef& map) { + _node_maps.push_back(new _core_bits::RefCopy(map)); + return *this; + } + + /// \brief Copy the node cross references into the given map. + /// + /// This function copies the node cross references (reverse references) + /// into the given map. The parameter should be a map, whose key type + /// is the Node type of the destination digraph, while the value type is + /// the Node type of the source digraph. + template + DigraphCopy& nodeCrossRef(NodeCrossRef& map) { + _node_maps.push_back(new _core_bits::CrossRefCopy(map)); + return *this; + } + + /// \brief Make a copy of the given node map. + /// + /// This function makes a copy of the given node map for the newly + /// created digraph. + /// The key type of the new map \c tmap should be the Node type of the + /// destination digraph, and the key type of the original map \c map + /// should be the Node type of the source digraph. + template + DigraphCopy& nodeMap(const FromMap& map, ToMap& tmap) { + _node_maps.push_back(new _core_bits::MapCopy(map, tmap)); + return *this; + } + + /// \brief Make a copy of the given node. + /// + /// This function makes a copy of the given node. + DigraphCopy& node(const Node& node, TNode& tnode) { + _node_maps.push_back(new _core_bits::ItemCopy(node, tnode)); + return *this; + } + + /// \brief Copy the arc references into the given map. + /// + /// This function copies the arc references into the given map. + /// The parameter should be a map, whose key type is the Arc type of + /// the source digraph, while the value type is the Arc type of the + /// destination digraph. + template + DigraphCopy& arcRef(ArcRef& map) { + _arc_maps.push_back(new _core_bits::RefCopy(map)); + return *this; + } + + /// \brief Copy the arc cross references into the given map. + /// + /// This function copies the arc cross references (reverse references) + /// into the given map. The parameter should be a map, whose key type + /// is the Arc type of the destination digraph, while the value type is + /// the Arc type of the source digraph. + template + DigraphCopy& arcCrossRef(ArcCrossRef& map) { + _arc_maps.push_back(new _core_bits::CrossRefCopy(map)); + return *this; + } + + /// \brief Make a copy of the given arc map. + /// + /// This function makes a copy of the given arc map for the newly + /// created digraph. + /// The key type of the new map \c tmap should be the Arc type of the + /// destination digraph, and the key type of the original map \c map + /// should be the Arc type of the source digraph. + template + DigraphCopy& arcMap(const FromMap& map, ToMap& tmap) { + _arc_maps.push_back(new _core_bits::MapCopy(map, tmap)); + return *this; + } + + /// \brief Make a copy of the given arc. + /// + /// This function makes a copy of the given arc. + DigraphCopy& arc(const Arc& arc, TArc& tarc) { + _arc_maps.push_back(new _core_bits::ItemCopy(arc, tarc)); + return *this; + } + + /// \brief Execute copying. + /// + /// This function executes the copying of the digraph along with the + /// copying of the assigned data. + void run() { + NodeRefMap nodeRefMap(_from); + ArcRefMap arcRefMap(_from); + _core_bits::DigraphCopySelector:: + copy(_from, _to, nodeRefMap, arcRefMap); + for (int i = 0; i < int(_node_maps.size()); ++i) { + _node_maps[i]->copy(_from, nodeRefMap); + } + for (int i = 0; i < int(_arc_maps.size()); ++i) { + _arc_maps[i]->copy(_from, arcRefMap); + } + } + + protected: + + const From& _from; + To& _to; + + std::vector<_core_bits::MapCopyBase* > + _node_maps; + + std::vector<_core_bits::MapCopyBase* > + _arc_maps; + + }; + + /// \brief Copy a digraph to another digraph. + /// + /// This function copies a digraph to another digraph. + /// The complete usage of it is detailed in the DigraphCopy class, but + /// a short example shows a basic work: + ///\code + /// digraphCopy(src, trg).nodeRef(nr).arcCrossRef(acr).run(); + ///\endcode + /// + /// After the copy the \c nr map will contain the mapping from the + /// nodes of the \c from digraph to the nodes of the \c to digraph and + /// \c acr will contain the mapping from the arcs of the \c to digraph + /// to the arcs of the \c from digraph. + /// + /// \see DigraphCopy + template + DigraphCopy digraphCopy(const From& from, To& to) { + return DigraphCopy(from, to); + } + + /// \brief Class to copy a graph. + /// + /// Class to copy a graph to another graph (duplicate a graph). The + /// simplest way of using it is through the \c graphCopy() function. + /// + /// This class not only make a copy of a graph, but it can create + /// references and cross references between the nodes, edges and arcs of + /// the two graphs, and it can copy maps for using with the newly created + /// graph. + /// + /// To make a copy from a graph, first an instance of GraphCopy + /// should be created, then the data belongs to the graph should + /// assigned to copy. In the end, the \c run() member should be + /// called. + /// + /// The next code copies a graph with several data: + ///\code + /// GraphCopy cg(orig_graph, new_graph); + /// // Create references for the nodes + /// OrigGraph::NodeMap nr(orig_graph); + /// cg.nodeRef(nr); + /// // Create cross references (inverse) for the edges + /// NewGraph::EdgeMap ecr(new_graph); + /// cg.edgeCrossRef(ecr); + /// // Copy an edge map + /// OrigGraph::EdgeMap oemap(orig_graph); + /// NewGraph::EdgeMap nemap(new_graph); + /// cg.edgeMap(oemap, nemap); + /// // Copy a node + /// OrigGraph::Node on; + /// NewGraph::Node nn; + /// cg.node(on, nn); + /// // Execute copying + /// cg.run(); + ///\endcode + template + class GraphCopy { + private: + + typedef typename From::Node Node; + typedef typename From::NodeIt NodeIt; + typedef typename From::Arc Arc; + typedef typename From::ArcIt ArcIt; + typedef typename From::Edge Edge; + typedef typename From::EdgeIt EdgeIt; + + typedef typename To::Node TNode; + typedef typename To::Arc TArc; + typedef typename To::Edge TEdge; + + typedef typename From::template NodeMap NodeRefMap; + typedef typename From::template EdgeMap EdgeRefMap; + + struct ArcRefMap { + ArcRefMap(const From& from, const To& to, + const EdgeRefMap& edge_ref, const NodeRefMap& node_ref) + : _from(from), _to(to), + _edge_ref(edge_ref), _node_ref(node_ref) {} + + typedef typename From::Arc Key; + typedef typename To::Arc Value; + + Value operator[](const Key& key) const { + bool forward = _from.u(key) != _from.v(key) ? + _node_ref[_from.source(key)] == + _to.source(_to.direct(_edge_ref[key], true)) : + _from.direction(key); + return _to.direct(_edge_ref[key], forward); + } + + const From& _from; + const To& _to; + const EdgeRefMap& _edge_ref; + const NodeRefMap& _node_ref; + }; + + public: + + /// \brief Constructor of GraphCopy. + /// + /// Constructor of GraphCopy for copying the content of the + /// \c from graph into the \c to graph. + GraphCopy(const From& from, To& to) + : _from(from), _to(to) {} + + /// \brief Destructor of GraphCopy + /// + /// Destructor of GraphCopy. + ~GraphCopy() { + for (int i = 0; i < int(_node_maps.size()); ++i) { + delete _node_maps[i]; + } + for (int i = 0; i < int(_arc_maps.size()); ++i) { + delete _arc_maps[i]; + } + for (int i = 0; i < int(_edge_maps.size()); ++i) { + delete _edge_maps[i]; + } + } + + /// \brief Copy the node references into the given map. + /// + /// This function copies the node references into the given map. + /// The parameter should be a map, whose key type is the Node type of + /// the source graph, while the value type is the Node type of the + /// destination graph. + template + GraphCopy& nodeRef(NodeRef& map) { + _node_maps.push_back(new _core_bits::RefCopy(map)); + return *this; + } + + /// \brief Copy the node cross references into the given map. + /// + /// This function copies the node cross references (reverse references) + /// into the given map. The parameter should be a map, whose key type + /// is the Node type of the destination graph, while the value type is + /// the Node type of the source graph. + template + GraphCopy& nodeCrossRef(NodeCrossRef& map) { + _node_maps.push_back(new _core_bits::CrossRefCopy(map)); + return *this; + } + + /// \brief Make a copy of the given node map. + /// + /// This function makes a copy of the given node map for the newly + /// created graph. + /// The key type of the new map \c tmap should be the Node type of the + /// destination graph, and the key type of the original map \c map + /// should be the Node type of the source graph. + template + GraphCopy& nodeMap(const FromMap& map, ToMap& tmap) { + _node_maps.push_back(new _core_bits::MapCopy(map, tmap)); + return *this; + } + + /// \brief Make a copy of the given node. + /// + /// This function makes a copy of the given node. + GraphCopy& node(const Node& node, TNode& tnode) { + _node_maps.push_back(new _core_bits::ItemCopy(node, tnode)); + return *this; + } + + /// \brief Copy the arc references into the given map. + /// + /// This function copies the arc references into the given map. + /// The parameter should be a map, whose key type is the Arc type of + /// the source graph, while the value type is the Arc type of the + /// destination graph. + template + GraphCopy& arcRef(ArcRef& map) { + _arc_maps.push_back(new _core_bits::RefCopy(map)); + return *this; + } + + /// \brief Copy the arc cross references into the given map. + /// + /// This function copies the arc cross references (reverse references) + /// into the given map. The parameter should be a map, whose key type + /// is the Arc type of the destination graph, while the value type is + /// the Arc type of the source graph. + template + GraphCopy& arcCrossRef(ArcCrossRef& map) { + _arc_maps.push_back(new _core_bits::CrossRefCopy(map)); + return *this; + } + + /// \brief Make a copy of the given arc map. + /// + /// This function makes a copy of the given arc map for the newly + /// created graph. + /// The key type of the new map \c tmap should be the Arc type of the + /// destination graph, and the key type of the original map \c map + /// should be the Arc type of the source graph. + template + GraphCopy& arcMap(const FromMap& map, ToMap& tmap) { + _arc_maps.push_back(new _core_bits::MapCopy(map, tmap)); + return *this; + } + + /// \brief Make a copy of the given arc. + /// + /// This function makes a copy of the given arc. + GraphCopy& arc(const Arc& arc, TArc& tarc) { + _arc_maps.push_back(new _core_bits::ItemCopy(arc, tarc)); + return *this; + } + + /// \brief Copy the edge references into the given map. + /// + /// This function copies the edge references into the given map. + /// The parameter should be a map, whose key type is the Edge type of + /// the source graph, while the value type is the Edge type of the + /// destination graph. + template + GraphCopy& edgeRef(EdgeRef& map) { + _edge_maps.push_back(new _core_bits::RefCopy(map)); + return *this; + } + + /// \brief Copy the edge cross references into the given map. + /// + /// This function copies the edge cross references (reverse references) + /// into the given map. The parameter should be a map, whose key type + /// is the Edge type of the destination graph, while the value type is + /// the Edge type of the source graph. + template + GraphCopy& edgeCrossRef(EdgeCrossRef& map) { + _edge_maps.push_back(new _core_bits::CrossRefCopy(map)); + return *this; + } + + /// \brief Make a copy of the given edge map. + /// + /// This function makes a copy of the given edge map for the newly + /// created graph. + /// The key type of the new map \c tmap should be the Edge type of the + /// destination graph, and the key type of the original map \c map + /// should be the Edge type of the source graph. + template + GraphCopy& edgeMap(const FromMap& map, ToMap& tmap) { + _edge_maps.push_back(new _core_bits::MapCopy(map, tmap)); + return *this; + } + + /// \brief Make a copy of the given edge. + /// + /// This function makes a copy of the given edge. + GraphCopy& edge(const Edge& edge, TEdge& tedge) { + _edge_maps.push_back(new _core_bits::ItemCopy(edge, tedge)); + return *this; + } + + /// \brief Execute copying. + /// + /// This function executes the copying of the graph along with the + /// copying of the assigned data. + void run() { + NodeRefMap nodeRefMap(_from); + EdgeRefMap edgeRefMap(_from); + ArcRefMap arcRefMap(_from, _to, edgeRefMap, nodeRefMap); + _core_bits::GraphCopySelector:: + copy(_from, _to, nodeRefMap, edgeRefMap); + for (int i = 0; i < int(_node_maps.size()); ++i) { + _node_maps[i]->copy(_from, nodeRefMap); + } + for (int i = 0; i < int(_edge_maps.size()); ++i) { + _edge_maps[i]->copy(_from, edgeRefMap); + } + for (int i = 0; i < int(_arc_maps.size()); ++i) { + _arc_maps[i]->copy(_from, arcRefMap); + } + } + + private: + + const From& _from; + To& _to; + + std::vector<_core_bits::MapCopyBase* > + _node_maps; + + std::vector<_core_bits::MapCopyBase* > + _arc_maps; + + std::vector<_core_bits::MapCopyBase* > + _edge_maps; + + }; + + /// \brief Copy a graph to another graph. + /// + /// This function copies a graph to another graph. + /// The complete usage of it is detailed in the GraphCopy class, + /// but a short example shows a basic work: + ///\code + /// graphCopy(src, trg).nodeRef(nr).edgeCrossRef(ecr).run(); + ///\endcode + /// + /// After the copy the \c nr map will contain the mapping from the + /// nodes of the \c from graph to the nodes of the \c to graph and + /// \c ecr will contain the mapping from the edges of the \c to graph + /// to the edges of the \c from graph. + /// + /// \see GraphCopy + template + GraphCopy + graphCopy(const From& from, To& to) { + return GraphCopy(from, to); + } + + /// \brief Class to copy a bipartite graph. + /// + /// Class to copy a bipartite graph to another graph (duplicate a + /// graph). The simplest way of using it is through the + /// \c bpGraphCopy() function. + /// + /// This class not only make a copy of a bipartite graph, but it can + /// create references and cross references between the nodes, edges + /// and arcs of the two graphs, and it can copy maps for using with + /// the newly created graph. + /// + /// To make a copy from a graph, first an instance of BpGraphCopy + /// should be created, then the data belongs to the graph should + /// assigned to copy. In the end, the \c run() member should be + /// called. + /// + /// The next code copies a graph with several data: + ///\code + /// BpGraphCopy cg(orig_graph, new_graph); + /// // Create references for the nodes + /// OrigBpGraph::NodeMap nr(orig_graph); + /// cg.nodeRef(nr); + /// // Create cross references (inverse) for the edges + /// NewBpGraph::EdgeMap ecr(new_graph); + /// cg.edgeCrossRef(ecr); + /// // Copy a red node map + /// OrigBpGraph::RedNodeMap ormap(orig_graph); + /// NewBpGraph::RedNodeMap nrmap(new_graph); + /// cg.redNodeMap(ormap, nrmap); + /// // Copy a node + /// OrigBpGraph::Node on; + /// NewBpGraph::Node nn; + /// cg.node(on, nn); + /// // Execute copying + /// cg.run(); + ///\endcode + template + class BpGraphCopy { + private: + + typedef typename From::Node Node; + typedef typename From::RedNode RedNode; + typedef typename From::BlueNode BlueNode; + typedef typename From::NodeIt NodeIt; + typedef typename From::Arc Arc; + typedef typename From::ArcIt ArcIt; + typedef typename From::Edge Edge; + typedef typename From::EdgeIt EdgeIt; + + typedef typename To::Node TNode; + typedef typename To::RedNode TRedNode; + typedef typename To::BlueNode TBlueNode; + typedef typename To::Arc TArc; + typedef typename To::Edge TEdge; + + typedef typename From::template RedNodeMap RedNodeRefMap; + typedef typename From::template BlueNodeMap BlueNodeRefMap; + typedef typename From::template EdgeMap EdgeRefMap; + + struct NodeRefMap { + NodeRefMap(const From& from, const RedNodeRefMap& red_node_ref, + const BlueNodeRefMap& blue_node_ref) + : _from(from), _red_node_ref(red_node_ref), + _blue_node_ref(blue_node_ref) {} + + typedef typename From::Node Key; + typedef typename To::Node Value; + + Value operator[](const Key& key) const { + if (_from.red(key)) { + return _red_node_ref[_from.asRedNodeUnsafe(key)]; + } else { + return _blue_node_ref[_from.asBlueNodeUnsafe(key)]; + } + } + + const From& _from; + const RedNodeRefMap& _red_node_ref; + const BlueNodeRefMap& _blue_node_ref; + }; + + struct ArcRefMap { + ArcRefMap(const From& from, const To& to, const EdgeRefMap& edge_ref) + : _from(from), _to(to), _edge_ref(edge_ref) {} + + typedef typename From::Arc Key; + typedef typename To::Arc Value; + + Value operator[](const Key& key) const { + return _to.direct(_edge_ref[key], _from.direction(key)); + } + + const From& _from; + const To& _to; + const EdgeRefMap& _edge_ref; + }; + + public: + + /// \brief Constructor of BpGraphCopy. + /// + /// Constructor of BpGraphCopy for copying the content of the + /// \c from graph into the \c to graph. + BpGraphCopy(const From& from, To& to) + : _from(from), _to(to) {} + + /// \brief Destructor of BpGraphCopy + /// + /// Destructor of BpGraphCopy. + ~BpGraphCopy() { + for (int i = 0; i < int(_node_maps.size()); ++i) { + delete _node_maps[i]; + } + for (int i = 0; i < int(_red_maps.size()); ++i) { + delete _red_maps[i]; + } + for (int i = 0; i < int(_blue_maps.size()); ++i) { + delete _blue_maps[i]; + } + for (int i = 0; i < int(_arc_maps.size()); ++i) { + delete _arc_maps[i]; + } + for (int i = 0; i < int(_edge_maps.size()); ++i) { + delete _edge_maps[i]; + } + } + + /// \brief Copy the node references into the given map. + /// + /// This function copies the node references into the given map. + /// The parameter should be a map, whose key type is the Node type of + /// the source graph, while the value type is the Node type of the + /// destination graph. + template + BpGraphCopy& nodeRef(NodeRef& map) { + _node_maps.push_back(new _core_bits::RefCopy(map)); + return *this; + } + + /// \brief Copy the node cross references into the given map. + /// + /// This function copies the node cross references (reverse references) + /// into the given map. The parameter should be a map, whose key type + /// is the Node type of the destination graph, while the value type is + /// the Node type of the source graph. + template + BpGraphCopy& nodeCrossRef(NodeCrossRef& map) { + _node_maps.push_back(new _core_bits::CrossRefCopy(map)); + return *this; + } + + /// \brief Make a copy of the given node map. + /// + /// This function makes a copy of the given node map for the newly + /// created graph. + /// The key type of the new map \c tmap should be the Node type of the + /// destination graph, and the key type of the original map \c map + /// should be the Node type of the source graph. + template + BpGraphCopy& nodeMap(const FromMap& map, ToMap& tmap) { + _node_maps.push_back(new _core_bits::MapCopy(map, tmap)); + return *this; + } + + /// \brief Make a copy of the given node. + /// + /// This function makes a copy of the given node. + BpGraphCopy& node(const Node& node, TNode& tnode) { + _node_maps.push_back(new _core_bits::ItemCopy(node, tnode)); + return *this; + } + + /// \brief Copy the red node references into the given map. + /// + /// This function copies the red node references into the given + /// map. The parameter should be a map, whose key type is the + /// Node type of the source graph with the red item set, while the + /// value type is the Node type of the destination graph. + template + BpGraphCopy& redRef(RedRef& map) { + _red_maps.push_back(new _core_bits::RefCopy(map)); + return *this; + } + + /// \brief Copy the red node cross references into the given map. + /// + /// This function copies the red node cross references (reverse + /// references) into the given map. The parameter should be a map, + /// whose key type is the Node type of the destination graph with + /// the red item set, while the value type is the Node type of the + /// source graph. + template + BpGraphCopy& redCrossRef(RedCrossRef& map) { + _red_maps.push_back(new _core_bits::CrossRefCopy(map)); + return *this; + } + + /// \brief Make a copy of the given red node map. + /// + /// This function makes a copy of the given red node map for the newly + /// created graph. + /// The key type of the new map \c tmap should be the Node type of + /// the destination graph with the red items, and the key type of + /// the original map \c map should be the Node type of the source + /// graph. + template + BpGraphCopy& redNodeMap(const FromMap& map, ToMap& tmap) { + _red_maps.push_back(new _core_bits::MapCopy(map, tmap)); + return *this; + } + + /// \brief Make a copy of the given red node. + /// + /// This function makes a copy of the given red node. + BpGraphCopy& redNode(const RedNode& node, TRedNode& tnode) { + _red_maps.push_back(new _core_bits::ItemCopy(node, tnode)); + return *this; + } + + /// \brief Copy the blue node references into the given map. + /// + /// This function copies the blue node references into the given + /// map. The parameter should be a map, whose key type is the + /// Node type of the source graph with the blue item set, while the + /// value type is the Node type of the destination graph. + template + BpGraphCopy& blueRef(BlueRef& map) { + _blue_maps.push_back(new _core_bits::RefCopy(map)); + return *this; + } + + /// \brief Copy the blue node cross references into the given map. + /// + /// This function copies the blue node cross references (reverse + /// references) into the given map. The parameter should be a map, + /// whose key type is the Node type of the destination graph with + /// the blue item set, while the value type is the Node type of the + /// source graph. + template + BpGraphCopy& blueCrossRef(BlueCrossRef& map) { + _blue_maps.push_back(new _core_bits::CrossRefCopy(map)); + return *this; + } + + /// \brief Make a copy of the given blue node map. + /// + /// This function makes a copy of the given blue node map for the newly + /// created graph. + /// The key type of the new map \c tmap should be the Node type of + /// the destination graph with the blue items, and the key type of + /// the original map \c map should be the Node type of the source + /// graph. + template + BpGraphCopy& blueNodeMap(const FromMap& map, ToMap& tmap) { + _blue_maps.push_back(new _core_bits::MapCopy(map, tmap)); + return *this; + } + + /// \brief Make a copy of the given blue node. + /// + /// This function makes a copy of the given blue node. + BpGraphCopy& blueNode(const BlueNode& node, TBlueNode& tnode) { + _blue_maps.push_back(new _core_bits::ItemCopy(node, tnode)); + return *this; + } + + /// \brief Copy the arc references into the given map. + /// + /// This function copies the arc references into the given map. + /// The parameter should be a map, whose key type is the Arc type of + /// the source graph, while the value type is the Arc type of the + /// destination graph. + template + BpGraphCopy& arcRef(ArcRef& map) { + _arc_maps.push_back(new _core_bits::RefCopy(map)); + return *this; + } + + /// \brief Copy the arc cross references into the given map. + /// + /// This function copies the arc cross references (reverse references) + /// into the given map. The parameter should be a map, whose key type + /// is the Arc type of the destination graph, while the value type is + /// the Arc type of the source graph. + template + BpGraphCopy& arcCrossRef(ArcCrossRef& map) { + _arc_maps.push_back(new _core_bits::CrossRefCopy(map)); + return *this; + } + + /// \brief Make a copy of the given arc map. + /// + /// This function makes a copy of the given arc map for the newly + /// created graph. + /// The key type of the new map \c tmap should be the Arc type of the + /// destination graph, and the key type of the original map \c map + /// should be the Arc type of the source graph. + template + BpGraphCopy& arcMap(const FromMap& map, ToMap& tmap) { + _arc_maps.push_back(new _core_bits::MapCopy(map, tmap)); + return *this; + } + + /// \brief Make a copy of the given arc. + /// + /// This function makes a copy of the given arc. + BpGraphCopy& arc(const Arc& arc, TArc& tarc) { + _arc_maps.push_back(new _core_bits::ItemCopy(arc, tarc)); + return *this; + } + + /// \brief Copy the edge references into the given map. + /// + /// This function copies the edge references into the given map. + /// The parameter should be a map, whose key type is the Edge type of + /// the source graph, while the value type is the Edge type of the + /// destination graph. + template + BpGraphCopy& edgeRef(EdgeRef& map) { + _edge_maps.push_back(new _core_bits::RefCopy(map)); + return *this; + } + + /// \brief Copy the edge cross references into the given map. + /// + /// This function copies the edge cross references (reverse references) + /// into the given map. The parameter should be a map, whose key type + /// is the Edge type of the destination graph, while the value type is + /// the Edge type of the source graph. + template + BpGraphCopy& edgeCrossRef(EdgeCrossRef& map) { + _edge_maps.push_back(new _core_bits::CrossRefCopy(map)); + return *this; + } + + /// \brief Make a copy of the given edge map. + /// + /// This function makes a copy of the given edge map for the newly + /// created graph. + /// The key type of the new map \c tmap should be the Edge type of the + /// destination graph, and the key type of the original map \c map + /// should be the Edge type of the source graph. + template + BpGraphCopy& edgeMap(const FromMap& map, ToMap& tmap) { + _edge_maps.push_back(new _core_bits::MapCopy(map, tmap)); + return *this; + } + + /// \brief Make a copy of the given edge. + /// + /// This function makes a copy of the given edge. + BpGraphCopy& edge(const Edge& edge, TEdge& tedge) { + _edge_maps.push_back(new _core_bits::ItemCopy(edge, tedge)); + return *this; + } + + /// \brief Execute copying. + /// + /// This function executes the copying of the graph along with the + /// copying of the assigned data. + void run() { + RedNodeRefMap redNodeRefMap(_from); + BlueNodeRefMap blueNodeRefMap(_from); + NodeRefMap nodeRefMap(_from, redNodeRefMap, blueNodeRefMap); + EdgeRefMap edgeRefMap(_from); + ArcRefMap arcRefMap(_from, _to, edgeRefMap); + _core_bits::BpGraphCopySelector:: + copy(_from, _to, redNodeRefMap, blueNodeRefMap, edgeRefMap); + for (int i = 0; i < int(_node_maps.size()); ++i) { + _node_maps[i]->copy(_from, nodeRefMap); + } + for (int i = 0; i < int(_red_maps.size()); ++i) { + _red_maps[i]->copy(_from, redNodeRefMap); + } + for (int i = 0; i < int(_blue_maps.size()); ++i) { + _blue_maps[i]->copy(_from, blueNodeRefMap); + } + for (int i = 0; i < int(_edge_maps.size()); ++i) { + _edge_maps[i]->copy(_from, edgeRefMap); + } + for (int i = 0; i < int(_arc_maps.size()); ++i) { + _arc_maps[i]->copy(_from, arcRefMap); + } + } + + private: + + const From& _from; + To& _to; + + std::vector<_core_bits::MapCopyBase* > + _node_maps; + + std::vector<_core_bits::MapCopyBase* > + _red_maps; + + std::vector<_core_bits::MapCopyBase* > + _blue_maps; + + std::vector<_core_bits::MapCopyBase* > + _arc_maps; + + std::vector<_core_bits::MapCopyBase* > + _edge_maps; + + }; + + /// \brief Copy a graph to another graph. + /// + /// This function copies a graph to another graph. + /// The complete usage of it is detailed in the BpGraphCopy class, + /// but a short example shows a basic work: + ///\code + /// graphCopy(src, trg).nodeRef(nr).edgeCrossRef(ecr).run(); + ///\endcode + /// + /// After the copy the \c nr map will contain the mapping from the + /// nodes of the \c from graph to the nodes of the \c to graph and + /// \c ecr will contain the mapping from the edges of the \c to graph + /// to the edges of the \c from graph. + /// + /// \see BpGraphCopy + template + BpGraphCopy + bpGraphCopy(const From& from, To& to) { + return BpGraphCopy(from, to); + } + + namespace _core_bits { + + template + struct FindArcSelector { + typedef typename Graph::Node Node; + typedef typename Graph::Arc Arc; + static Arc find(const Graph &g, Node u, Node v, Arc e) { + if (e == INVALID) { + g.firstOut(e, u); + } else { + g.nextOut(e); + } + while (e != INVALID && g.target(e) != v) { + g.nextOut(e); + } + return e; + } + }; + + template + struct FindArcSelector< + Graph, + typename enable_if::type> + { + typedef typename Graph::Node Node; + typedef typename Graph::Arc Arc; + static Arc find(const Graph &g, Node u, Node v, Arc prev) { + return g.findArc(u, v, prev); + } + }; + } + + /// \brief Find an arc between two nodes of a digraph. + /// + /// This function finds an arc from node \c u to node \c v in the + /// digraph \c g. + /// + /// If \c prev is \ref INVALID (this is the default value), then + /// it finds the first arc from \c u to \c v. Otherwise it looks for + /// the next arc from \c u to \c v after \c prev. + /// \return The found arc or \ref INVALID if there is no such an arc. + /// + /// Thus you can iterate through each arc from \c u to \c v as it follows. + ///\code + /// for(Arc e = findArc(g,u,v); e != INVALID; e = findArc(g,u,v,e)) { + /// ... + /// } + ///\endcode + /// + /// \note \ref ConArcIt provides iterator interface for the same + /// functionality. + /// + ///\sa ConArcIt + ///\sa ArcLookUp, AllArcLookUp, DynArcLookUp + template + inline typename Graph::Arc + findArc(const Graph &g, typename Graph::Node u, typename Graph::Node v, + typename Graph::Arc prev = INVALID) { + return _core_bits::FindArcSelector::find(g, u, v, prev); + } + + /// \brief Iterator for iterating on parallel arcs connecting the same nodes. + /// + /// Iterator for iterating on parallel arcs connecting the same nodes. It is + /// a higher level interface for the \ref findArc() function. You can + /// use it the following way: + ///\code + /// for (ConArcIt it(g, src, trg); it != INVALID; ++it) { + /// ... + /// } + ///\endcode + /// + ///\sa findArc() + ///\sa ArcLookUp, AllArcLookUp, DynArcLookUp + template + class ConArcIt : public GR::Arc { + typedef typename GR::Arc Parent; + + public: + + typedef typename GR::Arc Arc; + typedef typename GR::Node Node; + + /// \brief Constructor. + /// + /// Construct a new ConArcIt iterating on the arcs that + /// connects nodes \c u and \c v. + ConArcIt(const GR& g, Node u, Node v) : _graph(g) { + Parent::operator=(findArc(_graph, u, v)); + } + + /// \brief Constructor. + /// + /// Construct a new ConArcIt that continues the iterating from arc \c a. + ConArcIt(const GR& g, Arc a) : Parent(a), _graph(g) {} + + /// \brief Increment operator. + /// + /// It increments the iterator and gives back the next arc. + ConArcIt& operator++() { + Parent::operator=(findArc(_graph, _graph.source(*this), + _graph.target(*this), *this)); + return *this; + } + private: + const GR& _graph; + }; + + namespace _core_bits { + + template + struct FindEdgeSelector { + typedef typename Graph::Node Node; + typedef typename Graph::Edge Edge; + static Edge find(const Graph &g, Node u, Node v, Edge e) { + bool b; + if (u != v) { + if (e == INVALID) { + g.firstInc(e, b, u); + } else { + b = g.u(e) == u; + g.nextInc(e, b); + } + while (e != INVALID && (b ? g.v(e) : g.u(e)) != v) { + g.nextInc(e, b); + } + } else { + if (e == INVALID) { + g.firstInc(e, b, u); + } else { + b = true; + g.nextInc(e, b); + } + while (e != INVALID && (!b || g.v(e) != v)) { + g.nextInc(e, b); + } + } + return e; + } + }; + + template + struct FindEdgeSelector< + Graph, + typename enable_if::type> + { + typedef typename Graph::Node Node; + typedef typename Graph::Edge Edge; + static Edge find(const Graph &g, Node u, Node v, Edge prev) { + return g.findEdge(u, v, prev); + } + }; + } + + /// \brief Find an edge between two nodes of a graph. + /// + /// This function finds an edge from node \c u to node \c v in graph \c g. + /// If node \c u and node \c v is equal then each loop edge + /// will be enumerated once. + /// + /// If \c prev is \ref INVALID (this is the default value), then + /// it finds the first edge from \c u to \c v. Otherwise it looks for + /// the next edge from \c u to \c v after \c prev. + /// \return The found edge or \ref INVALID if there is no such an edge. + /// + /// Thus you can iterate through each edge between \c u and \c v + /// as it follows. + ///\code + /// for(Edge e = findEdge(g,u,v); e != INVALID; e = findEdge(g,u,v,e)) { + /// ... + /// } + ///\endcode + /// + /// \note \ref ConEdgeIt provides iterator interface for the same + /// functionality. + /// + ///\sa ConEdgeIt + template + inline typename Graph::Edge + findEdge(const Graph &g, typename Graph::Node u, typename Graph::Node v, + typename Graph::Edge p = INVALID) { + return _core_bits::FindEdgeSelector::find(g, u, v, p); + } + + /// \brief Iterator for iterating on parallel edges connecting the same nodes. + /// + /// Iterator for iterating on parallel edges connecting the same nodes. + /// It is a higher level interface for the findEdge() function. You can + /// use it the following way: + ///\code + /// for (ConEdgeIt it(g, u, v); it != INVALID; ++it) { + /// ... + /// } + ///\endcode + /// + ///\sa findEdge() + template + class ConEdgeIt : public GR::Edge { + typedef typename GR::Edge Parent; + + public: + + typedef typename GR::Edge Edge; + typedef typename GR::Node Node; + + /// \brief Constructor. + /// + /// Construct a new ConEdgeIt iterating on the edges that + /// connects nodes \c u and \c v. + ConEdgeIt(const GR& g, Node u, Node v) : _graph(g), _u(u), _v(v) { + Parent::operator=(findEdge(_graph, _u, _v)); + } + + /// \brief Constructor. + /// + /// Construct a new ConEdgeIt that continues iterating from edge \c e. + ConEdgeIt(const GR& g, Edge e) : Parent(e), _graph(g) {} + + /// \brief Increment operator. + /// + /// It increments the iterator and gives back the next edge. + ConEdgeIt& operator++() { + Parent::operator=(findEdge(_graph, _u, _v, *this)); + return *this; + } + private: + const GR& _graph; + Node _u, _v; + }; + + + ///Dynamic arc look-up between given endpoints. + + ///Using this class, you can find an arc in a digraph from a given + ///source to a given target in amortized time O(logd), + ///where d is the out-degree of the source node. + /// + ///It is possible to find \e all parallel arcs between two nodes with + ///the \c operator() member. + /// + ///This is a dynamic data structure. Consider to use \ref ArcLookUp or + ///\ref AllArcLookUp if your digraph is not changed so frequently. + /// + ///This class uses a self-adjusting binary search tree, the Splay tree + ///of Sleator and Tarjan to guarantee the logarithmic amortized + ///time bound for arc look-ups. This class also guarantees the + ///optimal time bound in a constant factor for any distribution of + ///queries. + /// + ///\tparam GR The type of the underlying digraph. + /// + ///\sa ArcLookUp + ///\sa AllArcLookUp + template + class DynArcLookUp + : protected ItemSetTraits::ItemNotifier::ObserverBase + { + typedef typename ItemSetTraits + ::ItemNotifier::ObserverBase Parent; + + TEMPLATE_DIGRAPH_TYPEDEFS(GR); + + public: + + /// The Digraph type + typedef GR Digraph; + + protected: + + class AutoNodeMap : public ItemSetTraits::template Map::Type + { + typedef typename ItemSetTraits::template Map::Type Parent; + + public: + + AutoNodeMap(const GR& digraph) : Parent(digraph, INVALID) {} + + virtual void add(const Node& node) { + Parent::add(node); + Parent::set(node, INVALID); + } + + virtual void add(const std::vector& nodes) { + Parent::add(nodes); + for (int i = 0; i < int(nodes.size()); ++i) { + Parent::set(nodes[i], INVALID); + } + } + + virtual void build() { + Parent::build(); + Node it; + typename Parent::Notifier* nf = Parent::notifier(); + for (nf->first(it); it != INVALID; nf->next(it)) { + Parent::set(it, INVALID); + } + } + }; + + class ArcLess { + const Digraph &g; + public: + ArcLess(const Digraph &_g) : g(_g) {} + bool operator()(Arc a,Arc b) const + { + return g.target(a) _parent; + typename Digraph::template ArcMap _left; + typename Digraph::template ArcMap _right; + + public: + + ///Constructor + + ///Constructor. + /// + ///It builds up the search database. + DynArcLookUp(const Digraph &g) + : _g(g),_head(g),_parent(g),_left(g),_right(g) + { + Parent::attach(_g.notifier(typename Digraph::Arc())); + refresh(); + } + + protected: + + virtual void add(const Arc& arc) { + insert(arc); + } + + virtual void add(const std::vector& arcs) { + for (int i = 0; i < int(arcs.size()); ++i) { + insert(arcs[i]); + } + } + + virtual void erase(const Arc& arc) { + remove(arc); + } + + virtual void erase(const std::vector& arcs) { + for (int i = 0; i < int(arcs.size()); ++i) { + remove(arcs[i]); + } + } + + virtual void build() { + refresh(); + } + + virtual void clear() { + for(NodeIt n(_g);n!=INVALID;++n) { + _head[n] = INVALID; + } + } + + void insert(Arc arc) { + Node s = _g.source(arc); + Node t = _g.target(arc); + _left[arc] = INVALID; + _right[arc] = INVALID; + + Arc e = _head[s]; + if (e == INVALID) { + _head[s] = arc; + _parent[arc] = INVALID; + return; + } + while (true) { + if (t < _g.target(e)) { + if (_left[e] == INVALID) { + _left[e] = arc; + _parent[arc] = e; + splay(arc); + return; + } else { + e = _left[e]; + } + } else { + if (_right[e] == INVALID) { + _right[e] = arc; + _parent[arc] = e; + splay(arc); + return; + } else { + e = _right[e]; + } + } + } + } + + void remove(Arc arc) { + if (_left[arc] == INVALID) { + if (_right[arc] != INVALID) { + _parent[_right[arc]] = _parent[arc]; + } + if (_parent[arc] != INVALID) { + if (_left[_parent[arc]] == arc) { + _left[_parent[arc]] = _right[arc]; + } else { + _right[_parent[arc]] = _right[arc]; + } + } else { + _head[_g.source(arc)] = _right[arc]; + } + } else if (_right[arc] == INVALID) { + _parent[_left[arc]] = _parent[arc]; + if (_parent[arc] != INVALID) { + if (_left[_parent[arc]] == arc) { + _left[_parent[arc]] = _left[arc]; + } else { + _right[_parent[arc]] = _left[arc]; + } + } else { + _head[_g.source(arc)] = _left[arc]; + } + } else { + Arc e = _left[arc]; + if (_right[e] != INVALID) { + e = _right[e]; + while (_right[e] != INVALID) { + e = _right[e]; + } + Arc s = _parent[e]; + _right[_parent[e]] = _left[e]; + if (_left[e] != INVALID) { + _parent[_left[e]] = _parent[e]; + } + + _left[e] = _left[arc]; + _parent[_left[arc]] = e; + _right[e] = _right[arc]; + _parent[_right[arc]] = e; + + _parent[e] = _parent[arc]; + if (_parent[arc] != INVALID) { + if (_left[_parent[arc]] == arc) { + _left[_parent[arc]] = e; + } else { + _right[_parent[arc]] = e; + } + } + splay(s); + } else { + _right[e] = _right[arc]; + _parent[_right[arc]] = e; + _parent[e] = _parent[arc]; + + if (_parent[arc] != INVALID) { + if (_left[_parent[arc]] == arc) { + _left[_parent[arc]] = e; + } else { + _right[_parent[arc]] = e; + } + } else { + _head[_g.source(arc)] = e; + } + } + } + } + + Arc refreshRec(std::vector &v,int a,int b) + { + int m=(a+b)/2; + Arc me=v[m]; + if (a < m) { + Arc left = refreshRec(v,a,m-1); + _left[me] = left; + _parent[left] = me; + } else { + _left[me] = INVALID; + } + if (m < b) { + Arc right = refreshRec(v,m+1,b); + _right[me] = right; + _parent[right] = me; + } else { + _right[me] = INVALID; + } + return me; + } + + void refresh() { + for(NodeIt n(_g);n!=INVALID;++n) { + std::vector v; + for(OutArcIt a(_g,n);a!=INVALID;++a) v.push_back(a); + if (!v.empty()) { + std::sort(v.begin(),v.end(),ArcLess(_g)); + Arc head = refreshRec(v,0,v.size()-1); + _head[n] = head; + _parent[head] = INVALID; + } + else _head[n] = INVALID; + } + } + + void zig(Arc v) { + Arc w = _parent[v]; + _parent[v] = _parent[w]; + _parent[w] = v; + _left[w] = _right[v]; + _right[v] = w; + if (_parent[v] != INVALID) { + if (_right[_parent[v]] == w) { + _right[_parent[v]] = v; + } else { + _left[_parent[v]] = v; + } + } + if (_left[w] != INVALID){ + _parent[_left[w]] = w; + } + } + + void zag(Arc v) { + Arc w = _parent[v]; + _parent[v] = _parent[w]; + _parent[w] = v; + _right[w] = _left[v]; + _left[v] = w; + if (_parent[v] != INVALID){ + if (_left[_parent[v]] == w) { + _left[_parent[v]] = v; + } else { + _right[_parent[v]] = v; + } + } + if (_right[w] != INVALID){ + _parent[_right[w]] = w; + } + } + + void splay(Arc v) { + while (_parent[v] != INVALID) { + if (v == _left[_parent[v]]) { + if (_parent[_parent[v]] == INVALID) { + zig(v); + } else { + if (_parent[v] == _left[_parent[_parent[v]]]) { + zig(_parent[v]); + zig(v); + } else { + zig(v); + zag(v); + } + } + } else { + if (_parent[_parent[v]] == INVALID) { + zag(v); + } else { + if (_parent[v] == _left[_parent[_parent[v]]]) { + zag(v); + zig(v); + } else { + zag(_parent[v]); + zag(v); + } + } + } + } + _head[_g.source(v)] = v; + } + + + public: + + ///Find an arc between two nodes. + + ///Find an arc between two nodes. + ///\param s The source node. + ///\param t The target node. + ///\param p The previous arc between \c s and \c t. It it is INVALID or + ///not given, the operator finds the first appropriate arc. + ///\return An arc from \c s to \c t after \c p or + ///\ref INVALID if there is no more. + /// + ///For example, you can count the number of arcs from \c u to \c v in the + ///following way. + ///\code + ///DynArcLookUp ae(g); + ///... + ///int n = 0; + ///for(Arc a = ae(u,v); a != INVALID; a = ae(u,v,a)) n++; + ///\endcode + /// + ///Finding the arcs take at most O(logd) + ///amortized time, specifically, the time complexity of the lookups + ///is equal to the optimal search tree implementation for the + ///current query distribution in a constant factor. + /// + ///\note This is a dynamic data structure, therefore the data + ///structure is updated after each graph alteration. Thus although + ///this data structure is theoretically faster than \ref ArcLookUp + ///and \ref AllArcLookUp, it often provides worse performance than + ///them. + Arc operator()(Node s, Node t, Arc p = INVALID) const { + if (p == INVALID) { + Arc a = _head[s]; + if (a == INVALID) return INVALID; + Arc r = INVALID; + while (true) { + if (_g.target(a) < t) { + if (_right[a] == INVALID) { + const_cast(*this).splay(a); + return r; + } else { + a = _right[a]; + } + } else { + if (_g.target(a) == t) { + r = a; + } + if (_left[a] == INVALID) { + const_cast(*this).splay(a); + return r; + } else { + a = _left[a]; + } + } + } + } else { + Arc a = p; + if (_right[a] != INVALID) { + a = _right[a]; + while (_left[a] != INVALID) { + a = _left[a]; + } + const_cast(*this).splay(a); + } else { + while (_parent[a] != INVALID && _right[_parent[a]] == a) { + a = _parent[a]; + } + if (_parent[a] == INVALID) { + return INVALID; + } else { + a = _parent[a]; + const_cast(*this).splay(a); + } + } + if (_g.target(a) == t) return a; + else return INVALID; + } + } + + }; + + ///Fast arc look-up between given endpoints. + + ///Using this class, you can find an arc in a digraph from a given + ///source to a given target in time O(logd), + ///where d is the out-degree of the source node. + /// + ///It is not possible to find \e all parallel arcs between two nodes. + ///Use \ref AllArcLookUp for this purpose. + /// + ///\warning This class is static, so you should call refresh() (or at + ///least refresh(Node)) to refresh this data structure whenever the + ///digraph changes. This is a time consuming (superlinearly proportional + ///(O(m logm)) to the number of arcs). + /// + ///\tparam GR The type of the underlying digraph. + /// + ///\sa DynArcLookUp + ///\sa AllArcLookUp + template + class ArcLookUp + { + TEMPLATE_DIGRAPH_TYPEDEFS(GR); + + public: + + /// The Digraph type + typedef GR Digraph; + + protected: + const Digraph &_g; + typename Digraph::template NodeMap _head; + typename Digraph::template ArcMap _left; + typename Digraph::template ArcMap _right; + + class ArcLess { + const Digraph &g; + public: + ArcLess(const Digraph &_g) : g(_g) {} + bool operator()(Arc a,Arc b) const + { + return g.target(a) &v,int a,int b) + { + int m=(a+b)/2; + Arc me=v[m]; + _left[me] = aO(d logd), where d + ///is the number of the outgoing arcs of \c n. + void refresh(Node n) + { + std::vector v; + for(OutArcIt e(_g,n);e!=INVALID;++e) v.push_back(e); + if(v.size()) { + std::sort(v.begin(),v.end(),ArcLess(_g)); + _head[n]=refreshRec(v,0,v.size()-1); + } + else _head[n]=INVALID; + } + ///Refresh the full data structure. + + ///Build up the full search database. In fact, it simply calls + ///\ref refresh(Node) "refresh(n)" for each node \c n. + /// + ///It runs in time O(m logD), where m is + ///the number of the arcs in the digraph and D is the maximum + ///out-degree of the digraph. + void refresh() + { + for(NodeIt n(_g);n!=INVALID;++n) refresh(n); + } + + ///Find an arc between two nodes. + + ///Find an arc between two nodes in time O(logd), + ///where d is the number of outgoing arcs of \c s. + ///\param s The source node. + ///\param t The target node. + ///\return An arc from \c s to \c t if there exists, + ///\ref INVALID otherwise. + /// + ///\warning If you change the digraph, refresh() must be called before using + ///this operator. If you change the outgoing arcs of + ///a single node \c n, then \ref refresh(Node) "refresh(n)" is enough. + Arc operator()(Node s, Node t) const + { + Arc e; + for(e=_head[s]; + e!=INVALID&&_g.target(e)!=t; + e = t < _g.target(e)?_left[e]:_right[e]) ; + return e; + } + + }; + + ///Fast look-up of all arcs between given endpoints. + + ///This class is the same as \ref ArcLookUp, with the addition + ///that it makes it possible to find all parallel arcs between given + ///endpoints. + /// + ///\warning This class is static, so you should call refresh() (or at + ///least refresh(Node)) to refresh this data structure whenever the + ///digraph changes. This is a time consuming (superlinearly proportional + ///(O(m logm)) to the number of arcs). + /// + ///\tparam GR The type of the underlying digraph. + /// + ///\sa DynArcLookUp + ///\sa ArcLookUp + template + class AllArcLookUp : public ArcLookUp + { + using ArcLookUp::_g; + using ArcLookUp::_right; + using ArcLookUp::_left; + using ArcLookUp::_head; + + TEMPLATE_DIGRAPH_TYPEDEFS(GR); + + typename GR::template ArcMap _next; + + Arc refreshNext(Arc head,Arc next=INVALID) + { + if(head==INVALID) return next; + else { + next=refreshNext(_right[head],next); + _next[head]=( next!=INVALID && _g.target(next)==_g.target(head)) + ? next : INVALID; + return refreshNext(_left[head],head); + } + } + + void refreshNext() + { + for(NodeIt n(_g);n!=INVALID;++n) refreshNext(_head[n]); + } + + public: + + /// The Digraph type + typedef GR Digraph; + + ///Constructor + + ///Constructor. + /// + ///It builds up the search database, which remains valid until the digraph + ///changes. + AllArcLookUp(const Digraph &g) : ArcLookUp(g), _next(g) {refreshNext();} + + ///Refresh the data structure at a node. + + ///Build up the search database of node \c n. + /// + ///It runs in time O(d logd), where d is + ///the number of the outgoing arcs of \c n. + void refresh(Node n) + { + ArcLookUp::refresh(n); + refreshNext(_head[n]); + } + + ///Refresh the full data structure. + + ///Build up the full search database. In fact, it simply calls + ///\ref refresh(Node) "refresh(n)" for each node \c n. + /// + ///It runs in time O(m logD), where m is + ///the number of the arcs in the digraph and D is the maximum + ///out-degree of the digraph. + void refresh() + { + for(NodeIt n(_g);n!=INVALID;++n) refresh(_head[n]); + } + + ///Find an arc between two nodes. + + ///Find an arc between two nodes. + ///\param s The source node. + ///\param t The target node. + ///\param prev The previous arc between \c s and \c t. It it is INVALID or + ///not given, the operator finds the first appropriate arc. + ///\return An arc from \c s to \c t after \c prev or + ///\ref INVALID if there is no more. + /// + ///For example, you can count the number of arcs from \c u to \c v in the + ///following way. + ///\code + ///AllArcLookUp ae(g); + ///... + ///int n = 0; + ///for(Arc a = ae(u,v); a != INVALID; a=ae(u,v,a)) n++; + ///\endcode + /// + ///Finding the first arc take O(logd) time, + ///where d is the number of outgoing arcs of \c s. Then the + ///consecutive arcs are found in constant time. + /// + ///\warning If you change the digraph, refresh() must be called before using + ///this operator. If you change the outgoing arcs of + ///a single node \c n, then \ref refresh(Node) "refresh(n)" is enough. + /// + Arc operator()(Node s, Node t, Arc prev=INVALID) const + { + if(prev==INVALID) + { + Arc f=INVALID; + Arc e; + for(e=_head[s]; + e!=INVALID&&_g.target(e)!=t; + e = t < _g.target(e)?_left[e]:_right[e]) ; + while(e!=INVALID) + if(_g.target(e)==t) + { + f = e; + e = _left[e]; + } + else e = _right[e]; + return f; + } + else return _next[prev]; + } + + }; + + /// @} + +} //namespace lemon + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/cost_scaling.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/cost_scaling.h new file mode 100644 index 00000000000..efecdfe77c7 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/cost_scaling.h @@ -0,0 +1,1607 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_COST_SCALING_H +#define LEMON_COST_SCALING_H + +/// \ingroup min_cost_flow_algs +/// \file +/// \brief Cost scaling algorithm for finding a minimum cost flow. + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace lemon { + + /// \brief Default traits class of CostScaling algorithm. + /// + /// Default traits class of CostScaling algorithm. + /// \tparam GR Digraph type. + /// \tparam V The number type used for flow amounts, capacity bounds + /// and supply values. By default it is \c int. + /// \tparam C The number type used for costs and potentials. + /// By default it is the same as \c V. +#ifdef DOXYGEN + template +#else + template < typename GR, typename V = int, typename C = V, + bool integer = std::numeric_limits::is_integer > +#endif + struct CostScalingDefaultTraits + { + /// The type of the digraph + typedef GR Digraph; + /// The type of the flow amounts, capacity bounds and supply values + typedef V Value; + /// The type of the arc costs + typedef C Cost; + + /// \brief The large cost type used for internal computations + /// + /// The large cost type used for internal computations. + /// It is \c long \c long if the \c Cost type is integer, + /// otherwise it is \c double. + /// \c Cost must be convertible to \c LargeCost. + typedef double LargeCost; + }; + + // Default traits class for integer cost types + template + struct CostScalingDefaultTraits + { + typedef GR Digraph; + typedef V Value; + typedef C Cost; +#ifdef LEMON_HAVE_LONG_LONG + typedef long long LargeCost; +#else + typedef long LargeCost; +#endif + }; + + + /// \addtogroup min_cost_flow_algs + /// @{ + + /// \brief Implementation of the Cost Scaling algorithm for + /// finding a \ref min_cost_flow "minimum cost flow". + /// + /// \ref CostScaling implements a cost scaling algorithm that performs + /// push/augment and relabel operations for finding a \ref min_cost_flow + /// "minimum cost flow" \cite amo93networkflows, + /// \cite goldberg90approximation, + /// \cite goldberg97efficient, \cite bunnagel98efficient. + /// It is a highly efficient primal-dual solution method, which + /// can be viewed as the generalization of the \ref Preflow + /// "preflow push-relabel" algorithm for the maximum flow problem. + /// It is a polynomial algorithm, its running time complexity is + /// \f$O(n^2m\log(nK))\f$, where K denotes the maximum arc cost. + /// + /// In general, \ref NetworkSimplex and \ref CostScaling are the fastest + /// implementations available in LEMON for solving this problem. + /// (For more information, see \ref min_cost_flow_algs "the module page".) + /// + /// Most of the parameters of the problem (except for the digraph) + /// can be given using separate functions, and the algorithm can be + /// executed using the \ref run() function. If some parameters are not + /// specified, then default values will be used. + /// + /// \tparam GR The digraph type the algorithm runs on. + /// \tparam V The number type used for flow amounts, capacity bounds + /// and supply values in the algorithm. By default, it is \c int. + /// \tparam C The number type used for costs and potentials in the + /// algorithm. By default, it is the same as \c V. + /// \tparam TR The traits class that defines various types used by the + /// algorithm. By default, it is \ref CostScalingDefaultTraits + /// "CostScalingDefaultTraits". + /// In most cases, this parameter should not be set directly, + /// consider to use the named template parameters instead. + /// + /// \warning Both \c V and \c C must be signed number types. + /// \warning All input data (capacities, supply values, and costs) must + /// be integer. + /// \warning This algorithm does not support negative costs for + /// arcs having infinite upper bound. + /// + /// \note %CostScaling provides three different internal methods, + /// from which the most efficient one is used by default. + /// For more information, see \ref Method. +#ifdef DOXYGEN + template +#else + template < typename GR, typename V = int, typename C = V, + typename TR = CostScalingDefaultTraits > +#endif + class CostScaling + { + public: + + /// The type of the digraph + typedef typename TR::Digraph Digraph; + /// The type of the flow amounts, capacity bounds and supply values + typedef typename TR::Value Value; + /// The type of the arc costs + typedef typename TR::Cost Cost; + + /// \brief The large cost type + /// + /// The large cost type used for internal computations. + /// By default, it is \c long \c long if the \c Cost type is integer, + /// otherwise it is \c double. + typedef typename TR::LargeCost LargeCost; + + /// \brief The \ref lemon::CostScalingDefaultTraits "traits class" + /// of the algorithm + typedef TR Traits; + + public: + + /// \brief Problem type constants for the \c run() function. + /// + /// Enum type containing the problem type constants that can be + /// returned by the \ref run() function of the algorithm. + enum ProblemType { + /// The problem has no feasible solution (flow). + INFEASIBLE, + /// The problem has optimal solution (i.e. it is feasible and + /// bounded), and the algorithm has found optimal flow and node + /// potentials (primal and dual solutions). + OPTIMAL, + /// The digraph contains an arc of negative cost and infinite + /// upper bound. It means that the objective function is unbounded + /// on that arc, however, note that it could actually be bounded + /// over the feasible flows, but this algroithm cannot handle + /// these cases. + UNBOUNDED + }; + + /// \brief Constants for selecting the internal method. + /// + /// Enum type containing constants for selecting the internal method + /// for the \ref run() function. + /// + /// \ref CostScaling provides three internal methods that differ mainly + /// in their base operations, which are used in conjunction with the + /// relabel operation. + /// By default, the so called \ref PARTIAL_AUGMENT + /// "Partial Augment-Relabel" method is used, which turned out to be + /// the most efficient and the most robust on various test inputs. + /// However, the other methods can be selected using the \ref run() + /// function with the proper parameter. + enum Method { + /// Local push operations are used, i.e. flow is moved only on one + /// admissible arc at once. + PUSH, + /// Augment operations are used, i.e. flow is moved on admissible + /// paths from a node with excess to a node with deficit. + AUGMENT, + /// Partial augment operations are used, i.e. flow is moved on + /// admissible paths started from a node with excess, but the + /// lengths of these paths are limited. This method can be viewed + /// as a combined version of the previous two operations. + PARTIAL_AUGMENT + }; + + private: + + TEMPLATE_DIGRAPH_TYPEDEFS(GR); + + typedef std::vector IntVector; + typedef std::vector ValueVector; + typedef std::vector CostVector; + typedef std::vector LargeCostVector; + typedef std::vector BoolVector; + // Note: vector is used instead of vector + // for efficiency reasons + + private: + + template + class StaticVectorMap { + public: + typedef KT Key; + typedef VT Value; + + StaticVectorMap(std::vector& v) : _v(v) {} + + const Value& operator[](const Key& key) const { + return _v[StaticDigraph::id(key)]; + } + + Value& operator[](const Key& key) { + return _v[StaticDigraph::id(key)]; + } + + void set(const Key& key, const Value& val) { + _v[StaticDigraph::id(key)] = val; + } + + private: + std::vector& _v; + }; + + typedef StaticVectorMap LargeCostArcMap; + + private: + + // Data related to the underlying digraph + const GR &_graph; + int _node_num; + int _arc_num; + int _res_node_num; + int _res_arc_num; + int _root; + + // Parameters of the problem + bool _has_lower; + Value _sum_supply; + int _sup_node_num; + + // Data structures for storing the digraph + IntNodeMap _node_id; + IntArcMap _arc_idf; + IntArcMap _arc_idb; + IntVector _first_out; + BoolVector _forward; + IntVector _source; + IntVector _target; + IntVector _reverse; + + // Node and arc data + ValueVector _lower; + ValueVector _upper; + CostVector _scost; + ValueVector _supply; + + ValueVector _res_cap; + LargeCostVector _cost; + LargeCostVector _pi; + ValueVector _excess; + IntVector _next_out; + std::deque _active_nodes; + + // Data for scaling + LargeCost _epsilon; + int _alpha; + + IntVector _buckets; + IntVector _bucket_next; + IntVector _bucket_prev; + IntVector _rank; + int _max_rank; + + public: + + /// \brief Constant for infinite upper bounds (capacities). + /// + /// Constant for infinite upper bounds (capacities). + /// It is \c std::numeric_limits::infinity() if available, + /// \c std::numeric_limits::max() otherwise. + const Value INF; + + public: + + /// \name Named Template Parameters + /// @{ + + template + struct SetLargeCostTraits : public Traits { + typedef T LargeCost; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c LargeCost type. + /// + /// \ref named-templ-param "Named parameter" for setting \c LargeCost + /// type, which is used for internal computations in the algorithm. + /// \c Cost must be convertible to \c LargeCost. + template + struct SetLargeCost + : public CostScaling > { + typedef CostScaling > Create; + }; + + /// @} + + protected: + + CostScaling() {} + + public: + + /// \brief Constructor. + /// + /// The constructor of the class. + /// + /// \param graph The digraph the algorithm runs on. + CostScaling(const GR& graph) : + _graph(graph), _node_id(graph), _arc_idf(graph), _arc_idb(graph), + INF(std::numeric_limits::has_infinity ? + std::numeric_limits::infinity() : + std::numeric_limits::max()) + { + // Check the number types + LEMON_ASSERT(std::numeric_limits::is_signed, + "The flow type of CostScaling must be signed"); + LEMON_ASSERT(std::numeric_limits::is_signed, + "The cost type of CostScaling must be signed"); + + // Reset data structures + reset(); + } + + /// \name Parameters + /// The parameters of the algorithm can be specified using these + /// functions. + + /// @{ + + /// \brief Set the lower bounds on the arcs. + /// + /// This function sets the lower bounds on the arcs. + /// If it is not used before calling \ref run(), the lower bounds + /// will be set to zero on all arcs. + /// + /// \param map An arc map storing the lower bounds. + /// Its \c Value type must be convertible to the \c Value type + /// of the algorithm. + /// + /// \return (*this) + template + CostScaling& lowerMap(const LowerMap& map) { + _has_lower = true; + for (ArcIt a(_graph); a != INVALID; ++a) { + _lower[_arc_idf[a]] = map[a]; + } + return *this; + } + + /// \brief Set the upper bounds (capacities) on the arcs. + /// + /// This function sets the upper bounds (capacities) on the arcs. + /// If it is not used before calling \ref run(), the upper bounds + /// will be set to \ref INF on all arcs (i.e. the flow value will be + /// unbounded from above). + /// + /// \param map An arc map storing the upper bounds. + /// Its \c Value type must be convertible to the \c Value type + /// of the algorithm. + /// + /// \return (*this) + template + CostScaling& upperMap(const UpperMap& map) { + for (ArcIt a(_graph); a != INVALID; ++a) { + _upper[_arc_idf[a]] = map[a]; + } + return *this; + } + + /// \brief Set the costs of the arcs. + /// + /// This function sets the costs of the arcs. + /// If it is not used before calling \ref run(), the costs + /// will be set to \c 1 on all arcs. + /// + /// \param map An arc map storing the costs. + /// Its \c Value type must be convertible to the \c Cost type + /// of the algorithm. + /// + /// \return (*this) + template + CostScaling& costMap(const CostMap& map) { + for (ArcIt a(_graph); a != INVALID; ++a) { + _scost[_arc_idf[a]] = map[a]; + _scost[_arc_idb[a]] = -map[a]; + } + return *this; + } + + /// \brief Set the supply values of the nodes. + /// + /// This function sets the supply values of the nodes. + /// If neither this function nor \ref stSupply() is used before + /// calling \ref run(), the supply of each node will be set to zero. + /// + /// \param map A node map storing the supply values. + /// Its \c Value type must be convertible to the \c Value type + /// of the algorithm. + /// + /// \return (*this) + template + CostScaling& supplyMap(const SupplyMap& map) { + for (NodeIt n(_graph); n != INVALID; ++n) { + _supply[_node_id[n]] = map[n]; + } + return *this; + } + + /// \brief Set single source and target nodes and a supply value. + /// + /// This function sets a single source node and a single target node + /// and the required flow value. + /// If neither this function nor \ref supplyMap() is used before + /// calling \ref run(), the supply of each node will be set to zero. + /// + /// Using this function has the same effect as using \ref supplyMap() + /// with a map in which \c k is assigned to \c s, \c -k is + /// assigned to \c t and all other nodes have zero supply value. + /// + /// \param s The source node. + /// \param t The target node. + /// \param k The required amount of flow from node \c s to node \c t + /// (i.e. the supply of \c s and the demand of \c t). + /// + /// \return (*this) + CostScaling& stSupply(const Node& s, const Node& t, Value k) { + for (int i = 0; i != _res_node_num; ++i) { + _supply[i] = 0; + } + _supply[_node_id[s]] = k; + _supply[_node_id[t]] = -k; + return *this; + } + + /// @} + + /// \name Execution control + /// The algorithm can be executed using \ref run(). + + /// @{ + + /// \brief Run the algorithm. + /// + /// This function runs the algorithm. + /// The paramters can be specified using functions \ref lowerMap(), + /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply(). + /// For example, + /// \code + /// CostScaling cs(graph); + /// cs.lowerMap(lower).upperMap(upper).costMap(cost) + /// .supplyMap(sup).run(); + /// \endcode + /// + /// This function can be called more than once. All the given parameters + /// are kept for the next call, unless \ref resetParams() or \ref reset() + /// is used, thus only the modified parameters have to be set again. + /// If the underlying digraph was also modified after the construction + /// of the class (or the last \ref reset() call), then the \ref reset() + /// function must be called. + /// + /// \param method The internal method that will be used in the + /// algorithm. For more information, see \ref Method. + /// \param factor The cost scaling factor. It must be at least two. + /// + /// \return \c INFEASIBLE if no feasible flow exists, + /// \n \c OPTIMAL if the problem has optimal solution + /// (i.e. it is feasible and bounded), and the algorithm has found + /// optimal flow and node potentials (primal and dual solutions), + /// \n \c UNBOUNDED if the digraph contains an arc of negative cost + /// and infinite upper bound. It means that the objective function + /// is unbounded on that arc, however, note that it could actually be + /// bounded over the feasible flows, but this algroithm cannot handle + /// these cases. + /// + /// \see ProblemType, Method + /// \see resetParams(), reset() + ProblemType run(Method method = PARTIAL_AUGMENT, int factor = 16) { + LEMON_ASSERT(factor >= 2, "The scaling factor must be at least 2"); + _alpha = factor; + ProblemType pt = init(); + if (pt != OPTIMAL) return pt; + start(method); + return OPTIMAL; + } + + /// \brief Reset all the parameters that have been given before. + /// + /// This function resets all the paramaters that have been given + /// before using functions \ref lowerMap(), \ref upperMap(), + /// \ref costMap(), \ref supplyMap(), \ref stSupply(). + /// + /// It is useful for multiple \ref run() calls. Basically, all the given + /// parameters are kept for the next \ref run() call, unless + /// \ref resetParams() or \ref reset() is used. + /// If the underlying digraph was also modified after the construction + /// of the class or the last \ref reset() call, then the \ref reset() + /// function must be used, otherwise \ref resetParams() is sufficient. + /// + /// For example, + /// \code + /// CostScaling cs(graph); + /// + /// // First run + /// cs.lowerMap(lower).upperMap(upper).costMap(cost) + /// .supplyMap(sup).run(); + /// + /// // Run again with modified cost map (resetParams() is not called, + /// // so only the cost map have to be set again) + /// cost[e] += 100; + /// cs.costMap(cost).run(); + /// + /// // Run again from scratch using resetParams() + /// // (the lower bounds will be set to zero on all arcs) + /// cs.resetParams(); + /// cs.upperMap(capacity).costMap(cost) + /// .supplyMap(sup).run(); + /// \endcode + /// + /// \return (*this) + /// + /// \see reset(), run() + CostScaling& resetParams() { + for (int i = 0; i != _res_node_num; ++i) { + _supply[i] = 0; + } + int limit = _first_out[_root]; + for (int j = 0; j != limit; ++j) { + _lower[j] = 0; + _upper[j] = INF; + _scost[j] = _forward[j] ? 1 : -1; + } + for (int j = limit; j != _res_arc_num; ++j) { + _lower[j] = 0; + _upper[j] = INF; + _scost[j] = 0; + _scost[_reverse[j]] = 0; + } + _has_lower = false; + return *this; + } + + /// \brief Reset the internal data structures and all the parameters + /// that have been given before. + /// + /// This function resets the internal data structures and all the + /// paramaters that have been given before using functions \ref lowerMap(), + /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply(). + /// + /// It is useful for multiple \ref run() calls. By default, all the given + /// parameters are kept for the next \ref run() call, unless + /// \ref resetParams() or \ref reset() is used. + /// If the underlying digraph was also modified after the construction + /// of the class or the last \ref reset() call, then the \ref reset() + /// function must be used, otherwise \ref resetParams() is sufficient. + /// + /// See \ref resetParams() for examples. + /// + /// \return (*this) + /// + /// \see resetParams(), run() + CostScaling& reset() { + // Resize vectors + _node_num = countNodes(_graph); + _arc_num = countArcs(_graph); + _res_node_num = _node_num + 1; + _res_arc_num = 2 * (_arc_num + _node_num); + _root = _node_num; + + _first_out.resize(_res_node_num + 1); + _forward.resize(_res_arc_num); + _source.resize(_res_arc_num); + _target.resize(_res_arc_num); + _reverse.resize(_res_arc_num); + + _lower.resize(_res_arc_num); + _upper.resize(_res_arc_num); + _scost.resize(_res_arc_num); + _supply.resize(_res_node_num); + + _res_cap.resize(_res_arc_num); + _cost.resize(_res_arc_num); + _pi.resize(_res_node_num); + _excess.resize(_res_node_num); + _next_out.resize(_res_node_num); + + // Copy the graph + int i = 0, j = 0, k = 2 * _arc_num + _node_num; + for (NodeIt n(_graph); n != INVALID; ++n, ++i) { + _node_id[n] = i; + } + i = 0; + for (NodeIt n(_graph); n != INVALID; ++n, ++i) { + _first_out[i] = j; + for (OutArcIt a(_graph, n); a != INVALID; ++a, ++j) { + _arc_idf[a] = j; + _forward[j] = true; + _source[j] = i; + _target[j] = _node_id[_graph.runningNode(a)]; + } + for (InArcIt a(_graph, n); a != INVALID; ++a, ++j) { + _arc_idb[a] = j; + _forward[j] = false; + _source[j] = i; + _target[j] = _node_id[_graph.runningNode(a)]; + } + _forward[j] = false; + _source[j] = i; + _target[j] = _root; + _reverse[j] = k; + _forward[k] = true; + _source[k] = _root; + _target[k] = i; + _reverse[k] = j; + ++j; ++k; + } + _first_out[i] = j; + _first_out[_res_node_num] = k; + for (ArcIt a(_graph); a != INVALID; ++a) { + int fi = _arc_idf[a]; + int bi = _arc_idb[a]; + _reverse[fi] = bi; + _reverse[bi] = fi; + } + + // Reset parameters + resetParams(); + return *this; + } + + /// @} + + /// \name Query Functions + /// The results of the algorithm can be obtained using these + /// functions.\n + /// The \ref run() function must be called before using them. + + /// @{ + + /// \brief Return the total cost of the found flow. + /// + /// This function returns the total cost of the found flow. + /// Its complexity is O(m). + /// + /// \note The return type of the function can be specified as a + /// template parameter. For example, + /// \code + /// cs.totalCost(); + /// \endcode + /// It is useful if the total cost cannot be stored in the \c Cost + /// type of the algorithm, which is the default return type of the + /// function. + /// + /// \pre \ref run() must be called before using this function. + template + Number totalCost() const { + Number c = 0; + for (ArcIt a(_graph); a != INVALID; ++a) { + int i = _arc_idb[a]; + c += static_cast(_res_cap[i]) * + (-static_cast(_scost[i])); + } + return c; + } + +#ifndef DOXYGEN + Cost totalCost() const { + return totalCost(); + } +#endif + + /// \brief Return the flow on the given arc. + /// + /// This function returns the flow on the given arc. + /// + /// \pre \ref run() must be called before using this function. + Value flow(const Arc& a) const { + return _res_cap[_arc_idb[a]]; + } + + /// \brief Copy the flow values (the primal solution) into the + /// given map. + /// + /// This function copies the flow value on each arc into the given + /// map. The \c Value type of the algorithm must be convertible to + /// the \c Value type of the map. + /// + /// \pre \ref run() must be called before using this function. + template + void flowMap(FlowMap &map) const { + for (ArcIt a(_graph); a != INVALID; ++a) { + map.set(a, _res_cap[_arc_idb[a]]); + } + } + + /// \brief Return the potential (dual value) of the given node. + /// + /// This function returns the potential (dual value) of the + /// given node. + /// + /// \pre \ref run() must be called before using this function. + Cost potential(const Node& n) const { + return static_cast(_pi[_node_id[n]]); + } + + /// \brief Copy the potential values (the dual solution) into the + /// given map. + /// + /// This function copies the potential (dual value) of each node + /// into the given map. + /// The \c Cost type of the algorithm must be convertible to the + /// \c Value type of the map. + /// + /// \pre \ref run() must be called before using this function. + template + void potentialMap(PotentialMap &map) const { + for (NodeIt n(_graph); n != INVALID; ++n) { + map.set(n, static_cast(_pi[_node_id[n]])); + } + } + + /// @} + + private: + + // Initialize the algorithm + ProblemType init() { + if (_res_node_num <= 1) return INFEASIBLE; + + // Check the sum of supply values + _sum_supply = 0; + for (int i = 0; i != _root; ++i) { + _sum_supply += _supply[i]; + } + if (_sum_supply > 0) return INFEASIBLE; + + // Check lower and upper bounds + LEMON_DEBUG(checkBoundMaps(), + "Upper bounds must be greater or equal to the lower bounds"); + + + // Initialize vectors + for (int i = 0; i != _res_node_num; ++i) { + _pi[i] = 0; + _excess[i] = _supply[i]; + } + + // Remove infinite upper bounds and check negative arcs + const Value MAX = std::numeric_limits::max(); + int last_out; + if (_has_lower) { + for (int i = 0; i != _root; ++i) { + last_out = _first_out[i+1]; + for (int j = _first_out[i]; j != last_out; ++j) { + if (_forward[j]) { + Value c = _scost[j] < 0 ? _upper[j] : _lower[j]; + if (c >= MAX) return UNBOUNDED; + _excess[i] -= c; + _excess[_target[j]] += c; + } + } + } + } else { + for (int i = 0; i != _root; ++i) { + last_out = _first_out[i+1]; + for (int j = _first_out[i]; j != last_out; ++j) { + if (_forward[j] && _scost[j] < 0) { + Value c = _upper[j]; + if (c >= MAX) return UNBOUNDED; + _excess[i] -= c; + _excess[_target[j]] += c; + } + } + } + } + Value ex, max_cap = 0; + for (int i = 0; i != _res_node_num; ++i) { + ex = _excess[i]; + _excess[i] = 0; + if (ex < 0) max_cap -= ex; + } + for (int j = 0; j != _res_arc_num; ++j) { + if (_upper[j] >= MAX) _upper[j] = max_cap; + } + + // Initialize the large cost vector and the epsilon parameter + _epsilon = 0; + LargeCost lc; + for (int i = 0; i != _root; ++i) { + last_out = _first_out[i+1]; + for (int j = _first_out[i]; j != last_out; ++j) { + lc = static_cast(_scost[j]) * _res_node_num * _alpha; + _cost[j] = lc; + if (lc > _epsilon) _epsilon = lc; + } + } + _epsilon /= _alpha; + + // Initialize maps for Circulation and remove non-zero lower bounds + ConstMap low(0); + typedef typename Digraph::template ArcMap ValueArcMap; + typedef typename Digraph::template NodeMap ValueNodeMap; + ValueArcMap cap(_graph), flow(_graph); + ValueNodeMap sup(_graph); + for (NodeIt n(_graph); n != INVALID; ++n) { + sup[n] = _supply[_node_id[n]]; + } + if (_has_lower) { + for (ArcIt a(_graph); a != INVALID; ++a) { + int j = _arc_idf[a]; + Value c = _lower[j]; + cap[a] = _upper[j] - c; + sup[_graph.source(a)] -= c; + sup[_graph.target(a)] += c; + } + } else { + for (ArcIt a(_graph); a != INVALID; ++a) { + cap[a] = _upper[_arc_idf[a]]; + } + } + + _sup_node_num = 0; + for (NodeIt n(_graph); n != INVALID; ++n) { + if (sup[n] > 0) ++_sup_node_num; + } + + // Find a feasible flow using Circulation + Circulation, ValueArcMap, ValueNodeMap> + circ(_graph, low, cap, sup); + if (!circ.flowMap(flow).run()) return INFEASIBLE; + + // Set residual capacities and handle GEQ supply type + if (_sum_supply < 0) { + for (ArcIt a(_graph); a != INVALID; ++a) { + Value fa = flow[a]; + _res_cap[_arc_idf[a]] = cap[a] - fa; + _res_cap[_arc_idb[a]] = fa; + sup[_graph.source(a)] -= fa; + sup[_graph.target(a)] += fa; + } + for (NodeIt n(_graph); n != INVALID; ++n) { + _excess[_node_id[n]] = sup[n]; + } + for (int a = _first_out[_root]; a != _res_arc_num; ++a) { + int u = _target[a]; + int ra = _reverse[a]; + _res_cap[a] = -_sum_supply + 1; + _res_cap[ra] = -_excess[u]; + _cost[a] = 0; + _cost[ra] = 0; + _excess[u] = 0; + } + } else { + for (ArcIt a(_graph); a != INVALID; ++a) { + Value fa = flow[a]; + _res_cap[_arc_idf[a]] = cap[a] - fa; + _res_cap[_arc_idb[a]] = fa; + } + for (int a = _first_out[_root]; a != _res_arc_num; ++a) { + int ra = _reverse[a]; + _res_cap[a] = 0; + _res_cap[ra] = 0; + _cost[a] = 0; + _cost[ra] = 0; + } + } + + // Initialize data structures for buckets + _max_rank = _alpha * _res_node_num; + _buckets.resize(_max_rank); + _bucket_next.resize(_res_node_num + 1); + _bucket_prev.resize(_res_node_num + 1); + _rank.resize(_res_node_num + 1); + + return OPTIMAL; + } + + // Check if the upper bound is greater than or equal to the lower bound + // on each forward arc. + bool checkBoundMaps() { + for (int j = 0; j != _res_arc_num; ++j) { + if (_forward[j] && _upper[j] < _lower[j]) return false; + } + return true; + } + + // Execute the algorithm and transform the results + void start(Method method) { + const int MAX_PARTIAL_PATH_LENGTH = 4; + + switch (method) { + case PUSH: + startPush(); + break; + case AUGMENT: + startAugment(_res_node_num - 1); + break; + case PARTIAL_AUGMENT: + startAugment(MAX_PARTIAL_PATH_LENGTH); + break; + } + + // Compute node potentials (dual solution) + for (int i = 0; i != _res_node_num; ++i) { + _pi[i] = static_cast(_pi[i] / (_res_node_num * _alpha)); + } + bool optimal = true; + for (int i = 0; optimal && i != _res_node_num; ++i) { + LargeCost pi_i = _pi[i]; + int last_out = _first_out[i+1]; + for (int j = _first_out[i]; j != last_out; ++j) { + if (_res_cap[j] > 0 && _scost[j] + pi_i - _pi[_target[j]] < 0) { + optimal = false; + break; + } + } + } + + if (!optimal) { + // Compute node potentials for the original costs with BellmanFord + // (if it is necessary) + typedef std::pair IntPair; + StaticDigraph sgr; + std::vector arc_vec; + std::vector cost_vec; + LargeCostArcMap cost_map(cost_vec); + + arc_vec.clear(); + cost_vec.clear(); + for (int j = 0; j != _res_arc_num; ++j) { + if (_res_cap[j] > 0) { + int u = _source[j], v = _target[j]; + arc_vec.push_back(IntPair(u, v)); + cost_vec.push_back(_scost[j] + _pi[u] - _pi[v]); + } + } + sgr.build(_res_node_num, arc_vec.begin(), arc_vec.end()); + + typename BellmanFord::Create + bf(sgr, cost_map); + bf.init(0); + bf.start(); + + for (int i = 0; i != _res_node_num; ++i) { + _pi[i] += bf.dist(sgr.node(i)); + } + } + + // Shift potentials to meet the requirements of the GEQ type + // optimality conditions + LargeCost max_pot = _pi[_root]; + for (int i = 0; i != _res_node_num; ++i) { + if (_pi[i] > max_pot) max_pot = _pi[i]; + } + if (max_pot != 0) { + for (int i = 0; i != _res_node_num; ++i) { + _pi[i] -= max_pot; + } + } + + // Handle non-zero lower bounds + if (_has_lower) { + int limit = _first_out[_root]; + for (int j = 0; j != limit; ++j) { + if (_forward[j]) _res_cap[_reverse[j]] += _lower[j]; + } + } + } + + // Initialize a cost scaling phase + void initPhase() { + // Saturate arcs not satisfying the optimality condition + for (int u = 0; u != _res_node_num; ++u) { + int last_out = _first_out[u+1]; + LargeCost pi_u = _pi[u]; + for (int a = _first_out[u]; a != last_out; ++a) { + Value delta = _res_cap[a]; + if (delta > 0) { + int v = _target[a]; + if (_cost[a] + pi_u - _pi[v] < 0) { + _excess[u] -= delta; + _excess[v] += delta; + _res_cap[a] = 0; + _res_cap[_reverse[a]] += delta; + } + } + } + } + + // Find active nodes (i.e. nodes with positive excess) + for (int u = 0; u != _res_node_num; ++u) { + if (_excess[u] > 0) _active_nodes.push_back(u); + } + + // Initialize the next arcs + for (int u = 0; u != _res_node_num; ++u) { + _next_out[u] = _first_out[u]; + } + } + + // Price (potential) refinement heuristic + bool priceRefinement() { + + // Stack for stroing the topological order + IntVector stack(_res_node_num); + int stack_top; + + // Perform phases + while (topologicalSort(stack, stack_top)) { + + // Compute node ranks in the acyclic admissible network and + // store the nodes in buckets + for (int i = 0; i != _res_node_num; ++i) { + _rank[i] = 0; + } + const int bucket_end = _root + 1; + for (int r = 0; r != _max_rank; ++r) { + _buckets[r] = bucket_end; + } + int top_rank = 0; + for ( ; stack_top >= 0; --stack_top) { + int u = stack[stack_top], v; + int rank_u = _rank[u]; + + LargeCost rc, pi_u = _pi[u]; + int last_out = _first_out[u+1]; + for (int a = _first_out[u]; a != last_out; ++a) { + if (_res_cap[a] > 0) { + v = _target[a]; + rc = _cost[a] + pi_u - _pi[v]; + if (rc < 0) { + LargeCost nrc = static_cast((-rc - 0.5) / _epsilon); + if (nrc < LargeCost(_max_rank)) { + int new_rank_v = rank_u + static_cast(nrc); + if (new_rank_v > _rank[v]) { + _rank[v] = new_rank_v; + } + } + } + } + } + + if (rank_u > 0) { + top_rank = std::max(top_rank, rank_u); + int bfirst = _buckets[rank_u]; + _bucket_next[u] = bfirst; + _bucket_prev[bfirst] = u; + _buckets[rank_u] = u; + } + } + + // Check if the current flow is epsilon-optimal + if (top_rank == 0) { + return true; + } + + // Process buckets in top-down order + for (int rank = top_rank; rank > 0; --rank) { + while (_buckets[rank] != bucket_end) { + // Remove the first node from the current bucket + int u = _buckets[rank]; + _buckets[rank] = _bucket_next[u]; + + // Search the outgoing arcs of u + LargeCost rc, pi_u = _pi[u]; + int last_out = _first_out[u+1]; + int v, old_rank_v, new_rank_v; + for (int a = _first_out[u]; a != last_out; ++a) { + if (_res_cap[a] > 0) { + v = _target[a]; + old_rank_v = _rank[v]; + + if (old_rank_v < rank) { + + // Compute the new rank of node v + rc = _cost[a] + pi_u - _pi[v]; + if (rc < 0) { + new_rank_v = rank; + } else { + LargeCost nrc = rc / _epsilon; + new_rank_v = 0; + if (nrc < LargeCost(_max_rank)) { + new_rank_v = rank - 1 - static_cast(nrc); + } + } + + // Change the rank of node v + if (new_rank_v > old_rank_v) { + _rank[v] = new_rank_v; + + // Remove v from its old bucket + if (old_rank_v > 0) { + if (_buckets[old_rank_v] == v) { + _buckets[old_rank_v] = _bucket_next[v]; + } else { + int pv = _bucket_prev[v], nv = _bucket_next[v]; + _bucket_next[pv] = nv; + _bucket_prev[nv] = pv; + } + } + + // Insert v into its new bucket + int nv = _buckets[new_rank_v]; + _bucket_next[v] = nv; + _bucket_prev[nv] = v; + _buckets[new_rank_v] = v; + } + } + } + } + + // Refine potential of node u + _pi[u] -= rank * _epsilon; + } + } + + } + + return false; + } + + // Find and cancel cycles in the admissible network and + // determine topological order using DFS + bool topologicalSort(IntVector &stack, int &stack_top) { + const int MAX_CYCLE_CANCEL = 1; + + BoolVector reached(_res_node_num, false); + BoolVector processed(_res_node_num, false); + IntVector pred(_res_node_num); + for (int i = 0; i != _res_node_num; ++i) { + _next_out[i] = _first_out[i]; + } + stack_top = -1; + + int cycle_cnt = 0; + for (int start = 0; start != _res_node_num; ++start) { + if (reached[start]) continue; + + // Start DFS search from this start node + pred[start] = -1; + int tip = start, v; + while (true) { + // Check the outgoing arcs of the current tip node + reached[tip] = true; + LargeCost pi_tip = _pi[tip]; + int a, last_out = _first_out[tip+1]; + for (a = _next_out[tip]; a != last_out; ++a) { + if (_res_cap[a] > 0) { + v = _target[a]; + if (_cost[a] + pi_tip - _pi[v] < 0) { + if (!reached[v]) { + // A new node is reached + reached[v] = true; + pred[v] = tip; + _next_out[tip] = a; + tip = v; + a = _next_out[tip]; + last_out = _first_out[tip+1]; + break; + } + else if (!processed[v]) { + // A cycle is found + ++cycle_cnt; + _next_out[tip] = a; + + // Find the minimum residual capacity along the cycle + Value d, delta = _res_cap[a]; + int u, delta_node = tip; + for (u = tip; u != v; ) { + u = pred[u]; + d = _res_cap[_next_out[u]]; + if (d <= delta) { + delta = d; + delta_node = u; + } + } + + // Augment along the cycle + _res_cap[a] -= delta; + _res_cap[_reverse[a]] += delta; + for (u = tip; u != v; ) { + u = pred[u]; + int ca = _next_out[u]; + _res_cap[ca] -= delta; + _res_cap[_reverse[ca]] += delta; + } + + // Check the maximum number of cycle canceling + if (cycle_cnt >= MAX_CYCLE_CANCEL) { + return false; + } + + // Roll back search to delta_node + if (delta_node != tip) { + for (u = tip; u != delta_node; u = pred[u]) { + reached[u] = false; + } + tip = delta_node; + a = _next_out[tip] + 1; + last_out = _first_out[tip+1]; + break; + } + } + } + } + } + + // Step back to the previous node + if (a == last_out) { + processed[tip] = true; + stack[++stack_top] = tip; + tip = pred[tip]; + if (tip < 0) { + // Finish DFS from the current start node + break; + } + ++_next_out[tip]; + } + } + + } + + return (cycle_cnt == 0); + } + + // Global potential update heuristic + void globalUpdate() { + const int bucket_end = _root + 1; + + // Initialize buckets + for (int r = 0; r != _max_rank; ++r) { + _buckets[r] = bucket_end; + } + Value total_excess = 0; + int b0 = bucket_end; + for (int i = 0; i != _res_node_num; ++i) { + if (_excess[i] < 0) { + _rank[i] = 0; + _bucket_next[i] = b0; + _bucket_prev[b0] = i; + b0 = i; + } else { + total_excess += _excess[i]; + _rank[i] = _max_rank; + } + } + if (total_excess == 0) return; + _buckets[0] = b0; + + // Search the buckets + int r = 0; + for ( ; r != _max_rank; ++r) { + while (_buckets[r] != bucket_end) { + // Remove the first node from the current bucket + int u = _buckets[r]; + _buckets[r] = _bucket_next[u]; + + // Search the incoming arcs of u + LargeCost pi_u = _pi[u]; + int last_out = _first_out[u+1]; + for (int a = _first_out[u]; a != last_out; ++a) { + int ra = _reverse[a]; + if (_res_cap[ra] > 0) { + int v = _source[ra]; + int old_rank_v = _rank[v]; + if (r < old_rank_v) { + // Compute the new rank of v + LargeCost nrc = (_cost[ra] + _pi[v] - pi_u) / _epsilon; + int new_rank_v = old_rank_v; + if (nrc < LargeCost(_max_rank)) { + new_rank_v = r + 1 + static_cast(nrc); + } + + // Change the rank of v + if (new_rank_v < old_rank_v) { + _rank[v] = new_rank_v; + _next_out[v] = _first_out[v]; + + // Remove v from its old bucket + if (old_rank_v < _max_rank) { + if (_buckets[old_rank_v] == v) { + _buckets[old_rank_v] = _bucket_next[v]; + } else { + int pv = _bucket_prev[v], nv = _bucket_next[v]; + _bucket_next[pv] = nv; + _bucket_prev[nv] = pv; + } + } + + // Insert v into its new bucket + int nv = _buckets[new_rank_v]; + _bucket_next[v] = nv; + _bucket_prev[nv] = v; + _buckets[new_rank_v] = v; + } + } + } + } + + // Finish search if there are no more active nodes + if (_excess[u] > 0) { + total_excess -= _excess[u]; + if (total_excess <= 0) break; + } + } + if (total_excess <= 0) break; + } + + // Relabel nodes + for (int u = 0; u != _res_node_num; ++u) { + int k = std::min(_rank[u], r); + if (k > 0) { + _pi[u] -= _epsilon * k; + _next_out[u] = _first_out[u]; + } + } + } + + /// Execute the algorithm performing augment and relabel operations + void startAugment(int max_length) { + // Paramters for heuristics + const int PRICE_REFINEMENT_LIMIT = 2; + const double GLOBAL_UPDATE_FACTOR = 1.0; + const int global_update_skip = static_cast(GLOBAL_UPDATE_FACTOR * + (_res_node_num + _sup_node_num * _sup_node_num)); + int next_global_update_limit = global_update_skip; + + // Perform cost scaling phases + IntVector path; + BoolVector path_arc(_res_arc_num, false); + int relabel_cnt = 0; + int eps_phase_cnt = 0; + for ( ; _epsilon >= 1; _epsilon = _epsilon < _alpha && _epsilon > 1 ? + 1 : _epsilon / _alpha ) + { + ++eps_phase_cnt; + + // Price refinement heuristic + if (eps_phase_cnt >= PRICE_REFINEMENT_LIMIT) { + if (priceRefinement()) continue; + } + + // Initialize current phase + initPhase(); + + // Perform partial augment and relabel operations + while (true) { + // Select an active node (FIFO selection) + while (_active_nodes.size() > 0 && + _excess[_active_nodes.front()] <= 0) { + _active_nodes.pop_front(); + } + if (_active_nodes.size() == 0) break; + int start = _active_nodes.front(); + + // Find an augmenting path from the start node + int tip = start; + while (int(path.size()) < max_length && _excess[tip] >= 0) { + int u; + LargeCost rc, min_red_cost = std::numeric_limits::max(); + LargeCost pi_tip = _pi[tip]; + int last_out = _first_out[tip+1]; + for (int a = _next_out[tip]; a != last_out; ++a) { + if (_res_cap[a] > 0) { + u = _target[a]; + rc = _cost[a] + pi_tip - _pi[u]; + if (rc < 0) { + path.push_back(a); + _next_out[tip] = a; + if (path_arc[a]) { + goto augment; // a cycle is found, stop path search + } + tip = u; + path_arc[a] = true; + goto next_step; + } + else if (rc < min_red_cost) { + min_red_cost = rc; + } + } + } + + // Relabel tip node + if (tip != start) { + int ra = _reverse[path.back()]; + min_red_cost = + std::min(min_red_cost, _cost[ra] + pi_tip - _pi[_target[ra]]); + } + last_out = _next_out[tip]; + for (int a = _first_out[tip]; a != last_out; ++a) { + if (_res_cap[a] > 0) { + rc = _cost[a] + pi_tip - _pi[_target[a]]; + if (rc < min_red_cost) { + min_red_cost = rc; + } + } + } + _pi[tip] -= min_red_cost + _epsilon; + _next_out[tip] = _first_out[tip]; + ++relabel_cnt; + + // Step back + if (tip != start) { + int pa = path.back(); + path_arc[pa] = false; + tip = _source[pa]; + path.pop_back(); + } + + next_step: ; + } + + // Augment along the found path (as much flow as possible) + augment: + Value delta; + int pa, u, v = start; + for (int i = 0; i != int(path.size()); ++i) { + pa = path[i]; + u = v; + v = _target[pa]; + path_arc[pa] = false; + delta = std::min(_res_cap[pa], _excess[u]); + _res_cap[pa] -= delta; + _res_cap[_reverse[pa]] += delta; + _excess[u] -= delta; + _excess[v] += delta; + if (_excess[v] > 0 && _excess[v] <= delta) { + _active_nodes.push_back(v); + } + } + path.clear(); + + // Global update heuristic + if (relabel_cnt >= next_global_update_limit) { + globalUpdate(); + next_global_update_limit += global_update_skip; + } + } + + } + + } + + /// Execute the algorithm performing push and relabel operations + void startPush() { + // Paramters for heuristics + const int PRICE_REFINEMENT_LIMIT = 2; + const double GLOBAL_UPDATE_FACTOR = 2.0; + + const int global_update_skip = static_cast(GLOBAL_UPDATE_FACTOR * + (_res_node_num + _sup_node_num * _sup_node_num)); + int next_global_update_limit = global_update_skip; + + // Perform cost scaling phases + BoolVector hyper(_res_node_num, false); + LargeCostVector hyper_cost(_res_node_num); + int relabel_cnt = 0; + int eps_phase_cnt = 0; + for ( ; _epsilon >= 1; _epsilon = _epsilon < _alpha && _epsilon > 1 ? + 1 : _epsilon / _alpha ) + { + ++eps_phase_cnt; + + // Price refinement heuristic + if (eps_phase_cnt >= PRICE_REFINEMENT_LIMIT) { + if (priceRefinement()) continue; + } + + // Initialize current phase + initPhase(); + + // Perform push and relabel operations + while (_active_nodes.size() > 0) { + LargeCost min_red_cost, rc, pi_n; + Value delta; + int n, t, a, last_out = _res_arc_num; + + next_node: + // Select an active node (FIFO selection) + n = _active_nodes.front(); + last_out = _first_out[n+1]; + pi_n = _pi[n]; + + // Perform push operations if there are admissible arcs + if (_excess[n] > 0) { + for (a = _next_out[n]; a != last_out; ++a) { + if (_res_cap[a] > 0 && + _cost[a] + pi_n - _pi[_target[a]] < 0) { + delta = std::min(_res_cap[a], _excess[n]); + t = _target[a]; + + // Push-look-ahead heuristic + Value ahead = -_excess[t]; + int last_out_t = _first_out[t+1]; + LargeCost pi_t = _pi[t]; + for (int ta = _next_out[t]; ta != last_out_t; ++ta) { + if (_res_cap[ta] > 0 && + _cost[ta] + pi_t - _pi[_target[ta]] < 0) + ahead += _res_cap[ta]; + if (ahead >= delta) break; + } + if (ahead < 0) ahead = 0; + + // Push flow along the arc + if (ahead < delta && !hyper[t]) { + _res_cap[a] -= ahead; + _res_cap[_reverse[a]] += ahead; + _excess[n] -= ahead; + _excess[t] += ahead; + _active_nodes.push_front(t); + hyper[t] = true; + hyper_cost[t] = _cost[a] + pi_n - pi_t; + _next_out[n] = a; + goto next_node; + } else { + _res_cap[a] -= delta; + _res_cap[_reverse[a]] += delta; + _excess[n] -= delta; + _excess[t] += delta; + if (_excess[t] > 0 && _excess[t] <= delta) + _active_nodes.push_back(t); + } + + if (_excess[n] == 0) { + _next_out[n] = a; + goto remove_nodes; + } + } + } + _next_out[n] = a; + } + + // Relabel the node if it is still active (or hyper) + if (_excess[n] > 0 || hyper[n]) { + min_red_cost = hyper[n] ? -hyper_cost[n] : + std::numeric_limits::max(); + for (int a = _first_out[n]; a != last_out; ++a) { + if (_res_cap[a] > 0) { + rc = _cost[a] + pi_n - _pi[_target[a]]; + if (rc < min_red_cost) { + min_red_cost = rc; + } + } + } + _pi[n] -= min_red_cost + _epsilon; + _next_out[n] = _first_out[n]; + hyper[n] = false; + ++relabel_cnt; + } + + // Remove nodes that are not active nor hyper + remove_nodes: + while ( _active_nodes.size() > 0 && + _excess[_active_nodes.front()] <= 0 && + !hyper[_active_nodes.front()] ) { + _active_nodes.pop_front(); + } + + // Global update heuristic + if (relabel_cnt >= next_global_update_limit) { + globalUpdate(); + for (int u = 0; u != _res_node_num; ++u) + hyper[u] = false; + next_global_update_limit += global_update_skip; + } + } + } + } + + }; //class CostScaling + + ///@} + +} //namespace lemon + +#endif //LEMON_COST_SCALING_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/counter.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/counter.h new file mode 100644 index 00000000000..a0049918929 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/counter.h @@ -0,0 +1,249 @@ +/* -*- 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_COUNTER_H +#define LEMON_COUNTER_H + +#include +#include + +///\ingroup timecount +///\file +///\brief Tools for counting steps and events + +namespace lemon +{ + + template class _NoSubCounter; + + template + class _SubCounter + { + P &_parent; + std::string _title; + std::ostream &_os; + int count; + public: + + typedef _SubCounter<_SubCounter

> SubCounter; + typedef _NoSubCounter<_SubCounter

> NoSubCounter; + + _SubCounter(P &parent) + : _parent(parent), _title(), _os(std::cerr), count(0) {} + _SubCounter(P &parent,std::string title,std::ostream &os=std::cerr) + : _parent(parent), _title(title), _os(os), count(0) {} + _SubCounter(P &parent,const char *title,std::ostream &os=std::cerr) + : _parent(parent), _title(title), _os(os), count(0) {} + ~_SubCounter() { + _os << _title << count < + class _NoSubCounter + { + P &_parent; + public: + typedef _NoSubCounter<_NoSubCounter

> SubCounter; + typedef _NoSubCounter<_NoSubCounter

> NoSubCounter; + + _NoSubCounter(P &parent) :_parent(parent) {} + _NoSubCounter(P &parent,std::string,std::ostream &) + :_parent(parent) {} + _NoSubCounter(P &parent,std::string) + :_parent(parent) {} + _NoSubCounter(P &parent,const char *,std::ostream &) + :_parent(parent) {} + _NoSubCounter(P &parent,const char *) + :_parent(parent) {} + ~_NoSubCounter() {} + _NoSubCounter &operator++() { ++_parent; return *this;} + int operator++(int) { _parent++; return 0;} + _NoSubCounter &operator--() { --_parent; return *this;} + int operator--(int) { _parent--; return 0;} + _NoSubCounter &operator+=(int c) { _parent+=c; return *this;} + _NoSubCounter &operator-=(int c) { _parent-=c; return *this;} + operator int() {return 0;} + }; + + + /// \addtogroup timecount + /// @{ + + /// A counter class + + /// This class makes it easier to count certain events (e.g. for debug + /// reasons). + /// You can increment or decrement the counter using \c operator++, + /// \c operator--, \c operator+= and \c operator-=. You can also + /// define subcounters for the different phases of the algorithm or + /// for different types of operations. + /// A report containing the given title and the value of the counter + /// is automatically printed on destruction. + /// + /// The following example shows the usage of counters and subcounters. + /// \code + /// // Bubble sort + /// std::vector v; + /// ... + /// Counter op("Operations: "); + /// Counter::SubCounter as(op, "Assignments: "); + /// Counter::SubCounter co(op, "Comparisons: "); + /// 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; // three assignments + /// } + /// ++co; // one comparison + /// } + /// } + /// \endcode + /// + /// This code prints out something like that: + /// \code + /// Comparisons: 45 + /// Assignments: 57 + /// Operations: 102 + /// \endcode + /// + /// \sa NoCounter + class Counter + { + std::string _title; + std::ostream &_os; + int count; + public: + + /// SubCounter class + + /// This class can be used to setup subcounters for a \ref Counter + /// to have finer reports. A subcounter provides exactly the same + /// operations as the main \ref Counter, but it also increments and + /// decrements the value of its parent. + /// Subcounters can also have subcounters. + /// + /// The parent counter must be given as the first parameter of the + /// constructor. Apart from that a title and an \c ostream object + /// can also be given just like for the main \ref Counter. + /// + /// A report containing the given title and the value of the + /// subcounter is automatically printed on destruction. If you + /// would like to turn off this report, use \ref NoSubCounter + /// instead. + /// + /// \sa NoSubCounter + typedef _SubCounter SubCounter; + + /// SubCounter class without printing report on destruction + + /// This class can be used to setup subcounters for a \ref Counter. + /// It is the same as \ref SubCounter but it does not print report + /// on destruction. (It modifies the value of its parent, so 'No' + /// only means 'do not print'.) + /// + /// Replacing \ref SubCounter "SubCounter"s with \ref NoSubCounter + /// "NoSubCounter"s makes it possible to turn off reporting + /// subcounter values without actually removing the definitions + /// and the increment or decrement operators. + /// + /// \sa SubCounter + typedef _NoSubCounter NoSubCounter; + + /// Constructor. + Counter() : _title(), _os(std::cerr), count(0) {} + /// Constructor. + Counter(std::string title,std::ostream &os=std::cerr) + : _title(title), _os(os), count(0) {} + /// Constructor. + Counter(const char *title,std::ostream &os=std::cerr) + : _title(title), _os(os), count(0) {} + /// Destructor. Prints the given title and the value of the counter. + ~Counter() { + _os << _title << count < SubCounter; + typedef _NoSubCounter NoSubCounter; + + NoCounter() {} + NoCounter(std::string,std::ostream &) {} + NoCounter(const char *,std::ostream &) {} + NoCounter(std::string) {} + NoCounter(const char *) {} + NoCounter &operator++() { return *this; } + int operator++(int) { return 0; } + NoCounter &operator--() { return *this; } + int operator--(int) { return 0; } + NoCounter &operator+=(int) { return *this;} + NoCounter &operator-=(int) { return *this;} + void reset(int) {} + void reset() {} + operator int() {return 0;} + }; + + ///@} +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/cplex.cc b/extern/quadriflow/3rd/lemon-1.3.1/lemon/cplex.cc new file mode 100644 index 00000000000..029a3efc500 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/cplex.cc @@ -0,0 +1,994 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 +#include +#include + +#include + +extern "C" { +#include +} + + +///\file +///\brief Implementation of the LEMON-CPLEX lp solver interface. +namespace lemon { + + CplexEnv::LicenseError::LicenseError(int status) { + if (!CPXgeterrorstring(0, status, _message)) { + std::strcpy(_message, "Cplex unknown error"); + } + } + + CplexEnv::CplexEnv() { + int status; + _cnt = new int; + (*_cnt) = 1; + _env = CPXopenCPLEX(&status); + if (_env == 0) { + delete _cnt; + _cnt = 0; + throw LicenseError(status); + } + } + + CplexEnv::CplexEnv(const CplexEnv& other) { + _env = other._env; + _cnt = other._cnt; + ++(*_cnt); + } + + CplexEnv& CplexEnv::operator=(const CplexEnv& other) { + _env = other._env; + _cnt = other._cnt; + ++(*_cnt); + return *this; + } + + CplexEnv::~CplexEnv() { + --(*_cnt); + if (*_cnt == 0) { + delete _cnt; + CPXcloseCPLEX(&_env); + } + } + + CplexBase::CplexBase() : LpBase() { + int status; + _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem"); + messageLevel(MESSAGE_NOTHING); + } + + CplexBase::CplexBase(const CplexEnv& env) + : LpBase(), _env(env) { + int status; + _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem"); + messageLevel(MESSAGE_NOTHING); + } + + CplexBase::CplexBase(const CplexBase& cplex) + : LpBase() { + int status; + _prob = CPXcloneprob(cplexEnv(), cplex._prob, &status); + rows = cplex.rows; + cols = cplex.cols; + messageLevel(MESSAGE_NOTHING); + } + + CplexBase::~CplexBase() { + CPXfreeprob(cplexEnv(),&_prob); + } + + int CplexBase::_addCol() { + int i = CPXgetnumcols(cplexEnv(), _prob); + double lb = -INF, ub = INF; + CPXnewcols(cplexEnv(), _prob, 1, 0, &lb, &ub, 0, 0); + return i; + } + + + int CplexBase::_addRow() { + int i = CPXgetnumrows(cplexEnv(), _prob); + const double ub = INF; + const char s = 'L'; + CPXnewrows(cplexEnv(), _prob, 1, &ub, &s, 0, 0); + return i; + } + + int CplexBase::_addRow(Value lb, ExprIterator b, + ExprIterator e, Value ub) { + int i = CPXgetnumrows(cplexEnv(), _prob); + if (lb == -INF) { + const char s = 'L'; + CPXnewrows(cplexEnv(), _prob, 1, &ub, &s, 0, 0); + } else if (ub == INF) { + const char s = 'G'; + CPXnewrows(cplexEnv(), _prob, 1, &lb, &s, 0, 0); + } else if (lb == ub){ + const char s = 'E'; + CPXnewrows(cplexEnv(), _prob, 1, &lb, &s, 0, 0); + } else { + const char s = 'R'; + double len = ub - lb; + CPXnewrows(cplexEnv(), _prob, 1, &lb, &s, &len, 0); + } + + std::vector indices; + std::vector rowlist; + std::vector values; + + for(ExprIterator it=b; it!=e; ++it) { + indices.push_back(it->first); + values.push_back(it->second); + rowlist.push_back(i); + } + + CPXchgcoeflist(cplexEnv(), _prob, values.size(), + &rowlist.front(), &indices.front(), &values.front()); + + return i; + } + + void CplexBase::_eraseCol(int i) { + CPXdelcols(cplexEnv(), _prob, i, i); + } + + void CplexBase::_eraseRow(int i) { + CPXdelrows(cplexEnv(), _prob, i, i); + } + + void CplexBase::_eraseColId(int i) { + cols.eraseIndex(i); + cols.shiftIndices(i); + } + void CplexBase::_eraseRowId(int i) { + rows.eraseIndex(i); + rows.shiftIndices(i); + } + + void CplexBase::_getColName(int col, std::string &name) const { + int size; + CPXgetcolname(cplexEnv(), _prob, 0, 0, 0, &size, col, col); + if (size == 0) { + name.clear(); + return; + } + + size *= -1; + std::vector buf(size); + char *cname; + int tmp; + CPXgetcolname(cplexEnv(), _prob, &cname, &buf.front(), size, + &tmp, col, col); + name = cname; + } + + void CplexBase::_setColName(int col, const std::string &name) { + char *cname; + cname = const_cast(name.c_str()); + CPXchgcolname(cplexEnv(), _prob, 1, &col, &cname); + } + + int CplexBase::_colByName(const std::string& name) const { + int index; + if (CPXgetcolindex(cplexEnv(), _prob, + const_cast(name.c_str()), &index) == 0) { + return index; + } + return -1; + } + + void CplexBase::_getRowName(int row, std::string &name) const { + int size; + CPXgetrowname(cplexEnv(), _prob, 0, 0, 0, &size, row, row); + if (size == 0) { + name.clear(); + return; + } + + size *= -1; + std::vector buf(size); + char *cname; + int tmp; + CPXgetrowname(cplexEnv(), _prob, &cname, &buf.front(), size, + &tmp, row, row); + name = cname; + } + + void CplexBase::_setRowName(int row, const std::string &name) { + char *cname; + cname = const_cast(name.c_str()); + CPXchgrowname(cplexEnv(), _prob, 1, &row, &cname); + } + + int CplexBase::_rowByName(const std::string& name) const { + int index; + if (CPXgetrowindex(cplexEnv(), _prob, + const_cast(name.c_str()), &index) == 0) { + return index; + } + return -1; + } + + void CplexBase::_setRowCoeffs(int i, ExprIterator b, + ExprIterator e) + { + std::vector indices; + std::vector rowlist; + std::vector values; + + for(ExprIterator it=b; it!=e; ++it) { + indices.push_back(it->first); + values.push_back(it->second); + rowlist.push_back(i); + } + + CPXchgcoeflist(cplexEnv(), _prob, values.size(), + &rowlist.front(), &indices.front(), &values.front()); + } + + void CplexBase::_getRowCoeffs(int i, InsertIterator b) const { + int tmp1, tmp2, tmp3, length; + CPXgetrows(cplexEnv(), _prob, &tmp1, &tmp2, 0, 0, 0, &length, i, i); + + length = -length; + std::vector indices(length); + std::vector values(length); + + CPXgetrows(cplexEnv(), _prob, &tmp1, &tmp2, + &indices.front(), &values.front(), + length, &tmp3, i, i); + + for (int i = 0; i < length; ++i) { + *b = std::make_pair(indices[i], values[i]); + ++b; + } + } + + void CplexBase::_setColCoeffs(int i, ExprIterator b, ExprIterator e) { + std::vector indices; + std::vector collist; + std::vector values; + + for(ExprIterator it=b; it!=e; ++it) { + indices.push_back(it->first); + values.push_back(it->second); + collist.push_back(i); + } + + CPXchgcoeflist(cplexEnv(), _prob, values.size(), + &indices.front(), &collist.front(), &values.front()); + } + + void CplexBase::_getColCoeffs(int i, InsertIterator b) const { + + int tmp1, tmp2, tmp3, length; + CPXgetcols(cplexEnv(), _prob, &tmp1, &tmp2, 0, 0, 0, &length, i, i); + + length = -length; + std::vector indices(length); + std::vector values(length); + + CPXgetcols(cplexEnv(), _prob, &tmp1, &tmp2, + &indices.front(), &values.front(), + length, &tmp3, i, i); + + for (int i = 0; i < length; ++i) { + *b = std::make_pair(indices[i], values[i]); + ++b; + } + + } + + void CplexBase::_setCoeff(int row, int col, Value value) { + CPXchgcoef(cplexEnv(), _prob, row, col, value); + } + + CplexBase::Value CplexBase::_getCoeff(int row, int col) const { + CplexBase::Value value; + CPXgetcoef(cplexEnv(), _prob, row, col, &value); + return value; + } + + void CplexBase::_setColLowerBound(int i, Value value) { + const char s = 'L'; + CPXchgbds(cplexEnv(), _prob, 1, &i, &s, &value); + } + + CplexBase::Value CplexBase::_getColLowerBound(int i) const { + CplexBase::Value res; + CPXgetlb(cplexEnv(), _prob, &res, i, i); + return res <= -CPX_INFBOUND ? -INF : res; + } + + void CplexBase::_setColUpperBound(int i, Value value) + { + const char s = 'U'; + CPXchgbds(cplexEnv(), _prob, 1, &i, &s, &value); + } + + CplexBase::Value CplexBase::_getColUpperBound(int i) const { + CplexBase::Value res; + CPXgetub(cplexEnv(), _prob, &res, i, i); + return res >= CPX_INFBOUND ? INF : res; + } + + CplexBase::Value CplexBase::_getRowLowerBound(int i) const { + char s; + CPXgetsense(cplexEnv(), _prob, &s, i, i); + CplexBase::Value res; + + switch (s) { + case 'G': + case 'R': + case 'E': + CPXgetrhs(cplexEnv(), _prob, &res, i, i); + return res <= -CPX_INFBOUND ? -INF : res; + default: + return -INF; + } + } + + CplexBase::Value CplexBase::_getRowUpperBound(int i) const { + char s; + CPXgetsense(cplexEnv(), _prob, &s, i, i); + CplexBase::Value res; + + switch (s) { + case 'L': + case 'E': + CPXgetrhs(cplexEnv(), _prob, &res, i, i); + return res >= CPX_INFBOUND ? INF : res; + case 'R': + CPXgetrhs(cplexEnv(), _prob, &res, i, i); + { + double rng; + CPXgetrngval(cplexEnv(), _prob, &rng, i, i); + res += rng; + } + return res >= CPX_INFBOUND ? INF : res; + default: + return INF; + } + } + + //This is easier to implement + void CplexBase::_set_row_bounds(int i, Value lb, Value ub) { + if (lb == -INF) { + const char s = 'L'; + CPXchgsense(cplexEnv(), _prob, 1, &i, &s); + CPXchgrhs(cplexEnv(), _prob, 1, &i, &ub); + } else if (ub == INF) { + const char s = 'G'; + CPXchgsense(cplexEnv(), _prob, 1, &i, &s); + CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb); + } else if (lb == ub){ + const char s = 'E'; + CPXchgsense(cplexEnv(), _prob, 1, &i, &s); + CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb); + } else { + const char s = 'R'; + CPXchgsense(cplexEnv(), _prob, 1, &i, &s); + CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb); + double len = ub - lb; + CPXchgrngval(cplexEnv(), _prob, 1, &i, &len); + } + } + + void CplexBase::_setRowLowerBound(int i, Value lb) + { + LEMON_ASSERT(lb != INF, "Invalid bound"); + _set_row_bounds(i, lb, CplexBase::_getRowUpperBound(i)); + } + + void CplexBase::_setRowUpperBound(int i, Value ub) + { + + LEMON_ASSERT(ub != -INF, "Invalid bound"); + _set_row_bounds(i, CplexBase::_getRowLowerBound(i), ub); + } + + void CplexBase::_setObjCoeffs(ExprIterator b, ExprIterator e) + { + std::vector indices; + std::vector values; + for(ExprIterator it=b; it!=e; ++it) { + indices.push_back(it->first); + values.push_back(it->second); + } + CPXchgobj(cplexEnv(), _prob, values.size(), + &indices.front(), &values.front()); + + } + + void CplexBase::_getObjCoeffs(InsertIterator b) const + { + int num = CPXgetnumcols(cplexEnv(), _prob); + std::vector x(num); + + CPXgetobj(cplexEnv(), _prob, &x.front(), 0, num - 1); + for (int i = 0; i < num; ++i) { + if (x[i] != 0.0) { + *b = std::make_pair(i, x[i]); + ++b; + } + } + } + + void CplexBase::_setObjCoeff(int i, Value obj_coef) + { + CPXchgobj(cplexEnv(), _prob, 1, &i, &obj_coef); + } + + CplexBase::Value CplexBase::_getObjCoeff(int i) const + { + Value x; + CPXgetobj(cplexEnv(), _prob, &x, i, i); + return x; + } + + void CplexBase::_setSense(CplexBase::Sense sense) { + switch (sense) { + case MIN: + CPXchgobjsen(cplexEnv(), _prob, CPX_MIN); + break; + case MAX: + CPXchgobjsen(cplexEnv(), _prob, CPX_MAX); + break; + } + } + + CplexBase::Sense CplexBase::_getSense() const { + switch (CPXgetobjsen(cplexEnv(), _prob)) { + case CPX_MIN: + return MIN; + case CPX_MAX: + return MAX; + default: + LEMON_ASSERT(false, "Invalid sense"); + return CplexBase::Sense(); + } + } + + void CplexBase::_clear() { + CPXfreeprob(cplexEnv(),&_prob); + int status; + _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem"); + } + + void CplexBase::_messageLevel(MessageLevel level) { + switch (level) { + case MESSAGE_NOTHING: + _message_enabled = false; + break; + case MESSAGE_ERROR: + case MESSAGE_WARNING: + case MESSAGE_NORMAL: + case MESSAGE_VERBOSE: + _message_enabled = true; + break; + } + } + + void CplexBase::_applyMessageLevel() { + CPXsetintparam(cplexEnv(), CPX_PARAM_SCRIND, + _message_enabled ? CPX_ON : CPX_OFF); + } + + void CplexBase::_write(std::string file, std::string format) const + { + if(format == "MPS" || format == "LP") + CPXwriteprob(cplexEnv(), cplexLp(), file.c_str(), format.c_str()); + else if(format == "SOL") + CPXsolwrite(cplexEnv(), cplexLp(), file.c_str()); + else throw UnsupportedFormatError(format); + } + + + + // CplexLp members + + CplexLp::CplexLp() + : LpBase(), LpSolver(), CplexBase() {} + + CplexLp::CplexLp(const CplexEnv& env) + : LpBase(), LpSolver(), CplexBase(env) {} + + CplexLp::CplexLp(const CplexLp& other) + : LpBase(), LpSolver(), CplexBase(other) {} + + CplexLp::~CplexLp() {} + + CplexLp* CplexLp::newSolver() const { return new CplexLp; } + CplexLp* CplexLp::cloneSolver() const {return new CplexLp(*this); } + + const char* CplexLp::_solverName() const { return "CplexLp"; } + + void CplexLp::_clear_temporals() { + _col_status.clear(); + _row_status.clear(); + _primal_ray.clear(); + _dual_ray.clear(); + } + + // The routine returns zero unless an error occurred during the + // optimization. Examples of errors include exhausting available + // memory (CPXERR_NO_MEMORY) or encountering invalid data in the + // CPLEX problem object (CPXERR_NO_PROBLEM). Exceeding a + // user-specified CPLEX limit, or proving the model infeasible or + // unbounded, are not considered errors. Note that a zero return + // value does not necessarily mean that a solution exists. Use query + // routines CPXsolninfo, CPXgetstat, and CPXsolution to obtain + // further information about the status of the optimization. + CplexLp::SolveExitStatus CplexLp::convertStatus(int status) { +#if CPX_VERSION >= 800 + if (status == 0) { + switch (CPXgetstat(cplexEnv(), _prob)) { + case CPX_STAT_OPTIMAL: + case CPX_STAT_INFEASIBLE: + case CPX_STAT_UNBOUNDED: + return SOLVED; + default: + return UNSOLVED; + } + } else { + return UNSOLVED; + } +#else + if (status == 0) { + //We want to exclude some cases + switch (CPXgetstat(cplexEnv(), _prob)) { + case CPX_OBJ_LIM: + case CPX_IT_LIM_FEAS: + case CPX_IT_LIM_INFEAS: + case CPX_TIME_LIM_FEAS: + case CPX_TIME_LIM_INFEAS: + return UNSOLVED; + default: + return SOLVED; + } + } else { + return UNSOLVED; + } +#endif + } + + CplexLp::SolveExitStatus CplexLp::_solve() { + _clear_temporals(); + _applyMessageLevel(); + return convertStatus(CPXlpopt(cplexEnv(), _prob)); + } + + CplexLp::SolveExitStatus CplexLp::solvePrimal() { + _clear_temporals(); + _applyMessageLevel(); + return convertStatus(CPXprimopt(cplexEnv(), _prob)); + } + + CplexLp::SolveExitStatus CplexLp::solveDual() { + _clear_temporals(); + _applyMessageLevel(); + return convertStatus(CPXdualopt(cplexEnv(), _prob)); + } + + CplexLp::SolveExitStatus CplexLp::solveBarrier() { + _clear_temporals(); + _applyMessageLevel(); + return convertStatus(CPXbaropt(cplexEnv(), _prob)); + } + + CplexLp::Value CplexLp::_getPrimal(int i) const { + Value x; + CPXgetx(cplexEnv(), _prob, &x, i, i); + return x; + } + + CplexLp::Value CplexLp::_getDual(int i) const { + Value y; + CPXgetpi(cplexEnv(), _prob, &y, i, i); + return y; + } + + CplexLp::Value CplexLp::_getPrimalValue() const { + Value objval; + CPXgetobjval(cplexEnv(), _prob, &objval); + return objval; + } + + CplexLp::VarStatus CplexLp::_getColStatus(int i) const { + if (_col_status.empty()) { + _col_status.resize(CPXgetnumcols(cplexEnv(), _prob)); + CPXgetbase(cplexEnv(), _prob, &_col_status.front(), 0); + } + switch (_col_status[i]) { + case CPX_BASIC: + return BASIC; + case CPX_FREE_SUPER: + return FREE; + case CPX_AT_LOWER: + return LOWER; + case CPX_AT_UPPER: + return UPPER; + default: + LEMON_ASSERT(false, "Wrong column status"); + return CplexLp::VarStatus(); + } + } + + CplexLp::VarStatus CplexLp::_getRowStatus(int i) const { + if (_row_status.empty()) { + _row_status.resize(CPXgetnumrows(cplexEnv(), _prob)); + CPXgetbase(cplexEnv(), _prob, 0, &_row_status.front()); + } + switch (_row_status[i]) { + case CPX_BASIC: + return BASIC; + case CPX_AT_LOWER: + { + char s; + CPXgetsense(cplexEnv(), _prob, &s, i, i); + return s != 'L' ? LOWER : UPPER; + } + case CPX_AT_UPPER: + return UPPER; + default: + LEMON_ASSERT(false, "Wrong row status"); + return CplexLp::VarStatus(); + } + } + + CplexLp::Value CplexLp::_getPrimalRay(int i) const { + if (_primal_ray.empty()) { + _primal_ray.resize(CPXgetnumcols(cplexEnv(), _prob)); + CPXgetray(cplexEnv(), _prob, &_primal_ray.front()); + } + return _primal_ray[i]; + } + + CplexLp::Value CplexLp::_getDualRay(int i) const { + if (_dual_ray.empty()) { + + } + return _dual_ray[i]; + } + + // Cplex 7.0 status values + // This table lists the statuses, returned by the CPXgetstat() + // routine, for solutions to LP problems or mixed integer problems. If + // no solution exists, the return value is zero. + + // For Simplex, Barrier + // 1 CPX_OPTIMAL + // Optimal solution found + // 2 CPX_INFEASIBLE + // Problem infeasible + // 3 CPX_UNBOUNDED + // Problem unbounded + // 4 CPX_OBJ_LIM + // Objective limit exceeded in Phase II + // 5 CPX_IT_LIM_FEAS + // Iteration limit exceeded in Phase II + // 6 CPX_IT_LIM_INFEAS + // Iteration limit exceeded in Phase I + // 7 CPX_TIME_LIM_FEAS + // Time limit exceeded in Phase II + // 8 CPX_TIME_LIM_INFEAS + // Time limit exceeded in Phase I + // 9 CPX_NUM_BEST_FEAS + // Problem non-optimal, singularities in Phase II + // 10 CPX_NUM_BEST_INFEAS + // Problem non-optimal, singularities in Phase I + // 11 CPX_OPTIMAL_INFEAS + // Optimal solution found, unscaled infeasibilities + // 12 CPX_ABORT_FEAS + // Aborted in Phase II + // 13 CPX_ABORT_INFEAS + // Aborted in Phase I + // 14 CPX_ABORT_DUAL_INFEAS + // Aborted in barrier, dual infeasible + // 15 CPX_ABORT_PRIM_INFEAS + // Aborted in barrier, primal infeasible + // 16 CPX_ABORT_PRIM_DUAL_INFEAS + // Aborted in barrier, primal and dual infeasible + // 17 CPX_ABORT_PRIM_DUAL_FEAS + // Aborted in barrier, primal and dual feasible + // 18 CPX_ABORT_CROSSOVER + // Aborted in crossover + // 19 CPX_INForUNBD + // Infeasible or unbounded + // 20 CPX_PIVOT + // User pivot used + // + // Pending return values + // ??case CPX_ABORT_DUAL_INFEAS + // ??case CPX_ABORT_CROSSOVER + // ??case CPX_INForUNBD + // ??case CPX_PIVOT + + //Some more interesting stuff: + + // CPX_PARAM_PROBMETHOD 1062 int LPMETHOD + // 0 Automatic + // 1 Primal Simplex + // 2 Dual Simplex + // 3 Network Simplex + // 4 Standard Barrier + // Default: 0 + // Description: Method for linear optimization. + // Determines which algorithm is used when CPXlpopt() (or "optimize" + // in the Interactive Optimizer) is called. Currently the behavior of + // the "Automatic" setting is that CPLEX simply invokes the dual + // simplex method, but this capability may be expanded in the future + // so that CPLEX chooses the method based on problem characteristics +#if CPX_VERSION < 900 + void statusSwitch(CPXENVptr cplexEnv(),int& stat){ + int lpmethod; + CPXgetintparam (cplexEnv(),CPX_PARAM_PROBMETHOD,&lpmethod); + if (lpmethod==2){ + if (stat==CPX_UNBOUNDED){ + stat=CPX_INFEASIBLE; + } + else{ + if (stat==CPX_INFEASIBLE) + stat=CPX_UNBOUNDED; + } + } + } +#else + void statusSwitch(CPXENVptr,int&){} +#endif + + CplexLp::ProblemType CplexLp::_getPrimalType() const { + // Unboundedness not treated well: the following is from cplex 9.0 doc + // About Unboundedness + + // The treatment of models that are unbounded involves a few + // subtleties. Specifically, a declaration of unboundedness means that + // ILOG CPLEX has determined that the model has an unbounded + // ray. Given any feasible solution x with objective z, a multiple of + // the unbounded ray can be added to x to give a feasible solution + // with objective z-1 (or z+1 for maximization models). Thus, if a + // feasible solution exists, then the optimal objective is + // unbounded. Note that ILOG CPLEX has not necessarily concluded that + // a feasible solution exists. Users can call the routine CPXsolninfo + // to determine whether ILOG CPLEX has also concluded that the model + // has a feasible solution. + + int stat = CPXgetstat(cplexEnv(), _prob); +#if CPX_VERSION >= 800 + switch (stat) + { + case CPX_STAT_OPTIMAL: + return OPTIMAL; + case CPX_STAT_UNBOUNDED: + return UNBOUNDED; + case CPX_STAT_INFEASIBLE: + return INFEASIBLE; + default: + return UNDEFINED; + } +#else + statusSwitch(cplexEnv(),stat); + //CPXgetstat(cplexEnv(), _prob); + switch (stat) { + case 0: + return UNDEFINED; //Undefined + case CPX_OPTIMAL://Optimal + return OPTIMAL; + case CPX_UNBOUNDED://Unbounded + return INFEASIBLE;//In case of dual simplex + //return UNBOUNDED; + case CPX_INFEASIBLE://Infeasible + // case CPX_IT_LIM_INFEAS: + // case CPX_TIME_LIM_INFEAS: + // case CPX_NUM_BEST_INFEAS: + // case CPX_OPTIMAL_INFEAS: + // case CPX_ABORT_INFEAS: + // case CPX_ABORT_PRIM_INFEAS: + // case CPX_ABORT_PRIM_DUAL_INFEAS: + return UNBOUNDED;//In case of dual simplex + //return INFEASIBLE; + // case CPX_OBJ_LIM: + // case CPX_IT_LIM_FEAS: + // case CPX_TIME_LIM_FEAS: + // case CPX_NUM_BEST_FEAS: + // case CPX_ABORT_FEAS: + // case CPX_ABORT_PRIM_DUAL_FEAS: + // return FEASIBLE; + default: + return UNDEFINED; //Everything else comes here + //FIXME error + } +#endif + } + + // Cplex 9.0 status values + // CPX_STAT_ABORT_DUAL_OBJ_LIM + // CPX_STAT_ABORT_IT_LIM + // CPX_STAT_ABORT_OBJ_LIM + // CPX_STAT_ABORT_PRIM_OBJ_LIM + // CPX_STAT_ABORT_TIME_LIM + // CPX_STAT_ABORT_USER + // CPX_STAT_FEASIBLE_RELAXED + // CPX_STAT_INFEASIBLE + // CPX_STAT_INForUNBD + // CPX_STAT_NUM_BEST + // CPX_STAT_OPTIMAL + // CPX_STAT_OPTIMAL_FACE_UNBOUNDED + // CPX_STAT_OPTIMAL_INFEAS + // CPX_STAT_OPTIMAL_RELAXED + // CPX_STAT_UNBOUNDED + + CplexLp::ProblemType CplexLp::_getDualType() const { + int stat = CPXgetstat(cplexEnv(), _prob); +#if CPX_VERSION >= 800 + switch (stat) { + case CPX_STAT_OPTIMAL: + return OPTIMAL; + case CPX_STAT_UNBOUNDED: + return INFEASIBLE; + default: + return UNDEFINED; + } +#else + statusSwitch(cplexEnv(),stat); + switch (stat) { + case 0: + return UNDEFINED; //Undefined + case CPX_OPTIMAL://Optimal + return OPTIMAL; + case CPX_UNBOUNDED: + return INFEASIBLE; + default: + return UNDEFINED; //Everything else comes here + //FIXME error + } +#endif + } + + // CplexMip members + + CplexMip::CplexMip() + : LpBase(), MipSolver(), CplexBase() { + +#if CPX_VERSION < 800 + CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MIP); +#else + CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MILP); +#endif + } + + CplexMip::CplexMip(const CplexEnv& env) + : LpBase(), MipSolver(), CplexBase(env) { + +#if CPX_VERSION < 800 + CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MIP); +#else + CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MILP); +#endif + + } + + CplexMip::CplexMip(const CplexMip& other) + : LpBase(), MipSolver(), CplexBase(other) {} + + CplexMip::~CplexMip() {} + + CplexMip* CplexMip::newSolver() const { return new CplexMip; } + CplexMip* CplexMip::cloneSolver() const {return new CplexMip(*this); } + + const char* CplexMip::_solverName() const { return "CplexMip"; } + + void CplexMip::_setColType(int i, CplexMip::ColTypes col_type) { + + // Note If a variable is to be changed to binary, a call to CPXchgbds + // should also be made to change the bounds to 0 and 1. + + switch (col_type){ + case INTEGER: { + const char t = 'I'; + CPXchgctype (cplexEnv(), _prob, 1, &i, &t); + } break; + case REAL: { + const char t = 'C'; + CPXchgctype (cplexEnv(), _prob, 1, &i, &t); + } break; + default: + break; + } + } + + CplexMip::ColTypes CplexMip::_getColType(int i) const { + char t; + CPXgetctype (cplexEnv(), _prob, &t, i, i); + switch (t) { + case 'I': + return INTEGER; + case 'C': + return REAL; + default: + LEMON_ASSERT(false, "Invalid column type"); + return ColTypes(); + } + + } + + CplexMip::SolveExitStatus CplexMip::_solve() { + int status; + _applyMessageLevel(); + status = CPXmipopt (cplexEnv(), _prob); + if (status==0) + return SOLVED; + else + return UNSOLVED; + + } + + + CplexMip::ProblemType CplexMip::_getType() const { + + int stat = CPXgetstat(cplexEnv(), _prob); + + //Fortunately, MIP statuses did not change for cplex 8.0 + switch (stat) { + case CPXMIP_OPTIMAL: + // Optimal integer solution has been found. + case CPXMIP_OPTIMAL_TOL: + // Optimal soluton with the tolerance defined by epgap or epagap has + // been found. + return OPTIMAL; + //This also exists in later issues + // case CPXMIP_UNBOUNDED: + //return UNBOUNDED; + case CPXMIP_INFEASIBLE: + return INFEASIBLE; + default: + return UNDEFINED; + } + //Unboundedness not treated well: the following is from cplex 9.0 doc + // About Unboundedness + + // The treatment of models that are unbounded involves a few + // subtleties. Specifically, a declaration of unboundedness means that + // ILOG CPLEX has determined that the model has an unbounded + // ray. Given any feasible solution x with objective z, a multiple of + // the unbounded ray can be added to x to give a feasible solution + // with objective z-1 (or z+1 for maximization models). Thus, if a + // feasible solution exists, then the optimal objective is + // unbounded. Note that ILOG CPLEX has not necessarily concluded that + // a feasible solution exists. Users can call the routine CPXsolninfo + // to determine whether ILOG CPLEX has also concluded that the model + // has a feasible solution. + } + + CplexMip::Value CplexMip::_getSol(int i) const { + Value x; + CPXgetmipx(cplexEnv(), _prob, &x, i, i); + return x; + } + + CplexMip::Value CplexMip::_getSolValue() const { + Value objval; + CPXgetmipobjval(cplexEnv(), _prob, &objval); + return objval; + } + +} //namespace lemon + diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/cplex.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/cplex.h new file mode 100644 index 00000000000..c17e7926ad6 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/cplex.h @@ -0,0 +1,292 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_CPLEX_H +#define LEMON_CPLEX_H + +///\file +///\brief Header of the LEMON-CPLEX lp solver interface. + +#include + +struct cpxenv; +struct cpxlp; + +namespace lemon { + + /// \brief Reference counted wrapper around cpxenv pointer + /// + /// The cplex uses environment object which is responsible for + /// checking the proper license usage. This class provides a simple + /// interface for share the environment object between different + /// problems. + class CplexEnv { + friend class CplexBase; + private: + cpxenv* _env; + mutable int* _cnt; + + public: + + /// \brief This exception is thrown when the license check is not + /// sufficient + class LicenseError : public Exception { + friend class CplexEnv; + private: + + LicenseError(int status); + char _message[510]; + + public: + + /// The short error message + virtual const char* what() const throw() { + return _message; + } + }; + + /// Constructor + CplexEnv(); + /// Shallow copy constructor + CplexEnv(const CplexEnv&); + /// Shallow assignement + CplexEnv& operator=(const CplexEnv&); + /// Destructor + virtual ~CplexEnv(); + + protected: + + cpxenv* cplexEnv() { return _env; } + const cpxenv* cplexEnv() const { return _env; } + }; + + /// \brief Base interface for the CPLEX LP and MIP solver + /// + /// This class implements the common interface of the CPLEX LP and + /// MIP solvers. + /// \ingroup lp_group + class CplexBase : virtual public LpBase { + protected: + + CplexEnv _env; + cpxlp* _prob; + + CplexBase(); + CplexBase(const CplexEnv&); + CplexBase(const CplexBase &); + virtual ~CplexBase(); + + virtual int _addCol(); + virtual int _addRow(); + virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u); + + virtual void _eraseCol(int i); + virtual void _eraseRow(int i); + + virtual void _eraseColId(int i); + virtual void _eraseRowId(int i); + + virtual void _getColName(int col, std::string& name) const; + virtual void _setColName(int col, const std::string& name); + virtual int _colByName(const std::string& name) const; + + virtual void _getRowName(int row, std::string& name) const; + virtual void _setRowName(int row, const std::string& name); + virtual int _rowByName(const std::string& name) const; + + virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e); + virtual void _getRowCoeffs(int i, InsertIterator b) const; + + virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e); + virtual void _getColCoeffs(int i, InsertIterator b) const; + + virtual void _setCoeff(int row, int col, Value value); + virtual Value _getCoeff(int row, int col) const; + + virtual void _setColLowerBound(int i, Value value); + virtual Value _getColLowerBound(int i) const; + + virtual void _setColUpperBound(int i, Value value); + virtual Value _getColUpperBound(int i) const; + + private: + void _set_row_bounds(int i, Value lb, Value ub); + protected: + + virtual void _setRowLowerBound(int i, Value value); + virtual Value _getRowLowerBound(int i) const; + + virtual void _setRowUpperBound(int i, Value value); + virtual Value _getRowUpperBound(int i) const; + + virtual void _setObjCoeffs(ExprIterator b, ExprIterator e); + virtual void _getObjCoeffs(InsertIterator b) const; + + virtual void _setObjCoeff(int i, Value obj_coef); + virtual Value _getObjCoeff(int i) const; + + virtual void _setSense(Sense sense); + virtual Sense _getSense() const; + + virtual void _clear(); + + virtual void _messageLevel(MessageLevel level); + void _applyMessageLevel(); + + bool _message_enabled; + + void _write(std::string file, std::string format) const; + + public: + + /// Returns the used \c CplexEnv instance + const CplexEnv& env() const { return _env; } + + /// \brief Returns the const cpxenv pointer + /// + /// \note The cpxenv might be destructed with the solver. + const cpxenv* cplexEnv() const { return _env.cplexEnv(); } + + /// \brief Returns the const cpxenv pointer + /// + /// \note The cpxenv might be destructed with the solver. + cpxenv* cplexEnv() { return _env.cplexEnv(); } + + /// Returns the cplex problem object + cpxlp* cplexLp() { return _prob; } + /// Returns the cplex problem object + const cpxlp* cplexLp() const { return _prob; } + +#ifdef DOXYGEN + /// Write the problem or the solution to a file in the given format + + /// This function writes the problem or the solution + /// to a file in the given format. + /// Trying to write in an unsupported format will trigger + /// \ref lemon::LpBase::UnsupportedFormatError "UnsupportedFormatError". + /// \param file The file path + /// \param format The output file format. + /// Supportted formats are "MPS", "LP" and "SOL". + void write(std::string file, std::string format = "MPS") const {} +#endif + + }; + + /// \brief Interface for the CPLEX LP solver + /// + /// This class implements an interface for the CPLEX LP solver. + ///\ingroup lp_group + class CplexLp : public LpSolver, public CplexBase { + public: + /// \e + CplexLp(); + /// \e + CplexLp(const CplexEnv&); + /// \e + CplexLp(const CplexLp&); + /// \e + virtual ~CplexLp(); + + /// \e + virtual CplexLp* cloneSolver() const; + /// \e + virtual CplexLp* newSolver() const; + + private: + + // these values cannot retrieved element by element + mutable std::vector _col_status; + mutable std::vector _row_status; + + mutable std::vector _primal_ray; + mutable std::vector _dual_ray; + + void _clear_temporals(); + + SolveExitStatus convertStatus(int status); + + protected: + + virtual const char* _solverName() const; + + virtual SolveExitStatus _solve(); + virtual Value _getPrimal(int i) const; + virtual Value _getDual(int i) const; + virtual Value _getPrimalValue() const; + + virtual VarStatus _getColStatus(int i) const; + virtual VarStatus _getRowStatus(int i) const; + + virtual Value _getPrimalRay(int i) const; + virtual Value _getDualRay(int i) const; + + virtual ProblemType _getPrimalType() const; + virtual ProblemType _getDualType() const; + + public: + + /// Solve with primal simplex method + SolveExitStatus solvePrimal(); + + /// Solve with dual simplex method + SolveExitStatus solveDual(); + + /// Solve with barrier method + SolveExitStatus solveBarrier(); + + }; + + /// \brief Interface for the CPLEX MIP solver + /// + /// This class implements an interface for the CPLEX MIP solver. + ///\ingroup lp_group + class CplexMip : public MipSolver, public CplexBase { + public: + /// \e + CplexMip(); + /// \e + CplexMip(const CplexEnv&); + /// \e + CplexMip(const CplexMip&); + /// \e + virtual ~CplexMip(); + + /// \e + virtual CplexMip* cloneSolver() const; + /// \e + virtual CplexMip* newSolver() const; + + protected: + + + virtual const char* _solverName() const; + + virtual ColTypes _getColType(int col) const; + virtual void _setColType(int col, ColTypes col_type); + + virtual SolveExitStatus _solve(); + virtual ProblemType _getType() const; + virtual Value _getSol(int i) const; + virtual Value _getSolValue() const; + + }; + +} //END OF NAMESPACE LEMON + +#endif //LEMON_CPLEX_H + diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/cycle_canceling.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/cycle_canceling.h new file mode 100644 index 00000000000..646d299e3ec --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/cycle_canceling.h @@ -0,0 +1,1230 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_CYCLE_CANCELING_H +#define LEMON_CYCLE_CANCELING_H + +/// \ingroup min_cost_flow_algs +/// \file +/// \brief Cycle-canceling algorithms for finding a minimum cost flow. + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace lemon { + + /// \addtogroup min_cost_flow_algs + /// @{ + + /// \brief Implementation of cycle-canceling algorithms for + /// finding a \ref min_cost_flow "minimum cost flow". + /// + /// \ref CycleCanceling implements three different cycle-canceling + /// algorithms for finding a \ref min_cost_flow "minimum cost flow" + /// \cite amo93networkflows, \cite klein67primal, + /// \cite goldberg89cyclecanceling. + /// The most efficent one is the \ref CANCEL_AND_TIGHTEN + /// "Cancel-and-Tighten" algorithm, thus it is the default method. + /// It runs in strongly polynomial time \f$O(n^2 m^2 \log n)\f$, + /// but in practice, it is typically orders of magnitude slower than + /// the scaling algorithms and \ref NetworkSimplex. + /// (For more information, see \ref min_cost_flow_algs "the module page".) + /// + /// Most of the parameters of the problem (except for the digraph) + /// can be given using separate functions, and the algorithm can be + /// executed using the \ref run() function. If some parameters are not + /// specified, then default values will be used. + /// + /// \tparam GR The digraph type the algorithm runs on. + /// \tparam V The number type used for flow amounts, capacity bounds + /// and supply values in the algorithm. By default, it is \c int. + /// \tparam C The number type used for costs and potentials in the + /// algorithm. By default, it is the same as \c V. + /// + /// \warning Both \c V and \c C must be signed number types. + /// \warning All input data (capacities, supply values, and costs) must + /// be integer. + /// \warning This algorithm does not support negative costs for + /// arcs having infinite upper bound. + /// + /// \note For more information about the three available methods, + /// see \ref Method. +#ifdef DOXYGEN + template +#else + template +#endif + class CycleCanceling + { + public: + + /// The type of the digraph + typedef GR Digraph; + /// The type of the flow amounts, capacity bounds and supply values + typedef V Value; + /// The type of the arc costs + typedef C Cost; + + public: + + /// \brief Problem type constants for the \c run() function. + /// + /// Enum type containing the problem type constants that can be + /// returned by the \ref run() function of the algorithm. + enum ProblemType { + /// The problem has no feasible solution (flow). + INFEASIBLE, + /// The problem has optimal solution (i.e. it is feasible and + /// bounded), and the algorithm has found optimal flow and node + /// potentials (primal and dual solutions). + OPTIMAL, + /// The digraph contains an arc of negative cost and infinite + /// upper bound. It means that the objective function is unbounded + /// on that arc, however, note that it could actually be bounded + /// over the feasible flows, but this algroithm cannot handle + /// these cases. + UNBOUNDED + }; + + /// \brief Constants for selecting the used method. + /// + /// Enum type containing constants for selecting the used method + /// for the \ref run() function. + /// + /// \ref CycleCanceling provides three different cycle-canceling + /// methods. By default, \ref CANCEL_AND_TIGHTEN "Cancel-and-Tighten" + /// is used, which is by far the most efficient and the most robust. + /// However, the other methods can be selected using the \ref run() + /// function with the proper parameter. + enum Method { + /// A simple cycle-canceling method, which uses the + /// \ref BellmanFord "Bellman-Ford" algorithm for detecting negative + /// cycles in the residual network. + /// The number of Bellman-Ford iterations is bounded by a successively + /// increased limit. + SIMPLE_CYCLE_CANCELING, + /// The "Minimum Mean Cycle-Canceling" algorithm, which is a + /// well-known strongly polynomial method + /// \cite goldberg89cyclecanceling. It improves along a + /// \ref min_mean_cycle "minimum mean cycle" in each iteration. + /// Its running time complexity is \f$O(n^2 m^3 \log n)\f$. + MINIMUM_MEAN_CYCLE_CANCELING, + /// The "Cancel-and-Tighten" algorithm, which can be viewed as an + /// improved version of the previous method + /// \cite goldberg89cyclecanceling. + /// It is faster both in theory and in practice, its running time + /// complexity is \f$O(n^2 m^2 \log n)\f$. + CANCEL_AND_TIGHTEN + }; + + private: + + TEMPLATE_DIGRAPH_TYPEDEFS(GR); + + typedef std::vector IntVector; + typedef std::vector DoubleVector; + typedef std::vector ValueVector; + typedef std::vector CostVector; + typedef std::vector BoolVector; + // Note: vector is used instead of vector for efficiency reasons + + private: + + template + class StaticVectorMap { + public: + typedef KT Key; + typedef VT Value; + + StaticVectorMap(std::vector& v) : _v(v) {} + + const Value& operator[](const Key& key) const { + return _v[StaticDigraph::id(key)]; + } + + Value& operator[](const Key& key) { + return _v[StaticDigraph::id(key)]; + } + + void set(const Key& key, const Value& val) { + _v[StaticDigraph::id(key)] = val; + } + + private: + std::vector& _v; + }; + + typedef StaticVectorMap CostNodeMap; + typedef StaticVectorMap CostArcMap; + + private: + + + // Data related to the underlying digraph + const GR &_graph; + int _node_num; + int _arc_num; + int _res_node_num; + int _res_arc_num; + int _root; + + // Parameters of the problem + bool _has_lower; + Value _sum_supply; + + // Data structures for storing the digraph + IntNodeMap _node_id; + IntArcMap _arc_idf; + IntArcMap _arc_idb; + IntVector _first_out; + BoolVector _forward; + IntVector _source; + IntVector _target; + IntVector _reverse; + + // Node and arc data + ValueVector _lower; + ValueVector _upper; + CostVector _cost; + ValueVector _supply; + + ValueVector _res_cap; + CostVector _pi; + + // Data for a StaticDigraph structure + typedef std::pair IntPair; + StaticDigraph _sgr; + std::vector _arc_vec; + std::vector _cost_vec; + IntVector _id_vec; + CostArcMap _cost_map; + CostNodeMap _pi_map; + + public: + + /// \brief Constant for infinite upper bounds (capacities). + /// + /// Constant for infinite upper bounds (capacities). + /// It is \c std::numeric_limits::infinity() if available, + /// \c std::numeric_limits::max() otherwise. + const Value INF; + + public: + + /// \brief Constructor. + /// + /// The constructor of the class. + /// + /// \param graph The digraph the algorithm runs on. + CycleCanceling(const GR& graph) : + _graph(graph), _node_id(graph), _arc_idf(graph), _arc_idb(graph), + _cost_map(_cost_vec), _pi_map(_pi), + INF(std::numeric_limits::has_infinity ? + std::numeric_limits::infinity() : + std::numeric_limits::max()) + { + // Check the number types + LEMON_ASSERT(std::numeric_limits::is_signed, + "The flow type of CycleCanceling must be signed"); + LEMON_ASSERT(std::numeric_limits::is_signed, + "The cost type of CycleCanceling must be signed"); + + // Reset data structures + reset(); + } + + /// \name Parameters + /// The parameters of the algorithm can be specified using these + /// functions. + + /// @{ + + /// \brief Set the lower bounds on the arcs. + /// + /// This function sets the lower bounds on the arcs. + /// If it is not used before calling \ref run(), the lower bounds + /// will be set to zero on all arcs. + /// + /// \param map An arc map storing the lower bounds. + /// Its \c Value type must be convertible to the \c Value type + /// of the algorithm. + /// + /// \return (*this) + template + CycleCanceling& lowerMap(const LowerMap& map) { + _has_lower = true; + for (ArcIt a(_graph); a != INVALID; ++a) { + _lower[_arc_idf[a]] = map[a]; + } + return *this; + } + + /// \brief Set the upper bounds (capacities) on the arcs. + /// + /// This function sets the upper bounds (capacities) on the arcs. + /// If it is not used before calling \ref run(), the upper bounds + /// will be set to \ref INF on all arcs (i.e. the flow value will be + /// unbounded from above). + /// + /// \param map An arc map storing the upper bounds. + /// Its \c Value type must be convertible to the \c Value type + /// of the algorithm. + /// + /// \return (*this) + template + CycleCanceling& upperMap(const UpperMap& map) { + for (ArcIt a(_graph); a != INVALID; ++a) { + _upper[_arc_idf[a]] = map[a]; + } + return *this; + } + + /// \brief Set the costs of the arcs. + /// + /// This function sets the costs of the arcs. + /// If it is not used before calling \ref run(), the costs + /// will be set to \c 1 on all arcs. + /// + /// \param map An arc map storing the costs. + /// Its \c Value type must be convertible to the \c Cost type + /// of the algorithm. + /// + /// \return (*this) + template + CycleCanceling& costMap(const CostMap& map) { + for (ArcIt a(_graph); a != INVALID; ++a) { + _cost[_arc_idf[a]] = map[a]; + _cost[_arc_idb[a]] = -map[a]; + } + return *this; + } + + /// \brief Set the supply values of the nodes. + /// + /// This function sets the supply values of the nodes. + /// If neither this function nor \ref stSupply() is used before + /// calling \ref run(), the supply of each node will be set to zero. + /// + /// \param map A node map storing the supply values. + /// Its \c Value type must be convertible to the \c Value type + /// of the algorithm. + /// + /// \return (*this) + template + CycleCanceling& supplyMap(const SupplyMap& map) { + for (NodeIt n(_graph); n != INVALID; ++n) { + _supply[_node_id[n]] = map[n]; + } + return *this; + } + + /// \brief Set single source and target nodes and a supply value. + /// + /// This function sets a single source node and a single target node + /// and the required flow value. + /// If neither this function nor \ref supplyMap() is used before + /// calling \ref run(), the supply of each node will be set to zero. + /// + /// Using this function has the same effect as using \ref supplyMap() + /// with a map in which \c k is assigned to \c s, \c -k is + /// assigned to \c t and all other nodes have zero supply value. + /// + /// \param s The source node. + /// \param t The target node. + /// \param k The required amount of flow from node \c s to node \c t + /// (i.e. the supply of \c s and the demand of \c t). + /// + /// \return (*this) + CycleCanceling& stSupply(const Node& s, const Node& t, Value k) { + for (int i = 0; i != _res_node_num; ++i) { + _supply[i] = 0; + } + _supply[_node_id[s]] = k; + _supply[_node_id[t]] = -k; + return *this; + } + + /// @} + + /// \name Execution control + /// The algorithm can be executed using \ref run(). + + /// @{ + + /// \brief Run the algorithm. + /// + /// This function runs the algorithm. + /// The paramters can be specified using functions \ref lowerMap(), + /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply(). + /// For example, + /// \code + /// CycleCanceling cc(graph); + /// cc.lowerMap(lower).upperMap(upper).costMap(cost) + /// .supplyMap(sup).run(); + /// \endcode + /// + /// This function can be called more than once. All the given parameters + /// are kept for the next call, unless \ref resetParams() or \ref reset() + /// is used, thus only the modified parameters have to be set again. + /// If the underlying digraph was also modified after the construction + /// of the class (or the last \ref reset() call), then the \ref reset() + /// function must be called. + /// + /// \param method The cycle-canceling method that will be used. + /// For more information, see \ref Method. + /// + /// \return \c INFEASIBLE if no feasible flow exists, + /// \n \c OPTIMAL if the problem has optimal solution + /// (i.e. it is feasible and bounded), and the algorithm has found + /// optimal flow and node potentials (primal and dual solutions), + /// \n \c UNBOUNDED if the digraph contains an arc of negative cost + /// and infinite upper bound. It means that the objective function + /// is unbounded on that arc, however, note that it could actually be + /// bounded over the feasible flows, but this algroithm cannot handle + /// these cases. + /// + /// \see ProblemType, Method + /// \see resetParams(), reset() + ProblemType run(Method method = CANCEL_AND_TIGHTEN) { + ProblemType pt = init(); + if (pt != OPTIMAL) return pt; + start(method); + return OPTIMAL; + } + + /// \brief Reset all the parameters that have been given before. + /// + /// This function resets all the paramaters that have been given + /// before using functions \ref lowerMap(), \ref upperMap(), + /// \ref costMap(), \ref supplyMap(), \ref stSupply(). + /// + /// It is useful for multiple \ref run() calls. Basically, all the given + /// parameters are kept for the next \ref run() call, unless + /// \ref resetParams() or \ref reset() is used. + /// If the underlying digraph was also modified after the construction + /// of the class or the last \ref reset() call, then the \ref reset() + /// function must be used, otherwise \ref resetParams() is sufficient. + /// + /// For example, + /// \code + /// CycleCanceling cs(graph); + /// + /// // First run + /// cc.lowerMap(lower).upperMap(upper).costMap(cost) + /// .supplyMap(sup).run(); + /// + /// // Run again with modified cost map (resetParams() is not called, + /// // so only the cost map have to be set again) + /// cost[e] += 100; + /// cc.costMap(cost).run(); + /// + /// // Run again from scratch using resetParams() + /// // (the lower bounds will be set to zero on all arcs) + /// cc.resetParams(); + /// cc.upperMap(capacity).costMap(cost) + /// .supplyMap(sup).run(); + /// \endcode + /// + /// \return (*this) + /// + /// \see reset(), run() + CycleCanceling& resetParams() { + for (int i = 0; i != _res_node_num; ++i) { + _supply[i] = 0; + } + int limit = _first_out[_root]; + for (int j = 0; j != limit; ++j) { + _lower[j] = 0; + _upper[j] = INF; + _cost[j] = _forward[j] ? 1 : -1; + } + for (int j = limit; j != _res_arc_num; ++j) { + _lower[j] = 0; + _upper[j] = INF; + _cost[j] = 0; + _cost[_reverse[j]] = 0; + } + _has_lower = false; + return *this; + } + + /// \brief Reset the internal data structures and all the parameters + /// that have been given before. + /// + /// This function resets the internal data structures and all the + /// paramaters that have been given before using functions \ref lowerMap(), + /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply(). + /// + /// It is useful for multiple \ref run() calls. Basically, all the given + /// parameters are kept for the next \ref run() call, unless + /// \ref resetParams() or \ref reset() is used. + /// If the underlying digraph was also modified after the construction + /// of the class or the last \ref reset() call, then the \ref reset() + /// function must be used, otherwise \ref resetParams() is sufficient. + /// + /// See \ref resetParams() for examples. + /// + /// \return (*this) + /// + /// \see resetParams(), run() + CycleCanceling& reset() { + // Resize vectors + _node_num = countNodes(_graph); + _arc_num = countArcs(_graph); + _res_node_num = _node_num + 1; + _res_arc_num = 2 * (_arc_num + _node_num); + _root = _node_num; + + _first_out.resize(_res_node_num + 1); + _forward.resize(_res_arc_num); + _source.resize(_res_arc_num); + _target.resize(_res_arc_num); + _reverse.resize(_res_arc_num); + + _lower.resize(_res_arc_num); + _upper.resize(_res_arc_num); + _cost.resize(_res_arc_num); + _supply.resize(_res_node_num); + + _res_cap.resize(_res_arc_num); + _pi.resize(_res_node_num); + + _arc_vec.reserve(_res_arc_num); + _cost_vec.reserve(_res_arc_num); + _id_vec.reserve(_res_arc_num); + + // Copy the graph + int i = 0, j = 0, k = 2 * _arc_num + _node_num; + for (NodeIt n(_graph); n != INVALID; ++n, ++i) { + _node_id[n] = i; + } + i = 0; + for (NodeIt n(_graph); n != INVALID; ++n, ++i) { + _first_out[i] = j; + for (OutArcIt a(_graph, n); a != INVALID; ++a, ++j) { + _arc_idf[a] = j; + _forward[j] = true; + _source[j] = i; + _target[j] = _node_id[_graph.runningNode(a)]; + } + for (InArcIt a(_graph, n); a != INVALID; ++a, ++j) { + _arc_idb[a] = j; + _forward[j] = false; + _source[j] = i; + _target[j] = _node_id[_graph.runningNode(a)]; + } + _forward[j] = false; + _source[j] = i; + _target[j] = _root; + _reverse[j] = k; + _forward[k] = true; + _source[k] = _root; + _target[k] = i; + _reverse[k] = j; + ++j; ++k; + } + _first_out[i] = j; + _first_out[_res_node_num] = k; + for (ArcIt a(_graph); a != INVALID; ++a) { + int fi = _arc_idf[a]; + int bi = _arc_idb[a]; + _reverse[fi] = bi; + _reverse[bi] = fi; + } + + // Reset parameters + resetParams(); + return *this; + } + + /// @} + + /// \name Query Functions + /// The results of the algorithm can be obtained using these + /// functions.\n + /// The \ref run() function must be called before using them. + + /// @{ + + /// \brief Return the total cost of the found flow. + /// + /// This function returns the total cost of the found flow. + /// Its complexity is O(m). + /// + /// \note The return type of the function can be specified as a + /// template parameter. For example, + /// \code + /// cc.totalCost(); + /// \endcode + /// It is useful if the total cost cannot be stored in the \c Cost + /// type of the algorithm, which is the default return type of the + /// function. + /// + /// \pre \ref run() must be called before using this function. + template + Number totalCost() const { + Number c = 0; + for (ArcIt a(_graph); a != INVALID; ++a) { + int i = _arc_idb[a]; + c += static_cast(_res_cap[i]) * + (-static_cast(_cost[i])); + } + return c; + } + +#ifndef DOXYGEN + Cost totalCost() const { + return totalCost(); + } +#endif + + /// \brief Return the flow on the given arc. + /// + /// This function returns the flow on the given arc. + /// + /// \pre \ref run() must be called before using this function. + Value flow(const Arc& a) const { + return _res_cap[_arc_idb[a]]; + } + + /// \brief Copy the flow values (the primal solution) into the + /// given map. + /// + /// This function copies the flow value on each arc into the given + /// map. The \c Value type of the algorithm must be convertible to + /// the \c Value type of the map. + /// + /// \pre \ref run() must be called before using this function. + template + void flowMap(FlowMap &map) const { + for (ArcIt a(_graph); a != INVALID; ++a) { + map.set(a, _res_cap[_arc_idb[a]]); + } + } + + /// \brief Return the potential (dual value) of the given node. + /// + /// This function returns the potential (dual value) of the + /// given node. + /// + /// \pre \ref run() must be called before using this function. + Cost potential(const Node& n) const { + return static_cast(_pi[_node_id[n]]); + } + + /// \brief Copy the potential values (the dual solution) into the + /// given map. + /// + /// This function copies the potential (dual value) of each node + /// into the given map. + /// The \c Cost type of the algorithm must be convertible to the + /// \c Value type of the map. + /// + /// \pre \ref run() must be called before using this function. + template + void potentialMap(PotentialMap &map) const { + for (NodeIt n(_graph); n != INVALID; ++n) { + map.set(n, static_cast(_pi[_node_id[n]])); + } + } + + /// @} + + private: + + // Initialize the algorithm + ProblemType init() { + if (_res_node_num <= 1) return INFEASIBLE; + + // Check the sum of supply values + _sum_supply = 0; + for (int i = 0; i != _root; ++i) { + _sum_supply += _supply[i]; + } + if (_sum_supply > 0) return INFEASIBLE; + + // Check lower and upper bounds + LEMON_DEBUG(checkBoundMaps(), + "Upper bounds must be greater or equal to the lower bounds"); + + + // Initialize vectors + for (int i = 0; i != _res_node_num; ++i) { + _pi[i] = 0; + } + ValueVector excess(_supply); + + // Remove infinite upper bounds and check negative arcs + const Value MAX = std::numeric_limits::max(); + int last_out; + if (_has_lower) { + for (int i = 0; i != _root; ++i) { + last_out = _first_out[i+1]; + for (int j = _first_out[i]; j != last_out; ++j) { + if (_forward[j]) { + Value c = _cost[j] < 0 ? _upper[j] : _lower[j]; + if (c >= MAX) return UNBOUNDED; + excess[i] -= c; + excess[_target[j]] += c; + } + } + } + } else { + for (int i = 0; i != _root; ++i) { + last_out = _first_out[i+1]; + for (int j = _first_out[i]; j != last_out; ++j) { + if (_forward[j] && _cost[j] < 0) { + Value c = _upper[j]; + if (c >= MAX) return UNBOUNDED; + excess[i] -= c; + excess[_target[j]] += c; + } + } + } + } + Value ex, max_cap = 0; + for (int i = 0; i != _res_node_num; ++i) { + ex = excess[i]; + if (ex < 0) max_cap -= ex; + } + for (int j = 0; j != _res_arc_num; ++j) { + if (_upper[j] >= MAX) _upper[j] = max_cap; + } + + // Initialize maps for Circulation and remove non-zero lower bounds + ConstMap low(0); + typedef typename Digraph::template ArcMap ValueArcMap; + typedef typename Digraph::template NodeMap ValueNodeMap; + ValueArcMap cap(_graph), flow(_graph); + ValueNodeMap sup(_graph); + for (NodeIt n(_graph); n != INVALID; ++n) { + sup[n] = _supply[_node_id[n]]; + } + if (_has_lower) { + for (ArcIt a(_graph); a != INVALID; ++a) { + int j = _arc_idf[a]; + Value c = _lower[j]; + cap[a] = _upper[j] - c; + sup[_graph.source(a)] -= c; + sup[_graph.target(a)] += c; + } + } else { + for (ArcIt a(_graph); a != INVALID; ++a) { + cap[a] = _upper[_arc_idf[a]]; + } + } + + // Find a feasible flow using Circulation + Circulation, ValueArcMap, ValueNodeMap> + circ(_graph, low, cap, sup); + if (!circ.flowMap(flow).run()) return INFEASIBLE; + + // Set residual capacities and handle GEQ supply type + if (_sum_supply < 0) { + for (ArcIt a(_graph); a != INVALID; ++a) { + Value fa = flow[a]; + _res_cap[_arc_idf[a]] = cap[a] - fa; + _res_cap[_arc_idb[a]] = fa; + sup[_graph.source(a)] -= fa; + sup[_graph.target(a)] += fa; + } + for (NodeIt n(_graph); n != INVALID; ++n) { + excess[_node_id[n]] = sup[n]; + } + for (int a = _first_out[_root]; a != _res_arc_num; ++a) { + int u = _target[a]; + int ra = _reverse[a]; + _res_cap[a] = -_sum_supply + 1; + _res_cap[ra] = -excess[u]; + _cost[a] = 0; + _cost[ra] = 0; + } + } else { + for (ArcIt a(_graph); a != INVALID; ++a) { + Value fa = flow[a]; + _res_cap[_arc_idf[a]] = cap[a] - fa; + _res_cap[_arc_idb[a]] = fa; + } + for (int a = _first_out[_root]; a != _res_arc_num; ++a) { + int ra = _reverse[a]; + _res_cap[a] = 1; + _res_cap[ra] = 0; + _cost[a] = 0; + _cost[ra] = 0; + } + } + + return OPTIMAL; + } + + // Check if the upper bound is greater than or equal to the lower bound + // on each forward arc. + bool checkBoundMaps() { + for (int j = 0; j != _res_arc_num; ++j) { + if (_forward[j] && _upper[j] < _lower[j]) return false; + } + return true; + } + + // Build a StaticDigraph structure containing the current + // residual network + void buildResidualNetwork() { + _arc_vec.clear(); + _cost_vec.clear(); + _id_vec.clear(); + for (int j = 0; j != _res_arc_num; ++j) { + if (_res_cap[j] > 0) { + _arc_vec.push_back(IntPair(_source[j], _target[j])); + _cost_vec.push_back(_cost[j]); + _id_vec.push_back(j); + } + } + _sgr.build(_res_node_num, _arc_vec.begin(), _arc_vec.end()); + } + + // Execute the algorithm and transform the results + void start(Method method) { + // Execute the algorithm + switch (method) { + case SIMPLE_CYCLE_CANCELING: + startSimpleCycleCanceling(); + break; + case MINIMUM_MEAN_CYCLE_CANCELING: + startMinMeanCycleCanceling(); + break; + case CANCEL_AND_TIGHTEN: + startCancelAndTighten(); + break; + } + + // Compute node potentials + if (method != SIMPLE_CYCLE_CANCELING) { + buildResidualNetwork(); + typename BellmanFord + ::template SetDistMap::Create bf(_sgr, _cost_map); + bf.distMap(_pi_map); + bf.init(0); + bf.start(); + } + + // Handle non-zero lower bounds + if (_has_lower) { + int limit = _first_out[_root]; + for (int j = 0; j != limit; ++j) { + if (_forward[j]) _res_cap[_reverse[j]] += _lower[j]; + } + } + } + + // Execute the "Simple Cycle Canceling" method + void startSimpleCycleCanceling() { + // Constants for computing the iteration limits + const int BF_FIRST_LIMIT = 2; + const double BF_LIMIT_FACTOR = 1.5; + + typedef StaticVectorMap FilterMap; + typedef FilterArcs ResDigraph; + typedef StaticVectorMap PredMap; + typedef typename BellmanFord + ::template SetDistMap + ::template SetPredMap::Create BF; + + // Build the residual network + _arc_vec.clear(); + _cost_vec.clear(); + for (int j = 0; j != _res_arc_num; ++j) { + _arc_vec.push_back(IntPair(_source[j], _target[j])); + _cost_vec.push_back(_cost[j]); + } + _sgr.build(_res_node_num, _arc_vec.begin(), _arc_vec.end()); + + FilterMap filter_map(_res_cap); + ResDigraph rgr(_sgr, filter_map); + std::vector cycle; + std::vector pred(_res_arc_num); + PredMap pred_map(pred); + BF bf(rgr, _cost_map); + bf.distMap(_pi_map).predMap(pred_map); + + int length_bound = BF_FIRST_LIMIT; + bool optimal = false; + while (!optimal) { + bf.init(0); + int iter_num = 0; + bool cycle_found = false; + while (!cycle_found) { + // Perform some iterations of the Bellman-Ford algorithm + int curr_iter_num = iter_num + length_bound <= _node_num ? + length_bound : _node_num - iter_num; + iter_num += curr_iter_num; + int real_iter_num = curr_iter_num; + for (int i = 0; i < curr_iter_num; ++i) { + if (bf.processNextWeakRound()) { + real_iter_num = i; + break; + } + } + if (real_iter_num < curr_iter_num) { + // Optimal flow is found + optimal = true; + break; + } else { + // Search for node disjoint negative cycles + std::vector state(_res_node_num, 0); + int id = 0; + for (int u = 0; u != _res_node_num; ++u) { + if (state[u] != 0) continue; + ++id; + int v = u; + for (; v != -1 && state[v] == 0; v = pred[v] == INVALID ? + -1 : rgr.id(rgr.source(pred[v]))) { + state[v] = id; + } + if (v != -1 && state[v] == id) { + // A negative cycle is found + cycle_found = true; + cycle.clear(); + StaticDigraph::Arc a = pred[v]; + Value d, delta = _res_cap[rgr.id(a)]; + cycle.push_back(rgr.id(a)); + while (rgr.id(rgr.source(a)) != v) { + a = pred_map[rgr.source(a)]; + d = _res_cap[rgr.id(a)]; + if (d < delta) delta = d; + cycle.push_back(rgr.id(a)); + } + + // Augment along the cycle + for (int i = 0; i < int(cycle.size()); ++i) { + int j = cycle[i]; + _res_cap[j] -= delta; + _res_cap[_reverse[j]] += delta; + } + } + } + } + + // Increase iteration limit if no cycle is found + if (!cycle_found) { + length_bound = static_cast(length_bound * BF_LIMIT_FACTOR); + } + } + } + } + + // Execute the "Minimum Mean Cycle Canceling" method + void startMinMeanCycleCanceling() { + typedef Path SPath; + typedef typename SPath::ArcIt SPathArcIt; + typedef typename HowardMmc + ::template SetPath::Create HwMmc; + typedef typename HartmannOrlinMmc + ::template SetPath::Create HoMmc; + + const double HW_ITER_LIMIT_FACTOR = 1.0; + const int HW_ITER_LIMIT_MIN_VALUE = 5; + + const int hw_iter_limit = + std::max(static_cast(HW_ITER_LIMIT_FACTOR * _node_num), + HW_ITER_LIMIT_MIN_VALUE); + + SPath cycle; + HwMmc hw_mmc(_sgr, _cost_map); + hw_mmc.cycle(cycle); + buildResidualNetwork(); + while (true) { + + typename HwMmc::TerminationCause hw_tc = + hw_mmc.findCycleMean(hw_iter_limit); + if (hw_tc == HwMmc::ITERATION_LIMIT) { + // Howard's algorithm reached the iteration limit, start a + // strongly polynomial algorithm instead + HoMmc ho_mmc(_sgr, _cost_map); + ho_mmc.cycle(cycle); + // Find a minimum mean cycle (Hartmann-Orlin algorithm) + if (!(ho_mmc.findCycleMean() && ho_mmc.cycleCost() < 0)) break; + ho_mmc.findCycle(); + } else { + // Find a minimum mean cycle (Howard algorithm) + if (!(hw_tc == HwMmc::OPTIMAL && hw_mmc.cycleCost() < 0)) break; + hw_mmc.findCycle(); + } + + // Compute delta value + Value delta = INF; + for (SPathArcIt a(cycle); a != INVALID; ++a) { + Value d = _res_cap[_id_vec[_sgr.id(a)]]; + if (d < delta) delta = d; + } + + // Augment along the cycle + for (SPathArcIt a(cycle); a != INVALID; ++a) { + int j = _id_vec[_sgr.id(a)]; + _res_cap[j] -= delta; + _res_cap[_reverse[j]] += delta; + } + + // Rebuild the residual network + buildResidualNetwork(); + } + } + + // Execute the "Cancel-and-Tighten" method + void startCancelAndTighten() { + // Constants for the min mean cycle computations + const double LIMIT_FACTOR = 1.0; + const int MIN_LIMIT = 5; + const double HW_ITER_LIMIT_FACTOR = 1.0; + const int HW_ITER_LIMIT_MIN_VALUE = 5; + + const int hw_iter_limit = + std::max(static_cast(HW_ITER_LIMIT_FACTOR * _node_num), + HW_ITER_LIMIT_MIN_VALUE); + + // Contruct auxiliary data vectors + DoubleVector pi(_res_node_num, 0.0); + IntVector level(_res_node_num); + BoolVector reached(_res_node_num); + BoolVector processed(_res_node_num); + IntVector pred_node(_res_node_num); + IntVector pred_arc(_res_node_num); + std::vector stack(_res_node_num); + std::vector proc_vector(_res_node_num); + + // Initialize epsilon + double epsilon = 0; + for (int a = 0; a != _res_arc_num; ++a) { + if (_res_cap[a] > 0 && -_cost[a] > epsilon) + epsilon = -_cost[a]; + } + + // Start phases + Tolerance tol; + tol.epsilon(1e-6); + int limit = int(LIMIT_FACTOR * std::sqrt(double(_res_node_num))); + if (limit < MIN_LIMIT) limit = MIN_LIMIT; + int iter = limit; + while (epsilon * _res_node_num >= 1) { + // Find and cancel cycles in the admissible network using DFS + for (int u = 0; u != _res_node_num; ++u) { + reached[u] = false; + processed[u] = false; + } + int stack_head = -1; + int proc_head = -1; + for (int start = 0; start != _res_node_num; ++start) { + if (reached[start]) continue; + + // New start node + reached[start] = true; + pred_arc[start] = -1; + pred_node[start] = -1; + + // Find the first admissible outgoing arc + double p = pi[start]; + int a = _first_out[start]; + int last_out = _first_out[start+1]; + for (; a != last_out && (_res_cap[a] == 0 || + !tol.negative(_cost[a] + p - pi[_target[a]])); ++a) ; + if (a == last_out) { + processed[start] = true; + proc_vector[++proc_head] = start; + continue; + } + stack[++stack_head] = a; + + while (stack_head >= 0) { + int sa = stack[stack_head]; + int u = _source[sa]; + int v = _target[sa]; + + if (!reached[v]) { + // A new node is reached + reached[v] = true; + pred_node[v] = u; + pred_arc[v] = sa; + p = pi[v]; + a = _first_out[v]; + last_out = _first_out[v+1]; + for (; a != last_out && (_res_cap[a] == 0 || + !tol.negative(_cost[a] + p - pi[_target[a]])); ++a) ; + stack[++stack_head] = a == last_out ? -1 : a; + } else { + if (!processed[v]) { + // A cycle is found + int n, w = u; + Value d, delta = _res_cap[sa]; + for (n = u; n != v; n = pred_node[n]) { + d = _res_cap[pred_arc[n]]; + if (d <= delta) { + delta = d; + w = pred_node[n]; + } + } + + // Augment along the cycle + _res_cap[sa] -= delta; + _res_cap[_reverse[sa]] += delta; + for (n = u; n != v; n = pred_node[n]) { + int pa = pred_arc[n]; + _res_cap[pa] -= delta; + _res_cap[_reverse[pa]] += delta; + } + for (n = u; stack_head > 0 && n != w; n = pred_node[n]) { + --stack_head; + reached[n] = false; + } + u = w; + } + v = u; + + // Find the next admissible outgoing arc + p = pi[v]; + a = stack[stack_head] + 1; + last_out = _first_out[v+1]; + for (; a != last_out && (_res_cap[a] == 0 || + !tol.negative(_cost[a] + p - pi[_target[a]])); ++a) ; + stack[stack_head] = a == last_out ? -1 : a; + } + + while (stack_head >= 0 && stack[stack_head] == -1) { + processed[v] = true; + proc_vector[++proc_head] = v; + if (--stack_head >= 0) { + // Find the next admissible outgoing arc + v = _source[stack[stack_head]]; + p = pi[v]; + a = stack[stack_head] + 1; + last_out = _first_out[v+1]; + for (; a != last_out && (_res_cap[a] == 0 || + !tol.negative(_cost[a] + p - pi[_target[a]])); ++a) ; + stack[stack_head] = a == last_out ? -1 : a; + } + } + } + } + + // Tighten potentials and epsilon + if (--iter > 0) { + for (int u = 0; u != _res_node_num; ++u) { + level[u] = 0; + } + for (int i = proc_head; i > 0; --i) { + int u = proc_vector[i]; + double p = pi[u]; + int l = level[u] + 1; + int last_out = _first_out[u+1]; + for (int a = _first_out[u]; a != last_out; ++a) { + int v = _target[a]; + if (_res_cap[a] > 0 && tol.negative(_cost[a] + p - pi[v]) && + l > level[v]) level[v] = l; + } + } + + // Modify potentials + double q = std::numeric_limits::max(); + for (int u = 0; u != _res_node_num; ++u) { + int lu = level[u]; + double p, pu = pi[u]; + int last_out = _first_out[u+1]; + for (int a = _first_out[u]; a != last_out; ++a) { + if (_res_cap[a] == 0) continue; + int v = _target[a]; + int ld = lu - level[v]; + if (ld > 0) { + p = (_cost[a] + pu - pi[v] + epsilon) / (ld + 1); + if (p < q) q = p; + } + } + } + for (int u = 0; u != _res_node_num; ++u) { + pi[u] -= q * level[u]; + } + + // Modify epsilon + epsilon = 0; + for (int u = 0; u != _res_node_num; ++u) { + double curr, pu = pi[u]; + int last_out = _first_out[u+1]; + for (int a = _first_out[u]; a != last_out; ++a) { + if (_res_cap[a] == 0) continue; + curr = _cost[a] + pu - pi[_target[a]]; + if (-curr > epsilon) epsilon = -curr; + } + } + } else { + typedef HowardMmc HwMmc; + typedef HartmannOrlinMmc HoMmc; + typedef typename BellmanFord + ::template SetDistMap::Create BF; + + // Set epsilon to the minimum cycle mean + Cost cycle_cost = 0; + int cycle_size = 1; + buildResidualNetwork(); + HwMmc hw_mmc(_sgr, _cost_map); + if (hw_mmc.findCycleMean(hw_iter_limit) == HwMmc::ITERATION_LIMIT) { + // Howard's algorithm reached the iteration limit, start a + // strongly polynomial algorithm instead + HoMmc ho_mmc(_sgr, _cost_map); + ho_mmc.findCycleMean(); + epsilon = -ho_mmc.cycleMean(); + cycle_cost = ho_mmc.cycleCost(); + cycle_size = ho_mmc.cycleSize(); + } else { + // Set epsilon + epsilon = -hw_mmc.cycleMean(); + cycle_cost = hw_mmc.cycleCost(); + cycle_size = hw_mmc.cycleSize(); + } + + // Compute feasible potentials for the current epsilon + for (int i = 0; i != int(_cost_vec.size()); ++i) { + _cost_vec[i] = cycle_size * _cost_vec[i] - cycle_cost; + } + BF bf(_sgr, _cost_map); + bf.distMap(_pi_map); + bf.init(0); + bf.start(); + for (int u = 0; u != _res_node_num; ++u) { + pi[u] = static_cast(_pi[u]) / cycle_size; + } + + iter = limit; + } + } + } + + }; //class CycleCanceling + + ///@} + +} //namespace lemon + +#endif //LEMON_CYCLE_CANCELING_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/dfs.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/dfs.h new file mode 100644 index 00000000000..6e9e84a4892 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/dfs.h @@ -0,0 +1,1637 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_DFS_H +#define LEMON_DFS_H + +///\ingroup search +///\file +///\brief DFS algorithm. + +#include +#include +#include +#include +#include +#include + +namespace lemon { + + ///Default traits class of Dfs class. + + ///Default traits class of Dfs class. + ///\tparam GR Digraph type. + template + struct DfsDefaultTraits + { + ///The type of the digraph the algorithm runs on. + typedef GR Digraph; + + ///\brief The type of the map that stores the predecessor + ///arcs of the %DFS paths. + /// + ///The type of the map that stores the predecessor + ///arcs of the %DFS paths. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + typedef typename Digraph::template NodeMap PredMap; + ///Instantiates a \c PredMap. + + ///This function instantiates a \ref PredMap. + ///\param g is the digraph, to which we would like to define the + ///\ref PredMap. + static PredMap *createPredMap(const Digraph &g) + { + return new PredMap(g); + } + + ///The type of the map that indicates which nodes are processed. + + ///The type of the map that indicates which nodes are processed. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + ///By default, it is a NullMap. + typedef NullMap ProcessedMap; + ///Instantiates a \c ProcessedMap. + + ///This function instantiates a \ref ProcessedMap. + ///\param g is the digraph, to which + ///we would like to define the \ref ProcessedMap. +#ifdef DOXYGEN + static ProcessedMap *createProcessedMap(const Digraph &g) +#else + static ProcessedMap *createProcessedMap(const Digraph &) +#endif + { + return new ProcessedMap(); + } + + ///The type of the map that indicates which nodes are reached. + + ///The type of the map that indicates which nodes are reached. + ///It must conform to + ///the \ref concepts::ReadWriteMap "ReadWriteMap" concept. + typedef typename Digraph::template NodeMap ReachedMap; + ///Instantiates a \c ReachedMap. + + ///This function instantiates a \ref ReachedMap. + ///\param g is the digraph, to which + ///we would like to define the \ref ReachedMap. + static ReachedMap *createReachedMap(const Digraph &g) + { + return new ReachedMap(g); + } + + ///The type of the map that stores the distances of the nodes. + + ///The type of the map that stores the distances of the nodes. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + typedef typename Digraph::template NodeMap DistMap; + ///Instantiates a \c DistMap. + + ///This function instantiates a \ref DistMap. + ///\param g is the digraph, to which we would like to define the + ///\ref DistMap. + static DistMap *createDistMap(const Digraph &g) + { + return new DistMap(g); + } + }; + + ///%DFS algorithm class. + + ///\ingroup search + ///This class provides an efficient implementation of the %DFS algorithm. + /// + ///There is also a \ref dfs() "function-type interface" for the DFS + ///algorithm, which is convenient in the simplier cases and it can be + ///used easier. + /// + ///\tparam GR The type of the digraph the algorithm runs on. + ///The default type is \ref ListDigraph. + ///\tparam TR The traits class that defines various types used by the + ///algorithm. By default, it is \ref DfsDefaultTraits + ///"DfsDefaultTraits". + ///In most cases, this parameter should not be set directly, + ///consider to use the named template parameters instead. +#ifdef DOXYGEN + template +#else + template > +#endif + class Dfs { + public: + + ///The type of the digraph the algorithm runs on. + typedef typename TR::Digraph Digraph; + + ///\brief The type of the map that stores the predecessor arcs of the + ///DFS paths. + typedef typename TR::PredMap PredMap; + ///The type of the map that stores the distances of the nodes. + typedef typename TR::DistMap DistMap; + ///The type of the map that indicates which nodes are reached. + typedef typename TR::ReachedMap ReachedMap; + ///The type of the map that indicates which nodes are processed. + typedef typename TR::ProcessedMap ProcessedMap; + ///The type of the paths. + typedef PredMapPath Path; + + ///The \ref lemon::DfsDefaultTraits "traits class" of the algorithm. + typedef TR Traits; + + private: + + typedef typename Digraph::Node Node; + typedef typename Digraph::NodeIt NodeIt; + typedef typename Digraph::Arc Arc; + typedef typename Digraph::OutArcIt OutArcIt; + + //Pointer to the underlying digraph. + const Digraph *G; + //Pointer to the map of predecessor arcs. + PredMap *_pred; + //Indicates if _pred is locally allocated (true) or not. + bool local_pred; + //Pointer to the map of distances. + DistMap *_dist; + //Indicates if _dist is locally allocated (true) or not. + bool local_dist; + //Pointer to the map of reached status of the nodes. + ReachedMap *_reached; + //Indicates if _reached is locally allocated (true) or not. + bool local_reached; + //Pointer to the map of processed status of the nodes. + ProcessedMap *_processed; + //Indicates if _processed is locally allocated (true) or not. + bool local_processed; + + std::vector _stack; + int _stack_head; + + //Creates the maps if necessary. + void create_maps() + { + if(!_pred) { + local_pred = true; + _pred = Traits::createPredMap(*G); + } + if(!_dist) { + local_dist = true; + _dist = Traits::createDistMap(*G); + } + if(!_reached) { + local_reached = true; + _reached = Traits::createReachedMap(*G); + } + if(!_processed) { + local_processed = true; + _processed = Traits::createProcessedMap(*G); + } + } + + protected: + + Dfs() {} + + public: + + typedef Dfs Create; + + ///\name Named Template Parameters + + ///@{ + + template + struct SetPredMapTraits : public Traits { + typedef T PredMap; + static PredMap *createPredMap(const Digraph &) + { + LEMON_ASSERT(false, "PredMap is not initialized"); + return 0; // ignore warnings + } + }; + ///\brief \ref named-templ-param "Named parameter" for setting + ///\c PredMap type. + /// + ///\ref named-templ-param "Named parameter" for setting + ///\c PredMap type. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + template + struct SetPredMap : public Dfs > { + typedef Dfs > Create; + }; + + template + struct SetDistMapTraits : public Traits { + typedef T DistMap; + static DistMap *createDistMap(const Digraph &) + { + LEMON_ASSERT(false, "DistMap is not initialized"); + return 0; // ignore warnings + } + }; + ///\brief \ref named-templ-param "Named parameter" for setting + ///\c DistMap type. + /// + ///\ref named-templ-param "Named parameter" for setting + ///\c DistMap type. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + template + struct SetDistMap : public Dfs< Digraph, SetDistMapTraits > { + typedef Dfs > Create; + }; + + template + struct SetReachedMapTraits : public Traits { + typedef T ReachedMap; + static ReachedMap *createReachedMap(const Digraph &) + { + LEMON_ASSERT(false, "ReachedMap is not initialized"); + return 0; // ignore warnings + } + }; + ///\brief \ref named-templ-param "Named parameter" for setting + ///\c ReachedMap type. + /// + ///\ref named-templ-param "Named parameter" for setting + ///\c ReachedMap type. + ///It must conform to + ///the \ref concepts::ReadWriteMap "ReadWriteMap" concept. + template + struct SetReachedMap : public Dfs< Digraph, SetReachedMapTraits > { + typedef Dfs< Digraph, SetReachedMapTraits > Create; + }; + + template + struct SetProcessedMapTraits : public Traits { + typedef T ProcessedMap; + static ProcessedMap *createProcessedMap(const Digraph &) + { + LEMON_ASSERT(false, "ProcessedMap is not initialized"); + return 0; // ignore warnings + } + }; + ///\brief \ref named-templ-param "Named parameter" for setting + ///\c ProcessedMap type. + /// + ///\ref named-templ-param "Named parameter" for setting + ///\c ProcessedMap type. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + template + struct SetProcessedMap : public Dfs< Digraph, SetProcessedMapTraits > { + typedef Dfs< Digraph, SetProcessedMapTraits > Create; + }; + + struct SetStandardProcessedMapTraits : public Traits { + typedef typename Digraph::template NodeMap ProcessedMap; + static ProcessedMap *createProcessedMap(const Digraph &g) + { + return new ProcessedMap(g); + } + }; + ///\brief \ref named-templ-param "Named parameter" for setting + ///\c ProcessedMap type to be Digraph::NodeMap. + /// + ///\ref named-templ-param "Named parameter" for setting + ///\c ProcessedMap type to be Digraph::NodeMap. + ///If you don't set it explicitly, it will be automatically allocated. + struct SetStandardProcessedMap : + public Dfs< Digraph, SetStandardProcessedMapTraits > { + typedef Dfs< Digraph, SetStandardProcessedMapTraits > Create; + }; + + ///@} + + public: + + ///Constructor. + + ///Constructor. + ///\param g The digraph the algorithm runs on. + Dfs(const Digraph &g) : + G(&g), + _pred(NULL), local_pred(false), + _dist(NULL), local_dist(false), + _reached(NULL), local_reached(false), + _processed(NULL), local_processed(false) + { } + + ///Destructor. + ~Dfs() + { + if(local_pred) delete _pred; + if(local_dist) delete _dist; + if(local_reached) delete _reached; + if(local_processed) delete _processed; + } + + ///Sets the map that stores the predecessor arcs. + + ///Sets the map that stores the predecessor arcs. + ///If you don't use this function before calling \ref run(Node) "run()" + ///or \ref init(), an instance will be allocated automatically. + ///The destructor deallocates this automatically allocated map, + ///of course. + ///\return (*this) + Dfs &predMap(PredMap &m) + { + if(local_pred) { + delete _pred; + local_pred=false; + } + _pred = &m; + return *this; + } + + ///Sets the map that indicates which nodes are reached. + + ///Sets the map that indicates which nodes are reached. + ///If you don't use this function before calling \ref run(Node) "run()" + ///or \ref init(), an instance will be allocated automatically. + ///The destructor deallocates this automatically allocated map, + ///of course. + ///\return (*this) + Dfs &reachedMap(ReachedMap &m) + { + if(local_reached) { + delete _reached; + local_reached=false; + } + _reached = &m; + return *this; + } + + ///Sets the map that indicates which nodes are processed. + + ///Sets the map that indicates which nodes are processed. + ///If you don't use this function before calling \ref run(Node) "run()" + ///or \ref init(), an instance will be allocated automatically. + ///The destructor deallocates this automatically allocated map, + ///of course. + ///\return (*this) + Dfs &processedMap(ProcessedMap &m) + { + if(local_processed) { + delete _processed; + local_processed=false; + } + _processed = &m; + return *this; + } + + ///Sets the map that stores the distances of the nodes. + + ///Sets the map that stores the distances of the nodes calculated by + ///the algorithm. + ///If you don't use this function before calling \ref run(Node) "run()" + ///or \ref init(), an instance will be allocated automatically. + ///The destructor deallocates this automatically allocated map, + ///of course. + ///\return (*this) + Dfs &distMap(DistMap &m) + { + if(local_dist) { + delete _dist; + local_dist=false; + } + _dist = &m; + return *this; + } + + public: + + ///\name Execution Control + ///The simplest way to execute the DFS algorithm is to use one of the + ///member functions called \ref run(Node) "run()".\n + ///If you need better control on the execution, you have to call + ///\ref init() first, then you can add a source node with \ref addSource() + ///and perform the actual computation with \ref start(). + ///This procedure can be repeated if there are nodes that have not + ///been reached. + + ///@{ + + ///\brief Initializes the internal data structures. + /// + ///Initializes the internal data structures. + void init() + { + create_maps(); + _stack.resize(countNodes(*G)); + _stack_head=-1; + for ( NodeIt u(*G) ; u!=INVALID ; ++u ) { + _pred->set(u,INVALID); + _reached->set(u,false); + _processed->set(u,false); + } + } + + ///Adds a new source node. + + ///Adds a new source node to the set of nodes to be processed. + /// + ///\pre The stack must be empty. Otherwise the algorithm gives + ///wrong results. (One of the outgoing arcs of all the source nodes + ///except for the last one will not be visited and distances will + ///also be wrong.) + void addSource(Node s) + { + LEMON_DEBUG(emptyQueue(), "The stack is not empty."); + if(!(*_reached)[s]) + { + _reached->set(s,true); + _pred->set(s,INVALID); + OutArcIt e(*G,s); + if(e!=INVALID) { + _stack[++_stack_head]=e; + _dist->set(s,_stack_head); + } + else { + _processed->set(s,true); + _dist->set(s,0); + } + } + } + + ///Processes the next arc. + + ///Processes the next arc. + /// + ///\return The processed arc. + /// + ///\pre The stack must not be empty. + Arc processNextArc() + { + Node m; + Arc e=_stack[_stack_head]; + if(!(*_reached)[m=G->target(e)]) { + _pred->set(m,e); + _reached->set(m,true); + ++_stack_head; + _stack[_stack_head] = OutArcIt(*G, m); + _dist->set(m,_stack_head); + } + else { + m=G->source(e); + ++_stack[_stack_head]; + } + while(_stack_head>=0 && _stack[_stack_head]==INVALID) { + _processed->set(m,true); + --_stack_head; + if(_stack_head>=0) { + m=G->source(_stack[_stack_head]); + ++_stack[_stack_head]; + } + } + return e; + } + + ///Next arc to be processed. + + ///Next arc to be processed. + /// + ///\return The next arc to be processed or \c INVALID if the stack + ///is empty. + OutArcIt nextArc() const + { + return _stack_head>=0?_stack[_stack_head]:INVALID; + } + + ///Returns \c false if there are nodes to be processed. + + ///Returns \c false if there are nodes to be processed + ///in the queue (stack). + bool emptyQueue() const { return _stack_head<0; } + + ///Returns the number of the nodes to be processed. + + ///Returns the number of the nodes to be processed + ///in the queue (stack). + int queueSize() const { return _stack_head+1; } + + ///Executes the algorithm. + + ///Executes the algorithm. + /// + ///This method runs the %DFS algorithm from the root node + ///in order to compute the DFS path to each node. + /// + /// The algorithm computes + ///- the %DFS tree, + ///- the distance of each node from the root in the %DFS tree. + /// + ///\pre init() must be called and a root node should be + ///added with addSource() before using this function. + /// + ///\note d.start() is just a shortcut of the following code. + ///\code + /// while ( !d.emptyQueue() ) { + /// d.processNextArc(); + /// } + ///\endcode + void start() + { + while ( !emptyQueue() ) processNextArc(); + } + + ///Executes the algorithm until the given target node is reached. + + ///Executes the algorithm until the given target node is reached. + /// + ///This method runs the %DFS algorithm from the root node + ///in order to compute the DFS path to \c t. + /// + ///The algorithm computes + ///- the %DFS path to \c t, + ///- the distance of \c t from the root in the %DFS tree. + /// + ///\pre init() must be called and a root node should be + ///added with addSource() before using this function. + void start(Node t) + { + while ( !emptyQueue() && !(*_reached)[t] ) + processNextArc(); + } + + ///Executes the algorithm until a condition is met. + + ///Executes the algorithm until a condition is met. + /// + ///This method runs the %DFS algorithm from the root node + ///until an arc \c a with am[a] true is found. + /// + ///\param am A \c bool (or convertible) arc map. The algorithm + ///will stop when it reaches an arc \c a with am[a] true. + /// + ///\return The reached arc \c a with am[a] true or + ///\c INVALID if no such arc was found. + /// + ///\pre init() must be called and a root node should be + ///added with addSource() before using this function. + /// + ///\warning Contrary to \ref Bfs and \ref Dijkstra, \c am is an arc map, + ///not a node map. + template + Arc start(const ArcBoolMap &am) + { + while ( !emptyQueue() && !am[_stack[_stack_head]] ) + processNextArc(); + return emptyQueue() ? INVALID : _stack[_stack_head]; + } + + ///Runs the algorithm from the given source node. + + ///This method runs the %DFS algorithm from node \c s + ///in order to compute the DFS path to each node. + /// + ///The algorithm computes + ///- the %DFS tree, + ///- the distance of each node from the root in the %DFS tree. + /// + ///\note d.run(s) is just a shortcut of the following code. + ///\code + /// d.init(); + /// d.addSource(s); + /// d.start(); + ///\endcode + void run(Node s) { + init(); + addSource(s); + start(); + } + + ///Finds the %DFS path between \c s and \c t. + + ///This method runs the %DFS algorithm from node \c s + ///in order to compute the DFS path to node \c t + ///(it stops searching when \c t is processed) + /// + ///\return \c true if \c t is reachable form \c s. + /// + ///\note Apart from the return value, d.run(s,t) is + ///just a shortcut of the following code. + ///\code + /// d.init(); + /// d.addSource(s); + /// d.start(t); + ///\endcode + bool run(Node s,Node t) { + init(); + addSource(s); + start(t); + return reached(t); + } + + ///Runs the algorithm to visit all nodes in the digraph. + + ///This method runs the %DFS algorithm in order to visit all nodes + ///in the digraph. + /// + ///\note d.run() is just a shortcut of the following code. + ///\code + /// d.init(); + /// for (NodeIt n(digraph); n != INVALID; ++n) { + /// if (!d.reached(n)) { + /// d.addSource(n); + /// d.start(); + /// } + /// } + ///\endcode + void run() { + init(); + for (NodeIt it(*G); it != INVALID; ++it) { + if (!reached(it)) { + addSource(it); + start(); + } + } + } + + ///@} + + ///\name Query Functions + ///The results of the DFS algorithm can be obtained using these + ///functions.\n + ///Either \ref run(Node) "run()" or \ref start() should be called + ///before using them. + + ///@{ + + ///The DFS path to the given node. + + ///Returns the DFS path to the given node from the root(s). + /// + ///\warning \c t should be reached from the root(s). + /// + ///\pre Either \ref run(Node) "run()" or \ref init() + ///must be called before using this function. + Path path(Node t) const { return Path(*G, *_pred, t); } + + ///The distance of the given node from the root(s). + + ///Returns the distance of the given node from the root(s). + /// + ///\warning If node \c v is not reached from the root(s), then + ///the return value of this function is undefined. + /// + ///\pre Either \ref run(Node) "run()" or \ref init() + ///must be called before using this function. + int dist(Node v) const { return (*_dist)[v]; } + + ///Returns the 'previous arc' of the %DFS tree for the given node. + + ///This function returns the 'previous arc' of the %DFS tree for the + ///node \c v, i.e. it returns the last arc of a %DFS path from a + ///root to \c v. It is \c INVALID if \c v is not reached from the + ///root(s) or if \c v is a root. + /// + ///The %DFS tree used here is equal to the %DFS tree used in + ///\ref predNode() and \ref predMap(). + /// + ///\pre Either \ref run(Node) "run()" or \ref init() + ///must be called before using this function. + Arc predArc(Node v) const { return (*_pred)[v];} + + ///Returns the 'previous node' of the %DFS tree for the given node. + + ///This function returns the 'previous node' of the %DFS + ///tree for the node \c v, i.e. it returns the last but one node + ///of a %DFS path from a root to \c v. It is \c INVALID + ///if \c v is not reached from the root(s) or if \c v is a root. + /// + ///The %DFS tree used here is equal to the %DFS tree used in + ///\ref predArc() and \ref predMap(). + /// + ///\pre Either \ref run(Node) "run()" or \ref init() + ///must be called before using this function. + Node predNode(Node v) const { return (*_pred)[v]==INVALID ? INVALID: + G->source((*_pred)[v]); } + + ///\brief Returns a const reference to the node map that stores the + ///distances of the nodes. + /// + ///Returns a const reference to the node map that stores the + ///distances of the nodes calculated by the algorithm. + /// + ///\pre Either \ref run(Node) "run()" or \ref init() + ///must be called before using this function. + const DistMap &distMap() const { return *_dist;} + + ///\brief Returns a const reference to the node map that stores the + ///predecessor arcs. + /// + ///Returns a const reference to the node map that stores the predecessor + ///arcs, which form the DFS tree (forest). + /// + ///\pre Either \ref run(Node) "run()" or \ref init() + ///must be called before using this function. + const PredMap &predMap() const { return *_pred;} + + ///Checks if the given node. node is reached from the root(s). + + ///Returns \c true if \c v is reached from the root(s). + /// + ///\pre Either \ref run(Node) "run()" or \ref init() + ///must be called before using this function. + bool reached(Node v) const { return (*_reached)[v]; } + + ///@} + }; + + ///Default traits class of dfs() function. + + ///Default traits class of dfs() function. + ///\tparam GR Digraph type. + template + struct DfsWizardDefaultTraits + { + ///The type of the digraph the algorithm runs on. + typedef GR Digraph; + + ///\brief The type of the map that stores the predecessor + ///arcs of the %DFS paths. + /// + ///The type of the map that stores the predecessor + ///arcs of the %DFS paths. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + typedef typename Digraph::template NodeMap PredMap; + ///Instantiates a PredMap. + + ///This function instantiates a PredMap. + ///\param g is the digraph, to which we would like to define the + ///PredMap. + static PredMap *createPredMap(const Digraph &g) + { + return new PredMap(g); + } + + ///The type of the map that indicates which nodes are processed. + + ///The type of the map that indicates which nodes are processed. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + ///By default, it is a NullMap. + typedef NullMap ProcessedMap; + ///Instantiates a ProcessedMap. + + ///This function instantiates a ProcessedMap. + ///\param g is the digraph, to which + ///we would like to define the ProcessedMap. +#ifdef DOXYGEN + static ProcessedMap *createProcessedMap(const Digraph &g) +#else + static ProcessedMap *createProcessedMap(const Digraph &) +#endif + { + return new ProcessedMap(); + } + + ///The type of the map that indicates which nodes are reached. + + ///The type of the map that indicates which nodes are reached. + ///It must conform to + ///the \ref concepts::ReadWriteMap "ReadWriteMap" concept. + typedef typename Digraph::template NodeMap ReachedMap; + ///Instantiates a ReachedMap. + + ///This function instantiates a ReachedMap. + ///\param g is the digraph, to which + ///we would like to define the ReachedMap. + static ReachedMap *createReachedMap(const Digraph &g) + { + return new ReachedMap(g); + } + + ///The type of the map that stores the distances of the nodes. + + ///The type of the map that stores the distances of the nodes. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + typedef typename Digraph::template NodeMap DistMap; + ///Instantiates a DistMap. + + ///This function instantiates a DistMap. + ///\param g is the digraph, to which we would like to define + ///the DistMap + static DistMap *createDistMap(const Digraph &g) + { + return new DistMap(g); + } + + ///The type of the DFS paths. + + ///The type of the DFS paths. + ///It must conform to the \ref concepts::Path "Path" concept. + typedef lemon::Path Path; + }; + + /// Default traits class used by DfsWizard + + /// Default traits class used by DfsWizard. + /// \tparam GR The type of the digraph. + template + class DfsWizardBase : public DfsWizardDefaultTraits + { + + typedef DfsWizardDefaultTraits Base; + protected: + //The type of the nodes in the digraph. + typedef typename Base::Digraph::Node Node; + + //Pointer to the digraph the algorithm runs on. + void *_g; + //Pointer to the map of reached nodes. + void *_reached; + //Pointer to the map of processed nodes. + void *_processed; + //Pointer to the map of predecessors arcs. + void *_pred; + //Pointer to the map of distances. + void *_dist; + //Pointer to the DFS path to the target node. + void *_path; + //Pointer to the distance of the target node. + int *_di; + + public: + /// Constructor. + + /// This constructor does not require parameters, it initiates + /// all of the attributes to \c 0. + DfsWizardBase() : _g(0), _reached(0), _processed(0), _pred(0), + _dist(0), _path(0), _di(0) {} + + /// Constructor. + + /// This constructor requires one parameter, + /// others are initiated to \c 0. + /// \param g The digraph the algorithm runs on. + DfsWizardBase(const GR &g) : + _g(reinterpret_cast(const_cast(&g))), + _reached(0), _processed(0), _pred(0), _dist(0), _path(0), _di(0) {} + + }; + + /// Auxiliary class for the function-type interface of DFS algorithm. + + /// This auxiliary class is created to implement the + /// \ref dfs() "function-type interface" of \ref Dfs algorithm. + /// It does not have own \ref run(Node) "run()" method, it uses the + /// functions and features of the plain \ref Dfs. + /// + /// This class should only be used through the \ref dfs() function, + /// which makes it easier to use the algorithm. + /// + /// \tparam TR The traits class that defines various types used by the + /// algorithm. + template + class DfsWizard : public TR + { + typedef TR Base; + + typedef typename TR::Digraph Digraph; + + typedef typename Digraph::Node Node; + typedef typename Digraph::NodeIt NodeIt; + typedef typename Digraph::Arc Arc; + typedef typename Digraph::OutArcIt OutArcIt; + + typedef typename TR::PredMap PredMap; + typedef typename TR::DistMap DistMap; + typedef typename TR::ReachedMap ReachedMap; + typedef typename TR::ProcessedMap ProcessedMap; + typedef typename TR::Path Path; + + public: + + /// Constructor. + DfsWizard() : TR() {} + + /// Constructor that requires parameters. + + /// Constructor that requires parameters. + /// These parameters will be the default values for the traits class. + /// \param g The digraph the algorithm runs on. + DfsWizard(const Digraph &g) : + TR(g) {} + + ///Copy constructor + DfsWizard(const TR &b) : TR(b) {} + + ~DfsWizard() {} + + ///Runs DFS algorithm from the given source node. + + ///This method runs DFS algorithm from node \c s + ///in order to compute the DFS path to each node. + void run(Node s) + { + Dfs alg(*reinterpret_cast(Base::_g)); + if (Base::_pred) + alg.predMap(*reinterpret_cast(Base::_pred)); + if (Base::_dist) + alg.distMap(*reinterpret_cast(Base::_dist)); + if (Base::_reached) + alg.reachedMap(*reinterpret_cast(Base::_reached)); + if (Base::_processed) + alg.processedMap(*reinterpret_cast(Base::_processed)); + if (s!=INVALID) + alg.run(s); + else + alg.run(); + } + + ///Finds the DFS path between \c s and \c t. + + ///This method runs DFS algorithm from node \c s + ///in order to compute the DFS path to node \c t + ///(it stops searching when \c t is processed). + /// + ///\return \c true if \c t is reachable form \c s. + bool run(Node s, Node t) + { + Dfs alg(*reinterpret_cast(Base::_g)); + if (Base::_pred) + alg.predMap(*reinterpret_cast(Base::_pred)); + if (Base::_dist) + alg.distMap(*reinterpret_cast(Base::_dist)); + if (Base::_reached) + alg.reachedMap(*reinterpret_cast(Base::_reached)); + if (Base::_processed) + alg.processedMap(*reinterpret_cast(Base::_processed)); + alg.run(s,t); + if (Base::_path) + *reinterpret_cast(Base::_path) = alg.path(t); + if (Base::_di) + *Base::_di = alg.dist(t); + return alg.reached(t); + } + + ///Runs DFS algorithm to visit all nodes in the digraph. + + ///This method runs DFS algorithm in order to visit all nodes + ///in the digraph. + void run() + { + run(INVALID); + } + + template + struct SetPredMapBase : public Base { + typedef T PredMap; + static PredMap *createPredMap(const Digraph &) { return 0; }; + SetPredMapBase(const TR &b) : TR(b) {} + }; + + ///\brief \ref named-templ-param "Named parameter" for setting + ///the predecessor map. + /// + ///\ref named-templ-param "Named parameter" function for setting + ///the map that stores the predecessor arcs of the nodes. + template + DfsWizard > predMap(const T &t) + { + Base::_pred=reinterpret_cast(const_cast(&t)); + return DfsWizard >(*this); + } + + template + struct SetReachedMapBase : public Base { + typedef T ReachedMap; + static ReachedMap *createReachedMap(const Digraph &) { return 0; }; + SetReachedMapBase(const TR &b) : TR(b) {} + }; + + ///\brief \ref named-templ-param "Named parameter" for setting + ///the reached map. + /// + ///\ref named-templ-param "Named parameter" function for setting + ///the map that indicates which nodes are reached. + template + DfsWizard > reachedMap(const T &t) + { + Base::_reached=reinterpret_cast(const_cast(&t)); + return DfsWizard >(*this); + } + + template + struct SetDistMapBase : public Base { + typedef T DistMap; + static DistMap *createDistMap(const Digraph &) { return 0; }; + SetDistMapBase(const TR &b) : TR(b) {} + }; + + ///\brief \ref named-templ-param "Named parameter" for setting + ///the distance map. + /// + ///\ref named-templ-param "Named parameter" function for setting + ///the map that stores the distances of the nodes calculated + ///by the algorithm. + template + DfsWizard > distMap(const T &t) + { + Base::_dist=reinterpret_cast(const_cast(&t)); + return DfsWizard >(*this); + } + + template + struct SetProcessedMapBase : public Base { + typedef T ProcessedMap; + static ProcessedMap *createProcessedMap(const Digraph &) { return 0; }; + SetProcessedMapBase(const TR &b) : TR(b) {} + }; + + ///\brief \ref named-func-param "Named parameter" for setting + ///the processed map. + /// + ///\ref named-templ-param "Named parameter" function for setting + ///the map that indicates which nodes are processed. + template + DfsWizard > processedMap(const T &t) + { + Base::_processed=reinterpret_cast(const_cast(&t)); + return DfsWizard >(*this); + } + + template + struct SetPathBase : public Base { + typedef T Path; + SetPathBase(const TR &b) : TR(b) {} + }; + ///\brief \ref named-func-param "Named parameter" + ///for getting the DFS path to the target node. + /// + ///\ref named-func-param "Named parameter" + ///for getting the DFS path to the target node. + template + DfsWizard > path(const T &t) + { + Base::_path=reinterpret_cast(const_cast(&t)); + return DfsWizard >(*this); + } + + ///\brief \ref named-func-param "Named parameter" + ///for getting the distance of the target node. + /// + ///\ref named-func-param "Named parameter" + ///for getting the distance of the target node. + DfsWizard dist(const int &d) + { + Base::_di=const_cast(&d); + return *this; + } + + }; + + ///Function-type interface for DFS algorithm. + + ///\ingroup search + ///Function-type interface for DFS algorithm. + /// + ///This function also has several \ref named-func-param "named parameters", + ///they are declared as the members of class \ref DfsWizard. + ///The following examples show how to use these parameters. + ///\code + /// // Compute the DFS tree + /// dfs(g).predMap(preds).distMap(dists).run(s); + /// + /// // Compute the DFS path from s to t + /// bool reached = dfs(g).path(p).dist(d).run(s,t); + ///\endcode + ///\warning Don't forget to put the \ref DfsWizard::run(Node) "run()" + ///to the end of the parameter list. + ///\sa DfsWizard + ///\sa Dfs + template + DfsWizard > + dfs(const GR &digraph) + { + return DfsWizard >(digraph); + } + +#ifdef DOXYGEN + /// \brief Visitor class for DFS. + /// + /// This class defines the interface of the DfsVisit events, and + /// it could be the base of a real visitor class. + template + struct DfsVisitor { + typedef GR Digraph; + typedef typename Digraph::Arc Arc; + typedef typename Digraph::Node Node; + /// \brief Called for the source node of the DFS. + /// + /// This function is called for the source node of the DFS. + void start(const Node& node) {} + /// \brief Called when the source node is leaved. + /// + /// This function is called when the source node is leaved. + void stop(const Node& node) {} + /// \brief Called when a node is reached first time. + /// + /// This function is called when a node is reached first time. + void reach(const Node& node) {} + /// \brief Called when an arc reaches a new node. + /// + /// This function is called when the DFS finds an arc whose target node + /// is not reached yet. + void discover(const Arc& arc) {} + /// \brief Called when an arc is examined but its target node is + /// already discovered. + /// + /// This function is called when an arc is examined but its target node is + /// already discovered. + void examine(const Arc& arc) {} + /// \brief Called when the DFS steps back from a node. + /// + /// This function is called when the DFS steps back from a node. + void leave(const Node& node) {} + /// \brief Called when the DFS steps back on an arc. + /// + /// This function is called when the DFS steps back on an arc. + void backtrack(const Arc& arc) {} + }; +#else + template + struct DfsVisitor { + typedef GR Digraph; + typedef typename Digraph::Arc Arc; + typedef typename Digraph::Node Node; + void start(const Node&) {} + void stop(const Node&) {} + void reach(const Node&) {} + void discover(const Arc&) {} + void examine(const Arc&) {} + void leave(const Node&) {} + void backtrack(const Arc&) {} + + template + struct Constraints { + void constraints() { + Arc arc; + Node node; + visitor.start(node); + visitor.stop(arc); + visitor.reach(node); + visitor.discover(arc); + visitor.examine(arc); + visitor.leave(node); + visitor.backtrack(arc); + } + _Visitor& visitor; + Constraints() {} + }; + }; +#endif + + /// \brief Default traits class of DfsVisit class. + /// + /// Default traits class of DfsVisit class. + /// \tparam _Digraph The type of the digraph the algorithm runs on. + template + struct DfsVisitDefaultTraits { + + /// \brief The type of the digraph the algorithm runs on. + typedef GR Digraph; + + /// \brief The type of the map that indicates which nodes are reached. + /// + /// The type of the map that indicates which nodes are reached. + /// It must conform to the + /// \ref concepts::ReadWriteMap "ReadWriteMap" concept. + typedef typename Digraph::template NodeMap ReachedMap; + + /// \brief Instantiates a ReachedMap. + /// + /// This function instantiates a ReachedMap. + /// \param digraph is the digraph, to which + /// we would like to define the ReachedMap. + static ReachedMap *createReachedMap(const Digraph &digraph) { + return new ReachedMap(digraph); + } + + }; + + /// \ingroup search + /// + /// \brief DFS algorithm class with visitor interface. + /// + /// This class provides an efficient implementation of the DFS algorithm + /// with visitor interface. + /// + /// The DfsVisit class provides an alternative interface to the Dfs + /// class. It works with callback mechanism, the DfsVisit object calls + /// the member functions of the \c Visitor class on every DFS event. + /// + /// This interface of the DFS algorithm should be used in special cases + /// when extra actions have to be performed in connection with certain + /// events of the DFS algorithm. Otherwise consider to use Dfs or dfs() + /// instead. + /// + /// \tparam GR The type of the digraph the algorithm runs on. + /// The default type is \ref ListDigraph. + /// The value of GR is not used directly by \ref DfsVisit, + /// it is only passed to \ref DfsVisitDefaultTraits. + /// \tparam VS The Visitor type that is used by the algorithm. + /// \ref DfsVisitor "DfsVisitor" is an empty visitor, which + /// does not observe the DFS events. If you want to observe the DFS + /// events, you should implement your own visitor class. + /// \tparam TR The traits class that defines various types used by the + /// algorithm. By default, it is \ref DfsVisitDefaultTraits + /// "DfsVisitDefaultTraits". + /// In most cases, this parameter should not be set directly, + /// consider to use the named template parameters instead. +#ifdef DOXYGEN + template +#else + template , + typename TR = DfsVisitDefaultTraits > +#endif + class DfsVisit { + public: + + ///The traits class. + typedef TR Traits; + + ///The type of the digraph the algorithm runs on. + typedef typename Traits::Digraph Digraph; + + ///The visitor type used by the algorithm. + typedef VS Visitor; + + ///The type of the map that indicates which nodes are reached. + typedef typename Traits::ReachedMap ReachedMap; + + private: + + typedef typename Digraph::Node Node; + typedef typename Digraph::NodeIt NodeIt; + typedef typename Digraph::Arc Arc; + typedef typename Digraph::OutArcIt OutArcIt; + + //Pointer to the underlying digraph. + const Digraph *_digraph; + //Pointer to the visitor object. + Visitor *_visitor; + //Pointer to the map of reached status of the nodes. + ReachedMap *_reached; + //Indicates if _reached is locally allocated (true) or not. + bool local_reached; + + std::vector _stack; + int _stack_head; + + //Creates the maps if necessary. + void create_maps() { + if(!_reached) { + local_reached = true; + _reached = Traits::createReachedMap(*_digraph); + } + } + + protected: + + DfsVisit() {} + + public: + + typedef DfsVisit Create; + + /// \name Named Template Parameters + + ///@{ + template + struct SetReachedMapTraits : public Traits { + typedef T ReachedMap; + static ReachedMap *createReachedMap(const Digraph &digraph) { + LEMON_ASSERT(false, "ReachedMap is not initialized"); + return 0; // ignore warnings + } + }; + /// \brief \ref named-templ-param "Named parameter" for setting + /// ReachedMap type. + /// + /// \ref named-templ-param "Named parameter" for setting ReachedMap type. + template + struct SetReachedMap : public DfsVisit< Digraph, Visitor, + SetReachedMapTraits > { + typedef DfsVisit< Digraph, Visitor, SetReachedMapTraits > Create; + }; + ///@} + + public: + + /// \brief Constructor. + /// + /// Constructor. + /// + /// \param digraph The digraph the algorithm runs on. + /// \param visitor The visitor object of the algorithm. + DfsVisit(const Digraph& digraph, Visitor& visitor) + : _digraph(&digraph), _visitor(&visitor), + _reached(0), local_reached(false) {} + + /// \brief Destructor. + ~DfsVisit() { + if(local_reached) delete _reached; + } + + /// \brief Sets the map that indicates which nodes are reached. + /// + /// Sets the map that indicates which nodes are reached. + /// If you don't use this function before calling \ref run(Node) "run()" + /// or \ref init(), an instance will be allocated automatically. + /// The destructor deallocates this automatically allocated map, + /// of course. + /// \return (*this) + DfsVisit &reachedMap(ReachedMap &m) { + if(local_reached) { + delete _reached; + local_reached=false; + } + _reached = &m; + return *this; + } + + public: + + /// \name Execution Control + /// The simplest way to execute the DFS algorithm is to use one of the + /// member functions called \ref run(Node) "run()".\n + /// If you need better control on the execution, you have to call + /// \ref init() first, then you can add a source node with \ref addSource() + /// and perform the actual computation with \ref start(). + /// This procedure can be repeated if there are nodes that have not + /// been reached. + + /// @{ + + /// \brief Initializes the internal data structures. + /// + /// Initializes the internal data structures. + void init() { + create_maps(); + _stack.resize(countNodes(*_digraph)); + _stack_head = -1; + for (NodeIt u(*_digraph) ; u != INVALID ; ++u) { + _reached->set(u, false); + } + } + + /// \brief Adds a new source node. + /// + /// Adds a new source node to the set of nodes to be processed. + /// + /// \pre The stack must be empty. Otherwise the algorithm gives + /// wrong results. (One of the outgoing arcs of all the source nodes + /// except for the last one will not be visited and distances will + /// also be wrong.) + void addSource(Node s) + { + LEMON_DEBUG(emptyQueue(), "The stack is not empty."); + if(!(*_reached)[s]) { + _reached->set(s,true); + _visitor->start(s); + _visitor->reach(s); + Arc e; + _digraph->firstOut(e, s); + if (e != INVALID) { + _stack[++_stack_head] = e; + } else { + _visitor->leave(s); + _visitor->stop(s); + } + } + } + + /// \brief Processes the next arc. + /// + /// Processes the next arc. + /// + /// \return The processed arc. + /// + /// \pre The stack must not be empty. + Arc processNextArc() { + Arc e = _stack[_stack_head]; + Node m = _digraph->target(e); + if(!(*_reached)[m]) { + _visitor->discover(e); + _visitor->reach(m); + _reached->set(m, true); + _digraph->firstOut(_stack[++_stack_head], m); + } else { + _visitor->examine(e); + m = _digraph->source(e); + _digraph->nextOut(_stack[_stack_head]); + } + while (_stack_head>=0 && _stack[_stack_head] == INVALID) { + _visitor->leave(m); + --_stack_head; + if (_stack_head >= 0) { + _visitor->backtrack(_stack[_stack_head]); + m = _digraph->source(_stack[_stack_head]); + _digraph->nextOut(_stack[_stack_head]); + } else { + _visitor->stop(m); + } + } + return e; + } + + /// \brief Next arc to be processed. + /// + /// Next arc to be processed. + /// + /// \return The next arc to be processed or INVALID if the stack is + /// empty. + Arc nextArc() const { + return _stack_head >= 0 ? _stack[_stack_head] : INVALID; + } + + /// \brief Returns \c false if there are nodes + /// to be processed. + /// + /// Returns \c false if there are nodes + /// to be processed in the queue (stack). + bool emptyQueue() const { return _stack_head < 0; } + + /// \brief Returns the number of the nodes to be processed. + /// + /// Returns the number of the nodes to be processed in the queue (stack). + int queueSize() const { return _stack_head + 1; } + + /// \brief Executes the algorithm. + /// + /// Executes the algorithm. + /// + /// This method runs the %DFS algorithm from the root node + /// in order to compute the %DFS path to each node. + /// + /// The algorithm computes + /// - the %DFS tree, + /// - the distance of each node from the root in the %DFS tree. + /// + /// \pre init() must be called and a root node should be + /// added with addSource() before using this function. + /// + /// \note d.start() is just a shortcut of the following code. + /// \code + /// while ( !d.emptyQueue() ) { + /// d.processNextArc(); + /// } + /// \endcode + void start() { + while ( !emptyQueue() ) processNextArc(); + } + + /// \brief Executes the algorithm until the given target node is reached. + /// + /// Executes the algorithm until the given target node is reached. + /// + /// This method runs the %DFS algorithm from the root node + /// in order to compute the DFS path to \c t. + /// + /// The algorithm computes + /// - the %DFS path to \c t, + /// - the distance of \c t from the root in the %DFS tree. + /// + /// \pre init() must be called and a root node should be added + /// with addSource() before using this function. + void start(Node t) { + while ( !emptyQueue() && !(*_reached)[t] ) + processNextArc(); + } + + /// \brief Executes the algorithm until a condition is met. + /// + /// Executes the algorithm until a condition is met. + /// + /// This method runs the %DFS algorithm from the root node + /// until an arc \c a with am[a] true is found. + /// + /// \param am A \c bool (or convertible) arc map. The algorithm + /// will stop when it reaches an arc \c a with am[a] true. + /// + /// \return The reached arc \c a with am[a] true or + /// \c INVALID if no such arc was found. + /// + /// \pre init() must be called and a root node should be added + /// with addSource() before using this function. + /// + /// \warning Contrary to \ref Bfs and \ref Dijkstra, \c am is an arc map, + /// not a node map. + template + Arc start(const AM &am) { + while ( !emptyQueue() && !am[_stack[_stack_head]] ) + processNextArc(); + return emptyQueue() ? INVALID : _stack[_stack_head]; + } + + /// \brief Runs the algorithm from the given source node. + /// + /// This method runs the %DFS algorithm from node \c s. + /// in order to compute the DFS path to each node. + /// + /// The algorithm computes + /// - the %DFS tree, + /// - the distance of each node from the root in the %DFS tree. + /// + /// \note d.run(s) is just a shortcut of the following code. + ///\code + /// d.init(); + /// d.addSource(s); + /// d.start(); + ///\endcode + void run(Node s) { + init(); + addSource(s); + start(); + } + + /// \brief Finds the %DFS path between \c s and \c t. + + /// This method runs the %DFS algorithm from node \c s + /// in order to compute the DFS path to node \c t + /// (it stops searching when \c t is processed). + /// + /// \return \c true if \c t is reachable form \c s. + /// + /// \note Apart from the return value, d.run(s,t) is + /// just a shortcut of the following code. + ///\code + /// d.init(); + /// d.addSource(s); + /// d.start(t); + ///\endcode + bool run(Node s,Node t) { + init(); + addSource(s); + start(t); + return reached(t); + } + + /// \brief Runs the algorithm to visit all nodes in the digraph. + + /// This method runs the %DFS algorithm in order to visit all nodes + /// in the digraph. + /// + /// \note d.run() is just a shortcut of the following code. + ///\code + /// d.init(); + /// for (NodeIt n(digraph); n != INVALID; ++n) { + /// if (!d.reached(n)) { + /// d.addSource(n); + /// d.start(); + /// } + /// } + ///\endcode + void run() { + init(); + for (NodeIt it(*_digraph); it != INVALID; ++it) { + if (!reached(it)) { + addSource(it); + start(); + } + } + } + + ///@} + + /// \name Query Functions + /// The results of the DFS algorithm can be obtained using these + /// functions.\n + /// Either \ref run(Node) "run()" or \ref start() should be called + /// before using them. + + ///@{ + + /// \brief Checks if the given node is reached from the root(s). + /// + /// Returns \c true if \c v is reached from the root(s). + /// + /// \pre Either \ref run(Node) "run()" or \ref init() + /// must be called before using this function. + bool reached(Node v) const { return (*_reached)[v]; } + + ///@} + + }; + +} //END OF NAMESPACE LEMON + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/dheap.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/dheap.h new file mode 100644 index 00000000000..a3ab62525aa --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/dheap.h @@ -0,0 +1,352 @@ +/* -*- 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_DHEAP_H +#define LEMON_DHEAP_H + +///\ingroup heaps +///\file +///\brief D-ary heap implementation. + +#include +#include +#include + +namespace lemon { + + /// \ingroup heaps + /// + ///\brief D-ary heap data structure. + /// + /// This class implements the \e D-ary \e heap data structure. + /// It fully conforms to the \ref concepts::Heap "heap concept". + /// + /// The \ref DHeap "D-ary heap" is a generalization of the + /// \ref BinHeap "binary heap" structure, its nodes have at most + /// \c D children, instead of two. + /// \ref BinHeap and \ref QuadHeap are specialized implementations + /// of this structure for D=2 and D=4, respectively. + /// + /// \tparam PR Type of the priorities of the items. + /// \tparam IM A read-writable item map with \c int values, used + /// internally to handle the cross references. + /// \tparam D The degree of the heap, each node have at most \e D + /// children. The default is 16. Powers of two are suggested to use + /// so that the multiplications and divisions needed to traverse the + /// nodes of the heap could be performed faster. + /// \tparam CMP A functor class for comparing the priorities. + /// The default is \c std::less. + /// + ///\sa BinHeap + ///\sa FouraryHeap +#ifdef DOXYGEN + template +#else + template > +#endif + class DHeap { + public: + /// Type of the item-int map. + typedef IM ItemIntMap; + /// Type of the priorities. + typedef PR Prio; + /// Type of the items stored in the heap. + typedef typename ItemIntMap::Key Item; + /// Type of the item-priority pairs. + typedef std::pair Pair; + /// Functor type for comparing the priorities. + typedef CMP Compare; + + /// \brief Type to represent the states of the items. + /// + /// Each item has a state associated to it. It can be "in heap", + /// "pre-heap" or "post-heap". The latter two are indifferent from the + /// heap's point of view, but may be useful to the user. + /// + /// The item-int map must be initialized in such way that it assigns + /// \c PRE_HEAP (-1) to any element to be put in the heap. + enum State { + IN_HEAP = 0, ///< = 0. + PRE_HEAP = -1, ///< = -1. + POST_HEAP = -2 ///< = -2. + }; + + private: + std::vector _data; + Compare _comp; + ItemIntMap &_iim; + + public: + /// \brief Constructor. + /// + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. + explicit DHeap(ItemIntMap &map) : _iim(map) {} + + /// \brief Constructor. + /// + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. + /// \param comp The function object used for comparing the priorities. + DHeap(ItemIntMap &map, const Compare &comp) + : _iim(map), _comp(comp) {} + + /// \brief The number of items stored in the heap. + /// + /// This function returns the number of items stored in the heap. + int size() const { return _data.size(); } + + /// \brief Check if the heap is empty. + /// + /// This function returns \c true if the heap is empty. + bool empty() const { return _data.empty(); } + + /// \brief Make the heap empty. + /// + /// This functon makes the heap empty. + /// It does not change the cross reference map. If you want to reuse + /// a heap that is not surely empty, you should first clear it and + /// then you should set the cross reference map to \c PRE_HEAP + /// for each item. + void clear() { _data.clear(); } + + private: + int parent(int i) { return (i-1)/D; } + int firstChild(int i) { return D*i+1; } + + bool less(const Pair &p1, const Pair &p2) const { + return _comp(p1.second, p2.second); + } + + void bubbleUp(int hole, Pair p) { + int par = parent(hole); + while( hole>0 && less(p,_data[par]) ) { + move(_data[par],hole); + hole = par; + par = parent(hole); + } + move(p, hole); + } + + void bubbleDown(int hole, Pair p, int length) { + if( length>1 ) { + int child = firstChild(hole); + while( child+D<=length ) { + int min=child; + for (int i=1; i0) bubbleDown(0, _data[n], n); + _data.pop_back(); + } + + /// \brief Remove the given item from the heap. + /// + /// This function removes the given item from the heap if it is + /// already stored. + /// \param i The item to delete. + /// \pre \e i must be in the heap. + void erase(const Item &i) { + int h = _iim[i]; + int n = _data.size()-1; + _iim.set(_data[h].first, POST_HEAP); + if( h=0) s=0; + return State(s); + } + + /// \brief Set the state of an item in the heap. + /// + /// This function sets the state of the given item in the heap. + /// It can be used to manually clear the heap when it is important + /// to achive better time complexity. + /// \param i The item. + /// \param st The state. It should not be \c IN_HEAP. + void state(const Item& i, State st) { + switch (st) { + case POST_HEAP: + case PRE_HEAP: + if (state(i) == IN_HEAP) erase(i); + _iim[i] = st; + break; + case IN_HEAP: + break; + } + } + + /// \brief Replace an item in the heap. + /// + /// This function replaces item \c i with item \c j. + /// Item \c i must be in the heap, while \c j must be out of the heap. + /// After calling this method, item \c i will be out of the + /// heap and \c j will be in the heap with the same prioriority + /// as item \c i had before. + void replace(const Item& i, const Item& j) { + int idx=_iim[i]; + _iim.set(i, _iim[j]); + _iim.set(j, idx); + _data[idx].first=j; + } + + }; // class DHeap + +} // namespace lemon + +#endif // LEMON_DHEAP_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/dijkstra.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/dijkstra.h new file mode 100644 index 00000000000..1564a03e6ec --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/dijkstra.h @@ -0,0 +1,1303 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_DIJKSTRA_H +#define LEMON_DIJKSTRA_H + +///\ingroup shortest_path +///\file +///\brief Dijkstra algorithm. + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace lemon { + + /// \brief Default operation traits for the Dijkstra algorithm class. + /// + /// This operation traits class defines all computational operations and + /// constants which are used in the Dijkstra algorithm. + template + struct DijkstraDefaultOperationTraits { + /// \e + typedef V Value; + /// \brief Gives back the zero value of the type. + static Value zero() { + return static_cast(0); + } + /// \brief Gives back the sum of the given two elements. + static Value plus(const Value& left, const Value& right) { + return left + right; + } + /// \brief Gives back true only if the first value is less than the second. + static bool less(const Value& left, const Value& right) { + return left < right; + } + }; + + ///Default traits class of Dijkstra class. + + ///Default traits class of Dijkstra class. + ///\tparam GR The type of the digraph. + ///\tparam LEN The type of the length map. + template + struct DijkstraDefaultTraits + { + ///The type of the digraph the algorithm runs on. + typedef GR Digraph; + + ///The type of the map that stores the arc lengths. + + ///The type of the map that stores the arc lengths. + ///It must conform to the \ref concepts::ReadMap "ReadMap" concept. + typedef LEN LengthMap; + ///The type of the arc lengths. + typedef typename LEN::Value Value; + + /// Operation traits for %Dijkstra algorithm. + + /// This class defines the operations that are used in the algorithm. + /// \see DijkstraDefaultOperationTraits + typedef DijkstraDefaultOperationTraits OperationTraits; + + /// The cross reference type used by the heap. + + /// The cross reference type used by the heap. + /// Usually it is \c Digraph::NodeMap. + typedef typename Digraph::template NodeMap HeapCrossRef; + ///Instantiates a \c HeapCrossRef. + + ///This function instantiates a \ref HeapCrossRef. + /// \param g is the digraph, to which we would like to define the + /// \ref HeapCrossRef. + static HeapCrossRef *createHeapCrossRef(const Digraph &g) + { + return new HeapCrossRef(g); + } + + ///The heap type used by the %Dijkstra algorithm. + + ///The heap type used by the Dijkstra algorithm. + /// + ///\sa BinHeap + ///\sa Dijkstra + typedef BinHeap > Heap; + ///Instantiates a \c Heap. + + ///This function instantiates a \ref Heap. + static Heap *createHeap(HeapCrossRef& r) + { + return new Heap(r); + } + + ///\brief The type of the map that stores the predecessor + ///arcs of the shortest paths. + /// + ///The type of the map that stores the predecessor + ///arcs of the shortest paths. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + typedef typename Digraph::template NodeMap PredMap; + ///Instantiates a \c PredMap. + + ///This function instantiates a \ref PredMap. + ///\param g is the digraph, to which we would like to define the + ///\ref PredMap. + static PredMap *createPredMap(const Digraph &g) + { + return new PredMap(g); + } + + ///The type of the map that indicates which nodes are processed. + + ///The type of the map that indicates which nodes are processed. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + ///By default, it is a NullMap. + typedef NullMap ProcessedMap; + ///Instantiates a \c ProcessedMap. + + ///This function instantiates a \ref ProcessedMap. + ///\param g is the digraph, to which + ///we would like to define the \ref ProcessedMap. +#ifdef DOXYGEN + static ProcessedMap *createProcessedMap(const Digraph &g) +#else + static ProcessedMap *createProcessedMap(const Digraph &) +#endif + { + return new ProcessedMap(); + } + + ///The type of the map that stores the distances of the nodes. + + ///The type of the map that stores the distances of the nodes. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + typedef typename Digraph::template NodeMap DistMap; + ///Instantiates a \c DistMap. + + ///This function instantiates a \ref DistMap. + ///\param g is the digraph, to which we would like to define + ///the \ref DistMap. + static DistMap *createDistMap(const Digraph &g) + { + return new DistMap(g); + } + }; + + ///%Dijkstra algorithm class. + + /// \ingroup shortest_path + ///This class provides an efficient implementation of the %Dijkstra algorithm. + /// + ///The %Dijkstra algorithm solves the single-source shortest path problem + ///when all arc lengths are non-negative. If there are negative lengths, + ///the BellmanFord algorithm should be used instead. + /// + ///The arc lengths are passed to the algorithm using a + ///\ref concepts::ReadMap "ReadMap", + ///so it is easy to change it to any kind of length. + ///The type of the length is determined by the + ///\ref concepts::ReadMap::Value "Value" of the length map. + ///It is also possible to change the underlying priority heap. + /// + ///There is also a \ref dijkstra() "function-type interface" for the + ///%Dijkstra algorithm, which is convenient in the simplier cases and + ///it can be used easier. + /// + ///\tparam GR The type of the digraph the algorithm runs on. + ///The default type is \ref ListDigraph. + ///\tparam LEN A \ref concepts::ReadMap "readable" arc map that specifies + ///the lengths of the arcs. + ///It is read once for each arc, so the map may involve in + ///relatively time consuming process to compute the arc lengths if + ///it is necessary. The default map type is \ref + ///concepts::Digraph::ArcMap "GR::ArcMap". + ///\tparam TR The traits class that defines various types used by the + ///algorithm. By default, it is \ref DijkstraDefaultTraits + ///"DijkstraDefaultTraits". + ///In most cases, this parameter should not be set directly, + ///consider to use the named template parameters instead. +#ifdef DOXYGEN + template +#else + template , + typename TR=DijkstraDefaultTraits > +#endif + class Dijkstra { + public: + + ///The type of the digraph the algorithm runs on. + typedef typename TR::Digraph Digraph; + + ///The type of the arc lengths. + typedef typename TR::Value Value; + ///The type of the map that stores the arc lengths. + typedef typename TR::LengthMap LengthMap; + ///\brief The type of the map that stores the predecessor arcs of the + ///shortest paths. + typedef typename TR::PredMap PredMap; + ///The type of the map that stores the distances of the nodes. + typedef typename TR::DistMap DistMap; + ///The type of the map that indicates which nodes are processed. + typedef typename TR::ProcessedMap ProcessedMap; + ///The type of the paths. + typedef PredMapPath Path; + ///The cross reference type used for the current heap. + typedef typename TR::HeapCrossRef HeapCrossRef; + ///The heap type used by the algorithm. + typedef typename TR::Heap Heap; + /// \brief The \ref lemon::DijkstraDefaultOperationTraits + /// "operation traits class" of the algorithm. + typedef typename TR::OperationTraits OperationTraits; + + ///The \ref lemon::DijkstraDefaultTraits "traits class" of the algorithm. + typedef TR Traits; + + private: + + typedef typename Digraph::Node Node; + typedef typename Digraph::NodeIt NodeIt; + typedef typename Digraph::Arc Arc; + typedef typename Digraph::OutArcIt OutArcIt; + + //Pointer to the underlying digraph. + const Digraph *G; + //Pointer to the length map. + const LengthMap *_length; + //Pointer to the map of predecessors arcs. + PredMap *_pred; + //Indicates if _pred is locally allocated (true) or not. + bool local_pred; + //Pointer to the map of distances. + DistMap *_dist; + //Indicates if _dist is locally allocated (true) or not. + bool local_dist; + //Pointer to the map of processed status of the nodes. + ProcessedMap *_processed; + //Indicates if _processed is locally allocated (true) or not. + bool local_processed; + //Pointer to the heap cross references. + HeapCrossRef *_heap_cross_ref; + //Indicates if _heap_cross_ref is locally allocated (true) or not. + bool local_heap_cross_ref; + //Pointer to the heap. + Heap *_heap; + //Indicates if _heap is locally allocated (true) or not. + bool local_heap; + + //Creates the maps if necessary. + void create_maps() + { + if(!_pred) { + local_pred = true; + _pred = Traits::createPredMap(*G); + } + if(!_dist) { + local_dist = true; + _dist = Traits::createDistMap(*G); + } + if(!_processed) { + local_processed = true; + _processed = Traits::createProcessedMap(*G); + } + if (!_heap_cross_ref) { + local_heap_cross_ref = true; + _heap_cross_ref = Traits::createHeapCrossRef(*G); + } + if (!_heap) { + local_heap = true; + _heap = Traits::createHeap(*_heap_cross_ref); + } + } + + public: + + typedef Dijkstra Create; + + ///\name Named Template Parameters + + ///@{ + + template + struct SetPredMapTraits : public Traits { + typedef T PredMap; + static PredMap *createPredMap(const Digraph &) + { + LEMON_ASSERT(false, "PredMap is not initialized"); + return 0; // ignore warnings + } + }; + ///\brief \ref named-templ-param "Named parameter" for setting + ///\c PredMap type. + /// + ///\ref named-templ-param "Named parameter" for setting + ///\c PredMap type. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + template + struct SetPredMap + : public Dijkstra< Digraph, LengthMap, SetPredMapTraits > { + typedef Dijkstra< Digraph, LengthMap, SetPredMapTraits > Create; + }; + + template + struct SetDistMapTraits : public Traits { + typedef T DistMap; + static DistMap *createDistMap(const Digraph &) + { + LEMON_ASSERT(false, "DistMap is not initialized"); + return 0; // ignore warnings + } + }; + ///\brief \ref named-templ-param "Named parameter" for setting + ///\c DistMap type. + /// + ///\ref named-templ-param "Named parameter" for setting + ///\c DistMap type. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + template + struct SetDistMap + : public Dijkstra< Digraph, LengthMap, SetDistMapTraits > { + typedef Dijkstra< Digraph, LengthMap, SetDistMapTraits > Create; + }; + + template + struct SetProcessedMapTraits : public Traits { + typedef T ProcessedMap; + static ProcessedMap *createProcessedMap(const Digraph &) + { + LEMON_ASSERT(false, "ProcessedMap is not initialized"); + return 0; // ignore warnings + } + }; + ///\brief \ref named-templ-param "Named parameter" for setting + ///\c ProcessedMap type. + /// + ///\ref named-templ-param "Named parameter" for setting + ///\c ProcessedMap type. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + template + struct SetProcessedMap + : public Dijkstra< Digraph, LengthMap, SetProcessedMapTraits > { + typedef Dijkstra< Digraph, LengthMap, SetProcessedMapTraits > Create; + }; + + struct SetStandardProcessedMapTraits : public Traits { + typedef typename Digraph::template NodeMap ProcessedMap; + static ProcessedMap *createProcessedMap(const Digraph &g) + { + return new ProcessedMap(g); + } + }; + ///\brief \ref named-templ-param "Named parameter" for setting + ///\c ProcessedMap type to be Digraph::NodeMap. + /// + ///\ref named-templ-param "Named parameter" for setting + ///\c ProcessedMap type to be Digraph::NodeMap. + ///If you don't set it explicitly, it will be automatically allocated. + struct SetStandardProcessedMap + : public Dijkstra< Digraph, LengthMap, SetStandardProcessedMapTraits > { + typedef Dijkstra< Digraph, LengthMap, SetStandardProcessedMapTraits > + Create; + }; + + template + struct SetHeapTraits : public Traits { + typedef CR HeapCrossRef; + typedef H Heap; + static HeapCrossRef *createHeapCrossRef(const Digraph &) { + LEMON_ASSERT(false, "HeapCrossRef is not initialized"); + return 0; // ignore warnings + } + static Heap *createHeap(HeapCrossRef &) + { + LEMON_ASSERT(false, "Heap is not initialized"); + return 0; // ignore warnings + } + }; + ///\brief \ref named-templ-param "Named parameter" for setting + ///heap and cross reference types + /// + ///\ref named-templ-param "Named parameter" for setting heap and cross + ///reference types. If this named parameter is used, then external + ///heap and cross reference objects must be passed to the algorithm + ///using the \ref heap() function before calling \ref run(Node) "run()" + ///or \ref init(). + ///\sa SetStandardHeap + template > + struct SetHeap + : public Dijkstra< Digraph, LengthMap, SetHeapTraits > { + typedef Dijkstra< Digraph, LengthMap, SetHeapTraits > Create; + }; + + template + struct SetStandardHeapTraits : public Traits { + typedef CR HeapCrossRef; + typedef H Heap; + static HeapCrossRef *createHeapCrossRef(const Digraph &G) { + return new HeapCrossRef(G); + } + static Heap *createHeap(HeapCrossRef &R) + { + return new Heap(R); + } + }; + ///\brief \ref named-templ-param "Named parameter" for setting + ///heap and cross reference types with automatic allocation + /// + ///\ref named-templ-param "Named parameter" for setting heap and cross + ///reference types with automatic allocation. + ///They should have standard constructor interfaces to be able to + ///automatically created by the algorithm (i.e. the digraph should be + ///passed to the constructor of the cross reference and the cross + ///reference should be passed to the constructor of the heap). + ///However, external heap and cross reference objects could also be + ///passed to the algorithm using the \ref heap() function before + ///calling \ref run(Node) "run()" or \ref init(). + ///\sa SetHeap + template > + struct SetStandardHeap + : public Dijkstra< Digraph, LengthMap, SetStandardHeapTraits > { + typedef Dijkstra< Digraph, LengthMap, SetStandardHeapTraits > + Create; + }; + + template + struct SetOperationTraitsTraits : public Traits { + typedef T OperationTraits; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + ///\c OperationTraits type + /// + ///\ref named-templ-param "Named parameter" for setting + ///\c OperationTraits type. + /// For more information, see \ref DijkstraDefaultOperationTraits. + template + struct SetOperationTraits + : public Dijkstra > { + typedef Dijkstra > + Create; + }; + + ///@} + + protected: + + Dijkstra() {} + + public: + + ///Constructor. + + ///Constructor. + ///\param g The digraph the algorithm runs on. + ///\param length The length map used by the algorithm. + Dijkstra(const Digraph& g, const LengthMap& length) : + G(&g), _length(&length), + _pred(NULL), local_pred(false), + _dist(NULL), local_dist(false), + _processed(NULL), local_processed(false), + _heap_cross_ref(NULL), local_heap_cross_ref(false), + _heap(NULL), local_heap(false) + { } + + ///Destructor. + ~Dijkstra() + { + if(local_pred) delete _pred; + if(local_dist) delete _dist; + if(local_processed) delete _processed; + if(local_heap_cross_ref) delete _heap_cross_ref; + if(local_heap) delete _heap; + } + + ///Sets the length map. + + ///Sets the length map. + ///\return (*this) + Dijkstra &lengthMap(const LengthMap &m) + { + _length = &m; + return *this; + } + + ///Sets the map that stores the predecessor arcs. + + ///Sets the map that stores the predecessor arcs. + ///If you don't use this function before calling \ref run(Node) "run()" + ///or \ref init(), an instance will be allocated automatically. + ///The destructor deallocates this automatically allocated map, + ///of course. + ///\return (*this) + Dijkstra &predMap(PredMap &m) + { + if(local_pred) { + delete _pred; + local_pred=false; + } + _pred = &m; + return *this; + } + + ///Sets the map that indicates which nodes are processed. + + ///Sets the map that indicates which nodes are processed. + ///If you don't use this function before calling \ref run(Node) "run()" + ///or \ref init(), an instance will be allocated automatically. + ///The destructor deallocates this automatically allocated map, + ///of course. + ///\return (*this) + Dijkstra &processedMap(ProcessedMap &m) + { + if(local_processed) { + delete _processed; + local_processed=false; + } + _processed = &m; + return *this; + } + + ///Sets the map that stores the distances of the nodes. + + ///Sets the map that stores the distances of the nodes calculated by the + ///algorithm. + ///If you don't use this function before calling \ref run(Node) "run()" + ///or \ref init(), an instance will be allocated automatically. + ///The destructor deallocates this automatically allocated map, + ///of course. + ///\return (*this) + Dijkstra &distMap(DistMap &m) + { + if(local_dist) { + delete _dist; + local_dist=false; + } + _dist = &m; + return *this; + } + + ///Sets the heap and the cross reference used by algorithm. + + ///Sets the heap and the cross reference used by algorithm. + ///If you don't use this function before calling \ref run(Node) "run()" + ///or \ref init(), heap and cross reference instances will be + ///allocated automatically. + ///The destructor deallocates these automatically allocated objects, + ///of course. + ///\return (*this) + Dijkstra &heap(Heap& hp, HeapCrossRef &cr) + { + if(local_heap_cross_ref) { + delete _heap_cross_ref; + local_heap_cross_ref=false; + } + _heap_cross_ref = &cr; + if(local_heap) { + delete _heap; + local_heap=false; + } + _heap = &hp; + return *this; + } + + private: + + void finalizeNodeData(Node v,Value dst) + { + _processed->set(v,true); + _dist->set(v, dst); + } + + public: + + ///\name Execution Control + ///The simplest way to execute the %Dijkstra algorithm is to use + ///one of the member functions called \ref run(Node) "run()".\n + ///If you need better control on the execution, you have to call + ///\ref init() first, then you can add several source nodes with + ///\ref addSource(). Finally the actual path computation can be + ///performed with one of the \ref start() functions. + + ///@{ + + ///\brief Initializes the internal data structures. + /// + ///Initializes the internal data structures. + void init() + { + create_maps(); + _heap->clear(); + for ( NodeIt u(*G) ; u!=INVALID ; ++u ) { + _pred->set(u,INVALID); + _processed->set(u,false); + _heap_cross_ref->set(u,Heap::PRE_HEAP); + } + } + + ///Adds a new source node. + + ///Adds a new source node to the priority heap. + ///The optional second parameter is the initial distance of the node. + /// + ///The function checks if the node has already been added to the heap and + ///it is pushed to the heap only if either it was not in the heap + ///or the shortest path found till then is shorter than \c dst. + void addSource(Node s,Value dst=OperationTraits::zero()) + { + if(_heap->state(s) != Heap::IN_HEAP) { + _heap->push(s,dst); + } else if(OperationTraits::less((*_heap)[s], dst)) { + _heap->set(s,dst); + _pred->set(s,INVALID); + } + } + + ///Processes the next node in the priority heap + + ///Processes the next node in the priority heap. + /// + ///\return The processed node. + /// + ///\warning The priority heap must not be empty. + Node processNextNode() + { + Node v=_heap->top(); + Value oldvalue=_heap->prio(); + _heap->pop(); + finalizeNodeData(v,oldvalue); + + for(OutArcIt e(*G,v); e!=INVALID; ++e) { + Node w=G->target(e); + switch(_heap->state(w)) { + case Heap::PRE_HEAP: + _heap->push(w,OperationTraits::plus(oldvalue, (*_length)[e])); + _pred->set(w,e); + break; + case Heap::IN_HEAP: + { + Value newvalue = OperationTraits::plus(oldvalue, (*_length)[e]); + if ( OperationTraits::less(newvalue, (*_heap)[w]) ) { + _heap->decrease(w, newvalue); + _pred->set(w,e); + } + } + break; + case Heap::POST_HEAP: + break; + } + } + return v; + } + + ///The next node to be processed. + + ///Returns the next node to be processed or \c INVALID if the + ///priority heap is empty. + Node nextNode() const + { + return !_heap->empty()?_heap->top():INVALID; + } + + ///Returns \c false if there are nodes to be processed. + + ///Returns \c false if there are nodes to be processed + ///in the priority heap. + bool emptyQueue() const { return _heap->empty(); } + + ///Returns the number of the nodes to be processed. + + ///Returns the number of the nodes to be processed + ///in the priority heap. + int queueSize() const { return _heap->size(); } + + ///Executes the algorithm. + + ///Executes the algorithm. + /// + ///This method runs the %Dijkstra algorithm from the root node(s) + ///in order to compute the shortest path to each node. + /// + ///The algorithm computes + ///- the shortest path tree (forest), + ///- the distance of each node from the root(s). + /// + ///\pre init() must be called and at least one root node should be + ///added with addSource() before using this function. + /// + ///\note d.start() is just a shortcut of the following code. + ///\code + /// while ( !d.emptyQueue() ) { + /// d.processNextNode(); + /// } + ///\endcode + void start() + { + while ( !emptyQueue() ) processNextNode(); + } + + ///Executes the algorithm until the given target node is processed. + + ///Executes the algorithm until the given target node is processed. + /// + ///This method runs the %Dijkstra algorithm from the root node(s) + ///in order to compute the shortest path to \c t. + /// + ///The algorithm computes + ///- the shortest path to \c t, + ///- the distance of \c t from the root(s). + /// + ///\pre init() must be called and at least one root node should be + ///added with addSource() before using this function. + void start(Node t) + { + while ( !_heap->empty() && _heap->top()!=t ) processNextNode(); + if ( !_heap->empty() ) { + finalizeNodeData(_heap->top(),_heap->prio()); + _heap->pop(); + } + } + + ///Executes the algorithm until a condition is met. + + ///Executes the algorithm until a condition is met. + /// + ///This method runs the %Dijkstra algorithm from the root node(s) in + ///order to compute the shortest path to a node \c v with + /// nm[v] true, if such a node can be found. + /// + ///\param nm A \c bool (or convertible) node map. The algorithm + ///will stop when it reaches a node \c v with nm[v] true. + /// + ///\return The reached node \c v with nm[v] true or + ///\c INVALID if no such node was found. + /// + ///\pre init() must be called and at least one root node should be + ///added with addSource() before using this function. + template + Node start(const NodeBoolMap &nm) + { + while ( !_heap->empty() && !nm[_heap->top()] ) processNextNode(); + if ( _heap->empty() ) return INVALID; + finalizeNodeData(_heap->top(),_heap->prio()); + return _heap->top(); + } + + ///Runs the algorithm from the given source node. + + ///This method runs the %Dijkstra algorithm from node \c s + ///in order to compute the shortest path to each node. + /// + ///The algorithm computes + ///- the shortest path tree, + ///- the distance of each node from the root. + /// + ///\note d.run(s) is just a shortcut of the following code. + ///\code + /// d.init(); + /// d.addSource(s); + /// d.start(); + ///\endcode + void run(Node s) { + init(); + addSource(s); + start(); + } + + ///Finds the shortest path between \c s and \c t. + + ///This method runs the %Dijkstra algorithm from node \c s + ///in order to compute the shortest path to node \c t + ///(it stops searching when \c t is processed). + /// + ///\return \c true if \c t is reachable form \c s. + /// + ///\note Apart from the return value, d.run(s,t) is just a + ///shortcut of the following code. + ///\code + /// d.init(); + /// d.addSource(s); + /// d.start(t); + ///\endcode + bool run(Node s,Node t) { + init(); + addSource(s); + start(t); + return (*_heap_cross_ref)[t] == Heap::POST_HEAP; + } + + ///@} + + ///\name Query Functions + ///The results of the %Dijkstra algorithm can be obtained using these + ///functions.\n + ///Either \ref run(Node) "run()" or \ref init() should be called + ///before using them. + + ///@{ + + ///The shortest path to the given node. + + ///Returns the shortest path to the given node from the root(s). + /// + ///\warning \c t should be reached from the root(s). + /// + ///\pre Either \ref run(Node) "run()" or \ref init() + ///must be called before using this function. + Path path(Node t) const { return Path(*G, *_pred, t); } + + ///The distance of the given node from the root(s). + + ///Returns the distance of the given node from the root(s). + /// + ///\warning If node \c v is not reached from the root(s), then + ///the return value of this function is undefined. + /// + ///\pre Either \ref run(Node) "run()" or \ref init() + ///must be called before using this function. + Value dist(Node v) const { return (*_dist)[v]; } + + ///\brief Returns the 'previous arc' of the shortest path tree for + ///the given node. + /// + ///This function returns the 'previous arc' of the shortest path + ///tree for the node \c v, i.e. it returns the last arc of a + ///shortest path from a root to \c v. It is \c INVALID if \c v + ///is not reached from the root(s) or if \c v is a root. + /// + ///The shortest path tree used here is equal to the shortest path + ///tree used in \ref predNode() and \ref predMap(). + /// + ///\pre Either \ref run(Node) "run()" or \ref init() + ///must be called before using this function. + Arc predArc(Node v) const { return (*_pred)[v]; } + + ///\brief Returns the 'previous node' of the shortest path tree for + ///the given node. + /// + ///This function returns the 'previous node' of the shortest path + ///tree for the node \c v, i.e. it returns the last but one node + ///of a shortest path from a root to \c v. It is \c INVALID + ///if \c v is not reached from the root(s) or if \c v is a root. + /// + ///The shortest path tree used here is equal to the shortest path + ///tree used in \ref predArc() and \ref predMap(). + /// + ///\pre Either \ref run(Node) "run()" or \ref init() + ///must be called before using this function. + Node predNode(Node v) const { return (*_pred)[v]==INVALID ? INVALID: + G->source((*_pred)[v]); } + + ///\brief Returns a const reference to the node map that stores the + ///distances of the nodes. + /// + ///Returns a const reference to the node map that stores the distances + ///of the nodes calculated by the algorithm. + /// + ///\pre Either \ref run(Node) "run()" or \ref init() + ///must be called before using this function. + const DistMap &distMap() const { return *_dist;} + + ///\brief Returns a const reference to the node map that stores the + ///predecessor arcs. + /// + ///Returns a const reference to the node map that stores the predecessor + ///arcs, which form the shortest path tree (forest). + /// + ///\pre Either \ref run(Node) "run()" or \ref init() + ///must be called before using this function. + const PredMap &predMap() const { return *_pred;} + + ///Checks if the given node is reached from the root(s). + + ///Returns \c true if \c v is reached from the root(s). + /// + ///\pre Either \ref run(Node) "run()" or \ref init() + ///must be called before using this function. + bool reached(Node v) const { return (*_heap_cross_ref)[v] != + Heap::PRE_HEAP; } + + ///Checks if a node is processed. + + ///Returns \c true if \c v is processed, i.e. the shortest + ///path to \c v has already found. + /// + ///\pre Either \ref run(Node) "run()" or \ref init() + ///must be called before using this function. + bool processed(Node v) const { return (*_heap_cross_ref)[v] == + Heap::POST_HEAP; } + + ///The current distance of the given node from the root(s). + + ///Returns the current distance of the given node from the root(s). + ///It may be decreased in the following processes. + /// + ///\pre Either \ref run(Node) "run()" or \ref init() + ///must be called before using this function and + ///node \c v must be reached but not necessarily processed. + Value currentDist(Node v) const { + return processed(v) ? (*_dist)[v] : (*_heap)[v]; + } + + ///@} + }; + + + ///Default traits class of dijkstra() function. + + ///Default traits class of dijkstra() function. + ///\tparam GR The type of the digraph. + ///\tparam LEN The type of the length map. + template + struct DijkstraWizardDefaultTraits + { + ///The type of the digraph the algorithm runs on. + typedef GR Digraph; + ///The type of the map that stores the arc lengths. + + ///The type of the map that stores the arc lengths. + ///It must conform to the \ref concepts::ReadMap "ReadMap" concept. + typedef LEN LengthMap; + ///The type of the arc lengths. + typedef typename LEN::Value Value; + + /// Operation traits for Dijkstra algorithm. + + /// This class defines the operations that are used in the algorithm. + /// \see DijkstraDefaultOperationTraits + typedef DijkstraDefaultOperationTraits OperationTraits; + + /// The cross reference type used by the heap. + + /// The cross reference type used by the heap. + /// Usually it is \c Digraph::NodeMap. + typedef typename Digraph::template NodeMap HeapCrossRef; + ///Instantiates a \ref HeapCrossRef. + + ///This function instantiates a \ref HeapCrossRef. + /// \param g is the digraph, to which we would like to define the + /// HeapCrossRef. + static HeapCrossRef *createHeapCrossRef(const Digraph &g) + { + return new HeapCrossRef(g); + } + + ///The heap type used by the Dijkstra algorithm. + + ///The heap type used by the Dijkstra algorithm. + /// + ///\sa BinHeap + ///\sa Dijkstra + typedef BinHeap, + std::less > Heap; + + ///Instantiates a \ref Heap. + + ///This function instantiates a \ref Heap. + /// \param r is the HeapCrossRef which is used. + static Heap *createHeap(HeapCrossRef& r) + { + return new Heap(r); + } + + ///\brief The type of the map that stores the predecessor + ///arcs of the shortest paths. + /// + ///The type of the map that stores the predecessor + ///arcs of the shortest paths. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + typedef typename Digraph::template NodeMap PredMap; + ///Instantiates a PredMap. + + ///This function instantiates a PredMap. + ///\param g is the digraph, to which we would like to define the + ///PredMap. + static PredMap *createPredMap(const Digraph &g) + { + return new PredMap(g); + } + + ///The type of the map that indicates which nodes are processed. + + ///The type of the map that indicates which nodes are processed. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + ///By default, it is a NullMap. + typedef NullMap ProcessedMap; + ///Instantiates a ProcessedMap. + + ///This function instantiates a ProcessedMap. + ///\param g is the digraph, to which + ///we would like to define the ProcessedMap. +#ifdef DOXYGEN + static ProcessedMap *createProcessedMap(const Digraph &g) +#else + static ProcessedMap *createProcessedMap(const Digraph &) +#endif + { + return new ProcessedMap(); + } + + ///The type of the map that stores the distances of the nodes. + + ///The type of the map that stores the distances of the nodes. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + typedef typename Digraph::template NodeMap DistMap; + ///Instantiates a DistMap. + + ///This function instantiates a DistMap. + ///\param g is the digraph, to which we would like to define + ///the DistMap + static DistMap *createDistMap(const Digraph &g) + { + return new DistMap(g); + } + + ///The type of the shortest paths. + + ///The type of the shortest paths. + ///It must conform to the \ref concepts::Path "Path" concept. + typedef lemon::Path Path; + }; + + /// Default traits class used by DijkstraWizard + + /// Default traits class used by DijkstraWizard. + /// \tparam GR The type of the digraph. + /// \tparam LEN The type of the length map. + template + class DijkstraWizardBase : public DijkstraWizardDefaultTraits + { + typedef DijkstraWizardDefaultTraits Base; + protected: + //The type of the nodes in the digraph. + typedef typename Base::Digraph::Node Node; + + //Pointer to the digraph the algorithm runs on. + void *_g; + //Pointer to the length map. + void *_length; + //Pointer to the map of processed nodes. + void *_processed; + //Pointer to the map of predecessors arcs. + void *_pred; + //Pointer to the map of distances. + void *_dist; + //Pointer to the shortest path to the target node. + void *_path; + //Pointer to the distance of the target node. + void *_di; + + public: + /// Constructor. + + /// This constructor does not require parameters, therefore it initiates + /// all of the attributes to \c 0. + DijkstraWizardBase() : _g(0), _length(0), _processed(0), _pred(0), + _dist(0), _path(0), _di(0) {} + + /// Constructor. + + /// This constructor requires two parameters, + /// others are initiated to \c 0. + /// \param g The digraph the algorithm runs on. + /// \param l The length map. + DijkstraWizardBase(const GR &g,const LEN &l) : + _g(reinterpret_cast(const_cast(&g))), + _length(reinterpret_cast(const_cast(&l))), + _processed(0), _pred(0), _dist(0), _path(0), _di(0) {} + + }; + + /// Auxiliary class for the function-type interface of Dijkstra algorithm. + + /// This auxiliary class is created to implement the + /// \ref dijkstra() "function-type interface" of \ref Dijkstra algorithm. + /// It does not have own \ref run(Node) "run()" method, it uses the + /// functions and features of the plain \ref Dijkstra. + /// + /// This class should only be used through the \ref dijkstra() function, + /// which makes it easier to use the algorithm. + /// + /// \tparam TR The traits class that defines various types used by the + /// algorithm. + template + class DijkstraWizard : public TR + { + typedef TR Base; + + typedef typename TR::Digraph Digraph; + + typedef typename Digraph::Node Node; + typedef typename Digraph::NodeIt NodeIt; + typedef typename Digraph::Arc Arc; + typedef typename Digraph::OutArcIt OutArcIt; + + typedef typename TR::LengthMap LengthMap; + typedef typename LengthMap::Value Value; + typedef typename TR::PredMap PredMap; + typedef typename TR::DistMap DistMap; + typedef typename TR::ProcessedMap ProcessedMap; + typedef typename TR::Path Path; + typedef typename TR::Heap Heap; + + public: + + /// Constructor. + DijkstraWizard() : TR() {} + + /// Constructor that requires parameters. + + /// Constructor that requires parameters. + /// These parameters will be the default values for the traits class. + /// \param g The digraph the algorithm runs on. + /// \param l The length map. + DijkstraWizard(const Digraph &g, const LengthMap &l) : + TR(g,l) {} + + ///Copy constructor + DijkstraWizard(const TR &b) : TR(b) {} + + ~DijkstraWizard() {} + + ///Runs Dijkstra algorithm from the given source node. + + ///This method runs %Dijkstra algorithm from the given source node + ///in order to compute the shortest path to each node. + void run(Node s) + { + Dijkstra + dijk(*reinterpret_cast(Base::_g), + *reinterpret_cast(Base::_length)); + if (Base::_pred) + dijk.predMap(*reinterpret_cast(Base::_pred)); + if (Base::_dist) + dijk.distMap(*reinterpret_cast(Base::_dist)); + if (Base::_processed) + dijk.processedMap(*reinterpret_cast(Base::_processed)); + dijk.run(s); + } + + ///Finds the shortest path between \c s and \c t. + + ///This method runs the %Dijkstra algorithm from node \c s + ///in order to compute the shortest path to node \c t + ///(it stops searching when \c t is processed). + /// + ///\return \c true if \c t is reachable form \c s. + bool run(Node s, Node t) + { + Dijkstra + dijk(*reinterpret_cast(Base::_g), + *reinterpret_cast(Base::_length)); + if (Base::_pred) + dijk.predMap(*reinterpret_cast(Base::_pred)); + if (Base::_dist) + dijk.distMap(*reinterpret_cast(Base::_dist)); + if (Base::_processed) + dijk.processedMap(*reinterpret_cast(Base::_processed)); + dijk.run(s,t); + if (Base::_path) + *reinterpret_cast(Base::_path) = dijk.path(t); + if (Base::_di) + *reinterpret_cast(Base::_di) = dijk.dist(t); + return dijk.reached(t); + } + + template + struct SetPredMapBase : public Base { + typedef T PredMap; + static PredMap *createPredMap(const Digraph &) { return 0; }; + SetPredMapBase(const TR &b) : TR(b) {} + }; + + ///\brief \ref named-templ-param "Named parameter" for setting + ///the predecessor map. + /// + ///\ref named-templ-param "Named parameter" function for setting + ///the map that stores the predecessor arcs of the nodes. + template + DijkstraWizard > predMap(const T &t) + { + Base::_pred=reinterpret_cast(const_cast(&t)); + return DijkstraWizard >(*this); + } + + template + struct SetDistMapBase : public Base { + typedef T DistMap; + static DistMap *createDistMap(const Digraph &) { return 0; }; + SetDistMapBase(const TR &b) : TR(b) {} + }; + + ///\brief \ref named-templ-param "Named parameter" for setting + ///the distance map. + /// + ///\ref named-templ-param "Named parameter" function for setting + ///the map that stores the distances of the nodes calculated + ///by the algorithm. + template + DijkstraWizard > distMap(const T &t) + { + Base::_dist=reinterpret_cast(const_cast(&t)); + return DijkstraWizard >(*this); + } + + template + struct SetProcessedMapBase : public Base { + typedef T ProcessedMap; + static ProcessedMap *createProcessedMap(const Digraph &) { return 0; }; + SetProcessedMapBase(const TR &b) : TR(b) {} + }; + + ///\brief \ref named-func-param "Named parameter" for setting + ///the processed map. + /// + ///\ref named-templ-param "Named parameter" function for setting + ///the map that indicates which nodes are processed. + template + DijkstraWizard > processedMap(const T &t) + { + Base::_processed=reinterpret_cast(const_cast(&t)); + return DijkstraWizard >(*this); + } + + template + struct SetPathBase : public Base { + typedef T Path; + SetPathBase(const TR &b) : TR(b) {} + }; + + ///\brief \ref named-func-param "Named parameter" + ///for getting the shortest path to the target node. + /// + ///\ref named-func-param "Named parameter" + ///for getting the shortest path to the target node. + template + DijkstraWizard > path(const T &t) + { + Base::_path=reinterpret_cast(const_cast(&t)); + return DijkstraWizard >(*this); + } + + ///\brief \ref named-func-param "Named parameter" + ///for getting the distance of the target node. + /// + ///\ref named-func-param "Named parameter" + ///for getting the distance of the target node. + DijkstraWizard dist(const Value &d) + { + Base::_di=reinterpret_cast(const_cast(&d)); + return *this; + } + + }; + + ///Function-type interface for Dijkstra algorithm. + + /// \ingroup shortest_path + ///Function-type interface for Dijkstra algorithm. + /// + ///This function also has several \ref named-func-param "named parameters", + ///they are declared as the members of class \ref DijkstraWizard. + ///The following examples show how to use these parameters. + ///\code + /// // Compute shortest path from node s to each node + /// dijkstra(g,length).predMap(preds).distMap(dists).run(s); + /// + /// // Compute shortest path from s to t + /// bool reached = dijkstra(g,length).path(p).dist(d).run(s,t); + ///\endcode + ///\warning Don't forget to put the \ref DijkstraWizard::run(Node) "run()" + ///to the end of the parameter list. + ///\sa DijkstraWizard + ///\sa Dijkstra + template + DijkstraWizard > + dijkstra(const GR &digraph, const LEN &length) + { + return DijkstraWizard >(digraph,length); + } + +} //END OF NAMESPACE LEMON + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/dim2.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/dim2.h new file mode 100644 index 00000000000..0b14221060f --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/dim2.h @@ -0,0 +1,726 @@ +/* -*- 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_DIM2_H +#define LEMON_DIM2_H + +#include +#include + +///\ingroup geomdat +///\file +///\brief A simple two dimensional vector and a bounding box implementation + +namespace lemon { + + ///Tools for handling two dimensional coordinates + + ///This namespace is a storage of several + ///tools for handling two dimensional coordinates + namespace dim2 { + + /// \addtogroup geomdat + /// @{ + + /// Two dimensional vector (plain vector) + + /// A simple two dimensional vector (plain vector) implementation + /// with the usual vector operations. + template + class Point { + + public: + + typedef T Value; + + ///First coordinate + T x; + ///Second coordinate + T y; + + ///Default constructor + Point() {} + + ///Construct an instance from coordinates + Point(T a, T b) : x(a), y(b) { } + + ///Returns the dimension of the vector (i.e. returns 2). + + ///The dimension of the vector. + ///This function always returns 2. + int size() const { return 2; } + + ///Subscripting operator + + ///\c p[0] is \c p.x and \c p[1] is \c p.y + /// + T& operator[](int idx) { return idx == 0 ? x : y; } + + ///Const subscripting operator + + ///\c p[0] is \c p.x and \c p[1] is \c p.y + /// + const T& operator[](int idx) const { return idx == 0 ? x : y; } + + ///Conversion constructor + template Point(const Point &p) : x(p.x), y(p.y) {} + + ///Give back the square of the norm of the vector + T normSquare() const { + return x*x+y*y; + } + + ///Increment the left hand side by \c u + Point& operator +=(const Point& u) { + x += u.x; + y += u.y; + return *this; + } + + ///Decrement the left hand side by \c u + Point& operator -=(const Point& u) { + x -= u.x; + y -= u.y; + return *this; + } + + ///Multiply the left hand side with a scalar + Point& operator *=(const T &u) { + x *= u; + y *= u; + return *this; + } + + ///Divide the left hand side by a scalar + Point& operator /=(const T &u) { + x /= u; + y /= u; + return *this; + } + + ///Return the scalar product of two vectors + T operator *(const Point& u) const { + return x*u.x+y*u.y; + } + + ///Return the sum of two vectors + Point operator+(const Point &u) const { + Point b=*this; + return b+=u; + } + + ///Return the negative of the vector + Point operator-() const { + Point b=*this; + b.x=-b.x; b.y=-b.y; + return b; + } + + ///Return the difference of two vectors + Point operator-(const Point &u) const { + Point b=*this; + return b-=u; + } + + ///Return a vector multiplied by a scalar + Point operator*(const T &u) const { + Point b=*this; + return b*=u; + } + + ///Return a vector divided by a scalar + Point operator/(const T &u) const { + Point b=*this; + return b/=u; + } + + ///Test equality + bool operator==(const Point &u) const { + return (x==u.x) && (y==u.y); + } + + ///Test inequality + bool operator!=(Point u) const { + return (x!=u.x) || (y!=u.y); + } + + }; + + ///Return a Point + + ///Return a Point. + ///\relates Point + template + inline Point makePoint(const T& x, const T& y) { + return Point(x, y); + } + + ///Return a vector multiplied by a scalar + + ///Return a vector multiplied by a scalar. + ///\relates Point + template Point operator*(const T &u,const Point &x) { + return x*u; + } + + ///Read a plain vector from a stream + + ///Read a plain vector from a stream. + ///\relates Point + /// + template + inline std::istream& operator>>(std::istream &is, Point &z) { + char c; + if (is >> c) { + if (c != '(') is.putback(c); + } else { + is.clear(); + } + if (!(is >> z.x)) return is; + if (is >> c) { + if (c != ',') is.putback(c); + } else { + is.clear(); + } + if (!(is >> z.y)) return is; + if (is >> c) { + if (c != ')') is.putback(c); + } else { + is.clear(); + } + return is; + } + + ///Write a plain vector to a stream + + ///Write a plain vector to a stream. + ///\relates Point + /// + template + inline std::ostream& operator<<(std::ostream &os, const Point& z) + { + os << "(" << z.x << "," << z.y << ")"; + return os; + } + + ///Rotate by 90 degrees + + ///Returns the parameter rotated by 90 degrees in positive direction. + ///\relates Point + /// + template + inline Point rot90(const Point &z) + { + return Point(-z.y,z.x); + } + + ///Rotate by 180 degrees + + ///Returns the parameter rotated by 180 degrees. + ///\relates Point + /// + template + inline Point rot180(const Point &z) + { + return Point(-z.x,-z.y); + } + + ///Rotate by 270 degrees + + ///Returns the parameter rotated by 90 degrees in negative direction. + ///\relates Point + /// + template + inline Point rot270(const Point &z) + { + return Point(z.y,-z.x); + } + + + + /// Bounding box of plain vectors (points). + + /// A class to calculate or store the bounding box of plain vectors + /// (\ref Point "points"). + template + class Box { + Point _bottom_left, _top_right; + bool _empty; + public: + + ///Default constructor: creates an empty box + Box() { _empty = true; } + + ///Construct a box from one point + Box(Point a) { + _bottom_left = _top_right = a; + _empty = false; + } + + ///Construct a box from two points + + ///Construct a box from two points. + ///\param a The bottom left corner. + ///\param b The top right corner. + ///\warning The coordinates of the bottom left corner must be no more + ///than those of the top right one. + Box(Point a,Point b) + { + _bottom_left = a; + _top_right = b; + _empty = false; + } + + ///Construct a box from four numbers + + ///Construct a box from four numbers. + ///\param l The left side of the box. + ///\param b The bottom of the box. + ///\param r The right side of the box. + ///\param t The top of the box. + ///\warning The left side must be no more than the right side and + ///bottom must be no more than the top. + Box(T l,T b,T r,T t) + { + _bottom_left=Point(l,b); + _top_right=Point(r,t); + _empty = false; + } + + ///Return \c true if the box is empty. + + ///Return \c true if the box is empty (i.e. return \c false + ///if at least one point was added to the box or the coordinates of + ///the box were set). + /// + ///The coordinates of an empty box are not defined. + bool empty() const { + return _empty; + } + + ///Make the box empty + void clear() { + _empty = true; + } + + ///Give back the bottom left corner of the box + + ///Give back the bottom left corner of the box. + ///If the box is empty, then the return value is not defined. + Point bottomLeft() const { + return _bottom_left; + } + + ///Set the bottom left corner of the box + + ///Set the bottom left corner of the box. + ///\pre The box must not be empty. + void bottomLeft(Point p) { + _bottom_left = p; + } + + ///Give back the top right corner of the box + + ///Give back the top right corner of the box. + ///If the box is empty, then the return value is not defined. + Point topRight() const { + return _top_right; + } + + ///Set the top right corner of the box + + ///Set the top right corner of the box. + ///\pre The box must not be empty. + void topRight(Point p) { + _top_right = p; + } + + ///Give back the bottom right corner of the box + + ///Give back the bottom right corner of the box. + ///If the box is empty, then the return value is not defined. + Point bottomRight() const { + return Point(_top_right.x,_bottom_left.y); + } + + ///Set the bottom right corner of the box + + ///Set the bottom right corner of the box. + ///\pre The box must not be empty. + void bottomRight(Point p) { + _top_right.x = p.x; + _bottom_left.y = p.y; + } + + ///Give back the top left corner of the box + + ///Give back the top left corner of the box. + ///If the box is empty, then the return value is not defined. + Point topLeft() const { + return Point(_bottom_left.x,_top_right.y); + } + + ///Set the top left corner of the box + + ///Set the top left corner of the box. + ///\pre The box must not be empty. + void topLeft(Point p) { + _top_right.y = p.y; + _bottom_left.x = p.x; + } + + ///Give back the bottom of the box + + ///Give back the bottom of the box. + ///If the box is empty, then the return value is not defined. + T bottom() const { + return _bottom_left.y; + } + + ///Set the bottom of the box + + ///Set the bottom of the box. + ///\pre The box must not be empty. + void bottom(T t) { + _bottom_left.y = t; + } + + ///Give back the top of the box + + ///Give back the top of the box. + ///If the box is empty, then the return value is not defined. + T top() const { + return _top_right.y; + } + + ///Set the top of the box + + ///Set the top of the box. + ///\pre The box must not be empty. + void top(T t) { + _top_right.y = t; + } + + ///Give back the left side of the box + + ///Give back the left side of the box. + ///If the box is empty, then the return value is not defined. + T left() const { + return _bottom_left.x; + } + + ///Set the left side of the box + + ///Set the left side of the box. + ///\pre The box must not be empty. + void left(T t) { + _bottom_left.x = t; + } + + /// Give back the right side of the box + + /// Give back the right side of the box. + ///If the box is empty, then the return value is not defined. + T right() const { + return _top_right.x; + } + + ///Set the right side of the box + + ///Set the right side of the box. + ///\pre The box must not be empty. + void right(T t) { + _top_right.x = t; + } + + ///Give back the height of the box + + ///Give back the height of the box. + ///If the box is empty, then the return value is not defined. + T height() const { + return _top_right.y-_bottom_left.y; + } + + ///Give back the width of the box + + ///Give back the width of the box. + ///If the box is empty, then the return value is not defined. + T width() const { + return _top_right.x-_bottom_left.x; + } + + ///Checks whether a point is inside the box + bool inside(const Point& u) const { + if (_empty) + return false; + else { + return ( (u.x-_bottom_left.x)*(_top_right.x-u.x) >= 0 && + (u.y-_bottom_left.y)*(_top_right.y-u.y) >= 0 ); + } + } + + ///Increments the box with a point + + ///Increments the box with a point. + /// + Box& add(const Point& u){ + if (_empty) { + _bottom_left = _top_right = u; + _empty = false; + } + else { + if (_bottom_left.x > u.x) _bottom_left.x = u.x; + if (_bottom_left.y > u.y) _bottom_left.y = u.y; + if (_top_right.x < u.x) _top_right.x = u.x; + if (_top_right.y < u.y) _top_right.y = u.y; + } + return *this; + } + + ///Increments the box to contain another box + + ///Increments the box to contain another box. + /// + Box& add(const Box &u){ + if ( !u.empty() ){ + add(u._bottom_left); + add(u._top_right); + } + return *this; + } + + ///Intersection of two boxes + + ///Intersection of two boxes. + /// + Box operator&(const Box& u) const { + Box b; + if (_empty || u._empty) { + b._empty = true; + } else { + b._bottom_left.x = std::max(_bottom_left.x, u._bottom_left.x); + b._bottom_left.y = std::max(_bottom_left.y, u._bottom_left.y); + b._top_right.x = std::min(_top_right.x, u._top_right.x); + b._top_right.y = std::min(_top_right.y, u._top_right.y); + b._empty = b._bottom_left.x > b._top_right.x || + b._bottom_left.y > b._top_right.y; + } + return b; + } + + };//class Box + + + ///Read a box from a stream + + ///Read a box from a stream. + ///\relates Box + template + inline std::istream& operator>>(std::istream &is, Box& b) { + char c; + Point p; + if (is >> c) { + if (c != '(') is.putback(c); + } else { + is.clear(); + } + if (!(is >> p)) return is; + b.bottomLeft(p); + if (is >> c) { + if (c != ',') is.putback(c); + } else { + is.clear(); + } + if (!(is >> p)) return is; + b.topRight(p); + if (is >> c) { + if (c != ')') is.putback(c); + } else { + is.clear(); + } + return is; + } + + ///Write a box to a stream + + ///Write a box to a stream. + ///\relates Box + template + inline std::ostream& operator<<(std::ostream &os, const Box& b) + { + os << "(" << b.bottomLeft() << "," << b.topRight() << ")"; + return os; + } + + ///Map of x-coordinates of a Point-map + + ///Map of x-coordinates of a \ref Point "Point"-map. + /// + template + class XMap + { + M& _map; + public: + + typedef typename M::Value::Value Value; + typedef typename M::Key Key; + ///\e + XMap(M& map) : _map(map) {} + Value operator[](Key k) const {return _map[k].x;} + void set(Key k,Value v) {_map.set(k,typename M::Value(v,_map[k].y));} + }; + + ///Returns an XMap class + + ///This function just returns an XMap class. + ///\relates XMap + template + inline XMap xMap(M &m) + { + return XMap(m); + } + + template + inline XMap xMap(const M &m) + { + return XMap(m); + } + + ///Constant (read only) version of XMap + + ///Constant (read only) version of XMap. + /// + template + class ConstXMap + { + const M& _map; + public: + + typedef typename M::Value::Value Value; + typedef typename M::Key Key; + ///\e + ConstXMap(const M &map) : _map(map) {} + Value operator[](Key k) const {return _map[k].x;} + }; + + ///Returns a ConstXMap class + + ///This function just returns a ConstXMap class. + ///\relates ConstXMap + template + inline ConstXMap xMap(const M &m) + { + return ConstXMap(m); + } + + ///Map of y-coordinates of a Point-map + + ///Map of y-coordinates of a \ref Point "Point"-map. + /// + template + class YMap + { + M& _map; + public: + + typedef typename M::Value::Value Value; + typedef typename M::Key Key; + ///\e + YMap(M& map) : _map(map) {} + Value operator[](Key k) const {return _map[k].y;} + void set(Key k,Value v) {_map.set(k,typename M::Value(_map[k].x,v));} + }; + + ///Returns a YMap class + + ///This function just returns a YMap class. + ///\relates YMap + template + inline YMap yMap(M &m) + { + return YMap(m); + } + + template + inline YMap yMap(const M &m) + { + return YMap(m); + } + + ///Constant (read only) version of YMap + + ///Constant (read only) version of YMap. + /// + template + class ConstYMap + { + const M& _map; + public: + + typedef typename M::Value::Value Value; + typedef typename M::Key Key; + ///\e + ConstYMap(const M &map) : _map(map) {} + Value operator[](Key k) const {return _map[k].y;} + }; + + ///Returns a ConstYMap class + + ///This function just returns a ConstYMap class. + ///\relates ConstYMap + template + inline ConstYMap yMap(const M &m) + { + return ConstYMap(m); + } + + + ///\brief Map of the normSquare() of a Point-map + /// + ///Map of the \ref Point::normSquare() "normSquare()" + ///of a \ref Point "Point"-map. + template + class NormSquareMap + { + const M& _map; + public: + + typedef typename M::Value::Value Value; + typedef typename M::Key Key; + ///\e + NormSquareMap(const M &map) : _map(map) {} + Value operator[](Key k) const {return _map[k].normSquare();} + }; + + ///Returns a NormSquareMap class + + ///This function just returns a NormSquareMap class. + ///\relates NormSquareMap + template + inline NormSquareMap normSquareMap(const M &m) + { + return NormSquareMap(m); + } + + /// @} + + } //namespce dim2 + +} //namespace lemon + +#endif //LEMON_DIM2_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/dimacs.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/dimacs.h new file mode 100644 index 00000000000..616879ffa5e --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/dimacs.h @@ -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-2013 + * 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_DIMACS_H +#define LEMON_DIMACS_H + +#include +#include +#include +#include +#include +#include +/// \ingroup dimacs_group +/// \file +/// \brief DIMACS file format reader. + +namespace lemon { + + /// \addtogroup dimacs_group + /// @{ + + /// DIMACS file type descriptor. + struct DimacsDescriptor + { + ///\brief DIMACS file type enum + /// + ///DIMACS file type enum. + enum Type { + NONE, ///< Undefined type. + MIN, ///< DIMACS file type for minimum cost flow problems. + MAX, ///< DIMACS file type for maximum flow problems. + SP, ///< DIMACS file type for shostest path problems. + MAT ///< DIMACS file type for plain graphs and matching problems. + }; + ///The file type + Type type; + ///The number of nodes in the graph + int nodeNum; + ///The number of edges in the graph + int edgeNum; + int lineShift; + ///Constructor. It sets the type to \c NONE. + DimacsDescriptor() : type(NONE) {} + }; + + ///Discover the type of a DIMACS file + + ///This function starts seeking the beginning of the given file for the + ///problem type and size info. + ///The found data is returned in a special struct that can be evaluated + ///and passed to the appropriate reader function. + DimacsDescriptor dimacsType(std::istream& is) + { + DimacsDescriptor r; + std::string problem,str; + char c; + r.lineShift=0; + while (is >> c) + switch(c) + { + case 'p': + if(is >> problem >> r.nodeNum >> r.edgeNum) + { + getline(is, str); + r.lineShift++; + if(problem=="min") r.type=DimacsDescriptor::MIN; + else if(problem=="max") r.type=DimacsDescriptor::MAX; + else if(problem=="sp") r.type=DimacsDescriptor::SP; + else if(problem=="mat") r.type=DimacsDescriptor::MAT; + else throw FormatError("Unknown problem type"); + return r; + } + else + { + throw FormatError("Missing or wrong problem type declaration."); + } + break; + case 'c': + getline(is, str); + r.lineShift++; + break; + default: + throw FormatError("Unknown DIMACS declaration."); + } + throw FormatError("Missing problem type declaration."); + } + + + /// \brief DIMACS minimum cost flow reader function. + /// + /// This function reads a minimum cost flow instance from DIMACS format, + /// i.e. from a DIMACS file having a line starting with + /// \code + /// p min + /// \endcode + /// At the beginning, \c g is cleared by \c g.clear(). The supply + /// amount of the nodes are written to the \c supply node map + /// (they are signed values). The lower bounds, capacities and costs + /// of the arcs are written to the \c lower, \c capacity and \c cost + /// arc maps. + /// + /// If the capacity of an arc is less than the lower bound, it will + /// be set to "infinite" instead. The actual value of "infinite" is + /// contolled by the \c infty parameter. If it is 0 (the default value), + /// \c std::numeric_limits::infinity() will be used if available, + /// \c std::numeric_limits::max() otherwise. If \c infty is set to + /// a non-zero value, that value will be used as "infinite". + /// + /// If the file type was previously evaluated by dimacsType(), then + /// the descriptor struct should be given by the \c dest parameter. + template + void readDimacsMin(std::istream& is, + Digraph &g, + LowerMap& lower, + CapacityMap& capacity, + CostMap& cost, + SupplyMap& supply, + typename CapacityMap::Value infty = 0, + DimacsDescriptor desc=DimacsDescriptor()) + { + g.clear(); + std::vector nodes; + typename Digraph::Arc e; + std::string problem, str; + char c; + int i, j; + if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is); + if(desc.type!=DimacsDescriptor::MIN) + throw FormatError("Problem type mismatch"); + + nodes.resize(desc.nodeNum + 1); + for (int k = 1; k <= desc.nodeNum; ++k) { + nodes[k] = g.addNode(); + supply.set(nodes[k], 0); + } + + typename SupplyMap::Value sup; + typename CapacityMap::Value low; + typename CapacityMap::Value cap; + typename CostMap::Value co; + typedef typename CapacityMap::Value Capacity; + if(infty==0) + infty = std::numeric_limits::has_infinity ? + std::numeric_limits::infinity() : + std::numeric_limits::max(); + + while (is >> c) { + switch (c) { + case 'c': // comment line + getline(is, str); + break; + case 'n': // node definition line + is >> i >> sup; + getline(is, str); + supply.set(nodes[i], sup); + break; + case 'a': // arc definition line + is >> i >> j >> low >> cap >> co; + getline(is, str); + e = g.addArc(nodes[i], nodes[j]); + lower.set(e, low); + if (cap >= low) + capacity.set(e, cap); + else + capacity.set(e, infty); + cost.set(e, co); + break; + } + } + } + + template + void _readDimacs(std::istream& is, + Digraph &g, + CapacityMap& capacity, + typename Digraph::Node &s, + typename Digraph::Node &t, + typename CapacityMap::Value infty = 0, + DimacsDescriptor desc=DimacsDescriptor()) { + g.clear(); + s=t=INVALID; + std::vector nodes; + typename Digraph::Arc e; + char c, d; + int i, j; + typename CapacityMap::Value _cap; + std::string str; + nodes.resize(desc.nodeNum + 1); + for (int k = 1; k <= desc.nodeNum; ++k) { + nodes[k] = g.addNode(); + } + typedef typename CapacityMap::Value Capacity; + + if(infty==0) + infty = std::numeric_limits::has_infinity ? + std::numeric_limits::infinity() : + std::numeric_limits::max(); + + while (is >> c) { + switch (c) { + case 'c': // comment line + getline(is, str); + break; + case 'n': // node definition line + if (desc.type==DimacsDescriptor::SP) { // shortest path problem + is >> i; + getline(is, str); + s = nodes[i]; + } + if (desc.type==DimacsDescriptor::MAX) { // max flow problem + is >> i >> d; + getline(is, str); + if (d == 's') s = nodes[i]; + if (d == 't') t = nodes[i]; + } + break; + case 'a': // arc definition line + if (desc.type==DimacsDescriptor::SP) { + is >> i >> j >> _cap; + getline(is, str); + e = g.addArc(nodes[i], nodes[j]); + capacity.set(e, _cap); + } + else if (desc.type==DimacsDescriptor::MAX) { + is >> i >> j >> _cap; + getline(is, str); + e = g.addArc(nodes[i], nodes[j]); + if (_cap >= 0) + capacity.set(e, _cap); + else + capacity.set(e, infty); + } + else { + is >> i >> j; + getline(is, str); + g.addArc(nodes[i], nodes[j]); + } + break; + } + } + } + + /// \brief DIMACS maximum flow reader function. + /// + /// This function reads a maximum flow instance from DIMACS format, + /// i.e. from a DIMACS file having a line starting with + /// \code + /// p max + /// \endcode + /// At the beginning, \c g is cleared by \c g.clear(). The arc + /// capacities are written to the \c capacity arc map and \c s and + /// \c t are set to the source and the target nodes. + /// + /// If the capacity of an arc is negative, it will + /// be set to "infinite" instead. The actual value of "infinite" is + /// contolled by the \c infty parameter. If it is 0 (the default value), + /// \c std::numeric_limits::infinity() will be used if available, + /// \c std::numeric_limits::max() otherwise. If \c infty is set to + /// a non-zero value, that value will be used as "infinite". + /// + /// If the file type was previously evaluated by dimacsType(), then + /// the descriptor struct should be given by the \c dest parameter. + template + void readDimacsMax(std::istream& is, + Digraph &g, + CapacityMap& capacity, + typename Digraph::Node &s, + typename Digraph::Node &t, + typename CapacityMap::Value infty = 0, + DimacsDescriptor desc=DimacsDescriptor()) { + if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is); + if(desc.type!=DimacsDescriptor::MAX) + throw FormatError("Problem type mismatch"); + _readDimacs(is,g,capacity,s,t,infty,desc); + } + + /// \brief DIMACS shortest path reader function. + /// + /// This function reads a shortest path instance from DIMACS format, + /// i.e. from a DIMACS file having a line starting with + /// \code + /// p sp + /// \endcode + /// At the beginning, \c g is cleared by \c g.clear(). The arc + /// lengths are written to the \c length arc map and \c s is set to the + /// source node. + /// + /// If the file type was previously evaluated by dimacsType(), then + /// the descriptor struct should be given by the \c dest parameter. + template + void readDimacsSp(std::istream& is, + Digraph &g, + LengthMap& length, + typename Digraph::Node &s, + DimacsDescriptor desc=DimacsDescriptor()) { + typename Digraph::Node t; + if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is); + if(desc.type!=DimacsDescriptor::SP) + throw FormatError("Problem type mismatch"); + _readDimacs(is, g, length, s, t, 0, desc); + } + + /// \brief DIMACS capacitated digraph reader function. + /// + /// This function reads an arc capacitated digraph instance from + /// DIMACS 'max' or 'sp' format. + /// At the beginning, \c g is cleared by \c g.clear() + /// and the arc capacities/lengths are written to the \c capacity + /// arc map. + /// + /// In case of the 'max' format, if the capacity of an arc is negative, + /// it will + /// be set to "infinite" instead. The actual value of "infinite" is + /// contolled by the \c infty parameter. If it is 0 (the default value), + /// \c std::numeric_limits::infinity() will be used if available, + /// \c std::numeric_limits::max() otherwise. If \c infty is set to + /// a non-zero value, that value will be used as "infinite". + /// + /// If the file type was previously evaluated by dimacsType(), then + /// the descriptor struct should be given by the \c dest parameter. + template + void readDimacsCap(std::istream& is, + Digraph &g, + CapacityMap& capacity, + typename CapacityMap::Value infty = 0, + DimacsDescriptor desc=DimacsDescriptor()) { + typename Digraph::Node u,v; + if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is); + if(desc.type!=DimacsDescriptor::MAX || desc.type!=DimacsDescriptor::SP) + throw FormatError("Problem type mismatch"); + _readDimacs(is, g, capacity, u, v, infty, desc); + } + + template + typename enable_if,void>::type + _addArcEdge(Graph &g, typename Graph::Node s, typename Graph::Node t, + dummy<0> = 0) + { + g.addEdge(s,t); + } + template + typename disable_if,void>::type + _addArcEdge(Graph &g, typename Graph::Node s, typename Graph::Node t, + dummy<1> = 1) + { + g.addArc(s,t); + } + + /// \brief DIMACS plain (di)graph reader function. + /// + /// This function reads a plain (di)graph without any designated nodes + /// and maps (e.g. a matching instance) from DIMACS format, i.e. from + /// DIMACS files having a line starting with + /// \code + /// p mat + /// \endcode + /// At the beginning, \c g is cleared by \c g.clear(). + /// + /// If the file type was previously evaluated by dimacsType(), then + /// the descriptor struct should be given by the \c dest parameter. + template + void readDimacsMat(std::istream& is, Graph &g, + DimacsDescriptor desc=DimacsDescriptor()) + { + if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is); + if(desc.type!=DimacsDescriptor::MAT) + throw FormatError("Problem type mismatch"); + + g.clear(); + std::vector nodes; + char c; + int i, j; + std::string str; + nodes.resize(desc.nodeNum + 1); + for (int k = 1; k <= desc.nodeNum; ++k) { + nodes[k] = g.addNode(); + } + + while (is >> c) { + switch (c) { + case 'c': // comment line + getline(is, str); + break; + case 'n': // node definition line + break; + case 'a': // arc definition line + is >> i >> j; + getline(is, str); + _addArcEdge(g,nodes[i], nodes[j]); + break; + } + } + } + + /// DIMACS plain digraph writer function. + /// + /// This function writes a digraph without any designated nodes and + /// maps into DIMACS format, i.e. into DIMACS file having a line + /// starting with + /// \code + /// p mat + /// \endcode + /// If \c comment is not empty, then it will be printed in the first line + /// prefixed by 'c'. + template + void writeDimacsMat(std::ostream& os, const Digraph &g, + std::string comment="") { + typedef typename Digraph::NodeIt NodeIt; + typedef typename Digraph::ArcIt ArcIt; + + if(!comment.empty()) + os << "c " << comment << std::endl; + os << "p mat " << g.nodeNum() << " " << g.arcNum() << std::endl; + + typename Digraph::template NodeMap nodes(g); + int i = 1; + for(NodeIt v(g); v != INVALID; ++v) { + nodes.set(v, i); + ++i; + } + for(ArcIt e(g); e != INVALID; ++e) { + os << "a " << nodes[g.source(e)] << " " << nodes[g.target(e)] + << std::endl; + } + } + + /// @} + +} //namespace lemon + +#endif //LEMON_DIMACS_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/edge_set.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/edge_set.h new file mode 100644 index 00000000000..399b7a266f0 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/edge_set.h @@ -0,0 +1,1420 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_EDGE_SET_H +#define LEMON_EDGE_SET_H + +#include +#include + +/// \ingroup graphs +/// \file +/// \brief ArcSet and EdgeSet classes. +/// +/// Graphs which use another graph's node-set as own. +namespace lemon { + + template + class ListArcSetBase { + public: + + typedef typename GR::Node Node; + typedef typename GR::NodeIt NodeIt; + + protected: + + struct NodeT { + int first_out, first_in; + NodeT() : first_out(-1), first_in(-1) {} + }; + + typedef typename ItemSetTraits:: + template Map::Type NodesImplBase; + + NodesImplBase* _nodes; + + struct ArcT { + Node source, target; + int next_out, next_in; + int prev_out, prev_in; + ArcT() : prev_out(-1), prev_in(-1) {} + }; + + std::vector arcs; + + int first_arc; + int first_free_arc; + + const GR* _graph; + + void initalize(const GR& graph, NodesImplBase& nodes) { + _graph = &graph; + _nodes = &nodes; + } + + public: + + class Arc { + friend class ListArcSetBase; + protected: + Arc(int _id) : id(_id) {} + int id; + public: + Arc() {} + Arc(Invalid) : id(-1) {} + bool operator==(const Arc& arc) const { return id == arc.id; } + bool operator!=(const Arc& arc) const { return id != arc.id; } + bool operator<(const Arc& arc) const { return id < arc.id; } + }; + + ListArcSetBase() : first_arc(-1), first_free_arc(-1) {} + + Node addNode() { + LEMON_ASSERT(false, + "This graph structure does not support node insertion"); + return INVALID; // avoid warning + } + + Arc addArc(const Node& u, const Node& v) { + int n; + if (first_free_arc == -1) { + n = arcs.size(); + arcs.push_back(ArcT()); + } else { + n = first_free_arc; + first_free_arc = arcs[first_free_arc].next_in; + } + arcs[n].next_in = (*_nodes)[v].first_in; + if ((*_nodes)[v].first_in != -1) { + arcs[(*_nodes)[v].first_in].prev_in = n; + } + (*_nodes)[v].first_in = n; + arcs[n].next_out = (*_nodes)[u].first_out; + if ((*_nodes)[u].first_out != -1) { + arcs[(*_nodes)[u].first_out].prev_out = n; + } + (*_nodes)[u].first_out = n; + arcs[n].source = u; + arcs[n].target = v; + return Arc(n); + } + + void erase(const Arc& arc) { + int n = arc.id; + if (arcs[n].prev_in != -1) { + arcs[arcs[n].prev_in].next_in = arcs[n].next_in; + } else { + (*_nodes)[arcs[n].target].first_in = arcs[n].next_in; + } + if (arcs[n].next_in != -1) { + arcs[arcs[n].next_in].prev_in = arcs[n].prev_in; + } + + if (arcs[n].prev_out != -1) { + arcs[arcs[n].prev_out].next_out = arcs[n].next_out; + } else { + (*_nodes)[arcs[n].source].first_out = arcs[n].next_out; + } + if (arcs[n].next_out != -1) { + arcs[arcs[n].next_out].prev_out = arcs[n].prev_out; + } + + } + + void clear() { + Node node; + for (first(node); node != INVALID; next(node)) { + (*_nodes)[node].first_in = -1; + (*_nodes)[node].first_out = -1; + } + arcs.clear(); + first_arc = -1; + first_free_arc = -1; + } + + void first(Node& node) const { + _graph->first(node); + } + + void next(Node& node) const { + _graph->next(node); + } + + void first(Arc& arc) const { + Node node; + first(node); + while (node != INVALID && (*_nodes)[node].first_in == -1) { + next(node); + } + arc.id = (node == INVALID) ? -1 : (*_nodes)[node].first_in; + } + + void next(Arc& arc) const { + if (arcs[arc.id].next_in != -1) { + arc.id = arcs[arc.id].next_in; + } else { + Node node = arcs[arc.id].target; + next(node); + while (node != INVALID && (*_nodes)[node].first_in == -1) { + next(node); + } + arc.id = (node == INVALID) ? -1 : (*_nodes)[node].first_in; + } + } + + void firstOut(Arc& arc, const Node& node) const { + arc.id = (*_nodes)[node].first_out; + } + + void nextOut(Arc& arc) const { + arc.id = arcs[arc.id].next_out; + } + + void firstIn(Arc& arc, const Node& node) const { + arc.id = (*_nodes)[node].first_in; + } + + void nextIn(Arc& arc) const { + arc.id = arcs[arc.id].next_in; + } + + int id(const Node& node) const { return _graph->id(node); } + int id(const Arc& arc) const { return arc.id; } + + Node nodeFromId(int ix) const { return _graph->nodeFromId(ix); } + Arc arcFromId(int ix) const { return Arc(ix); } + + int maxNodeId() const { return _graph->maxNodeId(); }; + int maxArcId() const { return arcs.size() - 1; } + + Node source(const Arc& arc) const { return arcs[arc.id].source;} + Node target(const Arc& arc) const { return arcs[arc.id].target;} + + typedef typename ItemSetTraits::ItemNotifier NodeNotifier; + + NodeNotifier& notifier(Node) const { + return _graph->notifier(Node()); + } + + template + class NodeMap : public GR::template NodeMap { + typedef typename GR::template NodeMap Parent; + + public: + + explicit NodeMap(const ListArcSetBase& arcset) + : Parent(*arcset._graph) {} + + NodeMap(const ListArcSetBase& arcset, const V& value) + : Parent(*arcset._graph, value) {} + + NodeMap& operator=(const NodeMap& cmap) { + return operator=(cmap); + } + + template + NodeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + }; + + }; + + /// \ingroup graphs + /// + /// \brief Digraph using a node set of another digraph or graph and + /// an own arc set. + /// + /// This structure can be used to establish another directed graph + /// over a node set of an existing one. This class uses the same + /// Node type as the underlying graph, and each valid node of the + /// original graph is valid in this arc set, therefore the node + /// objects of the original graph can be used directly with this + /// class. The node handling functions (id handling, observing, and + /// iterators) works equivalently as in the original graph. + /// + /// This implementation is based on doubly-linked lists, from each + /// node the outgoing and the incoming arcs make up lists, therefore + /// one arc can be erased in constant time. It also makes possible, + /// that node can be removed from the underlying graph, in this case + /// all arcs incident to the given node is erased from the arc set. + /// + /// This class fully conforms to the \ref concepts::Digraph + /// "Digraph" concept. + /// It provides only linear time counting for nodes and arcs. + /// + /// \param GR The type of the graph which shares its node set with + /// this class. Its interface must conform to the + /// \ref concepts::Digraph "Digraph" or \ref concepts::Graph "Graph" + /// concept. + template + class ListArcSet : public ArcSetExtender > { + typedef ArcSetExtender > Parent; + + public: + + typedef typename Parent::Node Node; + typedef typename Parent::Arc Arc; + + typedef typename Parent::NodesImplBase NodesImplBase; + + void eraseNode(const Node& node) { + Arc arc; + Parent::firstOut(arc, node); + while (arc != INVALID ) { + erase(arc); + Parent::firstOut(arc, node); + } + + Parent::firstIn(arc, node); + while (arc != INVALID ) { + erase(arc); + Parent::firstIn(arc, node); + } + } + + void clearNodes() { + Parent::clear(); + } + + class NodesImpl : public NodesImplBase { + typedef NodesImplBase Parent; + + public: + NodesImpl(const GR& graph, ListArcSet& arcset) + : Parent(graph), _arcset(arcset) {} + + virtual ~NodesImpl() {} + + protected: + + virtual void erase(const Node& node) { + _arcset.eraseNode(node); + Parent::erase(node); + } + virtual void erase(const std::vector& nodes) { + for (int i = 0; i < int(nodes.size()); ++i) { + _arcset.eraseNode(nodes[i]); + } + Parent::erase(nodes); + } + virtual void clear() { + _arcset.clearNodes(); + Parent::clear(); + } + + private: + ListArcSet& _arcset; + }; + + NodesImpl _nodes; + + public: + + /// \brief Constructor of the ArcSet. + /// + /// Constructor of the ArcSet. + ListArcSet(const GR& graph) : _nodes(graph, *this) { + Parent::initalize(graph, _nodes); + } + + /// \brief Add a new arc to the digraph. + /// + /// Add a new arc to the digraph with source node \c s + /// and target node \c t. + /// \return The new arc. + Arc addArc(const Node& s, const Node& t) { + return Parent::addArc(s, t); + } + + /// \brief Erase an arc from the digraph. + /// + /// Erase an arc \c a from the digraph. + void erase(const Arc& a) { + return Parent::erase(a); + } + + }; + + template + class ListEdgeSetBase { + public: + + typedef typename GR::Node Node; + typedef typename GR::NodeIt NodeIt; + + protected: + + struct NodeT { + int first_out; + NodeT() : first_out(-1) {} + }; + + typedef typename ItemSetTraits:: + template Map::Type NodesImplBase; + + NodesImplBase* _nodes; + + struct ArcT { + Node target; + int prev_out, next_out; + ArcT() : prev_out(-1), next_out(-1) {} + }; + + std::vector arcs; + + int first_arc; + int first_free_arc; + + const GR* _graph; + + void initalize(const GR& graph, NodesImplBase& nodes) { + _graph = &graph; + _nodes = &nodes; + } + + public: + + class Edge { + friend class ListEdgeSetBase; + protected: + + int id; + explicit Edge(int _id) { id = _id;} + + public: + Edge() {} + Edge (Invalid) { id = -1; } + bool operator==(const Edge& arc) const {return id == arc.id;} + bool operator!=(const Edge& arc) const {return id != arc.id;} + bool operator<(const Edge& arc) const {return id < arc.id;} + }; + + class Arc { + friend class ListEdgeSetBase; + protected: + Arc(int _id) : id(_id) {} + int id; + public: + operator Edge() const { return edgeFromId(id / 2); } + + Arc() {} + Arc(Invalid) : id(-1) {} + bool operator==(const Arc& arc) const { return id == arc.id; } + bool operator!=(const Arc& arc) const { return id != arc.id; } + bool operator<(const Arc& arc) const { return id < arc.id; } + }; + + ListEdgeSetBase() : first_arc(-1), first_free_arc(-1) {} + + Node addNode() { + LEMON_ASSERT(false, + "This graph structure does not support node insertion"); + return INVALID; // avoid warning + } + + Edge addEdge(const Node& u, const Node& v) { + int n; + + if (first_free_arc == -1) { + n = arcs.size(); + arcs.push_back(ArcT()); + arcs.push_back(ArcT()); + } else { + n = first_free_arc; + first_free_arc = arcs[n].next_out; + } + + arcs[n].target = u; + arcs[n | 1].target = v; + + arcs[n].next_out = (*_nodes)[v].first_out; + if ((*_nodes)[v].first_out != -1) { + arcs[(*_nodes)[v].first_out].prev_out = n; + } + (*_nodes)[v].first_out = n; + arcs[n].prev_out = -1; + + if ((*_nodes)[u].first_out != -1) { + arcs[(*_nodes)[u].first_out].prev_out = (n | 1); + } + arcs[n | 1].next_out = (*_nodes)[u].first_out; + (*_nodes)[u].first_out = (n | 1); + arcs[n | 1].prev_out = -1; + + return Edge(n / 2); + } + + void erase(const Edge& arc) { + int n = arc.id * 2; + + if (arcs[n].next_out != -1) { + arcs[arcs[n].next_out].prev_out = arcs[n].prev_out; + } + + if (arcs[n].prev_out != -1) { + arcs[arcs[n].prev_out].next_out = arcs[n].next_out; + } else { + (*_nodes)[arcs[n | 1].target].first_out = arcs[n].next_out; + } + + if (arcs[n | 1].next_out != -1) { + arcs[arcs[n | 1].next_out].prev_out = arcs[n | 1].prev_out; + } + + if (arcs[n | 1].prev_out != -1) { + arcs[arcs[n | 1].prev_out].next_out = arcs[n | 1].next_out; + } else { + (*_nodes)[arcs[n].target].first_out = arcs[n | 1].next_out; + } + + arcs[n].next_out = first_free_arc; + first_free_arc = n; + + } + + void clear() { + Node node; + for (first(node); node != INVALID; next(node)) { + (*_nodes)[node].first_out = -1; + } + arcs.clear(); + first_arc = -1; + first_free_arc = -1; + } + + void first(Node& node) const { + _graph->first(node); + } + + void next(Node& node) const { + _graph->next(node); + } + + void first(Arc& arc) const { + Node node; + first(node); + while (node != INVALID && (*_nodes)[node].first_out == -1) { + next(node); + } + arc.id = (node == INVALID) ? -1 : (*_nodes)[node].first_out; + } + + void next(Arc& arc) const { + if (arcs[arc.id].next_out != -1) { + arc.id = arcs[arc.id].next_out; + } else { + Node node = arcs[arc.id ^ 1].target; + next(node); + while(node != INVALID && (*_nodes)[node].first_out == -1) { + next(node); + } + arc.id = (node == INVALID) ? -1 : (*_nodes)[node].first_out; + } + } + + void first(Edge& edge) const { + Node node; + first(node); + while (node != INVALID) { + edge.id = (*_nodes)[node].first_out; + while ((edge.id & 1) != 1) { + edge.id = arcs[edge.id].next_out; + } + if (edge.id != -1) { + edge.id /= 2; + return; + } + next(node); + } + edge.id = -1; + } + + void next(Edge& edge) const { + Node node = arcs[edge.id * 2].target; + edge.id = arcs[(edge.id * 2) | 1].next_out; + while ((edge.id & 1) != 1) { + edge.id = arcs[edge.id].next_out; + } + if (edge.id != -1) { + edge.id /= 2; + return; + } + next(node); + while (node != INVALID) { + edge.id = (*_nodes)[node].first_out; + while ((edge.id & 1) != 1) { + edge.id = arcs[edge.id].next_out; + } + if (edge.id != -1) { + edge.id /= 2; + return; + } + next(node); + } + edge.id = -1; + } + + void firstOut(Arc& arc, const Node& node) const { + arc.id = (*_nodes)[node].first_out; + } + + void nextOut(Arc& arc) const { + arc.id = arcs[arc.id].next_out; + } + + void firstIn(Arc& arc, const Node& node) const { + arc.id = (((*_nodes)[node].first_out) ^ 1); + if (arc.id == -2) arc.id = -1; + } + + void nextIn(Arc& arc) const { + arc.id = ((arcs[arc.id ^ 1].next_out) ^ 1); + if (arc.id == -2) arc.id = -1; + } + + void firstInc(Edge &arc, bool& dir, const Node& node) const { + int de = (*_nodes)[node].first_out; + if (de != -1 ) { + arc.id = de / 2; + dir = ((de & 1) == 1); + } else { + arc.id = -1; + dir = true; + } + } + void nextInc(Edge &arc, bool& dir) const { + int de = (arcs[(arc.id * 2) | (dir ? 1 : 0)].next_out); + if (de != -1 ) { + arc.id = de / 2; + dir = ((de & 1) == 1); + } else { + arc.id = -1; + dir = true; + } + } + + static bool direction(Arc arc) { + return (arc.id & 1) == 1; + } + + static Arc direct(Edge edge, bool dir) { + return Arc(edge.id * 2 + (dir ? 1 : 0)); + } + + int id(const Node& node) const { return _graph->id(node); } + static int id(Arc e) { return e.id; } + static int id(Edge e) { return e.id; } + + Node nodeFromId(int id) const { return _graph->nodeFromId(id); } + static Arc arcFromId(int id) { return Arc(id);} + static Edge edgeFromId(int id) { return Edge(id);} + + int maxNodeId() const { return _graph->maxNodeId(); }; + int maxEdgeId() const { return arcs.size() / 2 - 1; } + int maxArcId() const { return arcs.size()-1; } + + Node source(Arc e) const { return arcs[e.id ^ 1].target; } + Node target(Arc e) const { return arcs[e.id].target; } + + Node u(Edge e) const { return arcs[2 * e.id].target; } + Node v(Edge e) const { return arcs[2 * e.id + 1].target; } + + typedef typename ItemSetTraits::ItemNotifier NodeNotifier; + + NodeNotifier& notifier(Node) const { + return _graph->notifier(Node()); + } + + template + class NodeMap : public GR::template NodeMap { + typedef typename GR::template NodeMap Parent; + + public: + + explicit NodeMap(const ListEdgeSetBase& arcset) + : Parent(*arcset._graph) {} + + NodeMap(const ListEdgeSetBase& arcset, const V& value) + : Parent(*arcset._graph, value) {} + + NodeMap& operator=(const NodeMap& cmap) { + return operator=(cmap); + } + + template + NodeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + }; + + }; + + /// \ingroup graphs + /// + /// \brief Graph using a node set of another digraph or graph and an + /// own edge set. + /// + /// This structure can be used to establish another graph over a + /// node set of an existing one. This class uses the same Node type + /// as the underlying graph, and each valid node of the original + /// graph is valid in this arc set, therefore the node objects of + /// the original graph can be used directly with this class. The + /// node handling functions (id handling, observing, and iterators) + /// works equivalently as in the original graph. + /// + /// This implementation is based on doubly-linked lists, from each + /// node the incident edges make up lists, therefore one edge can be + /// erased in constant time. It also makes possible, that node can + /// be removed from the underlying graph, in this case all edges + /// incident to the given node is erased from the arc set. + /// + /// This class fully conforms to the \ref concepts::Graph "Graph" + /// concept. + /// It provides only linear time counting for nodes, edges and arcs. + /// + /// \param GR The type of the graph which shares its node set + /// with this class. Its interface must conform to the + /// \ref concepts::Digraph "Digraph" or \ref concepts::Graph "Graph" + /// concept. + template + class ListEdgeSet : public EdgeSetExtender > { + typedef EdgeSetExtender > Parent; + + public: + + typedef typename Parent::Node Node; + typedef typename Parent::Arc Arc; + typedef typename Parent::Edge Edge; + + typedef typename Parent::NodesImplBase NodesImplBase; + + void eraseNode(const Node& node) { + Arc arc; + Parent::firstOut(arc, node); + while (arc != INVALID ) { + erase(arc); + Parent::firstOut(arc, node); + } + + } + + void clearNodes() { + Parent::clear(); + } + + class NodesImpl : public NodesImplBase { + typedef NodesImplBase Parent; + + public: + NodesImpl(const GR& graph, ListEdgeSet& arcset) + : Parent(graph), _arcset(arcset) {} + + virtual ~NodesImpl() {} + + protected: + + virtual void erase(const Node& node) { + _arcset.eraseNode(node); + Parent::erase(node); + } + virtual void erase(const std::vector& nodes) { + for (int i = 0; i < int(nodes.size()); ++i) { + _arcset.eraseNode(nodes[i]); + } + Parent::erase(nodes); + } + virtual void clear() { + _arcset.clearNodes(); + Parent::clear(); + } + + private: + ListEdgeSet& _arcset; + }; + + NodesImpl _nodes; + + public: + + /// \brief Constructor of the EdgeSet. + /// + /// Constructor of the EdgeSet. + ListEdgeSet(const GR& graph) : _nodes(graph, *this) { + Parent::initalize(graph, _nodes); + } + + /// \brief Add a new edge to the graph. + /// + /// Add a new edge to the graph with node \c u + /// and node \c v endpoints. + /// \return The new edge. + Edge addEdge(const Node& u, const Node& v) { + return Parent::addEdge(u, v); + } + + /// \brief Erase an edge from the graph. + /// + /// Erase the edge \c e from the graph. + void erase(const Edge& e) { + return Parent::erase(e); + } + + }; + + template + class SmartArcSetBase { + public: + + typedef typename GR::Node Node; + typedef typename GR::NodeIt NodeIt; + + protected: + + struct NodeT { + int first_out, first_in; + NodeT() : first_out(-1), first_in(-1) {} + }; + + typedef typename ItemSetTraits:: + template Map::Type NodesImplBase; + + NodesImplBase* _nodes; + + struct ArcT { + Node source, target; + int next_out, next_in; + ArcT() {} + }; + + std::vector arcs; + + const GR* _graph; + + void initalize(const GR& graph, NodesImplBase& nodes) { + _graph = &graph; + _nodes = &nodes; + } + + public: + + class Arc { + friend class SmartArcSetBase; + protected: + Arc(int _id) : id(_id) {} + int id; + public: + Arc() {} + Arc(Invalid) : id(-1) {} + bool operator==(const Arc& arc) const { return id == arc.id; } + bool operator!=(const Arc& arc) const { return id != arc.id; } + bool operator<(const Arc& arc) const { return id < arc.id; } + }; + + SmartArcSetBase() {} + + Node addNode() { + LEMON_ASSERT(false, + "This graph structure does not support node insertion"); + return INVALID; // avoid warning + } + + Arc addArc(const Node& u, const Node& v) { + int n = arcs.size(); + arcs.push_back(ArcT()); + arcs[n].next_in = (*_nodes)[v].first_in; + (*_nodes)[v].first_in = n; + arcs[n].next_out = (*_nodes)[u].first_out; + (*_nodes)[u].first_out = n; + arcs[n].source = u; + arcs[n].target = v; + return Arc(n); + } + + void clear() { + Node node; + for (first(node); node != INVALID; next(node)) { + (*_nodes)[node].first_in = -1; + (*_nodes)[node].first_out = -1; + } + arcs.clear(); + } + + void first(Node& node) const { + _graph->first(node); + } + + void next(Node& node) const { + _graph->next(node); + } + + void first(Arc& arc) const { + arc.id = arcs.size() - 1; + } + + static void next(Arc& arc) { + --arc.id; + } + + void firstOut(Arc& arc, const Node& node) const { + arc.id = (*_nodes)[node].first_out; + } + + void nextOut(Arc& arc) const { + arc.id = arcs[arc.id].next_out; + } + + void firstIn(Arc& arc, const Node& node) const { + arc.id = (*_nodes)[node].first_in; + } + + void nextIn(Arc& arc) const { + arc.id = arcs[arc.id].next_in; + } + + int id(const Node& node) const { return _graph->id(node); } + int id(const Arc& arc) const { return arc.id; } + + Node nodeFromId(int ix) const { return _graph->nodeFromId(ix); } + Arc arcFromId(int ix) const { return Arc(ix); } + + int maxNodeId() const { return _graph->maxNodeId(); }; + int maxArcId() const { return arcs.size() - 1; } + + Node source(const Arc& arc) const { return arcs[arc.id].source;} + Node target(const Arc& arc) const { return arcs[arc.id].target;} + + typedef typename ItemSetTraits::ItemNotifier NodeNotifier; + + NodeNotifier& notifier(Node) const { + return _graph->notifier(Node()); + } + + template + class NodeMap : public GR::template NodeMap { + typedef typename GR::template NodeMap Parent; + + public: + + explicit NodeMap(const SmartArcSetBase& arcset) + : Parent(*arcset._graph) { } + + NodeMap(const SmartArcSetBase& arcset, const V& value) + : Parent(*arcset._graph, value) { } + + NodeMap& operator=(const NodeMap& cmap) { + return operator=(cmap); + } + + template + NodeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + }; + + }; + + + /// \ingroup graphs + /// + /// \brief Digraph using a node set of another digraph or graph and + /// an own arc set. + /// + /// This structure can be used to establish another directed graph + /// over a node set of an existing one. This class uses the same + /// Node type as the underlying graph, and each valid node of the + /// original graph is valid in this arc set, therefore the node + /// objects of the original graph can be used directly with this + /// class. The node handling functions (id handling, observing, and + /// iterators) works equivalently as in the original graph. + /// + /// \param GR The type of the graph which shares its node set with + /// this class. Its interface must conform to the + /// \ref concepts::Digraph "Digraph" or \ref concepts::Graph "Graph" + /// concept. + /// + /// This implementation is slightly faster than the \c ListArcSet, + /// because it uses continuous storage for arcs and it uses just + /// single-linked lists for enumerate outgoing and incoming + /// arcs. Therefore the arcs cannot be erased from the arc sets. + /// + /// This class fully conforms to the \ref concepts::Digraph "Digraph" + /// concept. + /// It provides only linear time counting for nodes and arcs. + /// + /// \warning If a node is erased from the underlying graph and this + /// node is the source or target of one arc in the arc set, then + /// the arc set is invalidated, and it cannot be used anymore. The + /// validity can be checked with the \c valid() member function. + template + class SmartArcSet : public ArcSetExtender > { + typedef ArcSetExtender > Parent; + + public: + + typedef typename Parent::Node Node; + typedef typename Parent::Arc Arc; + + protected: + + typedef typename Parent::NodesImplBase NodesImplBase; + + void eraseNode(const Node& node) { + if (typename Parent::InArcIt(*this, node) == INVALID && + typename Parent::OutArcIt(*this, node) == INVALID) { + return; + } + throw typename NodesImplBase::Notifier::ImmediateDetach(); + } + + void clearNodes() { + Parent::clear(); + } + + class NodesImpl : public NodesImplBase { + typedef NodesImplBase Parent; + + public: + NodesImpl(const GR& graph, SmartArcSet& arcset) + : Parent(graph), _arcset(arcset) {} + + virtual ~NodesImpl() {} + + bool attached() const { + return Parent::attached(); + } + + protected: + + virtual void erase(const Node& node) { + try { + _arcset.eraseNode(node); + Parent::erase(node); + } catch (const typename NodesImplBase::Notifier::ImmediateDetach&) { + Parent::clear(); + throw; + } + } + virtual void erase(const std::vector& nodes) { + try { + for (int i = 0; i < int(nodes.size()); ++i) { + _arcset.eraseNode(nodes[i]); + } + Parent::erase(nodes); + } catch (const typename NodesImplBase::Notifier::ImmediateDetach&) { + Parent::clear(); + throw; + } + } + virtual void clear() { + _arcset.clearNodes(); + Parent::clear(); + } + + private: + SmartArcSet& _arcset; + }; + + NodesImpl _nodes; + + public: + + /// \brief Constructor of the ArcSet. + /// + /// Constructor of the ArcSet. + SmartArcSet(const GR& graph) : _nodes(graph, *this) { + Parent::initalize(graph, _nodes); + } + + /// \brief Add a new arc to the digraph. + /// + /// Add a new arc to the digraph with source node \c s + /// and target node \c t. + /// \return The new arc. + Arc addArc(const Node& s, const Node& t) { + return Parent::addArc(s, t); + } + + /// \brief Validity check + /// + /// This functions gives back false if the ArcSet is + /// invalidated. It occurs when a node in the underlying graph is + /// erased and it is not isolated in the ArcSet. + bool valid() const { + return _nodes.attached(); + } + + }; + + + template + class SmartEdgeSetBase { + public: + + typedef typename GR::Node Node; + typedef typename GR::NodeIt NodeIt; + + protected: + + struct NodeT { + int first_out; + NodeT() : first_out(-1) {} + }; + + typedef typename ItemSetTraits:: + template Map::Type NodesImplBase; + + NodesImplBase* _nodes; + + struct ArcT { + Node target; + int next_out; + ArcT() {} + }; + + std::vector arcs; + + const GR* _graph; + + void initalize(const GR& graph, NodesImplBase& nodes) { + _graph = &graph; + _nodes = &nodes; + } + + public: + + class Edge { + friend class SmartEdgeSetBase; + protected: + + int id; + explicit Edge(int _id) { id = _id;} + + public: + Edge() {} + Edge (Invalid) { id = -1; } + bool operator==(const Edge& arc) const {return id == arc.id;} + bool operator!=(const Edge& arc) const {return id != arc.id;} + bool operator<(const Edge& arc) const {return id < arc.id;} + }; + + class Arc { + friend class SmartEdgeSetBase; + protected: + Arc(int _id) : id(_id) {} + int id; + public: + operator Edge() const { return edgeFromId(id / 2); } + + Arc() {} + Arc(Invalid) : id(-1) {} + bool operator==(const Arc& arc) const { return id == arc.id; } + bool operator!=(const Arc& arc) const { return id != arc.id; } + bool operator<(const Arc& arc) const { return id < arc.id; } + }; + + SmartEdgeSetBase() {} + + Node addNode() { + LEMON_ASSERT(false, + "This graph structure does not support node insertion"); + return INVALID; // avoid warning + } + + Edge addEdge(const Node& u, const Node& v) { + int n = arcs.size(); + arcs.push_back(ArcT()); + arcs.push_back(ArcT()); + + arcs[n].target = u; + arcs[n | 1].target = v; + + arcs[n].next_out = (*_nodes)[v].first_out; + (*_nodes)[v].first_out = n; + + arcs[n | 1].next_out = (*_nodes)[u].first_out; + (*_nodes)[u].first_out = (n | 1); + + return Edge(n / 2); + } + + void clear() { + Node node; + for (first(node); node != INVALID; next(node)) { + (*_nodes)[node].first_out = -1; + } + arcs.clear(); + } + + void first(Node& node) const { + _graph->first(node); + } + + void next(Node& node) const { + _graph->next(node); + } + + void first(Arc& arc) const { + arc.id = arcs.size() - 1; + } + + static void next(Arc& arc) { + --arc.id; + } + + void first(Edge& arc) const { + arc.id = arcs.size() / 2 - 1; + } + + static void next(Edge& arc) { + --arc.id; + } + + void firstOut(Arc& arc, const Node& node) const { + arc.id = (*_nodes)[node].first_out; + } + + void nextOut(Arc& arc) const { + arc.id = arcs[arc.id].next_out; + } + + void firstIn(Arc& arc, const Node& node) const { + arc.id = (((*_nodes)[node].first_out) ^ 1); + if (arc.id == -2) arc.id = -1; + } + + void nextIn(Arc& arc) const { + arc.id = ((arcs[arc.id ^ 1].next_out) ^ 1); + if (arc.id == -2) arc.id = -1; + } + + void firstInc(Edge &arc, bool& dir, const Node& node) const { + int de = (*_nodes)[node].first_out; + if (de != -1 ) { + arc.id = de / 2; + dir = ((de & 1) == 1); + } else { + arc.id = -1; + dir = true; + } + } + void nextInc(Edge &arc, bool& dir) const { + int de = (arcs[(arc.id * 2) | (dir ? 1 : 0)].next_out); + if (de != -1 ) { + arc.id = de / 2; + dir = ((de & 1) == 1); + } else { + arc.id = -1; + dir = true; + } + } + + static bool direction(Arc arc) { + return (arc.id & 1) == 1; + } + + static Arc direct(Edge edge, bool dir) { + return Arc(edge.id * 2 + (dir ? 1 : 0)); + } + + int id(Node node) const { return _graph->id(node); } + static int id(Arc arc) { return arc.id; } + static int id(Edge arc) { return arc.id; } + + Node nodeFromId(int id) const { return _graph->nodeFromId(id); } + static Arc arcFromId(int id) { return Arc(id); } + static Edge edgeFromId(int id) { return Edge(id);} + + int maxNodeId() const { return _graph->maxNodeId(); }; + int maxArcId() const { return arcs.size() - 1; } + int maxEdgeId() const { return arcs.size() / 2 - 1; } + + Node source(Arc e) const { return arcs[e.id ^ 1].target; } + Node target(Arc e) const { return arcs[e.id].target; } + + Node u(Edge e) const { return arcs[2 * e.id].target; } + Node v(Edge e) const { return arcs[2 * e.id + 1].target; } + + typedef typename ItemSetTraits::ItemNotifier NodeNotifier; + + NodeNotifier& notifier(Node) const { + return _graph->notifier(Node()); + } + + template + class NodeMap : public GR::template NodeMap { + typedef typename GR::template NodeMap Parent; + + public: + + explicit NodeMap(const SmartEdgeSetBase& arcset) + : Parent(*arcset._graph) { } + + NodeMap(const SmartEdgeSetBase& arcset, const V& value) + : Parent(*arcset._graph, value) { } + + NodeMap& operator=(const NodeMap& cmap) { + return operator=(cmap); + } + + template + NodeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + }; + + }; + + /// \ingroup graphs + /// + /// \brief Graph using a node set of another digraph or graph and an + /// own edge set. + /// + /// This structure can be used to establish another graph over a + /// node set of an existing one. This class uses the same Node type + /// as the underlying graph, and each valid node of the original + /// graph is valid in this arc set, therefore the node objects of + /// the original graph can be used directly with this class. The + /// node handling functions (id handling, observing, and iterators) + /// works equivalently as in the original graph. + /// + /// \param GR The type of the graph which shares its node set + /// with this class. Its interface must conform to the + /// \ref concepts::Digraph "Digraph" or \ref concepts::Graph "Graph" + /// concept. + /// + /// This implementation is slightly faster than the \c ListEdgeSet, + /// because it uses continuous storage for edges and it uses just + /// single-linked lists for enumerate incident edges. Therefore the + /// edges cannot be erased from the edge sets. + /// + /// This class fully conforms to the \ref concepts::Graph "Graph" + /// concept. + /// It provides only linear time counting for nodes, edges and arcs. + /// + /// \warning If a node is erased from the underlying graph and this + /// node is incident to one edge in the edge set, then the edge set + /// is invalidated, and it cannot be used anymore. The validity can + /// be checked with the \c valid() member function. + template + class SmartEdgeSet : public EdgeSetExtender > { + typedef EdgeSetExtender > Parent; + + public: + + typedef typename Parent::Node Node; + typedef typename Parent::Arc Arc; + typedef typename Parent::Edge Edge; + + protected: + + typedef typename Parent::NodesImplBase NodesImplBase; + + void eraseNode(const Node& node) { + if (typename Parent::IncEdgeIt(*this, node) == INVALID) { + return; + } + throw typename NodesImplBase::Notifier::ImmediateDetach(); + } + + void clearNodes() { + Parent::clear(); + } + + class NodesImpl : public NodesImplBase { + typedef NodesImplBase Parent; + + public: + NodesImpl(const GR& graph, SmartEdgeSet& arcset) + : Parent(graph), _arcset(arcset) {} + + virtual ~NodesImpl() {} + + bool attached() const { + return Parent::attached(); + } + + protected: + + virtual void erase(const Node& node) { + try { + _arcset.eraseNode(node); + Parent::erase(node); + } catch (const typename NodesImplBase::Notifier::ImmediateDetach&) { + Parent::clear(); + throw; + } + } + virtual void erase(const std::vector& nodes) { + try { + for (int i = 0; i < int(nodes.size()); ++i) { + _arcset.eraseNode(nodes[i]); + } + Parent::erase(nodes); + } catch (const typename NodesImplBase::Notifier::ImmediateDetach&) { + Parent::clear(); + throw; + } + } + virtual void clear() { + _arcset.clearNodes(); + Parent::clear(); + } + + private: + SmartEdgeSet& _arcset; + }; + + NodesImpl _nodes; + + public: + + /// \brief Constructor of the EdgeSet. + /// + /// Constructor of the EdgeSet. + SmartEdgeSet(const GR& graph) : _nodes(graph, *this) { + Parent::initalize(graph, _nodes); + } + + /// \brief Add a new edge to the graph. + /// + /// Add a new edge to the graph with node \c u + /// and node \c v endpoints. + /// \return The new edge. + Edge addEdge(const Node& u, const Node& v) { + return Parent::addEdge(u, v); + } + + /// \brief Validity check + /// + /// This functions gives back false if the EdgeSet is + /// invalidated. It occurs when a node in the underlying graph is + /// erased and it is not isolated in the EdgeSet. + bool valid() const { + return _nodes.attached(); + } + + }; + +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/edmonds_karp.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/edmonds_karp.h new file mode 100644 index 00000000000..92af3cba313 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/edmonds_karp.h @@ -0,0 +1,556 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_EDMONDS_KARP_H +#define LEMON_EDMONDS_KARP_H + +/// \file +/// \ingroup max_flow +/// \brief Implementation of the Edmonds-Karp algorithm. + +#include +#include + +namespace lemon { + + /// \brief Default traits class of EdmondsKarp class. + /// + /// Default traits class of EdmondsKarp class. + /// \param GR Digraph type. + /// \param CAP Type of capacity map. + template + struct EdmondsKarpDefaultTraits { + + /// \brief The digraph type the algorithm runs on. + typedef GR Digraph; + + /// \brief The type of the map that stores the arc capacities. + /// + /// The type of the map that stores the arc capacities. + /// It must meet the \ref concepts::ReadMap "ReadMap" concept. + typedef CAP CapacityMap; + + /// \brief The type of the flow values. + typedef typename CapacityMap::Value Value; + + /// \brief The type of the map that stores the flow values. + /// + /// The type of the map that stores the flow values. + /// It must meet the \ref concepts::ReadWriteMap "ReadWriteMap" concept. +#ifdef DOXYGEN + typedef GR::ArcMap FlowMap; +#else + typedef typename Digraph::template ArcMap FlowMap; +#endif + + /// \brief Instantiates a FlowMap. + /// + /// This function instantiates a \ref FlowMap. + /// \param digraph The digraph for which we would like to define + /// the flow map. + static FlowMap* createFlowMap(const Digraph& digraph) { + return new FlowMap(digraph); + } + + /// \brief The tolerance used by the algorithm + /// + /// The tolerance used by the algorithm to handle inexact computation. + typedef lemon::Tolerance Tolerance; + + }; + + /// \ingroup max_flow + /// + /// \brief Edmonds-Karp algorithms class. + /// + /// This class provides an implementation of the \e Edmonds-Karp \e + /// algorithm producing a \ref max_flow "flow of maximum value" in a + /// digraph \cite clrs01algorithms, \cite amo93networkflows, + /// \cite edmondskarp72theoretical. + /// The Edmonds-Karp algorithm is slower than the Preflow + /// algorithm, but it has an advantage of the step-by-step execution + /// control with feasible flow solutions. The \e source node, the \e + /// target node, the \e capacity of the arcs and the \e starting \e + /// flow value of the arcs should be passed to the algorithm + /// through the constructor. + /// + /// The time complexity of the algorithm is \f$ O(nm^2) \f$ in + /// worst case. Always try the Preflow algorithm instead of this if + /// you just want to compute the optimal flow. + /// + /// \tparam GR The type of the digraph the algorithm runs on. + /// \tparam CAP The type of the capacity map. The default map + /// type is \ref concepts::Digraph::ArcMap "GR::ArcMap". + /// \tparam TR The traits class that defines various types used by the + /// algorithm. By default, it is \ref EdmondsKarpDefaultTraits + /// "EdmondsKarpDefaultTraits". + /// In most cases, this parameter should not be set directly, + /// consider to use the named template parameters instead. + +#ifdef DOXYGEN + template +#else + template , + typename TR = EdmondsKarpDefaultTraits > +#endif + class EdmondsKarp { + public: + + /// \brief The \ref lemon::EdmondsKarpDefaultTraits "traits class" + /// of the algorithm. + typedef TR Traits; + /// The type of the digraph the algorithm runs on. + typedef typename Traits::Digraph Digraph; + /// The type of the capacity map. + typedef typename Traits::CapacityMap CapacityMap; + /// The type of the flow values. + typedef typename Traits::Value Value; + + /// The type of the flow map. + typedef typename Traits::FlowMap FlowMap; + /// The type of the tolerance. + typedef typename Traits::Tolerance Tolerance; + + private: + + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + typedef typename Digraph::template NodeMap PredMap; + + const Digraph& _graph; + const CapacityMap* _capacity; + + Node _source, _target; + + FlowMap* _flow; + bool _local_flow; + + PredMap* _pred; + std::vector _queue; + + Tolerance _tolerance; + Value _flow_value; + + void createStructures() { + if (!_flow) { + _flow = Traits::createFlowMap(_graph); + _local_flow = true; + } + if (!_pred) { + _pred = new PredMap(_graph); + } + _queue.resize(countNodes(_graph)); + } + + void destroyStructures() { + if (_local_flow) { + delete _flow; + } + if (_pred) { + delete _pred; + } + } + + public: + + typedef EdmondsKarp Create; + + ///\name Named template parameters + + ///@{ + + template + struct SetFlowMapTraits : public Traits { + typedef T FlowMap; + static FlowMap *createFlowMap(const Digraph&) { + LEMON_ASSERT(false, "FlowMap is not initialized"); + return 0; + } + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// FlowMap type + /// + /// \ref named-templ-param "Named parameter" for setting FlowMap + /// type + template + struct SetFlowMap + : public EdmondsKarp > { + typedef EdmondsKarp > Create; + }; + + /// @} + + protected: + + EdmondsKarp() {} + + public: + + /// \brief The constructor of the class. + /// + /// The constructor of the class. + /// \param digraph The digraph the algorithm runs on. + /// \param capacity The capacity of the arcs. + /// \param source The source node. + /// \param target The target node. + EdmondsKarp(const Digraph& digraph, const CapacityMap& capacity, + Node source, Node target) + : _graph(digraph), _capacity(&capacity), _source(source), _target(target), + _flow(0), _local_flow(false), _pred(0), _tolerance(), _flow_value() + { + LEMON_ASSERT(_source != _target, + "Flow source and target are the same nodes."); + } + + /// \brief Destructor. + /// + /// Destructor. + ~EdmondsKarp() { + destroyStructures(); + } + + /// \brief Sets the capacity map. + /// + /// Sets the capacity map. + /// \return (*this) + EdmondsKarp& capacityMap(const CapacityMap& map) { + _capacity = ↦ + return *this; + } + + /// \brief Sets the flow map. + /// + /// Sets the flow map. + /// If you don't use this function before calling \ref run() or + /// \ref init(), an instance will be allocated automatically. + /// The destructor deallocates this automatically allocated map, + /// of course. + /// \return (*this) + EdmondsKarp& flowMap(FlowMap& map) { + if (_local_flow) { + delete _flow; + _local_flow = false; + } + _flow = ↦ + return *this; + } + + /// \brief Sets the source node. + /// + /// Sets the source node. + /// \return (*this) + EdmondsKarp& source(const Node& node) { + _source = node; + return *this; + } + + /// \brief Sets the target node. + /// + /// Sets the target node. + /// \return (*this) + EdmondsKarp& target(const Node& node) { + _target = node; + return *this; + } + + /// \brief Sets the tolerance used by algorithm. + /// + /// Sets the tolerance used by algorithm. + /// \return (*this) + EdmondsKarp& tolerance(const Tolerance& tolerance) { + _tolerance = tolerance; + return *this; + } + + /// \brief Returns a const reference to the tolerance. + /// + /// Returns a const reference to the tolerance object used by + /// the algorithm. + const Tolerance& tolerance() const { + return _tolerance; + } + + /// \name Execution control + /// The simplest way to execute the algorithm is to use \ref run().\n + /// If you need better control on the initial solution or the execution, + /// you have to call one of the \ref init() functions first, then + /// \ref start() or multiple times the \ref augment() function. + + ///@{ + + /// \brief Initializes the algorithm. + /// + /// Initializes the internal data structures and sets the initial + /// flow to zero on each arc. + void init() { + createStructures(); + for (ArcIt it(_graph); it != INVALID; ++it) { + _flow->set(it, 0); + } + _flow_value = 0; + } + + /// \brief Initializes the algorithm using the given flow map. + /// + /// Initializes the internal data structures and sets the initial + /// flow to the given \c flowMap. The \c flowMap should + /// contain a feasible flow, i.e. at each node excluding the source + /// and the target, the incoming flow should be equal to the + /// outgoing flow. + template + void init(const FlowMap& flowMap) { + createStructures(); + for (ArcIt e(_graph); e != INVALID; ++e) { + _flow->set(e, flowMap[e]); + } + _flow_value = 0; + for (OutArcIt jt(_graph, _source); jt != INVALID; ++jt) { + _flow_value += (*_flow)[jt]; + } + for (InArcIt jt(_graph, _source); jt != INVALID; ++jt) { + _flow_value -= (*_flow)[jt]; + } + } + + /// \brief Initializes the algorithm using the given flow map. + /// + /// Initializes the internal data structures and sets the initial + /// flow to the given \c flowMap. The \c flowMap should + /// contain a feasible flow, i.e. at each node excluding the source + /// and the target, the incoming flow should be equal to the + /// outgoing flow. + /// \return \c false when the given \c flowMap does not contain a + /// feasible flow. + template + bool checkedInit(const FlowMap& flowMap) { + createStructures(); + for (ArcIt e(_graph); e != INVALID; ++e) { + _flow->set(e, flowMap[e]); + } + for (NodeIt it(_graph); it != INVALID; ++it) { + if (it == _source || it == _target) continue; + Value outFlow = 0; + for (OutArcIt jt(_graph, it); jt != INVALID; ++jt) { + outFlow += (*_flow)[jt]; + } + Value inFlow = 0; + for (InArcIt jt(_graph, it); jt != INVALID; ++jt) { + inFlow += (*_flow)[jt]; + } + if (_tolerance.different(outFlow, inFlow)) { + return false; + } + } + for (ArcIt it(_graph); it != INVALID; ++it) { + if (_tolerance.less((*_flow)[it], 0)) return false; + if (_tolerance.less((*_capacity)[it], (*_flow)[it])) return false; + } + _flow_value = 0; + for (OutArcIt jt(_graph, _source); jt != INVALID; ++jt) { + _flow_value += (*_flow)[jt]; + } + for (InArcIt jt(_graph, _source); jt != INVALID; ++jt) { + _flow_value -= (*_flow)[jt]; + } + return true; + } + + /// \brief Augments the solution along a shortest path. + /// + /// Augments the solution along a shortest path. This function searches a + /// shortest path between the source and the target + /// in the residual digraph by the Bfs algoritm. + /// Then it increases the flow on this path with the minimal residual + /// capacity on the path. If there is no such path, it gives back + /// false. + /// \return \c false when the augmenting did not success, i.e. the + /// current flow is a feasible and optimal solution. + bool augment() { + for (NodeIt n(_graph); n != INVALID; ++n) { + _pred->set(n, INVALID); + } + + int first = 0, last = 1; + + _queue[0] = _source; + _pred->set(_source, OutArcIt(_graph, _source)); + + while (first != last && (*_pred)[_target] == INVALID) { + Node n = _queue[first++]; + + for (OutArcIt e(_graph, n); e != INVALID; ++e) { + Value rem = (*_capacity)[e] - (*_flow)[e]; + Node t = _graph.target(e); + if (_tolerance.positive(rem) && (*_pred)[t] == INVALID) { + _pred->set(t, e); + _queue[last++] = t; + } + } + for (InArcIt e(_graph, n); e != INVALID; ++e) { + Value rem = (*_flow)[e]; + Node t = _graph.source(e); + if (_tolerance.positive(rem) && (*_pred)[t] == INVALID) { + _pred->set(t, e); + _queue[last++] = t; + } + } + } + + if ((*_pred)[_target] != INVALID) { + Node n = _target; + Arc e = (*_pred)[n]; + + Value prem = (*_capacity)[e] - (*_flow)[e]; + n = _graph.source(e); + while (n != _source) { + e = (*_pred)[n]; + if (_graph.target(e) == n) { + Value rem = (*_capacity)[e] - (*_flow)[e]; + if (rem < prem) prem = rem; + n = _graph.source(e); + } else { + Value rem = (*_flow)[e]; + if (rem < prem) prem = rem; + n = _graph.target(e); + } + } + + n = _target; + e = (*_pred)[n]; + + _flow->set(e, (*_flow)[e] + prem); + n = _graph.source(e); + while (n != _source) { + e = (*_pred)[n]; + if (_graph.target(e) == n) { + _flow->set(e, (*_flow)[e] + prem); + n = _graph.source(e); + } else { + _flow->set(e, (*_flow)[e] - prem); + n = _graph.target(e); + } + } + + _flow_value += prem; + return true; + } else { + return false; + } + } + + /// \brief Executes the algorithm + /// + /// Executes the algorithm by performing augmenting phases until the + /// optimal solution is reached. + /// \pre One of the \ref init() functions must be called before + /// using this function. + void start() { + while (augment()) {} + } + + /// \brief Runs the algorithm. + /// + /// Runs the Edmonds-Karp algorithm. + /// \note ek.run() is just a shortcut of the following code. + ///\code + /// ek.init(); + /// ek.start(); + ///\endcode + void run() { + init(); + start(); + } + + /// @} + + /// \name Query Functions + /// The result of the Edmonds-Karp algorithm can be obtained using these + /// functions.\n + /// Either \ref run() or \ref start() should be called before using them. + + ///@{ + + /// \brief Returns the value of the maximum flow. + /// + /// Returns the value of the maximum flow found by the algorithm. + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + Value flowValue() const { + return _flow_value; + } + + /// \brief Returns the flow value on the given arc. + /// + /// Returns the flow value on the given arc. + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + Value flow(const Arc& arc) const { + return (*_flow)[arc]; + } + + /// \brief Returns a const reference to the flow map. + /// + /// Returns a const reference to the arc map storing the found flow. + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + const FlowMap& flowMap() const { + return *_flow; + } + + /// \brief Returns \c true when the node is on the source side of the + /// minimum cut. + /// + /// Returns true when the node is on the source side of the found + /// minimum cut. + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + bool minCut(const Node& node) const { + return ((*_pred)[node] != INVALID) || node == _source; + } + + /// \brief Gives back a minimum value cut. + /// + /// Sets \c cutMap to the characteristic vector of a minimum value + /// cut. \c cutMap should be a \ref concepts::WriteMap "writable" + /// node map with \c bool (or convertible) value type. + /// + /// \note This function calls \ref minCut() for each node, so it runs in + /// O(n) time. + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + template + void minCutMap(CutMap& cutMap) const { + for (NodeIt n(_graph); n != INVALID; ++n) { + cutMap.set(n, (*_pred)[n] != INVALID); + } + cutMap.set(_source, true); + } + + /// @} + + }; + +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/elevator.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/elevator.h new file mode 100644 index 00000000000..e4adcd59982 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/elevator.h @@ -0,0 +1,982 @@ +/* -*- 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_ELEVATOR_H +#define LEMON_ELEVATOR_H + +///\ingroup auxdat +///\file +///\brief Elevator class +/// +///Elevator class implements an efficient data structure +///for labeling items in push-relabel type algorithms. +/// + +#include +#include + +namespace lemon { + + ///Class for handling "labels" in push-relabel type algorithms. + + ///A class for handling "labels" in push-relabel type algorithms. + /// + ///\ingroup auxdat + ///Using this class you can assign "labels" (nonnegative integer numbers) + ///to the edges or nodes of a graph, manipulate and query them through + ///operations typically arising in "push-relabel" type algorithms. + /// + ///Each item is either \em active or not, and you can also choose a + ///highest level active item. + /// + ///\sa LinkedElevator + /// + ///\param GR Type of the underlying graph. + ///\param Item Type of the items the data is assigned to (\c GR::Node, + ///\c GR::Arc or \c GR::Edge). + template + class Elevator + { + public: + + typedef Item Key; + typedef int Value; + + private: + + typedef Item *Vit; + typedef typename ItemSetTraits::template Map::Type VitMap; + typedef typename ItemSetTraits::template Map::Type IntMap; + + const GR &_g; + int _max_level; + int _item_num; + VitMap _where; + IntMap _level; + std::vector _items; + std::vector _first; + std::vector _last_active; + + int _highest_active; + + void copy(Item i, Vit p) + { + _where[*p=i] = p; + } + void copy(Vit s, Vit p) + { + if(s!=p) + { + Item i=*s; + *p=i; + _where[i] = p; + } + } + void swap(Vit i, Vit j) + { + Item ti=*i; + Vit ct = _where[ti]; + _where[ti] = _where[*i=*j]; + _where[*j] = ct; + *j=ti; + } + + public: + + ///Constructor with given maximum level. + + ///Constructor with given maximum level. + /// + ///\param graph The underlying graph. + ///\param max_level The maximum allowed level. + ///Set the range of the possible labels to [0..max_level]. + Elevator(const GR &graph,int max_level) : + _g(graph), + _max_level(max_level), + _item_num(_max_level), + _where(graph), + _level(graph,0), + _items(_max_level), + _first(_max_level+2), + _last_active(_max_level+2), + _highest_active(-1) {} + ///Constructor. + + ///Constructor. + /// + ///\param graph The underlying graph. + ///Set the range of the possible labels to [0..max_level], + ///where \c max_level is equal to the number of labeled items in the graph. + Elevator(const GR &graph) : + _g(graph), + _max_level(countItems(graph)), + _item_num(_max_level), + _where(graph), + _level(graph,0), + _items(_max_level), + _first(_max_level+2), + _last_active(_max_level+2), + _highest_active(-1) + { + } + + ///Activate item \c i. + + ///Activate item \c i. + ///\pre Item \c i shouldn't be active before. + void activate(Item i) + { + const int l=_level[i]; + swap(_where[i],++_last_active[l]); + if(l>_highest_active) _highest_active=l; + } + + ///Deactivate item \c i. + + ///Deactivate item \c i. + ///\pre Item \c i must be active before. + void deactivate(Item i) + { + swap(_where[i],_last_active[_level[i]]--); + while(_highest_active>=0 && + _last_active[_highest_active]<_first[_highest_active]) + _highest_active--; + } + + ///Query whether item \c i is active + bool active(Item i) const { return _where[i]<=_last_active[_level[i]]; } + + ///Return the level of item \c i. + int operator[](Item i) const { return _level[i]; } + + ///Return the number of items on level \c l. + int onLevel(int l) const + { + return _first[l+1]-_first[l]; + } + ///Return true if level \c l is empty. + bool emptyLevel(int l) const + { + return _first[l+1]-_first[l]==0; + } + ///Return the number of items above level \c l. + int aboveLevel(int l) const + { + return _first[_max_level+1]-_first[l+1]; + } + ///Return the number of active items on level \c l. + int activesOnLevel(int l) const + { + return _last_active[l]-_first[l]+1; + } + ///Return true if there is no active item on level \c l. + bool activeFree(int l) const + { + return _last_active[l]<_first[l]; + } + ///Return the maximum allowed level. + int maxLevel() const + { + return _max_level; + } + + ///\name Highest Active Item + ///Functions for working with the highest level + ///active item. + + ///@{ + + ///Return a highest level active item. + + ///Return a highest level active item or INVALID if there is no active + ///item. + Item highestActive() const + { + return _highest_active>=0?*_last_active[_highest_active]:INVALID; + } + + ///Return the highest active level. + + ///Return the level of the highest active item or -1 if there is no active + ///item. + int highestActiveLevel() const + { + return _highest_active; + } + + ///Lift the highest active item by one. + + ///Lift the item returned by highestActive() by one. + /// + void liftHighestActive() + { + Item it = *_last_active[_highest_active]; + ++_level[it]; + swap(_last_active[_highest_active]--,_last_active[_highest_active+1]); + --_first[++_highest_active]; + } + + ///Lift the highest active item to the given level. + + ///Lift the item returned by highestActive() to level \c new_level. + /// + ///\warning \c new_level must be strictly higher + ///than the current level. + /// + void liftHighestActive(int new_level) + { + const Item li = *_last_active[_highest_active]; + + copy(--_first[_highest_active+1],_last_active[_highest_active]--); + for(int l=_highest_active+1;l=0 && + _last_active[_highest_active]<_first[_highest_active]) + _highest_active--; + } + + ///@} + + ///\name Active Item on Certain Level + ///Functions for working with the active items. + + ///@{ + + ///Return an active item on level \c l. + + ///Return an active item on level \c l or \ref INVALID if there is no such + ///an item. (\c l must be from the range [0...\c max_level]. + Item activeOn(int l) const + { + return _last_active[l]>=_first[l]?*_last_active[l]:INVALID; + } + + ///Lift the active item returned by \c activeOn(level) by one. + + ///Lift the active item returned by \ref activeOn() "activeOn(level)" + ///by one. + Item liftActiveOn(int level) + { + Item it =*_last_active[level]; + ++_level[it]; + swap(_last_active[level]--, --_first[level+1]); + if (level+1>_highest_active) ++_highest_active; + } + + ///Lift the active item returned by \c activeOn(level) to the given level. + + ///Lift the active item returned by \ref activeOn() "activeOn(level)" + ///to the given level. + void liftActiveOn(int level, int new_level) + { + const Item ai = *_last_active[level]; + + copy(--_first[level+1], _last_active[level]--); + for(int l=level+1;l_highest_active) _highest_active=new_level; + } + + ///Lift the active item returned by \c activeOn(level) to the top level. + + ///Lift the active item returned by \ref activeOn() "activeOn(level)" + ///to the top level and deactivate it. + void liftActiveToTop(int level) + { + const Item ai = *_last_active[level]; + + copy(--_first[level+1],_last_active[level]--); + for(int l=level+1;l<_max_level;l++) + { + copy(_last_active[l],_first[l]); + copy(--_first[l+1], _last_active[l]--); + } + copy(ai,_first[_max_level]); + --_last_active[_max_level]; + _level[ai] = _max_level; + + if (_highest_active==level) { + while(_highest_active>=0 && + _last_active[_highest_active]<_first[_highest_active]) + _highest_active--; + } + } + + ///@} + + ///Lift an active item to a higher level. + + ///Lift an active item to a higher level. + ///\param i The item to be lifted. It must be active. + ///\param new_level The new level of \c i. It must be strictly higher + ///than the current level. + /// + void lift(Item i, int new_level) + { + const int lo = _level[i]; + const Vit w = _where[i]; + + copy(_last_active[lo],w); + copy(--_first[lo+1],_last_active[lo]--); + for(int l=lo+1;l_highest_active) _highest_active=new_level; + } + + ///Move an inactive item to the top but one level (in a dirty way). + + ///This function moves an inactive item from the top level to the top + ///but one level (in a dirty way). + ///\warning It makes the underlying datastructure corrupt, so use it + ///only if you really know what it is for. + ///\pre The item is on the top level. + void dirtyTopButOne(Item i) { + _level[i] = _max_level - 1; + } + + ///Lift all items on and above the given level to the top level. + + ///This function lifts all items on and above level \c l to the top + ///level and deactivates them. + void liftToTop(int l) + { + const Vit f=_first[l]; + const Vit tl=_first[_max_level]; + for(Vit i=f;i!=tl;++i) + _level[*i] = _max_level; + for(int i=l;i<=_max_level;i++) + { + _first[i]=f; + _last_active[i]=f-1; + } + for(_highest_active=l-1; + _highest_active>=0 && + _last_active[_highest_active]<_first[_highest_active]; + _highest_active--) ; + } + + private: + int _init_lev; + Vit _init_num; + + public: + + ///\name Initialization + ///Using these functions you can initialize the levels of the items. + ///\n + ///The initialization must be started with calling \c initStart(). + ///Then the items should be listed level by level starting with the + ///lowest one (level 0) using \c initAddItem() and \c initNewLevel(). + ///Finally \c initFinish() must be called. + ///The items not listed are put on the highest level. + ///@{ + + ///Start the initialization process. + void initStart() + { + _init_lev=0; + _init_num=&_items[0]; + _first[0]=&_items[0]; + _last_active[0]=&_items[0]-1; + Vit n=&_items[0]; + for(typename ItemSetTraits::ItemIt i(_g);i!=INVALID;++i) + { + *n=i; + _where[i] = n; + _level[i] = _max_level; + ++n; + } + } + + ///Add an item to the current level. + void initAddItem(Item i) + { + swap(_where[i],_init_num); + _level[i] = _init_lev; + ++_init_num; + } + + ///Start a new level. + + ///Start a new level. + ///It shouldn't be used before the items on level 0 are listed. + void initNewLevel() + { + _init_lev++; + _first[_init_lev]=_init_num; + _last_active[_init_lev]=_init_num-1; + } + + ///Finalize the initialization process. + void initFinish() + { + for(_init_lev++;_init_lev<=_max_level;_init_lev++) + { + _first[_init_lev]=_init_num; + _last_active[_init_lev]=_init_num-1; + } + _first[_max_level+1]=&_items[0]+_item_num; + _last_active[_max_level+1]=&_items[0]+_item_num-1; + _highest_active = -1; + } + + ///@} + + }; + + ///Class for handling "labels" in push-relabel type algorithms. + + ///A class for handling "labels" in push-relabel type algorithms. + /// + ///\ingroup auxdat + ///Using this class you can assign "labels" (nonnegative integer numbers) + ///to the edges or nodes of a graph, manipulate and query them through + ///operations typically arising in "push-relabel" type algorithms. + /// + ///Each item is either \em active or not, and you can also choose a + ///highest level active item. + /// + ///\sa Elevator + /// + ///\param GR Type of the underlying graph. + ///\param Item Type of the items the data is assigned to (\c GR::Node, + ///\c GR::Arc or \c GR::Edge). + template + class LinkedElevator { + public: + + typedef Item Key; + typedef int Value; + + private: + + typedef typename ItemSetTraits:: + template Map::Type ItemMap; + typedef typename ItemSetTraits:: + template Map::Type IntMap; + typedef typename ItemSetTraits:: + template Map::Type BoolMap; + + const GR &_graph; + int _max_level; + int _item_num; + std::vector _first, _last; + ItemMap _prev, _next; + int _highest_active; + IntMap _level; + BoolMap _active; + + public: + ///Constructor with given maximum level. + + ///Constructor with given maximum level. + /// + ///\param graph The underlying graph. + ///\param max_level The maximum allowed level. + ///Set the range of the possible labels to [0..max_level]. + LinkedElevator(const GR& graph, int max_level) + : _graph(graph), _max_level(max_level), _item_num(_max_level), + _first(_max_level + 1), _last(_max_level + 1), + _prev(graph), _next(graph), + _highest_active(-1), _level(graph), _active(graph) {} + + ///Constructor. + + ///Constructor. + /// + ///\param graph The underlying graph. + ///Set the range of the possible labels to [0..max_level], + ///where \c max_level is equal to the number of labeled items in the graph. + LinkedElevator(const GR& graph) + : _graph(graph), _max_level(countItems(graph)), + _item_num(_max_level), + _first(_max_level + 1), _last(_max_level + 1), + _prev(graph, INVALID), _next(graph, INVALID), + _highest_active(-1), _level(graph), _active(graph) {} + + + ///Activate item \c i. + + ///Activate item \c i. + ///\pre Item \c i shouldn't be active before. + void activate(Item i) { + _active[i] = true; + + int level = _level[i]; + if (level > _highest_active) { + _highest_active = level; + } + + if (_prev[i] == INVALID || _active[_prev[i]]) return; + //unlace + _next[_prev[i]] = _next[i]; + if (_next[i] != INVALID) { + _prev[_next[i]] = _prev[i]; + } else { + _last[level] = _prev[i]; + } + //lace + _next[i] = _first[level]; + _prev[_first[level]] = i; + _prev[i] = INVALID; + _first[level] = i; + + } + + ///Deactivate item \c i. + + ///Deactivate item \c i. + ///\pre Item \c i must be active before. + void deactivate(Item i) { + _active[i] = false; + int level = _level[i]; + + if (_next[i] == INVALID || !_active[_next[i]]) + goto find_highest_level; + + //unlace + _prev[_next[i]] = _prev[i]; + if (_prev[i] != INVALID) { + _next[_prev[i]] = _next[i]; + } else { + _first[_level[i]] = _next[i]; + } + //lace + _prev[i] = _last[level]; + _next[_last[level]] = i; + _next[i] = INVALID; + _last[level] = i; + + find_highest_level: + if (level == _highest_active) { + while (_highest_active >= 0 && activeFree(_highest_active)) + --_highest_active; + } + } + + ///Query whether item \c i is active + bool active(Item i) const { return _active[i]; } + + ///Return the level of item \c i. + int operator[](Item i) const { return _level[i]; } + + ///Return the number of items on level \c l. + int onLevel(int l) const { + int num = 0; + Item n = _first[l]; + while (n != INVALID) { + ++num; + n = _next[n]; + } + return num; + } + + ///Return true if the level is empty. + bool emptyLevel(int l) const { + return _first[l] == INVALID; + } + + ///Return the number of items above level \c l. + int aboveLevel(int l) const { + int num = 0; + for (int level = l + 1; level < _max_level; ++level) + num += onLevel(level); + return num; + } + + ///Return the number of active items on level \c l. + int activesOnLevel(int l) const { + int num = 0; + Item n = _first[l]; + while (n != INVALID && _active[n]) { + ++num; + n = _next[n]; + } + return num; + } + + ///Return true if there is no active item on level \c l. + bool activeFree(int l) const { + return _first[l] == INVALID || !_active[_first[l]]; + } + + ///Return the maximum allowed level. + int maxLevel() const { + return _max_level; + } + + ///\name Highest Active Item + ///Functions for working with the highest level + ///active item. + + ///@{ + + ///Return a highest level active item. + + ///Return a highest level active item or INVALID if there is no active + ///item. + Item highestActive() const { + return _highest_active >= 0 ? _first[_highest_active] : INVALID; + } + + ///Return the highest active level. + + ///Return the level of the highest active item or -1 if there is no active + ///item. + int highestActiveLevel() const { + return _highest_active; + } + + ///Lift the highest active item by one. + + ///Lift the item returned by highestActive() by one. + /// + void liftHighestActive() { + Item i = _first[_highest_active]; + if (_next[i] != INVALID) { + _prev[_next[i]] = INVALID; + _first[_highest_active] = _next[i]; + } else { + _first[_highest_active] = INVALID; + _last[_highest_active] = INVALID; + } + _level[i] = ++_highest_active; + if (_first[_highest_active] == INVALID) { + _first[_highest_active] = i; + _last[_highest_active] = i; + _prev[i] = INVALID; + _next[i] = INVALID; + } else { + _prev[_first[_highest_active]] = i; + _next[i] = _first[_highest_active]; + _first[_highest_active] = i; + } + } + + ///Lift the highest active item to the given level. + + ///Lift the item returned by highestActive() to level \c new_level. + /// + ///\warning \c new_level must be strictly higher + ///than the current level. + /// + void liftHighestActive(int new_level) { + Item i = _first[_highest_active]; + if (_next[i] != INVALID) { + _prev[_next[i]] = INVALID; + _first[_highest_active] = _next[i]; + } else { + _first[_highest_active] = INVALID; + _last[_highest_active] = INVALID; + } + _level[i] = _highest_active = new_level; + if (_first[_highest_active] == INVALID) { + _first[_highest_active] = _last[_highest_active] = i; + _prev[i] = INVALID; + _next[i] = INVALID; + } else { + _prev[_first[_highest_active]] = i; + _next[i] = _first[_highest_active]; + _first[_highest_active] = i; + } + } + + ///Lift the highest active item to the top level. + + ///Lift the item returned by highestActive() to the top level and + ///deactivate it. + void liftHighestActiveToTop() { + Item i = _first[_highest_active]; + _level[i] = _max_level; + if (_next[i] != INVALID) { + _prev[_next[i]] = INVALID; + _first[_highest_active] = _next[i]; + } else { + _first[_highest_active] = INVALID; + _last[_highest_active] = INVALID; + } + while (_highest_active >= 0 && activeFree(_highest_active)) + --_highest_active; + } + + ///@} + + ///\name Active Item on Certain Level + ///Functions for working with the active items. + + ///@{ + + ///Return an active item on level \c l. + + ///Return an active item on level \c l or \ref INVALID if there is no such + ///an item. (\c l must be from the range [0...\c max_level]. + Item activeOn(int l) const + { + return _active[_first[l]] ? _first[l] : INVALID; + } + + ///Lift the active item returned by \c activeOn(l) by one. + + ///Lift the active item returned by \ref activeOn() "activeOn(l)" + ///by one. + Item liftActiveOn(int l) + { + Item i = _first[l]; + if (_next[i] != INVALID) { + _prev[_next[i]] = INVALID; + _first[l] = _next[i]; + } else { + _first[l] = INVALID; + _last[l] = INVALID; + } + _level[i] = ++l; + if (_first[l] == INVALID) { + _first[l] = _last[l] = i; + _prev[i] = INVALID; + _next[i] = INVALID; + } else { + _prev[_first[l]] = i; + _next[i] = _first[l]; + _first[l] = i; + } + if (_highest_active < l) { + _highest_active = l; + } + } + + ///Lift the active item returned by \c activeOn(l) to the given level. + + ///Lift the active item returned by \ref activeOn() "activeOn(l)" + ///to the given level. + void liftActiveOn(int l, int new_level) + { + Item i = _first[l]; + if (_next[i] != INVALID) { + _prev[_next[i]] = INVALID; + _first[l] = _next[i]; + } else { + _first[l] = INVALID; + _last[l] = INVALID; + } + _level[i] = l = new_level; + if (_first[l] == INVALID) { + _first[l] = _last[l] = i; + _prev[i] = INVALID; + _next[i] = INVALID; + } else { + _prev[_first[l]] = i; + _next[i] = _first[l]; + _first[l] = i; + } + if (_highest_active < l) { + _highest_active = l; + } + } + + ///Lift the active item returned by \c activeOn(l) to the top level. + + ///Lift the active item returned by \ref activeOn() "activeOn(l)" + ///to the top level and deactivate it. + void liftActiveToTop(int l) + { + Item i = _first[l]; + if (_next[i] != INVALID) { + _prev[_next[i]] = INVALID; + _first[l] = _next[i]; + } else { + _first[l] = INVALID; + _last[l] = INVALID; + } + _level[i] = _max_level; + if (l == _highest_active) { + while (_highest_active >= 0 && activeFree(_highest_active)) + --_highest_active; + } + } + + ///@} + + /// \brief Lift an active item to a higher level. + /// + /// Lift an active item to a higher level. + /// \param i The item to be lifted. It must be active. + /// \param new_level The new level of \c i. It must be strictly higher + /// than the current level. + /// + void lift(Item i, int new_level) { + if (_next[i] != INVALID) { + _prev[_next[i]] = _prev[i]; + } else { + _last[new_level] = _prev[i]; + } + if (_prev[i] != INVALID) { + _next[_prev[i]] = _next[i]; + } else { + _first[new_level] = _next[i]; + } + _level[i] = new_level; + if (_first[new_level] == INVALID) { + _first[new_level] = _last[new_level] = i; + _prev[i] = INVALID; + _next[i] = INVALID; + } else { + _prev[_first[new_level]] = i; + _next[i] = _first[new_level]; + _first[new_level] = i; + } + if (_highest_active < new_level) { + _highest_active = new_level; + } + } + + ///Move an inactive item to the top but one level (in a dirty way). + + ///This function moves an inactive item from the top level to the top + ///but one level (in a dirty way). + ///\warning It makes the underlying datastructure corrupt, so use it + ///only if you really know what it is for. + ///\pre The item is on the top level. + void dirtyTopButOne(Item i) { + _level[i] = _max_level - 1; + } + + ///Lift all items on and above the given level to the top level. + + ///This function lifts all items on and above level \c l to the top + ///level and deactivates them. + void liftToTop(int l) { + for (int i = l + 1; _first[i] != INVALID; ++i) { + Item n = _first[i]; + while (n != INVALID) { + _level[n] = _max_level; + n = _next[n]; + } + _first[i] = INVALID; + _last[i] = INVALID; + } + if (_highest_active > l - 1) { + _highest_active = l - 1; + while (_highest_active >= 0 && activeFree(_highest_active)) + --_highest_active; + } + } + + private: + + int _init_level; + + public: + + ///\name Initialization + ///Using these functions you can initialize the levels of the items. + ///\n + ///The initialization must be started with calling \c initStart(). + ///Then the items should be listed level by level starting with the + ///lowest one (level 0) using \c initAddItem() and \c initNewLevel(). + ///Finally \c initFinish() must be called. + ///The items not listed are put on the highest level. + ///@{ + + ///Start the initialization process. + void initStart() { + + for (int i = 0; i <= _max_level; ++i) { + _first[i] = _last[i] = INVALID; + } + _init_level = 0; + for(typename ItemSetTraits::ItemIt i(_graph); + i != INVALID; ++i) { + _level[i] = _max_level; + _active[i] = false; + } + } + + ///Add an item to the current level. + void initAddItem(Item i) { + _level[i] = _init_level; + if (_last[_init_level] == INVALID) { + _first[_init_level] = i; + _last[_init_level] = i; + _prev[i] = INVALID; + _next[i] = INVALID; + } else { + _prev[i] = _last[_init_level]; + _next[i] = INVALID; + _next[_last[_init_level]] = i; + _last[_init_level] = i; + } + } + + ///Start a new level. + + ///Start a new level. + ///It shouldn't be used before the items on level 0 are listed. + void initNewLevel() { + ++_init_level; + } + + ///Finalize the initialization process. + void initFinish() { + _highest_active = -1; + } + + ///@} + + }; + + +} //END OF NAMESPACE LEMON + +#endif + diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/error.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/error.h new file mode 100644 index 00000000000..f937704541b --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/error.h @@ -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-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_ERROR_H +#define LEMON_ERROR_H + +/// \ingroup exceptions +/// \file +/// \brief Basic exception classes and error handling. + +#include +#include +#include +#include +#include +#include + +namespace lemon { + + /// \addtogroup exceptions + /// @{ + + /// \brief Generic exception class. + /// + /// Base class for exceptions used in LEMON. + /// + class Exception : public std::exception { + public: + ///Constructor + Exception() throw() {} + ///Virtual destructor + virtual ~Exception() throw() {} + ///A short description of the exception + virtual const char* what() const throw() { + return "lemon::Exception"; + } + }; + + /// \brief Input-Output error + /// + /// This exception is thrown when a file operation cannot be + /// succeeded. + class IoError : public Exception { + protected: + std::string _message; + std::string _file; + + mutable std::string _what; + public: + + /// Copy constructor + IoError(const IoError &error) throw() : Exception() { + message(error._message); + file(error._file); + } + + /// Constructor + explicit IoError(const char *message) throw() { + IoError::message(message); + } + + /// Constructor + explicit IoError(const std::string &message) throw() { + IoError::message(message); + } + + /// Constructor + explicit IoError(const char *message, + const std::string &file) throw() { + IoError::message(message); + IoError::file(file); + } + + /// Constructor + explicit IoError(const std::string &message, + const std::string &file) throw() { + IoError::message(message); + IoError::file(file); + } + + /// Virtual destructor + virtual ~IoError() throw() {} + + /// Set the error message + void message(const char *message) throw() { + try { + _message = message; + } catch (...) {} + } + + /// Set the error message + void message(const std::string& message) throw() { + try { + _message = message; + } catch (...) {} + } + + /// Set the file name + void file(const std::string &file) throw() { + try { + _file = file; + } catch (...) {} + } + + /// Returns the error message + const std::string& message() const throw() { + return _message; + } + + /// \brief Returns the filename + /// + /// Returns the filename or an empty string if it was not specified. + const std::string& file() const throw() { + return _file; + } + + /// \brief Returns a short error message + /// + /// Returns a short error message which contains the message and the + /// file name. + virtual const char* what() const throw() { + try { + _what.clear(); + std::ostringstream oss; + oss << "lemon:IoError" << ": "; + oss << _message; + if (!_file.empty()) { + oss << " ('" << _file << "')"; + } + _what = oss.str(); + } + catch (...) {} + if (!_what.empty()) return _what.c_str(); + else return "lemon:IoError"; + } + + }; + + /// \brief Format error + /// + /// This exception is thrown when an input file has wrong + /// format or a data representation is not legal. + class FormatError : public Exception { + protected: + std::string _message; + std::string _file; + int _line; + + mutable std::string _what; + public: + + /// Copy constructor + FormatError(const FormatError &error) throw() : Exception() { + message(error._message); + file(error._file); + line(error._line); + } + + /// Constructor + explicit FormatError(const char *message) throw() { + FormatError::message(message); + _line = 0; + } + + /// Constructor + explicit FormatError(const std::string &message) throw() { + FormatError::message(message); + _line = 0; + } + + /// Constructor + explicit FormatError(const char *message, + const std::string &file, int line = 0) throw() { + FormatError::message(message); + FormatError::file(file); + FormatError::line(line); + } + + /// Constructor + explicit FormatError(const std::string &message, + const std::string &file, int line = 0) throw() { + FormatError::message(message); + FormatError::file(file); + FormatError::line(line); + } + + /// Virtual destructor + virtual ~FormatError() throw() {} + + /// Set the line number + void line(int line) throw() { _line = line; } + + /// Set the error message + void message(const char *message) throw() { + try { + _message = message; + } catch (...) {} + } + + /// Set the error message + void message(const std::string& message) throw() { + try { + _message = message; + } catch (...) {} + } + + /// Set the file name + void file(const std::string &file) throw() { + try { + _file = file; + } catch (...) {} + } + + /// \brief Returns the line number + /// + /// Returns the line number or zero if it was not specified. + int line() const throw() { return _line; } + + /// Returns the error message + const std::string& message() const throw() { + return _message; + } + + /// \brief Returns the filename + /// + /// Returns the filename or an empty string if it was not specified. + const std::string& file() const throw() { + return _file; + } + + /// \brief Returns a short error message + /// + /// Returns a short error message which contains the message, the + /// file name and the line number. + virtual const char* what() const throw() { + try { + _what.clear(); + std::ostringstream oss; + oss << "lemon:FormatError" << ": "; + oss << _message; + if (!_file.empty() || _line != 0) { + oss << " ("; + if (!_file.empty()) oss << "in file '" << _file << "'"; + if (!_file.empty() && _line != 0) oss << " "; + if (_line != 0) oss << "at line " << _line; + oss << ")"; + } + _what = oss.str(); + } + catch (...) {} + if (!_what.empty()) return _what.c_str(); + else return "lemon:FormatError"; + } + + }; + + /// @} + +} + +#endif // LEMON_ERROR_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/euler.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/euler.h new file mode 100644 index 00000000000..3a3cbd0653d --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/euler.h @@ -0,0 +1,287 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_EULER_H +#define LEMON_EULER_H + +#include +#include +#include +#include + +/// \ingroup graph_properties +/// \file +/// \brief Euler tour iterators and a function for checking the \e Eulerian +/// property. +/// +///This file provides Euler tour iterators and a function to check +///if a (di)graph is \e Eulerian. + +namespace lemon { + + ///Euler tour iterator for digraphs. + + /// \ingroup graph_properties + ///This iterator provides an Euler tour (Eulerian circuit) of a \e directed + ///graph (if there exists) and it converts to the \c Arc type of the digraph. + /// + ///For example, if the given digraph has an Euler tour (i.e it has only one + ///non-trivial component and the in-degree is equal to the out-degree + ///for all nodes), then the following code will put the arcs of \c g + ///to the vector \c et according to an Euler tour of \c g. + ///\code + /// std::vector et; + /// for(DiEulerIt e(g); e!=INVALID; ++e) + /// et.push_back(e); + ///\endcode + ///If \c g has no Euler tour, then the resulted walk will not be closed + ///or not contain all arcs. + ///\sa EulerIt + template + class DiEulerIt + { + typedef typename GR::Node Node; + typedef typename GR::NodeIt NodeIt; + typedef typename GR::Arc Arc; + typedef typename GR::ArcIt ArcIt; + typedef typename GR::OutArcIt OutArcIt; + typedef typename GR::InArcIt InArcIt; + + const GR &g; + typename GR::template NodeMap narc; + std::list euler; + + public: + + ///Constructor + + ///Constructor. + ///\param gr A digraph. + ///\param start The starting point of the tour. If it is not given, + ///the tour will start from the first node that has an outgoing arc. + DiEulerIt(const GR &gr, typename GR::Node start = INVALID) + : g(gr), narc(g) + { + if (start==INVALID) { + NodeIt n(g); + while (n!=INVALID && OutArcIt(g,n)==INVALID) ++n; + start=n; + } + if (start!=INVALID) { + for (NodeIt n(g); n!=INVALID; ++n) narc[n]=OutArcIt(g,n); + while (narc[start]!=INVALID) { + euler.push_back(narc[start]); + Node next=g.target(narc[start]); + ++narc[start]; + start=next; + } + } + } + + ///Arc conversion + operator Arc() { return euler.empty()?INVALID:euler.front(); } + ///Compare with \c INVALID + bool operator==(Invalid) { return euler.empty(); } + ///Compare with \c INVALID + bool operator!=(Invalid) { return !euler.empty(); } + + ///Next arc of the tour + + ///Next arc of the tour + /// + DiEulerIt &operator++() { + Node s=g.target(euler.front()); + euler.pop_front(); + typename std::list::iterator next=euler.begin(); + while(narc[s]!=INVALID) { + euler.insert(next,narc[s]); + Node n=g.target(narc[s]); + ++narc[s]; + s=n; + } + return *this; + } + ///Postfix incrementation + + /// Postfix incrementation. + /// + ///\warning This incrementation + ///returns an \c Arc, not a \ref DiEulerIt, as one may + ///expect. + Arc operator++(int) + { + Arc e=*this; + ++(*this); + return e; + } + }; + + ///Euler tour iterator for graphs. + + /// \ingroup graph_properties + ///This iterator provides an Euler tour (Eulerian circuit) of an + ///\e undirected graph (if there exists) and it converts to the \c Arc + ///and \c Edge types of the graph. + /// + ///For example, if the given graph has an Euler tour (i.e it has only one + ///non-trivial component and the degree of each node is even), + ///the following code will print the arc IDs according to an + ///Euler tour of \c g. + ///\code + /// for(EulerIt e(g); e!=INVALID; ++e) { + /// std::cout << g.id(Edge(e)) << std::eol; + /// } + ///\endcode + ///Although this iterator is for undirected graphs, it still returns + ///arcs in order to indicate the direction of the tour. + ///(But arcs convert to edges, of course.) + /// + ///If \c g has no Euler tour, then the resulted walk will not be closed + ///or not contain all edges. + template + class EulerIt + { + typedef typename GR::Node Node; + typedef typename GR::NodeIt NodeIt; + typedef typename GR::Arc Arc; + typedef typename GR::Edge Edge; + typedef typename GR::ArcIt ArcIt; + typedef typename GR::OutArcIt OutArcIt; + typedef typename GR::InArcIt InArcIt; + + const GR &g; + typename GR::template NodeMap narc; + typename GR::template EdgeMap visited; + std::list euler; + + public: + + ///Constructor + + ///Constructor. + ///\param gr A graph. + ///\param start The starting point of the tour. If it is not given, + ///the tour will start from the first node that has an incident edge. + EulerIt(const GR &gr, typename GR::Node start = INVALID) + : g(gr), narc(g), visited(g, false) + { + if (start==INVALID) { + NodeIt n(g); + while (n!=INVALID && OutArcIt(g,n)==INVALID) ++n; + start=n; + } + if (start!=INVALID) { + for (NodeIt n(g); n!=INVALID; ++n) narc[n]=OutArcIt(g,n); + while(narc[start]!=INVALID) { + euler.push_back(narc[start]); + visited[narc[start]]=true; + Node next=g.target(narc[start]); + ++narc[start]; + start=next; + while(narc[start]!=INVALID && visited[narc[start]]) ++narc[start]; + } + } + } + + ///Arc conversion + operator Arc() const { return euler.empty()?INVALID:euler.front(); } + ///Edge conversion + operator Edge() const { return euler.empty()?INVALID:euler.front(); } + ///Compare with \c INVALID + bool operator==(Invalid) const { return euler.empty(); } + ///Compare with \c INVALID + bool operator!=(Invalid) const { return !euler.empty(); } + + ///Next arc of the tour + + ///Next arc of the tour + /// + EulerIt &operator++() { + Node s=g.target(euler.front()); + euler.pop_front(); + typename std::list::iterator next=euler.begin(); + while(narc[s]!=INVALID) { + while(narc[s]!=INVALID && visited[narc[s]]) ++narc[s]; + if(narc[s]==INVALID) break; + else { + euler.insert(next,narc[s]); + visited[narc[s]]=true; + Node n=g.target(narc[s]); + ++narc[s]; + s=n; + } + } + return *this; + } + + ///Postfix incrementation + + /// Postfix incrementation. + /// + ///\warning This incrementation returns an \c Arc (which converts to + ///an \c Edge), not an \ref EulerIt, as one may expect. + Arc operator++(int) + { + Arc e=*this; + ++(*this); + return e; + } + }; + + + ///Check if the given graph is Eulerian + + /// \ingroup graph_properties + ///This function checks if the given graph is Eulerian. + ///It works for both directed and undirected graphs. + /// + ///By definition, a digraph is called \e Eulerian if + ///and only if it is connected and the number of incoming and outgoing + ///arcs are the same for each node. + ///Similarly, an undirected graph is called \e Eulerian if + ///and only if it is connected and the number of incident edges is even + ///for each node. + /// + ///\note There are (di)graphs that are not Eulerian, but still have an + /// Euler tour, since they may contain isolated nodes. + /// + ///\sa DiEulerIt, EulerIt + template +#ifdef DOXYGEN + bool +#else + typename enable_if,bool>::type + eulerian(const GR &g) + { + for(typename GR::NodeIt n(g);n!=INVALID;++n) + if(countIncEdges(g,n)%2) return false; + return connected(g); + } + template + typename disable_if,bool>::type +#endif + eulerian(const GR &g) + { + for(typename GR::NodeIt n(g);n!=INVALID;++n) + if(countInArcs(g,n)!=countOutArcs(g,n)) return false; + return connected(undirector(g)); + } + +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/fib_heap.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/fib_heap.h new file mode 100644 index 00000000000..3441722a034 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/fib_heap.h @@ -0,0 +1,475 @@ +/* -*- 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_FIB_HEAP_H +#define LEMON_FIB_HEAP_H + +///\file +///\ingroup heaps +///\brief Fibonacci heap implementation. + +#include +#include +#include +#include + +namespace lemon { + + /// \ingroup heaps + /// + /// \brief Fibonacci heap data structure. + /// + /// This class implements the \e Fibonacci \e heap data structure. + /// It fully conforms to the \ref concepts::Heap "heap concept". + /// + /// The methods \ref increase() and \ref erase() are not efficient in a + /// Fibonacci heap. In case of many calls of these operations, it is + /// better to use other heap structure, e.g. \ref BinHeap "binary heap". + /// + /// \tparam PR Type of the priorities of the items. + /// \tparam IM A read-writable item map with \c int values, used + /// internally to handle the cross references. + /// \tparam CMP A functor class for comparing the priorities. + /// The default is \c std::less. +#ifdef DOXYGEN + template +#else + template > +#endif + class FibHeap { + public: + + /// Type of the item-int map. + typedef IM ItemIntMap; + /// Type of the priorities. + typedef PR Prio; + /// Type of the items stored in the heap. + typedef typename ItemIntMap::Key Item; + /// Type of the item-priority pairs. + typedef std::pair Pair; + /// Functor type for comparing the priorities. + typedef CMP Compare; + + private: + class Store; + + std::vector _data; + int _minimum; + ItemIntMap &_iim; + Compare _comp; + int _num; + + public: + + /// \brief Type to represent the states of the items. + /// + /// Each item has a state associated to it. It can be "in heap", + /// "pre-heap" or "post-heap". The latter two are indifferent from the + /// heap's point of view, but may be useful to the user. + /// + /// The item-int map must be initialized in such way that it assigns + /// \c PRE_HEAP (-1) to any element to be put in the heap. + enum State { + IN_HEAP = 0, ///< = 0. + PRE_HEAP = -1, ///< = -1. + POST_HEAP = -2 ///< = -2. + }; + + /// \brief Constructor. + /// + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. + explicit FibHeap(ItemIntMap &map) + : _minimum(0), _iim(map), _num() {} + + /// \brief Constructor. + /// + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. + /// \param comp The function object used for comparing the priorities. + FibHeap(ItemIntMap &map, const Compare &comp) + : _minimum(0), _iim(map), _comp(comp), _num() {} + + /// \brief The number of items stored in the heap. + /// + /// This function returns the number of items stored in the heap. + int size() const { return _num; } + + /// \brief Check if the heap is empty. + /// + /// This function returns \c true if the heap is empty. + bool empty() const { return _num==0; } + + /// \brief Make the heap empty. + /// + /// This functon makes the heap empty. + /// It does not change the cross reference map. If you want to reuse + /// a heap that is not surely empty, you should first clear it and + /// then you should set the cross reference map to \c PRE_HEAP + /// for each item. + void clear() { + _data.clear(); _minimum = 0; _num = 0; + } + + /// \brief Insert an item into the heap with the given priority. + /// + /// This function inserts the given item into the heap with the + /// given priority. + /// \param item The item to insert. + /// \param prio The priority of the item. + /// \pre \e item must not be stored in the heap. + void push (const Item& item, const Prio& prio) { + int i=_iim[item]; + if ( i < 0 ) { + int s=_data.size(); + _iim.set( item, s ); + Store st; + st.name=item; + _data.push_back(st); + i=s; + } else { + _data[i].parent=_data[i].child=-1; + _data[i].degree=0; + _data[i].in=true; + _data[i].marked=false; + } + + if ( _num ) { + _data[_data[_minimum].right_neighbor].left_neighbor=i; + _data[i].right_neighbor=_data[_minimum].right_neighbor; + _data[_minimum].right_neighbor=i; + _data[i].left_neighbor=_minimum; + if ( _comp( prio, _data[_minimum].prio) ) _minimum=i; + } else { + _data[i].right_neighbor=_data[i].left_neighbor=i; + _minimum=i; + } + _data[i].prio=prio; + ++_num; + } + + /// \brief Return the item having minimum priority. + /// + /// This function returns the item having minimum priority. + /// \pre The heap must be non-empty. + Item top() const { return _data[_minimum].name; } + + /// \brief The minimum priority. + /// + /// This function returns the minimum priority. + /// \pre The heap must be non-empty. + Prio prio() const { return _data[_minimum].prio; } + + /// \brief Remove the item having minimum priority. + /// + /// This function removes the item having minimum priority. + /// \pre The heap must be non-empty. + void pop() { + /*The first case is that there are only one root.*/ + if ( _data[_minimum].left_neighbor==_minimum ) { + _data[_minimum].in=false; + if ( _data[_minimum].degree!=0 ) { + makeRoot(_data[_minimum].child); + _minimum=_data[_minimum].child; + balance(); + } + } else { + int right=_data[_minimum].right_neighbor; + unlace(_minimum); + _data[_minimum].in=false; + if ( _data[_minimum].degree > 0 ) { + int left=_data[_minimum].left_neighbor; + int child=_data[_minimum].child; + int last_child=_data[child].left_neighbor; + + makeRoot(child); + + _data[left].right_neighbor=child; + _data[child].left_neighbor=left; + _data[right].left_neighbor=last_child; + _data[last_child].right_neighbor=right; + } + _minimum=right; + balance(); + } // the case where there are more roots + --_num; + } + + /// \brief Remove the given item from the heap. + /// + /// This function removes the given item from the heap if it is + /// already stored. + /// \param item The item to delete. + /// \pre \e item must be in the heap. + void erase (const Item& item) { + int i=_iim[item]; + + if ( i >= 0 && _data[i].in ) { + if ( _data[i].parent!=-1 ) { + int p=_data[i].parent; + cut(i,p); + cascade(p); + } + _minimum=i; //As if its prio would be -infinity + pop(); + } + } + + /// \brief The priority of the given item. + /// + /// This function returns the priority of the given item. + /// \param item The item. + /// \pre \e item must be in the heap. + Prio operator[](const Item& item) const { + return _data[_iim[item]].prio; + } + + /// \brief Set the priority of an item or insert it, if it is + /// not stored in the heap. + /// + /// This method sets the priority of the given item if it is + /// already stored in the heap. Otherwise it inserts the given + /// item into the heap with the given priority. + /// \param item The item. + /// \param prio The priority. + void set (const Item& item, const Prio& prio) { + int i=_iim[item]; + if ( i >= 0 && _data[i].in ) { + if ( _comp(prio, _data[i].prio) ) decrease(item, prio); + if ( _comp(_data[i].prio, prio) ) increase(item, prio); + } else push(item, prio); + } + + /// \brief Decrease the priority of an item to the given value. + /// + /// This function decreases the priority of an item to the given value. + /// \param item The item. + /// \param prio The priority. + /// \pre \e item must be stored in the heap with priority at least \e prio. + void decrease (const Item& item, const Prio& prio) { + int i=_iim[item]; + _data[i].prio=prio; + int p=_data[i].parent; + + if ( p!=-1 && _comp(prio, _data[p].prio) ) { + cut(i,p); + cascade(p); + } + if ( _comp(prio, _data[_minimum].prio) ) _minimum=i; + } + + /// \brief Increase the priority of an item to the given value. + /// + /// This function increases the priority of an item to the given value. + /// \param item The item. + /// \param prio The priority. + /// \pre \e item must be stored in the heap with priority at most \e prio. + void increase (const Item& item, const Prio& prio) { + erase(item); + push(item, prio); + } + + /// \brief Return the state of an item. + /// + /// This method returns \c PRE_HEAP if the given item has never + /// been in the heap, \c IN_HEAP if it is in the heap at the moment, + /// and \c POST_HEAP otherwise. + /// In the latter case it is possible that the item will get back + /// to the heap again. + /// \param item The item. + State state(const Item &item) const { + int i=_iim[item]; + if( i>=0 ) { + if ( _data[i].in ) i=0; + else i=-2; + } + return State(i); + } + + /// \brief Set the state of an item in the heap. + /// + /// This function sets the state of the given item in the heap. + /// It can be used to manually clear the heap when it is important + /// to achive better time complexity. + /// \param i The item. + /// \param st The state. It should not be \c IN_HEAP. + void state(const Item& i, State st) { + switch (st) { + case POST_HEAP: + case PRE_HEAP: + if (state(i) == IN_HEAP) { + erase(i); + } + _iim[i] = st; + break; + case IN_HEAP: + break; + } + } + + private: + + void balance() { + + int maxdeg=int( std::floor( 2.08*log(double(_data.size()))))+1; + + std::vector A(maxdeg,-1); + + /* + *Recall that now minimum does not point to the minimum prio element. + *We set minimum to this during balance(). + */ + int anchor=_data[_minimum].left_neighbor; + int next=_minimum; + bool end=false; + + do { + int active=next; + if ( anchor==active ) end=true; + int d=_data[active].degree; + next=_data[active].right_neighbor; + + while (A[d]!=-1) { + if( _comp(_data[active].prio, _data[A[d]].prio) ) { + fuse(active,A[d]); + } else { + fuse(A[d],active); + active=A[d]; + } + A[d]=-1; + ++d; + } + A[d]=active; + } while ( !end ); + + + while ( _data[_minimum].parent >=0 ) + _minimum=_data[_minimum].parent; + int s=_minimum; + int m=_minimum; + do { + if ( _comp(_data[s].prio, _data[_minimum].prio) ) _minimum=s; + s=_data[s].right_neighbor; + } while ( s != m ); + } + + void makeRoot(int c) { + int s=c; + do { + _data[s].parent=-1; + s=_data[s].right_neighbor; + } while ( s != c ); + } + + void cut(int a, int b) { + /* + *Replacing a from the children of b. + */ + --_data[b].degree; + + if ( _data[b].degree !=0 ) { + int child=_data[b].child; + if ( child==a ) + _data[b].child=_data[child].right_neighbor; + unlace(a); + } + + + /*Lacing a to the roots.*/ + int right=_data[_minimum].right_neighbor; + _data[_minimum].right_neighbor=a; + _data[a].left_neighbor=_minimum; + _data[a].right_neighbor=right; + _data[right].left_neighbor=a; + + _data[a].parent=-1; + _data[a].marked=false; + } + + void cascade(int a) { + if ( _data[a].parent!=-1 ) { + int p=_data[a].parent; + + if ( _data[a].marked==false ) _data[a].marked=true; + else { + cut(a,p); + cascade(p); + } + } + } + + void fuse(int a, int b) { + unlace(b); + + /*Lacing b under a.*/ + _data[b].parent=a; + + if (_data[a].degree==0) { + _data[b].left_neighbor=b; + _data[b].right_neighbor=b; + _data[a].child=b; + } else { + int child=_data[a].child; + int last_child=_data[child].left_neighbor; + _data[child].left_neighbor=b; + _data[b].right_neighbor=child; + _data[last_child].right_neighbor=b; + _data[b].left_neighbor=last_child; + } + + ++_data[a].degree; + + _data[b].marked=false; + } + + /* + *It is invoked only if a has siblings. + */ + void unlace(int a) { + int leftn=_data[a].left_neighbor; + int rightn=_data[a].right_neighbor; + _data[leftn].right_neighbor=rightn; + _data[rightn].left_neighbor=leftn; + } + + + class Store { + friend class FibHeap; + + Item name; + int parent; + int left_neighbor; + int right_neighbor; + int child; + int degree; + bool marked; + bool in; + Prio prio; + + Store() : parent(-1), child(-1), degree(), marked(false), in(true) {} + }; + }; + +} //namespace lemon + +#endif //LEMON_FIB_HEAP_H + diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/fractional_matching.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/fractional_matching.h new file mode 100644 index 00000000000..7448f411d93 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/fractional_matching.h @@ -0,0 +1,2139 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_FRACTIONAL_MATCHING_H +#define LEMON_FRACTIONAL_MATCHING_H + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +///\ingroup matching +///\file +///\brief Fractional matching algorithms in general graphs. + +namespace lemon { + + /// \brief Default traits class of MaxFractionalMatching class. + /// + /// Default traits class of MaxFractionalMatching class. + /// \tparam GR Graph type. + template + struct MaxFractionalMatchingDefaultTraits { + + /// \brief The type of the graph the algorithm runs on. + typedef GR Graph; + + /// \brief The type of the map that stores the matching. + /// + /// The type of the map that stores the matching arcs. + /// It must meet the \ref concepts::ReadWriteMap "ReadWriteMap" concept. + typedef typename Graph::template NodeMap MatchingMap; + + /// \brief Instantiates a MatchingMap. + /// + /// This function instantiates a \ref MatchingMap. + /// \param graph The graph for which we would like to define + /// the matching map. + static MatchingMap* createMatchingMap(const Graph& graph) { + return new MatchingMap(graph); + } + + /// \brief The elevator type used by MaxFractionalMatching algorithm. + /// + /// The elevator type used by MaxFractionalMatching algorithm. + /// + /// \sa Elevator + /// \sa LinkedElevator + typedef LinkedElevator Elevator; + + /// \brief Instantiates an Elevator. + /// + /// This function instantiates an \ref Elevator. + /// \param graph The graph for which we would like to define + /// the elevator. + /// \param max_level The maximum level of the elevator. + static Elevator* createElevator(const Graph& graph, int max_level) { + return new Elevator(graph, max_level); + } + }; + + /// \ingroup matching + /// + /// \brief Max cardinality fractional matching + /// + /// This class provides an implementation of fractional matching + /// algorithm based on push-relabel principle. + /// + /// The maximum cardinality fractional matching is a relaxation of the + /// maximum cardinality matching problem where the odd set constraints + /// are omitted. + /// It can be formulated with the following linear program. + /// \f[ \sum_{e \in \delta(u)}x_e \le 1 \quad \forall u\in V\f] + /// \f[x_e \ge 0\quad \forall e\in E\f] + /// \f[\max \sum_{e\in E}x_e\f] + /// where \f$\delta(X)\f$ is the set of edges incident to a node in + /// \f$X\f$. The result can be represented as the union of a + /// matching with one value edges and a set of odd length cycles + /// with half value edges. + /// + /// The algorithm calculates an optimal fractional matching and a + /// barrier. The number of adjacents of any node set minus the size + /// of node set is a lower bound on the uncovered nodes in the + /// graph. For maximum matching a barrier is computed which + /// maximizes this difference. + /// + /// The algorithm can be executed with the run() function. After it + /// the matching (the primal solution) and the barrier (the dual + /// solution) can be obtained using the query functions. + /// + /// The primal solution is multiplied by + /// \ref MaxFractionalMatching::primalScale "2". + /// + /// \tparam GR The undirected graph type the algorithm runs on. +#ifdef DOXYGEN + template +#else + template > +#endif + class MaxFractionalMatching { + public: + + /// \brief The \ref lemon::MaxFractionalMatchingDefaultTraits + /// "traits class" of the algorithm. + typedef TR Traits; + /// The type of the graph the algorithm runs on. + typedef typename TR::Graph Graph; + /// The type of the matching map. + typedef typename TR::MatchingMap MatchingMap; + /// The type of the elevator. + typedef typename TR::Elevator Elevator; + + /// \brief Scaling factor for primal solution + /// + /// Scaling factor for primal solution. + static const int primalScale = 2; + + private: + + const Graph &_graph; + int _node_num; + bool _allow_loops; + int _empty_level; + + TEMPLATE_GRAPH_TYPEDEFS(Graph); + + bool _local_matching; + MatchingMap *_matching; + + bool _local_level; + Elevator *_level; + + typedef typename Graph::template NodeMap InDegMap; + InDegMap *_indeg; + + void createStructures() { + _node_num = countNodes(_graph); + + if (!_matching) { + _local_matching = true; + _matching = Traits::createMatchingMap(_graph); + } + if (!_level) { + _local_level = true; + _level = Traits::createElevator(_graph, _node_num); + } + if (!_indeg) { + _indeg = new InDegMap(_graph); + } + } + + void destroyStructures() { + if (_local_matching) { + delete _matching; + } + if (_local_level) { + delete _level; + } + if (_indeg) { + delete _indeg; + } + } + + void postprocessing() { + for (NodeIt n(_graph); n != INVALID; ++n) { + if ((*_indeg)[n] != 0) continue; + _indeg->set(n, -1); + Node u = n; + while ((*_matching)[u] != INVALID) { + Node v = _graph.target((*_matching)[u]); + _indeg->set(v, -1); + Arc a = _graph.oppositeArc((*_matching)[u]); + u = _graph.target((*_matching)[v]); + _indeg->set(u, -1); + _matching->set(v, a); + } + } + + for (NodeIt n(_graph); n != INVALID; ++n) { + if ((*_indeg)[n] != 1) continue; + _indeg->set(n, -1); + + int num = 1; + Node u = _graph.target((*_matching)[n]); + while (u != n) { + _indeg->set(u, -1); + u = _graph.target((*_matching)[u]); + ++num; + } + if (num % 2 == 0 && num > 2) { + Arc prev = _graph.oppositeArc((*_matching)[n]); + Node v = _graph.target((*_matching)[n]); + u = _graph.target((*_matching)[v]); + _matching->set(v, prev); + while (u != n) { + prev = _graph.oppositeArc((*_matching)[u]); + v = _graph.target((*_matching)[u]); + u = _graph.target((*_matching)[v]); + _matching->set(v, prev); + } + } + } + } + + public: + + typedef MaxFractionalMatching Create; + + ///\name Named Template Parameters + + ///@{ + + template + struct SetMatchingMapTraits : public Traits { + typedef T MatchingMap; + static MatchingMap *createMatchingMap(const Graph&) { + LEMON_ASSERT(false, "MatchingMap is not initialized"); + return 0; // ignore warnings + } + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// MatchingMap type + /// + /// \ref named-templ-param "Named parameter" for setting MatchingMap + /// type. + template + struct SetMatchingMap + : public MaxFractionalMatching > { + typedef MaxFractionalMatching > Create; + }; + + template + struct SetElevatorTraits : public Traits { + typedef T Elevator; + static Elevator *createElevator(const Graph&, int) { + LEMON_ASSERT(false, "Elevator is not initialized"); + return 0; // ignore warnings + } + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// Elevator type + /// + /// \ref named-templ-param "Named parameter" for setting Elevator + /// type. If this named parameter is used, then an external + /// elevator object must be passed to the algorithm using the + /// \ref elevator(Elevator&) "elevator()" function before calling + /// \ref run() or \ref init(). + /// \sa SetStandardElevator + template + struct SetElevator + : public MaxFractionalMatching > { + typedef MaxFractionalMatching > Create; + }; + + template + struct SetStandardElevatorTraits : public Traits { + typedef T Elevator; + static Elevator *createElevator(const Graph& graph, int max_level) { + return new Elevator(graph, max_level); + } + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// Elevator type with automatic allocation + /// + /// \ref named-templ-param "Named parameter" for setting Elevator + /// type with automatic allocation. + /// The Elevator should have standard constructor interface to be + /// able to automatically created by the algorithm (i.e. the + /// graph and the maximum level should be passed to it). + /// However an external elevator object could also be passed to the + /// algorithm with the \ref elevator(Elevator&) "elevator()" function + /// before calling \ref run() or \ref init(). + /// \sa SetElevator + template + struct SetStandardElevator + : public MaxFractionalMatching > { + typedef MaxFractionalMatching > Create; + }; + + /// @} + + protected: + + MaxFractionalMatching() {} + + public: + + /// \brief Constructor + /// + /// Constructor. + /// + MaxFractionalMatching(const Graph &graph, bool allow_loops = true) + : _graph(graph), _allow_loops(allow_loops), + _local_matching(false), _matching(0), + _local_level(false), _level(0), _indeg(0) + {} + + ~MaxFractionalMatching() { + destroyStructures(); + } + + /// \brief Sets the matching map. + /// + /// Sets the matching map. + /// If you don't use this function before calling \ref run() or + /// \ref init(), an instance will be allocated automatically. + /// The destructor deallocates this automatically allocated map, + /// of course. + /// \return (*this) + MaxFractionalMatching& matchingMap(MatchingMap& map) { + if (_local_matching) { + delete _matching; + _local_matching = false; + } + _matching = ↦ + return *this; + } + + /// \brief Sets the elevator used by algorithm. + /// + /// Sets the elevator used by algorithm. + /// If you don't use this function before calling \ref run() or + /// \ref init(), an instance will be allocated automatically. + /// The destructor deallocates this automatically allocated elevator, + /// of course. + /// \return (*this) + MaxFractionalMatching& elevator(Elevator& elevator) { + if (_local_level) { + delete _level; + _local_level = false; + } + _level = &elevator; + return *this; + } + + /// \brief Returns a const reference to the elevator. + /// + /// Returns a const reference to the elevator. + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + const Elevator& elevator() const { + return *_level; + } + + /// \name Execution control + /// The simplest way to execute the algorithm is to use one of the + /// member functions called \c run(). \n + /// If you need more control on the execution, first + /// you must call \ref init() and then one variant of the start() + /// member. + + /// @{ + + /// \brief Initializes the internal data structures. + /// + /// Initializes the internal data structures and sets the initial + /// matching. + void init() { + createStructures(); + + _level->initStart(); + for (NodeIt n(_graph); n != INVALID; ++n) { + _indeg->set(n, 0); + _matching->set(n, INVALID); + _level->initAddItem(n); + } + _level->initFinish(); + + _empty_level = _node_num; + for (NodeIt n(_graph); n != INVALID; ++n) { + for (OutArcIt a(_graph, n); a != INVALID; ++a) { + if (_graph.target(a) == n && !_allow_loops) continue; + _matching->set(n, a); + Node v = _graph.target((*_matching)[n]); + _indeg->set(v, (*_indeg)[v] + 1); + break; + } + } + + for (NodeIt n(_graph); n != INVALID; ++n) { + if ((*_indeg)[n] == 0) { + _level->activate(n); + } + } + } + + /// \brief Starts the algorithm and computes a fractional matching + /// + /// The algorithm computes a maximum fractional matching. + /// + /// \param postprocess The algorithm computes first a matching + /// which is a union of a matching with one value edges, cycles + /// with half value edges and even length paths with half value + /// edges. If the parameter is true, then after the push-relabel + /// algorithm it postprocesses the matching to contain only + /// matching edges and half value odd cycles. + void start(bool postprocess = true) { + Node n; + while ((n = _level->highestActive()) != INVALID) { + int level = _level->highestActiveLevel(); + int new_level = _level->maxLevel(); + for (InArcIt a(_graph, n); a != INVALID; ++a) { + Node u = _graph.source(a); + if (n == u && !_allow_loops) continue; + Node v = _graph.target((*_matching)[u]); + if ((*_level)[v] < level) { + _indeg->set(v, (*_indeg)[v] - 1); + if ((*_indeg)[v] == 0) { + _level->activate(v); + } + _matching->set(u, a); + _indeg->set(n, (*_indeg)[n] + 1); + _level->deactivate(n); + goto no_more_push; + } else if (new_level > (*_level)[v]) { + new_level = (*_level)[v]; + } + } + + if (new_level + 1 < _level->maxLevel()) { + _level->liftHighestActive(new_level + 1); + } else { + _level->liftHighestActiveToTop(); + } + if (_level->emptyLevel(level)) { + _level->liftToTop(level); + } + no_more_push: + ; + } + for (NodeIt n(_graph); n != INVALID; ++n) { + if ((*_matching)[n] == INVALID) continue; + Node u = _graph.target((*_matching)[n]); + if ((*_indeg)[u] > 1) { + _indeg->set(u, (*_indeg)[u] - 1); + _matching->set(n, INVALID); + } + } + if (postprocess) { + postprocessing(); + } + } + + /// \brief Starts the algorithm and computes a perfect fractional + /// matching + /// + /// The algorithm computes a perfect fractional matching. If it + /// does not exists, then the algorithm returns false and the + /// matching is undefined and the barrier. + /// + /// \param postprocess The algorithm computes first a matching + /// which is a union of a matching with one value edges, cycles + /// with half value edges and even length paths with half value + /// edges. If the parameter is true, then after the push-relabel + /// algorithm it postprocesses the matching to contain only + /// matching edges and half value odd cycles. + bool startPerfect(bool postprocess = true) { + Node n; + while ((n = _level->highestActive()) != INVALID) { + int level = _level->highestActiveLevel(); + int new_level = _level->maxLevel(); + for (InArcIt a(_graph, n); a != INVALID; ++a) { + Node u = _graph.source(a); + if (n == u && !_allow_loops) continue; + Node v = _graph.target((*_matching)[u]); + if ((*_level)[v] < level) { + _indeg->set(v, (*_indeg)[v] - 1); + if ((*_indeg)[v] == 0) { + _level->activate(v); + } + _matching->set(u, a); + _indeg->set(n, (*_indeg)[n] + 1); + _level->deactivate(n); + goto no_more_push; + } else if (new_level > (*_level)[v]) { + new_level = (*_level)[v]; + } + } + + if (new_level + 1 < _level->maxLevel()) { + _level->liftHighestActive(new_level + 1); + } else { + _level->liftHighestActiveToTop(); + _empty_level = _level->maxLevel() - 1; + return false; + } + if (_level->emptyLevel(level)) { + _level->liftToTop(level); + _empty_level = level; + return false; + } + no_more_push: + ; + } + if (postprocess) { + postprocessing(); + } + return true; + } + + /// \brief Runs the algorithm + /// + /// Just a shortcut for the next code: + ///\code + /// init(); + /// start(); + ///\endcode + void run(bool postprocess = true) { + init(); + start(postprocess); + } + + /// \brief Runs the algorithm to find a perfect fractional matching + /// + /// Just a shortcut for the next code: + ///\code + /// init(); + /// startPerfect(); + ///\endcode + bool runPerfect(bool postprocess = true) { + init(); + return startPerfect(postprocess); + } + + ///@} + + /// \name Query Functions + /// The result of the %Matching algorithm can be obtained using these + /// functions.\n + /// Before the use of these functions, + /// either run() or start() must be called. + ///@{ + + + /// \brief Return the number of covered nodes in the matching. + /// + /// This function returns the number of covered nodes in the matching. + /// + /// \pre Either run() or start() must be called before using this function. + int matchingSize() const { + int num = 0; + for (NodeIt n(_graph); n != INVALID; ++n) { + if ((*_matching)[n] != INVALID) { + ++num; + } + } + return num; + } + + /// \brief Returns a const reference to the matching map. + /// + /// Returns a const reference to the node map storing the found + /// fractional matching. This method can be called after + /// running the algorithm. + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + const MatchingMap& matchingMap() const { + return *_matching; + } + + /// \brief Return \c true if the given edge is in the matching. + /// + /// This function returns \c true if the given edge is in the + /// found matching. The result is scaled by \ref primalScale + /// "primal scale". + /// + /// \pre Either run() or start() must be called before using this function. + int matching(const Edge& edge) const { + return (edge == (*_matching)[_graph.u(edge)] ? 1 : 0) + + (edge == (*_matching)[_graph.v(edge)] ? 1 : 0); + } + + /// \brief Return the fractional matching arc (or edge) incident + /// to the given node. + /// + /// This function returns one of the fractional matching arc (or + /// edge) incident to the given node in the found matching or \c + /// INVALID if the node is not covered by the matching or if the + /// node is on an odd length cycle then it is the successor edge + /// on the cycle. + /// + /// \pre Either run() or start() must be called before using this function. + Arc matching(const Node& node) const { + return (*_matching)[node]; + } + + /// \brief Returns true if the node is in the barrier + /// + /// The barrier is a subset of the nodes. If the nodes in the + /// barrier have less adjacent nodes than the size of the barrier, + /// then at least as much nodes cannot be covered as the + /// difference of the two subsets. + bool barrier(const Node& node) const { + return (*_level)[node] >= _empty_level; + } + + /// @} + + }; + + /// \ingroup matching + /// + /// \brief Weighted fractional matching in general graphs + /// + /// This class provides an efficient implementation of fractional + /// matching algorithm. The implementation uses priority queues and + /// provides \f$O(nm\log n)\f$ time complexity. + /// + /// The maximum weighted fractional matching is a relaxation of the + /// maximum weighted matching problem where the odd set constraints + /// are omitted. + /// It can be formulated with the following linear program. + /// \f[ \sum_{e \in \delta(u)}x_e \le 1 \quad \forall u\in V\f] + /// \f[x_e \ge 0\quad \forall e\in E\f] + /// \f[\max \sum_{e\in E}x_ew_e\f] + /// where \f$\delta(X)\f$ is the set of edges incident to a node in + /// \f$X\f$. The result must be the union of a matching with one + /// value edges and a set of odd length cycles with half value edges. + /// + /// The algorithm calculates an optimal fractional matching and a + /// proof of the optimality. The solution of the dual problem can be + /// used to check the result of the algorithm. The dual linear + /// problem is the following. + /// \f[ y_u + y_v \ge w_{uv} \quad \forall uv\in E\f] + /// \f[y_u \ge 0 \quad \forall u \in V\f] + /// \f[\min \sum_{u \in V}y_u \f] + /// + /// The algorithm can be executed with the run() function. + /// After it the matching (the primal solution) and the dual solution + /// can be obtained using the query functions. + /// + /// The primal solution is multiplied by + /// \ref MaxWeightedFractionalMatching::primalScale "2". + /// If the value type is integer, then the dual + /// solution is scaled by + /// \ref MaxWeightedFractionalMatching::dualScale "4". + /// + /// \tparam GR The undirected graph type the algorithm runs on. + /// \tparam WM The type edge weight map. The default type is + /// \ref concepts::Graph::EdgeMap "GR::EdgeMap". +#ifdef DOXYGEN + template +#else + template > +#endif + class MaxWeightedFractionalMatching { + public: + + /// The graph type of the algorithm + typedef GR Graph; + /// The type of the edge weight map + typedef WM WeightMap; + /// The value type of the edge weights + typedef typename WeightMap::Value Value; + + /// The type of the matching map + typedef typename Graph::template NodeMap + MatchingMap; + + /// \brief Scaling factor for primal solution + /// + /// Scaling factor for primal solution. + static const int primalScale = 2; + + /// \brief Scaling factor for dual solution + /// + /// Scaling factor for dual solution. It is equal to 4 or 1 + /// according to the value type. + static const int dualScale = + std::numeric_limits::is_integer ? 4 : 1; + + private: + + TEMPLATE_GRAPH_TYPEDEFS(Graph); + + typedef typename Graph::template NodeMap NodePotential; + + const Graph& _graph; + const WeightMap& _weight; + + MatchingMap* _matching; + NodePotential* _node_potential; + + int _node_num; + bool _allow_loops; + + enum Status { + EVEN = -1, MATCHED = 0, ODD = 1 + }; + + typedef typename Graph::template NodeMap StatusMap; + StatusMap* _status; + + typedef typename Graph::template NodeMap PredMap; + PredMap* _pred; + + typedef ExtendFindEnum TreeSet; + + IntNodeMap *_tree_set_index; + TreeSet *_tree_set; + + IntNodeMap *_delta1_index; + BinHeap *_delta1; + + IntNodeMap *_delta2_index; + BinHeap *_delta2; + + IntEdgeMap *_delta3_index; + BinHeap *_delta3; + + Value _delta_sum; + + void createStructures() { + _node_num = countNodes(_graph); + + if (!_matching) { + _matching = new MatchingMap(_graph); + } + if (!_node_potential) { + _node_potential = new NodePotential(_graph); + } + if (!_status) { + _status = new StatusMap(_graph); + } + if (!_pred) { + _pred = new PredMap(_graph); + } + if (!_tree_set) { + _tree_set_index = new IntNodeMap(_graph); + _tree_set = new TreeSet(*_tree_set_index); + } + if (!_delta1) { + _delta1_index = new IntNodeMap(_graph); + _delta1 = new BinHeap(*_delta1_index); + } + if (!_delta2) { + _delta2_index = new IntNodeMap(_graph); + _delta2 = new BinHeap(*_delta2_index); + } + if (!_delta3) { + _delta3_index = new IntEdgeMap(_graph); + _delta3 = new BinHeap(*_delta3_index); + } + } + + void destroyStructures() { + if (_matching) { + delete _matching; + } + if (_node_potential) { + delete _node_potential; + } + if (_status) { + delete _status; + } + if (_pred) { + delete _pred; + } + if (_tree_set) { + delete _tree_set_index; + delete _tree_set; + } + if (_delta1) { + delete _delta1_index; + delete _delta1; + } + if (_delta2) { + delete _delta2_index; + delete _delta2; + } + if (_delta3) { + delete _delta3_index; + delete _delta3; + } + } + + void matchedToEven(Node node, int tree) { + _tree_set->insert(node, tree); + _node_potential->set(node, (*_node_potential)[node] + _delta_sum); + _delta1->push(node, (*_node_potential)[node]); + + if (_delta2->state(node) == _delta2->IN_HEAP) { + _delta2->erase(node); + } + + for (InArcIt a(_graph, node); a != INVALID; ++a) { + Node v = _graph.source(a); + Value rw = (*_node_potential)[node] + (*_node_potential)[v] - + dualScale * _weight[a]; + if (node == v) { + if (_allow_loops && _graph.direction(a)) { + _delta3->push(a, rw / 2); + } + } else if ((*_status)[v] == EVEN) { + _delta3->push(a, rw / 2); + } else if ((*_status)[v] == MATCHED) { + if (_delta2->state(v) != _delta2->IN_HEAP) { + _pred->set(v, a); + _delta2->push(v, rw); + } else if ((*_delta2)[v] > rw) { + _pred->set(v, a); + _delta2->decrease(v, rw); + } + } + } + } + + void matchedToOdd(Node node, int tree) { + _tree_set->insert(node, tree); + _node_potential->set(node, (*_node_potential)[node] - _delta_sum); + + if (_delta2->state(node) == _delta2->IN_HEAP) { + _delta2->erase(node); + } + } + + void evenToMatched(Node node, int tree) { + _delta1->erase(node); + _node_potential->set(node, (*_node_potential)[node] - _delta_sum); + Arc min = INVALID; + Value minrw = std::numeric_limits::max(); + for (InArcIt a(_graph, node); a != INVALID; ++a) { + Node v = _graph.source(a); + Value rw = (*_node_potential)[node] + (*_node_potential)[v] - + dualScale * _weight[a]; + + if (node == v) { + if (_allow_loops && _graph.direction(a)) { + _delta3->erase(a); + } + } else if ((*_status)[v] == EVEN) { + _delta3->erase(a); + if (minrw > rw) { + min = _graph.oppositeArc(a); + minrw = rw; + } + } else if ((*_status)[v] == MATCHED) { + if ((*_pred)[v] == a) { + Arc mina = INVALID; + Value minrwa = std::numeric_limits::max(); + for (OutArcIt aa(_graph, v); aa != INVALID; ++aa) { + Node va = _graph.target(aa); + if ((*_status)[va] != EVEN || + _tree_set->find(va) == tree) continue; + Value rwa = (*_node_potential)[v] + (*_node_potential)[va] - + dualScale * _weight[aa]; + if (minrwa > rwa) { + minrwa = rwa; + mina = aa; + } + } + if (mina != INVALID) { + _pred->set(v, mina); + _delta2->increase(v, minrwa); + } else { + _pred->set(v, INVALID); + _delta2->erase(v); + } + } + } + } + if (min != INVALID) { + _pred->set(node, min); + _delta2->push(node, minrw); + } else { + _pred->set(node, INVALID); + } + } + + void oddToMatched(Node node) { + _node_potential->set(node, (*_node_potential)[node] + _delta_sum); + Arc min = INVALID; + Value minrw = std::numeric_limits::max(); + for (InArcIt a(_graph, node); a != INVALID; ++a) { + Node v = _graph.source(a); + if ((*_status)[v] != EVEN) continue; + Value rw = (*_node_potential)[node] + (*_node_potential)[v] - + dualScale * _weight[a]; + + if (minrw > rw) { + min = _graph.oppositeArc(a); + minrw = rw; + } + } + if (min != INVALID) { + _pred->set(node, min); + _delta2->push(node, minrw); + } else { + _pred->set(node, INVALID); + } + } + + void alternatePath(Node even, int tree) { + Node odd; + + _status->set(even, MATCHED); + evenToMatched(even, tree); + + Arc prev = (*_matching)[even]; + while (prev != INVALID) { + odd = _graph.target(prev); + even = _graph.target((*_pred)[odd]); + _matching->set(odd, (*_pred)[odd]); + _status->set(odd, MATCHED); + oddToMatched(odd); + + prev = (*_matching)[even]; + _status->set(even, MATCHED); + _matching->set(even, _graph.oppositeArc((*_matching)[odd])); + evenToMatched(even, tree); + } + } + + void destroyTree(int tree) { + for (typename TreeSet::ItemIt n(*_tree_set, tree); n != INVALID; ++n) { + if ((*_status)[n] == EVEN) { + _status->set(n, MATCHED); + evenToMatched(n, tree); + } else if ((*_status)[n] == ODD) { + _status->set(n, MATCHED); + oddToMatched(n); + } + } + _tree_set->eraseClass(tree); + } + + + void unmatchNode(const Node& node) { + int tree = _tree_set->find(node); + + alternatePath(node, tree); + destroyTree(tree); + + _matching->set(node, INVALID); + } + + + void augmentOnEdge(const Edge& edge) { + Node left = _graph.u(edge); + int left_tree = _tree_set->find(left); + + alternatePath(left, left_tree); + destroyTree(left_tree); + _matching->set(left, _graph.direct(edge, true)); + + Node right = _graph.v(edge); + int right_tree = _tree_set->find(right); + + alternatePath(right, right_tree); + destroyTree(right_tree); + _matching->set(right, _graph.direct(edge, false)); + } + + void augmentOnArc(const Arc& arc) { + Node left = _graph.source(arc); + _status->set(left, MATCHED); + _matching->set(left, arc); + _pred->set(left, arc); + + Node right = _graph.target(arc); + int right_tree = _tree_set->find(right); + + alternatePath(right, right_tree); + destroyTree(right_tree); + _matching->set(right, _graph.oppositeArc(arc)); + } + + void extendOnArc(const Arc& arc) { + Node base = _graph.target(arc); + int tree = _tree_set->find(base); + + Node odd = _graph.source(arc); + _tree_set->insert(odd, tree); + _status->set(odd, ODD); + matchedToOdd(odd, tree); + _pred->set(odd, arc); + + Node even = _graph.target((*_matching)[odd]); + _tree_set->insert(even, tree); + _status->set(even, EVEN); + matchedToEven(even, tree); + } + + void cycleOnEdge(const Edge& edge, int tree) { + Node nca = INVALID; + std::vector left_path, right_path; + + { + std::set left_set, right_set; + Node left = _graph.u(edge); + left_path.push_back(left); + left_set.insert(left); + + Node right = _graph.v(edge); + right_path.push_back(right); + right_set.insert(right); + + while (true) { + + if (left_set.find(right) != left_set.end()) { + nca = right; + break; + } + + if ((*_matching)[left] == INVALID) break; + + left = _graph.target((*_matching)[left]); + left_path.push_back(left); + left = _graph.target((*_pred)[left]); + left_path.push_back(left); + + left_set.insert(left); + + if (right_set.find(left) != right_set.end()) { + nca = left; + break; + } + + if ((*_matching)[right] == INVALID) break; + + right = _graph.target((*_matching)[right]); + right_path.push_back(right); + right = _graph.target((*_pred)[right]); + right_path.push_back(right); + + right_set.insert(right); + + } + + if (nca == INVALID) { + if ((*_matching)[left] == INVALID) { + nca = right; + while (left_set.find(nca) == left_set.end()) { + nca = _graph.target((*_matching)[nca]); + right_path.push_back(nca); + nca = _graph.target((*_pred)[nca]); + right_path.push_back(nca); + } + } else { + nca = left; + while (right_set.find(nca) == right_set.end()) { + nca = _graph.target((*_matching)[nca]); + left_path.push_back(nca); + nca = _graph.target((*_pred)[nca]); + left_path.push_back(nca); + } + } + } + } + + alternatePath(nca, tree); + Arc prev; + + prev = _graph.direct(edge, true); + for (int i = 0; left_path[i] != nca; i += 2) { + _matching->set(left_path[i], prev); + _status->set(left_path[i], MATCHED); + evenToMatched(left_path[i], tree); + + prev = _graph.oppositeArc((*_pred)[left_path[i + 1]]); + _status->set(left_path[i + 1], MATCHED); + oddToMatched(left_path[i + 1]); + } + _matching->set(nca, prev); + + for (int i = 0; right_path[i] != nca; i += 2) { + _status->set(right_path[i], MATCHED); + evenToMatched(right_path[i], tree); + + _matching->set(right_path[i + 1], (*_pred)[right_path[i + 1]]); + _status->set(right_path[i + 1], MATCHED); + oddToMatched(right_path[i + 1]); + } + + destroyTree(tree); + } + + void extractCycle(const Arc &arc) { + Node left = _graph.source(arc); + Node odd = _graph.target((*_matching)[left]); + Arc prev; + while (odd != left) { + Node even = _graph.target((*_matching)[odd]); + prev = (*_matching)[odd]; + odd = _graph.target((*_matching)[even]); + _matching->set(even, _graph.oppositeArc(prev)); + } + _matching->set(left, arc); + + Node right = _graph.target(arc); + int right_tree = _tree_set->find(right); + alternatePath(right, right_tree); + destroyTree(right_tree); + _matching->set(right, _graph.oppositeArc(arc)); + } + + public: + + /// \brief Constructor + /// + /// Constructor. + MaxWeightedFractionalMatching(const Graph& graph, const WeightMap& weight, + bool allow_loops = true) + : _graph(graph), _weight(weight), _matching(0), + _node_potential(0), _node_num(0), _allow_loops(allow_loops), + _status(0), _pred(0), + _tree_set_index(0), _tree_set(0), + + _delta1_index(0), _delta1(0), + _delta2_index(0), _delta2(0), + _delta3_index(0), _delta3(0), + + _delta_sum() {} + + ~MaxWeightedFractionalMatching() { + destroyStructures(); + } + + /// \name Execution Control + /// The simplest way to execute the algorithm is to use the + /// \ref run() member function. + + ///@{ + + /// \brief Initialize the algorithm + /// + /// This function initializes the algorithm. + void init() { + createStructures(); + + for (NodeIt n(_graph); n != INVALID; ++n) { + (*_delta1_index)[n] = _delta1->PRE_HEAP; + (*_delta2_index)[n] = _delta2->PRE_HEAP; + } + for (EdgeIt e(_graph); e != INVALID; ++e) { + (*_delta3_index)[e] = _delta3->PRE_HEAP; + } + + _delta1->clear(); + _delta2->clear(); + _delta3->clear(); + _tree_set->clear(); + + for (NodeIt n(_graph); n != INVALID; ++n) { + Value max = 0; + for (OutArcIt e(_graph, n); e != INVALID; ++e) { + if (_graph.target(e) == n && !_allow_loops) continue; + if ((dualScale * _weight[e]) / 2 > max) { + max = (dualScale * _weight[e]) / 2; + } + } + _node_potential->set(n, max); + _delta1->push(n, max); + + _tree_set->insert(n); + + _matching->set(n, INVALID); + _status->set(n, EVEN); + } + + for (EdgeIt e(_graph); e != INVALID; ++e) { + Node left = _graph.u(e); + Node right = _graph.v(e); + if (left == right && !_allow_loops) continue; + _delta3->push(e, ((*_node_potential)[left] + + (*_node_potential)[right] - + dualScale * _weight[e]) / 2); + } + } + + /// \brief Start the algorithm + /// + /// This function starts the algorithm. + /// + /// \pre \ref init() must be called before using this function. + void start() { + enum OpType { + D1, D2, D3 + }; + + int unmatched = _node_num; + while (unmatched > 0) { + Value d1 = !_delta1->empty() ? + _delta1->prio() : std::numeric_limits::max(); + + Value d2 = !_delta2->empty() ? + _delta2->prio() : std::numeric_limits::max(); + + Value d3 = !_delta3->empty() ? + _delta3->prio() : std::numeric_limits::max(); + + _delta_sum = d3; OpType ot = D3; + if (d1 < _delta_sum) { _delta_sum = d1; ot = D1; } + if (d2 < _delta_sum) { _delta_sum = d2; ot = D2; } + + switch (ot) { + case D1: + { + Node n = _delta1->top(); + unmatchNode(n); + --unmatched; + } + break; + case D2: + { + Node n = _delta2->top(); + Arc a = (*_pred)[n]; + if ((*_matching)[n] == INVALID) { + augmentOnArc(a); + --unmatched; + } else { + Node v = _graph.target((*_matching)[n]); + if ((*_matching)[n] != + _graph.oppositeArc((*_matching)[v])) { + extractCycle(a); + --unmatched; + } else { + extendOnArc(a); + } + } + } break; + case D3: + { + Edge e = _delta3->top(); + + Node left = _graph.u(e); + Node right = _graph.v(e); + + int left_tree = _tree_set->find(left); + int right_tree = _tree_set->find(right); + + if (left_tree == right_tree) { + cycleOnEdge(e, left_tree); + --unmatched; + } else { + augmentOnEdge(e); + unmatched -= 2; + } + } break; + } + } + } + + /// \brief Run the algorithm. + /// + /// This method runs the \c %MaxWeightedFractionalMatching algorithm. + /// + /// \note mwfm.run() is just a shortcut of the following code. + /// \code + /// mwfm.init(); + /// mwfm.start(); + /// \endcode + void run() { + init(); + start(); + } + + /// @} + + /// \name Primal Solution + /// Functions to get the primal solution, i.e. the maximum weighted + /// matching.\n + /// Either \ref run() or \ref start() function should be called before + /// using them. + + /// @{ + + /// \brief Return the weight of the matching. + /// + /// This function returns the weight of the found matching. This + /// value is scaled by \ref primalScale "primal scale". + /// + /// \pre Either run() or start() must be called before using this function. + Value matchingWeight() const { + Value sum = 0; + for (NodeIt n(_graph); n != INVALID; ++n) { + if ((*_matching)[n] != INVALID) { + sum += _weight[(*_matching)[n]]; + } + } + return sum * primalScale / 2; + } + + /// \brief Return the number of covered nodes in the matching. + /// + /// This function returns the number of covered nodes in the matching. + /// + /// \pre Either run() or start() must be called before using this function. + int matchingSize() const { + int num = 0; + for (NodeIt n(_graph); n != INVALID; ++n) { + if ((*_matching)[n] != INVALID) { + ++num; + } + } + return num; + } + + /// \brief Return \c true if the given edge is in the matching. + /// + /// This function returns \c true if the given edge is in the + /// found matching. The result is scaled by \ref primalScale + /// "primal scale". + /// + /// \pre Either run() or start() must be called before using this function. + int matching(const Edge& edge) const { + return (edge == (*_matching)[_graph.u(edge)] ? 1 : 0) + + (edge == (*_matching)[_graph.v(edge)] ? 1 : 0); + } + + /// \brief Return the fractional matching arc (or edge) incident + /// to the given node. + /// + /// This function returns one of the fractional matching arc (or + /// edge) incident to the given node in the found matching or \c + /// INVALID if the node is not covered by the matching or if the + /// node is on an odd length cycle then it is the successor edge + /// on the cycle. + /// + /// \pre Either run() or start() must be called before using this function. + Arc matching(const Node& node) const { + return (*_matching)[node]; + } + + /// \brief Return a const reference to the matching map. + /// + /// This function returns a const reference to a node map that stores + /// the matching arc (or edge) incident to each node. + const MatchingMap& matchingMap() const { + return *_matching; + } + + /// @} + + /// \name Dual Solution + /// Functions to get the dual solution.\n + /// Either \ref run() or \ref start() function should be called before + /// using them. + + /// @{ + + /// \brief Return the value of the dual solution. + /// + /// This function returns the value of the dual solution. + /// It should be equal to the primal value scaled by \ref dualScale + /// "dual scale". + /// + /// \pre Either run() or start() must be called before using this function. + Value dualValue() const { + Value sum = 0; + for (NodeIt n(_graph); n != INVALID; ++n) { + sum += nodeValue(n); + } + return sum; + } + + /// \brief Return the dual value (potential) of the given node. + /// + /// This function returns the dual value (potential) of the given node. + /// + /// \pre Either run() or start() must be called before using this function. + Value nodeValue(const Node& n) const { + return (*_node_potential)[n]; + } + + /// @} + + }; + + /// \ingroup matching + /// + /// \brief Weighted fractional perfect matching in general graphs + /// + /// This class provides an efficient implementation of fractional + /// matching algorithm. The implementation uses priority queues and + /// provides \f$O(nm\log n)\f$ time complexity. + /// + /// The maximum weighted fractional perfect matching is a relaxation + /// of the maximum weighted perfect matching problem where the odd + /// set constraints are omitted. + /// It can be formulated with the following linear program. + /// \f[ \sum_{e \in \delta(u)}x_e = 1 \quad \forall u\in V\f] + /// \f[x_e \ge 0\quad \forall e\in E\f] + /// \f[\max \sum_{e\in E}x_ew_e\f] + /// where \f$\delta(X)\f$ is the set of edges incident to a node in + /// \f$X\f$. The result must be the union of a matching with one + /// value edges and a set of odd length cycles with half value edges. + /// + /// The algorithm calculates an optimal fractional matching and a + /// proof of the optimality. The solution of the dual problem can be + /// used to check the result of the algorithm. The dual linear + /// problem is the following. + /// \f[ y_u + y_v \ge w_{uv} \quad \forall uv\in E\f] + /// \f[\min \sum_{u \in V}y_u \f] + /// + /// The algorithm can be executed with the run() function. + /// After it the matching (the primal solution) and the dual solution + /// can be obtained using the query functions. + /// + /// The primal solution is multiplied by + /// \ref MaxWeightedPerfectFractionalMatching::primalScale "2". + /// If the value type is integer, then the dual + /// solution is scaled by + /// \ref MaxWeightedPerfectFractionalMatching::dualScale "4". + /// + /// \tparam GR The undirected graph type the algorithm runs on. + /// \tparam WM The type edge weight map. The default type is + /// \ref concepts::Graph::EdgeMap "GR::EdgeMap". +#ifdef DOXYGEN + template +#else + template > +#endif + class MaxWeightedPerfectFractionalMatching { + public: + + /// The graph type of the algorithm + typedef GR Graph; + /// The type of the edge weight map + typedef WM WeightMap; + /// The value type of the edge weights + typedef typename WeightMap::Value Value; + + /// The type of the matching map + typedef typename Graph::template NodeMap + MatchingMap; + + /// \brief Scaling factor for primal solution + /// + /// Scaling factor for primal solution. + static const int primalScale = 2; + + /// \brief Scaling factor for dual solution + /// + /// Scaling factor for dual solution. It is equal to 4 or 1 + /// according to the value type. + static const int dualScale = + std::numeric_limits::is_integer ? 4 : 1; + + private: + + TEMPLATE_GRAPH_TYPEDEFS(Graph); + + typedef typename Graph::template NodeMap NodePotential; + + const Graph& _graph; + const WeightMap& _weight; + + MatchingMap* _matching; + NodePotential* _node_potential; + + int _node_num; + bool _allow_loops; + + enum Status { + EVEN = -1, MATCHED = 0, ODD = 1 + }; + + typedef typename Graph::template NodeMap StatusMap; + StatusMap* _status; + + typedef typename Graph::template NodeMap PredMap; + PredMap* _pred; + + typedef ExtendFindEnum TreeSet; + + IntNodeMap *_tree_set_index; + TreeSet *_tree_set; + + IntNodeMap *_delta2_index; + BinHeap *_delta2; + + IntEdgeMap *_delta3_index; + BinHeap *_delta3; + + Value _delta_sum; + + void createStructures() { + _node_num = countNodes(_graph); + + if (!_matching) { + _matching = new MatchingMap(_graph); + } + if (!_node_potential) { + _node_potential = new NodePotential(_graph); + } + if (!_status) { + _status = new StatusMap(_graph); + } + if (!_pred) { + _pred = new PredMap(_graph); + } + if (!_tree_set) { + _tree_set_index = new IntNodeMap(_graph); + _tree_set = new TreeSet(*_tree_set_index); + } + if (!_delta2) { + _delta2_index = new IntNodeMap(_graph); + _delta2 = new BinHeap(*_delta2_index); + } + if (!_delta3) { + _delta3_index = new IntEdgeMap(_graph); + _delta3 = new BinHeap(*_delta3_index); + } + } + + void destroyStructures() { + if (_matching) { + delete _matching; + } + if (_node_potential) { + delete _node_potential; + } + if (_status) { + delete _status; + } + if (_pred) { + delete _pred; + } + if (_tree_set) { + delete _tree_set_index; + delete _tree_set; + } + if (_delta2) { + delete _delta2_index; + delete _delta2; + } + if (_delta3) { + delete _delta3_index; + delete _delta3; + } + } + + void matchedToEven(Node node, int tree) { + _tree_set->insert(node, tree); + _node_potential->set(node, (*_node_potential)[node] + _delta_sum); + + if (_delta2->state(node) == _delta2->IN_HEAP) { + _delta2->erase(node); + } + + for (InArcIt a(_graph, node); a != INVALID; ++a) { + Node v = _graph.source(a); + Value rw = (*_node_potential)[node] + (*_node_potential)[v] - + dualScale * _weight[a]; + if (node == v) { + if (_allow_loops && _graph.direction(a)) { + _delta3->push(a, rw / 2); + } + } else if ((*_status)[v] == EVEN) { + _delta3->push(a, rw / 2); + } else if ((*_status)[v] == MATCHED) { + if (_delta2->state(v) != _delta2->IN_HEAP) { + _pred->set(v, a); + _delta2->push(v, rw); + } else if ((*_delta2)[v] > rw) { + _pred->set(v, a); + _delta2->decrease(v, rw); + } + } + } + } + + void matchedToOdd(Node node, int tree) { + _tree_set->insert(node, tree); + _node_potential->set(node, (*_node_potential)[node] - _delta_sum); + + if (_delta2->state(node) == _delta2->IN_HEAP) { + _delta2->erase(node); + } + } + + void evenToMatched(Node node, int tree) { + _node_potential->set(node, (*_node_potential)[node] - _delta_sum); + Arc min = INVALID; + Value minrw = std::numeric_limits::max(); + for (InArcIt a(_graph, node); a != INVALID; ++a) { + Node v = _graph.source(a); + Value rw = (*_node_potential)[node] + (*_node_potential)[v] - + dualScale * _weight[a]; + + if (node == v) { + if (_allow_loops && _graph.direction(a)) { + _delta3->erase(a); + } + } else if ((*_status)[v] == EVEN) { + _delta3->erase(a); + if (minrw > rw) { + min = _graph.oppositeArc(a); + minrw = rw; + } + } else if ((*_status)[v] == MATCHED) { + if ((*_pred)[v] == a) { + Arc mina = INVALID; + Value minrwa = std::numeric_limits::max(); + for (OutArcIt aa(_graph, v); aa != INVALID; ++aa) { + Node va = _graph.target(aa); + if ((*_status)[va] != EVEN || + _tree_set->find(va) == tree) continue; + Value rwa = (*_node_potential)[v] + (*_node_potential)[va] - + dualScale * _weight[aa]; + if (minrwa > rwa) { + minrwa = rwa; + mina = aa; + } + } + if (mina != INVALID) { + _pred->set(v, mina); + _delta2->increase(v, minrwa); + } else { + _pred->set(v, INVALID); + _delta2->erase(v); + } + } + } + } + if (min != INVALID) { + _pred->set(node, min); + _delta2->push(node, minrw); + } else { + _pred->set(node, INVALID); + } + } + + void oddToMatched(Node node) { + _node_potential->set(node, (*_node_potential)[node] + _delta_sum); + Arc min = INVALID; + Value minrw = std::numeric_limits::max(); + for (InArcIt a(_graph, node); a != INVALID; ++a) { + Node v = _graph.source(a); + if ((*_status)[v] != EVEN) continue; + Value rw = (*_node_potential)[node] + (*_node_potential)[v] - + dualScale * _weight[a]; + + if (minrw > rw) { + min = _graph.oppositeArc(a); + minrw = rw; + } + } + if (min != INVALID) { + _pred->set(node, min); + _delta2->push(node, minrw); + } else { + _pred->set(node, INVALID); + } + } + + void alternatePath(Node even, int tree) { + Node odd; + + _status->set(even, MATCHED); + evenToMatched(even, tree); + + Arc prev = (*_matching)[even]; + while (prev != INVALID) { + odd = _graph.target(prev); + even = _graph.target((*_pred)[odd]); + _matching->set(odd, (*_pred)[odd]); + _status->set(odd, MATCHED); + oddToMatched(odd); + + prev = (*_matching)[even]; + _status->set(even, MATCHED); + _matching->set(even, _graph.oppositeArc((*_matching)[odd])); + evenToMatched(even, tree); + } + } + + void destroyTree(int tree) { + for (typename TreeSet::ItemIt n(*_tree_set, tree); n != INVALID; ++n) { + if ((*_status)[n] == EVEN) { + _status->set(n, MATCHED); + evenToMatched(n, tree); + } else if ((*_status)[n] == ODD) { + _status->set(n, MATCHED); + oddToMatched(n); + } + } + _tree_set->eraseClass(tree); + } + + void augmentOnEdge(const Edge& edge) { + Node left = _graph.u(edge); + int left_tree = _tree_set->find(left); + + alternatePath(left, left_tree); + destroyTree(left_tree); + _matching->set(left, _graph.direct(edge, true)); + + Node right = _graph.v(edge); + int right_tree = _tree_set->find(right); + + alternatePath(right, right_tree); + destroyTree(right_tree); + _matching->set(right, _graph.direct(edge, false)); + } + + void augmentOnArc(const Arc& arc) { + Node left = _graph.source(arc); + _status->set(left, MATCHED); + _matching->set(left, arc); + _pred->set(left, arc); + + Node right = _graph.target(arc); + int right_tree = _tree_set->find(right); + + alternatePath(right, right_tree); + destroyTree(right_tree); + _matching->set(right, _graph.oppositeArc(arc)); + } + + void extendOnArc(const Arc& arc) { + Node base = _graph.target(arc); + int tree = _tree_set->find(base); + + Node odd = _graph.source(arc); + _tree_set->insert(odd, tree); + _status->set(odd, ODD); + matchedToOdd(odd, tree); + _pred->set(odd, arc); + + Node even = _graph.target((*_matching)[odd]); + _tree_set->insert(even, tree); + _status->set(even, EVEN); + matchedToEven(even, tree); + } + + void cycleOnEdge(const Edge& edge, int tree) { + Node nca = INVALID; + std::vector left_path, right_path; + + { + std::set left_set, right_set; + Node left = _graph.u(edge); + left_path.push_back(left); + left_set.insert(left); + + Node right = _graph.v(edge); + right_path.push_back(right); + right_set.insert(right); + + while (true) { + + if (left_set.find(right) != left_set.end()) { + nca = right; + break; + } + + if ((*_matching)[left] == INVALID) break; + + left = _graph.target((*_matching)[left]); + left_path.push_back(left); + left = _graph.target((*_pred)[left]); + left_path.push_back(left); + + left_set.insert(left); + + if (right_set.find(left) != right_set.end()) { + nca = left; + break; + } + + if ((*_matching)[right] == INVALID) break; + + right = _graph.target((*_matching)[right]); + right_path.push_back(right); + right = _graph.target((*_pred)[right]); + right_path.push_back(right); + + right_set.insert(right); + + } + + if (nca == INVALID) { + if ((*_matching)[left] == INVALID) { + nca = right; + while (left_set.find(nca) == left_set.end()) { + nca = _graph.target((*_matching)[nca]); + right_path.push_back(nca); + nca = _graph.target((*_pred)[nca]); + right_path.push_back(nca); + } + } else { + nca = left; + while (right_set.find(nca) == right_set.end()) { + nca = _graph.target((*_matching)[nca]); + left_path.push_back(nca); + nca = _graph.target((*_pred)[nca]); + left_path.push_back(nca); + } + } + } + } + + alternatePath(nca, tree); + Arc prev; + + prev = _graph.direct(edge, true); + for (int i = 0; left_path[i] != nca; i += 2) { + _matching->set(left_path[i], prev); + _status->set(left_path[i], MATCHED); + evenToMatched(left_path[i], tree); + + prev = _graph.oppositeArc((*_pred)[left_path[i + 1]]); + _status->set(left_path[i + 1], MATCHED); + oddToMatched(left_path[i + 1]); + } + _matching->set(nca, prev); + + for (int i = 0; right_path[i] != nca; i += 2) { + _status->set(right_path[i], MATCHED); + evenToMatched(right_path[i], tree); + + _matching->set(right_path[i + 1], (*_pred)[right_path[i + 1]]); + _status->set(right_path[i + 1], MATCHED); + oddToMatched(right_path[i + 1]); + } + + destroyTree(tree); + } + + void extractCycle(const Arc &arc) { + Node left = _graph.source(arc); + Node odd = _graph.target((*_matching)[left]); + Arc prev; + while (odd != left) { + Node even = _graph.target((*_matching)[odd]); + prev = (*_matching)[odd]; + odd = _graph.target((*_matching)[even]); + _matching->set(even, _graph.oppositeArc(prev)); + } + _matching->set(left, arc); + + Node right = _graph.target(arc); + int right_tree = _tree_set->find(right); + alternatePath(right, right_tree); + destroyTree(right_tree); + _matching->set(right, _graph.oppositeArc(arc)); + } + + public: + + /// \brief Constructor + /// + /// Constructor. + MaxWeightedPerfectFractionalMatching(const Graph& graph, + const WeightMap& weight, + bool allow_loops = true) + : _graph(graph), _weight(weight), _matching(0), + _node_potential(0), _node_num(0), _allow_loops(allow_loops), + _status(0), _pred(0), + _tree_set_index(0), _tree_set(0), + + _delta2_index(0), _delta2(0), + _delta3_index(0), _delta3(0), + + _delta_sum() {} + + ~MaxWeightedPerfectFractionalMatching() { + destroyStructures(); + } + + /// \name Execution Control + /// The simplest way to execute the algorithm is to use the + /// \ref run() member function. + + ///@{ + + /// \brief Initialize the algorithm + /// + /// This function initializes the algorithm. + void init() { + createStructures(); + + for (NodeIt n(_graph); n != INVALID; ++n) { + (*_delta2_index)[n] = _delta2->PRE_HEAP; + } + for (EdgeIt e(_graph); e != INVALID; ++e) { + (*_delta3_index)[e] = _delta3->PRE_HEAP; + } + + _delta2->clear(); + _delta3->clear(); + _tree_set->clear(); + + for (NodeIt n(_graph); n != INVALID; ++n) { + Value max = - std::numeric_limits::max(); + for (OutArcIt e(_graph, n); e != INVALID; ++e) { + if (_graph.target(e) == n && !_allow_loops) continue; + if ((dualScale * _weight[e]) / 2 > max) { + max = (dualScale * _weight[e]) / 2; + } + } + _node_potential->set(n, max); + + _tree_set->insert(n); + + _matching->set(n, INVALID); + _status->set(n, EVEN); + } + + for (EdgeIt e(_graph); e != INVALID; ++e) { + Node left = _graph.u(e); + Node right = _graph.v(e); + if (left == right && !_allow_loops) continue; + _delta3->push(e, ((*_node_potential)[left] + + (*_node_potential)[right] - + dualScale * _weight[e]) / 2); + } + } + + /// \brief Start the algorithm + /// + /// This function starts the algorithm. + /// + /// \pre \ref init() must be called before using this function. + bool start() { + enum OpType { + D2, D3 + }; + + int unmatched = _node_num; + while (unmatched > 0) { + Value d2 = !_delta2->empty() ? + _delta2->prio() : std::numeric_limits::max(); + + Value d3 = !_delta3->empty() ? + _delta3->prio() : std::numeric_limits::max(); + + _delta_sum = d3; OpType ot = D3; + if (d2 < _delta_sum) { _delta_sum = d2; ot = D2; } + + if (_delta_sum == std::numeric_limits::max()) { + return false; + } + + switch (ot) { + case D2: + { + Node n = _delta2->top(); + Arc a = (*_pred)[n]; + if ((*_matching)[n] == INVALID) { + augmentOnArc(a); + --unmatched; + } else { + Node v = _graph.target((*_matching)[n]); + if ((*_matching)[n] != + _graph.oppositeArc((*_matching)[v])) { + extractCycle(a); + --unmatched; + } else { + extendOnArc(a); + } + } + } break; + case D3: + { + Edge e = _delta3->top(); + + Node left = _graph.u(e); + Node right = _graph.v(e); + + int left_tree = _tree_set->find(left); + int right_tree = _tree_set->find(right); + + if (left_tree == right_tree) { + cycleOnEdge(e, left_tree); + --unmatched; + } else { + augmentOnEdge(e); + unmatched -= 2; + } + } break; + } + } + return true; + } + + /// \brief Run the algorithm. + /// + /// This method runs the \c %MaxWeightedPerfectFractionalMatching + /// algorithm. + /// + /// \note mwfm.run() is just a shortcut of the following code. + /// \code + /// mwpfm.init(); + /// mwpfm.start(); + /// \endcode + bool run() { + init(); + return start(); + } + + /// @} + + /// \name Primal Solution + /// Functions to get the primal solution, i.e. the maximum weighted + /// matching.\n + /// Either \ref run() or \ref start() function should be called before + /// using them. + + /// @{ + + /// \brief Return the weight of the matching. + /// + /// This function returns the weight of the found matching. This + /// value is scaled by \ref primalScale "primal scale". + /// + /// \pre Either run() or start() must be called before using this function. + Value matchingWeight() const { + Value sum = 0; + for (NodeIt n(_graph); n != INVALID; ++n) { + if ((*_matching)[n] != INVALID) { + sum += _weight[(*_matching)[n]]; + } + } + return sum * primalScale / 2; + } + + /// \brief Return the number of covered nodes in the matching. + /// + /// This function returns the number of covered nodes in the matching. + /// + /// \pre Either run() or start() must be called before using this function. + int matchingSize() const { + int num = 0; + for (NodeIt n(_graph); n != INVALID; ++n) { + if ((*_matching)[n] != INVALID) { + ++num; + } + } + return num; + } + + /// \brief Return \c true if the given edge is in the matching. + /// + /// This function returns \c true if the given edge is in the + /// found matching. The result is scaled by \ref primalScale + /// "primal scale". + /// + /// \pre Either run() or start() must be called before using this function. + int matching(const Edge& edge) const { + return (edge == (*_matching)[_graph.u(edge)] ? 1 : 0) + + (edge == (*_matching)[_graph.v(edge)] ? 1 : 0); + } + + /// \brief Return the fractional matching arc (or edge) incident + /// to the given node. + /// + /// This function returns one of the fractional matching arc (or + /// edge) incident to the given node in the found matching or \c + /// INVALID if the node is not covered by the matching or if the + /// node is on an odd length cycle then it is the successor edge + /// on the cycle. + /// + /// \pre Either run() or start() must be called before using this function. + Arc matching(const Node& node) const { + return (*_matching)[node]; + } + + /// \brief Return a const reference to the matching map. + /// + /// This function returns a const reference to a node map that stores + /// the matching arc (or edge) incident to each node. + const MatchingMap& matchingMap() const { + return *_matching; + } + + /// @} + + /// \name Dual Solution + /// Functions to get the dual solution.\n + /// Either \ref run() or \ref start() function should be called before + /// using them. + + /// @{ + + /// \brief Return the value of the dual solution. + /// + /// This function returns the value of the dual solution. + /// It should be equal to the primal value scaled by \ref dualScale + /// "dual scale". + /// + /// \pre Either run() or start() must be called before using this function. + Value dualValue() const { + Value sum = 0; + for (NodeIt n(_graph); n != INVALID; ++n) { + sum += nodeValue(n); + } + return sum; + } + + /// \brief Return the dual value (potential) of the given node. + /// + /// This function returns the dual value (potential) of the given node. + /// + /// \pre Either run() or start() must be called before using this function. + Value nodeValue(const Node& n) const { + return (*_node_potential)[n]; + } + + /// @} + + }; + +} //END OF NAMESPACE LEMON + +#endif //LEMON_FRACTIONAL_MATCHING_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/full_graph.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/full_graph.h new file mode 100644 index 00000000000..b63df2e0746 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/full_graph.h @@ -0,0 +1,1082 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_FULL_GRAPH_H +#define LEMON_FULL_GRAPH_H + +#include +#include + +///\ingroup graphs +///\file +///\brief FullDigraph and FullGraph classes. + +namespace lemon { + + class FullDigraphBase { + public: + + typedef FullDigraphBase Digraph; + + class Node; + class Arc; + + protected: + + int _node_num; + int _arc_num; + + FullDigraphBase() {} + + void construct(int n) { _node_num = n; _arc_num = n * n; } + + public: + + typedef True NodeNumTag; + typedef True ArcNumTag; + + Node operator()(int ix) const { return Node(ix); } + static int index(const Node& node) { return node._id; } + + Arc arc(const Node& s, const Node& t) const { + return Arc(s._id * _node_num + t._id); + } + + int nodeNum() const { return _node_num; } + int arcNum() const { return _arc_num; } + + int maxNodeId() const { return _node_num - 1; } + int maxArcId() const { return _arc_num - 1; } + + Node source(Arc arc) const { return arc._id / _node_num; } + Node target(Arc arc) const { return arc._id % _node_num; } + + static int id(Node node) { return node._id; } + static int id(Arc arc) { return arc._id; } + + static Node nodeFromId(int id) { return Node(id);} + static Arc arcFromId(int id) { return Arc(id);} + + typedef True FindArcTag; + + Arc findArc(Node s, Node t, Arc prev = INVALID) const { + return prev == INVALID ? arc(s, t) : INVALID; + } + + class Node { + friend class FullDigraphBase; + + protected: + int _id; + Node(int id) : _id(id) {} + public: + Node() {} + Node (Invalid) : _id(-1) {} + bool operator==(const Node node) const {return _id == node._id;} + bool operator!=(const Node node) const {return _id != node._id;} + bool operator<(const Node node) const {return _id < node._id;} + }; + + class Arc { + friend class FullDigraphBase; + + protected: + int _id; // _node_num * source + target; + + Arc(int id) : _id(id) {} + + public: + Arc() { } + Arc (Invalid) { _id = -1; } + bool operator==(const Arc arc) const {return _id == arc._id;} + bool operator!=(const Arc arc) const {return _id != arc._id;} + bool operator<(const Arc arc) const {return _id < arc._id;} + }; + + void first(Node& node) const { + node._id = _node_num - 1; + } + + static void next(Node& node) { + --node._id; + } + + void first(Arc& arc) const { + arc._id = _arc_num - 1; + } + + static void next(Arc& arc) { + --arc._id; + } + + void firstOut(Arc& arc, const Node& node) const { + arc._id = (node._id + 1) * _node_num - 1; + } + + void nextOut(Arc& arc) const { + if (arc._id % _node_num == 0) arc._id = 0; + --arc._id; + } + + void firstIn(Arc& arc, const Node& node) const { + arc._id = _arc_num + node._id - _node_num; + } + + void nextIn(Arc& arc) const { + arc._id -= _node_num; + if (arc._id < 0) arc._id = -1; + } + + }; + + typedef DigraphExtender ExtendedFullDigraphBase; + + /// \ingroup graphs + /// + /// \brief A directed full graph class. + /// + /// FullDigraph is a simple and fast implmenetation of directed full + /// (complete) graphs. It contains an arc from each node to each node + /// (including a loop for each node), therefore the number of arcs + /// is the square of the number of nodes. + /// This class is completely static and it needs constant memory space. + /// Thus you can neither add nor delete nodes or arcs, however + /// the structure can be resized using resize(). + /// + /// This type fully conforms to the \ref concepts::Digraph "Digraph concept". + /// Most of its member functions and nested classes are documented + /// only in the concept class. + /// + /// This class provides constant time counting for nodes and arcs. + /// + /// \note FullDigraph and FullGraph classes are very similar, + /// but there are two differences. While this class conforms only + /// to the \ref concepts::Digraph "Digraph" concept, FullGraph + /// conforms to the \ref concepts::Graph "Graph" concept, + /// moreover FullGraph does not contain a loop for each + /// node as this class does. + /// + /// \sa FullGraph + class FullDigraph : public ExtendedFullDigraphBase { + typedef ExtendedFullDigraphBase Parent; + + public: + + /// \brief Default constructor. + /// + /// Default constructor. The number of nodes and arcs will be zero. + FullDigraph() { construct(0); } + + /// \brief Constructor + /// + /// Constructor. + /// \param n The number of the nodes. + FullDigraph(int n) { construct(n); } + + /// \brief Resizes the digraph + /// + /// This function resizes the digraph. It fully destroys and + /// rebuilds the structure, therefore the maps of the digraph will be + /// reallocated automatically and the previous values will be lost. + void resize(int n) { + Parent::notifier(Arc()).clear(); + Parent::notifier(Node()).clear(); + construct(n); + Parent::notifier(Node()).build(); + Parent::notifier(Arc()).build(); + } + + /// \brief Returns the node with the given index. + /// + /// Returns the node with the given index. Since this structure is + /// completely static, the nodes can be indexed with integers from + /// the range [0..nodeNum()-1]. + /// The index of a node is the same as its ID. + /// \sa index() + Node operator()(int ix) const { return Parent::operator()(ix); } + + /// \brief Returns the index of the given node. + /// + /// Returns the index of the given node. Since this structure is + /// completely static, the nodes can be indexed with integers from + /// the range [0..nodeNum()-1]. + /// The index of a node is the same as its ID. + /// \sa operator()() + static int index(const Node& node) { return Parent::index(node); } + + /// \brief Returns the arc connecting the given nodes. + /// + /// Returns the arc connecting the given nodes. + Arc arc(Node u, Node v) const { + return Parent::arc(u, v); + } + + /// \brief Number of nodes. + int nodeNum() const { return Parent::nodeNum(); } + /// \brief Number of arcs. + int arcNum() const { return Parent::arcNum(); } + }; + + + class FullGraphBase { + public: + + typedef FullGraphBase Graph; + + class Node; + class Arc; + class Edge; + + protected: + + int _node_num; + int _edge_num; + + FullGraphBase() {} + + void construct(int n) { _node_num = n; _edge_num = n * (n - 1) / 2; } + + int _uid(int e) const { + int u = e / _node_num; + int v = e % _node_num; + return u < v ? u : _node_num - 2 - u; + } + + int _vid(int e) const { + int u = e / _node_num; + int v = e % _node_num; + return u < v ? v : _node_num - 1 - v; + } + + void _uvid(int e, int& u, int& v) const { + u = e / _node_num; + v = e % _node_num; + if (u >= v) { + u = _node_num - 2 - u; + v = _node_num - 1 - v; + } + } + + void _stid(int a, int& s, int& t) const { + if ((a & 1) == 1) { + _uvid(a >> 1, s, t); + } else { + _uvid(a >> 1, t, s); + } + } + + int _eid(int u, int v) const { + if (u < (_node_num - 1) / 2) { + return u * _node_num + v; + } else { + return (_node_num - 1 - u) * _node_num - v - 1; + } + } + + public: + + Node operator()(int ix) const { return Node(ix); } + static int index(const Node& node) { return node._id; } + + Edge edge(const Node& u, const Node& v) const { + if (u._id < v._id) { + return Edge(_eid(u._id, v._id)); + } else if (u._id != v._id) { + return Edge(_eid(v._id, u._id)); + } else { + return INVALID; + } + } + + Arc arc(const Node& s, const Node& t) const { + if (s._id < t._id) { + return Arc((_eid(s._id, t._id) << 1) | 1); + } else if (s._id != t._id) { + return Arc(_eid(t._id, s._id) << 1); + } else { + return INVALID; + } + } + + typedef True NodeNumTag; + typedef True ArcNumTag; + typedef True EdgeNumTag; + + int nodeNum() const { return _node_num; } + int arcNum() const { return 2 * _edge_num; } + int edgeNum() const { return _edge_num; } + + static int id(Node node) { return node._id; } + static int id(Arc arc) { return arc._id; } + static int id(Edge edge) { return edge._id; } + + int maxNodeId() const { return _node_num-1; } + int maxArcId() const { return 2 * _edge_num-1; } + int maxEdgeId() const { return _edge_num-1; } + + static Node nodeFromId(int id) { return Node(id);} + static Arc arcFromId(int id) { return Arc(id);} + static Edge edgeFromId(int id) { return Edge(id);} + + Node u(Edge edge) const { + return Node(_uid(edge._id)); + } + + Node v(Edge edge) const { + return Node(_vid(edge._id)); + } + + Node source(Arc arc) const { + return Node((arc._id & 1) == 1 ? + _uid(arc._id >> 1) : _vid(arc._id >> 1)); + } + + Node target(Arc arc) const { + return Node((arc._id & 1) == 1 ? + _vid(arc._id >> 1) : _uid(arc._id >> 1)); + } + + typedef True FindEdgeTag; + typedef True FindArcTag; + + Edge findEdge(Node u, Node v, Edge prev = INVALID) const { + return prev != INVALID ? INVALID : edge(u, v); + } + + Arc findArc(Node s, Node t, Arc prev = INVALID) const { + return prev != INVALID ? INVALID : arc(s, t); + } + + class Node { + friend class FullGraphBase; + + protected: + int _id; + Node(int id) : _id(id) {} + public: + Node() {} + Node (Invalid) { _id = -1; } + bool operator==(const Node node) const {return _id == node._id;} + bool operator!=(const Node node) const {return _id != node._id;} + bool operator<(const Node node) const {return _id < node._id;} + }; + + class Edge { + friend class FullGraphBase; + friend class Arc; + + protected: + int _id; + + Edge(int id) : _id(id) {} + + public: + Edge() { } + Edge (Invalid) { _id = -1; } + + bool operator==(const Edge edge) const {return _id == edge._id;} + bool operator!=(const Edge edge) const {return _id != edge._id;} + bool operator<(const Edge edge) const {return _id < edge._id;} + }; + + class Arc { + friend class FullGraphBase; + + protected: + int _id; + + Arc(int id) : _id(id) {} + + public: + Arc() { } + Arc (Invalid) { _id = -1; } + + operator Edge() const { return Edge(_id != -1 ? (_id >> 1) : -1); } + + bool operator==(const Arc arc) const {return _id == arc._id;} + bool operator!=(const Arc arc) const {return _id != arc._id;} + bool operator<(const Arc arc) const {return _id < arc._id;} + }; + + static bool direction(Arc arc) { + return (arc._id & 1) == 1; + } + + static Arc direct(Edge edge, bool dir) { + return Arc((edge._id << 1) | (dir ? 1 : 0)); + } + + void first(Node& node) const { + node._id = _node_num - 1; + } + + static void next(Node& node) { + --node._id; + } + + void first(Arc& arc) const { + arc._id = (_edge_num << 1) - 1; + } + + static void next(Arc& arc) { + --arc._id; + } + + void first(Edge& edge) const { + edge._id = _edge_num - 1; + } + + static void next(Edge& edge) { + --edge._id; + } + + void firstOut(Arc& arc, const Node& node) const { + int s = node._id, t = _node_num - 1; + if (s < t) { + arc._id = (_eid(s, t) << 1) | 1; + } else { + --t; + arc._id = (t != -1 ? (_eid(t, s) << 1) : -1); + } + } + + void nextOut(Arc& arc) const { + int s, t; + _stid(arc._id, s, t); + --t; + if (s < t) { + arc._id = (_eid(s, t) << 1) | 1; + } else { + if (s == t) --t; + arc._id = (t != -1 ? (_eid(t, s) << 1) : -1); + } + } + + void firstIn(Arc& arc, const Node& node) const { + int s = _node_num - 1, t = node._id; + if (s > t) { + arc._id = (_eid(t, s) << 1); + } else { + --s; + arc._id = (s != -1 ? (_eid(s, t) << 1) | 1 : -1); + } + } + + void nextIn(Arc& arc) const { + int s, t; + _stid(arc._id, s, t); + --s; + if (s > t) { + arc._id = (_eid(t, s) << 1); + } else { + if (s == t) --s; + arc._id = (s != -1 ? (_eid(s, t) << 1) | 1 : -1); + } + } + + void firstInc(Edge& edge, bool& dir, const Node& node) const { + int u = node._id, v = _node_num - 1; + if (u < v) { + edge._id = _eid(u, v); + dir = true; + } else { + --v; + edge._id = (v != -1 ? _eid(v, u) : -1); + dir = false; + } + } + + void nextInc(Edge& edge, bool& dir) const { + int u, v; + if (dir) { + _uvid(edge._id, u, v); + --v; + if (u < v) { + edge._id = _eid(u, v); + } else { + --v; + edge._id = (v != -1 ? _eid(v, u) : -1); + dir = false; + } + } else { + _uvid(edge._id, v, u); + --v; + edge._id = (v != -1 ? _eid(v, u) : -1); + } + } + + }; + + typedef GraphExtender ExtendedFullGraphBase; + + /// \ingroup graphs + /// + /// \brief An undirected full graph class. + /// + /// FullGraph is a simple and fast implmenetation of undirected full + /// (complete) graphs. It contains an edge between every distinct pair + /// of nodes, therefore the number of edges is n(n-1)/2. + /// This class is completely static and it needs constant memory space. + /// Thus you can neither add nor delete nodes or edges, however + /// the structure can be resized using resize(). + /// + /// This type fully conforms to the \ref concepts::Graph "Graph concept". + /// Most of its member functions and nested classes are documented + /// only in the concept class. + /// + /// This class provides constant time counting for nodes, edges and arcs. + /// + /// \note FullDigraph and FullGraph classes are very similar, + /// but there are two differences. While FullDigraph + /// conforms only to the \ref concepts::Digraph "Digraph" concept, + /// this class conforms to the \ref concepts::Graph "Graph" concept, + /// moreover this class does not contain a loop for each + /// node as FullDigraph does. + /// + /// \sa FullDigraph + class FullGraph : public ExtendedFullGraphBase { + typedef ExtendedFullGraphBase Parent; + + public: + + /// \brief Default constructor. + /// + /// Default constructor. The number of nodes and edges will be zero. + FullGraph() { construct(0); } + + /// \brief Constructor + /// + /// Constructor. + /// \param n The number of the nodes. + FullGraph(int n) { construct(n); } + + /// \brief Resizes the graph + /// + /// This function resizes the graph. It fully destroys and + /// rebuilds the structure, therefore the maps of the graph will be + /// reallocated automatically and the previous values will be lost. + void resize(int n) { + Parent::notifier(Arc()).clear(); + Parent::notifier(Edge()).clear(); + Parent::notifier(Node()).clear(); + construct(n); + Parent::notifier(Node()).build(); + Parent::notifier(Edge()).build(); + Parent::notifier(Arc()).build(); + } + + /// \brief Returns the node with the given index. + /// + /// Returns the node with the given index. Since this structure is + /// completely static, the nodes can be indexed with integers from + /// the range [0..nodeNum()-1]. + /// The index of a node is the same as its ID. + /// \sa index() + Node operator()(int ix) const { return Parent::operator()(ix); } + + /// \brief Returns the index of the given node. + /// + /// Returns the index of the given node. Since this structure is + /// completely static, the nodes can be indexed with integers from + /// the range [0..nodeNum()-1]. + /// The index of a node is the same as its ID. + /// \sa operator()() + static int index(const Node& node) { return Parent::index(node); } + + /// \brief Returns the arc connecting the given nodes. + /// + /// Returns the arc connecting the given nodes. + Arc arc(Node s, Node t) const { + return Parent::arc(s, t); + } + + /// \brief Returns the edge connecting the given nodes. + /// + /// Returns the edge connecting the given nodes. + Edge edge(Node u, Node v) const { + return Parent::edge(u, v); + } + + /// \brief Number of nodes. + int nodeNum() const { return Parent::nodeNum(); } + /// \brief Number of arcs. + int arcNum() const { return Parent::arcNum(); } + /// \brief Number of edges. + int edgeNum() const { return Parent::edgeNum(); } + + }; + + class FullBpGraphBase { + + protected: + + int _red_num, _blue_num; + int _node_num, _edge_num; + + public: + + typedef FullBpGraphBase Graph; + + class Node; + class Arc; + class Edge; + + class Node { + friend class FullBpGraphBase; + protected: + + int _id; + explicit Node(int id) { _id = id;} + + public: + Node() {} + Node (Invalid) { _id = -1; } + bool operator==(const Node& node) const {return _id == node._id;} + bool operator!=(const Node& node) const {return _id != node._id;} + bool operator<(const Node& node) const {return _id < node._id;} + }; + + class RedNode : public Node { + friend class FullBpGraphBase; + protected: + + explicit RedNode(int pid) : Node(pid) {} + + public: + RedNode() {} + RedNode(const RedNode& node) : Node(node) {} + RedNode(Invalid) : Node(INVALID){} + }; + + class BlueNode : public Node { + friend class FullBpGraphBase; + protected: + + explicit BlueNode(int pid) : Node(pid) {} + + public: + BlueNode() {} + BlueNode(const BlueNode& node) : Node(node) {} + BlueNode(Invalid) : Node(INVALID){} + }; + + class Edge { + friend class FullBpGraphBase; + protected: + + int _id; + explicit Edge(int id) { _id = id;} + + public: + Edge() {} + Edge (Invalid) { _id = -1; } + bool operator==(const Edge& arc) const {return _id == arc._id;} + bool operator!=(const Edge& arc) const {return _id != arc._id;} + bool operator<(const Edge& arc) const {return _id < arc._id;} + }; + + class Arc { + friend class FullBpGraphBase; + protected: + + int _id; + explicit Arc(int id) { _id = id;} + + public: + operator Edge() const { + return _id != -1 ? edgeFromId(_id / 2) : INVALID; + } + + Arc() {} + Arc (Invalid) { _id = -1; } + bool operator==(const Arc& arc) const {return _id == arc._id;} + bool operator!=(const Arc& arc) const {return _id != arc._id;} + bool operator<(const Arc& arc) const {return _id < arc._id;} + }; + + + protected: + + FullBpGraphBase() + : _red_num(0), _blue_num(0), _node_num(0), _edge_num(0) {} + + void construct(int redNum, int blueNum) { + _red_num = redNum; _blue_num = blueNum; + _node_num = redNum + blueNum; _edge_num = redNum * blueNum; + } + + public: + + typedef True NodeNumTag; + typedef True EdgeNumTag; + typedef True ArcNumTag; + + int nodeNum() const { return _node_num; } + int redNum() const { return _red_num; } + int blueNum() const { return _blue_num; } + int edgeNum() const { return _edge_num; } + int arcNum() const { return 2 * _edge_num; } + + int maxNodeId() const { return _node_num - 1; } + int maxRedId() const { return _red_num - 1; } + int maxBlueId() const { return _blue_num - 1; } + int maxEdgeId() const { return _edge_num - 1; } + int maxArcId() const { return 2 * _edge_num - 1; } + + bool red(Node n) const { return n._id < _red_num; } + bool blue(Node n) const { return n._id >= _red_num; } + + static RedNode asRedNodeUnsafe(Node n) { return RedNode(n._id); } + static BlueNode asBlueNodeUnsafe(Node n) { return BlueNode(n._id); } + + Node source(Arc a) const { + if (a._id & 1) { + return Node((a._id >> 1) % _red_num); + } else { + return Node((a._id >> 1) / _red_num + _red_num); + } + } + Node target(Arc a) const { + if (a._id & 1) { + return Node((a._id >> 1) / _red_num + _red_num); + } else { + return Node((a._id >> 1) % _red_num); + } + } + + RedNode redNode(Edge e) const { + return RedNode(e._id % _red_num); + } + BlueNode blueNode(Edge e) const { + return BlueNode(e._id / _red_num + _red_num); + } + + static bool direction(Arc a) { + return (a._id & 1) == 1; + } + + static Arc direct(Edge e, bool d) { + return Arc(e._id * 2 + (d ? 1 : 0)); + } + + void first(Node& node) const { + node._id = _node_num - 1; + } + + static void next(Node& node) { + --node._id; + } + + void first(RedNode& node) const { + node._id = _red_num - 1; + } + + static void next(RedNode& node) { + --node._id; + } + + void first(BlueNode& node) const { + if (_red_num == _node_num) node._id = -1; + else node._id = _node_num - 1; + } + + void next(BlueNode& node) const { + if (node._id == _red_num) node._id = -1; + else --node._id; + } + + void first(Arc& arc) const { + arc._id = 2 * _edge_num - 1; + } + + static void next(Arc& arc) { + --arc._id; + } + + void first(Edge& arc) const { + arc._id = _edge_num - 1; + } + + static void next(Edge& arc) { + --arc._id; + } + + void firstOut(Arc &a, const Node& v) const { + if (v._id < _red_num) { + a._id = 2 * (v._id + _red_num * (_blue_num - 1)) + 1; + } else { + a._id = 2 * (_red_num - 1 + _red_num * (v._id - _red_num)); + } + } + void nextOut(Arc &a) const { + if (a._id & 1) { + a._id -= 2 * _red_num; + if (a._id < 0) a._id = -1; + } else { + if (a._id % (2 * _red_num) == 0) a._id = -1; + else a._id -= 2; + } + } + + void firstIn(Arc &a, const Node& v) const { + if (v._id < _red_num) { + a._id = 2 * (v._id + _red_num * (_blue_num - 1)); + } else { + a._id = 2 * (_red_num - 1 + _red_num * (v._id - _red_num)) + 1; + } + } + void nextIn(Arc &a) const { + if (a._id & 1) { + if (a._id % (2 * _red_num) == 1) a._id = -1; + else a._id -= 2; + } else { + a._id -= 2 * _red_num; + if (a._id < 0) a._id = -1; + } + } + + void firstInc(Edge &e, bool& d, const Node& v) const { + if (v._id < _red_num) { + d = true; + e._id = v._id + _red_num * (_blue_num - 1); + } else { + d = false; + e._id = _red_num - 1 + _red_num * (v._id - _red_num); + } + } + void nextInc(Edge &e, bool& d) const { + if (d) { + e._id -= _red_num; + if (e._id < 0) e._id = -1; + } else { + if (e._id % _red_num == 0) e._id = -1; + else --e._id; + } + } + + static int id(const Node& v) { return v._id; } + int id(const RedNode& v) const { return v._id; } + int id(const BlueNode& v) const { return v._id - _red_num; } + static int id(Arc e) { return e._id; } + static int id(Edge e) { return e._id; } + + static Node nodeFromId(int id) { return Node(id);} + static Arc arcFromId(int id) { return Arc(id);} + static Edge edgeFromId(int id) { return Edge(id);} + + bool valid(Node n) const { + return n._id >= 0 && n._id < _node_num; + } + bool valid(Arc a) const { + return a._id >= 0 && a._id < 2 * _edge_num; + } + bool valid(Edge e) const { + return e._id >= 0 && e._id < _edge_num; + } + + RedNode redNode(int index) const { + return RedNode(index); + } + + int index(RedNode n) const { + return n._id; + } + + BlueNode blueNode(int index) const { + return BlueNode(index + _red_num); + } + + int index(BlueNode n) const { + return n._id - _red_num; + } + + void clear() { + _red_num = 0; _blue_num = 0; + _node_num = 0; _edge_num = 0; + } + + Edge edge(const Node& u, const Node& v) const { + if (u._id < _red_num) { + if (v._id < _red_num) { + return Edge(-1); + } else { + return Edge(u._id + _red_num * (v._id - _red_num)); + } + } else { + if (v._id < _red_num) { + return Edge(v._id + _red_num * (u._id - _red_num)); + } else { + return Edge(-1); + } + } + } + + Arc arc(const Node& u, const Node& v) const { + if (u._id < _red_num) { + if (v._id < _red_num) { + return Arc(-1); + } else { + return Arc(2 * (u._id + _red_num * (v._id - _red_num)) + 1); + } + } else { + if (v._id < _red_num) { + return Arc(2 * (v._id + _red_num * (u._id - _red_num))); + } else { + return Arc(-1); + } + } + } + + typedef True FindEdgeTag; + typedef True FindArcTag; + + Edge findEdge(Node u, Node v, Edge prev = INVALID) const { + return prev != INVALID ? INVALID : edge(u, v); + } + + Arc findArc(Node s, Node t, Arc prev = INVALID) const { + return prev != INVALID ? INVALID : arc(s, t); + } + + }; + + typedef BpGraphExtender ExtendedFullBpGraphBase; + + /// \ingroup graphs + /// + /// \brief An undirected full bipartite graph class. + /// + /// FullBpGraph is a simple and fast implmenetation of undirected + /// full bipartite graphs. It contains an edge between every + /// red-blue pairs of nodes, therefore the number of edges is + /// nr*nb. This class is completely static and it needs + /// constant memory space. Thus you can neither add nor delete + /// nodes or edges, however the structure can be resized using + /// resize(). + /// + /// This type fully conforms to the \ref concepts::BpGraph "BpGraph concept". + /// Most of its member functions and nested classes are documented + /// only in the concept class. + /// + /// This class provides constant time counting for nodes, edges and arcs. + /// + /// \sa FullGraph + class FullBpGraph : public ExtendedFullBpGraphBase { + public: + + typedef ExtendedFullBpGraphBase Parent; + + /// \brief Default constructor. + /// + /// Default constructor. The number of nodes and edges will be zero. + FullBpGraph() { construct(0, 0); } + + /// \brief Constructor + /// + /// Constructor. + /// \param redNum The number of the red nodes. + /// \param blueNum The number of the blue nodes. + FullBpGraph(int redNum, int blueNum) { construct(redNum, blueNum); } + + /// \brief Resizes the graph + /// + /// This function resizes the graph. It fully destroys and + /// rebuilds the structure, therefore the maps of the graph will be + /// reallocated automatically and the previous values will be lost. + void resize(int redNum, int blueNum) { + Parent::notifier(Arc()).clear(); + Parent::notifier(Edge()).clear(); + Parent::notifier(Node()).clear(); + Parent::notifier(BlueNode()).clear(); + Parent::notifier(RedNode()).clear(); + construct(redNum, blueNum); + Parent::notifier(RedNode()).build(); + Parent::notifier(BlueNode()).build(); + Parent::notifier(Node()).build(); + Parent::notifier(Edge()).build(); + Parent::notifier(Arc()).build(); + } + + using Parent::redNode; + using Parent::blueNode; + + /// \brief Returns the red node with the given index. + /// + /// Returns the red node with the given index. Since this + /// structure is completely static, the red nodes can be indexed + /// with integers from the range [0..redNum()-1]. + /// \sa redIndex() + RedNode redNode(int index) const { return Parent::redNode(index); } + + /// \brief Returns the index of the given red node. + /// + /// Returns the index of the given red node. Since this structure + /// is completely static, the red nodes can be indexed with + /// integers from the range [0..redNum()-1]. + /// + /// \sa operator()() + int index(RedNode node) const { return Parent::index(node); } + + /// \brief Returns the blue node with the given index. + /// + /// Returns the blue node with the given index. Since this + /// structure is completely static, the blue nodes can be indexed + /// with integers from the range [0..blueNum()-1]. + /// \sa blueIndex() + BlueNode blueNode(int index) const { return Parent::blueNode(index); } + + /// \brief Returns the index of the given blue node. + /// + /// Returns the index of the given blue node. Since this structure + /// is completely static, the blue nodes can be indexed with + /// integers from the range [0..blueNum()-1]. + /// + /// \sa operator()() + int index(BlueNode node) const { return Parent::index(node); } + + /// \brief Returns the edge which connects the given nodes. + /// + /// Returns the edge which connects the given nodes. + Edge edge(const Node& u, const Node& v) const { + return Parent::edge(u, v); + } + + /// \brief Returns the arc which connects the given nodes. + /// + /// Returns the arc which connects the given nodes. + Arc arc(const Node& u, const Node& v) const { + return Parent::arc(u, v); + } + + /// \brief Number of nodes. + int nodeNum() const { return Parent::nodeNum(); } + /// \brief Number of red nodes. + int redNum() const { return Parent::redNum(); } + /// \brief Number of blue nodes. + int blueNum() const { return Parent::blueNum(); } + /// \brief Number of arcs. + int arcNum() const { return Parent::arcNum(); } + /// \brief Number of edges. + int edgeNum() const { return Parent::edgeNum(); } + }; + + +} //namespace lemon + + +#endif //LEMON_FULL_GRAPH_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/glpk.cc b/extern/quadriflow/3rd/lemon-1.3.1/lemon/glpk.cc new file mode 100644 index 00000000000..38d81151f2f --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/glpk.cc @@ -0,0 +1,1012 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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. + * + */ + +///\file +///\brief Implementation of the LEMON GLPK LP and MIP solver interface. + +#include +#include + +#include + +namespace lemon { + + // GlpkBase members + + GlpkBase::GlpkBase() : LpBase() { + lp = glp_create_prob(); + glp_create_index(lp); + messageLevel(MESSAGE_NOTHING); + } + + GlpkBase::GlpkBase(const GlpkBase &other) : LpBase() { + lp = glp_create_prob(); + glp_copy_prob(lp, other.lp, GLP_ON); + glp_create_index(lp); + rows = other.rows; + cols = other.cols; + messageLevel(MESSAGE_NOTHING); + } + + GlpkBase::~GlpkBase() { + glp_delete_prob(lp); + } + + int GlpkBase::_addCol() { + int i = glp_add_cols(lp, 1); + glp_set_col_bnds(lp, i, GLP_FR, 0.0, 0.0); + return i; + } + + int GlpkBase::_addRow() { + int i = glp_add_rows(lp, 1); + glp_set_row_bnds(lp, i, GLP_FR, 0.0, 0.0); + return i; + } + + int GlpkBase::_addRow(Value lo, ExprIterator b, + ExprIterator e, Value up) { + int i = glp_add_rows(lp, 1); + + if (lo == -INF) { + if (up == INF) { + glp_set_row_bnds(lp, i, GLP_FR, lo, up); + } else { + glp_set_row_bnds(lp, i, GLP_UP, lo, up); + } + } else { + if (up == INF) { + glp_set_row_bnds(lp, i, GLP_LO, lo, up); + } else if (lo != up) { + glp_set_row_bnds(lp, i, GLP_DB, lo, up); + } else { + glp_set_row_bnds(lp, i, GLP_FX, lo, up); + } + } + + std::vector indexes; + std::vector values; + + indexes.push_back(0); + values.push_back(0); + + for(ExprIterator it = b; it != e; ++it) { + indexes.push_back(it->first); + values.push_back(it->second); + } + + glp_set_mat_row(lp, i, values.size() - 1, + &indexes.front(), &values.front()); + return i; + } + + void GlpkBase::_eraseCol(int i) { + int ca[2]; + ca[1] = i; + glp_del_cols(lp, 1, ca); + } + + void GlpkBase::_eraseRow(int i) { + int ra[2]; + ra[1] = i; + glp_del_rows(lp, 1, ra); + } + + void GlpkBase::_eraseColId(int i) { + cols.eraseIndex(i); + cols.shiftIndices(i); + } + + void GlpkBase::_eraseRowId(int i) { + rows.eraseIndex(i); + rows.shiftIndices(i); + } + + void GlpkBase::_getColName(int c, std::string& name) const { + const char *str = glp_get_col_name(lp, c); + if (str) name = str; + else name.clear(); + } + + void GlpkBase::_setColName(int c, const std::string & name) { + glp_set_col_name(lp, c, const_cast(name.c_str())); + + } + + int GlpkBase::_colByName(const std::string& name) const { + int k = glp_find_col(lp, const_cast(name.c_str())); + return k > 0 ? k : -1; + } + + void GlpkBase::_getRowName(int r, std::string& name) const { + const char *str = glp_get_row_name(lp, r); + if (str) name = str; + else name.clear(); + } + + void GlpkBase::_setRowName(int r, const std::string & name) { + glp_set_row_name(lp, r, const_cast(name.c_str())); + + } + + int GlpkBase::_rowByName(const std::string& name) const { + int k = glp_find_row(lp, const_cast(name.c_str())); + return k > 0 ? k : -1; + } + + void GlpkBase::_setRowCoeffs(int i, ExprIterator b, ExprIterator e) { + std::vector indexes; + std::vector values; + + indexes.push_back(0); + values.push_back(0); + + for(ExprIterator it = b; it != e; ++it) { + indexes.push_back(it->first); + values.push_back(it->second); + } + + glp_set_mat_row(lp, i, values.size() - 1, + &indexes.front(), &values.front()); + } + + void GlpkBase::_getRowCoeffs(int ix, InsertIterator b) const { + int length = glp_get_mat_row(lp, ix, 0, 0); + + std::vector indexes(length + 1); + std::vector values(length + 1); + + glp_get_mat_row(lp, ix, &indexes.front(), &values.front()); + + for (int i = 1; i <= length; ++i) { + *b = std::make_pair(indexes[i], values[i]); + ++b; + } + } + + void GlpkBase::_setColCoeffs(int ix, ExprIterator b, + ExprIterator e) { + + std::vector indexes; + std::vector values; + + indexes.push_back(0); + values.push_back(0); + + for(ExprIterator it = b; it != e; ++it) { + indexes.push_back(it->first); + values.push_back(it->second); + } + + glp_set_mat_col(lp, ix, values.size() - 1, + &indexes.front(), &values.front()); + } + + void GlpkBase::_getColCoeffs(int ix, InsertIterator b) const { + int length = glp_get_mat_col(lp, ix, 0, 0); + + std::vector indexes(length + 1); + std::vector values(length + 1); + + glp_get_mat_col(lp, ix, &indexes.front(), &values.front()); + + for (int i = 1; i <= length; ++i) { + *b = std::make_pair(indexes[i], values[i]); + ++b; + } + } + + void GlpkBase::_setCoeff(int ix, int jx, Value value) { + + if (glp_get_num_cols(lp) < glp_get_num_rows(lp)) { + + int length = glp_get_mat_row(lp, ix, 0, 0); + + std::vector indexes(length + 2); + std::vector values(length + 2); + + glp_get_mat_row(lp, ix, &indexes.front(), &values.front()); + + //The following code does not suppose that the elements of the + //array indexes are sorted + bool found = false; + for (int i = 1; i <= length; ++i) { + if (indexes[i] == jx) { + found = true; + values[i] = value; + break; + } + } + if (!found) { + ++length; + indexes[length] = jx; + values[length] = value; + } + + glp_set_mat_row(lp, ix, length, &indexes.front(), &values.front()); + + } else { + + int length = glp_get_mat_col(lp, jx, 0, 0); + + std::vector indexes(length + 2); + std::vector values(length + 2); + + glp_get_mat_col(lp, jx, &indexes.front(), &values.front()); + + //The following code does not suppose that the elements of the + //array indexes are sorted + bool found = false; + for (int i = 1; i <= length; ++i) { + if (indexes[i] == ix) { + found = true; + values[i] = value; + break; + } + } + if (!found) { + ++length; + indexes[length] = ix; + values[length] = value; + } + + glp_set_mat_col(lp, jx, length, &indexes.front(), &values.front()); + } + + } + + GlpkBase::Value GlpkBase::_getCoeff(int ix, int jx) const { + + int length = glp_get_mat_row(lp, ix, 0, 0); + + std::vector indexes(length + 1); + std::vector values(length + 1); + + glp_get_mat_row(lp, ix, &indexes.front(), &values.front()); + + for (int i = 1; i <= length; ++i) { + if (indexes[i] == jx) { + return values[i]; + } + } + + return 0; + } + + void GlpkBase::_setColLowerBound(int i, Value lo) { + LEMON_ASSERT(lo != INF, "Invalid bound"); + + int b = glp_get_col_type(lp, i); + double up = glp_get_col_ub(lp, i); + if (lo == -INF) { + switch (b) { + case GLP_FR: + case GLP_LO: + glp_set_col_bnds(lp, i, GLP_FR, lo, up); + break; + case GLP_UP: + break; + case GLP_DB: + case GLP_FX: + glp_set_col_bnds(lp, i, GLP_UP, lo, up); + break; + default: + break; + } + } else { + switch (b) { + case GLP_FR: + case GLP_LO: + glp_set_col_bnds(lp, i, GLP_LO, lo, up); + break; + case GLP_UP: + case GLP_DB: + case GLP_FX: + if (lo == up) + glp_set_col_bnds(lp, i, GLP_FX, lo, up); + else + glp_set_col_bnds(lp, i, GLP_DB, lo, up); + break; + default: + break; + } + } + } + + GlpkBase::Value GlpkBase::_getColLowerBound(int i) const { + int b = glp_get_col_type(lp, i); + switch (b) { + case GLP_LO: + case GLP_DB: + case GLP_FX: + return glp_get_col_lb(lp, i); + default: + return -INF; + } + } + + void GlpkBase::_setColUpperBound(int i, Value up) { + LEMON_ASSERT(up != -INF, "Invalid bound"); + + int b = glp_get_col_type(lp, i); + double lo = glp_get_col_lb(lp, i); + if (up == INF) { + switch (b) { + case GLP_FR: + case GLP_LO: + break; + case GLP_UP: + glp_set_col_bnds(lp, i, GLP_FR, lo, up); + break; + case GLP_DB: + case GLP_FX: + glp_set_col_bnds(lp, i, GLP_LO, lo, up); + break; + default: + break; + } + } else { + switch (b) { + case GLP_FR: + glp_set_col_bnds(lp, i, GLP_UP, lo, up); + break; + case GLP_UP: + glp_set_col_bnds(lp, i, GLP_UP, lo, up); + break; + case GLP_LO: + case GLP_DB: + case GLP_FX: + if (lo == up) + glp_set_col_bnds(lp, i, GLP_FX, lo, up); + else + glp_set_col_bnds(lp, i, GLP_DB, lo, up); + break; + default: + break; + } + } + + } + + GlpkBase::Value GlpkBase::_getColUpperBound(int i) const { + int b = glp_get_col_type(lp, i); + switch (b) { + case GLP_UP: + case GLP_DB: + case GLP_FX: + return glp_get_col_ub(lp, i); + default: + return INF; + } + } + + void GlpkBase::_setRowLowerBound(int i, Value lo) { + LEMON_ASSERT(lo != INF, "Invalid bound"); + + int b = glp_get_row_type(lp, i); + double up = glp_get_row_ub(lp, i); + if (lo == -INF) { + switch (b) { + case GLP_FR: + case GLP_LO: + glp_set_row_bnds(lp, i, GLP_FR, lo, up); + break; + case GLP_UP: + break; + case GLP_DB: + case GLP_FX: + glp_set_row_bnds(lp, i, GLP_UP, lo, up); + break; + default: + break; + } + } else { + switch (b) { + case GLP_FR: + case GLP_LO: + glp_set_row_bnds(lp, i, GLP_LO, lo, up); + break; + case GLP_UP: + case GLP_DB: + case GLP_FX: + if (lo == up) + glp_set_row_bnds(lp, i, GLP_FX, lo, up); + else + glp_set_row_bnds(lp, i, GLP_DB, lo, up); + break; + default: + break; + } + } + + } + + GlpkBase::Value GlpkBase::_getRowLowerBound(int i) const { + int b = glp_get_row_type(lp, i); + switch (b) { + case GLP_LO: + case GLP_DB: + case GLP_FX: + return glp_get_row_lb(lp, i); + default: + return -INF; + } + } + + void GlpkBase::_setRowUpperBound(int i, Value up) { + LEMON_ASSERT(up != -INF, "Invalid bound"); + + int b = glp_get_row_type(lp, i); + double lo = glp_get_row_lb(lp, i); + if (up == INF) { + switch (b) { + case GLP_FR: + case GLP_LO: + break; + case GLP_UP: + glp_set_row_bnds(lp, i, GLP_FR, lo, up); + break; + case GLP_DB: + case GLP_FX: + glp_set_row_bnds(lp, i, GLP_LO, lo, up); + break; + default: + break; + } + } else { + switch (b) { + case GLP_FR: + glp_set_row_bnds(lp, i, GLP_UP, lo, up); + break; + case GLP_UP: + glp_set_row_bnds(lp, i, GLP_UP, lo, up); + break; + case GLP_LO: + case GLP_DB: + case GLP_FX: + if (lo == up) + glp_set_row_bnds(lp, i, GLP_FX, lo, up); + else + glp_set_row_bnds(lp, i, GLP_DB, lo, up); + break; + default: + break; + } + } + } + + GlpkBase::Value GlpkBase::_getRowUpperBound(int i) const { + int b = glp_get_row_type(lp, i); + switch (b) { + case GLP_UP: + case GLP_DB: + case GLP_FX: + return glp_get_row_ub(lp, i); + default: + return INF; + } + } + + void GlpkBase::_setObjCoeffs(ExprIterator b, ExprIterator e) { + for (int i = 1; i <= glp_get_num_cols(lp); ++i) { + glp_set_obj_coef(lp, i, 0.0); + } + for (ExprIterator it = b; it != e; ++it) { + glp_set_obj_coef(lp, it->first, it->second); + } + } + + void GlpkBase::_getObjCoeffs(InsertIterator b) const { + for (int i = 1; i <= glp_get_num_cols(lp); ++i) { + Value val = glp_get_obj_coef(lp, i); + if (val != 0.0) { + *b = std::make_pair(i, val); + ++b; + } + } + } + + void GlpkBase::_setObjCoeff(int i, Value obj_coef) { + //i = 0 means the constant term (shift) + glp_set_obj_coef(lp, i, obj_coef); + } + + GlpkBase::Value GlpkBase::_getObjCoeff(int i) const { + //i = 0 means the constant term (shift) + return glp_get_obj_coef(lp, i); + } + + void GlpkBase::_setSense(GlpkBase::Sense sense) { + switch (sense) { + case MIN: + glp_set_obj_dir(lp, GLP_MIN); + break; + case MAX: + glp_set_obj_dir(lp, GLP_MAX); + break; + } + } + + GlpkBase::Sense GlpkBase::_getSense() const { + switch(glp_get_obj_dir(lp)) { + case GLP_MIN: + return MIN; + case GLP_MAX: + return MAX; + default: + LEMON_ASSERT(false, "Wrong sense"); + return GlpkBase::Sense(); + } + } + + void GlpkBase::_clear() { + glp_erase_prob(lp); + } + + void GlpkBase::freeEnv() { + glp_free_env(); + } + + void GlpkBase::_messageLevel(MessageLevel level) { + switch (level) { + case MESSAGE_NOTHING: + _message_level = GLP_MSG_OFF; + break; + case MESSAGE_ERROR: + _message_level = GLP_MSG_ERR; + break; + case MESSAGE_WARNING: + _message_level = GLP_MSG_ERR; + break; + case MESSAGE_NORMAL: + _message_level = GLP_MSG_ON; + break; + case MESSAGE_VERBOSE: + _message_level = GLP_MSG_ALL; + break; + } + } + + void GlpkBase::_write(std::string file, std::string format) const + { + if(format == "MPS") + glp_write_mps(lp, GLP_MPS_FILE, 0, file.c_str()); + else if(format == "LP") + glp_write_lp(lp, 0, file.c_str()); + else throw UnsupportedFormatError(format); + } + + GlpkBase::FreeEnvHelper GlpkBase::freeEnvHelper; + + // GlpkLp members + + GlpkLp::GlpkLp() + : LpBase(), LpSolver(), GlpkBase() { + presolver(false); + } + + GlpkLp::GlpkLp(const GlpkLp& other) + : LpBase(other), LpSolver(other), GlpkBase(other) { + presolver(false); + } + + GlpkLp* GlpkLp::newSolver() const { return new GlpkLp; } + GlpkLp* GlpkLp::cloneSolver() const { return new GlpkLp(*this); } + + const char* GlpkLp::_solverName() const { return "GlpkLp"; } + + void GlpkLp::_clear_temporals() { + _primal_ray.clear(); + _dual_ray.clear(); + } + + GlpkLp::SolveExitStatus GlpkLp::_solve() { + return solvePrimal(); + } + + GlpkLp::SolveExitStatus GlpkLp::solvePrimal() { + _clear_temporals(); + + glp_smcp smcp; + glp_init_smcp(&smcp); + + smcp.msg_lev = _message_level; + smcp.presolve = _presolve; + + // If the basis is not valid we get an error return value. + // In this case we can try to create a new basis. + switch (glp_simplex(lp, &smcp)) { + case 0: + break; + case GLP_EBADB: + case GLP_ESING: + case GLP_ECOND: + glp_term_out(false); + glp_adv_basis(lp, 0); + glp_term_out(true); + if (glp_simplex(lp, &smcp) != 0) return UNSOLVED; + break; + default: + return UNSOLVED; + } + + return SOLVED; + } + + GlpkLp::SolveExitStatus GlpkLp::solveDual() { + _clear_temporals(); + + glp_smcp smcp; + glp_init_smcp(&smcp); + + smcp.msg_lev = _message_level; + smcp.meth = GLP_DUAL; + smcp.presolve = _presolve; + + // If the basis is not valid we get an error return value. + // In this case we can try to create a new basis. + switch (glp_simplex(lp, &smcp)) { + case 0: + break; + case GLP_EBADB: + case GLP_ESING: + case GLP_ECOND: + glp_term_out(false); + glp_adv_basis(lp, 0); + glp_term_out(true); + if (glp_simplex(lp, &smcp) != 0) return UNSOLVED; + break; + default: + return UNSOLVED; + } + return SOLVED; + } + + GlpkLp::Value GlpkLp::_getPrimal(int i) const { + return glp_get_col_prim(lp, i); + } + + GlpkLp::Value GlpkLp::_getDual(int i) const { + return glp_get_row_dual(lp, i); + } + + GlpkLp::Value GlpkLp::_getPrimalValue() const { + return glp_get_obj_val(lp); + } + + GlpkLp::VarStatus GlpkLp::_getColStatus(int i) const { + switch (glp_get_col_stat(lp, i)) { + case GLP_BS: + return BASIC; + case GLP_UP: + return UPPER; + case GLP_LO: + return LOWER; + case GLP_NF: + return FREE; + case GLP_NS: + return FIXED; + default: + LEMON_ASSERT(false, "Wrong column status"); + return GlpkLp::VarStatus(); + } + } + + GlpkLp::VarStatus GlpkLp::_getRowStatus(int i) const { + switch (glp_get_row_stat(lp, i)) { + case GLP_BS: + return BASIC; + case GLP_UP: + return UPPER; + case GLP_LO: + return LOWER; + case GLP_NF: + return FREE; + case GLP_NS: + return FIXED; + default: + LEMON_ASSERT(false, "Wrong row status"); + return GlpkLp::VarStatus(); + } + } + + GlpkLp::Value GlpkLp::_getPrimalRay(int i) const { + if (_primal_ray.empty()) { + int row_num = glp_get_num_rows(lp); + int col_num = glp_get_num_cols(lp); + + _primal_ray.resize(col_num + 1, 0.0); + + int index = glp_get_unbnd_ray(lp); + if (index != 0) { + // The primal ray is found in primal simplex second phase + LEMON_ASSERT((index <= row_num ? glp_get_row_stat(lp, index) : + glp_get_col_stat(lp, index - row_num)) != GLP_BS, + "Wrong primal ray"); + + bool negate = glp_get_obj_dir(lp) == GLP_MAX; + + if (index > row_num) { + _primal_ray[index - row_num] = 1.0; + if (glp_get_col_dual(lp, index - row_num) > 0) { + negate = !negate; + } + } else { + if (glp_get_row_dual(lp, index) > 0) { + negate = !negate; + } + } + + std::vector ray_indexes(row_num + 1); + std::vector ray_values(row_num + 1); + int ray_length = glp_eval_tab_col(lp, index, &ray_indexes.front(), + &ray_values.front()); + + for (int i = 1; i <= ray_length; ++i) { + if (ray_indexes[i] > row_num) { + _primal_ray[ray_indexes[i] - row_num] = ray_values[i]; + } + } + + if (negate) { + for (int i = 1; i <= col_num; ++i) { + _primal_ray[i] = - _primal_ray[i]; + } + } + } else { + for (int i = 1; i <= col_num; ++i) { + _primal_ray[i] = glp_get_col_prim(lp, i); + } + } + } + return _primal_ray[i]; + } + + GlpkLp::Value GlpkLp::_getDualRay(int i) const { + if (_dual_ray.empty()) { + int row_num = glp_get_num_rows(lp); + + _dual_ray.resize(row_num + 1, 0.0); + + int index = glp_get_unbnd_ray(lp); + if (index != 0) { + // The dual ray is found in dual simplex second phase + LEMON_ASSERT((index <= row_num ? glp_get_row_stat(lp, index) : + glp_get_col_stat(lp, index - row_num)) == GLP_BS, + + "Wrong dual ray"); + + int idx; + bool negate = false; + + if (index > row_num) { + idx = glp_get_col_bind(lp, index - row_num); + if (glp_get_col_prim(lp, index - row_num) > + glp_get_col_ub(lp, index - row_num)) { + negate = true; + } + } else { + idx = glp_get_row_bind(lp, index); + if (glp_get_row_prim(lp, index) > glp_get_row_ub(lp, index)) { + negate = true; + } + } + + _dual_ray[idx] = negate ? - 1.0 : 1.0; + + glp_btran(lp, &_dual_ray.front()); + } else { + double eps = 1e-7; + // The dual ray is found in primal simplex first phase + // We assume that the glpk minimizes the slack to get feasible solution + for (int i = 1; i <= row_num; ++i) { + int index = glp_get_bhead(lp, i); + if (index <= row_num) { + double res = glp_get_row_prim(lp, index); + if (res > glp_get_row_ub(lp, index) + eps) { + _dual_ray[i] = -1; + } else if (res < glp_get_row_lb(lp, index) - eps) { + _dual_ray[i] = 1; + } else { + _dual_ray[i] = 0; + } + _dual_ray[i] *= glp_get_rii(lp, index); + } else { + double res = glp_get_col_prim(lp, index - row_num); + if (res > glp_get_col_ub(lp, index - row_num) + eps) { + _dual_ray[i] = -1; + } else if (res < glp_get_col_lb(lp, index - row_num) - eps) { + _dual_ray[i] = 1; + } else { + _dual_ray[i] = 0; + } + _dual_ray[i] /= glp_get_sjj(lp, index - row_num); + } + } + + glp_btran(lp, &_dual_ray.front()); + + for (int i = 1; i <= row_num; ++i) { + _dual_ray[i] /= glp_get_rii(lp, i); + } + } + } + return _dual_ray[i]; + } + + GlpkLp::ProblemType GlpkLp::_getPrimalType() const { + if (glp_get_status(lp) == GLP_OPT) + return OPTIMAL; + switch (glp_get_prim_stat(lp)) { + case GLP_UNDEF: + return UNDEFINED; + case GLP_FEAS: + case GLP_INFEAS: + if (glp_get_dual_stat(lp) == GLP_NOFEAS) { + return UNBOUNDED; + } else { + return UNDEFINED; + } + case GLP_NOFEAS: + return INFEASIBLE; + default: + LEMON_ASSERT(false, "Wrong primal type"); + return GlpkLp::ProblemType(); + } + } + + GlpkLp::ProblemType GlpkLp::_getDualType() const { + if (glp_get_status(lp) == GLP_OPT) + return OPTIMAL; + switch (glp_get_dual_stat(lp)) { + case GLP_UNDEF: + return UNDEFINED; + case GLP_FEAS: + case GLP_INFEAS: + if (glp_get_prim_stat(lp) == GLP_NOFEAS) { + return UNBOUNDED; + } else { + return UNDEFINED; + } + case GLP_NOFEAS: + return INFEASIBLE; + default: + LEMON_ASSERT(false, "Wrong primal type"); + return GlpkLp::ProblemType(); + } + } + + void GlpkLp::presolver(bool presolve) { + _presolve = presolve; + } + + // GlpkMip members + + GlpkMip::GlpkMip() + : LpBase(), MipSolver(), GlpkBase() { + } + + GlpkMip::GlpkMip(const GlpkMip& other) + : LpBase(), MipSolver(), GlpkBase(other) { + } + + void GlpkMip::_setColType(int i, GlpkMip::ColTypes col_type) { + switch (col_type) { + case INTEGER: + glp_set_col_kind(lp, i, GLP_IV); + break; + case REAL: + glp_set_col_kind(lp, i, GLP_CV); + break; + } + } + + GlpkMip::ColTypes GlpkMip::_getColType(int i) const { + switch (glp_get_col_kind(lp, i)) { + case GLP_IV: + case GLP_BV: + return INTEGER; + default: + return REAL; + } + + } + + GlpkMip::SolveExitStatus GlpkMip::_solve() { + glp_smcp smcp; + glp_init_smcp(&smcp); + + smcp.msg_lev = _message_level; + smcp.meth = GLP_DUAL; + + // If the basis is not valid we get an error return value. + // In this case we can try to create a new basis. + switch (glp_simplex(lp, &smcp)) { + case 0: + break; + case GLP_EBADB: + case GLP_ESING: + case GLP_ECOND: + glp_term_out(false); + glp_adv_basis(lp, 0); + glp_term_out(true); + if (glp_simplex(lp, &smcp) != 0) return UNSOLVED; + break; + default: + return UNSOLVED; + } + + if (glp_get_status(lp) != GLP_OPT) return SOLVED; + + glp_iocp iocp; + glp_init_iocp(&iocp); + + iocp.msg_lev = _message_level; + + if (glp_intopt(lp, &iocp) != 0) return UNSOLVED; + return SOLVED; + } + + + GlpkMip::ProblemType GlpkMip::_getType() const { + switch (glp_get_status(lp)) { + case GLP_OPT: + switch (glp_mip_status(lp)) { + case GLP_UNDEF: + return UNDEFINED; + case GLP_NOFEAS: + return INFEASIBLE; + case GLP_FEAS: + return FEASIBLE; + case GLP_OPT: + return OPTIMAL; + default: + LEMON_ASSERT(false, "Wrong problem type."); + return GlpkMip::ProblemType(); + } + case GLP_NOFEAS: + return INFEASIBLE; + case GLP_INFEAS: + case GLP_FEAS: + if (glp_get_dual_stat(lp) == GLP_NOFEAS) { + return UNBOUNDED; + } else { + return UNDEFINED; + } + default: + LEMON_ASSERT(false, "Wrong problem type."); + return GlpkMip::ProblemType(); + } + } + + GlpkMip::Value GlpkMip::_getSol(int i) const { + return glp_mip_col_val(lp, i); + } + + GlpkMip::Value GlpkMip::_getSolValue() const { + return glp_mip_obj_val(lp); + } + + GlpkMip* GlpkMip::newSolver() const { return new GlpkMip; } + GlpkMip* GlpkMip::cloneSolver() const {return new GlpkMip(*this); } + + const char* GlpkMip::_solverName() const { return "GlpkMip"; } + + + +} //END OF NAMESPACE LEMON diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/glpk.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/glpk.h new file mode 100644 index 00000000000..ccdc54ac059 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/glpk.h @@ -0,0 +1,263 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_GLPK_H +#define LEMON_GLPK_H + +///\file +///\brief Header of the LEMON-GLPK lp solver interface. +///\ingroup lp_group + +#include + +namespace lemon { + + namespace _solver_bits { + class VoidPtr { + private: + void *_ptr; + public: + VoidPtr() : _ptr(0) {} + + template + VoidPtr(T* ptr) : _ptr(reinterpret_cast(ptr)) {} + + template + VoidPtr& operator=(T* ptr) { + _ptr = reinterpret_cast(ptr); + return *this; + } + + template + operator T*() const { return reinterpret_cast(_ptr); } + }; + } + + /// \brief Base interface for the GLPK LP and MIP solver + /// + /// This class implements the common interface of the GLPK LP and MIP solver. + /// \ingroup lp_group + class GlpkBase : virtual public LpBase { + protected: + + _solver_bits::VoidPtr lp; + + GlpkBase(); + GlpkBase(const GlpkBase&); + virtual ~GlpkBase(); + + protected: + + virtual int _addCol(); + virtual int _addRow(); + virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u); + + virtual void _eraseCol(int i); + virtual void _eraseRow(int i); + + virtual void _eraseColId(int i); + virtual void _eraseRowId(int i); + + virtual void _getColName(int col, std::string& name) const; + virtual void _setColName(int col, const std::string& name); + virtual int _colByName(const std::string& name) const; + + virtual void _getRowName(int row, std::string& name) const; + virtual void _setRowName(int row, const std::string& name); + virtual int _rowByName(const std::string& name) const; + + virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e); + virtual void _getRowCoeffs(int i, InsertIterator b) const; + + virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e); + virtual void _getColCoeffs(int i, InsertIterator b) const; + + virtual void _setCoeff(int row, int col, Value value); + virtual Value _getCoeff(int row, int col) const; + + virtual void _setColLowerBound(int i, Value value); + virtual Value _getColLowerBound(int i) const; + + virtual void _setColUpperBound(int i, Value value); + virtual Value _getColUpperBound(int i) const; + + virtual void _setRowLowerBound(int i, Value value); + virtual Value _getRowLowerBound(int i) const; + + virtual void _setRowUpperBound(int i, Value value); + virtual Value _getRowUpperBound(int i) const; + + virtual void _setObjCoeffs(ExprIterator b, ExprIterator e); + virtual void _getObjCoeffs(InsertIterator b) const; + + virtual void _setObjCoeff(int i, Value obj_coef); + virtual Value _getObjCoeff(int i) const; + + virtual void _setSense(Sense); + virtual Sense _getSense() const; + + virtual void _clear(); + + virtual void _messageLevel(MessageLevel level); + + virtual void _write(std::string file, std::string format) const; + + private: + + static void freeEnv(); + + struct FreeEnvHelper { + ~FreeEnvHelper() { + freeEnv(); + } + }; + + static FreeEnvHelper freeEnvHelper; + + protected: + + int _message_level; + + public: + + ///Pointer to the underlying GLPK data structure. + _solver_bits::VoidPtr lpx() {return lp;} + ///Const pointer to the underlying GLPK data structure. + _solver_bits::VoidPtr lpx() const {return lp;} + + ///Returns the constraint identifier understood by GLPK. + int lpxRow(Row r) const { return rows(id(r)); } + + ///Returns the variable identifier understood by GLPK. + int lpxCol(Col c) const { return cols(id(c)); } + +#ifdef DOXYGEN + /// Write the problem or the solution to a file in the given format + + /// This function writes the problem or the solution + /// to a file in the given format. + /// Trying to write in an unsupported format will trigger + /// \ref LpBase::UnsupportedFormatError. + /// \param file The file path + /// \param format The output file format. + /// Supportted formats are "MPS" and "LP". + void write(std::string file, std::string format = "MPS") const {} +#endif + + }; + + /// \brief Interface for the GLPK LP solver + /// + /// This class implements an interface for the GLPK LP solver. + ///\ingroup lp_group + class GlpkLp : public LpSolver, public GlpkBase { + public: + + ///\e + GlpkLp(); + ///\e + GlpkLp(const GlpkLp&); + + ///\e + virtual GlpkLp* cloneSolver() const; + ///\e + virtual GlpkLp* newSolver() const; + + private: + + mutable std::vector _primal_ray; + mutable std::vector _dual_ray; + + void _clear_temporals(); + + protected: + + virtual const char* _solverName() const; + + virtual SolveExitStatus _solve(); + virtual Value _getPrimal(int i) const; + virtual Value _getDual(int i) const; + + virtual Value _getPrimalValue() const; + + virtual VarStatus _getColStatus(int i) const; + virtual VarStatus _getRowStatus(int i) const; + + virtual Value _getPrimalRay(int i) const; + virtual Value _getDualRay(int i) const; + + virtual ProblemType _getPrimalType() const; + virtual ProblemType _getDualType() const; + + public: + + ///Solve with primal simplex + SolveExitStatus solvePrimal(); + + ///Solve with dual simplex + SolveExitStatus solveDual(); + + private: + + bool _presolve; + + public: + + ///Turns on or off the presolver + + ///Turns on (\c b is \c true) or off (\c b is \c false) the presolver + /// + ///The presolver is off by default. + void presolver(bool presolve); + + }; + + /// \brief Interface for the GLPK MIP solver + /// + /// This class implements an interface for the GLPK MIP solver. + ///\ingroup lp_group + class GlpkMip : public MipSolver, public GlpkBase { + public: + + ///\e + GlpkMip(); + ///\e + GlpkMip(const GlpkMip&); + + virtual GlpkMip* cloneSolver() const; + virtual GlpkMip* newSolver() const; + + protected: + + virtual const char* _solverName() const; + + virtual ColTypes _getColType(int col) const; + virtual void _setColType(int col, ColTypes col_type); + + virtual SolveExitStatus _solve(); + virtual ProblemType _getType() const; + virtual Value _getSol(int i) const; + virtual Value _getSolValue() const; + + }; + + +} //END OF NAMESPACE LEMON + +#endif //LEMON_GLPK_H + diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/gomory_hu.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/gomory_hu.h new file mode 100644 index 00000000000..c43305f88e1 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/gomory_hu.h @@ -0,0 +1,568 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_GOMORY_HU_TREE_H +#define LEMON_GOMORY_HU_TREE_H + +#include + +#include +#include +#include +#include + +/// \ingroup min_cut +/// \file +/// \brief Gomory-Hu cut tree in graphs. + +namespace lemon { + + /// \ingroup min_cut + /// + /// \brief Gomory-Hu cut tree algorithm + /// + /// The Gomory-Hu tree is a tree on the node set of a given graph, but it + /// may contain edges which are not in the original graph. It has the + /// property that the minimum capacity edge of the path between two nodes + /// in this tree has the same weight as the minimum cut in the graph + /// between these nodes. Moreover the components obtained by removing + /// this edge from the tree determine the corresponding minimum cut. + /// Therefore once this tree is computed, the minimum cut between any pair + /// of nodes can easily be obtained. + /// + /// The algorithm calculates \e n-1 distinct minimum cuts (currently with + /// the \ref Preflow algorithm), thus it has \f$O(n^3\sqrt{m})\f$ overall + /// time complexity. It calculates a rooted Gomory-Hu tree. + /// The structure of the tree and the edge weights can be + /// obtained using \c predNode(), \c predValue() and \c rootDist(). + /// The functions \c minCutMap() and \c minCutValue() calculate + /// the minimum cut and the minimum cut value between any two nodes + /// in the graph. You can also list (iterate on) the nodes and the + /// edges of the cuts using \c MinCutNodeIt and \c MinCutEdgeIt. + /// + /// \tparam GR The type of the undirected graph the algorithm runs on. + /// \tparam CAP The type of the edge map containing the capacities. + /// The default map type is \ref concepts::Graph::EdgeMap "GR::EdgeMap". +#ifdef DOXYGEN + template +#else + template > +#endif + class GomoryHu { + public: + + /// The graph type of the algorithm + typedef GR Graph; + /// The capacity map type of the algorithm + typedef CAP Capacity; + /// The value type of capacities + typedef typename Capacity::Value Value; + + private: + + TEMPLATE_GRAPH_TYPEDEFS(Graph); + + const Graph& _graph; + const Capacity& _capacity; + + Node _root; + typename Graph::template NodeMap* _pred; + typename Graph::template NodeMap* _weight; + typename Graph::template NodeMap* _order; + + void createStructures() { + if (!_pred) { + _pred = new typename Graph::template NodeMap(_graph); + } + if (!_weight) { + _weight = new typename Graph::template NodeMap(_graph); + } + if (!_order) { + _order = new typename Graph::template NodeMap(_graph); + } + } + + void destroyStructures() { + if (_pred) { + delete _pred; + } + if (_weight) { + delete _weight; + } + if (_order) { + delete _order; + } + } + + public: + + /// \brief Constructor + /// + /// Constructor. + /// \param graph The undirected graph the algorithm runs on. + /// \param capacity The edge capacity map. + GomoryHu(const Graph& graph, const Capacity& capacity) + : _graph(graph), _capacity(capacity), + _pred(0), _weight(0), _order(0) + { + checkConcept, Capacity>(); + } + + + /// \brief Destructor + /// + /// Destructor. + ~GomoryHu() { + destroyStructures(); + } + + private: + + // Initialize the internal data structures + void init() { + createStructures(); + + _root = NodeIt(_graph); + for (NodeIt n(_graph); n != INVALID; ++n) { + (*_pred)[n] = _root; + (*_order)[n] = -1; + } + (*_pred)[_root] = INVALID; + (*_weight)[_root] = std::numeric_limits::max(); + } + + + // Start the algorithm + void start() { + Preflow fa(_graph, _capacity, _root, INVALID); + + for (NodeIt n(_graph); n != INVALID; ++n) { + if (n == _root) continue; + + Node pn = (*_pred)[n]; + fa.source(n); + fa.target(pn); + + fa.runMinCut(); + + (*_weight)[n] = fa.flowValue(); + + for (NodeIt nn(_graph); nn != INVALID; ++nn) { + if (nn != n && fa.minCut(nn) && (*_pred)[nn] == pn) { + (*_pred)[nn] = n; + } + } + if ((*_pred)[pn] != INVALID && fa.minCut((*_pred)[pn])) { + (*_pred)[n] = (*_pred)[pn]; + (*_pred)[pn] = n; + (*_weight)[n] = (*_weight)[pn]; + (*_weight)[pn] = fa.flowValue(); + } + } + + (*_order)[_root] = 0; + int index = 1; + + for (NodeIt n(_graph); n != INVALID; ++n) { + std::vector st; + Node nn = n; + while ((*_order)[nn] == -1) { + st.push_back(nn); + nn = (*_pred)[nn]; + } + while (!st.empty()) { + (*_order)[st.back()] = index++; + st.pop_back(); + } + } + } + + public: + + ///\name Execution Control + + ///@{ + + /// \brief Run the Gomory-Hu algorithm. + /// + /// This function runs the Gomory-Hu algorithm. + void run() { + init(); + start(); + } + + /// @} + + ///\name Query Functions + ///The results of the algorithm can be obtained using these + ///functions.\n + ///\ref run() should be called before using them.\n + ///See also \ref MinCutNodeIt and \ref MinCutEdgeIt. + + ///@{ + + /// \brief Return the predecessor node in the Gomory-Hu tree. + /// + /// This function returns the predecessor node of the given node + /// in the Gomory-Hu tree. + /// If \c node is the root of the tree, then it returns \c INVALID. + /// + /// \pre \ref run() must be called before using this function. + Node predNode(const Node& node) const { + return (*_pred)[node]; + } + + /// \brief Return the weight of the predecessor edge in the + /// Gomory-Hu tree. + /// + /// This function returns the weight of the predecessor edge of the + /// given node in the Gomory-Hu tree. + /// If \c node is the root of the tree, the result is undefined. + /// + /// \pre \ref run() must be called before using this function. + Value predValue(const Node& node) const { + return (*_weight)[node]; + } + + /// \brief Return the distance from the root node in the Gomory-Hu tree. + /// + /// This function returns the distance of the given node from the root + /// node in the Gomory-Hu tree. + /// + /// \pre \ref run() must be called before using this function. + int rootDist(const Node& node) const { + return (*_order)[node]; + } + + /// \brief Return the minimum cut value between two nodes + /// + /// This function returns the minimum cut value between the nodes + /// \c s and \c t. + /// It finds the nearest common ancestor of the given nodes in the + /// Gomory-Hu tree and calculates the minimum weight edge on the + /// paths to the ancestor. + /// + /// \pre \ref run() must be called before using this function. + Value minCutValue(const Node& s, const Node& t) const { + Node sn = s, tn = t; + Value value = std::numeric_limits::max(); + + while (sn != tn) { + if ((*_order)[sn] < (*_order)[tn]) { + if ((*_weight)[tn] <= value) value = (*_weight)[tn]; + tn = (*_pred)[tn]; + } else { + if ((*_weight)[sn] <= value) value = (*_weight)[sn]; + sn = (*_pred)[sn]; + } + } + return value; + } + + /// \brief Return the minimum cut between two nodes + /// + /// This function returns the minimum cut between the nodes \c s and \c t + /// in the \c cutMap parameter by setting the nodes in the component of + /// \c s to \c true and the other nodes to \c false. + /// + /// For higher level interfaces see MinCutNodeIt and MinCutEdgeIt. + /// + /// \param s The base node. + /// \param t The node you want to separate from node \c s. + /// \param cutMap The cut will be returned in this map. + /// It must be a \c bool (or convertible) \ref concepts::ReadWriteMap + /// "ReadWriteMap" on the graph nodes. + /// + /// \return The value of the minimum cut between \c s and \c t. + /// + /// \pre \ref run() must be called before using this function. + template + Value minCutMap(const Node& s, + const Node& t, + CutMap& cutMap + ) const { + Node sn = s, tn = t; + bool s_root=false; + Node rn = INVALID; + Value value = std::numeric_limits::max(); + + while (sn != tn) { + if ((*_order)[sn] < (*_order)[tn]) { + if ((*_weight)[tn] <= value) { + rn = tn; + s_root = false; + value = (*_weight)[tn]; + } + tn = (*_pred)[tn]; + } else { + if ((*_weight)[sn] <= value) { + rn = sn; + s_root = true; + value = (*_weight)[sn]; + } + sn = (*_pred)[sn]; + } + } + + typename Graph::template NodeMap reached(_graph, false); + reached[_root] = true; + cutMap.set(_root, !s_root); + reached[rn] = true; + cutMap.set(rn, s_root); + + std::vector st; + for (NodeIt n(_graph); n != INVALID; ++n) { + st.clear(); + Node nn = n; + while (!reached[nn]) { + st.push_back(nn); + nn = (*_pred)[nn]; + } + while (!st.empty()) { + cutMap.set(st.back(), cutMap[nn]); + st.pop_back(); + } + } + + return value; + } + + ///@} + + friend class MinCutNodeIt; + + /// Iterate on the nodes of a minimum cut + + /// This iterator class lists the nodes of a minimum cut found by + /// GomoryHu. Before using it, you must allocate a GomoryHu class + /// and call its \ref GomoryHu::run() "run()" method. + /// + /// This example counts the nodes in the minimum cut separating \c s from + /// \c t. + /// \code + /// GomoryHu gom(g, capacities); + /// gom.run(); + /// int cnt=0; + /// for(GomoryHu::MinCutNodeIt n(gom,s,t); n!=INVALID; ++n) ++cnt; + /// \endcode + class MinCutNodeIt + { + bool _side; + typename Graph::NodeIt _node_it; + typename Graph::template NodeMap _cut; + public: + /// Constructor + + /// Constructor. + /// + MinCutNodeIt(GomoryHu const &gomory, + ///< The GomoryHu class. You must call its + /// run() method + /// before initializing this iterator. + const Node& s, ///< The base node. + const Node& t, + ///< The node you want to separate from node \c s. + bool side=true + ///< If it is \c true (default) then the iterator lists + /// the nodes of the component containing \c s, + /// otherwise it lists the other component. + /// \note As the minimum cut is not always unique, + /// \code + /// MinCutNodeIt(gomory, s, t, true); + /// \endcode + /// and + /// \code + /// MinCutNodeIt(gomory, t, s, false); + /// \endcode + /// does not necessarily give the same set of nodes. + /// However, it is ensured that + /// \code + /// MinCutNodeIt(gomory, s, t, true); + /// \endcode + /// and + /// \code + /// MinCutNodeIt(gomory, s, t, false); + /// \endcode + /// together list each node exactly once. + ) + : _side(side), _cut(gomory._graph) + { + gomory.minCutMap(s,t,_cut); + for(_node_it=typename Graph::NodeIt(gomory._graph); + _node_it!=INVALID && _cut[_node_it]!=_side; + ++_node_it) {} + } + /// Conversion to \c Node + + /// Conversion to \c Node. + /// + operator typename Graph::Node() const + { + return _node_it; + } + bool operator==(Invalid) { return _node_it==INVALID; } + bool operator!=(Invalid) { return _node_it!=INVALID; } + /// Next node + + /// Next node. + /// + MinCutNodeIt &operator++() + { + for(++_node_it;_node_it!=INVALID&&_cut[_node_it]!=_side;++_node_it) {} + return *this; + } + /// Postfix incrementation + + /// Postfix incrementation. + /// + /// \warning This incrementation + /// returns a \c Node, not a \c MinCutNodeIt, as one may + /// expect. + typename Graph::Node operator++(int) + { + typename Graph::Node n=*this; + ++(*this); + return n; + } + }; + + friend class MinCutEdgeIt; + + /// Iterate on the edges of a minimum cut + + /// This iterator class lists the edges of a minimum cut found by + /// GomoryHu. Before using it, you must allocate a GomoryHu class + /// and call its \ref GomoryHu::run() "run()" method. + /// + /// This example computes the value of the minimum cut separating \c s from + /// \c t. + /// \code + /// GomoryHu gom(g, capacities); + /// gom.run(); + /// int value=0; + /// for(GomoryHu::MinCutEdgeIt e(gom,s,t); e!=INVALID; ++e) + /// value+=capacities[e]; + /// \endcode + /// The result will be the same as the value returned by + /// \ref GomoryHu::minCutValue() "gom.minCutValue(s,t)". + class MinCutEdgeIt + { + bool _side; + const Graph &_graph; + typename Graph::NodeIt _node_it; + typename Graph::OutArcIt _arc_it; + typename Graph::template NodeMap _cut; + void step() + { + ++_arc_it; + while(_node_it!=INVALID && _arc_it==INVALID) + { + for(++_node_it;_node_it!=INVALID&&!_cut[_node_it];++_node_it) {} + if(_node_it!=INVALID) + _arc_it=typename Graph::OutArcIt(_graph,_node_it); + } + } + + public: + /// Constructor + + /// Constructor. + /// + MinCutEdgeIt(GomoryHu const &gomory, + ///< The GomoryHu class. You must call its + /// run() method + /// before initializing this iterator. + const Node& s, ///< The base node. + const Node& t, + ///< The node you want to separate from node \c s. + bool side=true + ///< If it is \c true (default) then the listed arcs + /// will be oriented from the + /// nodes of the component containing \c s, + /// otherwise they will be oriented in the opposite + /// direction. + ) + : _graph(gomory._graph), _cut(_graph) + { + gomory.minCutMap(s,t,_cut); + if(!side) + for(typename Graph::NodeIt n(_graph);n!=INVALID;++n) + _cut[n]=!_cut[n]; + + for(_node_it=typename Graph::NodeIt(_graph); + _node_it!=INVALID && !_cut[_node_it]; + ++_node_it) {} + _arc_it = _node_it!=INVALID ? + typename Graph::OutArcIt(_graph,_node_it) : INVALID; + while(_node_it!=INVALID && _arc_it == INVALID) + { + for(++_node_it; _node_it!=INVALID&&!_cut[_node_it]; ++_node_it) {} + if(_node_it!=INVALID) + _arc_it= typename Graph::OutArcIt(_graph,_node_it); + } + while(_arc_it!=INVALID && _cut[_graph.target(_arc_it)]) step(); + } + /// Conversion to \c Arc + + /// Conversion to \c Arc. + /// + operator typename Graph::Arc() const + { + return _arc_it; + } + /// Conversion to \c Edge + + /// Conversion to \c Edge. + /// + operator typename Graph::Edge() const + { + return _arc_it; + } + bool operator==(Invalid) { return _node_it==INVALID; } + bool operator!=(Invalid) { return _node_it!=INVALID; } + /// Next edge + + /// Next edge. + /// + MinCutEdgeIt &operator++() + { + step(); + while(_arc_it!=INVALID && _cut[_graph.target(_arc_it)]) step(); + return *this; + } + /// Postfix incrementation + + /// Postfix incrementation. + /// + /// \warning This incrementation + /// returns an \c Arc, not a \c MinCutEdgeIt, as one may expect. + typename Graph::Arc operator++(int) + { + typename Graph::Arc e=*this; + ++(*this); + return e; + } + }; + + }; + +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/graph_to_eps.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/graph_to_eps.h new file mode 100644 index 00000000000..29ba836937d --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/graph_to_eps.h @@ -0,0 +1,1186 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_GRAPH_TO_EPS_H +#define LEMON_GRAPH_TO_EPS_H + +#include +#include +#include +#include +#include + +#ifndef WIN32 +#include +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + + +///\ingroup eps_io +///\file +///\brief A well configurable tool for visualizing graphs + +namespace lemon { + + namespace _graph_to_eps_bits { + template + class _NegY { + public: + typedef typename MT::Key Key; + typedef typename MT::Value Value; + const MT ↦ + int yscale; + _NegY(const MT &m,bool b) : map(m), yscale(1-b*2) {} + Value operator[](Key n) { return Value(map[n].x,map[n].y*yscale);} + }; + } + +///Default traits class of GraphToEps + +///Default traits class of \ref GraphToEps. +/// +///\param GR is the type of the underlying graph. +template +struct DefaultGraphToEpsTraits +{ + typedef GR Graph; + typedef GR Digraph; + typedef typename Graph::Node Node; + typedef typename Graph::NodeIt NodeIt; + typedef typename Graph::Arc Arc; + typedef typename Graph::ArcIt ArcIt; + typedef typename Graph::InArcIt InArcIt; + typedef typename Graph::OutArcIt OutArcIt; + + + const Graph &g; + + std::ostream& os; + + typedef ConstMap > CoordsMapType; + CoordsMapType _coords; + ConstMap _nodeSizes; + ConstMap _nodeShapes; + + ConstMap _nodeColors; + ConstMap _arcColors; + + ConstMap _arcWidths; + + double _arcWidthScale; + + double _nodeScale; + double _xBorder, _yBorder; + double _scale; + double _nodeBorderQuotient; + + bool _drawArrows; + double _arrowLength, _arrowWidth; + + bool _showNodes, _showArcs; + + bool _enableParallel; + double _parArcDist; + + bool _showNodeText; + ConstMap _nodeTexts; + double _nodeTextSize; + + bool _showNodePsText; + ConstMap _nodePsTexts; + char *_nodePsTextsPreamble; + + bool _undirected; + + bool _pleaseRemoveOsStream; + + bool _scaleToA4; + + std::string _title; + std::string _copyright; + + enum NodeTextColorType + { DIST_COL=0, DIST_BW=1, CUST_COL=2, SAME_COL=3 } _nodeTextColorType; + ConstMap _nodeTextColors; + + bool _autoNodeScale; + bool _autoArcWidthScale; + + bool _absoluteNodeSizes; + bool _absoluteArcWidths; + + bool _negY; + + bool _preScale; + ///Constructor + + ///Constructor + ///\param gr Reference to the graph to be printed. + ///\param ost Reference to the output stream. + ///By default, it is std::cout. + ///\param pros If it is \c true, then the \c ostream referenced by \c os + ///will be explicitly deallocated by the destructor. + DefaultGraphToEpsTraits(const GR &gr, std::ostream& ost = std::cout, + bool pros = false) : + g(gr), os(ost), + _coords(dim2::Point(1,1)), _nodeSizes(1), _nodeShapes(0), + _nodeColors(WHITE), _arcColors(BLACK), + _arcWidths(1.0), _arcWidthScale(0.003), + _nodeScale(.01), _xBorder(10), _yBorder(10), _scale(1.0), + _nodeBorderQuotient(.1), + _drawArrows(false), _arrowLength(1), _arrowWidth(0.3), + _showNodes(true), _showArcs(true), + _enableParallel(false), _parArcDist(1), + _showNodeText(false), _nodeTexts(false), _nodeTextSize(1), + _showNodePsText(false), _nodePsTexts(false), _nodePsTextsPreamble(0), + _undirected(lemon::UndirectedTagIndicator::value), + _pleaseRemoveOsStream(pros), _scaleToA4(false), + _nodeTextColorType(SAME_COL), _nodeTextColors(BLACK), + _autoNodeScale(false), + _autoArcWidthScale(false), + _absoluteNodeSizes(false), + _absoluteArcWidths(false), + _negY(false), + _preScale(true) + {} +}; + +///Auxiliary class to implement the named parameters of \ref graphToEps() + +///Auxiliary class to implement the named parameters of \ref graphToEps(). +/// +///For detailed examples see the \ref graph_to_eps_demo.cc demo file. +template class GraphToEps : public T +{ + // Can't believe it is required by the C++ standard + using T::g; + using T::os; + + using T::_coords; + using T::_nodeSizes; + using T::_nodeShapes; + using T::_nodeColors; + using T::_arcColors; + using T::_arcWidths; + + using T::_arcWidthScale; + using T::_nodeScale; + using T::_xBorder; + using T::_yBorder; + using T::_scale; + using T::_nodeBorderQuotient; + + using T::_drawArrows; + using T::_arrowLength; + using T::_arrowWidth; + + using T::_showNodes; + using T::_showArcs; + + using T::_enableParallel; + using T::_parArcDist; + + using T::_showNodeText; + using T::_nodeTexts; + using T::_nodeTextSize; + + using T::_showNodePsText; + using T::_nodePsTexts; + using T::_nodePsTextsPreamble; + + using T::_undirected; + + using T::_pleaseRemoveOsStream; + + using T::_scaleToA4; + + using T::_title; + using T::_copyright; + + using T::CUST_COL; + using T::DIST_COL; + using T::DIST_BW; + using T::_nodeTextColorType; + using T::_nodeTextColors; + + using T::_autoNodeScale; + using T::_autoArcWidthScale; + + using T::_absoluteNodeSizes; + using T::_absoluteArcWidths; + + + using T::_negY; + using T::_preScale; + + // dradnats ++C eht yb deriuqer si ti eveileb t'naC + + typedef typename T::Graph Graph; + typedef typename T::Digraph Digraph; + typedef typename Graph::Node Node; + typedef typename Graph::NodeIt NodeIt; + typedef typename Graph::Arc Arc; + typedef typename Graph::ArcIt ArcIt; + typedef typename Graph::InArcIt InArcIt; + typedef typename Graph::OutArcIt OutArcIt; + + static const int INTERPOL_PREC; + static const double A4HEIGHT; + static const double A4WIDTH; + static const double A4BORDER; + + bool dontPrint; + +public: + ///Node shapes + + ///Node shapes. + /// + enum NodeShapes { + /// = 0 + ///\image html nodeshape_0.png + ///\image latex nodeshape_0.eps "CIRCLE shape (0)" width=2cm + CIRCLE=0, + /// = 1 + ///\image html nodeshape_1.png + ///\image latex nodeshape_1.eps "SQUARE shape (1)" width=2cm + SQUARE=1, + /// = 2 + ///\image html nodeshape_2.png + ///\image latex nodeshape_2.eps "DIAMOND shape (2)" width=2cm + DIAMOND=2, + /// = 3 + ///\image html nodeshape_3.png + ///\image latex nodeshape_3.eps "MALE shape (3)" width=2cm + MALE=3, + /// = 4 + ///\image html nodeshape_4.png + ///\image latex nodeshape_4.eps "FEMALE shape (4)" width=2cm + FEMALE=4 + }; + +private: + class arcLess { + const Graph &g; + public: + arcLess(const Graph &_g) : g(_g) {} + bool operator()(Arc a,Arc b) const + { + Node ai=std::min(g.source(a),g.target(a)); + Node aa=std::max(g.source(a),g.target(a)); + Node bi=std::min(g.source(b),g.target(b)); + Node ba=std::max(g.source(b),g.target(b)); + return ai + static std::string psOut(const dim2::Point &p) + { + std::ostringstream os; + os << p.x << ' ' << p.y; + return os.str(); + } + static std::string psOut(const Color &c) + { + std::ostringstream os; + os << c.red() << ' ' << c.green() << ' ' << c.blue(); + return os.str(); + } + +public: + GraphToEps(const T &t) : T(t), dontPrint(false) {}; + + template struct CoordsTraits : public T { + typedef X CoordsMapType; + const X &_coords; + CoordsTraits(const T &t,const X &x) : T(t), _coords(x) {} + }; + ///Sets the map of the node coordinates + + ///Sets the map of the node coordinates. + ///\param x must be a node map with \ref dim2::Point "dim2::Point" or + ///\ref dim2::Point "dim2::Point" values. + template GraphToEps > coords(const X &x) { + dontPrint=true; + return GraphToEps >(CoordsTraits(*this,x)); + } + template struct NodeSizesTraits : public T { + const X &_nodeSizes; + NodeSizesTraits(const T &t,const X &x) : T(t), _nodeSizes(x) {} + }; + ///Sets the map of the node sizes + + ///Sets the map of the node sizes. + ///\param x must be a node map with \c double (or convertible) values. + template GraphToEps > nodeSizes(const X &x) + { + dontPrint=true; + return GraphToEps >(NodeSizesTraits(*this,x)); + } + template struct NodeShapesTraits : public T { + const X &_nodeShapes; + NodeShapesTraits(const T &t,const X &x) : T(t), _nodeShapes(x) {} + }; + ///Sets the map of the node shapes + + ///Sets the map of the node shapes. + ///The available shape values + ///can be found in \ref NodeShapes "enum NodeShapes". + ///\param x must be a node map with \c int (or convertible) values. + ///\sa NodeShapes + template GraphToEps > nodeShapes(const X &x) + { + dontPrint=true; + return GraphToEps >(NodeShapesTraits(*this,x)); + } + template struct NodeTextsTraits : public T { + const X &_nodeTexts; + NodeTextsTraits(const T &t,const X &x) : T(t), _nodeTexts(x) {} + }; + ///Sets the text printed on the nodes + + ///Sets the text printed on the nodes. + ///\param x must be a node map with type that can be pushed to a standard + ///\c ostream. + template GraphToEps > nodeTexts(const X &x) + { + dontPrint=true; + _showNodeText=true; + return GraphToEps >(NodeTextsTraits(*this,x)); + } + template struct NodePsTextsTraits : public T { + const X &_nodePsTexts; + NodePsTextsTraits(const T &t,const X &x) : T(t), _nodePsTexts(x) {} + }; + ///Inserts a PostScript block to the nodes + + ///With this command it is possible to insert a verbatim PostScript + ///block to the nodes. + ///The PS current point will be moved to the center of the node before + ///the PostScript block inserted. + /// + ///Before and after the block a newline character is inserted so you + ///don't have to bother with the separators. + /// + ///\param x must be a node map with type that can be pushed to a standard + ///\c ostream. + /// + ///\sa nodePsTextsPreamble() + template GraphToEps > nodePsTexts(const X &x) + { + dontPrint=true; + _showNodePsText=true; + return GraphToEps >(NodePsTextsTraits(*this,x)); + } + template struct ArcWidthsTraits : public T { + const X &_arcWidths; + ArcWidthsTraits(const T &t,const X &x) : T(t), _arcWidths(x) {} + }; + ///Sets the map of the arc widths + + ///Sets the map of the arc widths. + ///\param x must be an arc map with \c double (or convertible) values. + template GraphToEps > arcWidths(const X &x) + { + dontPrint=true; + return GraphToEps >(ArcWidthsTraits(*this,x)); + } + + template struct NodeColorsTraits : public T { + const X &_nodeColors; + NodeColorsTraits(const T &t,const X &x) : T(t), _nodeColors(x) {} + }; + ///Sets the map of the node colors + + ///Sets the map of the node colors. + ///\param x must be a node map with \ref Color values. + /// + ///\sa Palette + template GraphToEps > + nodeColors(const X &x) + { + dontPrint=true; + return GraphToEps >(NodeColorsTraits(*this,x)); + } + template struct NodeTextColorsTraits : public T { + const X &_nodeTextColors; + NodeTextColorsTraits(const T &t,const X &x) : T(t), _nodeTextColors(x) {} + }; + ///Sets the map of the node text colors + + ///Sets the map of the node text colors. + ///\param x must be a node map with \ref Color values. + /// + ///\sa Palette + template GraphToEps > + nodeTextColors(const X &x) + { + dontPrint=true; + _nodeTextColorType=CUST_COL; + return GraphToEps > + (NodeTextColorsTraits(*this,x)); + } + template struct ArcColorsTraits : public T { + const X &_arcColors; + ArcColorsTraits(const T &t,const X &x) : T(t), _arcColors(x) {} + }; + ///Sets the map of the arc colors + + ///Sets the map of the arc colors. + ///\param x must be an arc map with \ref Color values. + /// + ///\sa Palette + template GraphToEps > + arcColors(const X &x) + { + dontPrint=true; + return GraphToEps >(ArcColorsTraits(*this,x)); + } + ///Sets a global scale factor for node sizes + + ///Sets a global scale factor for node sizes. + /// + /// If nodeSizes() is not given, this function simply sets the node + /// sizes to \c d. If nodeSizes() is given, but + /// autoNodeScale() is not, then the node size given by + /// nodeSizes() will be multiplied by the value \c d. + /// If both nodeSizes() and autoNodeScale() are used, then the + /// node sizes will be scaled in such a way that the greatest size will be + /// equal to \c d. + /// \sa nodeSizes() + /// \sa autoNodeScale() + GraphToEps &nodeScale(double d=.01) {_nodeScale=d;return *this;} + ///Turns on/off the automatic node size scaling. + + ///Turns on/off the automatic node size scaling. + /// + ///\sa nodeScale() + /// + GraphToEps &autoNodeScale(bool b=true) { + _autoNodeScale=b;return *this; + } + + ///Turns on/off the absolutematic node size scaling. + + ///Turns on/off the absolutematic node size scaling. + /// + ///\sa nodeScale() + /// + GraphToEps &absoluteNodeSizes(bool b=true) { + _absoluteNodeSizes=b;return *this; + } + + ///Negates the Y coordinates. + GraphToEps &negateY(bool b=true) { + _negY=b;return *this; + } + + ///Turn on/off pre-scaling + + ///By default, graphToEps() rescales the whole image in order to avoid + ///very big or very small bounding boxes. + /// + ///This (p)rescaling can be turned off with this function. + /// + GraphToEps &preScale(bool b=true) { + _preScale=b;return *this; + } + + ///Sets a global scale factor for arc widths + + /// Sets a global scale factor for arc widths. + /// + /// If arcWidths() is not given, this function simply sets the arc + /// widths to \c d. If arcWidths() is given, but + /// autoArcWidthScale() is not, then the arc withs given by + /// arcWidths() will be multiplied by the value \c d. + /// If both arcWidths() and autoArcWidthScale() are used, then the + /// arc withs will be scaled in such a way that the greatest width will be + /// equal to \c d. + GraphToEps &arcWidthScale(double d=.003) {_arcWidthScale=d;return *this;} + ///Turns on/off the automatic arc width scaling. + + ///Turns on/off the automatic arc width scaling. + /// + ///\sa arcWidthScale() + /// + GraphToEps &autoArcWidthScale(bool b=true) { + _autoArcWidthScale=b;return *this; + } + ///Turns on/off the absolutematic arc width scaling. + + ///Turns on/off the absolutematic arc width scaling. + /// + ///\sa arcWidthScale() + /// + GraphToEps &absoluteArcWidths(bool b=true) { + _absoluteArcWidths=b;return *this; + } + ///Sets a global scale factor for the whole picture + GraphToEps &scale(double d) {_scale=d;return *this;} + ///Sets the width of the border around the picture + GraphToEps &border(double b=10) {_xBorder=_yBorder=b;return *this;} + ///Sets the width of the border around the picture + GraphToEps &border(double x, double y) { + _xBorder=x;_yBorder=y;return *this; + } + ///Sets whether to draw arrows + GraphToEps &drawArrows(bool b=true) {_drawArrows=b;return *this;} + ///Sets the length of the arrowheads + GraphToEps &arrowLength(double d=1.0) {_arrowLength*=d;return *this;} + ///Sets the width of the arrowheads + GraphToEps &arrowWidth(double d=.3) {_arrowWidth*=d;return *this;} + + ///Scales the drawing to fit to A4 page + GraphToEps &scaleToA4() {_scaleToA4=true;return *this;} + + ///Enables parallel arcs + GraphToEps &enableParallel(bool b=true) {_enableParallel=b;return *this;} + + ///Sets the distance between parallel arcs + GraphToEps &parArcDist(double d) {_parArcDist*=d;return *this;} + + ///Hides the arcs + GraphToEps &hideArcs(bool b=true) {_showArcs=!b;return *this;} + ///Hides the nodes + GraphToEps &hideNodes(bool b=true) {_showNodes=!b;return *this;} + + ///Sets the size of the node texts + GraphToEps &nodeTextSize(double d) {_nodeTextSize=d;return *this;} + + ///Sets the color of the node texts to be different from the node color + + ///Sets the color of the node texts to be as different from the node color + ///as it is possible. + GraphToEps &distantColorNodeTexts() + {_nodeTextColorType=DIST_COL;return *this;} + ///Sets the color of the node texts to be black or white and always visible. + + ///Sets the color of the node texts to be black or white according to + ///which is more different from the node color. + GraphToEps &distantBWNodeTexts() + {_nodeTextColorType=DIST_BW;return *this;} + + ///Gives a preamble block for node Postscript block. + + ///Gives a preamble block for node Postscript block. + /// + ///\sa nodePsTexts() + GraphToEps & nodePsTextsPreamble(const char *str) { + _nodePsTextsPreamble=str ;return *this; + } + ///Sets whether the graph is undirected + + ///Sets whether the graph is undirected. + /// + ///This setting is the default for undirected graphs. + /// + ///\sa directed() + GraphToEps &undirected(bool b=true) {_undirected=b;return *this;} + + ///Sets whether the graph is directed + + ///Sets whether the graph is directed. + ///Use it to show the edges as a pair of directed ones. + /// + ///This setting is the default for digraphs. + /// + ///\sa undirected() + GraphToEps &directed(bool b=true) {_undirected=!b;return *this;} + + ///Sets the title. + + ///Sets the title of the generated image, + ///namely it inserts a %%Title: DSC field to the header of + ///the EPS file. + GraphToEps &title(const std::string &t) {_title=t;return *this;} + ///Sets the copyright statement. + + ///Sets the copyright statement of the generated image, + ///namely it inserts a %%Copyright: DSC field to the header of + ///the EPS file. + GraphToEps ©right(const std::string &t) {_copyright=t;return *this;} + +protected: + bool isInsideNode(dim2::Point p, double r,int t) + { + switch(t) { + case CIRCLE: + case MALE: + case FEMALE: + return p.normSquare()<=r*r; + case SQUARE: + return p.x<=r&&p.x>=-r&&p.y<=r&&p.y>=-r; + case DIAMOND: + return p.x+p.y<=r && p.x-p.y<=r && -p.x+p.y<=r && -p.x-p.y<=r; + } + return false; + } + +public: + ~GraphToEps() { } + + ///Draws the graph. + + ///Like other functions using + ///\ref named-templ-func-param "named template parameters", + ///this function calls the algorithm itself, i.e. in this case + ///it draws the graph. + void run() { + const double EPSILON=1e-9; + if(dontPrint) return; + + _graph_to_eps_bits::_NegY + mycoords(_coords,_negY); + + os << "%!PS-Adobe-2.0 EPSF-2.0\n"; + if(_title.size()>0) os << "%%Title: " << _title << '\n'; + if(_copyright.size()>0) os << "%%Copyright: " << _copyright << '\n'; + os << "%%Creator: LEMON, graphToEps()\n"; + + { + os << "%%CreationDate: "; +#ifndef WIN32 + timeval tv; + gettimeofday(&tv, 0); + + char cbuf[26]; + ctime_r(&tv.tv_sec,cbuf); + os << cbuf; +#else + os << bits::getWinFormattedDate(); + os << std::endl; +#endif + } + + if (_autoArcWidthScale) { + double max_w=0; + for(ArcIt e(g);e!=INVALID;++e) + max_w=std::max(double(_arcWidths[e]),max_w); + if(max_w>EPSILON) { + _arcWidthScale/=max_w; + } + } + + if (_autoNodeScale) { + double max_s=0; + for(NodeIt n(g);n!=INVALID;++n) + max_s=std::max(double(_nodeSizes[n]),max_s); + if(max_s>EPSILON) { + _nodeScale/=max_s; + } + } + + double diag_len = 1; + if(!(_absoluteNodeSizes&&_absoluteArcWidths)) { + dim2::Box bb; + for(NodeIt n(g);n!=INVALID;++n) bb.add(mycoords[n]); + if (bb.empty()) { + bb = dim2::Box(dim2::Point(0,0)); + } + diag_len = std::sqrt((bb.bottomLeft()-bb.topRight()).normSquare()); + if(diag_len bb; + for(NodeIt n(g);n!=INVALID;++n) { + double ns=_nodeSizes[n]*_nodeScale; + dim2::Point p(ns,ns); + switch(_nodeShapes[n]) { + case CIRCLE: + case SQUARE: + case DIAMOND: + bb.add(p+mycoords[n]); + bb.add(-p+mycoords[n]); + break; + case MALE: + bb.add(-p+mycoords[n]); + bb.add(dim2::Point(1.5*ns,1.5*std::sqrt(3.0)*ns)+mycoords[n]); + break; + case FEMALE: + bb.add(p+mycoords[n]); + bb.add(dim2::Point(-ns,-3.01*ns)+mycoords[n]); + break; + } + } + if (bb.empty()) { + bb = dim2::Box(dim2::Point(0,0)); + } + + if(_scaleToA4) + os <<"%%BoundingBox: 0 0 596 842\n%%DocumentPaperSizes: a4\n"; + else { + if(_preScale) { + //Rescale so that BoundingBox won't be neither to big nor too small. + while(bb.height()*_scale>1000||bb.width()*_scale>1000) _scale/=10; + while(bb.height()*_scale<100||bb.width()*_scale<100) _scale*=10; + } + + os << "%%BoundingBox: " + << int(floor(bb.left() * _scale - _xBorder)) << ' ' + << int(floor(bb.bottom() * _scale - _yBorder)) << ' ' + << int(ceil(bb.right() * _scale + _xBorder)) << ' ' + << int(ceil(bb.top() * _scale + _yBorder)) << '\n'; + } + + os << "%%EndComments\n"; + + //x1 y1 x2 y2 x3 y3 cr cg cb w + os << "/lb { setlinewidth setrgbcolor newpath moveto\n" + << " 4 2 roll 1 index 1 index curveto stroke } bind def\n"; + os << "/l { setlinewidth setrgbcolor newpath moveto lineto stroke }" + << " bind def\n"; + //x y r + os << "/c { newpath dup 3 index add 2 index moveto 0 360 arc closepath }" + << " bind def\n"; + //x y r + os << "/sq { newpath 2 index 1 index add 2 index 2 index add moveto\n" + << " 2 index 1 index sub 2 index 2 index add lineto\n" + << " 2 index 1 index sub 2 index 2 index sub lineto\n" + << " 2 index 1 index add 2 index 2 index sub lineto\n" + << " closepath pop pop pop} bind def\n"; + //x y r + os << "/di { newpath 2 index 1 index add 2 index moveto\n" + << " 2 index 2 index 2 index add lineto\n" + << " 2 index 1 index sub 2 index lineto\n" + << " 2 index 2 index 2 index sub lineto\n" + << " closepath pop pop pop} bind def\n"; + // x y r cr cg cb + os << "/nc { 0 0 0 setrgbcolor 5 index 5 index 5 index c fill\n" + << " setrgbcolor " << 1+_nodeBorderQuotient << " div c fill\n" + << " } bind def\n"; + os << "/nsq { 0 0 0 setrgbcolor 5 index 5 index 5 index sq fill\n" + << " setrgbcolor " << 1+_nodeBorderQuotient << " div sq fill\n" + << " } bind def\n"; + os << "/ndi { 0 0 0 setrgbcolor 5 index 5 index 5 index di fill\n" + << " setrgbcolor " << 1+_nodeBorderQuotient << " div di fill\n" + << " } bind def\n"; + os << "/nfemale { 0 0 0 setrgbcolor 3 index " + << _nodeBorderQuotient/(1+_nodeBorderQuotient) + << " 1.5 mul mul setlinewidth\n" + << " newpath 5 index 5 index moveto " + << "5 index 5 index 5 index 3.01 mul sub\n" + << " lineto 5 index 4 index .7 mul sub 5 index 5 index 2.2 mul sub" + << " moveto\n" + << " 5 index 4 index .7 mul add 5 index 5 index 2.2 mul sub lineto " + << "stroke\n" + << " 5 index 5 index 5 index c fill\n" + << " setrgbcolor " << 1+_nodeBorderQuotient << " div c fill\n" + << " } bind def\n"; + os << "/nmale {\n" + << " 0 0 0 setrgbcolor 3 index " + << _nodeBorderQuotient/(1+_nodeBorderQuotient) + <<" 1.5 mul mul setlinewidth\n" + << " newpath 5 index 5 index moveto\n" + << " 5 index 4 index 1 mul 1.5 mul add\n" + << " 5 index 5 index 3 sqrt 1.5 mul mul add\n" + << " 1 index 1 index lineto\n" + << " 1 index 1 index 7 index sub moveto\n" + << " 1 index 1 index lineto\n" + << " exch 5 index 3 sqrt .5 mul mul sub exch 5 index .5 mul sub" + << " lineto\n" + << " stroke\n" + << " 5 index 5 index 5 index c fill\n" + << " setrgbcolor " << 1+_nodeBorderQuotient << " div c fill\n" + << " } bind def\n"; + + + os << "/arrl " << _arrowLength << " def\n"; + os << "/arrw " << _arrowWidth << " def\n"; + // l dx_norm dy_norm + os << "/lrl { 2 index mul exch 2 index mul exch rlineto pop} bind def\n"; + //len w dx_norm dy_norm x1 y1 cr cg cb + os << "/arr { setrgbcolor /y1 exch def /x1 exch def /dy exch def /dx " + << "exch def\n" + << " /w exch def /len exch def\n" + //<< "0.1 setlinewidth x1 y1 moveto dx len mul dy len mul rlineto stroke" + << " newpath x1 dy w 2 div mul add y1 dx w 2 div mul sub moveto\n" + << " len w sub arrl sub dx dy lrl\n" + << " arrw dy dx neg lrl\n" + << " dx arrl w add mul dy w 2 div arrw add mul sub\n" + << " dy arrl w add mul dx w 2 div arrw add mul add rlineto\n" + << " dx arrl w add mul neg dy w 2 div arrw add mul sub\n" + << " dy arrl w add mul neg dx w 2 div arrw add mul add rlineto\n" + << " arrw dy dx neg lrl\n" + << " len w sub arrl sub neg dx dy lrl\n" + << " closepath fill } bind def\n"; + os << "/cshow { 2 index 2 index moveto dup stringwidth pop\n" + << " neg 2 div fosi .35 mul neg rmoveto show pop pop} def\n"; + + os << "\ngsave\n"; + if(_scaleToA4) + if(bb.height()>bb.width()) { + double sc= std::min((A4HEIGHT-2*A4BORDER)/bb.height(), + (A4WIDTH-2*A4BORDER)/bb.width()); + os << ((A4WIDTH -2*A4BORDER)-sc*bb.width())/2 + A4BORDER << ' ' + << ((A4HEIGHT-2*A4BORDER)-sc*bb.height())/2 + A4BORDER + << " translate\n" + << sc << " dup scale\n" + << -bb.left() << ' ' << -bb.bottom() << " translate\n"; + } + else { + double sc= std::min((A4HEIGHT-2*A4BORDER)/bb.width(), + (A4WIDTH-2*A4BORDER)/bb.height()); + os << ((A4WIDTH -2*A4BORDER)-sc*bb.height())/2 + A4BORDER << ' ' + << ((A4HEIGHT-2*A4BORDER)-sc*bb.width())/2 + A4BORDER + << " translate\n" + << sc << " dup scale\n90 rotate\n" + << -bb.left() << ' ' << -bb.top() << " translate\n"; + } + else if(_scale!=1.0) os << _scale << " dup scale\n"; + + if(_showArcs) { + os << "%Arcs:\ngsave\n"; + if(_enableParallel) { + std::vector el; + for(ArcIt e(g);e!=INVALID;++e) + if((!_undirected||g.source(e)0 + &&g.source(e)!=g.target(e)) + el.push_back(e); + std::sort(el.begin(),el.end(),arcLess(g)); + + typename std::vector::iterator j; + for(typename std::vector::iterator i=el.begin();i!=el.end();i=j) { + for(j=i+1;j!=el.end()&&isParallel(*i,*j);++j) ; + + double sw=0; + for(typename std::vector::iterator e=i;e!=j;++e) + sw+=_arcWidths[*e]*_arcWidthScale+_parArcDist; + sw-=_parArcDist; + sw/=-2.0; + dim2::Point + dvec(mycoords[g.target(*i)]-mycoords[g.source(*i)]); + double l=std::sqrt(dvec.normSquare()); + dim2::Point d(dvec/std::max(l,EPSILON)); + dim2::Point m; +// m=dim2::Point(mycoords[g.target(*i)]+ +// mycoords[g.source(*i)])/2.0; + +// m=dim2::Point(mycoords[g.source(*i)])+ +// dvec*(double(_nodeSizes[g.source(*i)])/ +// (_nodeSizes[g.source(*i)]+_nodeSizes[g.target(*i)])); + + m=dim2::Point(mycoords[g.source(*i)])+ + d*(l+_nodeSizes[g.source(*i)]-_nodeSizes[g.target(*i)])/2.0; + + for(typename std::vector::iterator e=i;e!=j;++e) { + sw+=_arcWidths[*e]*_arcWidthScale/2.0; + dim2::Point mm=m+rot90(d)*sw/.75; + if(_drawArrows) { + int node_shape; + dim2::Point s=mycoords[g.source(*e)]; + dim2::Point t=mycoords[g.target(*e)]; + double rn=_nodeSizes[g.target(*e)]*_nodeScale; + node_shape=_nodeShapes[g.target(*e)]; + dim2::Bezier3 bez(s,mm,mm,t); + double t1=0,t2=1; + for(int ii=0;ii apoint=bez((t1+t2)/2); + rn = _arrowLength+_arcWidths[*e]*_arcWidthScale; + rn*=rn; + t2=(t1+t2)/2;t1=0; + for(int ii=0;iirn) t1=(t1+t2)/2; + else t2=(t1+t2)/2; + dim2::Point linend=bez((t1+t2)/2); + bez=bez.before((t1+t2)/2); +// rn=_nodeSizes[g.source(*e)]*_nodeScale; +// node_shape=_nodeShapes[g.source(*e)]; +// t1=0;t2=1; +// for(int i=0;i dd(rot90(linend-apoint)); + dd*=(.5*_arcWidths[*e]*_arcWidthScale+_arrowWidth)/ + std::sqrt(dd.normSquare()); + os << "newpath " << psOut(apoint) << " moveto " + << psOut(linend+dd) << " lineto " + << psOut(linend-dd) << " lineto closepath fill\n"; + } + else { + os << mycoords[g.source(*e)].x << ' ' + << mycoords[g.source(*e)].y << ' ' + << mm.x << ' ' << mm.y << ' ' + << mycoords[g.target(*e)].x << ' ' + << mycoords[g.target(*e)].y << ' ' + << _arcColors[*e].red() << ' ' + << _arcColors[*e].green() << ' ' + << _arcColors[*e].blue() << ' ' + << _arcWidths[*e]*_arcWidthScale << " lb\n"; + } + sw+=_arcWidths[*e]*_arcWidthScale/2.0+_parArcDist; + } + } + } + else for(ArcIt e(g);e!=INVALID;++e) + if((!_undirected||g.source(e)0 + &&g.source(e)!=g.target(e)) { + if(_drawArrows) { + dim2::Point d(mycoords[g.target(e)]-mycoords[g.source(e)]); + double rn=_nodeSizes[g.target(e)]*_nodeScale; + int node_shape=_nodeShapes[g.target(e)]; + double t1=0,t2=1; + for(int i=0;i GraphToEps > edgeWidths(const X &x) + { + return arcWidths(x); + } + + ///An alias for arcColors() + template GraphToEps > + edgeColors(const X &x) + { + return arcColors(x); + } + + ///An alias for arcWidthScale() + GraphToEps &edgeWidthScale(double d) {return arcWidthScale(d);} + + ///An alias for autoArcWidthScale() + GraphToEps &autoEdgeWidthScale(bool b=true) + { + return autoArcWidthScale(b); + } + + ///An alias for absoluteArcWidths() + GraphToEps &absoluteEdgeWidths(bool b=true) + { + return absoluteArcWidths(b); + } + + ///An alias for parArcDist() + GraphToEps &parEdgeDist(double d) {return parArcDist(d);} + + ///An alias for hideArcs() + GraphToEps &hideEdges(bool b=true) {return hideArcs(b);} + + ///@} +}; + +template +const int GraphToEps::INTERPOL_PREC = 20; +template +const double GraphToEps::A4HEIGHT = 841.8897637795276; +template +const double GraphToEps::A4WIDTH = 595.275590551181; +template +const double GraphToEps::A4BORDER = 15; + + +///Generates an EPS file from a graph + +///\ingroup eps_io +///Generates an EPS file from a graph. +///\param g Reference to the graph to be printed. +///\param os Reference to the output stream. +///By default, it is std::cout. +/// +///This function also has a lot of +///\ref named-templ-func-param "named parameters", +///they are declared as the members of class \ref GraphToEps. The following +///example shows how to use these parameters. +///\code +/// graphToEps(g,os).scale(10).coords(coords) +/// .nodeScale(2).nodeSizes(sizes) +/// .arcWidthScale(.4).run(); +///\endcode +/// +///For more detailed examples, see the \ref graph_to_eps_demo.cc demo file. +/// +///\warning Don't forget to put the \ref GraphToEps::run() "run()" +///to the end of the parameter list. +///\sa GraphToEps +///\sa graphToEps(GR &g, const char *file_name) +template +GraphToEps > +graphToEps(GR &g, std::ostream& os=std::cout) +{ + return + GraphToEps >(DefaultGraphToEpsTraits(g,os)); +} + +///Generates an EPS file from a graph + +///\ingroup eps_io +///This function does the same as +///\ref graphToEps(GR &g,std::ostream& os) +///but it writes its output into the file \c file_name +///instead of a stream. +///\sa graphToEps(GR &g, std::ostream& os) +template +GraphToEps > +graphToEps(GR &g,const char *file_name) +{ + std::ostream* os = new std::ofstream(file_name); + if (!(*os)) { + delete os; + throw IoError("Cannot write file", file_name); + } + return GraphToEps > + (DefaultGraphToEpsTraits(g,*os,true)); +} + +///Generates an EPS file from a graph + +///\ingroup eps_io +///This function does the same as +///\ref graphToEps(GR &g,std::ostream& os) +///but it writes its output into the file \c file_name +///instead of a stream. +///\sa graphToEps(GR &g, std::ostream& os) +template +GraphToEps > +graphToEps(GR &g,const std::string& file_name) +{ + std::ostream* os = new std::ofstream(file_name.c_str()); + if (!(*os)) { + delete os; + throw IoError("Cannot write file", file_name); + } + return GraphToEps > + (DefaultGraphToEpsTraits(g,*os,true)); +} + +} //END OF NAMESPACE LEMON + +#endif // LEMON_GRAPH_TO_EPS_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/greedy_tsp.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/greedy_tsp.h new file mode 100644 index 00000000000..95461717ae0 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/greedy_tsp.h @@ -0,0 +1,251 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_GREEDY_TSP_H +#define LEMON_GREEDY_TSP_H + +/// \ingroup tsp +/// \file +/// \brief Greedy algorithm for symmetric TSP + +#include +#include +#include +#include + +namespace lemon { + + /// \ingroup tsp + /// + /// \brief Greedy algorithm for symmetric TSP. + /// + /// GreedyTsp implements the greedy heuristic for solving + /// symmetric \ref tsp "TSP". + /// + /// This algorithm is quite similar to the \ref NearestNeighborTsp + /// "nearest neighbor" heuristic, but it maintains a set of disjoint paths. + /// At each step, the shortest possible edge is added to these paths + /// as long as it does not create a cycle of less than n edges and it does + /// not increase the degree of any node above two. + /// + /// This method runs in O(n2) time. + /// It quickly finds a relatively short tour for most TSP instances, + /// but it could also yield a really bad (or even the worst) solution + /// in special cases. + /// + /// \tparam CM Type of the cost map. + template + class GreedyTsp + { + public: + + /// Type of the cost map + typedef CM CostMap; + /// Type of the edge costs + typedef typename CM::Value Cost; + + private: + + GRAPH_TYPEDEFS(FullGraph); + + const FullGraph &_gr; + const CostMap &_cost; + Cost _sum; + std::vector _path; + + private: + + // Functor class to compare edges by their costs + class EdgeComp { + private: + const CostMap &_cost; + + public: + EdgeComp(const CostMap &cost) : _cost(cost) {} + + bool operator()(const Edge &a, const Edge &b) const { + return _cost[a] < _cost[b]; + } + }; + + public: + + /// \brief Constructor + /// + /// Constructor. + /// \param gr The \ref FullGraph "full graph" the algorithm runs on. + /// \param cost The cost map. + GreedyTsp(const FullGraph &gr, const CostMap &cost) + : _gr(gr), _cost(cost) {} + + /// \name Execution Control + /// @{ + + /// \brief Runs the algorithm. + /// + /// This function runs the algorithm. + /// + /// \return The total cost of the found tour. + Cost run() { + _path.clear(); + + if (_gr.nodeNum() == 0) return _sum = 0; + else if (_gr.nodeNum() == 1) { + _path.push_back(_gr(0)); + return _sum = 0; + } + + std::vector plist; + plist.resize(_gr.nodeNum()*2, -1); + + std::vector sorted_edges; + sorted_edges.reserve(_gr.edgeNum()); + for (EdgeIt e(_gr); e != INVALID; ++e) + sorted_edges.push_back(e); + std::sort(sorted_edges.begin(), sorted_edges.end(), EdgeComp(_cost)); + + FullGraph::NodeMap item_int_map(_gr); + UnionFind > union_find(item_int_map); + for (NodeIt n(_gr); n != INVALID; ++n) + union_find.insert(n); + + FullGraph::NodeMap degree(_gr, 0); + + int nodesNum = 0, i = 0; + while (nodesNum != _gr.nodeNum()-1) { + Edge e = sorted_edges[i++]; + Node u = _gr.u(e), + v = _gr.v(e); + + if (degree[u] <= 1 && degree[v] <= 1) { + if (union_find.join(u, v)) { + const int uid = _gr.id(u), + vid = _gr.id(v); + + plist[uid*2 + degree[u]] = vid; + plist[vid*2 + degree[v]] = uid; + + ++degree[u]; + ++degree[v]; + ++nodesNum; + } + } + } + + for (int i=0, n=-1; i<_gr.nodeNum()*2; ++i) { + if (plist[i] == -1) { + if (n==-1) { + n = i; + } else { + plist[n] = i/2; + plist[i] = n/2; + break; + } + } + } + + for (int i=0, next=0, last=-1; i!=_gr.nodeNum(); ++i) { + _path.push_back(_gr.nodeFromId(next)); + if (plist[2*next] != last) { + last = next; + next = plist[2*next]; + } else { + last = next; + next = plist[2*next+1]; + } + } + + _sum = _cost[_gr.edge(_path.back(), _path.front())]; + for (int i = 0; i < int(_path.size())-1; ++i) { + _sum += _cost[_gr.edge(_path[i], _path[i+1])]; + } + + return _sum; + } + + /// @} + + /// \name Query Functions + /// @{ + + /// \brief The total cost of the found tour. + /// + /// This function returns the total cost of the found tour. + /// + /// \pre run() must be called before using this function. + Cost tourCost() const { + return _sum; + } + + /// \brief Returns a const reference to the node sequence of the + /// found tour. + /// + /// This function returns a const reference to a vector + /// that stores the node sequence of the found tour. + /// + /// \pre run() must be called before using this function. + const std::vector& tourNodes() const { + return _path; + } + + /// \brief Gives back the node sequence of the found tour. + /// + /// This function copies the node sequence of the found tour into + /// an STL container through the given output iterator. The + /// value_type of the container must be FullGraph::Node. + /// For example, + /// \code + /// std::vector nodes(countNodes(graph)); + /// tsp.tourNodes(nodes.begin()); + /// \endcode + /// or + /// \code + /// std::list nodes; + /// tsp.tourNodes(std::back_inserter(nodes)); + /// \endcode + /// + /// \pre run() must be called before using this function. + template + void tourNodes(Iterator out) const { + std::copy(_path.begin(), _path.end(), out); + } + + /// \brief Gives back the found tour as a path. + /// + /// This function copies the found tour as a list of arcs/edges into + /// the given \ref lemon::concepts::Path "path structure". + /// + /// \pre run() must be called before using this function. + template + void tour(Path &path) const { + path.clear(); + for (int i = 0; i < int(_path.size()) - 1; ++i) { + path.addBack(_gr.arc(_path[i], _path[i+1])); + } + if (int(_path.size()) >= 2) { + path.addBack(_gr.arc(_path.back(), _path.front())); + } + } + + /// @} + + }; + +}; // namespace lemon + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/grid_graph.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/grid_graph.h new file mode 100644 index 00000000000..a3dff0f612f --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/grid_graph.h @@ -0,0 +1,699 @@ +/* -*- 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 GRID_GRAPH_H +#define GRID_GRAPH_H + +#include +#include +#include +#include + +///\ingroup graphs +///\file +///\brief GridGraph class. + +namespace lemon { + + class GridGraphBase { + + public: + + typedef GridGraphBase Graph; + + class Node; + class Edge; + class Arc; + + public: + + GridGraphBase() {} + + protected: + + void construct(int width, int height) { + _width = width; _height = height; + _node_num = width * height; + _edge_num = 2 * _node_num - width - height; + _edge_limit = _node_num - _width; + } + + public: + + Node operator()(int i, int j) const { + LEMON_DEBUG(0 <= i && i < _width && + 0 <= j && j < _height, "Index out of range"); + return Node(i + j * _width); + } + + int col(Node n) const { + return n._id % _width; + } + + int row(Node n) const { + return n._id / _width; + } + + dim2::Point pos(Node n) const { + return dim2::Point(col(n), row(n)); + } + + int width() const { + return _width; + } + + int height() const { + return _height; + } + + typedef True NodeNumTag; + typedef True EdgeNumTag; + typedef True ArcNumTag; + + int nodeNum() const { return _node_num; } + int edgeNum() const { return _edge_num; } + int arcNum() const { return 2 * _edge_num; } + + Node u(Edge edge) const { + if (edge._id < _edge_limit) { + return edge._id; + } else { + return (edge._id - _edge_limit) % (_width - 1) + + (edge._id - _edge_limit) / (_width - 1) * _width; + } + } + + Node v(Edge edge) const { + if (edge._id < _edge_limit) { + return edge._id + _width; + } else { + return (edge._id - _edge_limit) % (_width - 1) + + (edge._id - _edge_limit) / (_width - 1) * _width + 1; + } + } + + Node source(Arc arc) const { + return (arc._id & 1) == 1 ? u(arc) : v(arc); + } + + Node target(Arc arc) const { + return (arc._id & 1) == 1 ? v(arc) : u(arc); + } + + static int id(Node node) { return node._id; } + static int id(Edge edge) { return edge._id; } + static int id(Arc arc) { return arc._id; } + + int maxNodeId() const { return _node_num - 1; } + int maxEdgeId() const { return _edge_num - 1; } + int maxArcId() const { return 2 * _edge_num - 1; } + + static Node nodeFromId(int id) { return Node(id);} + static Edge edgeFromId(int id) { return Edge(id);} + static Arc arcFromId(int id) { return Arc(id);} + + typedef True FindEdgeTag; + typedef True FindArcTag; + + Edge findEdge(Node u, Node v, Edge prev = INVALID) const { + if (prev != INVALID) return INVALID; + if (v._id > u._id) { + if (v._id - u._id == _width) + return Edge(u._id); + if (v._id - u._id == 1 && u._id % _width < _width - 1) { + return Edge(u._id / _width * (_width - 1) + + u._id % _width + _edge_limit); + } + } else { + if (u._id - v._id == _width) + return Edge(v._id); + if (u._id - v._id == 1 && v._id % _width < _width - 1) { + return Edge(v._id / _width * (_width - 1) + + v._id % _width + _edge_limit); + } + } + return INVALID; + } + + Arc findArc(Node u, Node v, Arc prev = INVALID) const { + if (prev != INVALID) return INVALID; + if (v._id > u._id) { + if (v._id - u._id == _width) + return Arc((u._id << 1) | 1); + if (v._id - u._id == 1 && u._id % _width < _width - 1) { + return Arc(((u._id / _width * (_width - 1) + + u._id % _width + _edge_limit) << 1) | 1); + } + } else { + if (u._id - v._id == _width) + return Arc(v._id << 1); + if (u._id - v._id == 1 && v._id % _width < _width - 1) { + return Arc((v._id / _width * (_width - 1) + + v._id % _width + _edge_limit) << 1); + } + } + return INVALID; + } + + class Node { + friend class GridGraphBase; + + protected: + int _id; + Node(int id) : _id(id) {} + public: + Node() {} + Node (Invalid) : _id(-1) {} + bool operator==(const Node node) const {return _id == node._id;} + bool operator!=(const Node node) const {return _id != node._id;} + bool operator<(const Node node) const {return _id < node._id;} + }; + + class Edge { + friend class GridGraphBase; + friend class Arc; + + protected: + int _id; + + Edge(int id) : _id(id) {} + + public: + Edge() {} + Edge (Invalid) : _id(-1) {} + bool operator==(const Edge edge) const {return _id == edge._id;} + bool operator!=(const Edge edge) const {return _id != edge._id;} + bool operator<(const Edge edge) const {return _id < edge._id;} + }; + + class Arc { + friend class GridGraphBase; + + protected: + int _id; + + Arc(int id) : _id(id) {} + + public: + Arc() {} + Arc (Invalid) : _id(-1) {} + operator Edge() const { return _id != -1 ? Edge(_id >> 1) : INVALID; } + bool operator==(const Arc arc) const {return _id == arc._id;} + bool operator!=(const Arc arc) const {return _id != arc._id;} + bool operator<(const Arc arc) const {return _id < arc._id;} + }; + + static bool direction(Arc arc) { + return (arc._id & 1) == 1; + } + + static Arc direct(Edge edge, bool dir) { + return Arc((edge._id << 1) | (dir ? 1 : 0)); + } + + void first(Node& node) const { + node._id = _node_num - 1; + } + + static void next(Node& node) { + --node._id; + } + + void first(Edge& edge) const { + edge._id = _edge_num - 1; + } + + static void next(Edge& edge) { + --edge._id; + } + + void first(Arc& arc) const { + arc._id = 2 * _edge_num - 1; + } + + static void next(Arc& arc) { + --arc._id; + } + + void firstOut(Arc& arc, const Node& node) const { + if (node._id % _width < _width - 1) { + arc._id = (_edge_limit + node._id % _width + + (node._id / _width) * (_width - 1)) << 1 | 1; + return; + } + if (node._id < _node_num - _width) { + arc._id = node._id << 1 | 1; + return; + } + if (node._id % _width > 0) { + arc._id = (_edge_limit + node._id % _width + + (node._id / _width) * (_width - 1) - 1) << 1; + return; + } + if (node._id >= _width) { + arc._id = (node._id - _width) << 1; + return; + } + arc._id = -1; + } + + void nextOut(Arc& arc) const { + int nid = arc._id >> 1; + if ((arc._id & 1) == 1) { + if (nid >= _edge_limit) { + nid = (nid - _edge_limit) % (_width - 1) + + (nid - _edge_limit) / (_width - 1) * _width; + if (nid < _node_num - _width) { + arc._id = nid << 1 | 1; + return; + } + } + if (nid % _width > 0) { + arc._id = (_edge_limit + nid % _width + + (nid / _width) * (_width - 1) - 1) << 1; + return; + } + if (nid >= _width) { + arc._id = (nid - _width) << 1; + return; + } + } else { + if (nid >= _edge_limit) { + nid = (nid - _edge_limit) % (_width - 1) + + (nid - _edge_limit) / (_width - 1) * _width + 1; + if (nid >= _width) { + arc._id = (nid - _width) << 1; + return; + } + } + } + arc._id = -1; + } + + void firstIn(Arc& arc, const Node& node) const { + if (node._id % _width < _width - 1) { + arc._id = (_edge_limit + node._id % _width + + (node._id / _width) * (_width - 1)) << 1; + return; + } + if (node._id < _node_num - _width) { + arc._id = node._id << 1; + return; + } + if (node._id % _width > 0) { + arc._id = (_edge_limit + node._id % _width + + (node._id / _width) * (_width - 1) - 1) << 1 | 1; + return; + } + if (node._id >= _width) { + arc._id = (node._id - _width) << 1 | 1; + return; + } + arc._id = -1; + } + + void nextIn(Arc& arc) const { + int nid = arc._id >> 1; + if ((arc._id & 1) == 0) { + if (nid >= _edge_limit) { + nid = (nid - _edge_limit) % (_width - 1) + + (nid - _edge_limit) / (_width - 1) * _width; + if (nid < _node_num - _width) { + arc._id = nid << 1; + return; + } + } + if (nid % _width > 0) { + arc._id = (_edge_limit + nid % _width + + (nid / _width) * (_width - 1) - 1) << 1 | 1; + return; + } + if (nid >= _width) { + arc._id = (nid - _width) << 1 | 1; + return; + } + } else { + if (nid >= _edge_limit) { + nid = (nid - _edge_limit) % (_width - 1) + + (nid - _edge_limit) / (_width - 1) * _width + 1; + if (nid >= _width) { + arc._id = (nid - _width) << 1 | 1; + return; + } + } + } + arc._id = -1; + } + + void firstInc(Edge& edge, bool& dir, const Node& node) const { + if (node._id % _width < _width - 1) { + edge._id = _edge_limit + node._id % _width + + (node._id / _width) * (_width - 1); + dir = true; + return; + } + if (node._id < _node_num - _width) { + edge._id = node._id; + dir = true; + return; + } + if (node._id % _width > 0) { + edge._id = _edge_limit + node._id % _width + + (node._id / _width) * (_width - 1) - 1; + dir = false; + return; + } + if (node._id >= _width) { + edge._id = node._id - _width; + dir = false; + return; + } + edge._id = -1; + dir = true; + } + + void nextInc(Edge& edge, bool& dir) const { + int nid = edge._id; + if (dir) { + if (nid >= _edge_limit) { + nid = (nid - _edge_limit) % (_width - 1) + + (nid - _edge_limit) / (_width - 1) * _width; + if (nid < _node_num - _width) { + edge._id = nid; + return; + } + } + if (nid % _width > 0) { + edge._id = _edge_limit + nid % _width + + (nid / _width) * (_width - 1) - 1; + dir = false; + return; + } + if (nid >= _width) { + edge._id = nid - _width; + dir = false; + return; + } + } else { + if (nid >= _edge_limit) { + nid = (nid - _edge_limit) % (_width - 1) + + (nid - _edge_limit) / (_width - 1) * _width + 1; + if (nid >= _width) { + edge._id = nid - _width; + return; + } + } + } + edge._id = -1; + dir = true; + } + + Arc right(Node n) const { + if (n._id % _width < _width - 1) { + return Arc(((_edge_limit + n._id % _width + + (n._id / _width) * (_width - 1)) << 1) | 1); + } else { + return INVALID; + } + } + + Arc left(Node n) const { + if (n._id % _width > 0) { + return Arc((_edge_limit + n._id % _width + + (n._id / _width) * (_width - 1) - 1) << 1); + } else { + return INVALID; + } + } + + Arc up(Node n) const { + if (n._id < _edge_limit) { + return Arc((n._id << 1) | 1); + } else { + return INVALID; + } + } + + Arc down(Node n) const { + if (n._id >= _width) { + return Arc((n._id - _width) << 1); + } else { + return INVALID; + } + } + + private: + int _width, _height; + int _node_num, _edge_num; + int _edge_limit; + }; + + + typedef GraphExtender ExtendedGridGraphBase; + + /// \ingroup graphs + /// + /// \brief Grid graph class + /// + /// GridGraph implements a special graph type. The nodes of the + /// graph can be indexed by two integer values \c (i,j) where \c i is + /// in the range [0..width()-1] and j is in the range + /// [0..height()-1]. Two nodes are connected in the graph if + /// the indices differ exactly on one position and the difference is + /// also exactly one. The nodes of the graph can be obtained by position + /// using the \c operator()() function and the indices of the nodes can + /// be obtained using \c pos(), \c col() and \c row() members. The outgoing + /// arcs can be retrieved with the \c right(), \c up(), \c left() + /// and \c down() functions, where the bottom-left corner is the + /// origin. + /// + /// This class is completely static and it needs constant memory space. + /// Thus you can neither add nor delete nodes or edges, however + /// the structure can be resized using resize(). + /// + /// \image html grid_graph.png + /// \image latex grid_graph.eps "Grid graph" width=\textwidth + /// + /// A short example about the basic usage: + ///\code + /// GridGraph graph(rows, cols); + /// GridGraph::NodeMap val(graph); + /// for (int i = 0; i < graph.width(); ++i) { + /// for (int j = 0; j < graph.height(); ++j) { + /// val[graph(i, j)] = i + j; + /// } + /// } + ///\endcode + /// + /// This type fully conforms to the \ref concepts::Graph "Graph concept". + /// Most of its member functions and nested classes are documented + /// only in the concept class. + /// + /// This class provides constant time counting for nodes, edges and arcs. + class GridGraph : public ExtendedGridGraphBase { + typedef ExtendedGridGraphBase Parent; + + public: + + /// \brief Map to get the indices of the nodes as \ref dim2::Point + /// "dim2::Point". + /// + /// Map to get the indices of the nodes as \ref dim2::Point + /// "dim2::Point". + class IndexMap { + public: + /// \brief The key type of the map + typedef GridGraph::Node Key; + /// \brief The value type of the map + typedef dim2::Point Value; + + /// \brief Constructor + IndexMap(const GridGraph& graph) : _graph(graph) {} + + /// \brief The subscript operator + Value operator[](Key key) const { + return _graph.pos(key); + } + + private: + const GridGraph& _graph; + }; + + /// \brief Map to get the column of the nodes. + /// + /// Map to get the column of the nodes. + class ColMap { + public: + /// \brief The key type of the map + typedef GridGraph::Node Key; + /// \brief The value type of the map + typedef int Value; + + /// \brief Constructor + ColMap(const GridGraph& graph) : _graph(graph) {} + + /// \brief The subscript operator + Value operator[](Key key) const { + return _graph.col(key); + } + + private: + const GridGraph& _graph; + }; + + /// \brief Map to get the row of the nodes. + /// + /// Map to get the row of the nodes. + class RowMap { + public: + /// \brief The key type of the map + typedef GridGraph::Node Key; + /// \brief The value type of the map + typedef int Value; + + /// \brief Constructor + RowMap(const GridGraph& graph) : _graph(graph) {} + + /// \brief The subscript operator + Value operator[](Key key) const { + return _graph.row(key); + } + + private: + const GridGraph& _graph; + }; + + /// \brief Constructor + /// + /// Construct a grid graph with the given size. + GridGraph(int width, int height) { construct(width, height); } + + /// \brief Resizes the graph + /// + /// This function resizes the graph. It fully destroys and + /// rebuilds the structure, therefore the maps of the graph will be + /// reallocated automatically and the previous values will be lost. + void resize(int width, int height) { + Parent::notifier(Arc()).clear(); + Parent::notifier(Edge()).clear(); + Parent::notifier(Node()).clear(); + construct(width, height); + Parent::notifier(Node()).build(); + Parent::notifier(Edge()).build(); + Parent::notifier(Arc()).build(); + } + + /// \brief The node on the given position. + /// + /// Gives back the node on the given position. + Node operator()(int i, int j) const { + return Parent::operator()(i, j); + } + + /// \brief The column index of the node. + /// + /// Gives back the column index of the node. + int col(Node n) const { + return Parent::col(n); + } + + /// \brief The row index of the node. + /// + /// Gives back the row index of the node. + int row(Node n) const { + return Parent::row(n); + } + + /// \brief The position of the node. + /// + /// Gives back the position of the node, ie. the (col,row) pair. + dim2::Point pos(Node n) const { + return Parent::pos(n); + } + + /// \brief The number of the columns. + /// + /// Gives back the number of the columns. + int width() const { + return Parent::width(); + } + + /// \brief The number of the rows. + /// + /// Gives back the number of the rows. + int height() const { + return Parent::height(); + } + + /// \brief The arc goes right from the node. + /// + /// Gives back the arc goes right from the node. If there is not + /// outgoing arc then it gives back INVALID. + Arc right(Node n) const { + return Parent::right(n); + } + + /// \brief The arc goes left from the node. + /// + /// Gives back the arc goes left from the node. If there is not + /// outgoing arc then it gives back INVALID. + Arc left(Node n) const { + return Parent::left(n); + } + + /// \brief The arc goes up from the node. + /// + /// Gives back the arc goes up from the node. If there is not + /// outgoing arc then it gives back INVALID. + Arc up(Node n) const { + return Parent::up(n); + } + + /// \brief The arc goes down from the node. + /// + /// Gives back the arc goes down from the node. If there is not + /// outgoing arc then it gives back INVALID. + Arc down(Node n) const { + return Parent::down(n); + } + + /// \brief Index map of the grid graph + /// + /// Just returns an IndexMap for the grid graph. + IndexMap indexMap() const { + return IndexMap(*this); + } + + /// \brief Row map of the grid graph + /// + /// Just returns a RowMap for the grid graph. + RowMap rowMap() const { + return RowMap(*this); + } + + /// \brief Column map of the grid graph + /// + /// Just returns a ColMap for the grid graph. + ColMap colMap() const { + return ColMap(*this); + } + + }; + +} +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/grosso_locatelli_pullan_mc.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/grosso_locatelli_pullan_mc.h new file mode 100644 index 00000000000..669e1fa3298 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/grosso_locatelli_pullan_mc.h @@ -0,0 +1,840 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_GROSSO_LOCATELLI_PULLAN_MC_H +#define LEMON_GROSSO_LOCATELLI_PULLAN_MC_H + +/// \ingroup approx_algs +/// +/// \file +/// \brief The iterated local search algorithm of Grosso, Locatelli, and Pullan +/// for the maximum clique problem + +#include +#include +#include +#include + +namespace lemon { + + /// \addtogroup approx_algs + /// @{ + + /// \brief Implementation of the iterated local search algorithm of Grosso, + /// Locatelli, and Pullan for the maximum clique problem + /// + /// \ref GrossoLocatelliPullanMc implements the iterated local search + /// algorithm of Grosso, Locatelli, and Pullan for solving the \e maximum + /// \e clique \e problem \cite grosso08maxclique. + /// It is to find the largest complete subgraph (\e clique) in an + /// undirected graph, i.e., the largest set of nodes where each + /// pair of nodes is connected. + /// + /// This class provides a simple but highly efficient and robust heuristic + /// method that quickly finds a quite large clique, but not necessarily the + /// largest one. + /// The algorithm performs a certain number of iterations to find several + /// cliques and selects the largest one among them. Various limits can be + /// specified to control the running time and the effectiveness of the + /// search process. + /// + /// \tparam GR The undirected graph type the algorithm runs on. + /// + /// \note %GrossoLocatelliPullanMc provides three different node selection + /// rules, from which the most powerful one is used by default. + /// For more information, see \ref SelectionRule. + template + class GrossoLocatelliPullanMc + { + public: + + /// \brief Constants for specifying the node selection rule. + /// + /// Enum type containing constants for specifying the node selection rule + /// for the \ref run() function. + /// + /// During the algorithm, nodes are selected for addition to the current + /// clique according to the applied rule. + /// In general, the PENALTY_BASED rule turned out to be the most powerful + /// and the most robust, thus it is the default option. + /// However, another selection rule can be specified using the \ref run() + /// function with the proper parameter. + enum SelectionRule { + + /// A node is selected randomly without any evaluation at each step. + RANDOM, + + /// A node of maximum degree is selected randomly at each step. + DEGREE_BASED, + + /// A node of minimum penalty is selected randomly at each step. + /// The node penalties are updated adaptively after each stage of the + /// search process. + PENALTY_BASED + }; + + /// \brief Constants for the causes of search termination. + /// + /// Enum type containing constants for the different causes of search + /// termination. The \ref run() function returns one of these values. + enum TerminationCause { + + /// The iteration count limit is reached. + ITERATION_LIMIT, + + /// The step count limit is reached. + STEP_LIMIT, + + /// The clique size limit is reached. + SIZE_LIMIT + }; + + private: + + TEMPLATE_GRAPH_TYPEDEFS(GR); + + typedef std::vector IntVector; + typedef std::vector BoolVector; + typedef std::vector BoolMatrix; + // Note: vector is used instead of vector for efficiency reasons + + // The underlying graph + const GR &_graph; + IntNodeMap _id; + + // Internal matrix representation of the graph + BoolMatrix _gr; + int _n; + + // Search options + bool _delta_based_restart; + int _restart_delta_limit; + + // Search limits + int _iteration_limit; + int _step_limit; + int _size_limit; + + // The current clique + BoolVector _clique; + int _size; + + // The best clique found so far + BoolVector _best_clique; + int _best_size; + + // The "distances" of the nodes from the current clique. + // _delta[u] is the number of nodes in the clique that are + // not connected with u. + IntVector _delta; + + // The current tabu set + BoolVector _tabu; + + // Random number generator + Random _rnd; + + private: + + // Implementation of the RANDOM node selection rule. + class RandomSelectionRule + { + private: + + // References to the algorithm instance + const BoolVector &_clique; + const IntVector &_delta; + const BoolVector &_tabu; + Random &_rnd; + + // Pivot rule data + int _n; + + public: + + // Constructor + RandomSelectionRule(GrossoLocatelliPullanMc &mc) : + _clique(mc._clique), _delta(mc._delta), _tabu(mc._tabu), + _rnd(mc._rnd), _n(mc._n) + {} + + // Return a node index for a feasible add move or -1 if no one exists + int nextFeasibleAddNode() const { + int start_node = _rnd[_n]; + for (int i = start_node; i != _n; i++) { + if (_delta[i] == 0 && !_tabu[i]) return i; + } + for (int i = 0; i != start_node; i++) { + if (_delta[i] == 0 && !_tabu[i]) return i; + } + return -1; + } + + // Return a node index for a feasible swap move or -1 if no one exists + int nextFeasibleSwapNode() const { + int start_node = _rnd[_n]; + for (int i = start_node; i != _n; i++) { + if (!_clique[i] && _delta[i] == 1 && !_tabu[i]) return i; + } + for (int i = 0; i != start_node; i++) { + if (!_clique[i] && _delta[i] == 1 && !_tabu[i]) return i; + } + return -1; + } + + // Return a node index for an add move or -1 if no one exists + int nextAddNode() const { + int start_node = _rnd[_n]; + for (int i = start_node; i != _n; i++) { + if (_delta[i] == 0) return i; + } + for (int i = 0; i != start_node; i++) { + if (_delta[i] == 0) return i; + } + return -1; + } + + // Update internal data structures between stages (if necessary) + void update() {} + + }; //class RandomSelectionRule + + + // Implementation of the DEGREE_BASED node selection rule. + class DegreeBasedSelectionRule + { + private: + + // References to the algorithm instance + const BoolVector &_clique; + const IntVector &_delta; + const BoolVector &_tabu; + Random &_rnd; + + // Pivot rule data + int _n; + IntVector _deg; + + public: + + // Constructor + DegreeBasedSelectionRule(GrossoLocatelliPullanMc &mc) : + _clique(mc._clique), _delta(mc._delta), _tabu(mc._tabu), + _rnd(mc._rnd), _n(mc._n), _deg(_n) + { + for (int i = 0; i != _n; i++) { + int d = 0; + BoolVector &row = mc._gr[i]; + for (int j = 0; j != _n; j++) { + if (row[j]) d++; + } + _deg[i] = d; + } + } + + // Return a node index for a feasible add move or -1 if no one exists + int nextFeasibleAddNode() const { + int start_node = _rnd[_n]; + int node = -1, max_deg = -1; + for (int i = start_node; i != _n; i++) { + if (_delta[i] == 0 && !_tabu[i] && _deg[i] > max_deg) { + node = i; + max_deg = _deg[i]; + } + } + for (int i = 0; i != start_node; i++) { + if (_delta[i] == 0 && !_tabu[i] && _deg[i] > max_deg) { + node = i; + max_deg = _deg[i]; + } + } + return node; + } + + // Return a node index for a feasible swap move or -1 if no one exists + int nextFeasibleSwapNode() const { + int start_node = _rnd[_n]; + int node = -1, max_deg = -1; + for (int i = start_node; i != _n; i++) { + if (!_clique[i] && _delta[i] == 1 && !_tabu[i] && + _deg[i] > max_deg) { + node = i; + max_deg = _deg[i]; + } + } + for (int i = 0; i != start_node; i++) { + if (!_clique[i] && _delta[i] == 1 && !_tabu[i] && + _deg[i] > max_deg) { + node = i; + max_deg = _deg[i]; + } + } + return node; + } + + // Return a node index for an add move or -1 if no one exists + int nextAddNode() const { + int start_node = _rnd[_n]; + int node = -1, max_deg = -1; + for (int i = start_node; i != _n; i++) { + if (_delta[i] == 0 && _deg[i] > max_deg) { + node = i; + max_deg = _deg[i]; + } + } + for (int i = 0; i != start_node; i++) { + if (_delta[i] == 0 && _deg[i] > max_deg) { + node = i; + max_deg = _deg[i]; + } + } + return node; + } + + // Update internal data structures between stages (if necessary) + void update() {} + + }; //class DegreeBasedSelectionRule + + + // Implementation of the PENALTY_BASED node selection rule. + class PenaltyBasedSelectionRule + { + private: + + // References to the algorithm instance + const BoolVector &_clique; + const IntVector &_delta; + const BoolVector &_tabu; + Random &_rnd; + + // Pivot rule data + int _n; + IntVector _penalty; + + public: + + // Constructor + PenaltyBasedSelectionRule(GrossoLocatelliPullanMc &mc) : + _clique(mc._clique), _delta(mc._delta), _tabu(mc._tabu), + _rnd(mc._rnd), _n(mc._n), _penalty(_n, 0) + {} + + // Return a node index for a feasible add move or -1 if no one exists + int nextFeasibleAddNode() const { + int start_node = _rnd[_n]; + int node = -1, min_p = std::numeric_limits::max(); + for (int i = start_node; i != _n; i++) { + if (_delta[i] == 0 && !_tabu[i] && _penalty[i] < min_p) { + node = i; + min_p = _penalty[i]; + } + } + for (int i = 0; i != start_node; i++) { + if (_delta[i] == 0 && !_tabu[i] && _penalty[i] < min_p) { + node = i; + min_p = _penalty[i]; + } + } + return node; + } + + // Return a node index for a feasible swap move or -1 if no one exists + int nextFeasibleSwapNode() const { + int start_node = _rnd[_n]; + int node = -1, min_p = std::numeric_limits::max(); + for (int i = start_node; i != _n; i++) { + if (!_clique[i] && _delta[i] == 1 && !_tabu[i] && + _penalty[i] < min_p) { + node = i; + min_p = _penalty[i]; + } + } + for (int i = 0; i != start_node; i++) { + if (!_clique[i] && _delta[i] == 1 && !_tabu[i] && + _penalty[i] < min_p) { + node = i; + min_p = _penalty[i]; + } + } + return node; + } + + // Return a node index for an add move or -1 if no one exists + int nextAddNode() const { + int start_node = _rnd[_n]; + int node = -1, min_p = std::numeric_limits::max(); + for (int i = start_node; i != _n; i++) { + if (_delta[i] == 0 && _penalty[i] < min_p) { + node = i; + min_p = _penalty[i]; + } + } + for (int i = 0; i != start_node; i++) { + if (_delta[i] == 0 && _penalty[i] < min_p) { + node = i; + min_p = _penalty[i]; + } + } + return node; + } + + // Update internal data structures between stages (if necessary) + void update() {} + + }; //class PenaltyBasedSelectionRule + + public: + + /// \brief Constructor. + /// + /// Constructor. + /// The global \ref rnd "random number generator instance" is used + /// during the algorithm. + /// + /// \param graph The undirected graph the algorithm runs on. + GrossoLocatelliPullanMc(const GR& graph) : + _graph(graph), _id(_graph), _rnd(rnd) + { + initOptions(); + } + + /// \brief Constructor with random seed. + /// + /// Constructor with random seed. + /// + /// \param graph The undirected graph the algorithm runs on. + /// \param seed Seed value for the internal random number generator + /// that is used during the algorithm. + GrossoLocatelliPullanMc(const GR& graph, int seed) : + _graph(graph), _id(_graph), _rnd(seed) + { + initOptions(); + } + + /// \brief Constructor with random number generator. + /// + /// Constructor with random number generator. + /// + /// \param graph The undirected graph the algorithm runs on. + /// \param random A random number generator that is used during the + /// algorithm. + GrossoLocatelliPullanMc(const GR& graph, const Random& random) : + _graph(graph), _id(_graph), _rnd(random) + { + initOptions(); + } + + /// \name Execution Control + /// The \ref run() function can be used to execute the algorithm.\n + /// The functions \ref iterationLimit(int), \ref stepLimit(int), and + /// \ref sizeLimit(int) can be used to specify various limits for the + /// search process. + + /// @{ + + /// \brief Sets the maximum number of iterations. + /// + /// This function sets the maximum number of iterations. + /// Each iteration of the algorithm finds a maximal clique (but not + /// necessarily the largest one) by performing several search steps + /// (node selections). + /// + /// This limit controls the running time and the success of the + /// algorithm. For larger values, the algorithm runs slower, but it more + /// likely finds larger cliques. For smaller values, the algorithm is + /// faster but probably gives worse results. + /// + /// The default value is \c 1000. + /// \c -1 means that number of iterations is not limited. + /// + /// \warning You should specify a reasonable limit for the number of + /// iterations and/or the number of search steps. + /// + /// \return (*this) + /// + /// \sa stepLimit(int) + /// \sa sizeLimit(int) + GrossoLocatelliPullanMc& iterationLimit(int limit) { + _iteration_limit = limit; + return *this; + } + + /// \brief Sets the maximum number of search steps. + /// + /// This function sets the maximum number of elementary search steps. + /// Each iteration of the algorithm finds a maximal clique (but not + /// necessarily the largest one) by performing several search steps + /// (node selections). + /// + /// This limit controls the running time and the success of the + /// algorithm. For larger values, the algorithm runs slower, but it more + /// likely finds larger cliques. For smaller values, the algorithm is + /// faster but probably gives worse results. + /// + /// The default value is \c -1, which means that number of steps + /// is not limited explicitly. However, the number of iterations is + /// limited and each iteration performs a finite number of search steps. + /// + /// \warning You should specify a reasonable limit for the number of + /// iterations and/or the number of search steps. + /// + /// \return (*this) + /// + /// \sa iterationLimit(int) + /// \sa sizeLimit(int) + GrossoLocatelliPullanMc& stepLimit(int limit) { + _step_limit = limit; + return *this; + } + + /// \brief Sets the desired clique size. + /// + /// This function sets the desired clique size that serves as a search + /// limit. If a clique of this size (or a larger one) is found, then the + /// algorithm terminates. + /// + /// This function is especially useful if you know an exact upper bound + /// for the size of the cliques in the graph or if any clique above + /// a certain size limit is sufficient for your application. + /// + /// The default value is \c -1, which means that the size limit is set to + /// the number of nodes in the graph. + /// + /// \return (*this) + /// + /// \sa iterationLimit(int) + /// \sa stepLimit(int) + GrossoLocatelliPullanMc& sizeLimit(int limit) { + _size_limit = limit; + return *this; + } + + /// \brief The maximum number of iterations. + /// + /// This function gives back the maximum number of iterations. + /// \c -1 means that no limit is specified. + /// + /// \sa iterationLimit(int) + int iterationLimit() const { + return _iteration_limit; + } + + /// \brief The maximum number of search steps. + /// + /// This function gives back the maximum number of search steps. + /// \c -1 means that no limit is specified. + /// + /// \sa stepLimit(int) + int stepLimit() const { + return _step_limit; + } + + /// \brief The desired clique size. + /// + /// This function gives back the desired clique size that serves as a + /// search limit. \c -1 means that this limit is set to the number of + /// nodes in the graph. + /// + /// \sa sizeLimit(int) + int sizeLimit() const { + return _size_limit; + } + + /// \brief Runs the algorithm. + /// + /// This function runs the algorithm. If one of the specified limits + /// is reached, the search process terminates. + /// + /// \param rule The node selection rule. For more information, see + /// \ref SelectionRule. + /// + /// \return The termination cause of the search. For more information, + /// see \ref TerminationCause. + TerminationCause run(SelectionRule rule = PENALTY_BASED) + { + init(); + switch (rule) { + case RANDOM: + return start(); + case DEGREE_BASED: + return start(); + default: + return start(); + } + } + + /// @} + + /// \name Query Functions + /// The results of the algorithm can be obtained using these functions.\n + /// The run() function must be called before using them. + + /// @{ + + /// \brief The size of the found clique + /// + /// This function returns the size of the found clique. + /// + /// \pre run() must be called before using this function. + int cliqueSize() const { + return _best_size; + } + + /// \brief Gives back the found clique in a \c bool node map + /// + /// This function gives back the characteristic vector of the found + /// clique in the given node map. + /// It must be a \ref concepts::WriteMap "writable" node map with + /// \c bool (or convertible) value type. + /// + /// \pre run() must be called before using this function. + template + void cliqueMap(CliqueMap &map) const { + for (NodeIt n(_graph); n != INVALID; ++n) { + map[n] = static_cast(_best_clique[_id[n]]); + } + } + + /// \brief Iterator to list the nodes of the found clique + /// + /// This iterator class lists the nodes of the found clique. + /// Before using it, you must allocate a GrossoLocatelliPullanMc instance + /// and call its \ref GrossoLocatelliPullanMc::run() "run()" method. + /// + /// The following example prints out the IDs of the nodes in the found + /// clique. + /// \code + /// GrossoLocatelliPullanMc mc(g); + /// mc.run(); + /// for (GrossoLocatelliPullanMc::CliqueNodeIt n(mc); + /// n != INVALID; ++n) + /// { + /// std::cout << g.id(n) << std::endl; + /// } + /// \endcode + class CliqueNodeIt + { + private: + NodeIt _it; + BoolNodeMap _map; + + public: + + /// Constructor + + /// Constructor. + /// \param mc The algorithm instance. + CliqueNodeIt(const GrossoLocatelliPullanMc &mc) + : _map(mc._graph) + { + mc.cliqueMap(_map); + for (_it = NodeIt(mc._graph); _it != INVALID && !_map[_it]; ++_it) ; + } + + /// Conversion to \c Node + operator Node() const { return _it; } + + bool operator==(Invalid) const { return _it == INVALID; } + bool operator!=(Invalid) const { return _it != INVALID; } + + /// Next node + CliqueNodeIt &operator++() { + for (++_it; _it != INVALID && !_map[_it]; ++_it) ; + return *this; + } + + /// Postfix incrementation + + /// Postfix incrementation. + /// + /// \warning This incrementation returns a \c Node, not a + /// \c CliqueNodeIt as one may expect. + typename GR::Node operator++(int) { + Node n=*this; + ++(*this); + return n; + } + + }; + + /// @} + + private: + + // Initialize search options and limits + void initOptions() { + // Search options + _delta_based_restart = true; + _restart_delta_limit = 4; + + // Search limits + _iteration_limit = 1000; + _step_limit = -1; // this is disabled by default + _size_limit = -1; // this is disabled by default + } + + // Adds a node to the current clique + void addCliqueNode(int u) { + if (_clique[u]) return; + _clique[u] = true; + _size++; + BoolVector &row = _gr[u]; + for (int i = 0; i != _n; i++) { + if (!row[i]) _delta[i]++; + } + } + + // Removes a node from the current clique + void delCliqueNode(int u) { + if (!_clique[u]) return; + _clique[u] = false; + _size--; + BoolVector &row = _gr[u]; + for (int i = 0; i != _n; i++) { + if (!row[i]) _delta[i]--; + } + } + + // Initialize data structures + void init() { + _n = countNodes(_graph); + int ui = 0; + for (NodeIt u(_graph); u != INVALID; ++u) { + _id[u] = ui++; + } + _gr.clear(); + _gr.resize(_n, BoolVector(_n, false)); + ui = 0; + for (NodeIt u(_graph); u != INVALID; ++u) { + for (IncEdgeIt e(_graph, u); e != INVALID; ++e) { + int vi = _id[_graph.runningNode(e)]; + _gr[ui][vi] = true; + _gr[vi][ui] = true; + } + ++ui; + } + + _clique.clear(); + _clique.resize(_n, false); + _size = 0; + _best_clique.clear(); + _best_clique.resize(_n, false); + _best_size = 0; + _delta.clear(); + _delta.resize(_n, 0); + _tabu.clear(); + _tabu.resize(_n, false); + } + + // Executes the algorithm + template + TerminationCause start() { + if (_n == 0) return SIZE_LIMIT; + if (_n == 1) { + _best_clique[0] = true; + _best_size = 1; + return SIZE_LIMIT; + } + + // Iterated local search algorithm + const int max_size = _size_limit >= 0 ? _size_limit : _n; + const int max_restart = _iteration_limit >= 0 ? + _iteration_limit : std::numeric_limits::max(); + const int max_select = _step_limit >= 0 ? + _step_limit : std::numeric_limits::max(); + + SelectionRuleImpl sel_method(*this); + int select = 0, restart = 0; + IntVector restart_nodes; + while (select < max_select && restart < max_restart) { + + // Perturbation/restart + restart++; + if (_delta_based_restart) { + restart_nodes.clear(); + for (int i = 0; i != _n; i++) { + if (_delta[i] >= _restart_delta_limit) + restart_nodes.push_back(i); + } + } + int rs_node = -1; + if (restart_nodes.size() > 0) { + rs_node = restart_nodes[_rnd[restart_nodes.size()]]; + } else { + rs_node = _rnd[_n]; + } + BoolVector &row = _gr[rs_node]; + for (int i = 0; i != _n; i++) { + if (_clique[i] && !row[i]) delCliqueNode(i); + } + addCliqueNode(rs_node); + + // Local search + _tabu.clear(); + _tabu.resize(_n, false); + bool tabu_empty = true; + int max_swap = _size; + while (select < max_select) { + select++; + int u; + if ((u = sel_method.nextFeasibleAddNode()) != -1) { + // Feasible add move + addCliqueNode(u); + if (tabu_empty) max_swap = _size; + } + else if ((u = sel_method.nextFeasibleSwapNode()) != -1) { + // Feasible swap move + int v = -1; + BoolVector &row = _gr[u]; + for (int i = 0; i != _n; i++) { + if (_clique[i] && !row[i]) { + v = i; + break; + } + } + addCliqueNode(u); + delCliqueNode(v); + _tabu[v] = true; + tabu_empty = false; + if (--max_swap <= 0) break; + } + else if ((u = sel_method.nextAddNode()) != -1) { + // Non-feasible add move + addCliqueNode(u); + } + else break; + } + if (_size > _best_size) { + _best_clique = _clique; + _best_size = _size; + if (_best_size >= max_size) return SIZE_LIMIT; + } + sel_method.update(); + } + + return (restart >= max_restart ? ITERATION_LIMIT : STEP_LIMIT); + } + + }; //class GrossoLocatelliPullanMc + + ///@} + +} //namespace lemon + +#endif //LEMON_GROSSO_LOCATELLI_PULLAN_MC_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/hao_orlin.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/hao_orlin.h new file mode 100644 index 00000000000..0eeaff95d14 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/hao_orlin.h @@ -0,0 +1,1015 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_HAO_ORLIN_H +#define LEMON_HAO_ORLIN_H + +#include +#include +#include + +#include +#include +#include + +/// \file +/// \ingroup min_cut +/// \brief Implementation of the Hao-Orlin algorithm. +/// +/// Implementation of the Hao-Orlin algorithm for finding a minimum cut +/// in a digraph. + +namespace lemon { + + /// \ingroup min_cut + /// + /// \brief Hao-Orlin algorithm for finding a minimum cut in a digraph. + /// + /// This class implements the Hao-Orlin algorithm for finding a minimum + /// value cut in a directed graph \f$D=(V,A)\f$. + /// It takes a fixed node \f$ source \in V \f$ and + /// consists of two phases: in the first phase it determines a + /// minimum cut with \f$ source \f$ on the source-side (i.e. a set + /// \f$ X\subsetneq V \f$ with \f$ source \in X \f$ and minimal outgoing + /// capacity) and in the second phase it determines a minimum cut + /// with \f$ source \f$ on the sink-side (i.e. a set + /// \f$ X\subsetneq V \f$ with \f$ source \notin X \f$ and minimal outgoing + /// capacity). Obviously, the smaller of these two cuts will be a + /// minimum cut of \f$ D \f$. The algorithm is a modified + /// preflow push-relabel algorithm. Our implementation calculates + /// the minimum cut in \f$ O(n^2\sqrt{m}) \f$ time (we use the + /// highest-label rule), or in \f$O(nm)\f$ for unit capacities. A notable + /// use of this algorithm is testing network reliability. + /// + /// For an undirected graph you can run just the first phase of the + /// algorithm or you can use the algorithm of Nagamochi and Ibaraki, + /// which solves the undirected problem in \f$ O(nm + n^2 \log n) \f$ + /// time. It is implemented in the NagamochiIbaraki algorithm class. + /// + /// \tparam GR The type of the digraph the algorithm runs on. + /// \tparam CAP The type of the arc map containing the capacities, + /// which can be any numreric type. The default map type is + /// \ref concepts::Digraph::ArcMap "GR::ArcMap". + /// \tparam TOL Tolerance class for handling inexact computations. The + /// default tolerance type is \ref Tolerance "Tolerance". +#ifdef DOXYGEN + template +#else + template , + typename TOL = Tolerance > +#endif + class HaoOrlin { + public: + + /// The digraph type of the algorithm + typedef GR Digraph; + /// The capacity map type of the algorithm + typedef CAP CapacityMap; + /// The tolerance type of the algorithm + typedef TOL Tolerance; + + private: + + typedef typename CapacityMap::Value Value; + + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + + const Digraph& _graph; + const CapacityMap* _capacity; + + typedef typename Digraph::template ArcMap FlowMap; + FlowMap* _flow; + + Node _source; + + int _node_num; + + // Bucketing structure + std::vector _first, _last; + typename Digraph::template NodeMap* _next; + typename Digraph::template NodeMap* _prev; + typename Digraph::template NodeMap* _active; + typename Digraph::template NodeMap* _bucket; + + std::vector _dormant; + + std::list > _sets; + std::list::iterator _highest; + + typedef typename Digraph::template NodeMap ExcessMap; + ExcessMap* _excess; + + typedef typename Digraph::template NodeMap SourceSetMap; + SourceSetMap* _source_set; + + Value _min_cut; + + typedef typename Digraph::template NodeMap MinCutMap; + MinCutMap* _min_cut_map; + + Tolerance _tolerance; + + public: + + /// \brief Constructor + /// + /// Constructor of the algorithm class. + HaoOrlin(const Digraph& graph, const CapacityMap& capacity, + const Tolerance& tolerance = Tolerance()) : + _graph(graph), _capacity(&capacity), _flow(0), _source(), + _node_num(), _first(), _last(), _next(0), _prev(0), + _active(0), _bucket(0), _dormant(), _sets(), _highest(), + _excess(0), _source_set(0), _min_cut(), _min_cut_map(0), + _tolerance(tolerance) {} + + ~HaoOrlin() { + if (_min_cut_map) { + delete _min_cut_map; + } + if (_source_set) { + delete _source_set; + } + if (_excess) { + delete _excess; + } + if (_next) { + delete _next; + } + if (_prev) { + delete _prev; + } + if (_active) { + delete _active; + } + if (_bucket) { + delete _bucket; + } + if (_flow) { + delete _flow; + } + } + + /// \brief Set the tolerance used by the algorithm. + /// + /// This function sets the tolerance object used by the algorithm. + /// \return (*this) + HaoOrlin& tolerance(const Tolerance& tolerance) { + _tolerance = tolerance; + return *this; + } + + /// \brief Returns a const reference to the tolerance. + /// + /// This function returns a const reference to the tolerance object + /// used by the algorithm. + const Tolerance& tolerance() const { + return _tolerance; + } + + private: + + void activate(const Node& i) { + (*_active)[i] = true; + + int bucket = (*_bucket)[i]; + + if ((*_prev)[i] == INVALID || (*_active)[(*_prev)[i]]) return; + //unlace + (*_next)[(*_prev)[i]] = (*_next)[i]; + if ((*_next)[i] != INVALID) { + (*_prev)[(*_next)[i]] = (*_prev)[i]; + } else { + _last[bucket] = (*_prev)[i]; + } + //lace + (*_next)[i] = _first[bucket]; + (*_prev)[_first[bucket]] = i; + (*_prev)[i] = INVALID; + _first[bucket] = i; + } + + void deactivate(const Node& i) { + (*_active)[i] = false; + int bucket = (*_bucket)[i]; + + if ((*_next)[i] == INVALID || !(*_active)[(*_next)[i]]) return; + + //unlace + (*_prev)[(*_next)[i]] = (*_prev)[i]; + if ((*_prev)[i] != INVALID) { + (*_next)[(*_prev)[i]] = (*_next)[i]; + } else { + _first[bucket] = (*_next)[i]; + } + //lace + (*_prev)[i] = _last[bucket]; + (*_next)[_last[bucket]] = i; + (*_next)[i] = INVALID; + _last[bucket] = i; + } + + void addItem(const Node& i, int bucket) { + (*_bucket)[i] = bucket; + if (_last[bucket] != INVALID) { + (*_prev)[i] = _last[bucket]; + (*_next)[_last[bucket]] = i; + (*_next)[i] = INVALID; + _last[bucket] = i; + } else { + (*_prev)[i] = INVALID; + _first[bucket] = i; + (*_next)[i] = INVALID; + _last[bucket] = i; + } + } + + void findMinCutOut() { + + for (NodeIt n(_graph); n != INVALID; ++n) { + (*_excess)[n] = 0; + (*_source_set)[n] = false; + } + + for (ArcIt a(_graph); a != INVALID; ++a) { + (*_flow)[a] = 0; + } + + int bucket_num = 0; + std::vector queue(_node_num); + int qfirst = 0, qlast = 0, qsep = 0; + + { + typename Digraph::template NodeMap reached(_graph, false); + + reached[_source] = true; + bool first_set = true; + + for (NodeIt t(_graph); t != INVALID; ++t) { + if (reached[t]) continue; + _sets.push_front(std::list()); + + queue[qlast++] = t; + reached[t] = true; + + while (qfirst != qlast) { + if (qsep == qfirst) { + ++bucket_num; + _sets.front().push_front(bucket_num); + _dormant[bucket_num] = !first_set; + _first[bucket_num] = _last[bucket_num] = INVALID; + qsep = qlast; + } + + Node n = queue[qfirst++]; + addItem(n, bucket_num); + + for (InArcIt a(_graph, n); a != INVALID; ++a) { + Node u = _graph.source(a); + if (!reached[u] && _tolerance.positive((*_capacity)[a])) { + reached[u] = true; + queue[qlast++] = u; + } + } + } + first_set = false; + } + + ++bucket_num; + (*_bucket)[_source] = 0; + _dormant[0] = true; + } + (*_source_set)[_source] = true; + + Node target = _last[_sets.back().back()]; + { + for (OutArcIt a(_graph, _source); a != INVALID; ++a) { + if (_tolerance.positive((*_capacity)[a])) { + Node u = _graph.target(a); + (*_flow)[a] = (*_capacity)[a]; + (*_excess)[u] += (*_capacity)[a]; + if (!(*_active)[u] && u != _source) { + activate(u); + } + } + } + + if ((*_active)[target]) { + deactivate(target); + } + + _highest = _sets.back().begin(); + while (_highest != _sets.back().end() && + !(*_active)[_first[*_highest]]) { + ++_highest; + } + } + + while (true) { + while (_highest != _sets.back().end()) { + Node n = _first[*_highest]; + Value excess = (*_excess)[n]; + int next_bucket = _node_num; + + int under_bucket; + if (++std::list::iterator(_highest) == _sets.back().end()) { + under_bucket = -1; + } else { + under_bucket = *(++std::list::iterator(_highest)); + } + + for (OutArcIt a(_graph, n); a != INVALID; ++a) { + Node v = _graph.target(a); + if (_dormant[(*_bucket)[v]]) continue; + Value rem = (*_capacity)[a] - (*_flow)[a]; + if (!_tolerance.positive(rem)) continue; + if ((*_bucket)[v] == under_bucket) { + if (!(*_active)[v] && v != target) { + activate(v); + } + if (!_tolerance.less(rem, excess)) { + (*_flow)[a] += excess; + (*_excess)[v] += excess; + excess = 0; + goto no_more_push; + } else { + excess -= rem; + (*_excess)[v] += rem; + (*_flow)[a] = (*_capacity)[a]; + } + } else if (next_bucket > (*_bucket)[v]) { + next_bucket = (*_bucket)[v]; + } + } + + for (InArcIt a(_graph, n); a != INVALID; ++a) { + Node v = _graph.source(a); + if (_dormant[(*_bucket)[v]]) continue; + Value rem = (*_flow)[a]; + if (!_tolerance.positive(rem)) continue; + if ((*_bucket)[v] == under_bucket) { + if (!(*_active)[v] && v != target) { + activate(v); + } + if (!_tolerance.less(rem, excess)) { + (*_flow)[a] -= excess; + (*_excess)[v] += excess; + excess = 0; + goto no_more_push; + } else { + excess -= rem; + (*_excess)[v] += rem; + (*_flow)[a] = 0; + } + } else if (next_bucket > (*_bucket)[v]) { + next_bucket = (*_bucket)[v]; + } + } + + no_more_push: + + (*_excess)[n] = excess; + + if (excess != 0) { + if ((*_next)[n] == INVALID) { + typename std::list >::iterator new_set = + _sets.insert(--_sets.end(), std::list()); + new_set->splice(new_set->end(), _sets.back(), + _sets.back().begin(), ++_highest); + for (std::list::iterator it = new_set->begin(); + it != new_set->end(); ++it) { + _dormant[*it] = true; + } + while (_highest != _sets.back().end() && + !(*_active)[_first[*_highest]]) { + ++_highest; + } + } else if (next_bucket == _node_num) { + _first[(*_bucket)[n]] = (*_next)[n]; + (*_prev)[(*_next)[n]] = INVALID; + + std::list >::iterator new_set = + _sets.insert(--_sets.end(), std::list()); + + new_set->push_front(bucket_num); + (*_bucket)[n] = bucket_num; + _first[bucket_num] = _last[bucket_num] = n; + (*_next)[n] = INVALID; + (*_prev)[n] = INVALID; + _dormant[bucket_num] = true; + ++bucket_num; + + while (_highest != _sets.back().end() && + !(*_active)[_first[*_highest]]) { + ++_highest; + } + } else { + _first[*_highest] = (*_next)[n]; + (*_prev)[(*_next)[n]] = INVALID; + + while (next_bucket != *_highest) { + --_highest; + } + + if (_highest == _sets.back().begin()) { + _sets.back().push_front(bucket_num); + _dormant[bucket_num] = false; + _first[bucket_num] = _last[bucket_num] = INVALID; + ++bucket_num; + } + --_highest; + + (*_bucket)[n] = *_highest; + (*_next)[n] = _first[*_highest]; + if (_first[*_highest] != INVALID) { + (*_prev)[_first[*_highest]] = n; + } else { + _last[*_highest] = n; + } + _first[*_highest] = n; + } + } else { + + deactivate(n); + if (!(*_active)[_first[*_highest]]) { + ++_highest; + if (_highest != _sets.back().end() && + !(*_active)[_first[*_highest]]) { + _highest = _sets.back().end(); + } + } + } + } + + if ((*_excess)[target] < _min_cut) { + _min_cut = (*_excess)[target]; + for (NodeIt i(_graph); i != INVALID; ++i) { + (*_min_cut_map)[i] = true; + } + for (std::list::iterator it = _sets.back().begin(); + it != _sets.back().end(); ++it) { + Node n = _first[*it]; + while (n != INVALID) { + (*_min_cut_map)[n] = false; + n = (*_next)[n]; + } + } + } + + { + Node new_target; + if ((*_prev)[target] != INVALID || (*_next)[target] != INVALID) { + if ((*_next)[target] == INVALID) { + _last[(*_bucket)[target]] = (*_prev)[target]; + new_target = (*_prev)[target]; + } else { + (*_prev)[(*_next)[target]] = (*_prev)[target]; + new_target = (*_next)[target]; + } + if ((*_prev)[target] == INVALID) { + _first[(*_bucket)[target]] = (*_next)[target]; + } else { + (*_next)[(*_prev)[target]] = (*_next)[target]; + } + } else { + _sets.back().pop_back(); + if (_sets.back().empty()) { + _sets.pop_back(); + if (_sets.empty()) + break; + for (std::list::iterator it = _sets.back().begin(); + it != _sets.back().end(); ++it) { + _dormant[*it] = false; + } + } + new_target = _last[_sets.back().back()]; + } + + (*_bucket)[target] = 0; + + (*_source_set)[target] = true; + for (OutArcIt a(_graph, target); a != INVALID; ++a) { + Value rem = (*_capacity)[a] - (*_flow)[a]; + if (!_tolerance.positive(rem)) continue; + Node v = _graph.target(a); + if (!(*_active)[v] && !(*_source_set)[v]) { + activate(v); + } + (*_excess)[v] += rem; + (*_flow)[a] = (*_capacity)[a]; + } + + for (InArcIt a(_graph, target); a != INVALID; ++a) { + Value rem = (*_flow)[a]; + if (!_tolerance.positive(rem)) continue; + Node v = _graph.source(a); + if (!(*_active)[v] && !(*_source_set)[v]) { + activate(v); + } + (*_excess)[v] += rem; + (*_flow)[a] = 0; + } + + target = new_target; + if ((*_active)[target]) { + deactivate(target); + } + + _highest = _sets.back().begin(); + while (_highest != _sets.back().end() && + !(*_active)[_first[*_highest]]) { + ++_highest; + } + } + } + } + + void findMinCutIn() { + + for (NodeIt n(_graph); n != INVALID; ++n) { + (*_excess)[n] = 0; + (*_source_set)[n] = false; + } + + for (ArcIt a(_graph); a != INVALID; ++a) { + (*_flow)[a] = 0; + } + + int bucket_num = 0; + std::vector queue(_node_num); + int qfirst = 0, qlast = 0, qsep = 0; + + { + typename Digraph::template NodeMap reached(_graph, false); + + reached[_source] = true; + + bool first_set = true; + + for (NodeIt t(_graph); t != INVALID; ++t) { + if (reached[t]) continue; + _sets.push_front(std::list()); + + queue[qlast++] = t; + reached[t] = true; + + while (qfirst != qlast) { + if (qsep == qfirst) { + ++bucket_num; + _sets.front().push_front(bucket_num); + _dormant[bucket_num] = !first_set; + _first[bucket_num] = _last[bucket_num] = INVALID; + qsep = qlast; + } + + Node n = queue[qfirst++]; + addItem(n, bucket_num); + + for (OutArcIt a(_graph, n); a != INVALID; ++a) { + Node u = _graph.target(a); + if (!reached[u] && _tolerance.positive((*_capacity)[a])) { + reached[u] = true; + queue[qlast++] = u; + } + } + } + first_set = false; + } + + ++bucket_num; + (*_bucket)[_source] = 0; + _dormant[0] = true; + } + (*_source_set)[_source] = true; + + Node target = _last[_sets.back().back()]; + { + for (InArcIt a(_graph, _source); a != INVALID; ++a) { + if (_tolerance.positive((*_capacity)[a])) { + Node u = _graph.source(a); + (*_flow)[a] = (*_capacity)[a]; + (*_excess)[u] += (*_capacity)[a]; + if (!(*_active)[u] && u != _source) { + activate(u); + } + } + } + if ((*_active)[target]) { + deactivate(target); + } + + _highest = _sets.back().begin(); + while (_highest != _sets.back().end() && + !(*_active)[_first[*_highest]]) { + ++_highest; + } + } + + + while (true) { + while (_highest != _sets.back().end()) { + Node n = _first[*_highest]; + Value excess = (*_excess)[n]; + int next_bucket = _node_num; + + int under_bucket; + if (++std::list::iterator(_highest) == _sets.back().end()) { + under_bucket = -1; + } else { + under_bucket = *(++std::list::iterator(_highest)); + } + + for (InArcIt a(_graph, n); a != INVALID; ++a) { + Node v = _graph.source(a); + if (_dormant[(*_bucket)[v]]) continue; + Value rem = (*_capacity)[a] - (*_flow)[a]; + if (!_tolerance.positive(rem)) continue; + if ((*_bucket)[v] == under_bucket) { + if (!(*_active)[v] && v != target) { + activate(v); + } + if (!_tolerance.less(rem, excess)) { + (*_flow)[a] += excess; + (*_excess)[v] += excess; + excess = 0; + goto no_more_push; + } else { + excess -= rem; + (*_excess)[v] += rem; + (*_flow)[a] = (*_capacity)[a]; + } + } else if (next_bucket > (*_bucket)[v]) { + next_bucket = (*_bucket)[v]; + } + } + + for (OutArcIt a(_graph, n); a != INVALID; ++a) { + Node v = _graph.target(a); + if (_dormant[(*_bucket)[v]]) continue; + Value rem = (*_flow)[a]; + if (!_tolerance.positive(rem)) continue; + if ((*_bucket)[v] == under_bucket) { + if (!(*_active)[v] && v != target) { + activate(v); + } + if (!_tolerance.less(rem, excess)) { + (*_flow)[a] -= excess; + (*_excess)[v] += excess; + excess = 0; + goto no_more_push; + } else { + excess -= rem; + (*_excess)[v] += rem; + (*_flow)[a] = 0; + } + } else if (next_bucket > (*_bucket)[v]) { + next_bucket = (*_bucket)[v]; + } + } + + no_more_push: + + (*_excess)[n] = excess; + + if (excess != 0) { + if ((*_next)[n] == INVALID) { + typename std::list >::iterator new_set = + _sets.insert(--_sets.end(), std::list()); + new_set->splice(new_set->end(), _sets.back(), + _sets.back().begin(), ++_highest); + for (std::list::iterator it = new_set->begin(); + it != new_set->end(); ++it) { + _dormant[*it] = true; + } + while (_highest != _sets.back().end() && + !(*_active)[_first[*_highest]]) { + ++_highest; + } + } else if (next_bucket == _node_num) { + _first[(*_bucket)[n]] = (*_next)[n]; + (*_prev)[(*_next)[n]] = INVALID; + + std::list >::iterator new_set = + _sets.insert(--_sets.end(), std::list()); + + new_set->push_front(bucket_num); + (*_bucket)[n] = bucket_num; + _first[bucket_num] = _last[bucket_num] = n; + (*_next)[n] = INVALID; + (*_prev)[n] = INVALID; + _dormant[bucket_num] = true; + ++bucket_num; + + while (_highest != _sets.back().end() && + !(*_active)[_first[*_highest]]) { + ++_highest; + } + } else { + _first[*_highest] = (*_next)[n]; + (*_prev)[(*_next)[n]] = INVALID; + + while (next_bucket != *_highest) { + --_highest; + } + if (_highest == _sets.back().begin()) { + _sets.back().push_front(bucket_num); + _dormant[bucket_num] = false; + _first[bucket_num] = _last[bucket_num] = INVALID; + ++bucket_num; + } + --_highest; + + (*_bucket)[n] = *_highest; + (*_next)[n] = _first[*_highest]; + if (_first[*_highest] != INVALID) { + (*_prev)[_first[*_highest]] = n; + } else { + _last[*_highest] = n; + } + _first[*_highest] = n; + } + } else { + + deactivate(n); + if (!(*_active)[_first[*_highest]]) { + ++_highest; + if (_highest != _sets.back().end() && + !(*_active)[_first[*_highest]]) { + _highest = _sets.back().end(); + } + } + } + } + + if ((*_excess)[target] < _min_cut) { + _min_cut = (*_excess)[target]; + for (NodeIt i(_graph); i != INVALID; ++i) { + (*_min_cut_map)[i] = false; + } + for (std::list::iterator it = _sets.back().begin(); + it != _sets.back().end(); ++it) { + Node n = _first[*it]; + while (n != INVALID) { + (*_min_cut_map)[n] = true; + n = (*_next)[n]; + } + } + } + + { + Node new_target; + if ((*_prev)[target] != INVALID || (*_next)[target] != INVALID) { + if ((*_next)[target] == INVALID) { + _last[(*_bucket)[target]] = (*_prev)[target]; + new_target = (*_prev)[target]; + } else { + (*_prev)[(*_next)[target]] = (*_prev)[target]; + new_target = (*_next)[target]; + } + if ((*_prev)[target] == INVALID) { + _first[(*_bucket)[target]] = (*_next)[target]; + } else { + (*_next)[(*_prev)[target]] = (*_next)[target]; + } + } else { + _sets.back().pop_back(); + if (_sets.back().empty()) { + _sets.pop_back(); + if (_sets.empty()) + break; + for (std::list::iterator it = _sets.back().begin(); + it != _sets.back().end(); ++it) { + _dormant[*it] = false; + } + } + new_target = _last[_sets.back().back()]; + } + + (*_bucket)[target] = 0; + + (*_source_set)[target] = true; + for (InArcIt a(_graph, target); a != INVALID; ++a) { + Value rem = (*_capacity)[a] - (*_flow)[a]; + if (!_tolerance.positive(rem)) continue; + Node v = _graph.source(a); + if (!(*_active)[v] && !(*_source_set)[v]) { + activate(v); + } + (*_excess)[v] += rem; + (*_flow)[a] = (*_capacity)[a]; + } + + for (OutArcIt a(_graph, target); a != INVALID; ++a) { + Value rem = (*_flow)[a]; + if (!_tolerance.positive(rem)) continue; + Node v = _graph.target(a); + if (!(*_active)[v] && !(*_source_set)[v]) { + activate(v); + } + (*_excess)[v] += rem; + (*_flow)[a] = 0; + } + + target = new_target; + if ((*_active)[target]) { + deactivate(target); + } + + _highest = _sets.back().begin(); + while (_highest != _sets.back().end() && + !(*_active)[_first[*_highest]]) { + ++_highest; + } + } + } + } + + public: + + /// \name Execution Control + /// The simplest way to execute the algorithm is to use + /// one of the member functions called \ref run(). + /// \n + /// If you need better control on the execution, + /// you have to call one of the \ref init() functions first, then + /// \ref calculateOut() and/or \ref calculateIn(). + + /// @{ + + /// \brief Initialize the internal data structures. + /// + /// This function initializes the internal data structures. It creates + /// the maps and some bucket structures for the algorithm. + /// The first node is used as the source node for the push-relabel + /// algorithm. + void init() { + init(NodeIt(_graph)); + } + + /// \brief Initialize the internal data structures. + /// + /// This function initializes the internal data structures. It creates + /// the maps and some bucket structures for the algorithm. + /// The given node is used as the source node for the push-relabel + /// algorithm. + void init(const Node& source) { + _source = source; + + _node_num = countNodes(_graph); + + _first.resize(_node_num); + _last.resize(_node_num); + + _dormant.resize(_node_num); + + if (!_flow) { + _flow = new FlowMap(_graph); + } + if (!_next) { + _next = new typename Digraph::template NodeMap(_graph); + } + if (!_prev) { + _prev = new typename Digraph::template NodeMap(_graph); + } + if (!_active) { + _active = new typename Digraph::template NodeMap(_graph); + } + if (!_bucket) { + _bucket = new typename Digraph::template NodeMap(_graph); + } + if (!_excess) { + _excess = new ExcessMap(_graph); + } + if (!_source_set) { + _source_set = new SourceSetMap(_graph); + } + if (!_min_cut_map) { + _min_cut_map = new MinCutMap(_graph); + } + + _min_cut = std::numeric_limits::max(); + } + + + /// \brief Calculate a minimum cut with \f$ source \f$ on the + /// source-side. + /// + /// This function calculates a minimum cut with \f$ source \f$ on the + /// source-side (i.e. a set \f$ X\subsetneq V \f$ with + /// \f$ source \in X \f$ and minimal outgoing capacity). + /// It updates the stored cut if (and only if) the newly found one + /// is better. + /// + /// \pre \ref init() must be called before using this function. + void calculateOut() { + findMinCutOut(); + } + + /// \brief Calculate a minimum cut with \f$ source \f$ on the + /// sink-side. + /// + /// This function calculates a minimum cut with \f$ source \f$ on the + /// sink-side (i.e. a set \f$ X\subsetneq V \f$ with + /// \f$ source \notin X \f$ and minimal outgoing capacity). + /// It updates the stored cut if (and only if) the newly found one + /// is better. + /// + /// \pre \ref init() must be called before using this function. + void calculateIn() { + findMinCutIn(); + } + + + /// \brief Run the algorithm. + /// + /// This function runs the algorithm. It chooses source node, + /// then calls \ref init(), \ref calculateOut() + /// and \ref calculateIn(). + void run() { + init(); + calculateOut(); + calculateIn(); + } + + /// \brief Run the algorithm. + /// + /// This function runs the algorithm. It calls \ref init(), + /// \ref calculateOut() and \ref calculateIn() with the given + /// source node. + void run(const Node& s) { + init(s); + calculateOut(); + calculateIn(); + } + + /// @} + + /// \name Query Functions + /// The result of the %HaoOrlin algorithm + /// can be obtained using these functions.\n + /// \ref run(), \ref calculateOut() or \ref calculateIn() + /// should be called before using them. + + /// @{ + + /// \brief Return the value of the minimum cut. + /// + /// This function returns the value of the best cut found by the + /// previously called \ref run(), \ref calculateOut() or \ref + /// calculateIn(). + /// + /// \pre \ref run(), \ref calculateOut() or \ref calculateIn() + /// must be called before using this function. + Value minCutValue() const { + return _min_cut; + } + + + /// \brief Return a minimum cut. + /// + /// This function gives the best cut found by the + /// previously called \ref run(), \ref calculateOut() or \ref + /// calculateIn(). + /// + /// It sets \c cutMap to the characteristic vector of the found + /// minimum value cut - a non-empty set \f$ X\subsetneq V \f$ + /// of minimum outgoing capacity (i.e. \c cutMap will be \c true exactly + /// for the nodes of \f$ X \f$). + /// + /// \param cutMap A \ref concepts::WriteMap "writable" node map with + /// \c bool (or convertible) value type. + /// + /// \return The value of the minimum cut. + /// + /// \pre \ref run(), \ref calculateOut() or \ref calculateIn() + /// must be called before using this function. + template + Value minCutMap(CutMap& cutMap) const { + for (NodeIt it(_graph); it != INVALID; ++it) { + cutMap.set(it, (*_min_cut_map)[it]); + } + return _min_cut; + } + + /// @} + + }; //class HaoOrlin + +} //namespace lemon + +#endif //LEMON_HAO_ORLIN_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/hartmann_orlin_mmc.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/hartmann_orlin_mmc.h new file mode 100644 index 00000000000..6b60a85ed7a --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/hartmann_orlin_mmc.h @@ -0,0 +1,654 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_HARTMANN_ORLIN_MMC_H +#define LEMON_HARTMANN_ORLIN_MMC_H + +/// \ingroup min_mean_cycle +/// +/// \file +/// \brief Hartmann-Orlin's algorithm for finding a minimum mean cycle. + +#include +#include +#include +#include +#include +#include + +namespace lemon { + + /// \brief Default traits class of HartmannOrlinMmc class. + /// + /// Default traits class of HartmannOrlinMmc class. + /// \tparam GR The type of the digraph. + /// \tparam CM The type of the cost map. + /// It must conform to the \ref concepts::ReadMap "ReadMap" concept. +#ifdef DOXYGEN + template +#else + template ::is_integer> +#endif + struct HartmannOrlinMmcDefaultTraits + { + /// The type of the digraph + typedef GR Digraph; + /// The type of the cost map + typedef CM CostMap; + /// The type of the arc costs + typedef typename CostMap::Value Cost; + + /// \brief The large cost type used for internal computations + /// + /// The large cost type used for internal computations. + /// It is \c long \c long if the \c Cost type is integer, + /// otherwise it is \c double. + /// \c Cost must be convertible to \c LargeCost. + typedef double LargeCost; + + /// The tolerance type used for internal computations + typedef lemon::Tolerance Tolerance; + + /// \brief The path type of the found cycles + /// + /// The path type of the found cycles. + /// It must conform to the \ref lemon::concepts::Path "Path" concept + /// and it must have an \c addFront() function. + typedef lemon::Path Path; + }; + + // Default traits class for integer cost types + template + struct HartmannOrlinMmcDefaultTraits + { + typedef GR Digraph; + typedef CM CostMap; + typedef typename CostMap::Value Cost; +#ifdef LEMON_HAVE_LONG_LONG + typedef long long LargeCost; +#else + typedef long LargeCost; +#endif + typedef lemon::Tolerance Tolerance; + typedef lemon::Path Path; + }; + + + /// \addtogroup min_mean_cycle + /// @{ + + /// \brief Implementation of the Hartmann-Orlin algorithm for finding + /// a minimum mean cycle. + /// + /// This class implements the Hartmann-Orlin algorithm for finding + /// a directed cycle of minimum mean cost in a digraph + /// \cite hartmann93finding, \cite dasdan98minmeancycle. + /// This method is based on \ref KarpMmc "Karp"'s original algorithm, but + /// applies an early termination scheme. It makes the algorithm + /// significantly faster for some problem instances, but slower for others. + /// The algorithm runs in time O(nm) and uses space O(n2+m). + /// + /// \tparam GR The type of the digraph the algorithm runs on. + /// \tparam CM The type of the cost map. The default + /// map type is \ref concepts::Digraph::ArcMap "GR::ArcMap". + /// \tparam TR The traits class that defines various types used by the + /// algorithm. By default, it is \ref HartmannOrlinMmcDefaultTraits + /// "HartmannOrlinMmcDefaultTraits". + /// In most cases, this parameter should not be set directly, + /// consider to use the named template parameters instead. +#ifdef DOXYGEN + template +#else + template < typename GR, + typename CM = typename GR::template ArcMap, + typename TR = HartmannOrlinMmcDefaultTraits > +#endif + class HartmannOrlinMmc + { + public: + + /// The type of the digraph + typedef typename TR::Digraph Digraph; + /// The type of the cost map + typedef typename TR::CostMap CostMap; + /// The type of the arc costs + typedef typename TR::Cost Cost; + + /// \brief The large cost type + /// + /// The large cost type used for internal computations. + /// By default, it is \c long \c long if the \c Cost type is integer, + /// otherwise it is \c double. + typedef typename TR::LargeCost LargeCost; + + /// The tolerance type + typedef typename TR::Tolerance Tolerance; + + /// \brief The path type of the found cycles + /// + /// The path type of the found cycles. + /// Using the \ref lemon::HartmannOrlinMmcDefaultTraits + /// "default traits class", + /// it is \ref lemon::Path "Path". + typedef typename TR::Path Path; + + /// \brief The + /// \ref lemon::HartmannOrlinMmcDefaultTraits "traits class" + /// of the algorithm + typedef TR Traits; + + private: + + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + + // Data sturcture for path data + struct PathData + { + LargeCost dist; + Arc pred; + PathData(LargeCost d, Arc p = INVALID) : + dist(d), pred(p) {} + }; + + typedef typename Digraph::template NodeMap > + PathDataNodeMap; + + private: + + // The digraph the algorithm runs on + const Digraph &_gr; + // The cost of the arcs + const CostMap &_cost; + + // Data for storing the strongly connected components + int _comp_num; + typename Digraph::template NodeMap _comp; + std::vector > _comp_nodes; + std::vector* _nodes; + typename Digraph::template NodeMap > _out_arcs; + + // Data for the found cycles + bool _curr_found, _best_found; + LargeCost _curr_cost, _best_cost; + int _curr_size, _best_size; + Node _curr_node, _best_node; + int _curr_level, _best_level; + + Path *_cycle_path; + bool _local_path; + + // Node map for storing path data + PathDataNodeMap _data; + // The processed nodes in the last round + std::vector _process; + + Tolerance _tolerance; + + // Infinite constant + const LargeCost INF; + + public: + + /// \name Named Template Parameters + /// @{ + + template + struct SetLargeCostTraits : public Traits { + typedef T LargeCost; + typedef lemon::Tolerance Tolerance; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c LargeCost type. + /// + /// \ref named-templ-param "Named parameter" for setting \c LargeCost + /// type. It is used for internal computations in the algorithm. + template + struct SetLargeCost + : public HartmannOrlinMmc > { + typedef HartmannOrlinMmc > Create; + }; + + template + struct SetPathTraits : public Traits { + typedef T Path; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c %Path type. + /// + /// \ref named-templ-param "Named parameter" for setting the \c %Path + /// type of the found cycles. + /// It must conform to the \ref lemon::concepts::Path "Path" concept + /// and it must have an \c addFront() function. + template + struct SetPath + : public HartmannOrlinMmc > { + typedef HartmannOrlinMmc > Create; + }; + + /// @} + + protected: + + HartmannOrlinMmc() {} + + public: + + /// \brief Constructor. + /// + /// The constructor of the class. + /// + /// \param digraph The digraph the algorithm runs on. + /// \param cost The costs of the arcs. + HartmannOrlinMmc( const Digraph &digraph, + const CostMap &cost ) : + _gr(digraph), _cost(cost), _comp(digraph), _out_arcs(digraph), + _best_found(false), _best_cost(0), _best_size(1), + _cycle_path(NULL), _local_path(false), _data(digraph), + INF(std::numeric_limits::has_infinity ? + std::numeric_limits::infinity() : + std::numeric_limits::max()) + {} + + /// Destructor. + ~HartmannOrlinMmc() { + if (_local_path) delete _cycle_path; + } + + /// \brief Set the path structure for storing the found cycle. + /// + /// This function sets an external path structure for storing the + /// found cycle. + /// + /// If you don't call this function before calling \ref run() or + /// \ref findCycleMean(), a local \ref Path "path" structure + /// will be allocated. The destuctor deallocates this automatically + /// allocated object, of course. + /// + /// \note The algorithm calls only the \ref lemon::Path::addFront() + /// "addFront()" function of the given path structure. + /// + /// \return (*this) + HartmannOrlinMmc& cycle(Path &path) { + if (_local_path) { + delete _cycle_path; + _local_path = false; + } + _cycle_path = &path; + return *this; + } + + /// \brief Set the tolerance used by the algorithm. + /// + /// This function sets the tolerance object used by the algorithm. + /// + /// \return (*this) + HartmannOrlinMmc& tolerance(const Tolerance& tolerance) { + _tolerance = tolerance; + return *this; + } + + /// \brief Return a const reference to the tolerance. + /// + /// This function returns a const reference to the tolerance object + /// used by the algorithm. + const Tolerance& tolerance() const { + return _tolerance; + } + + /// \name Execution control + /// The simplest way to execute the algorithm is to call the \ref run() + /// function.\n + /// If you only need the minimum mean cost, you may call + /// \ref findCycleMean(). + + /// @{ + + /// \brief Run the algorithm. + /// + /// This function runs the algorithm. + /// It can be called more than once (e.g. if the underlying digraph + /// and/or the arc costs have been modified). + /// + /// \return \c true if a directed cycle exists in the digraph. + /// + /// \note mmc.run() is just a shortcut of the following code. + /// \code + /// return mmc.findCycleMean() && mmc.findCycle(); + /// \endcode + bool run() { + return findCycleMean() && findCycle(); + } + + /// \brief Find the minimum cycle mean. + /// + /// This function finds the minimum mean cost of the directed + /// cycles in the digraph. + /// + /// \return \c true if a directed cycle exists in the digraph. + bool findCycleMean() { + // Initialization and find strongly connected components + init(); + findComponents(); + + // Find the minimum cycle mean in the components + for (int comp = 0; comp < _comp_num; ++comp) { + if (!initComponent(comp)) continue; + processRounds(); + + // Update the best cycle (global minimum mean cycle) + if ( _curr_found && (!_best_found || + _curr_cost * _best_size < _best_cost * _curr_size) ) { + _best_found = true; + _best_cost = _curr_cost; + _best_size = _curr_size; + _best_node = _curr_node; + _best_level = _curr_level; + } + } + return _best_found; + } + + /// \brief Find a minimum mean directed cycle. + /// + /// This function finds a directed cycle of minimum mean cost + /// in the digraph using the data computed by findCycleMean(). + /// + /// \return \c true if a directed cycle exists in the digraph. + /// + /// \pre \ref findCycleMean() must be called before using this function. + bool findCycle() { + if (!_best_found) return false; + IntNodeMap reached(_gr, -1); + int r = _best_level + 1; + Node u = _best_node; + while (reached[u] < 0) { + reached[u] = --r; + u = _gr.source(_data[u][r].pred); + } + r = reached[u]; + Arc e = _data[u][r].pred; + _cycle_path->addFront(e); + _best_cost = _cost[e]; + _best_size = 1; + Node v; + while ((v = _gr.source(e)) != u) { + e = _data[v][--r].pred; + _cycle_path->addFront(e); + _best_cost += _cost[e]; + ++_best_size; + } + return true; + } + + /// @} + + /// \name Query Functions + /// The results of the algorithm can be obtained using these + /// functions.\n + /// The algorithm should be executed before using them. + + /// @{ + + /// \brief Return the total cost of the found cycle. + /// + /// This function returns the total cost of the found cycle. + /// + /// \pre \ref run() or \ref findCycleMean() must be called before + /// using this function. + Cost cycleCost() const { + return static_cast(_best_cost); + } + + /// \brief Return the number of arcs on the found cycle. + /// + /// This function returns the number of arcs on the found cycle. + /// + /// \pre \ref run() or \ref findCycleMean() must be called before + /// using this function. + int cycleSize() const { + return _best_size; + } + + /// \brief Return the mean cost of the found cycle. + /// + /// This function returns the mean cost of the found cycle. + /// + /// \note alg.cycleMean() is just a shortcut of the + /// following code. + /// \code + /// return static_cast(alg.cycleCost()) / alg.cycleSize(); + /// \endcode + /// + /// \pre \ref run() or \ref findCycleMean() must be called before + /// using this function. + double cycleMean() const { + return static_cast(_best_cost) / _best_size; + } + + /// \brief Return the found cycle. + /// + /// This function returns a const reference to the path structure + /// storing the found cycle. + /// + /// \pre \ref run() or \ref findCycle() must be called before using + /// this function. + const Path& cycle() const { + return *_cycle_path; + } + + ///@} + + private: + + // Initialization + void init() { + if (!_cycle_path) { + _local_path = true; + _cycle_path = new Path; + } + _cycle_path->clear(); + _best_found = false; + _best_cost = 0; + _best_size = 1; + _cycle_path->clear(); + for (NodeIt u(_gr); u != INVALID; ++u) + _data[u].clear(); + } + + // Find strongly connected components and initialize _comp_nodes + // and _out_arcs + void findComponents() { + _comp_num = stronglyConnectedComponents(_gr, _comp); + _comp_nodes.resize(_comp_num); + if (_comp_num == 1) { + _comp_nodes[0].clear(); + for (NodeIt n(_gr); n != INVALID; ++n) { + _comp_nodes[0].push_back(n); + _out_arcs[n].clear(); + for (OutArcIt a(_gr, n); a != INVALID; ++a) { + _out_arcs[n].push_back(a); + } + } + } else { + for (int i = 0; i < _comp_num; ++i) + _comp_nodes[i].clear(); + for (NodeIt n(_gr); n != INVALID; ++n) { + int k = _comp[n]; + _comp_nodes[k].push_back(n); + _out_arcs[n].clear(); + for (OutArcIt a(_gr, n); a != INVALID; ++a) { + if (_comp[_gr.target(a)] == k) _out_arcs[n].push_back(a); + } + } + } + } + + // Initialize path data for the current component + bool initComponent(int comp) { + _nodes = &(_comp_nodes[comp]); + int n = _nodes->size(); + if (n < 1 || (n == 1 && _out_arcs[(*_nodes)[0]].size() == 0)) { + return false; + } + for (int i = 0; i < n; ++i) { + _data[(*_nodes)[i]].resize(n + 1, PathData(INF)); + } + return true; + } + + // Process all rounds of computing path data for the current component. + // _data[v][k] is the cost of a shortest directed walk from the root + // node to node v containing exactly k arcs. + void processRounds() { + Node start = (*_nodes)[0]; + _data[start][0] = PathData(0); + _process.clear(); + _process.push_back(start); + + int k, n = _nodes->size(); + int next_check = 4; + bool terminate = false; + for (k = 1; k <= n && int(_process.size()) < n && !terminate; ++k) { + processNextBuildRound(k); + if (k == next_check || k == n) { + terminate = checkTermination(k); + next_check = next_check * 3 / 2; + } + } + for ( ; k <= n && !terminate; ++k) { + processNextFullRound(k); + if (k == next_check || k == n) { + terminate = checkTermination(k); + next_check = next_check * 3 / 2; + } + } + } + + // Process one round and rebuild _process + void processNextBuildRound(int k) { + std::vector next; + Node u, v; + Arc e; + LargeCost d; + for (int i = 0; i < int(_process.size()); ++i) { + u = _process[i]; + for (int j = 0; j < int(_out_arcs[u].size()); ++j) { + e = _out_arcs[u][j]; + v = _gr.target(e); + d = _data[u][k-1].dist + _cost[e]; + if (_tolerance.less(d, _data[v][k].dist)) { + if (_data[v][k].dist == INF) next.push_back(v); + _data[v][k] = PathData(d, e); + } + } + } + _process.swap(next); + } + + // Process one round using _nodes instead of _process + void processNextFullRound(int k) { + Node u, v; + Arc e; + LargeCost d; + for (int i = 0; i < int(_nodes->size()); ++i) { + u = (*_nodes)[i]; + for (int j = 0; j < int(_out_arcs[u].size()); ++j) { + e = _out_arcs[u][j]; + v = _gr.target(e); + d = _data[u][k-1].dist + _cost[e]; + if (_tolerance.less(d, _data[v][k].dist)) { + _data[v][k] = PathData(d, e); + } + } + } + } + + // Check early termination + bool checkTermination(int k) { + typedef std::pair Pair; + typename GR::template NodeMap level(_gr, Pair(-1, 0)); + typename GR::template NodeMap pi(_gr); + int n = _nodes->size(); + LargeCost cost; + int size; + Node u; + + // Search for cycles that are already found + _curr_found = false; + for (int i = 0; i < n; ++i) { + u = (*_nodes)[i]; + if (_data[u][k].dist == INF) continue; + for (int j = k; j >= 0; --j) { + if (level[u].first == i && level[u].second > 0) { + // A cycle is found + cost = _data[u][level[u].second].dist - _data[u][j].dist; + size = level[u].second - j; + if (!_curr_found || cost * _curr_size < _curr_cost * size) { + _curr_cost = cost; + _curr_size = size; + _curr_node = u; + _curr_level = level[u].second; + _curr_found = true; + } + } + level[u] = Pair(i, j); + if (j != 0) { + u = _gr.source(_data[u][j].pred); + } + } + } + + // If at least one cycle is found, check the optimality condition + LargeCost d; + if (_curr_found && k < n) { + // Find node potentials + for (int i = 0; i < n; ++i) { + u = (*_nodes)[i]; + pi[u] = INF; + for (int j = 0; j <= k; ++j) { + if (_data[u][j].dist < INF) { + d = _data[u][j].dist * _curr_size - j * _curr_cost; + if (_tolerance.less(d, pi[u])) pi[u] = d; + } + } + } + + // Check the optimality condition for all arcs + bool done = true; + for (ArcIt a(_gr); a != INVALID; ++a) { + if (_tolerance.less(_cost[a] * _curr_size - _curr_cost, + pi[_gr.target(a)] - pi[_gr.source(a)]) ) { + done = false; + break; + } + } + return done; + } + return (k == n); + } + + }; //class HartmannOrlinMmc + + ///@} + +} //namespace lemon + +#endif //LEMON_HARTMANN_ORLIN_MMC_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/howard_mmc.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/howard_mmc.h new file mode 100644 index 00000000000..690236340ff --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/howard_mmc.h @@ -0,0 +1,651 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_HOWARD_MMC_H +#define LEMON_HOWARD_MMC_H + +/// \ingroup min_mean_cycle +/// +/// \file +/// \brief Howard's algorithm for finding a minimum mean cycle. + +#include +#include +#include +#include +#include +#include + +namespace lemon { + + /// \brief Default traits class of HowardMmc class. + /// + /// Default traits class of HowardMmc class. + /// \tparam GR The type of the digraph. + /// \tparam CM The type of the cost map. + /// It must conform to the \ref concepts::ReadMap "ReadMap" concept. +#ifdef DOXYGEN + template +#else + template ::is_integer> +#endif + struct HowardMmcDefaultTraits + { + /// The type of the digraph + typedef GR Digraph; + /// The type of the cost map + typedef CM CostMap; + /// The type of the arc costs + typedef typename CostMap::Value Cost; + + /// \brief The large cost type used for internal computations + /// + /// The large cost type used for internal computations. + /// It is \c long \c long if the \c Cost type is integer, + /// otherwise it is \c double. + /// \c Cost must be convertible to \c LargeCost. + typedef double LargeCost; + + /// The tolerance type used for internal computations + typedef lemon::Tolerance Tolerance; + + /// \brief The path type of the found cycles + /// + /// The path type of the found cycles. + /// It must conform to the \ref lemon::concepts::Path "Path" concept + /// and it must have an \c addBack() function. + typedef lemon::Path Path; + }; + + // Default traits class for integer cost types + template + struct HowardMmcDefaultTraits + { + typedef GR Digraph; + typedef CM CostMap; + typedef typename CostMap::Value Cost; +#ifdef LEMON_HAVE_LONG_LONG + typedef long long LargeCost; +#else + typedef long LargeCost; +#endif + typedef lemon::Tolerance Tolerance; + typedef lemon::Path Path; + }; + + + /// \addtogroup min_mean_cycle + /// @{ + + /// \brief Implementation of Howard's algorithm for finding a minimum + /// mean cycle. + /// + /// This class implements Howard's policy iteration algorithm for finding + /// a directed cycle of minimum mean cost in a digraph + /// \cite dasdan98minmeancycle, \cite dasdan04experimental. + /// This class provides the most efficient algorithm for the + /// minimum mean cycle problem, though the best known theoretical + /// bound on its running time is exponential. + /// + /// \tparam GR The type of the digraph the algorithm runs on. + /// \tparam CM The type of the cost map. The default + /// map type is \ref concepts::Digraph::ArcMap "GR::ArcMap". + /// \tparam TR The traits class that defines various types used by the + /// algorithm. By default, it is \ref HowardMmcDefaultTraits + /// "HowardMmcDefaultTraits". + /// In most cases, this parameter should not be set directly, + /// consider to use the named template parameters instead. +#ifdef DOXYGEN + template +#else + template < typename GR, + typename CM = typename GR::template ArcMap, + typename TR = HowardMmcDefaultTraits > +#endif + class HowardMmc + { + public: + + /// The type of the digraph + typedef typename TR::Digraph Digraph; + /// The type of the cost map + typedef typename TR::CostMap CostMap; + /// The type of the arc costs + typedef typename TR::Cost Cost; + + /// \brief The large cost type + /// + /// The large cost type used for internal computations. + /// By default, it is \c long \c long if the \c Cost type is integer, + /// otherwise it is \c double. + typedef typename TR::LargeCost LargeCost; + + /// The tolerance type + typedef typename TR::Tolerance Tolerance; + + /// \brief The path type of the found cycles + /// + /// The path type of the found cycles. + /// Using the \ref lemon::HowardMmcDefaultTraits "default traits class", + /// it is \ref lemon::Path "Path". + typedef typename TR::Path Path; + + /// The \ref lemon::HowardMmcDefaultTraits "traits class" of the algorithm + typedef TR Traits; + + /// \brief Constants for the causes of search termination. + /// + /// Enum type containing constants for the different causes of search + /// termination. The \ref findCycleMean() function returns one of + /// these values. + enum TerminationCause { + + /// No directed cycle can be found in the digraph. + NO_CYCLE = 0, + + /// Optimal solution (minimum cycle mean) is found. + OPTIMAL = 1, + + /// The iteration count limit is reached. + ITERATION_LIMIT + }; + + private: + + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + + // The digraph the algorithm runs on + const Digraph &_gr; + // The cost of the arcs + const CostMap &_cost; + + // Data for the found cycles + bool _curr_found, _best_found; + LargeCost _curr_cost, _best_cost; + int _curr_size, _best_size; + Node _curr_node, _best_node; + + Path *_cycle_path; + bool _local_path; + + // Internal data used by the algorithm + typename Digraph::template NodeMap _policy; + typename Digraph::template NodeMap _reached; + typename Digraph::template NodeMap _level; + typename Digraph::template NodeMap _dist; + + // Data for storing the strongly connected components + int _comp_num; + typename Digraph::template NodeMap _comp; + std::vector > _comp_nodes; + std::vector* _nodes; + typename Digraph::template NodeMap > _in_arcs; + + // Queue used for BFS search + std::vector _queue; + int _qfront, _qback; + + Tolerance _tolerance; + + // Infinite constant + const LargeCost INF; + + public: + + /// \name Named Template Parameters + /// @{ + + template + struct SetLargeCostTraits : public Traits { + typedef T LargeCost; + typedef lemon::Tolerance Tolerance; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c LargeCost type. + /// + /// \ref named-templ-param "Named parameter" for setting \c LargeCost + /// type. It is used for internal computations in the algorithm. + template + struct SetLargeCost + : public HowardMmc > { + typedef HowardMmc > Create; + }; + + template + struct SetPathTraits : public Traits { + typedef T Path; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c %Path type. + /// + /// \ref named-templ-param "Named parameter" for setting the \c %Path + /// type of the found cycles. + /// It must conform to the \ref lemon::concepts::Path "Path" concept + /// and it must have an \c addBack() function. + template + struct SetPath + : public HowardMmc > { + typedef HowardMmc > Create; + }; + + /// @} + + protected: + + HowardMmc() {} + + public: + + /// \brief Constructor. + /// + /// The constructor of the class. + /// + /// \param digraph The digraph the algorithm runs on. + /// \param cost The costs of the arcs. + HowardMmc( const Digraph &digraph, + const CostMap &cost ) : + _gr(digraph), _cost(cost), _best_found(false), + _best_cost(0), _best_size(1), _cycle_path(NULL), _local_path(false), + _policy(digraph), _reached(digraph), _level(digraph), _dist(digraph), + _comp(digraph), _in_arcs(digraph), + INF(std::numeric_limits::has_infinity ? + std::numeric_limits::infinity() : + std::numeric_limits::max()) + {} + + /// Destructor. + ~HowardMmc() { + if (_local_path) delete _cycle_path; + } + + /// \brief Set the path structure for storing the found cycle. + /// + /// This function sets an external path structure for storing the + /// found cycle. + /// + /// If you don't call this function before calling \ref run() or + /// \ref findCycleMean(), a local \ref Path "path" structure + /// will be allocated. The destuctor deallocates this automatically + /// allocated object, of course. + /// + /// \note The algorithm calls only the \ref lemon::Path::addBack() + /// "addBack()" function of the given path structure. + /// + /// \return (*this) + HowardMmc& cycle(Path &path) { + if (_local_path) { + delete _cycle_path; + _local_path = false; + } + _cycle_path = &path; + return *this; + } + + /// \brief Set the tolerance used by the algorithm. + /// + /// This function sets the tolerance object used by the algorithm. + /// + /// \return (*this) + HowardMmc& tolerance(const Tolerance& tolerance) { + _tolerance = tolerance; + return *this; + } + + /// \brief Return a const reference to the tolerance. + /// + /// This function returns a const reference to the tolerance object + /// used by the algorithm. + const Tolerance& tolerance() const { + return _tolerance; + } + + /// \name Execution control + /// The simplest way to execute the algorithm is to call the \ref run() + /// function.\n + /// If you only need the minimum mean cost, you may call + /// \ref findCycleMean(). + + /// @{ + + /// \brief Run the algorithm. + /// + /// This function runs the algorithm. + /// It can be called more than once (e.g. if the underlying digraph + /// and/or the arc costs have been modified). + /// + /// \return \c true if a directed cycle exists in the digraph. + /// + /// \note mmc.run() is just a shortcut of the following code. + /// \code + /// return mmc.findCycleMean() && mmc.findCycle(); + /// \endcode + bool run() { + return findCycleMean() && findCycle(); + } + + /// \brief Find the minimum cycle mean (or an upper bound). + /// + /// This function finds the minimum mean cost of the directed + /// cycles in the digraph (or an upper bound for it). + /// + /// By default, the function finds the exact minimum cycle mean, + /// but an optional limit can also be specified for the number of + /// iterations performed during the search process. + /// The return value indicates if the optimal solution is found + /// or the iteration limit is reached. In the latter case, an + /// approximate solution is provided, which corresponds to a directed + /// cycle whose mean cost is relatively small, but not necessarily + /// minimal. + /// + /// \param limit The maximum allowed number of iterations during + /// the search process. Its default value implies that the algorithm + /// runs until it finds the exact optimal solution. + /// + /// \return The termination cause of the search process. + /// For more information, see \ref TerminationCause. + TerminationCause findCycleMean(int limit = + std::numeric_limits::max()) { + // Initialize and find strongly connected components + init(); + findComponents(); + + // Find the minimum cycle mean in the components + int iter_count = 0; + bool iter_limit_reached = false; + for (int comp = 0; comp < _comp_num; ++comp) { + // Find the minimum mean cycle in the current component + if (!buildPolicyGraph(comp)) continue; + while (true) { + if (++iter_count > limit) { + iter_limit_reached = true; + break; + } + findPolicyCycle(); + if (!computeNodeDistances()) break; + } + + // Update the best cycle (global minimum mean cycle) + if ( _curr_found && (!_best_found || + _curr_cost * _best_size < _best_cost * _curr_size) ) { + _best_found = true; + _best_cost = _curr_cost; + _best_size = _curr_size; + _best_node = _curr_node; + } + + if (iter_limit_reached) break; + } + + if (iter_limit_reached) { + return ITERATION_LIMIT; + } else { + return _best_found ? OPTIMAL : NO_CYCLE; + } + } + + /// \brief Find a minimum mean directed cycle. + /// + /// This function finds a directed cycle of minimum mean cost + /// in the digraph using the data computed by findCycleMean(). + /// + /// \return \c true if a directed cycle exists in the digraph. + /// + /// \pre \ref findCycleMean() must be called before using this function. + bool findCycle() { + if (!_best_found) return false; + _cycle_path->addBack(_policy[_best_node]); + for ( Node v = _best_node; + (v = _gr.target(_policy[v])) != _best_node; ) { + _cycle_path->addBack(_policy[v]); + } + return true; + } + + /// @} + + /// \name Query Functions + /// The results of the algorithm can be obtained using these + /// functions.\n + /// The algorithm should be executed before using them. + + /// @{ + + /// \brief Return the total cost of the found cycle. + /// + /// This function returns the total cost of the found cycle. + /// + /// \pre \ref run() or \ref findCycleMean() must be called before + /// using this function. + Cost cycleCost() const { + return static_cast(_best_cost); + } + + /// \brief Return the number of arcs on the found cycle. + /// + /// This function returns the number of arcs on the found cycle. + /// + /// \pre \ref run() or \ref findCycleMean() must be called before + /// using this function. + int cycleSize() const { + return _best_size; + } + + /// \brief Return the mean cost of the found cycle. + /// + /// This function returns the mean cost of the found cycle. + /// + /// \note alg.cycleMean() is just a shortcut of the + /// following code. + /// \code + /// return static_cast(alg.cycleCost()) / alg.cycleSize(); + /// \endcode + /// + /// \pre \ref run() or \ref findCycleMean() must be called before + /// using this function. + double cycleMean() const { + return static_cast(_best_cost) / _best_size; + } + + /// \brief Return the found cycle. + /// + /// This function returns a const reference to the path structure + /// storing the found cycle. + /// + /// \pre \ref run() or \ref findCycle() must be called before using + /// this function. + const Path& cycle() const { + return *_cycle_path; + } + + ///@} + + private: + + // Initialize + void init() { + if (!_cycle_path) { + _local_path = true; + _cycle_path = new Path; + } + _queue.resize(countNodes(_gr)); + _best_found = false; + _best_cost = 0; + _best_size = 1; + _cycle_path->clear(); + } + + // Find strongly connected components and initialize _comp_nodes + // and _in_arcs + void findComponents() { + _comp_num = stronglyConnectedComponents(_gr, _comp); + _comp_nodes.resize(_comp_num); + if (_comp_num == 1) { + _comp_nodes[0].clear(); + for (NodeIt n(_gr); n != INVALID; ++n) { + _comp_nodes[0].push_back(n); + _in_arcs[n].clear(); + for (InArcIt a(_gr, n); a != INVALID; ++a) { + _in_arcs[n].push_back(a); + } + } + } else { + for (int i = 0; i < _comp_num; ++i) + _comp_nodes[i].clear(); + for (NodeIt n(_gr); n != INVALID; ++n) { + int k = _comp[n]; + _comp_nodes[k].push_back(n); + _in_arcs[n].clear(); + for (InArcIt a(_gr, n); a != INVALID; ++a) { + if (_comp[_gr.source(a)] == k) _in_arcs[n].push_back(a); + } + } + } + } + + // Build the policy graph in the given strongly connected component + // (the out-degree of every node is 1) + bool buildPolicyGraph(int comp) { + _nodes = &(_comp_nodes[comp]); + if (_nodes->size() < 1 || + (_nodes->size() == 1 && _in_arcs[(*_nodes)[0]].size() == 0)) { + return false; + } + for (int i = 0; i < int(_nodes->size()); ++i) { + _dist[(*_nodes)[i]] = INF; + } + Node u, v; + Arc e; + for (int i = 0; i < int(_nodes->size()); ++i) { + v = (*_nodes)[i]; + for (int j = 0; j < int(_in_arcs[v].size()); ++j) { + e = _in_arcs[v][j]; + u = _gr.source(e); + if (_cost[e] < _dist[u]) { + _dist[u] = _cost[e]; + _policy[u] = e; + } + } + } + return true; + } + + // Find the minimum mean cycle in the policy graph + void findPolicyCycle() { + for (int i = 0; i < int(_nodes->size()); ++i) { + _level[(*_nodes)[i]] = -1; + } + LargeCost ccost; + int csize; + Node u, v; + _curr_found = false; + for (int i = 0; i < int(_nodes->size()); ++i) { + u = (*_nodes)[i]; + if (_level[u] >= 0) continue; + for (; _level[u] < 0; u = _gr.target(_policy[u])) { + _level[u] = i; + } + if (_level[u] == i) { + // A cycle is found + ccost = _cost[_policy[u]]; + csize = 1; + for (v = u; (v = _gr.target(_policy[v])) != u; ) { + ccost += _cost[_policy[v]]; + ++csize; + } + if ( !_curr_found || + (ccost * _curr_size < _curr_cost * csize) ) { + _curr_found = true; + _curr_cost = ccost; + _curr_size = csize; + _curr_node = u; + } + } + } + } + + // Contract the policy graph and compute node distances + bool computeNodeDistances() { + // Find the component of the main cycle and compute node distances + // using reverse BFS + for (int i = 0; i < int(_nodes->size()); ++i) { + _reached[(*_nodes)[i]] = false; + } + _qfront = _qback = 0; + _queue[0] = _curr_node; + _reached[_curr_node] = true; + _dist[_curr_node] = 0; + Node u, v; + Arc e; + while (_qfront <= _qback) { + v = _queue[_qfront++]; + for (int j = 0; j < int(_in_arcs[v].size()); ++j) { + e = _in_arcs[v][j]; + u = _gr.source(e); + if (_policy[u] == e && !_reached[u]) { + _reached[u] = true; + _dist[u] = _dist[v] + _cost[e] * _curr_size - _curr_cost; + _queue[++_qback] = u; + } + } + } + + // Connect all other nodes to this component and compute node + // distances using reverse BFS + _qfront = 0; + while (_qback < int(_nodes->size())-1) { + v = _queue[_qfront++]; + for (int j = 0; j < int(_in_arcs[v].size()); ++j) { + e = _in_arcs[v][j]; + u = _gr.source(e); + if (!_reached[u]) { + _reached[u] = true; + _policy[u] = e; + _dist[u] = _dist[v] + _cost[e] * _curr_size - _curr_cost; + _queue[++_qback] = u; + } + } + } + + // Improve node distances + bool improved = false; + for (int i = 0; i < int(_nodes->size()); ++i) { + v = (*_nodes)[i]; + for (int j = 0; j < int(_in_arcs[v].size()); ++j) { + e = _in_arcs[v][j]; + u = _gr.source(e); + LargeCost delta = _dist[v] + _cost[e] * _curr_size - _curr_cost; + if (_tolerance.less(delta, _dist[u])) { + _dist[u] = delta; + _policy[u] = e; + improved = true; + } + } + } + return improved; + } + + }; //class HowardMmc + + ///@} + +} //namespace lemon + +#endif //LEMON_HOWARD_MMC_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/hypercube_graph.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/hypercube_graph.h new file mode 100644 index 00000000000..2cf37ad49d2 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/hypercube_graph.h @@ -0,0 +1,459 @@ +/* -*- 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 HYPERCUBE_GRAPH_H +#define HYPERCUBE_GRAPH_H + +#include +#include +#include +#include + +///\ingroup graphs +///\file +///\brief HypercubeGraph class. + +namespace lemon { + + class HypercubeGraphBase { + + public: + + typedef HypercubeGraphBase Graph; + + class Node; + class Edge; + class Arc; + + public: + + HypercubeGraphBase() {} + + protected: + + void construct(int dim) { + LEMON_ASSERT(dim >= 1, "The number of dimensions must be at least 1."); + _dim = dim; + _node_num = 1 << dim; + _edge_num = dim * (1 << (dim-1)); + } + + public: + + typedef True NodeNumTag; + typedef True EdgeNumTag; + typedef True ArcNumTag; + + int nodeNum() const { return _node_num; } + int edgeNum() const { return _edge_num; } + int arcNum() const { return 2 * _edge_num; } + + int maxNodeId() const { return _node_num - 1; } + int maxEdgeId() const { return _edge_num - 1; } + int maxArcId() const { return 2 * _edge_num - 1; } + + static Node nodeFromId(int id) { return Node(id); } + static Edge edgeFromId(int id) { return Edge(id); } + static Arc arcFromId(int id) { return Arc(id); } + + static int id(Node node) { return node._id; } + static int id(Edge edge) { return edge._id; } + static int id(Arc arc) { return arc._id; } + + Node u(Edge edge) const { + int base = edge._id & ((1 << (_dim-1)) - 1); + int k = edge._id >> (_dim-1); + return ((base >> k) << (k+1)) | (base & ((1 << k) - 1)); + } + + Node v(Edge edge) const { + int base = edge._id & ((1 << (_dim-1)) - 1); + int k = edge._id >> (_dim-1); + return ((base >> k) << (k+1)) | (base & ((1 << k) - 1)) | (1 << k); + } + + Node source(Arc arc) const { + return (arc._id & 1) == 1 ? u(arc) : v(arc); + } + + Node target(Arc arc) const { + return (arc._id & 1) == 1 ? v(arc) : u(arc); + } + + typedef True FindEdgeTag; + typedef True FindArcTag; + + Edge findEdge(Node u, Node v, Edge prev = INVALID) const { + if (prev != INVALID) return INVALID; + int d = u._id ^ v._id; + int k = 0; + if (d == 0) return INVALID; + for ( ; (d & 1) == 0; d >>= 1) ++k; + if (d >> 1 != 0) return INVALID; + return (k << (_dim-1)) | ((u._id >> (k+1)) << k) | + (u._id & ((1 << k) - 1)); + } + + Arc findArc(Node u, Node v, Arc prev = INVALID) const { + Edge edge = findEdge(u, v, prev); + if (edge == INVALID) return INVALID; + int k = edge._id >> (_dim-1); + return ((u._id >> k) & 1) == 1 ? edge._id << 1 : (edge._id << 1) | 1; + } + + class Node { + friend class HypercubeGraphBase; + + protected: + int _id; + Node(int id) : _id(id) {} + public: + Node() {} + Node (Invalid) : _id(-1) {} + bool operator==(const Node node) const {return _id == node._id;} + bool operator!=(const Node node) const {return _id != node._id;} + bool operator<(const Node node) const {return _id < node._id;} + }; + + class Edge { + friend class HypercubeGraphBase; + friend class Arc; + + protected: + int _id; + + Edge(int id) : _id(id) {} + + public: + Edge() {} + Edge (Invalid) : _id(-1) {} + bool operator==(const Edge edge) const {return _id == edge._id;} + bool operator!=(const Edge edge) const {return _id != edge._id;} + bool operator<(const Edge edge) const {return _id < edge._id;} + }; + + class Arc { + friend class HypercubeGraphBase; + + protected: + int _id; + + Arc(int id) : _id(id) {} + + public: + Arc() {} + Arc (Invalid) : _id(-1) {} + operator Edge() const { return _id != -1 ? Edge(_id >> 1) : INVALID; } + bool operator==(const Arc arc) const {return _id == arc._id;} + bool operator!=(const Arc arc) const {return _id != arc._id;} + bool operator<(const Arc arc) const {return _id < arc._id;} + }; + + void first(Node& node) const { + node._id = _node_num - 1; + } + + static void next(Node& node) { + --node._id; + } + + void first(Edge& edge) const { + edge._id = _edge_num - 1; + } + + static void next(Edge& edge) { + --edge._id; + } + + void first(Arc& arc) const { + arc._id = 2 * _edge_num - 1; + } + + static void next(Arc& arc) { + --arc._id; + } + + void firstInc(Edge& edge, bool& dir, const Node& node) const { + edge._id = node._id >> 1; + dir = (node._id & 1) == 0; + } + + void nextInc(Edge& edge, bool& dir) const { + Node n = dir ? u(edge) : v(edge); + int k = (edge._id >> (_dim-1)) + 1; + if (k < _dim) { + edge._id = (k << (_dim-1)) | + ((n._id >> (k+1)) << k) | (n._id & ((1 << k) - 1)); + dir = ((n._id >> k) & 1) == 0; + } else { + edge._id = -1; + dir = true; + } + } + + void firstOut(Arc& arc, const Node& node) const { + arc._id = ((node._id >> 1) << 1) | (~node._id & 1); + } + + void nextOut(Arc& arc) const { + Node n = (arc._id & 1) == 1 ? u(arc) : v(arc); + int k = (arc._id >> _dim) + 1; + if (k < _dim) { + arc._id = (k << (_dim-1)) | + ((n._id >> (k+1)) << k) | (n._id & ((1 << k) - 1)); + arc._id = (arc._id << 1) | (~(n._id >> k) & 1); + } else { + arc._id = -1; + } + } + + void firstIn(Arc& arc, const Node& node) const { + arc._id = ((node._id >> 1) << 1) | (node._id & 1); + } + + void nextIn(Arc& arc) const { + Node n = (arc._id & 1) == 1 ? v(arc) : u(arc); + int k = (arc._id >> _dim) + 1; + if (k < _dim) { + arc._id = (k << (_dim-1)) | + ((n._id >> (k+1)) << k) | (n._id & ((1 << k) - 1)); + arc._id = (arc._id << 1) | ((n._id >> k) & 1); + } else { + arc._id = -1; + } + } + + static bool direction(Arc arc) { + return (arc._id & 1) == 1; + } + + static Arc direct(Edge edge, bool dir) { + return Arc((edge._id << 1) | (dir ? 1 : 0)); + } + + int dimension() const { + return _dim; + } + + bool projection(Node node, int n) const { + return static_cast(node._id & (1 << n)); + } + + int dimension(Edge edge) const { + return edge._id >> (_dim-1); + } + + int dimension(Arc arc) const { + return arc._id >> _dim; + } + + static int index(Node node) { + return node._id; + } + + Node operator()(int ix) const { + return Node(ix); + } + + private: + int _dim; + int _node_num, _edge_num; + }; + + + typedef GraphExtender ExtendedHypercubeGraphBase; + + /// \ingroup graphs + /// + /// \brief Hypercube graph class + /// + /// HypercubeGraph implements a special graph type. The nodes of the + /// graph are indexed with integers having at most \c dim binary digits. + /// Two nodes are connected in the graph if and only if their indices + /// differ only on one position in the binary form. + /// This class is completely static and it needs constant memory space. + /// Thus you can neither add nor delete nodes or edges, however, + /// the structure can be resized using resize(). + /// + /// This type fully conforms to the \ref concepts::Graph "Graph concept". + /// Most of its member functions and nested classes are documented + /// only in the concept class. + /// + /// This class provides constant time counting for nodes, edges and arcs. + /// + /// \note The type of the indices is chosen to \c int for efficiency + /// reasons. Thus the maximum dimension of this implementation is 26 + /// (assuming that the size of \c int is 32 bit). + class HypercubeGraph : public ExtendedHypercubeGraphBase { + typedef ExtendedHypercubeGraphBase Parent; + + public: + + /// \brief Constructs a hypercube graph with \c dim dimensions. + /// + /// Constructs a hypercube graph with \c dim dimensions. + HypercubeGraph(int dim) { construct(dim); } + + /// \brief Resizes the graph + /// + /// This function resizes the graph. It fully destroys and + /// rebuilds the structure, therefore the maps of the graph will be + /// reallocated automatically and the previous values will be lost. + void resize(int dim) { + Parent::notifier(Arc()).clear(); + Parent::notifier(Edge()).clear(); + Parent::notifier(Node()).clear(); + construct(dim); + Parent::notifier(Node()).build(); + Parent::notifier(Edge()).build(); + Parent::notifier(Arc()).build(); + } + + /// \brief The number of dimensions. + /// + /// Gives back the number of dimensions. + int dimension() const { + return Parent::dimension(); + } + + /// \brief Returns \c true if the n'th bit of the node is one. + /// + /// Returns \c true if the n'th bit of the node is one. + bool projection(Node node, int n) const { + return Parent::projection(node, n); + } + + /// \brief The dimension id of an edge. + /// + /// Gives back the dimension id of the given edge. + /// It is in the range [0..dim-1]. + int dimension(Edge edge) const { + return Parent::dimension(edge); + } + + /// \brief The dimension id of an arc. + /// + /// Gives back the dimension id of the given arc. + /// It is in the range [0..dim-1]. + int dimension(Arc arc) const { + return Parent::dimension(arc); + } + + /// \brief The index of a node. + /// + /// Gives back the index of the given node. + /// The lower bits of the integer describes the node. + static int index(Node node) { + return Parent::index(node); + } + + /// \brief Gives back a node by its index. + /// + /// Gives back a node by its index. + Node operator()(int ix) const { + return Parent::operator()(ix); + } + + /// \brief Number of nodes. + int nodeNum() const { return Parent::nodeNum(); } + /// \brief Number of edges. + int edgeNum() const { return Parent::edgeNum(); } + /// \brief Number of arcs. + int arcNum() const { return Parent::arcNum(); } + + /// \brief Linear combination map. + /// + /// This map makes possible to give back a linear combination + /// for each node. It works like the \c std::accumulate function, + /// so it accumulates the \c bf binary function with the \c fv first + /// value. The map accumulates only on that positions (dimensions) + /// where the index of the node is one. The values that have to be + /// accumulated should be given by the \c begin and \c end iterators + /// and the length of this range should be equal to the dimension + /// number of the graph. + /// + ///\code + /// const int DIM = 3; + /// HypercubeGraph graph(DIM); + /// dim2::Point base[DIM]; + /// for (int k = 0; k < DIM; ++k) { + /// base[k].x = rnd(); + /// base[k].y = rnd(); + /// } + /// HypercubeGraph::HyperMap > + /// pos(graph, base, base + DIM, dim2::Point(0.0, 0.0)); + ///\endcode + /// + /// \see HypercubeGraph + template > + class HyperMap { + public: + + /// \brief The key type of the map + typedef Node Key; + /// \brief The value type of the map + typedef T Value; + + /// \brief Constructor for HyperMap. + /// + /// Construct a HyperMap for the given graph. The values that have + /// to be accumulated should be given by the \c begin and \c end + /// iterators and the length of this range should be equal to the + /// dimension number of the graph. + /// + /// This map accumulates the \c bf binary function with the \c fv + /// first value on that positions (dimensions) where the index of + /// the node is one. + template + HyperMap(const Graph& graph, It begin, It end, + T fv = 0, const BF& bf = BF()) + : _graph(graph), _values(begin, end), _first_value(fv), _bin_func(bf) + { + LEMON_ASSERT(_values.size() == graph.dimension(), + "Wrong size of range"); + } + + /// \brief The partial accumulated value. + /// + /// Gives back the partial accumulated value. + Value operator[](const Key& k) const { + Value val = _first_value; + int id = _graph.index(k); + int n = 0; + while (id != 0) { + if (id & 1) { + val = _bin_func(val, _values[n]); + } + id >>= 1; + ++n; + } + return val; + } + + private: + const Graph& _graph; + std::vector _values; + T _first_value; + BF _bin_func; + }; + + }; + +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/insertion_tsp.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/insertion_tsp.h new file mode 100644 index 00000000000..fa16825db52 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/insertion_tsp.h @@ -0,0 +1,533 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_INSERTION_TSP_H +#define LEMON_INSERTION_TSP_H + +/// \ingroup tsp +/// \file +/// \brief Insertion algorithm for symmetric TSP + +#include +#include +#include +#include +#include + +namespace lemon { + + /// \ingroup tsp + /// + /// \brief Insertion algorithm for symmetric TSP. + /// + /// InsertionTsp implements the insertion heuristic for solving + /// symmetric \ref tsp "TSP". + /// + /// This is a fast and effective tour construction method that has + /// many variants. + /// It starts with a subtour containing a few nodes of the graph and it + /// iteratively inserts the other nodes into this subtour according to a + /// certain node selection rule. + /// + /// This method is among the fastest TSP algorithms, and it typically + /// provides quite good solutions (usually much better than + /// \ref NearestNeighborTsp and \ref GreedyTsp). + /// + /// InsertionTsp implements four different node selection rules, + /// from which the most effective one (\e farthest \e node \e selection) + /// is used by default. + /// With this choice, the algorithm runs in O(n2) time. + /// For more information, see \ref SelectionRule. + /// + /// \tparam CM Type of the cost map. + template + class InsertionTsp + { + public: + + /// Type of the cost map + typedef CM CostMap; + /// Type of the edge costs + typedef typename CM::Value Cost; + + private: + + GRAPH_TYPEDEFS(FullGraph); + + const FullGraph &_gr; + const CostMap &_cost; + std::vector _notused; + std::vector _tour; + Cost _sum; + + public: + + /// \brief Constants for specifying the node selection rule. + /// + /// Enum type containing constants for specifying the node selection + /// rule for the \ref run() function. + /// + /// During the algorithm, nodes are selected for addition to the current + /// subtour according to the applied rule. + /// The FARTHEST method is one of the fastest selection rules, and + /// it is typically the most effective, thus it is the default + /// option. The RANDOM rule usually gives slightly worse results, + /// but it is more robust. + /// + /// The desired selection rule can be specified as a parameter of the + /// \ref run() function. + enum SelectionRule { + + /// An unvisited node having minimum distance from the current + /// subtour is selected at each step. + /// The algorithm runs in O(n2) time using this + /// selection rule. + NEAREST, + + /// An unvisited node having maximum distance from the current + /// subtour is selected at each step. + /// The algorithm runs in O(n2) time using this + /// selection rule. + FARTHEST, + + /// An unvisited node whose insertion results in the least + /// increase of the subtour's total cost is selected at each step. + /// The algorithm runs in O(n3) time using this + /// selection rule, but in most cases, it is almost as fast as + /// with other rules. + CHEAPEST, + + /// An unvisited node is selected randomly without any evaluation + /// at each step. + /// The global \ref rnd "random number generator instance" is used. + /// You can seed it before executing the algorithm, if you + /// would like to. + /// The algorithm runs in O(n2) time using this + /// selection rule. + RANDOM + }; + + public: + + /// \brief Constructor + /// + /// Constructor. + /// \param gr The \ref FullGraph "full graph" the algorithm runs on. + /// \param cost The cost map. + InsertionTsp(const FullGraph &gr, const CostMap &cost) + : _gr(gr), _cost(cost) {} + + /// \name Execution Control + /// @{ + + /// \brief Runs the algorithm. + /// + /// This function runs the algorithm. + /// + /// \param rule The node selection rule. For more information, see + /// \ref SelectionRule. + /// + /// \return The total cost of the found tour. + Cost run(SelectionRule rule = FARTHEST) { + _tour.clear(); + + if (_gr.nodeNum() == 0) return _sum = 0; + else if (_gr.nodeNum() == 1) { + _tour.push_back(_gr(0)); + return _sum = 0; + } + + switch (rule) { + case NEAREST: + init(true); + start >, + DefaultInsertion>(); + break; + case FARTHEST: + init(false); + start >, + DefaultInsertion>(); + break; + case CHEAPEST: + init(true); + start(); + break; + case RANDOM: + init(true); + start(); + break; + } + return _sum; + } + + /// @} + + /// \name Query Functions + /// @{ + + /// \brief The total cost of the found tour. + /// + /// This function returns the total cost of the found tour. + /// + /// \pre run() must be called before using this function. + Cost tourCost() const { + return _sum; + } + + /// \brief Returns a const reference to the node sequence of the + /// found tour. + /// + /// This function returns a const reference to a vector + /// that stores the node sequence of the found tour. + /// + /// \pre run() must be called before using this function. + const std::vector& tourNodes() const { + return _tour; + } + + /// \brief Gives back the node sequence of the found tour. + /// + /// This function copies the node sequence of the found tour into + /// an STL container through the given output iterator. The + /// value_type of the container must be FullGraph::Node. + /// For example, + /// \code + /// std::vector nodes(countNodes(graph)); + /// tsp.tourNodes(nodes.begin()); + /// \endcode + /// or + /// \code + /// std::list nodes; + /// tsp.tourNodes(std::back_inserter(nodes)); + /// \endcode + /// + /// \pre run() must be called before using this function. + template + void tourNodes(Iterator out) const { + std::copy(_tour.begin(), _tour.end(), out); + } + + /// \brief Gives back the found tour as a path. + /// + /// This function copies the found tour as a list of arcs/edges into + /// the given \ref lemon::concepts::Path "path structure". + /// + /// \pre run() must be called before using this function. + template + void tour(Path &path) const { + path.clear(); + for (int i = 0; i < int(_tour.size()) - 1; ++i) { + path.addBack(_gr.arc(_tour[i], _tour[i+1])); + } + if (int(_tour.size()) >= 2) { + path.addBack(_gr.arc(_tour.back(), _tour.front())); + } + } + + /// @} + + private: + + // Initializes the algorithm + void init(bool min) { + Edge min_edge = min ? mapMin(_gr, _cost) : mapMax(_gr, _cost); + + _tour.clear(); + _tour.push_back(_gr.u(min_edge)); + _tour.push_back(_gr.v(min_edge)); + + _notused.clear(); + for (NodeIt n(_gr); n!=INVALID; ++n) { + if (n != _gr.u(min_edge) && n != _gr.v(min_edge)) { + _notused.push_back(n); + } + } + + _sum = _cost[min_edge] * 2; + } + + // Executes the algorithm + template + void start() { + SelectionFunctor selectNode(_gr, _cost, _tour, _notused); + InsertionFunctor insertNode(_gr, _cost, _tour, _sum); + + for (int i=0; i<_gr.nodeNum()-2; ++i) { + insertNode.insert(selectNode.select()); + } + + _sum = _cost[_gr.edge(_tour.back(), _tour.front())]; + for (int i = 0; i < int(_tour.size())-1; ++i) { + _sum += _cost[_gr.edge(_tour[i], _tour[i+1])]; + } + } + + + // Implementation of the nearest and farthest selection rule + template + class ComparingSelection { + public: + ComparingSelection(const FullGraph &gr, const CostMap &cost, + std::vector &tour, std::vector ¬used) + : _gr(gr), _cost(cost), _tour(tour), _notused(notused), + _dist(gr, 0), _compare() + { + // Compute initial distances for the unused nodes + for (unsigned int i=0; i<_notused.size(); ++i) { + Node u = _notused[i]; + Cost min_dist = _cost[_gr.edge(u, _tour[0])]; + for (unsigned int j=1; j<_tour.size(); ++j) { + Cost curr = _cost[_gr.edge(u, _tour[j])]; + if (curr < min_dist) { + min_dist = curr; + } + } + _dist[u] = min_dist; + } + } + + Node select() { + + // Select an used node with minimum distance + Cost ins_dist = 0; + int ins_node = -1; + for (unsigned int i=0; i<_notused.size(); ++i) { + Cost curr = _dist[_notused[i]]; + if (_compare(curr, ins_dist) || ins_node == -1) { + ins_dist = curr; + ins_node = i; + } + } + + // Remove the selected node from the unused vector + Node sn = _notused[ins_node]; + _notused[ins_node] = _notused.back(); + _notused.pop_back(); + + // Update the distances of the remaining nodes + for (unsigned int i=0; i<_notused.size(); ++i) { + Node u = _notused[i]; + Cost nc = _cost[_gr.edge(sn, u)]; + if (nc < _dist[u]) { + _dist[u] = nc; + } + } + + return sn; + } + + private: + const FullGraph &_gr; + const CostMap &_cost; + std::vector &_tour; + std::vector &_notused; + FullGraph::NodeMap _dist; + Comparator _compare; + }; + + // Implementation of the cheapest selection rule + class CheapestSelection { + private: + Cost costDiff(Node u, Node v, Node w) const { + return + _cost[_gr.edge(u, w)] + + _cost[_gr.edge(v, w)] - + _cost[_gr.edge(u, v)]; + } + + public: + CheapestSelection(const FullGraph &gr, const CostMap &cost, + std::vector &tour, std::vector ¬used) + : _gr(gr), _cost(cost), _tour(tour), _notused(notused), + _ins_cost(gr, 0), _ins_pos(gr, -1) + { + // Compute insertion cost and position for the unused nodes + for (unsigned int i=0; i<_notused.size(); ++i) { + Node u = _notused[i]; + Cost min_cost = costDiff(_tour.back(), _tour.front(), u); + int min_pos = 0; + for (unsigned int j=1; j<_tour.size(); ++j) { + Cost curr_cost = costDiff(_tour[j-1], _tour[j], u); + if (curr_cost < min_cost) { + min_cost = curr_cost; + min_pos = j; + } + } + _ins_cost[u] = min_cost; + _ins_pos[u] = min_pos; + } + } + + Cost select() { + + // Select an used node with minimum insertion cost + Cost min_cost = 0; + int min_node = -1; + for (unsigned int i=0; i<_notused.size(); ++i) { + Cost curr_cost = _ins_cost[_notused[i]]; + if (curr_cost < min_cost || min_node == -1) { + min_cost = curr_cost; + min_node = i; + } + } + + // Remove the selected node from the unused vector + Node sn = _notused[min_node]; + _notused[min_node] = _notused.back(); + _notused.pop_back(); + + // Insert the selected node into the tour + const int ipos = _ins_pos[sn]; + _tour.insert(_tour.begin() + ipos, sn); + + // Update the insertion cost and position of the remaining nodes + for (unsigned int i=0; i<_notused.size(); ++i) { + Node u = _notused[i]; + Cost curr_cost = _ins_cost[u]; + int curr_pos = _ins_pos[u]; + + int ipos_prev = ipos == 0 ? _tour.size()-1 : ipos-1; + int ipos_next = ipos == int(_tour.size())-1 ? 0 : ipos+1; + Cost nc1 = costDiff(_tour[ipos_prev], _tour[ipos], u); + Cost nc2 = costDiff(_tour[ipos], _tour[ipos_next], u); + + if (nc1 <= curr_cost || nc2 <= curr_cost) { + // A new position is better than the old one + if (nc1 <= nc2) { + curr_cost = nc1; + curr_pos = ipos; + } else { + curr_cost = nc2; + curr_pos = ipos_next; + } + } + else { + if (curr_pos == ipos) { + // The minimum should be found again + curr_cost = costDiff(_tour.back(), _tour.front(), u); + curr_pos = 0; + for (unsigned int j=1; j<_tour.size(); ++j) { + Cost tmp_cost = costDiff(_tour[j-1], _tour[j], u); + if (tmp_cost < curr_cost) { + curr_cost = tmp_cost; + curr_pos = j; + } + } + } + else if (curr_pos > ipos) { + ++curr_pos; + } + } + + _ins_cost[u] = curr_cost; + _ins_pos[u] = curr_pos; + } + + return min_cost; + } + + private: + const FullGraph &_gr; + const CostMap &_cost; + std::vector &_tour; + std::vector &_notused; + FullGraph::NodeMap _ins_cost; + FullGraph::NodeMap _ins_pos; + }; + + // Implementation of the random selection rule + class RandomSelection { + public: + RandomSelection(const FullGraph &, const CostMap &, + std::vector &, std::vector ¬used) + : _notused(notused) {} + + Node select() const { + const int index = rnd[_notused.size()]; + Node n = _notused[index]; + _notused[index] = _notused.back(); + _notused.pop_back(); + return n; + } + + private: + std::vector &_notused; + }; + + + // Implementation of the default insertion method + class DefaultInsertion { + private: + Cost costDiff(Node u, Node v, Node w) const { + return + _cost[_gr.edge(u, w)] + + _cost[_gr.edge(v, w)] - + _cost[_gr.edge(u, v)]; + } + + public: + DefaultInsertion(const FullGraph &gr, const CostMap &cost, + std::vector &tour, Cost &total_cost) : + _gr(gr), _cost(cost), _tour(tour), _total(total_cost) {} + + void insert(Node n) const { + int min = 0; + Cost min_val = + costDiff(_tour.front(), _tour.back(), n); + + for (unsigned int i=1; i<_tour.size(); ++i) { + Cost tmp = costDiff(_tour[i-1], _tour[i], n); + if (tmp < min_val) { + min = i; + min_val = tmp; + } + } + + _tour.insert(_tour.begin()+min, n); + _total += min_val; + } + + private: + const FullGraph &_gr; + const CostMap &_cost; + std::vector &_tour; + Cost &_total; + }; + + // Implementation of a special insertion method for the cheapest + // selection rule + class CheapestInsertion { + TEMPLATE_GRAPH_TYPEDEFS(FullGraph); + public: + CheapestInsertion(const FullGraph &, const CostMap &, + std::vector &, Cost &total_cost) : + _total(total_cost) {} + + void insert(Cost diff) const { + _total += diff; + } + + private: + Cost &_total; + }; + + }; + +}; // namespace lemon + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/karp_mmc.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/karp_mmc.h new file mode 100644 index 00000000000..1f05d4369c9 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/karp_mmc.h @@ -0,0 +1,590 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_KARP_MMC_H +#define LEMON_KARP_MMC_H + +/// \ingroup min_mean_cycle +/// +/// \file +/// \brief Karp's algorithm for finding a minimum mean cycle. + +#include +#include +#include +#include +#include +#include + +namespace lemon { + + /// \brief Default traits class of KarpMmc class. + /// + /// Default traits class of KarpMmc class. + /// \tparam GR The type of the digraph. + /// \tparam CM The type of the cost map. + /// It must conform to the \ref concepts::ReadMap "ReadMap" concept. +#ifdef DOXYGEN + template +#else + template ::is_integer> +#endif + struct KarpMmcDefaultTraits + { + /// The type of the digraph + typedef GR Digraph; + /// The type of the cost map + typedef CM CostMap; + /// The type of the arc costs + typedef typename CostMap::Value Cost; + + /// \brief The large cost type used for internal computations + /// + /// The large cost type used for internal computations. + /// It is \c long \c long if the \c Cost type is integer, + /// otherwise it is \c double. + /// \c Cost must be convertible to \c LargeCost. + typedef double LargeCost; + + /// The tolerance type used for internal computations + typedef lemon::Tolerance Tolerance; + + /// \brief The path type of the found cycles + /// + /// The path type of the found cycles. + /// It must conform to the \ref lemon::concepts::Path "Path" concept + /// and it must have an \c addFront() function. + typedef lemon::Path Path; + }; + + // Default traits class for integer cost types + template + struct KarpMmcDefaultTraits + { + typedef GR Digraph; + typedef CM CostMap; + typedef typename CostMap::Value Cost; +#ifdef LEMON_HAVE_LONG_LONG + typedef long long LargeCost; +#else + typedef long LargeCost; +#endif + typedef lemon::Tolerance Tolerance; + typedef lemon::Path Path; + }; + + + /// \addtogroup min_mean_cycle + /// @{ + + /// \brief Implementation of Karp's algorithm for finding a minimum + /// mean cycle. + /// + /// This class implements Karp's algorithm for finding a directed + /// cycle of minimum mean cost in a digraph + /// \cite karp78characterization, \cite dasdan98minmeancycle. + /// It runs in time O(nm) and uses space O(n2+m). + /// + /// \tparam GR The type of the digraph the algorithm runs on. + /// \tparam CM The type of the cost map. The default + /// map type is \ref concepts::Digraph::ArcMap "GR::ArcMap". + /// \tparam TR The traits class that defines various types used by the + /// algorithm. By default, it is \ref KarpMmcDefaultTraits + /// "KarpMmcDefaultTraits". + /// In most cases, this parameter should not be set directly, + /// consider to use the named template parameters instead. +#ifdef DOXYGEN + template +#else + template < typename GR, + typename CM = typename GR::template ArcMap, + typename TR = KarpMmcDefaultTraits > +#endif + class KarpMmc + { + public: + + /// The type of the digraph + typedef typename TR::Digraph Digraph; + /// The type of the cost map + typedef typename TR::CostMap CostMap; + /// The type of the arc costs + typedef typename TR::Cost Cost; + + /// \brief The large cost type + /// + /// The large cost type used for internal computations. + /// By default, it is \c long \c long if the \c Cost type is integer, + /// otherwise it is \c double. + typedef typename TR::LargeCost LargeCost; + + /// The tolerance type + typedef typename TR::Tolerance Tolerance; + + /// \brief The path type of the found cycles + /// + /// The path type of the found cycles. + /// Using the \ref lemon::KarpMmcDefaultTraits "default traits class", + /// it is \ref lemon::Path "Path". + typedef typename TR::Path Path; + + /// The \ref lemon::KarpMmcDefaultTraits "traits class" of the algorithm + typedef TR Traits; + + private: + + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + + // Data sturcture for path data + struct PathData + { + LargeCost dist; + Arc pred; + PathData(LargeCost d, Arc p = INVALID) : + dist(d), pred(p) {} + }; + + typedef typename Digraph::template NodeMap > + PathDataNodeMap; + + private: + + // The digraph the algorithm runs on + const Digraph &_gr; + // The cost of the arcs + const CostMap &_cost; + + // Data for storing the strongly connected components + int _comp_num; + typename Digraph::template NodeMap _comp; + std::vector > _comp_nodes; + std::vector* _nodes; + typename Digraph::template NodeMap > _out_arcs; + + // Data for the found cycle + LargeCost _cycle_cost; + int _cycle_size; + Node _cycle_node; + + Path *_cycle_path; + bool _local_path; + + // Node map for storing path data + PathDataNodeMap _data; + // The processed nodes in the last round + std::vector _process; + + Tolerance _tolerance; + + // Infinite constant + const LargeCost INF; + + public: + + /// \name Named Template Parameters + /// @{ + + template + struct SetLargeCostTraits : public Traits { + typedef T LargeCost; + typedef lemon::Tolerance Tolerance; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c LargeCost type. + /// + /// \ref named-templ-param "Named parameter" for setting \c LargeCost + /// type. It is used for internal computations in the algorithm. + template + struct SetLargeCost + : public KarpMmc > { + typedef KarpMmc > Create; + }; + + template + struct SetPathTraits : public Traits { + typedef T Path; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c %Path type. + /// + /// \ref named-templ-param "Named parameter" for setting the \c %Path + /// type of the found cycles. + /// It must conform to the \ref lemon::concepts::Path "Path" concept + /// and it must have an \c addFront() function. + template + struct SetPath + : public KarpMmc > { + typedef KarpMmc > Create; + }; + + /// @} + + protected: + + KarpMmc() {} + + public: + + /// \brief Constructor. + /// + /// The constructor of the class. + /// + /// \param digraph The digraph the algorithm runs on. + /// \param cost The costs of the arcs. + KarpMmc( const Digraph &digraph, + const CostMap &cost ) : + _gr(digraph), _cost(cost), _comp(digraph), _out_arcs(digraph), + _cycle_cost(0), _cycle_size(1), _cycle_node(INVALID), + _cycle_path(NULL), _local_path(false), _data(digraph), + INF(std::numeric_limits::has_infinity ? + std::numeric_limits::infinity() : + std::numeric_limits::max()) + {} + + /// Destructor. + ~KarpMmc() { + if (_local_path) delete _cycle_path; + } + + /// \brief Set the path structure for storing the found cycle. + /// + /// This function sets an external path structure for storing the + /// found cycle. + /// + /// If you don't call this function before calling \ref run() or + /// \ref findCycleMean(), a local \ref Path "path" structure + /// will be allocated. The destuctor deallocates this automatically + /// allocated object, of course. + /// + /// \note The algorithm calls only the \ref lemon::Path::addFront() + /// "addFront()" function of the given path structure. + /// + /// \return (*this) + KarpMmc& cycle(Path &path) { + if (_local_path) { + delete _cycle_path; + _local_path = false; + } + _cycle_path = &path; + return *this; + } + + /// \brief Set the tolerance used by the algorithm. + /// + /// This function sets the tolerance object used by the algorithm. + /// + /// \return (*this) + KarpMmc& tolerance(const Tolerance& tolerance) { + _tolerance = tolerance; + return *this; + } + + /// \brief Return a const reference to the tolerance. + /// + /// This function returns a const reference to the tolerance object + /// used by the algorithm. + const Tolerance& tolerance() const { + return _tolerance; + } + + /// \name Execution control + /// The simplest way to execute the algorithm is to call the \ref run() + /// function.\n + /// If you only need the minimum mean cost, you may call + /// \ref findCycleMean(). + + /// @{ + + /// \brief Run the algorithm. + /// + /// This function runs the algorithm. + /// It can be called more than once (e.g. if the underlying digraph + /// and/or the arc costs have been modified). + /// + /// \return \c true if a directed cycle exists in the digraph. + /// + /// \note mmc.run() is just a shortcut of the following code. + /// \code + /// return mmc.findCycleMean() && mmc.findCycle(); + /// \endcode + bool run() { + return findCycleMean() && findCycle(); + } + + /// \brief Find the minimum cycle mean. + /// + /// This function finds the minimum mean cost of the directed + /// cycles in the digraph. + /// + /// \return \c true if a directed cycle exists in the digraph. + bool findCycleMean() { + // Initialization and find strongly connected components + init(); + findComponents(); + + // Find the minimum cycle mean in the components + for (int comp = 0; comp < _comp_num; ++comp) { + if (!initComponent(comp)) continue; + processRounds(); + updateMinMean(); + } + return (_cycle_node != INVALID); + } + + /// \brief Find a minimum mean directed cycle. + /// + /// This function finds a directed cycle of minimum mean cost + /// in the digraph using the data computed by findCycleMean(). + /// + /// \return \c true if a directed cycle exists in the digraph. + /// + /// \pre \ref findCycleMean() must be called before using this function. + bool findCycle() { + if (_cycle_node == INVALID) return false; + IntNodeMap reached(_gr, -1); + int r = _data[_cycle_node].size(); + Node u = _cycle_node; + while (reached[u] < 0) { + reached[u] = --r; + u = _gr.source(_data[u][r].pred); + } + r = reached[u]; + Arc e = _data[u][r].pred; + _cycle_path->addFront(e); + _cycle_cost = _cost[e]; + _cycle_size = 1; + Node v; + while ((v = _gr.source(e)) != u) { + e = _data[v][--r].pred; + _cycle_path->addFront(e); + _cycle_cost += _cost[e]; + ++_cycle_size; + } + return true; + } + + /// @} + + /// \name Query Functions + /// The results of the algorithm can be obtained using these + /// functions.\n + /// The algorithm should be executed before using them. + + /// @{ + + /// \brief Return the total cost of the found cycle. + /// + /// This function returns the total cost of the found cycle. + /// + /// \pre \ref run() or \ref findCycleMean() must be called before + /// using this function. + Cost cycleCost() const { + return static_cast(_cycle_cost); + } + + /// \brief Return the number of arcs on the found cycle. + /// + /// This function returns the number of arcs on the found cycle. + /// + /// \pre \ref run() or \ref findCycleMean() must be called before + /// using this function. + int cycleSize() const { + return _cycle_size; + } + + /// \brief Return the mean cost of the found cycle. + /// + /// This function returns the mean cost of the found cycle. + /// + /// \note alg.cycleMean() is just a shortcut of the + /// following code. + /// \code + /// return static_cast(alg.cycleCost()) / alg.cycleSize(); + /// \endcode + /// + /// \pre \ref run() or \ref findCycleMean() must be called before + /// using this function. + double cycleMean() const { + return static_cast(_cycle_cost) / _cycle_size; + } + + /// \brief Return the found cycle. + /// + /// This function returns a const reference to the path structure + /// storing the found cycle. + /// + /// \pre \ref run() or \ref findCycle() must be called before using + /// this function. + const Path& cycle() const { + return *_cycle_path; + } + + ///@} + + private: + + // Initialization + void init() { + if (!_cycle_path) { + _local_path = true; + _cycle_path = new Path; + } + _cycle_path->clear(); + _cycle_cost = 0; + _cycle_size = 1; + _cycle_node = INVALID; + for (NodeIt u(_gr); u != INVALID; ++u) + _data[u].clear(); + } + + // Find strongly connected components and initialize _comp_nodes + // and _out_arcs + void findComponents() { + _comp_num = stronglyConnectedComponents(_gr, _comp); + _comp_nodes.resize(_comp_num); + if (_comp_num == 1) { + _comp_nodes[0].clear(); + for (NodeIt n(_gr); n != INVALID; ++n) { + _comp_nodes[0].push_back(n); + _out_arcs[n].clear(); + for (OutArcIt a(_gr, n); a != INVALID; ++a) { + _out_arcs[n].push_back(a); + } + } + } else { + for (int i = 0; i < _comp_num; ++i) + _comp_nodes[i].clear(); + for (NodeIt n(_gr); n != INVALID; ++n) { + int k = _comp[n]; + _comp_nodes[k].push_back(n); + _out_arcs[n].clear(); + for (OutArcIt a(_gr, n); a != INVALID; ++a) { + if (_comp[_gr.target(a)] == k) _out_arcs[n].push_back(a); + } + } + } + } + + // Initialize path data for the current component + bool initComponent(int comp) { + _nodes = &(_comp_nodes[comp]); + int n = _nodes->size(); + if (n < 1 || (n == 1 && _out_arcs[(*_nodes)[0]].size() == 0)) { + return false; + } + for (int i = 0; i < n; ++i) { + _data[(*_nodes)[i]].resize(n + 1, PathData(INF)); + } + return true; + } + + // Process all rounds of computing path data for the current component. + // _data[v][k] is the cost of a shortest directed walk from the root + // node to node v containing exactly k arcs. + void processRounds() { + Node start = (*_nodes)[0]; + _data[start][0] = PathData(0); + _process.clear(); + _process.push_back(start); + + int k, n = _nodes->size(); + for (k = 1; k <= n && int(_process.size()) < n; ++k) { + processNextBuildRound(k); + } + for ( ; k <= n; ++k) { + processNextFullRound(k); + } + } + + // Process one round and rebuild _process + void processNextBuildRound(int k) { + std::vector next; + Node u, v; + Arc e; + LargeCost d; + for (int i = 0; i < int(_process.size()); ++i) { + u = _process[i]; + for (int j = 0; j < int(_out_arcs[u].size()); ++j) { + e = _out_arcs[u][j]; + v = _gr.target(e); + d = _data[u][k-1].dist + _cost[e]; + if (_tolerance.less(d, _data[v][k].dist)) { + if (_data[v][k].dist == INF) next.push_back(v); + _data[v][k] = PathData(d, e); + } + } + } + _process.swap(next); + } + + // Process one round using _nodes instead of _process + void processNextFullRound(int k) { + Node u, v; + Arc e; + LargeCost d; + for (int i = 0; i < int(_nodes->size()); ++i) { + u = (*_nodes)[i]; + for (int j = 0; j < int(_out_arcs[u].size()); ++j) { + e = _out_arcs[u][j]; + v = _gr.target(e); + d = _data[u][k-1].dist + _cost[e]; + if (_tolerance.less(d, _data[v][k].dist)) { + _data[v][k] = PathData(d, e); + } + } + } + } + + // Update the minimum cycle mean + void updateMinMean() { + int n = _nodes->size(); + for (int i = 0; i < n; ++i) { + Node u = (*_nodes)[i]; + if (_data[u][n].dist == INF) continue; + LargeCost cost, max_cost = 0; + int size, max_size = 1; + bool found_curr = false; + for (int k = 0; k < n; ++k) { + if (_data[u][k].dist == INF) continue; + cost = _data[u][n].dist - _data[u][k].dist; + size = n - k; + if (!found_curr || cost * max_size > max_cost * size) { + found_curr = true; + max_cost = cost; + max_size = size; + } + } + if ( found_curr && (_cycle_node == INVALID || + max_cost * _cycle_size < _cycle_cost * max_size) ) { + _cycle_cost = max_cost; + _cycle_size = max_size; + _cycle_node = u; + } + } + } + + }; //class KarpMmc + + ///@} + +} //namespace lemon + +#endif //LEMON_KARP_MMC_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/kruskal.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/kruskal.h new file mode 100644 index 00000000000..04c2ddb9384 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/kruskal.h @@ -0,0 +1,324 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_KRUSKAL_H +#define LEMON_KRUSKAL_H + +#include +#include +#include +#include + +#include +#include + +///\ingroup spantree +///\file +///\brief Kruskal's algorithm to compute a minimum cost spanning tree + +namespace lemon { + + namespace _kruskal_bits { + + // Kruskal for directed graphs. + + template + typename disable_if, + typename In::value_type::second_type >::type + kruskal(const Digraph& digraph, const In& in, Out& out,dummy<0> = 0) { + typedef typename In::value_type::second_type Value; + typedef typename Digraph::template NodeMap IndexMap; + typedef typename Digraph::Node Node; + + IndexMap index(digraph); + UnionFind uf(index); + for (typename Digraph::NodeIt it(digraph); it != INVALID; ++it) { + uf.insert(it); + } + + Value tree_value = 0; + for (typename In::const_iterator it = in.begin(); it != in.end(); ++it) { + if (uf.join(digraph.target(it->first),digraph.source(it->first))) { + out.set(it->first, true); + tree_value += it->second; + } + else { + out.set(it->first, false); + } + } + return tree_value; + } + + // Kruskal for undirected graphs. + + template + typename enable_if, + typename In::value_type::second_type >::type + kruskal(const Graph& graph, const In& in, Out& out,dummy<1> = 1) { + typedef typename In::value_type::second_type Value; + typedef typename Graph::template NodeMap IndexMap; + typedef typename Graph::Node Node; + + IndexMap index(graph); + UnionFind uf(index); + for (typename Graph::NodeIt it(graph); it != INVALID; ++it) { + uf.insert(it); + } + + Value tree_value = 0; + for (typename In::const_iterator it = in.begin(); it != in.end(); ++it) { + if (uf.join(graph.u(it->first),graph.v(it->first))) { + out.set(it->first, true); + tree_value += it->second; + } + else { + out.set(it->first, false); + } + } + return tree_value; + } + + + template + struct PairComp { + typedef typename Sequence::value_type Value; + bool operator()(const Value& left, const Value& right) { + return left.second < right.second; + } + }; + + template + struct SequenceInputIndicator { + static const bool value = false; + }; + + template + struct SequenceInputIndicator::type> { + static const bool value = true; + }; + + template + struct MapInputIndicator { + static const bool value = false; + }; + + template + struct MapInputIndicator::type> { + static const bool value = true; + }; + + template + struct SequenceOutputIndicator { + static const bool value = false; + }; + + template + struct SequenceOutputIndicator::type> { + static const bool value = true; + }; + + template + struct MapOutputIndicator { + static const bool value = false; + }; + + template + struct MapOutputIndicator::type> { + static const bool value = true; + }; + + template + struct KruskalValueSelector {}; + + template + struct KruskalValueSelector, void>::type> + { + typedef typename In::value_type::second_type Value; + }; + + template + struct KruskalValueSelector, void>::type> + { + typedef typename In::Value Value; + }; + + template + struct KruskalInputSelector {}; + + template + struct KruskalOutputSelector {}; + + template + struct KruskalInputSelector, void>::type > + { + typedef typename In::value_type::second_type Value; + + static Value kruskal(const Graph& graph, const In& in, Out& out) { + return KruskalOutputSelector:: + kruskal(graph, in, out); + } + + }; + + template + struct KruskalInputSelector, void>::type > + { + typedef typename In::Value Value; + static Value kruskal(const Graph& graph, const In& in, Out& out) { + typedef typename In::Key MapArc; + typedef typename In::Value Value; + typedef typename ItemSetTraits::ItemIt MapArcIt; + typedef std::vector > Sequence; + Sequence seq; + + for (MapArcIt it(graph); it != INVALID; ++it) { + seq.push_back(std::make_pair(it, in[it])); + } + + std::sort(seq.begin(), seq.end(), PairComp()); + return KruskalOutputSelector:: + kruskal(graph, seq, out); + } + }; + + template + struct RemoveConst { + typedef T type; + }; + + template + struct RemoveConst { + typedef T type; + }; + + template + struct KruskalOutputSelector, void>::type > + { + typedef typename In::value_type::second_type Value; + + static Value kruskal(const Graph& graph, const In& in, Out& out) { + typedef LoggerBoolMap::type> Map; + Map map(out); + return _kruskal_bits::kruskal(graph, in, map); + } + + }; + + template + struct KruskalOutputSelector, void>::type > + { + typedef typename In::value_type::second_type Value; + + static Value kruskal(const Graph& graph, const In& in, Out& out) { + return _kruskal_bits::kruskal(graph, in, out); + } + }; + + } + + /// \ingroup spantree + /// + /// \brief Kruskal's algorithm for finding a minimum cost spanning tree of + /// a graph. + /// + /// This function runs Kruskal's algorithm to find a minimum cost + /// spanning tree of a graph. + /// Due to some C++ hacking, it accepts various input and output types. + /// + /// \param g The graph the algorithm runs on. + /// It can be either \ref concepts::Digraph "directed" or + /// \ref concepts::Graph "undirected". + /// If the graph is directed, the algorithm consider it to be + /// undirected by disregarding the direction of the arcs. + /// + /// \param in This object is used to describe the arc/edge costs. + /// It can be one of the following choices. + /// - An STL compatible 'Forward Container' with + /// std::pair or + /// std::pair as its value_type, where + /// \c C is the type of the costs. The pairs indicates the arcs/edges + /// along with the assigned cost. They must be in a + /// cost-ascending order. + /// - Any readable arc/edge map. The values of the map indicate the + /// arc/edge costs. + /// + /// \retval out Here we also have a choice. + /// - It can be a writable arc/edge map with \c bool value type. After + /// running the algorithm it will contain the found minimum cost spanning + /// tree: the value of an arc/edge will be set to \c true if it belongs + /// to the tree, otherwise it will be set to \c false. The value of + /// each arc/edge will be set exactly once. + /// - It can also be an iteraror of an STL Container with + /// GR::Arc or GR::Edge as its + /// value_type. The algorithm copies the elements of the + /// found tree into this sequence. For example, if we know that the + /// spanning tree of the graph \c g has say 53 arcs, then we can + /// put its arcs into an STL vector \c tree with a code like this. + ///\code + /// std::vector tree(53); + /// kruskal(g,cost,tree.begin()); + ///\endcode + /// Or if we don't know in advance the size of the tree, we can + /// write this. + ///\code + /// std::vector tree; + /// kruskal(g,cost,std::back_inserter(tree)); + ///\endcode + /// + /// \return The total cost of the found spanning tree. + /// + /// \note If the input graph is not (weakly) connected, a spanning + /// forest is calculated instead of a spanning tree. + +#ifdef DOXYGEN + template + Value kruskal(const Graph& g, const In& in, Out& out) +#else + template + inline typename _kruskal_bits::KruskalValueSelector::Value + kruskal(const Graph& graph, const In& in, Out& out) +#endif + { + return _kruskal_bits::KruskalInputSelector:: + kruskal(graph, in, out); + } + + + template + inline typename _kruskal_bits::KruskalValueSelector::Value + kruskal(const Graph& graph, const In& in, const Out& out) + { + return _kruskal_bits::KruskalInputSelector:: + kruskal(graph, in, out); + } + +} //namespace lemon + +#endif //LEMON_KRUSKAL_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/lemon.pc.in b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lemon.pc.in new file mode 100644 index 00000000000..e85bf7652ec --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lemon.pc.in @@ -0,0 +1,10 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=@CMAKE_INSTALL_PREFIX@/bin +libdir=@CMAKE_INSTALL_PREFIX@/lib +includedir=@CMAKE_INSTALL_PREFIX@/include + +Name: @PROJECT_NAME@ +Description: Library for Efficient Modeling and Optimization in Networks +Version: @PROJECT_VERSION@ +Libs: -L${libdir} -lemon @GLPK_LIBS@ @CPLEX_LIBS@ @SOPLEX_LIBS@ @CLP_LIBS@ @CBC_LIBS@ +Cflags: -I${includedir} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/lgf_reader.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lgf_reader.h new file mode 100644 index 00000000000..2f49fa25f21 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lgf_reader.h @@ -0,0 +1,3854 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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. + * + */ + +///\ingroup lemon_io +///\file +///\brief \ref lgf-format "LEMON Graph Format" reader. + + +#ifndef LEMON_LGF_READER_H +#define LEMON_LGF_READER_H + +#include +#include +#include + +#include +#include + +#include + +#include + +#include +#include + +namespace lemon { + + namespace _reader_bits { + + template + struct DefaultConverter { + Value operator()(const std::string& str) { + std::istringstream is(str); + Value value; + if (!(is >> value)) { + throw FormatError("Cannot read token"); + } + + char c; + if (is >> std::ws >> c) { + throw FormatError("Remaining characters in token"); + } + return value; + } + }; + + template <> + struct DefaultConverter { + std::string operator()(const std::string& str) { + return str; + } + }; + + template + class MapStorageBase { + public: + typedef _Item Item; + + public: + MapStorageBase() {} + virtual ~MapStorageBase() {} + + virtual void set(const Item& item, const std::string& value) = 0; + + }; + + template > + class MapStorage : public MapStorageBase<_Item> { + public: + typedef _Map Map; + typedef _Converter Converter; + typedef _Item Item; + + private: + Map& _map; + Converter _converter; + + public: + MapStorage(Map& map, const Converter& converter = Converter()) + : _map(map), _converter(converter) {} + virtual ~MapStorage() {} + + virtual void set(const Item& item ,const std::string& value) { + _map.set(item, _converter(value)); + } + }; + + template > + class GraphArcMapStorage : public MapStorageBase { + public: + typedef _Map Map; + typedef _Converter Converter; + typedef _GR GR; + typedef typename GR::Edge Item; + static const bool dir = _dir; + + private: + const GR& _graph; + Map& _map; + Converter _converter; + + public: + GraphArcMapStorage(const GR& graph, Map& map, + const Converter& converter = Converter()) + : _graph(graph), _map(map), _converter(converter) {} + virtual ~GraphArcMapStorage() {} + + virtual void set(const Item& item ,const std::string& value) { + _map.set(_graph.direct(item, dir), _converter(value)); + } + }; + + class ValueStorageBase { + public: + ValueStorageBase() {} + virtual ~ValueStorageBase() {} + + virtual void set(const std::string&) = 0; + }; + + template > + class ValueStorage : public ValueStorageBase { + public: + typedef _Value Value; + typedef _Converter Converter; + + private: + Value& _value; + Converter _converter; + + public: + ValueStorage(Value& value, const Converter& converter = Converter()) + : _value(value), _converter(converter) {} + + virtual void set(const std::string& value) { + _value = _converter(value); + } + }; + + template > + struct MapLookUpConverter { + const Map& _map; + + MapLookUpConverter(const Map& map) + : _map(map) {} + + Value operator()(const std::string& str) { + typename Map::const_iterator it = _map.find(str); + if (it == _map.end()) { + std::ostringstream msg; + msg << "Item not found: " << str; + throw FormatError(msg.str()); + } + return it->second; + } + }; + + template , + typename Map2 = std::map > + struct DoubleMapLookUpConverter { + const Map1& _map1; + const Map2& _map2; + + DoubleMapLookUpConverter(const Map1& map1, const Map2& map2) + : _map1(map1), _map2(map2) {} + + Value operator()(const std::string& str) { + typename Map1::const_iterator it1 = _map1.find(str); + typename Map2::const_iterator it2 = _map2.find(str); + if (it1 == _map1.end()) { + if (it2 == _map2.end()) { + std::ostringstream msg; + msg << "Item not found: " << str; + throw FormatError(msg.str()); + } else { + return it2->second; + } + } else { + if (it2 == _map2.end()) { + return it1->second; + } else { + std::ostringstream msg; + msg << "Item is ambigous: " << str; + throw FormatError(msg.str()); + } + } + } + }; + + template + struct GraphArcLookUpConverter { + const GR& _graph; + const std::map& _map; + + GraphArcLookUpConverter(const GR& graph, + const std::map& map) + : _graph(graph), _map(map) {} + + typename GR::Arc operator()(const std::string& str) { + if (str.empty() || (str[0] != '+' && str[0] != '-')) { + throw FormatError("Item must start with '+' or '-'"); + } + typename std::map + ::const_iterator it = _map.find(str.substr(1)); + if (it == _map.end()) { + throw FormatError("Item not found"); + } + return _graph.direct(it->second, str[0] == '+'); + } + }; + + inline bool isWhiteSpace(char c) { + return c == ' ' || c == '\t' || c == '\v' || + c == '\n' || c == '\r' || c == '\f'; + } + + inline bool isOct(char c) { + return '0' <= c && c <='7'; + } + + inline int valueOct(char c) { + LEMON_ASSERT(isOct(c), "The character is not octal."); + return c - '0'; + } + + inline bool isHex(char c) { + return ('0' <= c && c <= '9') || + ('a' <= c && c <= 'z') || + ('A' <= c && c <= 'Z'); + } + + inline int valueHex(char c) { + LEMON_ASSERT(isHex(c), "The character is not hexadecimal."); + if ('0' <= c && c <= '9') return c - '0'; + if ('a' <= c && c <= 'z') return c - 'a' + 10; + return c - 'A' + 10; + } + + inline bool isIdentifierFirstChar(char c) { + return ('a' <= c && c <= 'z') || + ('A' <= c && c <= 'Z') || c == '_'; + } + + inline bool isIdentifierChar(char c) { + return isIdentifierFirstChar(c) || + ('0' <= c && c <= '9'); + } + + inline char readEscape(std::istream& is) { + char c; + if (!is.get(c)) + throw FormatError("Escape format error"); + + switch (c) { + case '\\': + return '\\'; + case '\"': + return '\"'; + case '\'': + return '\''; + case '\?': + return '\?'; + case 'a': + return '\a'; + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case 'v': + return '\v'; + case 'x': + { + int code; + if (!is.get(c) || !isHex(c)) + throw FormatError("Escape format error"); + else if (code = valueHex(c), !is.get(c) || !isHex(c)) is.putback(c); + else code = code * 16 + valueHex(c); + return code; + } + default: + { + int code; + if (!isOct(c)) + throw FormatError("Escape format error"); + else if (code = valueOct(c), !is.get(c) || !isOct(c)) + is.putback(c); + else if (code = code * 8 + valueOct(c), !is.get(c) || !isOct(c)) + is.putback(c); + else code = code * 8 + valueOct(c); + return code; + } + } + } + + inline std::istream& readToken(std::istream& is, std::string& str) { + std::ostringstream os; + + char c; + is >> std::ws; + + if (!is.get(c)) + return is; + + if (c == '\"') { + while (is.get(c) && c != '\"') { + if (c == '\\') + c = readEscape(is); + os << c; + } + if (!is) + throw FormatError("Quoted format error"); + } else { + is.putback(c); + while (is.get(c) && !isWhiteSpace(c)) { + if (c == '\\') + c = readEscape(is); + os << c; + } + if (!is) { + is.clear(); + } else { + is.putback(c); + } + } + str = os.str(); + return is; + } + + class Section { + public: + virtual ~Section() {} + virtual void process(std::istream& is, int& line_num) = 0; + }; + + template + class LineSection : public Section { + private: + + Functor _functor; + + public: + + LineSection(const Functor& functor) : _functor(functor) {} + virtual ~LineSection() {} + + virtual void process(std::istream& is, int& line_num) { + char c; + std::string line; + while (is.get(c) && c != '@') { + if (c == '\n') { + ++line_num; + } else if (c == '#') { + getline(is, line); + ++line_num; + } else if (!isWhiteSpace(c)) { + is.putback(c); + getline(is, line); + _functor(line); + ++line_num; + } + } + if (is) is.putback(c); + else if (is.eof()) is.clear(); + } + }; + + template + class StreamSection : public Section { + private: + + Functor _functor; + + public: + + StreamSection(const Functor& functor) : _functor(functor) {} + virtual ~StreamSection() {} + + virtual void process(std::istream& is, int& line_num) { + _functor(is, line_num); + char c; + std::string line; + while (is.get(c) && c != '@') { + if (c == '\n') { + ++line_num; + } else if (!isWhiteSpace(c)) { + getline(is, line); + ++line_num; + } + } + if (is) is.putback(c); + else if (is.eof()) is.clear(); + } + }; + + } + + template + class DigraphReader; + + template + DigraphReader digraphReader(TDGR& digraph, std::istream& is = std::cin); + template + DigraphReader digraphReader(TDGR& digraph, const std::string& fn); + template + DigraphReader digraphReader(TDGR& digraph, const char *fn); + + /// \ingroup lemon_io + /// + /// \brief \ref lgf-format "LGF" reader for directed graphs + /// + /// This utility reads an \ref lgf-format "LGF" file. + /// + /// The reading method does a batch processing. The user creates a + /// reader object, then various reading rules can be added to the + /// reader, and eventually the reading is executed with the \c run() + /// member function. A map reading rule can be added to the reader + /// with the \c nodeMap() or \c arcMap() members. An optional + /// converter parameter can also be added as a standard functor + /// converting from \c std::string to the value type of the map. If it + /// is set, it will determine how the tokens in the file should be + /// converted to the value type of the map. If the functor is not set, + /// then a default conversion will be used. One map can be read into + /// multiple map objects at the same time. The \c attribute(), \c + /// node() and \c arc() functions are used to add attribute reading + /// rules. + /// + ///\code + /// DigraphReader(digraph, std::cin). + /// nodeMap("coordinates", coord_map). + /// arcMap("capacity", cap_map). + /// node("source", src). + /// node("target", trg). + /// attribute("caption", caption). + /// run(); + ///\endcode + /// + /// By default, the reader uses the first section in the file of the + /// proper type. If a section has an optional name, then it can be + /// selected for reading by giving an optional name parameter to the + /// \c nodes(), \c arcs() or \c attributes() functions. + /// + /// The \c useNodes() and \c useArcs() functions are used to tell the reader + /// that the nodes or arcs should not be constructed (added to the + /// graph) during the reading, but instead the label map of the items + /// are given as a parameter of these functions. An + /// application of these functions is multipass reading, which is + /// important if two \c \@arcs sections must be read from the + /// file. In this case the first phase would read the node set and one + /// of the arc sets, while the second phase would read the second arc + /// set into an \e ArcSet class (\c SmartArcSet or \c ListArcSet). + /// The previously read label node map should be passed to the \c + /// useNodes() functions. Another application of multipass reading when + /// paths are given as a node map or an arc map. + /// It is impossible to read this in + /// a single pass, because the arcs are not constructed when the node + /// maps are read. + template + class DigraphReader { + public: + + typedef DGR Digraph; + + private: + + TEMPLATE_DIGRAPH_TYPEDEFS(DGR); + + std::istream* _is; + bool local_is; + std::string _filename; + + DGR& _digraph; + + std::string _nodes_caption; + std::string _arcs_caption; + std::string _attributes_caption; + + typedef std::map NodeIndex; + NodeIndex _node_index; + typedef std::map ArcIndex; + ArcIndex _arc_index; + + typedef std::vector*> > NodeMaps; + NodeMaps _node_maps; + + typedef std::vector*> >ArcMaps; + ArcMaps _arc_maps; + + typedef std::multimap + Attributes; + Attributes _attributes; + + bool _use_nodes; + bool _use_arcs; + + bool _skip_nodes; + bool _skip_arcs; + + int line_num; + std::istringstream line; + + public: + + /// \brief Constructor + /// + /// Construct a directed graph reader, which reads from the given + /// input stream. + DigraphReader(DGR& digraph, std::istream& is = std::cin) + : _is(&is), local_is(false), _digraph(digraph), + _use_nodes(false), _use_arcs(false), + _skip_nodes(false), _skip_arcs(false) {} + + /// \brief Constructor + /// + /// Construct a directed graph reader, which reads from the given + /// file. + DigraphReader(DGR& digraph, const std::string& fn) + : _is(new std::ifstream(fn.c_str())), local_is(true), + _filename(fn), _digraph(digraph), + _use_nodes(false), _use_arcs(false), + _skip_nodes(false), _skip_arcs(false) { + if (!(*_is)) { + delete _is; + throw IoError("Cannot open file", fn); + } + } + + /// \brief Constructor + /// + /// Construct a directed graph reader, which reads from the given + /// file. + DigraphReader(DGR& digraph, const char* fn) + : _is(new std::ifstream(fn)), local_is(true), + _filename(fn), _digraph(digraph), + _use_nodes(false), _use_arcs(false), + _skip_nodes(false), _skip_arcs(false) { + if (!(*_is)) { + delete _is; + throw IoError("Cannot open file", fn); + } + } + + /// \brief Destructor + ~DigraphReader() { + for (typename NodeMaps::iterator it = _node_maps.begin(); + it != _node_maps.end(); ++it) { + delete it->second; + } + + for (typename ArcMaps::iterator it = _arc_maps.begin(); + it != _arc_maps.end(); ++it) { + delete it->second; + } + + for (typename Attributes::iterator it = _attributes.begin(); + it != _attributes.end(); ++it) { + delete it->second; + } + + if (local_is) { + delete _is; + } + + } + + private: + + template + friend DigraphReader digraphReader(TDGR& digraph, std::istream& is); + template + friend DigraphReader digraphReader(TDGR& digraph, + const std::string& fn); + template + friend DigraphReader digraphReader(TDGR& digraph, const char *fn); + + DigraphReader(DigraphReader& other) + : _is(other._is), local_is(other.local_is), _digraph(other._digraph), + _use_nodes(other._use_nodes), _use_arcs(other._use_arcs), + _skip_nodes(other._skip_nodes), _skip_arcs(other._skip_arcs) { + + other._is = 0; + other.local_is = false; + + _node_index.swap(other._node_index); + _arc_index.swap(other._arc_index); + + _node_maps.swap(other._node_maps); + _arc_maps.swap(other._arc_maps); + _attributes.swap(other._attributes); + + _nodes_caption = other._nodes_caption; + _arcs_caption = other._arcs_caption; + _attributes_caption = other._attributes_caption; + + } + + DigraphReader& operator=(const DigraphReader&); + + public: + + /// \name Reading Rules + /// @{ + + /// \brief Node map reading rule + /// + /// Add a node map reading rule to the reader. + template + DigraphReader& nodeMap(const std::string& caption, Map& map) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* storage = + new _reader_bits::MapStorage(map); + _node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Node map reading rule + /// + /// Add a node map reading rule with specialized converter to the + /// reader. + template + DigraphReader& nodeMap(const std::string& caption, Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* storage = + new _reader_bits::MapStorage(map, converter); + _node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Arc map reading rule + /// + /// Add an arc map reading rule to the reader. + template + DigraphReader& arcMap(const std::string& caption, Map& map) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* storage = + new _reader_bits::MapStorage(map); + _arc_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Arc map reading rule + /// + /// Add an arc map reading rule with specialized converter to the + /// reader. + template + DigraphReader& arcMap(const std::string& caption, Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* storage = + new _reader_bits::MapStorage(map, converter); + _arc_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Attribute reading rule + /// + /// Add an attribute reading rule to the reader. + template + DigraphReader& attribute(const std::string& caption, Value& value) { + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(value); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Attribute reading rule + /// + /// Add an attribute reading rule with specialized converter to the + /// reader. + template + DigraphReader& attribute(const std::string& caption, Value& value, + const Converter& converter = Converter()) { + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(value, converter); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Node reading rule + /// + /// Add a node reading rule to reader. + DigraphReader& node(const std::string& caption, Node& node) { + typedef _reader_bits::MapLookUpConverter Converter; + Converter converter(_node_index); + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(node, converter); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Arc reading rule + /// + /// Add an arc reading rule to reader. + DigraphReader& arc(const std::string& caption, Arc& arc) { + typedef _reader_bits::MapLookUpConverter Converter; + Converter converter(_arc_index); + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(arc, converter); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// @} + + /// \name Select Section by Name + /// @{ + + /// \brief Set \c \@nodes section to be read + /// + /// Set \c \@nodes section to be read + DigraphReader& nodes(const std::string& caption) { + _nodes_caption = caption; + return *this; + } + + /// \brief Set \c \@arcs section to be read + /// + /// Set \c \@arcs section to be read + DigraphReader& arcs(const std::string& caption) { + _arcs_caption = caption; + return *this; + } + + /// \brief Set \c \@attributes section to be read + /// + /// Set \c \@attributes section to be read + DigraphReader& attributes(const std::string& caption) { + _attributes_caption = caption; + return *this; + } + + /// @} + + /// \name Using Previously Constructed Node or Arc Set + /// @{ + + /// \brief Use previously constructed node set + /// + /// Use previously constructed node set, and specify the node + /// label map. + template + DigraphReader& useNodes(const Map& map) { + checkConcept, Map>(); + LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member"); + _use_nodes = true; + _writer_bits::DefaultConverter converter; + for (NodeIt n(_digraph); n != INVALID; ++n) { + _node_index.insert(std::make_pair(converter(map[n]), n)); + } + return *this; + } + + /// \brief Use previously constructed node set + /// + /// Use previously constructed node set, and specify the node + /// label map and a functor which converts the label map values to + /// \c std::string. + template + DigraphReader& useNodes(const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member"); + _use_nodes = true; + for (NodeIt n(_digraph); n != INVALID; ++n) { + _node_index.insert(std::make_pair(converter(map[n]), n)); + } + return *this; + } + + /// \brief Use previously constructed arc set + /// + /// Use previously constructed arc set, and specify the arc + /// label map. + template + DigraphReader& useArcs(const Map& map) { + checkConcept, Map>(); + LEMON_ASSERT(!_use_arcs, "Multiple usage of useArcs() member"); + _use_arcs = true; + _writer_bits::DefaultConverter converter; + for (ArcIt a(_digraph); a != INVALID; ++a) { + _arc_index.insert(std::make_pair(converter(map[a]), a)); + } + return *this; + } + + /// \brief Use previously constructed arc set + /// + /// Use previously constructed arc set, and specify the arc + /// label map and a functor which converts the label map values to + /// \c std::string. + template + DigraphReader& useArcs(const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + LEMON_ASSERT(!_use_arcs, "Multiple usage of useArcs() member"); + _use_arcs = true; + for (ArcIt a(_digraph); a != INVALID; ++a) { + _arc_index.insert(std::make_pair(converter(map[a]), a)); + } + return *this; + } + + /// \brief Skips the reading of node section + /// + /// Omit the reading of the node section. This implies that each node + /// map reading rule will be abandoned, and the nodes of the graph + /// will not be constructed, which usually cause that the arc set + /// could not be read due to lack of node name resolving. + /// Therefore \c skipArcs() function should also be used, or + /// \c useNodes() should be used to specify the label of the nodes. + DigraphReader& skipNodes() { + LEMON_ASSERT(!_skip_nodes, "Skip nodes already set"); + _skip_nodes = true; + return *this; + } + + /// \brief Skips the reading of arc section + /// + /// Omit the reading of the arc section. This implies that each arc + /// map reading rule will be abandoned, and the arcs of the graph + /// will not be constructed. + DigraphReader& skipArcs() { + LEMON_ASSERT(!_skip_arcs, "Skip arcs already set"); + _skip_arcs = true; + return *this; + } + + /// @} + + private: + + bool readLine() { + std::string str; + while(++line_num, std::getline(*_is, str)) { + line.clear(); line.str(str); + char c; + if (line >> std::ws >> c && c != '#') { + line.putback(c); + return true; + } + } + return false; + } + + bool readSuccess() { + return static_cast(*_is); + } + + void skipSection() { + char c; + while (readSuccess() && line >> c && c != '@') { + readLine(); + } + if (readSuccess()) { + line.putback(c); + } + } + + void readNodes() { + + std::vector map_index(_node_maps.size()); + int map_num, label_index; + + char c; + if (!readLine() || !(line >> c) || c == '@') { + if (readSuccess() && line) line.putback(c); + if (!_node_maps.empty()) + throw FormatError("Cannot find map names"); + return; + } + line.putback(c); + + { + std::map maps; + + std::string map; + int index = 0; + while (_reader_bits::readToken(line, map)) { + if (maps.find(map) != maps.end()) { + std::ostringstream msg; + msg << "Multiple occurence of node map: " << map; + throw FormatError(msg.str()); + } + maps.insert(std::make_pair(map, index)); + ++index; + } + + for (int i = 0; i < static_cast(_node_maps.size()); ++i) { + std::map::iterator jt = + maps.find(_node_maps[i].first); + if (jt == maps.end()) { + std::ostringstream msg; + msg << "Map not found: " << _node_maps[i].first; + throw FormatError(msg.str()); + } + map_index[i] = jt->second; + } + + { + std::map::iterator jt = maps.find("label"); + if (jt != maps.end()) { + label_index = jt->second; + } else { + label_index = -1; + } + } + map_num = maps.size(); + } + + while (readLine() && line >> c && c != '@') { + line.putback(c); + + std::vector tokens(map_num); + for (int i = 0; i < map_num; ++i) { + if (!_reader_bits::readToken(line, tokens[i])) { + std::ostringstream msg; + msg << "Column not found (" << i + 1 << ")"; + throw FormatError(msg.str()); + } + } + if (line >> std::ws >> c) + throw FormatError("Extra character at the end of line"); + + Node n; + if (!_use_nodes) { + n = _digraph.addNode(); + if (label_index != -1) + _node_index.insert(std::make_pair(tokens[label_index], n)); + } else { + if (label_index == -1) + throw FormatError("Label map not found"); + typename std::map::iterator it = + _node_index.find(tokens[label_index]); + if (it == _node_index.end()) { + std::ostringstream msg; + msg << "Node with label not found: " << tokens[label_index]; + throw FormatError(msg.str()); + } + n = it->second; + } + + for (int i = 0; i < static_cast(_node_maps.size()); ++i) { + _node_maps[i].second->set(n, tokens[map_index[i]]); + } + + } + if (readSuccess()) { + line.putback(c); + } + } + + void readArcs() { + + std::vector map_index(_arc_maps.size()); + int map_num, label_index; + + char c; + if (!readLine() || !(line >> c) || c == '@') { + if (readSuccess() && line) line.putback(c); + if (!_arc_maps.empty()) + throw FormatError("Cannot find map names"); + return; + } + line.putback(c); + + { + std::map maps; + + std::string map; + int index = 0; + while (_reader_bits::readToken(line, map)) { + if(map == "-") { + if(index!=0) + throw FormatError("'-' is not allowed as a map name"); + else if (line >> std::ws >> c) + throw FormatError("Extra character at the end of line"); + else break; + } + if (maps.find(map) != maps.end()) { + std::ostringstream msg; + msg << "Multiple occurence of arc map: " << map; + throw FormatError(msg.str()); + } + maps.insert(std::make_pair(map, index)); + ++index; + } + + for (int i = 0; i < static_cast(_arc_maps.size()); ++i) { + std::map::iterator jt = + maps.find(_arc_maps[i].first); + if (jt == maps.end()) { + std::ostringstream msg; + msg << "Map not found: " << _arc_maps[i].first; + throw FormatError(msg.str()); + } + map_index[i] = jt->second; + } + + { + std::map::iterator jt = maps.find("label"); + if (jt != maps.end()) { + label_index = jt->second; + } else { + label_index = -1; + } + } + map_num = maps.size(); + } + + while (readLine() && line >> c && c != '@') { + line.putback(c); + + std::string source_token; + std::string target_token; + + if (!_reader_bits::readToken(line, source_token)) + throw FormatError("Source not found"); + + if (!_reader_bits::readToken(line, target_token)) + throw FormatError("Target not found"); + + std::vector tokens(map_num); + for (int i = 0; i < map_num; ++i) { + if (!_reader_bits::readToken(line, tokens[i])) { + std::ostringstream msg; + msg << "Column not found (" << i + 1 << ")"; + throw FormatError(msg.str()); + } + } + if (line >> std::ws >> c) + throw FormatError("Extra character at the end of line"); + + Arc a; + if (!_use_arcs) { + + typename NodeIndex::iterator it; + + it = _node_index.find(source_token); + if (it == _node_index.end()) { + std::ostringstream msg; + msg << "Item not found: " << source_token; + throw FormatError(msg.str()); + } + Node source = it->second; + + it = _node_index.find(target_token); + if (it == _node_index.end()) { + std::ostringstream msg; + msg << "Item not found: " << target_token; + throw FormatError(msg.str()); + } + Node target = it->second; + + a = _digraph.addArc(source, target); + if (label_index != -1) + _arc_index.insert(std::make_pair(tokens[label_index], a)); + } else { + if (label_index == -1) + throw FormatError("Label map not found"); + typename std::map::iterator it = + _arc_index.find(tokens[label_index]); + if (it == _arc_index.end()) { + std::ostringstream msg; + msg << "Arc with label not found: " << tokens[label_index]; + throw FormatError(msg.str()); + } + a = it->second; + } + + for (int i = 0; i < static_cast(_arc_maps.size()); ++i) { + _arc_maps[i].second->set(a, tokens[map_index[i]]); + } + + } + if (readSuccess()) { + line.putback(c); + } + } + + void readAttributes() { + + std::set read_attr; + + char c; + while (readLine() && line >> c && c != '@') { + line.putback(c); + + std::string attr, token; + if (!_reader_bits::readToken(line, attr)) + throw FormatError("Attribute name not found"); + if (!_reader_bits::readToken(line, token)) + throw FormatError("Attribute value not found"); + if (line >> c) + throw FormatError("Extra character at the end of line"); + + { + std::set::iterator it = read_attr.find(attr); + if (it != read_attr.end()) { + std::ostringstream msg; + msg << "Multiple occurence of attribute: " << attr; + throw FormatError(msg.str()); + } + read_attr.insert(attr); + } + + { + typename Attributes::iterator it = _attributes.lower_bound(attr); + while (it != _attributes.end() && it->first == attr) { + it->second->set(token); + ++it; + } + } + + } + if (readSuccess()) { + line.putback(c); + } + for (typename Attributes::iterator it = _attributes.begin(); + it != _attributes.end(); ++it) { + if (read_attr.find(it->first) == read_attr.end()) { + std::ostringstream msg; + msg << "Attribute not found: " << it->first; + throw FormatError(msg.str()); + } + } + } + + public: + + /// \name Execution of the Reader + /// @{ + + /// \brief Start the batch processing + /// + /// This function starts the batch processing + void run() { + LEMON_ASSERT(_is != 0, "This reader assigned to an other reader"); + + bool nodes_done = _skip_nodes; + bool arcs_done = _skip_arcs; + bool attributes_done = false; + + line_num = 0; + readLine(); + skipSection(); + + while (readSuccess()) { + try { + char c; + std::string section, caption; + line >> c; + _reader_bits::readToken(line, section); + _reader_bits::readToken(line, caption); + + if (line >> c) + throw FormatError("Extra character at the end of line"); + + if (section == "nodes" && !nodes_done) { + if (_nodes_caption.empty() || _nodes_caption == caption) { + readNodes(); + nodes_done = true; + } + } else if ((section == "arcs" || section == "edges") && + !arcs_done) { + if (_arcs_caption.empty() || _arcs_caption == caption) { + readArcs(); + arcs_done = true; + } + } else if (section == "attributes" && !attributes_done) { + if (_attributes_caption.empty() || _attributes_caption == caption) { + readAttributes(); + attributes_done = true; + } + } else { + readLine(); + skipSection(); + } + } catch (FormatError& error) { + error.line(line_num); + error.file(_filename); + throw; + } + } + + if (!nodes_done) { + throw FormatError("Section @nodes not found"); + } + + if (!arcs_done) { + throw FormatError("Section @arcs not found"); + } + + if (!attributes_done && !_attributes.empty()) { + throw FormatError("Section @attributes not found"); + } + + } + + /// @} + + }; + + /// \ingroup lemon_io + /// + /// \brief Return a \ref lemon::DigraphReader "DigraphReader" class + /// + /// This function just returns a \ref lemon::DigraphReader + /// "DigraphReader" class. + /// + /// With this function a digraph can be read from an + /// \ref lgf-format "LGF" file or input stream with several maps and + /// attributes. For example, there is network flow problem on a + /// digraph, i.e. a digraph with a \e capacity map on the arcs and + /// \e source and \e target nodes. This digraph can be read with the + /// following code: + /// + ///\code + ///ListDigraph digraph; + ///ListDigraph::ArcMap cm(digraph); + ///ListDigraph::Node src, trg; + ///digraphReader(digraph, std::cin). + /// arcMap("capacity", cap). + /// node("source", src). + /// node("target", trg). + /// run(); + ///\endcode + /// + /// For a complete documentation, please see the + /// \ref lemon::DigraphReader "DigraphReader" + /// class documentation. + /// \warning Don't forget to put the \ref lemon::DigraphReader::run() "run()" + /// to the end of the parameter list. + /// \relates DigraphReader + /// \sa digraphReader(TDGR& digraph, const std::string& fn) + /// \sa digraphReader(TDGR& digraph, const char* fn) + template + DigraphReader digraphReader(TDGR& digraph, std::istream& is) { + DigraphReader tmp(digraph, is); + return tmp; + } + + /// \brief Return a \ref DigraphReader class + /// + /// This function just returns a \ref DigraphReader class. + /// \relates DigraphReader + /// \sa digraphReader(TDGR& digraph, std::istream& is) + template + DigraphReader digraphReader(TDGR& digraph, const std::string& fn) { + DigraphReader tmp(digraph, fn); + return tmp; + } + + /// \brief Return a \ref DigraphReader class + /// + /// This function just returns a \ref DigraphReader class. + /// \relates DigraphReader + /// \sa digraphReader(TDGR& digraph, std::istream& is) + template + DigraphReader digraphReader(TDGR& digraph, const char* fn) { + DigraphReader tmp(digraph, fn); + return tmp; + } + + template + class GraphReader; + + template + GraphReader graphReader(TGR& graph, std::istream& is = std::cin); + template + GraphReader graphReader(TGR& graph, const std::string& fn); + template + GraphReader graphReader(TGR& graph, const char *fn); + + /// \ingroup lemon_io + /// + /// \brief \ref lgf-format "LGF" reader for undirected graphs + /// + /// This utility reads an \ref lgf-format "LGF" file. + /// + /// It can be used almost the same way as \c DigraphReader. + /// The only difference is that this class can handle edges and + /// edge maps as well as arcs and arc maps. + /// + /// The columns in the \c \@edges (or \c \@arcs) section are the + /// edge maps. However, if there are two maps with the same name + /// prefixed with \c '+' and \c '-', then these can be read into an + /// arc map. Similarly, an attribute can be read into an arc, if + /// it's value is an edge label prefixed with \c '+' or \c '-'. + template + class GraphReader { + public: + + typedef GR Graph; + + private: + + TEMPLATE_GRAPH_TYPEDEFS(GR); + + std::istream* _is; + bool local_is; + std::string _filename; + + GR& _graph; + + std::string _nodes_caption; + std::string _edges_caption; + std::string _attributes_caption; + + typedef std::map NodeIndex; + NodeIndex _node_index; + typedef std::map EdgeIndex; + EdgeIndex _edge_index; + + typedef std::vector*> > NodeMaps; + NodeMaps _node_maps; + + typedef std::vector*> > EdgeMaps; + EdgeMaps _edge_maps; + + typedef std::multimap + Attributes; + Attributes _attributes; + + bool _use_nodes; + bool _use_edges; + + bool _skip_nodes; + bool _skip_edges; + + int line_num; + std::istringstream line; + + public: + + /// \brief Constructor + /// + /// Construct an undirected graph reader, which reads from the given + /// input stream. + GraphReader(GR& graph, std::istream& is = std::cin) + : _is(&is), local_is(false), _graph(graph), + _use_nodes(false), _use_edges(false), + _skip_nodes(false), _skip_edges(false) {} + + /// \brief Constructor + /// + /// Construct an undirected graph reader, which reads from the given + /// file. + GraphReader(GR& graph, const std::string& fn) + : _is(new std::ifstream(fn.c_str())), local_is(true), + _filename(fn), _graph(graph), + _use_nodes(false), _use_edges(false), + _skip_nodes(false), _skip_edges(false) { + if (!(*_is)) { + delete _is; + throw IoError("Cannot open file", fn); + } + } + + /// \brief Constructor + /// + /// Construct an undirected graph reader, which reads from the given + /// file. + GraphReader(GR& graph, const char* fn) + : _is(new std::ifstream(fn)), local_is(true), + _filename(fn), _graph(graph), + _use_nodes(false), _use_edges(false), + _skip_nodes(false), _skip_edges(false) { + if (!(*_is)) { + delete _is; + throw IoError("Cannot open file", fn); + } + } + + /// \brief Destructor + ~GraphReader() { + for (typename NodeMaps::iterator it = _node_maps.begin(); + it != _node_maps.end(); ++it) { + delete it->second; + } + + for (typename EdgeMaps::iterator it = _edge_maps.begin(); + it != _edge_maps.end(); ++it) { + delete it->second; + } + + for (typename Attributes::iterator it = _attributes.begin(); + it != _attributes.end(); ++it) { + delete it->second; + } + + if (local_is) { + delete _is; + } + + } + + private: + template + friend GraphReader graphReader(TGR& graph, std::istream& is); + template + friend GraphReader graphReader(TGR& graph, const std::string& fn); + template + friend GraphReader graphReader(TGR& graph, const char *fn); + + GraphReader(GraphReader& other) + : _is(other._is), local_is(other.local_is), _graph(other._graph), + _use_nodes(other._use_nodes), _use_edges(other._use_edges), + _skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) { + + other._is = 0; + other.local_is = false; + + _node_index.swap(other._node_index); + _edge_index.swap(other._edge_index); + + _node_maps.swap(other._node_maps); + _edge_maps.swap(other._edge_maps); + _attributes.swap(other._attributes); + + _nodes_caption = other._nodes_caption; + _edges_caption = other._edges_caption; + _attributes_caption = other._attributes_caption; + + } + + GraphReader& operator=(const GraphReader&); + + public: + + /// \name Reading Rules + /// @{ + + /// \brief Node map reading rule + /// + /// Add a node map reading rule to the reader. + template + GraphReader& nodeMap(const std::string& caption, Map& map) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* storage = + new _reader_bits::MapStorage(map); + _node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Node map reading rule + /// + /// Add a node map reading rule with specialized converter to the + /// reader. + template + GraphReader& nodeMap(const std::string& caption, Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* storage = + new _reader_bits::MapStorage(map, converter); + _node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Edge map reading rule + /// + /// Add an edge map reading rule to the reader. + template + GraphReader& edgeMap(const std::string& caption, Map& map) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* storage = + new _reader_bits::MapStorage(map); + _edge_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Edge map reading rule + /// + /// Add an edge map reading rule with specialized converter to the + /// reader. + template + GraphReader& edgeMap(const std::string& caption, Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* storage = + new _reader_bits::MapStorage(map, converter); + _edge_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Arc map reading rule + /// + /// Add an arc map reading rule to the reader. + template + GraphReader& arcMap(const std::string& caption, Map& map) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* forward_storage = + new _reader_bits::GraphArcMapStorage(_graph, map); + _edge_maps.push_back(std::make_pair('+' + caption, forward_storage)); + _reader_bits::MapStorageBase* backward_storage = + new _reader_bits::GraphArcMapStorage(_graph, map); + _edge_maps.push_back(std::make_pair('-' + caption, backward_storage)); + return *this; + } + + /// \brief Arc map reading rule + /// + /// Add an arc map reading rule with specialized converter to the + /// reader. + template + GraphReader& arcMap(const std::string& caption, Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* forward_storage = + new _reader_bits::GraphArcMapStorage + (_graph, map, converter); + _edge_maps.push_back(std::make_pair('+' + caption, forward_storage)); + _reader_bits::MapStorageBase* backward_storage = + new _reader_bits::GraphArcMapStorage + (_graph, map, converter); + _edge_maps.push_back(std::make_pair('-' + caption, backward_storage)); + return *this; + } + + /// \brief Attribute reading rule + /// + /// Add an attribute reading rule to the reader. + template + GraphReader& attribute(const std::string& caption, Value& value) { + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(value); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Attribute reading rule + /// + /// Add an attribute reading rule with specialized converter to the + /// reader. + template + GraphReader& attribute(const std::string& caption, Value& value, + const Converter& converter = Converter()) { + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(value, converter); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Node reading rule + /// + /// Add a node reading rule to reader. + GraphReader& node(const std::string& caption, Node& node) { + typedef _reader_bits::MapLookUpConverter Converter; + Converter converter(_node_index); + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(node, converter); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Edge reading rule + /// + /// Add an edge reading rule to reader. + GraphReader& edge(const std::string& caption, Edge& edge) { + typedef _reader_bits::MapLookUpConverter Converter; + Converter converter(_edge_index); + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(edge, converter); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Arc reading rule + /// + /// Add an arc reading rule to reader. + GraphReader& arc(const std::string& caption, Arc& arc) { + typedef _reader_bits::GraphArcLookUpConverter Converter; + Converter converter(_graph, _edge_index); + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(arc, converter); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// @} + + /// \name Select Section by Name + /// @{ + + /// \brief Set \c \@nodes section to be read + /// + /// Set \c \@nodes section to be read. + GraphReader& nodes(const std::string& caption) { + _nodes_caption = caption; + return *this; + } + + /// \brief Set \c \@edges section to be read + /// + /// Set \c \@edges section to be read. + GraphReader& edges(const std::string& caption) { + _edges_caption = caption; + return *this; + } + + /// \brief Set \c \@attributes section to be read + /// + /// Set \c \@attributes section to be read. + GraphReader& attributes(const std::string& caption) { + _attributes_caption = caption; + return *this; + } + + /// @} + + /// \name Using Previously Constructed Node or Edge Set + /// @{ + + /// \brief Use previously constructed node set + /// + /// Use previously constructed node set, and specify the node + /// label map. + template + GraphReader& useNodes(const Map& map) { + checkConcept, Map>(); + LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member"); + _use_nodes = true; + _writer_bits::DefaultConverter converter; + for (NodeIt n(_graph); n != INVALID; ++n) { + _node_index.insert(std::make_pair(converter(map[n]), n)); + } + return *this; + } + + /// \brief Use previously constructed node set + /// + /// Use previously constructed node set, and specify the node + /// label map and a functor which converts the label map values to + /// \c std::string. + template + GraphReader& useNodes(const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member"); + _use_nodes = true; + for (NodeIt n(_graph); n != INVALID; ++n) { + _node_index.insert(std::make_pair(converter(map[n]), n)); + } + return *this; + } + + /// \brief Use previously constructed edge set + /// + /// Use previously constructed edge set, and specify the edge + /// label map. + template + GraphReader& useEdges(const Map& map) { + checkConcept, Map>(); + LEMON_ASSERT(!_use_edges, "Multiple usage of useEdges() member"); + _use_edges = true; + _writer_bits::DefaultConverter converter; + for (EdgeIt a(_graph); a != INVALID; ++a) { + _edge_index.insert(std::make_pair(converter(map[a]), a)); + } + return *this; + } + + /// \brief Use previously constructed edge set + /// + /// Use previously constructed edge set, and specify the edge + /// label map and a functor which converts the label map values to + /// \c std::string. + template + GraphReader& useEdges(const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + LEMON_ASSERT(!_use_edges, "Multiple usage of useEdges() member"); + _use_edges = true; + for (EdgeIt a(_graph); a != INVALID; ++a) { + _edge_index.insert(std::make_pair(converter(map[a]), a)); + } + return *this; + } + + /// \brief Skip the reading of node section + /// + /// Omit the reading of the node section. This implies that each node + /// map reading rule will be abandoned, and the nodes of the graph + /// will not be constructed, which usually cause that the edge set + /// could not be read due to lack of node name + /// could not be read due to lack of node name resolving. + /// Therefore \c skipEdges() function should also be used, or + /// \c useNodes() should be used to specify the label of the nodes. + GraphReader& skipNodes() { + LEMON_ASSERT(!_skip_nodes, "Skip nodes already set"); + _skip_nodes = true; + return *this; + } + + /// \brief Skip the reading of edge section + /// + /// Omit the reading of the edge section. This implies that each edge + /// map reading rule will be abandoned, and the edges of the graph + /// will not be constructed. + GraphReader& skipEdges() { + LEMON_ASSERT(!_skip_edges, "Skip edges already set"); + _skip_edges = true; + return *this; + } + + /// @} + + private: + + bool readLine() { + std::string str; + while(++line_num, std::getline(*_is, str)) { + line.clear(); line.str(str); + char c; + if (line >> std::ws >> c && c != '#') { + line.putback(c); + return true; + } + } + return false; + } + + bool readSuccess() { + return static_cast(*_is); + } + + void skipSection() { + char c; + while (readSuccess() && line >> c && c != '@') { + readLine(); + } + if (readSuccess()) { + line.putback(c); + } + } + + void readNodes() { + + std::vector map_index(_node_maps.size()); + int map_num, label_index; + + char c; + if (!readLine() || !(line >> c) || c == '@') { + if (readSuccess() && line) line.putback(c); + if (!_node_maps.empty()) + throw FormatError("Cannot find map names"); + return; + } + line.putback(c); + + { + std::map maps; + + std::string map; + int index = 0; + while (_reader_bits::readToken(line, map)) { + if (maps.find(map) != maps.end()) { + std::ostringstream msg; + msg << "Multiple occurence of node map: " << map; + throw FormatError(msg.str()); + } + maps.insert(std::make_pair(map, index)); + ++index; + } + + for (int i = 0; i < static_cast(_node_maps.size()); ++i) { + std::map::iterator jt = + maps.find(_node_maps[i].first); + if (jt == maps.end()) { + std::ostringstream msg; + msg << "Map not found: " << _node_maps[i].first; + throw FormatError(msg.str()); + } + map_index[i] = jt->second; + } + + { + std::map::iterator jt = maps.find("label"); + if (jt != maps.end()) { + label_index = jt->second; + } else { + label_index = -1; + } + } + map_num = maps.size(); + } + + while (readLine() && line >> c && c != '@') { + line.putback(c); + + std::vector tokens(map_num); + for (int i = 0; i < map_num; ++i) { + if (!_reader_bits::readToken(line, tokens[i])) { + std::ostringstream msg; + msg << "Column not found (" << i + 1 << ")"; + throw FormatError(msg.str()); + } + } + if (line >> std::ws >> c) + throw FormatError("Extra character at the end of line"); + + Node n; + if (!_use_nodes) { + n = _graph.addNode(); + if (label_index != -1) + _node_index.insert(std::make_pair(tokens[label_index], n)); + } else { + if (label_index == -1) + throw FormatError("Label map not found"); + typename std::map::iterator it = + _node_index.find(tokens[label_index]); + if (it == _node_index.end()) { + std::ostringstream msg; + msg << "Node with label not found: " << tokens[label_index]; + throw FormatError(msg.str()); + } + n = it->second; + } + + for (int i = 0; i < static_cast(_node_maps.size()); ++i) { + _node_maps[i].second->set(n, tokens[map_index[i]]); + } + + } + if (readSuccess()) { + line.putback(c); + } + } + + void readEdges() { + + std::vector map_index(_edge_maps.size()); + int map_num, label_index; + + char c; + if (!readLine() || !(line >> c) || c == '@') { + if (readSuccess() && line) line.putback(c); + if (!_edge_maps.empty()) + throw FormatError("Cannot find map names"); + return; + } + line.putback(c); + + { + std::map maps; + + std::string map; + int index = 0; + while (_reader_bits::readToken(line, map)) { + if(map == "-") { + if(index!=0) + throw FormatError("'-' is not allowed as a map name"); + else if (line >> std::ws >> c) + throw FormatError("Extra character at the end of line"); + else break; + } + if (maps.find(map) != maps.end()) { + std::ostringstream msg; + msg << "Multiple occurence of edge map: " << map; + throw FormatError(msg.str()); + } + maps.insert(std::make_pair(map, index)); + ++index; + } + + for (int i = 0; i < static_cast(_edge_maps.size()); ++i) { + std::map::iterator jt = + maps.find(_edge_maps[i].first); + if (jt == maps.end()) { + std::ostringstream msg; + msg << "Map not found: " << _edge_maps[i].first; + throw FormatError(msg.str()); + } + map_index[i] = jt->second; + } + + { + std::map::iterator jt = maps.find("label"); + if (jt != maps.end()) { + label_index = jt->second; + } else { + label_index = -1; + } + } + map_num = maps.size(); + } + + while (readLine() && line >> c && c != '@') { + line.putback(c); + + std::string source_token; + std::string target_token; + + if (!_reader_bits::readToken(line, source_token)) + throw FormatError("Node u not found"); + + if (!_reader_bits::readToken(line, target_token)) + throw FormatError("Node v not found"); + + std::vector tokens(map_num); + for (int i = 0; i < map_num; ++i) { + if (!_reader_bits::readToken(line, tokens[i])) { + std::ostringstream msg; + msg << "Column not found (" << i + 1 << ")"; + throw FormatError(msg.str()); + } + } + if (line >> std::ws >> c) + throw FormatError("Extra character at the end of line"); + + Edge e; + if (!_use_edges) { + + typename NodeIndex::iterator it; + + it = _node_index.find(source_token); + if (it == _node_index.end()) { + std::ostringstream msg; + msg << "Item not found: " << source_token; + throw FormatError(msg.str()); + } + Node source = it->second; + + it = _node_index.find(target_token); + if (it == _node_index.end()) { + std::ostringstream msg; + msg << "Item not found: " << target_token; + throw FormatError(msg.str()); + } + Node target = it->second; + + e = _graph.addEdge(source, target); + if (label_index != -1) + _edge_index.insert(std::make_pair(tokens[label_index], e)); + } else { + if (label_index == -1) + throw FormatError("Label map not found"); + typename std::map::iterator it = + _edge_index.find(tokens[label_index]); + if (it == _edge_index.end()) { + std::ostringstream msg; + msg << "Edge with label not found: " << tokens[label_index]; + throw FormatError(msg.str()); + } + e = it->second; + } + + for (int i = 0; i < static_cast(_edge_maps.size()); ++i) { + _edge_maps[i].second->set(e, tokens[map_index[i]]); + } + + } + if (readSuccess()) { + line.putback(c); + } + } + + void readAttributes() { + + std::set read_attr; + + char c; + while (readLine() && line >> c && c != '@') { + line.putback(c); + + std::string attr, token; + if (!_reader_bits::readToken(line, attr)) + throw FormatError("Attribute name not found"); + if (!_reader_bits::readToken(line, token)) + throw FormatError("Attribute value not found"); + if (line >> c) + throw FormatError("Extra character at the end of line"); + + { + std::set::iterator it = read_attr.find(attr); + if (it != read_attr.end()) { + std::ostringstream msg; + msg << "Multiple occurence of attribute: " << attr; + throw FormatError(msg.str()); + } + read_attr.insert(attr); + } + + { + typename Attributes::iterator it = _attributes.lower_bound(attr); + while (it != _attributes.end() && it->first == attr) { + it->second->set(token); + ++it; + } + } + + } + if (readSuccess()) { + line.putback(c); + } + for (typename Attributes::iterator it = _attributes.begin(); + it != _attributes.end(); ++it) { + if (read_attr.find(it->first) == read_attr.end()) { + std::ostringstream msg; + msg << "Attribute not found: " << it->first; + throw FormatError(msg.str()); + } + } + } + + public: + + /// \name Execution of the Reader + /// @{ + + /// \brief Start the batch processing + /// + /// This function starts the batch processing + void run() { + + LEMON_ASSERT(_is != 0, "This reader assigned to an other reader"); + + bool nodes_done = _skip_nodes; + bool edges_done = _skip_edges; + bool attributes_done = false; + + line_num = 0; + readLine(); + skipSection(); + + while (readSuccess()) { + try { + char c; + std::string section, caption; + line >> c; + _reader_bits::readToken(line, section); + _reader_bits::readToken(line, caption); + + if (line >> c) + throw FormatError("Extra character at the end of line"); + + if (section == "nodes" && !nodes_done) { + if (_nodes_caption.empty() || _nodes_caption == caption) { + readNodes(); + nodes_done = true; + } + } else if ((section == "edges" || section == "arcs") && + !edges_done) { + if (_edges_caption.empty() || _edges_caption == caption) { + readEdges(); + edges_done = true; + } + } else if (section == "attributes" && !attributes_done) { + if (_attributes_caption.empty() || _attributes_caption == caption) { + readAttributes(); + attributes_done = true; + } + } else { + readLine(); + skipSection(); + } + } catch (FormatError& error) { + error.line(line_num); + error.file(_filename); + throw; + } + } + + if (!nodes_done) { + throw FormatError("Section @nodes not found"); + } + + if (!edges_done) { + throw FormatError("Section @edges not found"); + } + + if (!attributes_done && !_attributes.empty()) { + throw FormatError("Section @attributes not found"); + } + + } + + /// @} + + }; + + /// \ingroup lemon_io + /// + /// \brief Return a \ref lemon::GraphReader "GraphReader" class + /// + /// This function just returns a \ref lemon::GraphReader "GraphReader" class. + /// + /// With this function a graph can be read from an + /// \ref lgf-format "LGF" file or input stream with several maps and + /// attributes. For example, there is weighted matching problem on a + /// graph, i.e. a graph with a \e weight map on the edges. This + /// graph can be read with the following code: + /// + ///\code + ///ListGraph graph; + ///ListGraph::EdgeMap weight(graph); + ///graphReader(graph, std::cin). + /// edgeMap("weight", weight). + /// run(); + ///\endcode + /// + /// For a complete documentation, please see the + /// \ref lemon::GraphReader "GraphReader" + /// class documentation. + /// \warning Don't forget to put the \ref lemon::GraphReader::run() "run()" + /// to the end of the parameter list. + /// \relates GraphReader + /// \sa graphReader(TGR& graph, const std::string& fn) + /// \sa graphReader(TGR& graph, const char* fn) + template + GraphReader graphReader(TGR& graph, std::istream& is) { + GraphReader tmp(graph, is); + return tmp; + } + + /// \brief Return a \ref GraphReader class + /// + /// This function just returns a \ref GraphReader class. + /// \relates GraphReader + /// \sa graphReader(TGR& graph, std::istream& is) + template + GraphReader graphReader(TGR& graph, const std::string& fn) { + GraphReader tmp(graph, fn); + return tmp; + } + + /// \brief Return a \ref GraphReader class + /// + /// This function just returns a \ref GraphReader class. + /// \relates GraphReader + /// \sa graphReader(TGR& graph, std::istream& is) + template + GraphReader graphReader(TGR& graph, const char* fn) { + GraphReader tmp(graph, fn); + return tmp; + } + + template + class BpGraphReader; + + template + BpGraphReader bpGraphReader(TBGR& graph, std::istream& is = std::cin); + template + BpGraphReader bpGraphReader(TBGR& graph, const std::string& fn); + template + BpGraphReader bpGraphReader(TBGR& graph, const char *fn); + + /// \ingroup lemon_io + /// + /// \brief \ref lgf-format "LGF" reader for bipartite graphs + /// + /// This utility reads an \ref lgf-format "LGF" file. + /// + /// It can be used almost the same way as \c GraphReader, but it + /// reads the red and blue nodes from separate sections, and these + /// sections can contain different set of maps. + /// + /// The red and blue node maps are read from the corresponding + /// sections. If a map is defined with the same name in both of + /// these sections, then it can be read as a node map. + template + class BpGraphReader { + public: + + typedef BGR Graph; + + private: + + TEMPLATE_BPGRAPH_TYPEDEFS(BGR); + + std::istream* _is; + bool local_is; + std::string _filename; + + BGR& _graph; + + std::string _nodes_caption; + std::string _edges_caption; + std::string _attributes_caption; + + typedef std::map RedNodeIndex; + RedNodeIndex _red_node_index; + typedef std::map BlueNodeIndex; + BlueNodeIndex _blue_node_index; + typedef std::map EdgeIndex; + EdgeIndex _edge_index; + + typedef std::vector*> > RedNodeMaps; + RedNodeMaps _red_node_maps; + typedef std::vector*> > BlueNodeMaps; + BlueNodeMaps _blue_node_maps; + + typedef std::vector*> > EdgeMaps; + EdgeMaps _edge_maps; + + typedef std::multimap + Attributes; + Attributes _attributes; + + bool _use_nodes; + bool _use_edges; + + bool _skip_nodes; + bool _skip_edges; + + int line_num; + std::istringstream line; + + public: + + /// \brief Constructor + /// + /// Construct an undirected graph reader, which reads from the given + /// input stream. + BpGraphReader(BGR& graph, std::istream& is = std::cin) + : _is(&is), local_is(false), _graph(graph), + _use_nodes(false), _use_edges(false), + _skip_nodes(false), _skip_edges(false) {} + + /// \brief Constructor + /// + /// Construct an undirected graph reader, which reads from the given + /// file. + BpGraphReader(BGR& graph, const std::string& fn) + : _is(new std::ifstream(fn.c_str())), local_is(true), + _filename(fn), _graph(graph), + _use_nodes(false), _use_edges(false), + _skip_nodes(false), _skip_edges(false) { + if (!(*_is)) { + delete _is; + throw IoError("Cannot open file", fn); + } + } + + /// \brief Constructor + /// + /// Construct an undirected graph reader, which reads from the given + /// file. + BpGraphReader(BGR& graph, const char* fn) + : _is(new std::ifstream(fn)), local_is(true), + _filename(fn), _graph(graph), + _use_nodes(false), _use_edges(false), + _skip_nodes(false), _skip_edges(false) { + if (!(*_is)) { + delete _is; + throw IoError("Cannot open file", fn); + } + } + + /// \brief Destructor + ~BpGraphReader() { + for (typename RedNodeMaps::iterator it = _red_node_maps.begin(); + it != _red_node_maps.end(); ++it) { + delete it->second; + } + + for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin(); + it != _blue_node_maps.end(); ++it) { + delete it->second; + } + + for (typename EdgeMaps::iterator it = _edge_maps.begin(); + it != _edge_maps.end(); ++it) { + delete it->second; + } + + for (typename Attributes::iterator it = _attributes.begin(); + it != _attributes.end(); ++it) { + delete it->second; + } + + if (local_is) { + delete _is; + } + + } + + private: + template + friend BpGraphReader bpGraphReader(TBGR& graph, std::istream& is); + template + friend BpGraphReader bpGraphReader(TBGR& graph, + const std::string& fn); + template + friend BpGraphReader bpGraphReader(TBGR& graph, const char *fn); + + BpGraphReader(BpGraphReader& other) + : _is(other._is), local_is(other.local_is), _graph(other._graph), + _use_nodes(other._use_nodes), _use_edges(other._use_edges), + _skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) { + + other._is = 0; + other.local_is = false; + + _red_node_index.swap(other._red_node_index); + _blue_node_index.swap(other._blue_node_index); + _edge_index.swap(other._edge_index); + + _red_node_maps.swap(other._red_node_maps); + _blue_node_maps.swap(other._blue_node_maps); + _edge_maps.swap(other._edge_maps); + _attributes.swap(other._attributes); + + _nodes_caption = other._nodes_caption; + _edges_caption = other._edges_caption; + _attributes_caption = other._attributes_caption; + + } + + BpGraphReader& operator=(const BpGraphReader&); + + public: + + /// \name Reading Rules + /// @{ + + /// \brief Node map reading rule + /// + /// Add a node map reading rule to the reader. + template + BpGraphReader& nodeMap(const std::string& caption, Map& map) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* red_storage = + new _reader_bits::MapStorage(map); + _red_node_maps.push_back(std::make_pair(caption, red_storage)); + _reader_bits::MapStorageBase* blue_storage = + new _reader_bits::MapStorage(map); + _blue_node_maps.push_back(std::make_pair(caption, blue_storage)); + return *this; + } + + /// \brief Node map reading rule + /// + /// Add a node map reading rule with specialized converter to the + /// reader. + template + BpGraphReader& nodeMap(const std::string& caption, Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* red_storage = + new _reader_bits::MapStorage(map, converter); + _red_node_maps.push_back(std::make_pair(caption, red_storage)); + _reader_bits::MapStorageBase* blue_storage = + new _reader_bits::MapStorage(map, converter); + _blue_node_maps.push_back(std::make_pair(caption, blue_storage)); + return *this; + } + + /// Add a red node map reading rule to the reader. + template + BpGraphReader& redNodeMap(const std::string& caption, Map& map) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* storage = + new _reader_bits::MapStorage(map); + _red_node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Red node map reading rule + /// + /// Add a red node map node reading rule with specialized converter to + /// the reader. + template + BpGraphReader& redNodeMap(const std::string& caption, Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* storage = + new _reader_bits::MapStorage(map, converter); + _red_node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// Add a blue node map reading rule to the reader. + template + BpGraphReader& blueNodeMap(const std::string& caption, Map& map) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* storage = + new _reader_bits::MapStorage(map); + _blue_node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Blue node map reading rule + /// + /// Add a blue node map reading rule with specialized converter to + /// the reader. + template + BpGraphReader& blueNodeMap(const std::string& caption, Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* storage = + new _reader_bits::MapStorage(map, converter); + _blue_node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Edge map reading rule + /// + /// Add an edge map reading rule to the reader. + template + BpGraphReader& edgeMap(const std::string& caption, Map& map) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* storage = + new _reader_bits::MapStorage(map); + _edge_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Edge map reading rule + /// + /// Add an edge map reading rule with specialized converter to the + /// reader. + template + BpGraphReader& edgeMap(const std::string& caption, Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* storage = + new _reader_bits::MapStorage(map, converter); + _edge_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Arc map reading rule + /// + /// Add an arc map reading rule to the reader. + template + BpGraphReader& arcMap(const std::string& caption, Map& map) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* forward_storage = + new _reader_bits::GraphArcMapStorage(_graph, map); + _edge_maps.push_back(std::make_pair('+' + caption, forward_storage)); + _reader_bits::MapStorageBase* backward_storage = + new _reader_bits::GraphArcMapStorage(_graph, map); + _edge_maps.push_back(std::make_pair('-' + caption, backward_storage)); + return *this; + } + + /// \brief Arc map reading rule + /// + /// Add an arc map reading rule with specialized converter to the + /// reader. + template + BpGraphReader& arcMap(const std::string& caption, Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* forward_storage = + new _reader_bits::GraphArcMapStorage + (_graph, map, converter); + _edge_maps.push_back(std::make_pair('+' + caption, forward_storage)); + _reader_bits::MapStorageBase* backward_storage = + new _reader_bits::GraphArcMapStorage + (_graph, map, converter); + _edge_maps.push_back(std::make_pair('-' + caption, backward_storage)); + return *this; + } + + /// \brief Attribute reading rule + /// + /// Add an attribute reading rule to the reader. + template + BpGraphReader& attribute(const std::string& caption, Value& value) { + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(value); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Attribute reading rule + /// + /// Add an attribute reading rule with specialized converter to the + /// reader. + template + BpGraphReader& attribute(const std::string& caption, Value& value, + const Converter& converter = Converter()) { + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(value, converter); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Node reading rule + /// + /// Add a node reading rule to reader. + BpGraphReader& node(const std::string& caption, Node& node) { + typedef _reader_bits::DoubleMapLookUpConverter< + Node, RedNodeIndex, BlueNodeIndex> Converter; + Converter converter(_red_node_index, _blue_node_index); + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(node, converter); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Red node reading rule + /// + /// Add a red node reading rule to reader. + BpGraphReader& redNode(const std::string& caption, RedNode& node) { + typedef _reader_bits::MapLookUpConverter Converter; + Converter converter(_red_node_index); + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(node, converter); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Blue node reading rule + /// + /// Add a blue node reading rule to reader. + BpGraphReader& blueNode(const std::string& caption, BlueNode& node) { + typedef _reader_bits::MapLookUpConverter Converter; + Converter converter(_blue_node_index); + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(node, converter); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Edge reading rule + /// + /// Add an edge reading rule to reader. + BpGraphReader& edge(const std::string& caption, Edge& edge) { + typedef _reader_bits::MapLookUpConverter Converter; + Converter converter(_edge_index); + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(edge, converter); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Arc reading rule + /// + /// Add an arc reading rule to reader. + BpGraphReader& arc(const std::string& caption, Arc& arc) { + typedef _reader_bits::GraphArcLookUpConverter Converter; + Converter converter(_graph, _edge_index); + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(arc, converter); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// @} + + /// \name Select Section by Name + /// @{ + + /// \brief Set \c \@nodes section to be read + /// + /// Set \c \@nodes section to be read. + BpGraphReader& nodes(const std::string& caption) { + _nodes_caption = caption; + return *this; + } + + /// \brief Set \c \@edges section to be read + /// + /// Set \c \@edges section to be read. + BpGraphReader& edges(const std::string& caption) { + _edges_caption = caption; + return *this; + } + + /// \brief Set \c \@attributes section to be read + /// + /// Set \c \@attributes section to be read. + BpGraphReader& attributes(const std::string& caption) { + _attributes_caption = caption; + return *this; + } + + /// @} + + /// \name Using Previously Constructed Node or Edge Set + /// @{ + + /// \brief Use previously constructed node set + /// + /// Use previously constructed node set, and specify the node + /// label map. + template + BpGraphReader& useNodes(const Map& map) { + checkConcept, Map>(); + LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member"); + _use_nodes = true; + _writer_bits::DefaultConverter converter; + for (RedNodeIt n(_graph); n != INVALID; ++n) { + _red_node_index.insert(std::make_pair(converter(map[n]), n)); + } + for (BlueNodeIt n(_graph); n != INVALID; ++n) { + _blue_node_index.insert(std::make_pair(converter(map[n]), n)); + } + return *this; + } + + /// \brief Use previously constructed node set + /// + /// Use previously constructed node set, and specify the node + /// label map and a functor which converts the label map values to + /// \c std::string. + template + BpGraphReader& useNodes(const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member"); + _use_nodes = true; + for (RedNodeIt n(_graph); n != INVALID; ++n) { + _red_node_index.insert(std::make_pair(converter(map[n]), n)); + } + for (BlueNodeIt n(_graph); n != INVALID; ++n) { + _blue_node_index.insert(std::make_pair(converter(map[n]), n)); + } + return *this; + } + + /// \brief Use previously constructed edge set + /// + /// Use previously constructed edge set, and specify the edge + /// label map. + template + BpGraphReader& useEdges(const Map& map) { + checkConcept, Map>(); + LEMON_ASSERT(!_use_edges, "Multiple usage of useEdges() member"); + _use_edges = true; + _writer_bits::DefaultConverter converter; + for (EdgeIt a(_graph); a != INVALID; ++a) { + _edge_index.insert(std::make_pair(converter(map[a]), a)); + } + return *this; + } + + /// \brief Use previously constructed edge set + /// + /// Use previously constructed edge set, and specify the edge + /// label map and a functor which converts the label map values to + /// \c std::string. + template + BpGraphReader& useEdges(const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + LEMON_ASSERT(!_use_edges, "Multiple usage of useEdges() member"); + _use_edges = true; + for (EdgeIt a(_graph); a != INVALID; ++a) { + _edge_index.insert(std::make_pair(converter(map[a]), a)); + } + return *this; + } + + /// \brief Skip the reading of node section + /// + /// Omit the reading of the node section. This implies that each node + /// map reading rule will be abandoned, and the nodes of the graph + /// will not be constructed, which usually cause that the edge set + /// could not be read due to lack of node name + /// could not be read due to lack of node name resolving. + /// Therefore \c skipEdges() function should also be used, or + /// \c useNodes() should be used to specify the label of the nodes. + BpGraphReader& skipNodes() { + LEMON_ASSERT(!_skip_nodes, "Skip nodes already set"); + _skip_nodes = true; + return *this; + } + + /// \brief Skip the reading of edge section + /// + /// Omit the reading of the edge section. This implies that each edge + /// map reading rule will be abandoned, and the edges of the graph + /// will not be constructed. + BpGraphReader& skipEdges() { + LEMON_ASSERT(!_skip_edges, "Skip edges already set"); + _skip_edges = true; + return *this; + } + + /// @} + + private: + + bool readLine() { + std::string str; + while(++line_num, std::getline(*_is, str)) { + line.clear(); line.str(str); + char c; + if (line >> std::ws >> c && c != '#') { + line.putback(c); + return true; + } + } + return false; + } + + bool readSuccess() { + return static_cast(*_is); + } + + void skipSection() { + char c; + while (readSuccess() && line >> c && c != '@') { + readLine(); + } + if (readSuccess()) { + line.putback(c); + } + } + + void readRedNodes() { + + std::vector map_index(_red_node_maps.size()); + int map_num, label_index; + + char c; + if (!readLine() || !(line >> c) || c == '@') { + if (readSuccess() && line) line.putback(c); + if (!_red_node_maps.empty()) + throw FormatError("Cannot find map names"); + return; + } + line.putback(c); + + { + std::map maps; + + std::string map; + int index = 0; + while (_reader_bits::readToken(line, map)) { + if (maps.find(map) != maps.end()) { + std::ostringstream msg; + msg << "Multiple occurence of red node map: " << map; + throw FormatError(msg.str()); + } + maps.insert(std::make_pair(map, index)); + ++index; + } + + for (int i = 0; i < static_cast(_red_node_maps.size()); ++i) { + std::map::iterator jt = + maps.find(_red_node_maps[i].first); + if (jt == maps.end()) { + std::ostringstream msg; + msg << "Map not found: " << _red_node_maps[i].first; + throw FormatError(msg.str()); + } + map_index[i] = jt->second; + } + + { + std::map::iterator jt = maps.find("label"); + if (jt != maps.end()) { + label_index = jt->second; + } else { + label_index = -1; + } + } + map_num = maps.size(); + } + + while (readLine() && line >> c && c != '@') { + line.putback(c); + + std::vector tokens(map_num); + for (int i = 0; i < map_num; ++i) { + if (!_reader_bits::readToken(line, tokens[i])) { + std::ostringstream msg; + msg << "Column not found (" << i + 1 << ")"; + throw FormatError(msg.str()); + } + } + if (line >> std::ws >> c) + throw FormatError("Extra character at the end of line"); + + RedNode n; + if (!_use_nodes) { + n = _graph.addRedNode(); + if (label_index != -1) + _red_node_index.insert(std::make_pair(tokens[label_index], n)); + } else { + if (label_index == -1) + throw FormatError("Label map not found"); + typename std::map::iterator it = + _red_node_index.find(tokens[label_index]); + if (it == _red_node_index.end()) { + std::ostringstream msg; + msg << "Node with label not found: " << tokens[label_index]; + throw FormatError(msg.str()); + } + n = it->second; + } + + for (int i = 0; i < static_cast(_red_node_maps.size()); ++i) { + _red_node_maps[i].second->set(n, tokens[map_index[i]]); + } + + } + if (readSuccess()) { + line.putback(c); + } + } + + void readBlueNodes() { + + std::vector map_index(_blue_node_maps.size()); + int map_num, label_index; + + char c; + if (!readLine() || !(line >> c) || c == '@') { + if (readSuccess() && line) line.putback(c); + if (!_blue_node_maps.empty()) + throw FormatError("Cannot find map names"); + return; + } + line.putback(c); + + { + std::map maps; + + std::string map; + int index = 0; + while (_reader_bits::readToken(line, map)) { + if (maps.find(map) != maps.end()) { + std::ostringstream msg; + msg << "Multiple occurence of blue node map: " << map; + throw FormatError(msg.str()); + } + maps.insert(std::make_pair(map, index)); + ++index; + } + + for (int i = 0; i < static_cast(_blue_node_maps.size()); ++i) { + std::map::iterator jt = + maps.find(_blue_node_maps[i].first); + if (jt == maps.end()) { + std::ostringstream msg; + msg << "Map not found: " << _blue_node_maps[i].first; + throw FormatError(msg.str()); + } + map_index[i] = jt->second; + } + + { + std::map::iterator jt = maps.find("label"); + if (jt != maps.end()) { + label_index = jt->second; + } else { + label_index = -1; + } + } + map_num = maps.size(); + } + + while (readLine() && line >> c && c != '@') { + line.putback(c); + + std::vector tokens(map_num); + for (int i = 0; i < map_num; ++i) { + if (!_reader_bits::readToken(line, tokens[i])) { + std::ostringstream msg; + msg << "Column not found (" << i + 1 << ")"; + throw FormatError(msg.str()); + } + } + if (line >> std::ws >> c) + throw FormatError("Extra character at the end of line"); + + BlueNode n; + if (!_use_nodes) { + n = _graph.addBlueNode(); + if (label_index != -1) + _blue_node_index.insert(std::make_pair(tokens[label_index], n)); + } else { + if (label_index == -1) + throw FormatError("Label map not found"); + typename std::map::iterator it = + _blue_node_index.find(tokens[label_index]); + if (it == _blue_node_index.end()) { + std::ostringstream msg; + msg << "Node with label not found: " << tokens[label_index]; + throw FormatError(msg.str()); + } + n = it->second; + } + + for (int i = 0; i < static_cast(_blue_node_maps.size()); ++i) { + _blue_node_maps[i].second->set(n, tokens[map_index[i]]); + } + + } + if (readSuccess()) { + line.putback(c); + } + } + + void readEdges() { + + std::vector map_index(_edge_maps.size()); + int map_num, label_index; + + char c; + if (!readLine() || !(line >> c) || c == '@') { + if (readSuccess() && line) line.putback(c); + if (!_edge_maps.empty()) + throw FormatError("Cannot find map names"); + return; + } + line.putback(c); + + { + std::map maps; + + std::string map; + int index = 0; + while (_reader_bits::readToken(line, map)) { + if (maps.find(map) != maps.end()) { + std::ostringstream msg; + msg << "Multiple occurence of edge map: " << map; + throw FormatError(msg.str()); + } + maps.insert(std::make_pair(map, index)); + ++index; + } + + for (int i = 0; i < static_cast(_edge_maps.size()); ++i) { + std::map::iterator jt = + maps.find(_edge_maps[i].first); + if (jt == maps.end()) { + std::ostringstream msg; + msg << "Map not found: " << _edge_maps[i].first; + throw FormatError(msg.str()); + } + map_index[i] = jt->second; + } + + { + std::map::iterator jt = maps.find("label"); + if (jt != maps.end()) { + label_index = jt->second; + } else { + label_index = -1; + } + } + map_num = maps.size(); + } + + while (readLine() && line >> c && c != '@') { + line.putback(c); + + std::string source_token; + std::string target_token; + + if (!_reader_bits::readToken(line, source_token)) + throw FormatError("Red node not found"); + + if (!_reader_bits::readToken(line, target_token)) + throw FormatError("Blue node not found"); + + std::vector tokens(map_num); + for (int i = 0; i < map_num; ++i) { + if (!_reader_bits::readToken(line, tokens[i])) { + std::ostringstream msg; + msg << "Column not found (" << i + 1 << ")"; + throw FormatError(msg.str()); + } + } + if (line >> std::ws >> c) + throw FormatError("Extra character at the end of line"); + + Edge e; + if (!_use_edges) { + typename RedNodeIndex::iterator rit = + _red_node_index.find(source_token); + if (rit == _red_node_index.end()) { + std::ostringstream msg; + msg << "Item not found: " << source_token; + throw FormatError(msg.str()); + } + RedNode source = rit->second; + typename BlueNodeIndex::iterator it = + _blue_node_index.find(target_token); + if (it == _blue_node_index.end()) { + std::ostringstream msg; + msg << "Item not found: " << target_token; + throw FormatError(msg.str()); + } + BlueNode target = it->second; + + // It is checked that source is red and + // target is blue, so this should be safe: + e = _graph.addEdge(source, target); + if (label_index != -1) + _edge_index.insert(std::make_pair(tokens[label_index], e)); + } else { + if (label_index == -1) + throw FormatError("Label map not found"); + typename std::map::iterator it = + _edge_index.find(tokens[label_index]); + if (it == _edge_index.end()) { + std::ostringstream msg; + msg << "Edge with label not found: " << tokens[label_index]; + throw FormatError(msg.str()); + } + e = it->second; + } + + for (int i = 0; i < static_cast(_edge_maps.size()); ++i) { + _edge_maps[i].second->set(e, tokens[map_index[i]]); + } + + } + if (readSuccess()) { + line.putback(c); + } + } + + void readAttributes() { + + std::set read_attr; + + char c; + while (readLine() && line >> c && c != '@') { + line.putback(c); + + std::string attr, token; + if (!_reader_bits::readToken(line, attr)) + throw FormatError("Attribute name not found"); + if (!_reader_bits::readToken(line, token)) + throw FormatError("Attribute value not found"); + if (line >> c) + throw FormatError("Extra character at the end of line"); + + { + std::set::iterator it = read_attr.find(attr); + if (it != read_attr.end()) { + std::ostringstream msg; + msg << "Multiple occurence of attribute: " << attr; + throw FormatError(msg.str()); + } + read_attr.insert(attr); + } + + { + typename Attributes::iterator it = _attributes.lower_bound(attr); + while (it != _attributes.end() && it->first == attr) { + it->second->set(token); + ++it; + } + } + + } + if (readSuccess()) { + line.putback(c); + } + for (typename Attributes::iterator it = _attributes.begin(); + it != _attributes.end(); ++it) { + if (read_attr.find(it->first) == read_attr.end()) { + std::ostringstream msg; + msg << "Attribute not found: " << it->first; + throw FormatError(msg.str()); + } + } + } + + public: + + /// \name Execution of the Reader + /// @{ + + /// \brief Start the batch processing + /// + /// This function starts the batch processing + void run() { + + LEMON_ASSERT(_is != 0, "This reader assigned to an other reader"); + + bool red_nodes_done = _skip_nodes; + bool blue_nodes_done = _skip_nodes; + bool edges_done = _skip_edges; + bool attributes_done = false; + + line_num = 0; + readLine(); + skipSection(); + + while (readSuccess()) { + try { + char c; + std::string section, caption; + line >> c; + _reader_bits::readToken(line, section); + _reader_bits::readToken(line, caption); + + if (line >> c) + throw FormatError("Extra character at the end of line"); + + if (section == "red_nodes" && !red_nodes_done) { + if (_nodes_caption.empty() || _nodes_caption == caption) { + readRedNodes(); + red_nodes_done = true; + } + } else if (section == "blue_nodes" && !blue_nodes_done) { + if (_nodes_caption.empty() || _nodes_caption == caption) { + readBlueNodes(); + blue_nodes_done = true; + } + } else if ((section == "edges" || section == "arcs") && + !edges_done) { + if (_edges_caption.empty() || _edges_caption == caption) { + readEdges(); + edges_done = true; + } + } else if (section == "attributes" && !attributes_done) { + if (_attributes_caption.empty() || _attributes_caption == caption) { + readAttributes(); + attributes_done = true; + } + } else { + readLine(); + skipSection(); + } + } catch (FormatError& error) { + error.line(line_num); + error.file(_filename); + throw; + } + } + + if (!red_nodes_done) { + throw FormatError("Section @red_nodes not found"); + } + + if (!blue_nodes_done) { + throw FormatError("Section @blue_nodes not found"); + } + + if (!edges_done) { + throw FormatError("Section @edges not found"); + } + + if (!attributes_done && !_attributes.empty()) { + throw FormatError("Section @attributes not found"); + } + + } + + /// @} + + }; + + /// \ingroup lemon_io + /// + /// \brief Return a \ref lemon::BpGraphReader "BpGraphReader" class + /// + /// This function just returns a \ref lemon::BpGraphReader + /// "BpGraphReader" class. + /// + /// With this function a graph can be read from an + /// \ref lgf-format "LGF" file or input stream with several maps and + /// attributes. For example, there is bipartite weighted matching problem + /// on a graph, i.e. a graph with a \e weight map on the edges. This + /// graph can be read with the following code: + /// + ///\code + ///ListBpGraph graph; + ///ListBpGraph::EdgeMap weight(graph); + ///bpGraphReader(graph, std::cin). + /// edgeMap("weight", weight). + /// run(); + ///\endcode + /// + /// For a complete documentation, please see the + /// \ref lemon::BpGraphReader "BpGraphReader" + /// class documentation. + /// \warning Don't forget to put the \ref lemon::BpGraphReader::run() "run()" + /// to the end of the parameter list. + /// \relates BpGraphReader + /// \sa bpGraphReader(TBGR& graph, const std::string& fn) + /// \sa bpGraphReader(TBGR& graph, const char* fn) + template + BpGraphReader bpGraphReader(TBGR& graph, std::istream& is) { + BpGraphReader tmp(graph, is); + return tmp; + } + + /// \brief Return a \ref BpGraphReader class + /// + /// This function just returns a \ref BpGraphReader class. + /// \relates BpGraphReader + /// \sa bpGraphReader(TBGR& graph, std::istream& is) + template + BpGraphReader bpGraphReader(TBGR& graph, const std::string& fn) { + BpGraphReader tmp(graph, fn); + return tmp; + } + + /// \brief Return a \ref BpGraphReader class + /// + /// This function just returns a \ref BpGraphReader class. + /// \relates BpGraphReader + /// \sa bpGraphReader(TBGR& graph, std::istream& is) + template + BpGraphReader bpGraphReader(TBGR& graph, const char* fn) { + BpGraphReader tmp(graph, fn); + return tmp; + } + + class SectionReader; + + SectionReader sectionReader(std::istream& is); + SectionReader sectionReader(const std::string& fn); + SectionReader sectionReader(const char* fn); + + /// \ingroup lemon_io + /// + /// \brief Section reader class + /// + /// In the \ref lgf-format "LGF" file extra sections can be placed, + /// which contain any data in arbitrary format. Such sections can be + /// read with this class. A reading rule can be added to the class + /// with two different functions. With the \c sectionLines() function a + /// functor can process the section line-by-line, while with the \c + /// sectionStream() member the section can be read from an input + /// stream. + class SectionReader { + private: + + std::istream* _is; + bool local_is; + std::string _filename; + + typedef std::map Sections; + Sections _sections; + + int line_num; + std::istringstream line; + + public: + + /// \brief Constructor + /// + /// Construct a section reader, which reads from the given input + /// stream. + SectionReader(std::istream& is) + : _is(&is), local_is(false) {} + + /// \brief Constructor + /// + /// Construct a section reader, which reads from the given file. + SectionReader(const std::string& fn) + : _is(new std::ifstream(fn.c_str())), local_is(true), + _filename(fn) { + if (!(*_is)) { + delete _is; + throw IoError("Cannot open file", fn); + } + } + + /// \brief Constructor + /// + /// Construct a section reader, which reads from the given file. + SectionReader(const char* fn) + : _is(new std::ifstream(fn)), local_is(true), + _filename(fn) { + if (!(*_is)) { + delete _is; + throw IoError("Cannot open file", fn); + } + } + + /// \brief Destructor + ~SectionReader() { + for (Sections::iterator it = _sections.begin(); + it != _sections.end(); ++it) { + delete it->second; + } + + if (local_is) { + delete _is; + } + + } + + private: + + friend SectionReader sectionReader(std::istream& is); + friend SectionReader sectionReader(const std::string& fn); + friend SectionReader sectionReader(const char* fn); + + SectionReader(SectionReader& other) + : _is(other._is), local_is(other.local_is) { + + other._is = 0; + other.local_is = false; + + _sections.swap(other._sections); + } + + SectionReader& operator=(const SectionReader&); + + public: + + /// \name Section Readers + /// @{ + + /// \brief Add a section processor with line oriented reading + /// + /// The first parameter is the type descriptor of the section, the + /// second is a functor, which takes just one \c std::string + /// parameter. At the reading process, each line of the section + /// will be given to the functor object. However, the empty lines + /// and the comment lines are filtered out, and the leading + /// whitespaces are trimmed from each processed string. + /// + /// For example, let's see a section, which contain several + /// integers, which should be inserted into a vector. + ///\code + /// @numbers + /// 12 45 23 + /// 4 + /// 23 6 + ///\endcode + /// + /// The functor is implemented as a struct: + ///\code + /// struct NumberSection { + /// std::vector& _data; + /// NumberSection(std::vector& data) : _data(data) {} + /// void operator()(const std::string& line) { + /// std::istringstream ls(line); + /// int value; + /// while (ls >> value) _data.push_back(value); + /// } + /// }; + /// + /// // ... + /// + /// reader.sectionLines("numbers", NumberSection(vec)); + ///\endcode + template + SectionReader& sectionLines(const std::string& type, Functor functor) { + LEMON_ASSERT(!type.empty(), "Type is empty."); + LEMON_ASSERT(_sections.find(type) == _sections.end(), + "Multiple reading of section."); + _sections.insert(std::make_pair(type, + new _reader_bits::LineSection(functor))); + return *this; + } + + + /// \brief Add a section processor with stream oriented reading + /// + /// The first parameter is the type of the section, the second is + /// a functor, which takes an \c std::istream& and an \c int& + /// parameter, the latter regard to the line number of stream. The + /// functor can read the input while the section go on, and the + /// line number should be modified accordingly. + template + SectionReader& sectionStream(const std::string& type, Functor functor) { + LEMON_ASSERT(!type.empty(), "Type is empty."); + LEMON_ASSERT(_sections.find(type) == _sections.end(), + "Multiple reading of section."); + _sections.insert(std::make_pair(type, + new _reader_bits::StreamSection(functor))); + return *this; + } + + /// @} + + private: + + bool readLine() { + std::string str; + while(++line_num, std::getline(*_is, str)) { + line.clear(); line.str(str); + char c; + if (line >> std::ws >> c && c != '#') { + line.putback(c); + return true; + } + } + return false; + } + + bool readSuccess() { + return static_cast(*_is); + } + + void skipSection() { + char c; + while (readSuccess() && line >> c && c != '@') { + readLine(); + } + if (readSuccess()) { + line.putback(c); + } + } + + public: + + + /// \name Execution of the Reader + /// @{ + + /// \brief Start the batch processing + /// + /// This function starts the batch processing. + void run() { + + LEMON_ASSERT(_is != 0, "This reader assigned to an other reader"); + + std::set extra_sections; + + line_num = 0; + readLine(); + skipSection(); + + while (readSuccess()) { + try { + char c; + std::string section, caption; + line >> c; + _reader_bits::readToken(line, section); + _reader_bits::readToken(line, caption); + + if (line >> c) + throw FormatError("Extra character at the end of line"); + + if (extra_sections.find(section) != extra_sections.end()) { + std::ostringstream msg; + msg << "Multiple occurence of section: " << section; + throw FormatError(msg.str()); + } + Sections::iterator it = _sections.find(section); + if (it != _sections.end()) { + extra_sections.insert(section); + it->second->process(*_is, line_num); + } + readLine(); + skipSection(); + } catch (FormatError& error) { + error.line(line_num); + error.file(_filename); + throw; + } + } + for (Sections::iterator it = _sections.begin(); + it != _sections.end(); ++it) { + if (extra_sections.find(it->first) == extra_sections.end()) { + std::ostringstream os; + os << "Cannot find section: " << it->first; + throw FormatError(os.str()); + } + } + } + + /// @} + + }; + + /// \ingroup lemon_io + /// + /// \brief Return a \ref SectionReader class + /// + /// This function just returns a \ref SectionReader class. + /// + /// Please see SectionReader documentation about the custom section + /// input. + /// + /// \relates SectionReader + /// \sa sectionReader(const std::string& fn) + /// \sa sectionReader(const char *fn) + inline SectionReader sectionReader(std::istream& is) { + SectionReader tmp(is); + return tmp; + } + + /// \brief Return a \ref SectionReader class + /// + /// This function just returns a \ref SectionReader class. + /// \relates SectionReader + /// \sa sectionReader(std::istream& is) + inline SectionReader sectionReader(const std::string& fn) { + SectionReader tmp(fn); + return tmp; + } + + /// \brief Return a \ref SectionReader class + /// + /// This function just returns a \ref SectionReader class. + /// \relates SectionReader + /// \sa sectionReader(std::istream& is) + inline SectionReader sectionReader(const char* fn) { + SectionReader tmp(fn); + return tmp; + } + + /// \ingroup lemon_io + /// + /// \brief Reader for the contents of the \ref lgf-format "LGF" file + /// + /// This class can be used to read the sections, the map names and + /// the attributes from a file. Usually, the LEMON programs know + /// that, which type of graph, which maps and which attributes + /// should be read from a file, but in general tools (like glemon) + /// the contents of an LGF file should be guessed somehow. This class + /// reads the graph and stores the appropriate information for + /// reading the graph. + /// + ///\code + /// LgfContents contents("graph.lgf"); + /// contents.run(); + /// + /// // Does it contain any node section and arc section? + /// if (contents.nodeSectionNum() == 0 || contents.arcSectionNum()) { + /// std::cerr << "Failure, cannot find graph." << std::endl; + /// return -1; + /// } + /// std::cout << "The name of the default node section: " + /// << contents.nodeSection(0) << std::endl; + /// std::cout << "The number of the arc maps: " + /// << contents.arcMaps(0).size() << std::endl; + /// std::cout << "The name of second arc map: " + /// << contents.arcMaps(0)[1] << std::endl; + ///\endcode + class LgfContents { + private: + + std::istream* _is; + bool local_is; + + std::vector _node_sections; + std::vector _edge_sections; + std::vector _attribute_sections; + std::vector _extra_sections; + + std::vector _arc_sections; + + std::vector > _node_maps; + std::vector > _edge_maps; + + std::vector > _attributes; + + + int line_num; + std::istringstream line; + + public: + + /// \brief Constructor + /// + /// Construct an \e LGF contents reader, which reads from the given + /// input stream. + LgfContents(std::istream& is) + : _is(&is), local_is(false) {} + + /// \brief Constructor + /// + /// Construct an \e LGF contents reader, which reads from the given + /// file. + LgfContents(const std::string& fn) + : _is(new std::ifstream(fn.c_str())), local_is(true) { + if (!(*_is)) { + delete _is; + throw IoError("Cannot open file", fn); + } + } + + /// \brief Constructor + /// + /// Construct an \e LGF contents reader, which reads from the given + /// file. + LgfContents(const char* fn) + : _is(new std::ifstream(fn)), local_is(true) { + if (!(*_is)) { + delete _is; + throw IoError("Cannot open file", fn); + } + } + + /// \brief Destructor + ~LgfContents() { + if (local_is) delete _is; + } + + private: + + LgfContents(const LgfContents&); + LgfContents& operator=(const LgfContents&); + + public: + + + /// \name Node Sections + /// @{ + + /// \brief Gives back the number of node sections in the file. + /// + /// Gives back the number of node sections in the file. + int nodeSectionNum() const { + return _node_sections.size(); + } + + /// \brief Returns the node section name at the given position. + /// + /// Returns the node section name at the given position. + const std::string& nodeSection(int i) const { + return _node_sections[i]; + } + + /// \brief Gives back the node maps for the given section. + /// + /// Gives back the node maps for the given section. + const std::vector& nodeMapNames(int i) const { + return _node_maps[i]; + } + + /// @} + + /// \name Arc/Edge Sections + /// @{ + + /// \brief Gives back the number of arc/edge sections in the file. + /// + /// Gives back the number of arc/edge sections in the file. + /// \note It is synonym of \c edgeSectionNum(). + int arcSectionNum() const { + return _edge_sections.size(); + } + + /// \brief Returns the arc/edge section name at the given position. + /// + /// Returns the arc/edge section name at the given position. + /// \note It is synonym of \c edgeSection(). + const std::string& arcSection(int i) const { + return _edge_sections[i]; + } + + /// \brief Gives back the arc/edge maps for the given section. + /// + /// Gives back the arc/edge maps for the given section. + /// \note It is synonym of \c edgeMapNames(). + const std::vector& arcMapNames(int i) const { + return _edge_maps[i]; + } + + /// @} + + /// \name Synonyms + /// @{ + + /// \brief Gives back the number of arc/edge sections in the file. + /// + /// Gives back the number of arc/edge sections in the file. + /// \note It is synonym of \c arcSectionNum(). + int edgeSectionNum() const { + return _edge_sections.size(); + } + + /// \brief Returns the section name at the given position. + /// + /// Returns the section name at the given position. + /// \note It is synonym of \c arcSection(). + const std::string& edgeSection(int i) const { + return _edge_sections[i]; + } + + /// \brief Gives back the edge maps for the given section. + /// + /// Gives back the edge maps for the given section. + /// \note It is synonym of \c arcMapNames(). + const std::vector& edgeMapNames(int i) const { + return _edge_maps[i]; + } + + /// @} + + /// \name Attribute Sections + /// @{ + + /// \brief Gives back the number of attribute sections in the file. + /// + /// Gives back the number of attribute sections in the file. + int attributeSectionNum() const { + return _attribute_sections.size(); + } + + /// \brief Returns the attribute section name at the given position. + /// + /// Returns the attribute section name at the given position. + const std::string& attributeSectionNames(int i) const { + return _attribute_sections[i]; + } + + /// \brief Gives back the attributes for the given section. + /// + /// Gives back the attributes for the given section. + const std::vector& attributes(int i) const { + return _attributes[i]; + } + + /// @} + + /// \name Extra Sections + /// @{ + + /// \brief Gives back the number of extra sections in the file. + /// + /// Gives back the number of extra sections in the file. + int extraSectionNum() const { + return _extra_sections.size(); + } + + /// \brief Returns the extra section type at the given position. + /// + /// Returns the section type at the given position. + const std::string& extraSection(int i) const { + return _extra_sections[i]; + } + + /// @} + + private: + + bool readLine() { + std::string str; + while(++line_num, std::getline(*_is, str)) { + line.clear(); line.str(str); + char c; + if (line >> std::ws >> c && c != '#') { + line.putback(c); + return true; + } + } + return false; + } + + bool readSuccess() { + return static_cast(*_is); + } + + void skipSection() { + char c; + while (readSuccess() && line >> c && c != '@') { + readLine(); + } + if (readSuccess()) { + line.putback(c); + } + } + + void readMaps(std::vector& maps) { + char c; + if (!readLine() || !(line >> c) || c == '@') { + if (readSuccess() && line) line.putback(c); + return; + } + line.putback(c); + std::string map; + while (_reader_bits::readToken(line, map)) { + maps.push_back(map); + } + } + + void readAttributes(std::vector& attrs) { + readLine(); + char c; + while (readSuccess() && line >> c && c != '@') { + line.putback(c); + std::string attr; + _reader_bits::readToken(line, attr); + attrs.push_back(attr); + readLine(); + } + line.putback(c); + } + + public: + + /// \name Execution of the Contents Reader + /// @{ + + /// \brief Starts the reading + /// + /// This function starts the reading. + void run() { + + readLine(); + skipSection(); + + while (readSuccess()) { + + char c; + line >> c; + + std::string section, caption; + _reader_bits::readToken(line, section); + _reader_bits::readToken(line, caption); + + if (section == "nodes") { + _node_sections.push_back(caption); + _node_maps.push_back(std::vector()); + readMaps(_node_maps.back()); + readLine(); skipSection(); + } else if (section == "arcs" || section == "edges") { + _edge_sections.push_back(caption); + _arc_sections.push_back(section == "arcs"); + _edge_maps.push_back(std::vector()); + readMaps(_edge_maps.back()); + readLine(); skipSection(); + } else if (section == "attributes") { + _attribute_sections.push_back(caption); + _attributes.push_back(std::vector()); + readAttributes(_attributes.back()); + } else { + _extra_sections.push_back(section); + readLine(); skipSection(); + } + } + } + + /// @} + + }; +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/lgf_writer.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lgf_writer.h new file mode 100644 index 00000000000..0695287d518 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lgf_writer.h @@ -0,0 +1,2687 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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. + * + */ + +///\ingroup lemon_io +///\file +///\brief \ref lgf-format "LEMON Graph Format" writer. + + +#ifndef LEMON_LGF_WRITER_H +#define LEMON_LGF_WRITER_H + +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#include +#include + +namespace lemon { + + namespace _writer_bits { + + template + struct DefaultConverter { + std::string operator()(const Value& value) { + std::ostringstream os; + os << value; + return os.str(); + } + }; + + template + bool operator<(const T&, const T&) { + throw FormatError("Label map is not comparable"); + } + + template + class MapLess { + public: + typedef _Map Map; + typedef typename Map::Key Item; + + private: + const Map& _map; + + public: + MapLess(const Map& map) : _map(map) {} + + bool operator()(const Item& left, const Item& right) { + return _map[left] < _map[right]; + } + }; + + template + class GraphArcMapLess { + public: + typedef _Map Map; + typedef _Graph Graph; + typedef typename Graph::Edge Item; + + private: + const Graph& _graph; + const Map& _map; + + public: + GraphArcMapLess(const Graph& graph, const Map& map) + : _graph(graph), _map(map) {} + + bool operator()(const Item& left, const Item& right) { + return _map[_graph.direct(left, _dir)] < + _map[_graph.direct(right, _dir)]; + } + }; + + template + class MapStorageBase { + public: + typedef _Item Item; + + public: + MapStorageBase() {} + virtual ~MapStorageBase() {} + + virtual std::string get(const Item& item) = 0; + virtual void sort(std::vector&) = 0; + }; + + template > + class MapStorage : public MapStorageBase<_Item> { + public: + typedef _Map Map; + typedef _Converter Converter; + typedef _Item Item; + + private: + const Map& _map; + Converter _converter; + + public: + MapStorage(const Map& map, const Converter& converter = Converter()) + : _map(map), _converter(converter) {} + virtual ~MapStorage() {} + + virtual std::string get(const Item& item) { + return _converter(_map[item]); + } + virtual void sort(std::vector& items) { + MapLess less(_map); + std::sort(items.begin(), items.end(), less); + } + }; + + template > + class GraphArcMapStorage : public MapStorageBase { + public: + typedef _Map Map; + typedef _Converter Converter; + typedef _Graph Graph; + typedef typename Graph::Edge Item; + static const bool dir = _dir; + + private: + const Graph& _graph; + const Map& _map; + Converter _converter; + + public: + GraphArcMapStorage(const Graph& graph, const Map& map, + const Converter& converter = Converter()) + : _graph(graph), _map(map), _converter(converter) {} + virtual ~GraphArcMapStorage() {} + + virtual std::string get(const Item& item) { + return _converter(_map[_graph.direct(item, dir)]); + } + virtual void sort(std::vector& items) { + GraphArcMapLess less(_graph, _map); + std::sort(items.begin(), items.end(), less); + } + }; + + class ValueStorageBase { + public: + ValueStorageBase() {} + virtual ~ValueStorageBase() {} + + virtual std::string get() = 0; + }; + + template > + class ValueStorage : public ValueStorageBase { + public: + typedef _Value Value; + typedef _Converter Converter; + + private: + const Value& _value; + Converter _converter; + + public: + ValueStorage(const Value& value, const Converter& converter = Converter()) + : _value(value), _converter(converter) {} + + virtual std::string get() { + return _converter(_value); + } + }; + + template > + struct MapLookUpConverter { + const Map& _map; + + MapLookUpConverter(const Map& map) + : _map(map) {} + + std::string operator()(const Value& value) { + typename Map::const_iterator it = _map.find(value); + if (it == _map.end()) { + throw FormatError("Item not found"); + } + return it->second; + } + }; + + template , + typename Map2 = std::map > + struct DoubleMapLookUpConverter { + const Map1& _map1; + const Map2& _map2; + + DoubleMapLookUpConverter(const Map1& map1, const Map2& map2) + : _map1(map1), _map2(map2) {} + + std::string operator()(const Value& value) { + typename Map1::const_iterator it1 = _map1.find(value); + typename Map1::const_iterator it2 = _map2.find(value); + if (it1 == _map1.end()) { + if (it2 == _map2.end()) { + throw FormatError("Item not found"); + } else { + return it2->second; + } + } else { + if (it2 == _map2.end()) { + return it1->second; + } else { + throw FormatError("Item is ambigous"); + } + } + } + }; + + template + struct GraphArcLookUpConverter { + const Graph& _graph; + const std::map& _map; + + GraphArcLookUpConverter(const Graph& graph, + const std::map& map) + : _graph(graph), _map(map) {} + + std::string operator()(const typename Graph::Arc& val) { + typename std::map + ::const_iterator it = _map.find(val); + if (it == _map.end()) { + throw FormatError("Item not found"); + } + return (_graph.direction(val) ? '+' : '-') + it->second; + } + }; + + inline bool isWhiteSpace(char c) { + return c == ' ' || c == '\t' || c == '\v' || + c == '\n' || c == '\r' || c == '\f'; + } + + inline bool isEscaped(char c) { + return c == '\\' || c == '\"' || c == '\'' || + c == '\a' || c == '\b'; + } + + inline static void writeEscape(std::ostream& os, char c) { + switch (c) { + case '\\': + os << "\\\\"; + return; + case '\"': + os << "\\\""; + return; + case '\a': + os << "\\a"; + return; + case '\b': + os << "\\b"; + return; + case '\f': + os << "\\f"; + return; + case '\r': + os << "\\r"; + return; + case '\n': + os << "\\n"; + return; + case '\t': + os << "\\t"; + return; + case '\v': + os << "\\v"; + return; + default: + if (c < 0x20) { + std::ios::fmtflags flags = os.flags(); + os << '\\' << std::oct << static_cast(c); + os.flags(flags); + } else { + os << c; + } + return; + } + } + + inline bool requireEscape(const std::string& str) { + if (str.empty() || str[0] == '@') return true; + std::istringstream is(str); + char c; + while (is.get(c)) { + if (isWhiteSpace(c) || isEscaped(c)) { + return true; + } + } + return false; + } + + inline std::ostream& writeToken(std::ostream& os, const std::string& str) { + + if (requireEscape(str)) { + os << '\"'; + for (std::string::const_iterator it = str.begin(); + it != str.end(); ++it) { + writeEscape(os, *it); + } + os << '\"'; + } else { + os << str; + } + return os; + } + + class Section { + public: + virtual ~Section() {} + virtual void process(std::ostream& os) = 0; + }; + + template + class LineSection : public Section { + private: + + Functor _functor; + + public: + + LineSection(const Functor& functor) : _functor(functor) {} + virtual ~LineSection() {} + + virtual void process(std::ostream& os) { + std::string line; + while (!(line = _functor()).empty()) os << line << std::endl; + } + }; + + template + class StreamSection : public Section { + private: + + Functor _functor; + + public: + + StreamSection(const Functor& functor) : _functor(functor) {} + virtual ~StreamSection() {} + + virtual void process(std::ostream& os) { + _functor(os); + } + }; + + } + + template + class DigraphWriter; + + template + DigraphWriter digraphWriter(const TDGR& digraph, + std::ostream& os = std::cout); + template + DigraphWriter digraphWriter(const TDGR& digraph, const std::string& fn); + + template + DigraphWriter digraphWriter(const TDGR& digraph, const char* fn); + + + /// \ingroup lemon_io + /// + /// \brief \ref lgf-format "LGF" writer for directed graphs + /// + /// This utility writes an \ref lgf-format "LGF" file. + /// + /// The writing method does a batch processing. The user creates a + /// writer object, then various writing rules can be added to the + /// writer, and eventually the writing is executed with the \c run() + /// member function. A map writing rule can be added to the writer + /// with the \c nodeMap() or \c arcMap() members. An optional + /// converter parameter can also be added as a standard functor + /// converting from the value type of the map to \c std::string. If it + /// is set, it will determine how the value type of the map is written to + /// the output stream. If the functor is not set, then a default + /// conversion will be used. The \c attribute(), \c node() and \c + /// arc() functions are used to add attribute writing rules. + /// + ///\code + /// DigraphWriter(digraph, std::cout). + /// nodeMap("coordinates", coord_map). + /// nodeMap("size", size). + /// nodeMap("title", title). + /// arcMap("capacity", cap_map). + /// node("source", src). + /// node("target", trg). + /// attribute("caption", caption). + /// run(); + ///\endcode + /// + /// + /// By default, the writer does not write additional captions to the + /// sections, but they can be give as an optional parameter of + /// the \c nodes(), \c arcs() or \c + /// attributes() functions. + /// + /// The \c skipNodes() and \c skipArcs() functions forbid the + /// writing of the sections. If two arc sections should be written + /// to the output, it can be done in two passes, the first pass + /// writes the node section and the first arc section, then the + /// second pass skips the node section and writes just the arc + /// section to the stream. The output stream can be retrieved with + /// the \c ostream() function, hence the second pass can append its + /// output to the output of the first pass. + template + class DigraphWriter { + public: + + typedef DGR Digraph; + TEMPLATE_DIGRAPH_TYPEDEFS(DGR); + + private: + + + std::ostream* _os; + bool local_os; + + const DGR& _digraph; + + std::string _nodes_caption; + std::string _arcs_caption; + std::string _attributes_caption; + + typedef std::map NodeIndex; + NodeIndex _node_index; + typedef std::map ArcIndex; + ArcIndex _arc_index; + + typedef std::vector* > > NodeMaps; + NodeMaps _node_maps; + + typedef std::vector* > >ArcMaps; + ArcMaps _arc_maps; + + typedef std::vector > Attributes; + Attributes _attributes; + + bool _skip_nodes; + bool _skip_arcs; + + public: + + /// \brief Constructor + /// + /// Construct a directed graph writer, which writes to the given + /// output stream. + DigraphWriter(const DGR& digraph, std::ostream& os = std::cout) + : _os(&os), local_os(false), _digraph(digraph), + _skip_nodes(false), _skip_arcs(false) {} + + /// \brief Constructor + /// + /// Construct a directed graph writer, which writes to the given + /// output file. + DigraphWriter(const DGR& digraph, const std::string& fn) + : _os(new std::ofstream(fn.c_str())), local_os(true), _digraph(digraph), + _skip_nodes(false), _skip_arcs(false) { + if (!(*_os)) { + delete _os; + throw IoError("Cannot write file", fn); + } + } + + /// \brief Constructor + /// + /// Construct a directed graph writer, which writes to the given + /// output file. + DigraphWriter(const DGR& digraph, const char* fn) + : _os(new std::ofstream(fn)), local_os(true), _digraph(digraph), + _skip_nodes(false), _skip_arcs(false) { + if (!(*_os)) { + delete _os; + throw IoError("Cannot write file", fn); + } + } + + /// \brief Destructor + ~DigraphWriter() { + for (typename NodeMaps::iterator it = _node_maps.begin(); + it != _node_maps.end(); ++it) { + delete it->second; + } + + for (typename ArcMaps::iterator it = _arc_maps.begin(); + it != _arc_maps.end(); ++it) { + delete it->second; + } + + for (typename Attributes::iterator it = _attributes.begin(); + it != _attributes.end(); ++it) { + delete it->second; + } + + if (local_os) { + delete _os; + } + } + + private: + + template + friend DigraphWriter digraphWriter(const TDGR& digraph, + std::ostream& os); + template + friend DigraphWriter digraphWriter(const TDGR& digraph, + const std::string& fn); + template + friend DigraphWriter digraphWriter(const TDGR& digraph, + const char *fn); + + DigraphWriter(DigraphWriter& other) + : _os(other._os), local_os(other.local_os), _digraph(other._digraph), + _skip_nodes(other._skip_nodes), _skip_arcs(other._skip_arcs) { + + other._os = 0; + other.local_os = false; + + _node_index.swap(other._node_index); + _arc_index.swap(other._arc_index); + + _node_maps.swap(other._node_maps); + _arc_maps.swap(other._arc_maps); + _attributes.swap(other._attributes); + + _nodes_caption = other._nodes_caption; + _arcs_caption = other._arcs_caption; + _attributes_caption = other._attributes_caption; + } + + DigraphWriter& operator=(const DigraphWriter&); + + public: + + /// \name Writing Rules + /// @{ + + /// \brief Node map writing rule + /// + /// Add a node map writing rule to the writer. + template + DigraphWriter& nodeMap(const std::string& caption, const Map& map) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map); + _node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Node map writing rule + /// + /// Add a node map writing rule with specialized converter to the + /// writer. + template + DigraphWriter& nodeMap(const std::string& caption, const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map, converter); + _node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Arc map writing rule + /// + /// Add an arc map writing rule to the writer. + template + DigraphWriter& arcMap(const std::string& caption, const Map& map) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map); + _arc_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Arc map writing rule + /// + /// Add an arc map writing rule with specialized converter to the + /// writer. + template + DigraphWriter& arcMap(const std::string& caption, const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map, converter); + _arc_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Attribute writing rule + /// + /// Add an attribute writing rule to the writer. + template + DigraphWriter& attribute(const std::string& caption, const Value& value) { + _writer_bits::ValueStorageBase* storage = + new _writer_bits::ValueStorage(value); + _attributes.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Attribute writing rule + /// + /// Add an attribute writing rule with specialized converter to the + /// writer. + template + DigraphWriter& attribute(const std::string& caption, const Value& value, + const Converter& converter = Converter()) { + _writer_bits::ValueStorageBase* storage = + new _writer_bits::ValueStorage(value, converter); + _attributes.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Node writing rule + /// + /// Add a node writing rule to the writer. + DigraphWriter& node(const std::string& caption, const Node& node) { + typedef _writer_bits::MapLookUpConverter Converter; + Converter converter(_node_index); + _writer_bits::ValueStorageBase* storage = + new _writer_bits::ValueStorage(node, converter); + _attributes.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Arc writing rule + /// + /// Add an arc writing rule to writer. + DigraphWriter& arc(const std::string& caption, const Arc& arc) { + typedef _writer_bits::MapLookUpConverter Converter; + Converter converter(_arc_index); + _writer_bits::ValueStorageBase* storage = + new _writer_bits::ValueStorage(arc, converter); + _attributes.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \name Section Captions + /// @{ + + /// \brief Add an additional caption to the \c \@nodes section + /// + /// Add an additional caption to the \c \@nodes section. + DigraphWriter& nodes(const std::string& caption) { + _nodes_caption = caption; + return *this; + } + + /// \brief Add an additional caption to the \c \@arcs section + /// + /// Add an additional caption to the \c \@arcs section. + DigraphWriter& arcs(const std::string& caption) { + _arcs_caption = caption; + return *this; + } + + /// \brief Add an additional caption to the \c \@attributes section + /// + /// Add an additional caption to the \c \@attributes section. + DigraphWriter& attributes(const std::string& caption) { + _attributes_caption = caption; + return *this; + } + + /// \name Skipping Section + /// @{ + + /// \brief Skip writing the node set + /// + /// The \c \@nodes section will not be written to the stream. + DigraphWriter& skipNodes() { + LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member"); + _skip_nodes = true; + return *this; + } + + /// \brief Skip writing arc set + /// + /// The \c \@arcs section will not be written to the stream. + DigraphWriter& skipArcs() { + LEMON_ASSERT(!_skip_arcs, "Multiple usage of skipArcs() member"); + _skip_arcs = true; + return *this; + } + + /// @} + + private: + + void writeNodes() { + _writer_bits::MapStorageBase* label = 0; + for (typename NodeMaps::iterator it = _node_maps.begin(); + it != _node_maps.end(); ++it) { + if (it->first == "label") { + label = it->second; + break; + } + } + + *_os << "@nodes"; + if (!_nodes_caption.empty()) { + _writer_bits::writeToken(*_os << ' ', _nodes_caption); + } + *_os << std::endl; + + if (label == 0) { + *_os << "label" << '\t'; + } + for (typename NodeMaps::iterator it = _node_maps.begin(); + it != _node_maps.end(); ++it) { + _writer_bits::writeToken(*_os, it->first) << '\t'; + } + *_os << std::endl; + + std::vector nodes; + for (NodeIt n(_digraph); n != INVALID; ++n) { + nodes.push_back(n); + } + + if (label == 0) { + IdMap id_map(_digraph); + _writer_bits::MapLess > id_less(id_map); + std::sort(nodes.begin(), nodes.end(), id_less); + } else { + label->sort(nodes); + } + + for (int i = 0; i < static_cast(nodes.size()); ++i) { + Node n = nodes[i]; + if (label == 0) { + std::ostringstream os; + os << _digraph.id(n); + _writer_bits::writeToken(*_os, os.str()); + *_os << '\t'; + _node_index.insert(std::make_pair(n, os.str())); + } + for (typename NodeMaps::iterator it = _node_maps.begin(); + it != _node_maps.end(); ++it) { + std::string value = it->second->get(n); + _writer_bits::writeToken(*_os, value); + if (it->first == "label") { + _node_index.insert(std::make_pair(n, value)); + } + *_os << '\t'; + } + *_os << std::endl; + } + } + + void createNodeIndex() { + _writer_bits::MapStorageBase* label = 0; + for (typename NodeMaps::iterator it = _node_maps.begin(); + it != _node_maps.end(); ++it) { + if (it->first == "label") { + label = it->second; + break; + } + } + + if (label == 0) { + for (NodeIt n(_digraph); n != INVALID; ++n) { + std::ostringstream os; + os << _digraph.id(n); + _node_index.insert(std::make_pair(n, os.str())); + } + } else { + for (NodeIt n(_digraph); n != INVALID; ++n) { + std::string value = label->get(n); + _node_index.insert(std::make_pair(n, value)); + } + } + } + + void writeArcs() { + _writer_bits::MapStorageBase* label = 0; + for (typename ArcMaps::iterator it = _arc_maps.begin(); + it != _arc_maps.end(); ++it) { + if (it->first == "label") { + label = it->second; + break; + } + } + + *_os << "@arcs"; + if (!_arcs_caption.empty()) { + _writer_bits::writeToken(*_os << ' ', _arcs_caption); + } + *_os << std::endl; + + *_os << '\t' << '\t'; + if (label == 0) { + *_os << "label" << '\t'; + } + for (typename ArcMaps::iterator it = _arc_maps.begin(); + it != _arc_maps.end(); ++it) { + _writer_bits::writeToken(*_os, it->first) << '\t'; + } + *_os << std::endl; + + std::vector arcs; + for (ArcIt n(_digraph); n != INVALID; ++n) { + arcs.push_back(n); + } + + if (label == 0) { + IdMap id_map(_digraph); + _writer_bits::MapLess > id_less(id_map); + std::sort(arcs.begin(), arcs.end(), id_less); + } else { + label->sort(arcs); + } + + for (int i = 0; i < static_cast(arcs.size()); ++i) { + Arc a = arcs[i]; + _writer_bits::writeToken(*_os, _node_index. + find(_digraph.source(a))->second); + *_os << '\t'; + _writer_bits::writeToken(*_os, _node_index. + find(_digraph.target(a))->second); + *_os << '\t'; + if (label == 0) { + std::ostringstream os; + os << _digraph.id(a); + _writer_bits::writeToken(*_os, os.str()); + *_os << '\t'; + _arc_index.insert(std::make_pair(a, os.str())); + } + for (typename ArcMaps::iterator it = _arc_maps.begin(); + it != _arc_maps.end(); ++it) { + std::string value = it->second->get(a); + _writer_bits::writeToken(*_os, value); + if (it->first == "label") { + _arc_index.insert(std::make_pair(a, value)); + } + *_os << '\t'; + } + *_os << std::endl; + } + } + + void createArcIndex() { + _writer_bits::MapStorageBase* label = 0; + for (typename ArcMaps::iterator it = _arc_maps.begin(); + it != _arc_maps.end(); ++it) { + if (it->first == "label") { + label = it->second; + break; + } + } + + if (label == 0) { + for (ArcIt a(_digraph); a != INVALID; ++a) { + std::ostringstream os; + os << _digraph.id(a); + _arc_index.insert(std::make_pair(a, os.str())); + } + } else { + for (ArcIt a(_digraph); a != INVALID; ++a) { + std::string value = label->get(a); + _arc_index.insert(std::make_pair(a, value)); + } + } + } + + void writeAttributes() { + if (_attributes.empty()) return; + *_os << "@attributes"; + if (!_attributes_caption.empty()) { + _writer_bits::writeToken(*_os << ' ', _attributes_caption); + } + *_os << std::endl; + for (typename Attributes::iterator it = _attributes.begin(); + it != _attributes.end(); ++it) { + _writer_bits::writeToken(*_os, it->first) << ' '; + _writer_bits::writeToken(*_os, it->second->get()); + *_os << std::endl; + } + } + + public: + + /// \name Execution of the Writer + /// @{ + + /// \brief Start the batch processing + /// + /// This function starts the batch processing. + void run() { + if (!_skip_nodes) { + writeNodes(); + } else { + createNodeIndex(); + } + if (!_skip_arcs) { + writeArcs(); + } else { + createArcIndex(); + } + writeAttributes(); + } + + /// \brief Give back the stream of the writer + /// + /// Give back the stream of the writer. + std::ostream& ostream() { + return *_os; + } + + /// @} + }; + + /// \ingroup lemon_io + /// + /// \brief Return a \ref lemon::DigraphWriter "DigraphWriter" class + /// + /// This function just returns a \ref lemon::DigraphWriter + /// "DigraphWriter" class. + /// + /// With this function a digraph can be write to a file or output + /// stream in \ref lgf-format "LGF" format with several maps and + /// attributes. For example, with the following code a network flow + /// problem can be written to the standard output, i.e. a digraph + /// with a \e capacity map on the arcs and \e source and \e target + /// nodes: + /// + ///\code + ///ListDigraph digraph; + ///ListDigraph::ArcMap cap(digraph); + ///ListDigraph::Node src, trg; + /// // Setting the capacity map and source and target nodes + ///digraphWriter(digraph, std::cout). + /// arcMap("capacity", cap). + /// node("source", src). + /// node("target", trg). + /// run(); + ///\endcode + /// + /// For a complete documentation, please see the + /// \ref lemon::DigraphWriter "DigraphWriter" + /// class documentation. + /// \warning Don't forget to put the \ref lemon::DigraphWriter::run() "run()" + /// to the end of the parameter list. + /// \relates DigraphWriter + /// \sa digraphWriter(const TDGR& digraph, const std::string& fn) + /// \sa digraphWriter(const TDGR& digraph, const char* fn) + template + DigraphWriter digraphWriter(const TDGR& digraph, std::ostream& os) { + DigraphWriter tmp(digraph, os); + return tmp; + } + + /// \brief Return a \ref DigraphWriter class + /// + /// This function just returns a \ref DigraphWriter class. + /// \relates DigraphWriter + /// \sa digraphWriter(const TDGR& digraph, std::ostream& os) + template + DigraphWriter digraphWriter(const TDGR& digraph, + const std::string& fn) { + DigraphWriter tmp(digraph, fn); + return tmp; + } + + /// \brief Return a \ref DigraphWriter class + /// + /// This function just returns a \ref DigraphWriter class. + /// \relates DigraphWriter + /// \sa digraphWriter(const TDGR& digraph, std::ostream& os) + template + DigraphWriter digraphWriter(const TDGR& digraph, const char* fn) { + DigraphWriter tmp(digraph, fn); + return tmp; + } + + template + class GraphWriter; + + template + GraphWriter graphWriter(const TGR& graph, std::ostream& os = std::cout); + template + GraphWriter graphWriter(const TGR& graph, const std::string& fn); + template + GraphWriter graphWriter(const TGR& graph, const char* fn); + + /// \ingroup lemon_io + /// + /// \brief \ref lgf-format "LGF" writer for undirected graphs + /// + /// This utility writes an \ref lgf-format "LGF" file. + /// + /// It can be used almost the same way as \c DigraphWriter. + /// The only difference is that this class can handle edges and + /// edge maps as well as arcs and arc maps. + /// + /// The arc maps are written into the file as two columns, the + /// caption of the columns are the name of the map prefixed with \c + /// '+' and \c '-'. The arcs are written into the \c \@attributes + /// section as a \c '+' or a \c '-' prefix (depends on the direction + /// of the arc) and the label of corresponding edge. + template + class GraphWriter { + public: + + typedef GR Graph; + TEMPLATE_GRAPH_TYPEDEFS(GR); + + private: + + + std::ostream* _os; + bool local_os; + + const GR& _graph; + + std::string _nodes_caption; + std::string _edges_caption; + std::string _attributes_caption; + + typedef std::map NodeIndex; + NodeIndex _node_index; + typedef std::map EdgeIndex; + EdgeIndex _edge_index; + + typedef std::vector* > > NodeMaps; + NodeMaps _node_maps; + + typedef std::vector* > >EdgeMaps; + EdgeMaps _edge_maps; + + typedef std::vector > Attributes; + Attributes _attributes; + + bool _skip_nodes; + bool _skip_edges; + + public: + + /// \brief Constructor + /// + /// Construct an undirected graph writer, which writes to the + /// given output stream. + GraphWriter(const GR& graph, std::ostream& os = std::cout) + : _os(&os), local_os(false), _graph(graph), + _skip_nodes(false), _skip_edges(false) {} + + /// \brief Constructor + /// + /// Construct a undirected graph writer, which writes to the given + /// output file. + GraphWriter(const GR& graph, const std::string& fn) + : _os(new std::ofstream(fn.c_str())), local_os(true), _graph(graph), + _skip_nodes(false), _skip_edges(false) { + if (!(*_os)) { + delete _os; + throw IoError("Cannot write file", fn); + } + } + + /// \brief Constructor + /// + /// Construct a undirected graph writer, which writes to the given + /// output file. + GraphWriter(const GR& graph, const char* fn) + : _os(new std::ofstream(fn)), local_os(true), _graph(graph), + _skip_nodes(false), _skip_edges(false) { + if (!(*_os)) { + delete _os; + throw IoError("Cannot write file", fn); + } + } + + /// \brief Destructor + ~GraphWriter() { + for (typename NodeMaps::iterator it = _node_maps.begin(); + it != _node_maps.end(); ++it) { + delete it->second; + } + + for (typename EdgeMaps::iterator it = _edge_maps.begin(); + it != _edge_maps.end(); ++it) { + delete it->second; + } + + for (typename Attributes::iterator it = _attributes.begin(); + it != _attributes.end(); ++it) { + delete it->second; + } + + if (local_os) { + delete _os; + } + } + + private: + + template + friend GraphWriter graphWriter(const TGR& graph, std::ostream& os); + template + friend GraphWriter graphWriter(const TGR& graph, + const std::string& fn); + template + friend GraphWriter graphWriter(const TGR& graph, const char *fn); + + GraphWriter(GraphWriter& other) + : _os(other._os), local_os(other.local_os), _graph(other._graph), + _skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) { + + other._os = 0; + other.local_os = false; + + _node_index.swap(other._node_index); + _edge_index.swap(other._edge_index); + + _node_maps.swap(other._node_maps); + _edge_maps.swap(other._edge_maps); + _attributes.swap(other._attributes); + + _nodes_caption = other._nodes_caption; + _edges_caption = other._edges_caption; + _attributes_caption = other._attributes_caption; + } + + GraphWriter& operator=(const GraphWriter&); + + public: + + /// \name Writing Rules + /// @{ + + /// \brief Node map writing rule + /// + /// Add a node map writing rule to the writer. + template + GraphWriter& nodeMap(const std::string& caption, const Map& map) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map); + _node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Node map writing rule + /// + /// Add a node map writing rule with specialized converter to the + /// writer. + template + GraphWriter& nodeMap(const std::string& caption, const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map, converter); + _node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Edge map writing rule + /// + /// Add an edge map writing rule to the writer. + template + GraphWriter& edgeMap(const std::string& caption, const Map& map) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map); + _edge_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Edge map writing rule + /// + /// Add an edge map writing rule with specialized converter to the + /// writer. + template + GraphWriter& edgeMap(const std::string& caption, const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map, converter); + _edge_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Arc map writing rule + /// + /// Add an arc map writing rule to the writer. + template + GraphWriter& arcMap(const std::string& caption, const Map& map) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* forward_storage = + new _writer_bits::GraphArcMapStorage(_graph, map); + _edge_maps.push_back(std::make_pair('+' + caption, forward_storage)); + _writer_bits::MapStorageBase* backward_storage = + new _writer_bits::GraphArcMapStorage(_graph, map); + _edge_maps.push_back(std::make_pair('-' + caption, backward_storage)); + return *this; + } + + /// \brief Arc map writing rule + /// + /// Add an arc map writing rule with specialized converter to the + /// writer. + template + GraphWriter& arcMap(const std::string& caption, const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* forward_storage = + new _writer_bits::GraphArcMapStorage + (_graph, map, converter); + _edge_maps.push_back(std::make_pair('+' + caption, forward_storage)); + _writer_bits::MapStorageBase* backward_storage = + new _writer_bits::GraphArcMapStorage + (_graph, map, converter); + _edge_maps.push_back(std::make_pair('-' + caption, backward_storage)); + return *this; + } + + /// \brief Attribute writing rule + /// + /// Add an attribute writing rule to the writer. + template + GraphWriter& attribute(const std::string& caption, const Value& value) { + _writer_bits::ValueStorageBase* storage = + new _writer_bits::ValueStorage(value); + _attributes.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Attribute writing rule + /// + /// Add an attribute writing rule with specialized converter to the + /// writer. + template + GraphWriter& attribute(const std::string& caption, const Value& value, + const Converter& converter = Converter()) { + _writer_bits::ValueStorageBase* storage = + new _writer_bits::ValueStorage(value, converter); + _attributes.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Node writing rule + /// + /// Add a node writing rule to the writer. + GraphWriter& node(const std::string& caption, const Node& node) { + typedef _writer_bits::MapLookUpConverter Converter; + Converter converter(_node_index); + _writer_bits::ValueStorageBase* storage = + new _writer_bits::ValueStorage(node, converter); + _attributes.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Edge writing rule + /// + /// Add an edge writing rule to writer. + GraphWriter& edge(const std::string& caption, const Edge& edge) { + typedef _writer_bits::MapLookUpConverter Converter; + Converter converter(_edge_index); + _writer_bits::ValueStorageBase* storage = + new _writer_bits::ValueStorage(edge, converter); + _attributes.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Arc writing rule + /// + /// Add an arc writing rule to writer. + GraphWriter& arc(const std::string& caption, const Arc& arc) { + typedef _writer_bits::GraphArcLookUpConverter Converter; + Converter converter(_graph, _edge_index); + _writer_bits::ValueStorageBase* storage = + new _writer_bits::ValueStorage(arc, converter); + _attributes.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \name Section Captions + /// @{ + + /// \brief Add an additional caption to the \c \@nodes section + /// + /// Add an additional caption to the \c \@nodes section. + GraphWriter& nodes(const std::string& caption) { + _nodes_caption = caption; + return *this; + } + + /// \brief Add an additional caption to the \c \@edges section + /// + /// Add an additional caption to the \c \@edges section. + GraphWriter& edges(const std::string& caption) { + _edges_caption = caption; + return *this; + } + + /// \brief Add an additional caption to the \c \@attributes section + /// + /// Add an additional caption to the \c \@attributes section. + GraphWriter& attributes(const std::string& caption) { + _attributes_caption = caption; + return *this; + } + + /// \name Skipping Section + /// @{ + + /// \brief Skip writing the node set + /// + /// The \c \@nodes section will not be written to the stream. + GraphWriter& skipNodes() { + LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member"); + _skip_nodes = true; + return *this; + } + + /// \brief Skip writing edge set + /// + /// The \c \@edges section will not be written to the stream. + GraphWriter& skipEdges() { + LEMON_ASSERT(!_skip_edges, "Multiple usage of skipEdges() member"); + _skip_edges = true; + return *this; + } + + /// @} + + private: + + void writeNodes() { + _writer_bits::MapStorageBase* label = 0; + for (typename NodeMaps::iterator it = _node_maps.begin(); + it != _node_maps.end(); ++it) { + if (it->first == "label") { + label = it->second; + break; + } + } + + *_os << "@nodes"; + if (!_nodes_caption.empty()) { + _writer_bits::writeToken(*_os << ' ', _nodes_caption); + } + *_os << std::endl; + + if (label == 0) { + *_os << "label" << '\t'; + } + for (typename NodeMaps::iterator it = _node_maps.begin(); + it != _node_maps.end(); ++it) { + _writer_bits::writeToken(*_os, it->first) << '\t'; + } + *_os << std::endl; + + std::vector nodes; + for (NodeIt n(_graph); n != INVALID; ++n) { + nodes.push_back(n); + } + + if (label == 0) { + IdMap id_map(_graph); + _writer_bits::MapLess > id_less(id_map); + std::sort(nodes.begin(), nodes.end(), id_less); + } else { + label->sort(nodes); + } + + for (int i = 0; i < static_cast(nodes.size()); ++i) { + Node n = nodes[i]; + if (label == 0) { + std::ostringstream os; + os << _graph.id(n); + _writer_bits::writeToken(*_os, os.str()); + *_os << '\t'; + _node_index.insert(std::make_pair(n, os.str())); + } + for (typename NodeMaps::iterator it = _node_maps.begin(); + it != _node_maps.end(); ++it) { + std::string value = it->second->get(n); + _writer_bits::writeToken(*_os, value); + if (it->first == "label") { + _node_index.insert(std::make_pair(n, value)); + } + *_os << '\t'; + } + *_os << std::endl; + } + } + + void createNodeIndex() { + _writer_bits::MapStorageBase* label = 0; + for (typename NodeMaps::iterator it = _node_maps.begin(); + it != _node_maps.end(); ++it) { + if (it->first == "label") { + label = it->second; + break; + } + } + + if (label == 0) { + for (NodeIt n(_graph); n != INVALID; ++n) { + std::ostringstream os; + os << _graph.id(n); + _node_index.insert(std::make_pair(n, os.str())); + } + } else { + for (NodeIt n(_graph); n != INVALID; ++n) { + std::string value = label->get(n); + _node_index.insert(std::make_pair(n, value)); + } + } + } + + void writeEdges() { + _writer_bits::MapStorageBase* label = 0; + for (typename EdgeMaps::iterator it = _edge_maps.begin(); + it != _edge_maps.end(); ++it) { + if (it->first == "label") { + label = it->second; + break; + } + } + + *_os << "@edges"; + if (!_edges_caption.empty()) { + _writer_bits::writeToken(*_os << ' ', _edges_caption); + } + *_os << std::endl; + + *_os << '\t' << '\t'; + if (label == 0) { + *_os << "label" << '\t'; + } + for (typename EdgeMaps::iterator it = _edge_maps.begin(); + it != _edge_maps.end(); ++it) { + _writer_bits::writeToken(*_os, it->first) << '\t'; + } + *_os << std::endl; + + std::vector edges; + for (EdgeIt n(_graph); n != INVALID; ++n) { + edges.push_back(n); + } + + if (label == 0) { + IdMap id_map(_graph); + _writer_bits::MapLess > id_less(id_map); + std::sort(edges.begin(), edges.end(), id_less); + } else { + label->sort(edges); + } + + for (int i = 0; i < static_cast(edges.size()); ++i) { + Edge e = edges[i]; + _writer_bits::writeToken(*_os, _node_index. + find(_graph.u(e))->second); + *_os << '\t'; + _writer_bits::writeToken(*_os, _node_index. + find(_graph.v(e))->second); + *_os << '\t'; + if (label == 0) { + std::ostringstream os; + os << _graph.id(e); + _writer_bits::writeToken(*_os, os.str()); + *_os << '\t'; + _edge_index.insert(std::make_pair(e, os.str())); + } + for (typename EdgeMaps::iterator it = _edge_maps.begin(); + it != _edge_maps.end(); ++it) { + std::string value = it->second->get(e); + _writer_bits::writeToken(*_os, value); + if (it->first == "label") { + _edge_index.insert(std::make_pair(e, value)); + } + *_os << '\t'; + } + *_os << std::endl; + } + } + + void createEdgeIndex() { + _writer_bits::MapStorageBase* label = 0; + for (typename EdgeMaps::iterator it = _edge_maps.begin(); + it != _edge_maps.end(); ++it) { + if (it->first == "label") { + label = it->second; + break; + } + } + + if (label == 0) { + for (EdgeIt e(_graph); e != INVALID; ++e) { + std::ostringstream os; + os << _graph.id(e); + _edge_index.insert(std::make_pair(e, os.str())); + } + } else { + for (EdgeIt e(_graph); e != INVALID; ++e) { + std::string value = label->get(e); + _edge_index.insert(std::make_pair(e, value)); + } + } + } + + void writeAttributes() { + if (_attributes.empty()) return; + *_os << "@attributes"; + if (!_attributes_caption.empty()) { + _writer_bits::writeToken(*_os << ' ', _attributes_caption); + } + *_os << std::endl; + for (typename Attributes::iterator it = _attributes.begin(); + it != _attributes.end(); ++it) { + _writer_bits::writeToken(*_os, it->first) << ' '; + _writer_bits::writeToken(*_os, it->second->get()); + *_os << std::endl; + } + } + + public: + + /// \name Execution of the Writer + /// @{ + + /// \brief Start the batch processing + /// + /// This function starts the batch processing. + void run() { + if (!_skip_nodes) { + writeNodes(); + } else { + createNodeIndex(); + } + if (!_skip_edges) { + writeEdges(); + } else { + createEdgeIndex(); + } + writeAttributes(); + } + + /// \brief Give back the stream of the writer + /// + /// Give back the stream of the writer + std::ostream& ostream() { + return *_os; + } + + /// @} + }; + + /// \ingroup lemon_io + /// + /// \brief Return a \ref lemon::GraphWriter "GraphWriter" class + /// + /// This function just returns a \ref lemon::GraphWriter "GraphWriter" class. + /// + /// With this function a graph can be write to a file or output + /// stream in \ref lgf-format "LGF" format with several maps and + /// attributes. For example, with the following code a weighted + /// matching problem can be written to the standard output, i.e. a + /// graph with a \e weight map on the edges: + /// + ///\code + ///ListGraph graph; + ///ListGraph::EdgeMap weight(graph); + /// // Setting the weight map + ///graphWriter(graph, std::cout). + /// edgeMap("weight", weight). + /// run(); + ///\endcode + /// + /// For a complete documentation, please see the + /// \ref lemon::GraphWriter "GraphWriter" + /// class documentation. + /// \warning Don't forget to put the \ref lemon::GraphWriter::run() "run()" + /// to the end of the parameter list. + /// \relates GraphWriter + /// \sa graphWriter(const TGR& graph, const std::string& fn) + /// \sa graphWriter(const TGR& graph, const char* fn) + template + GraphWriter graphWriter(const TGR& graph, std::ostream& os) { + GraphWriter tmp(graph, os); + return tmp; + } + + /// \brief Return a \ref GraphWriter class + /// + /// This function just returns a \ref GraphWriter class. + /// \relates GraphWriter + /// \sa graphWriter(const TGR& graph, std::ostream& os) + template + GraphWriter graphWriter(const TGR& graph, const std::string& fn) { + GraphWriter tmp(graph, fn); + return tmp; + } + + /// \brief Return a \ref GraphWriter class + /// + /// This function just returns a \ref GraphWriter class. + /// \relates GraphWriter + /// \sa graphWriter(const TGR& graph, std::ostream& os) + template + GraphWriter graphWriter(const TGR& graph, const char* fn) { + GraphWriter tmp(graph, fn); + return tmp; + } + + template + class BpGraphWriter; + + template + BpGraphWriter bpGraphWriter(const TBGR& graph, + std::ostream& os = std::cout); + template + BpGraphWriter bpGraphWriter(const TBGR& graph, const std::string& fn); + template + BpGraphWriter bpGraphWriter(const TBGR& graph, const char* fn); + + /// \ingroup lemon_io + /// + /// \brief \ref lgf-format "LGF" writer for undirected bipartite graphs + /// + /// This utility writes an \ref lgf-format "LGF" file. + /// + /// It can be used almost the same way as \c GraphWriter, but it + /// reads the red and blue nodes from separate sections, and these + /// sections can contain different set of maps. + /// + /// The red and blue node maps are written to the corresponding + /// sections. The node maps are written to both of these sections + /// with the same map name. + template + class BpGraphWriter { + public: + + typedef BGR BpGraph; + TEMPLATE_BPGRAPH_TYPEDEFS(BGR); + + private: + + + std::ostream* _os; + bool local_os; + + const BGR& _graph; + + std::string _nodes_caption; + std::string _edges_caption; + std::string _attributes_caption; + + typedef std::map RedNodeIndex; + RedNodeIndex _red_node_index; + typedef std::map BlueNodeIndex; + BlueNodeIndex _blue_node_index; + typedef std::map EdgeIndex; + EdgeIndex _edge_index; + + typedef std::vector* > > RedNodeMaps; + RedNodeMaps _red_node_maps; + typedef std::vector* > > BlueNodeMaps; + BlueNodeMaps _blue_node_maps; + + typedef std::vector* > >EdgeMaps; + EdgeMaps _edge_maps; + + typedef std::vector > Attributes; + Attributes _attributes; + + bool _skip_nodes; + bool _skip_edges; + + public: + + /// \brief Constructor + /// + /// Construct a bipartite graph writer, which writes to the given + /// output stream. + BpGraphWriter(const BGR& graph, std::ostream& os = std::cout) + : _os(&os), local_os(false), _graph(graph), + _skip_nodes(false), _skip_edges(false) {} + + /// \brief Constructor + /// + /// Construct a bipartite graph writer, which writes to the given + /// output file. + BpGraphWriter(const BGR& graph, const std::string& fn) + : _os(new std::ofstream(fn.c_str())), local_os(true), _graph(graph), + _skip_nodes(false), _skip_edges(false) { + if (!(*_os)) { + delete _os; + throw IoError("Cannot write file", fn); + } + } + + /// \brief Constructor + /// + /// Construct a bipartite graph writer, which writes to the given + /// output file. + BpGraphWriter(const BGR& graph, const char* fn) + : _os(new std::ofstream(fn)), local_os(true), _graph(graph), + _skip_nodes(false), _skip_edges(false) { + if (!(*_os)) { + delete _os; + throw IoError("Cannot write file", fn); + } + } + + /// \brief Destructor + ~BpGraphWriter() { + for (typename RedNodeMaps::iterator it = _red_node_maps.begin(); + it != _red_node_maps.end(); ++it) { + delete it->second; + } + + for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin(); + it != _blue_node_maps.end(); ++it) { + delete it->second; + } + + for (typename EdgeMaps::iterator it = _edge_maps.begin(); + it != _edge_maps.end(); ++it) { + delete it->second; + } + + for (typename Attributes::iterator it = _attributes.begin(); + it != _attributes.end(); ++it) { + delete it->second; + } + + if (local_os) { + delete _os; + } + } + + private: + + template + friend BpGraphWriter bpGraphWriter(const TBGR& graph, + std::ostream& os); + template + friend BpGraphWriter bpGraphWriter(const TBGR& graph, + const std::string& fn); + template + friend BpGraphWriter bpGraphWriter(const TBGR& graph, const char *fn); + + BpGraphWriter(BpGraphWriter& other) + : _os(other._os), local_os(other.local_os), _graph(other._graph), + _skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) { + + other._os = 0; + other.local_os = false; + + _red_node_index.swap(other._red_node_index); + _blue_node_index.swap(other._blue_node_index); + _edge_index.swap(other._edge_index); + + _red_node_maps.swap(other._red_node_maps); + _blue_node_maps.swap(other._blue_node_maps); + _edge_maps.swap(other._edge_maps); + _attributes.swap(other._attributes); + + _nodes_caption = other._nodes_caption; + _edges_caption = other._edges_caption; + _attributes_caption = other._attributes_caption; + } + + BpGraphWriter& operator=(const BpGraphWriter&); + + public: + + /// \name Writing Rules + /// @{ + + /// \brief Node map writing rule + /// + /// Add a node map writing rule to the writer. + template + BpGraphWriter& nodeMap(const std::string& caption, const Map& map) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* red_storage = + new _writer_bits::MapStorage(map); + _red_node_maps.push_back(std::make_pair(caption, red_storage)); + _writer_bits::MapStorageBase* blue_storage = + new _writer_bits::MapStorage(map); + _blue_node_maps.push_back(std::make_pair(caption, blue_storage)); + return *this; + } + + /// \brief Node map writing rule + /// + /// Add a node map writing rule with specialized converter to the + /// writer. + template + BpGraphWriter& nodeMap(const std::string& caption, const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* red_storage = + new _writer_bits::MapStorage(map, converter); + _red_node_maps.push_back(std::make_pair(caption, red_storage)); + _writer_bits::MapStorageBase* blue_storage = + new _writer_bits::MapStorage(map, converter); + _blue_node_maps.push_back(std::make_pair(caption, blue_storage)); + return *this; + } + + /// \brief Red node map writing rule + /// + /// Add a red node map writing rule to the writer. + template + BpGraphWriter& redNodeMap(const std::string& caption, const Map& map) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map); + _red_node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Red node map writing rule + /// + /// Add a red node map writing rule with specialized converter to the + /// writer. + template + BpGraphWriter& redNodeMap(const std::string& caption, const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map, converter); + _red_node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Blue node map writing rule + /// + /// Add a blue node map writing rule to the writer. + template + BpGraphWriter& blueNodeMap(const std::string& caption, const Map& map) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map); + _blue_node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Blue node map writing rule + /// + /// Add a blue node map writing rule with specialized converter to the + /// writer. + template + BpGraphWriter& blueNodeMap(const std::string& caption, const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map, converter); + _blue_node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Edge map writing rule + /// + /// Add an edge map writing rule to the writer. + template + BpGraphWriter& edgeMap(const std::string& caption, const Map& map) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map); + _edge_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Edge map writing rule + /// + /// Add an edge map writing rule with specialized converter to the + /// writer. + template + BpGraphWriter& edgeMap(const std::string& caption, const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map, converter); + _edge_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Arc map writing rule + /// + /// Add an arc map writing rule to the writer. + template + BpGraphWriter& arcMap(const std::string& caption, const Map& map) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* forward_storage = + new _writer_bits::GraphArcMapStorage(_graph, map); + _edge_maps.push_back(std::make_pair('+' + caption, forward_storage)); + _writer_bits::MapStorageBase* backward_storage = + new _writer_bits::GraphArcMapStorage(_graph, map); + _edge_maps.push_back(std::make_pair('-' + caption, backward_storage)); + return *this; + } + + /// \brief Arc map writing rule + /// + /// Add an arc map writing rule with specialized converter to the + /// writer. + template + BpGraphWriter& arcMap(const std::string& caption, const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* forward_storage = + new _writer_bits::GraphArcMapStorage + (_graph, map, converter); + _edge_maps.push_back(std::make_pair('+' + caption, forward_storage)); + _writer_bits::MapStorageBase* backward_storage = + new _writer_bits::GraphArcMapStorage + (_graph, map, converter); + _edge_maps.push_back(std::make_pair('-' + caption, backward_storage)); + return *this; + } + + /// \brief Attribute writing rule + /// + /// Add an attribute writing rule to the writer. + template + BpGraphWriter& attribute(const std::string& caption, const Value& value) { + _writer_bits::ValueStorageBase* storage = + new _writer_bits::ValueStorage(value); + _attributes.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Attribute writing rule + /// + /// Add an attribute writing rule with specialized converter to the + /// writer. + template + BpGraphWriter& attribute(const std::string& caption, const Value& value, + const Converter& converter = Converter()) { + _writer_bits::ValueStorageBase* storage = + new _writer_bits::ValueStorage(value, converter); + _attributes.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Node writing rule + /// + /// Add a node writing rule to the writer. + BpGraphWriter& node(const std::string& caption, const Node& node) { + typedef _writer_bits::DoubleMapLookUpConverter< + Node, RedNodeIndex, BlueNodeIndex> Converter; + Converter converter(_red_node_index, _blue_node_index); + _writer_bits::ValueStorageBase* storage = + new _writer_bits::ValueStorage(node, converter); + _attributes.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Red node writing rule + /// + /// Add a red node writing rule to the writer. + BpGraphWriter& redNode(const std::string& caption, const RedNode& node) { + typedef _writer_bits::MapLookUpConverter Converter; + Converter converter(_red_node_index); + _writer_bits::ValueStorageBase* storage = + new _writer_bits::ValueStorage(node, converter); + _attributes.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Blue node writing rule + /// + /// Add a blue node writing rule to the writer. + BpGraphWriter& blueNode(const std::string& caption, const BlueNode& node) { + typedef _writer_bits::MapLookUpConverter Converter; + Converter converter(_blue_node_index); + _writer_bits::ValueStorageBase* storage = + new _writer_bits::ValueStorage(node, converter); + _attributes.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Edge writing rule + /// + /// Add an edge writing rule to writer. + BpGraphWriter& edge(const std::string& caption, const Edge& edge) { + typedef _writer_bits::MapLookUpConverter Converter; + Converter converter(_edge_index); + _writer_bits::ValueStorageBase* storage = + new _writer_bits::ValueStorage(edge, converter); + _attributes.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Arc writing rule + /// + /// Add an arc writing rule to writer. + BpGraphWriter& arc(const std::string& caption, const Arc& arc) { + typedef _writer_bits::GraphArcLookUpConverter Converter; + Converter converter(_graph, _edge_index); + _writer_bits::ValueStorageBase* storage = + new _writer_bits::ValueStorage(arc, converter); + _attributes.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \name Section Captions + /// @{ + + /// \brief Add an additional caption to the \c \@red_nodes and + /// \c \@blue_nodes section + /// + /// Add an additional caption to the \c \@red_nodes and \c + /// \@blue_nodes section. + BpGraphWriter& nodes(const std::string& caption) { + _nodes_caption = caption; + return *this; + } + + /// \brief Add an additional caption to the \c \@edges section + /// + /// Add an additional caption to the \c \@edges section. + BpGraphWriter& edges(const std::string& caption) { + _edges_caption = caption; + return *this; + } + + /// \brief Add an additional caption to the \c \@attributes section + /// + /// Add an additional caption to the \c \@attributes section. + BpGraphWriter& attributes(const std::string& caption) { + _attributes_caption = caption; + return *this; + } + + /// \name Skipping Section + /// @{ + + /// \brief Skip writing the node set + /// + /// The \c \@red_nodes and \c \@blue_nodes section will not be + /// written to the stream. + BpGraphWriter& skipNodes() { + LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member"); + _skip_nodes = true; + return *this; + } + + /// \brief Skip writing edge set + /// + /// The \c \@edges section will not be written to the stream. + BpGraphWriter& skipEdges() { + LEMON_ASSERT(!_skip_edges, "Multiple usage of skipEdges() member"); + _skip_edges = true; + return *this; + } + + /// @} + + private: + + void writeRedNodes() { + _writer_bits::MapStorageBase* label = 0; + for (typename RedNodeMaps::iterator it = _red_node_maps.begin(); + it != _red_node_maps.end(); ++it) { + if (it->first == "label") { + label = it->second; + break; + } + } + + *_os << "@red_nodes"; + if (!_nodes_caption.empty()) { + _writer_bits::writeToken(*_os << ' ', _nodes_caption); + } + *_os << std::endl; + + if (label == 0) { + *_os << "label" << '\t'; + } + for (typename RedNodeMaps::iterator it = _red_node_maps.begin(); + it != _red_node_maps.end(); ++it) { + _writer_bits::writeToken(*_os, it->first) << '\t'; + } + *_os << std::endl; + + std::vector nodes; + for (RedNodeIt n(_graph); n != INVALID; ++n) { + nodes.push_back(n); + } + + if (label == 0) { + IdMap id_map(_graph); + _writer_bits::MapLess > id_less(id_map); + std::sort(nodes.begin(), nodes.end(), id_less); + } else { + label->sort(nodes); + } + + for (int i = 0; i < static_cast(nodes.size()); ++i) { + RedNode n = nodes[i]; + if (label == 0) { + std::ostringstream os; + os << _graph.id(static_cast(n)); + _writer_bits::writeToken(*_os, os.str()); + *_os << '\t'; + _red_node_index.insert(std::make_pair(n, os.str())); + } + for (typename RedNodeMaps::iterator it = _red_node_maps.begin(); + it != _red_node_maps.end(); ++it) { + std::string value = it->second->get(n); + _writer_bits::writeToken(*_os, value); + if (it->first == "label") { + _red_node_index.insert(std::make_pair(n, value)); + } + *_os << '\t'; + } + *_os << std::endl; + } + } + + void writeBlueNodes() { + _writer_bits::MapStorageBase* label = 0; + for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin(); + it != _blue_node_maps.end(); ++it) { + if (it->first == "label") { + label = it->second; + break; + } + } + + *_os << "@blue_nodes"; + if (!_nodes_caption.empty()) { + _writer_bits::writeToken(*_os << ' ', _nodes_caption); + } + *_os << std::endl; + + if (label == 0) { + *_os << "label" << '\t'; + } + for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin(); + it != _blue_node_maps.end(); ++it) { + _writer_bits::writeToken(*_os, it->first) << '\t'; + } + *_os << std::endl; + + std::vector nodes; + for (BlueNodeIt n(_graph); n != INVALID; ++n) { + nodes.push_back(n); + } + + if (label == 0) { + IdMap id_map(_graph); + _writer_bits::MapLess > id_less(id_map); + std::sort(nodes.begin(), nodes.end(), id_less); + } else { + label->sort(nodes); + } + + for (int i = 0; i < static_cast(nodes.size()); ++i) { + BlueNode n = nodes[i]; + if (label == 0) { + std::ostringstream os; + os << _graph.id(static_cast(n)); + _writer_bits::writeToken(*_os, os.str()); + *_os << '\t'; + _blue_node_index.insert(std::make_pair(n, os.str())); + } + for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin(); + it != _blue_node_maps.end(); ++it) { + std::string value = it->second->get(n); + _writer_bits::writeToken(*_os, value); + if (it->first == "label") { + _blue_node_index.insert(std::make_pair(n, value)); + } + *_os << '\t'; + } + *_os << std::endl; + } + } + + void createRedNodeIndex() { + _writer_bits::MapStorageBase* label = 0; + for (typename RedNodeMaps::iterator it = _red_node_maps.begin(); + it != _red_node_maps.end(); ++it) { + if (it->first == "label") { + label = it->second; + break; + } + } + + if (label == 0) { + for (RedNodeIt n(_graph); n != INVALID; ++n) { + std::ostringstream os; + os << _graph.id(n); + _red_node_index.insert(std::make_pair(n, os.str())); + } + } else { + for (RedNodeIt n(_graph); n != INVALID; ++n) { + std::string value = label->get(n); + _red_node_index.insert(std::make_pair(n, value)); + } + } + } + + void createBlueNodeIndex() { + _writer_bits::MapStorageBase* label = 0; + for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin(); + it != _blue_node_maps.end(); ++it) { + if (it->first == "label") { + label = it->second; + break; + } + } + + if (label == 0) { + for (BlueNodeIt n(_graph); n != INVALID; ++n) { + std::ostringstream os; + os << _graph.id(n); + _blue_node_index.insert(std::make_pair(n, os.str())); + } + } else { + for (BlueNodeIt n(_graph); n != INVALID; ++n) { + std::string value = label->get(n); + _blue_node_index.insert(std::make_pair(n, value)); + } + } + } + + void writeEdges() { + _writer_bits::MapStorageBase* label = 0; + for (typename EdgeMaps::iterator it = _edge_maps.begin(); + it != _edge_maps.end(); ++it) { + if (it->first == "label") { + label = it->second; + break; + } + } + + *_os << "@edges"; + if (!_edges_caption.empty()) { + _writer_bits::writeToken(*_os << ' ', _edges_caption); + } + *_os << std::endl; + + *_os << '\t' << '\t'; + if (label == 0) { + *_os << "label" << '\t'; + } + for (typename EdgeMaps::iterator it = _edge_maps.begin(); + it != _edge_maps.end(); ++it) { + _writer_bits::writeToken(*_os, it->first) << '\t'; + } + *_os << std::endl; + + std::vector edges; + for (EdgeIt n(_graph); n != INVALID; ++n) { + edges.push_back(n); + } + + if (label == 0) { + IdMap id_map(_graph); + _writer_bits::MapLess > id_less(id_map); + std::sort(edges.begin(), edges.end(), id_less); + } else { + label->sort(edges); + } + + for (int i = 0; i < static_cast(edges.size()); ++i) { + Edge e = edges[i]; + _writer_bits::writeToken(*_os, _red_node_index. + find(_graph.redNode(e))->second); + *_os << '\t'; + _writer_bits::writeToken(*_os, _blue_node_index. + find(_graph.blueNode(e))->second); + *_os << '\t'; + if (label == 0) { + std::ostringstream os; + os << _graph.id(e); + _writer_bits::writeToken(*_os, os.str()); + *_os << '\t'; + _edge_index.insert(std::make_pair(e, os.str())); + } + for (typename EdgeMaps::iterator it = _edge_maps.begin(); + it != _edge_maps.end(); ++it) { + std::string value = it->second->get(e); + _writer_bits::writeToken(*_os, value); + if (it->first == "label") { + _edge_index.insert(std::make_pair(e, value)); + } + *_os << '\t'; + } + *_os << std::endl; + } + } + + void createEdgeIndex() { + _writer_bits::MapStorageBase* label = 0; + for (typename EdgeMaps::iterator it = _edge_maps.begin(); + it != _edge_maps.end(); ++it) { + if (it->first == "label") { + label = it->second; + break; + } + } + + if (label == 0) { + for (EdgeIt e(_graph); e != INVALID; ++e) { + std::ostringstream os; + os << _graph.id(e); + _edge_index.insert(std::make_pair(e, os.str())); + } + } else { + for (EdgeIt e(_graph); e != INVALID; ++e) { + std::string value = label->get(e); + _edge_index.insert(std::make_pair(e, value)); + } + } + } + + void writeAttributes() { + if (_attributes.empty()) return; + *_os << "@attributes"; + if (!_attributes_caption.empty()) { + _writer_bits::writeToken(*_os << ' ', _attributes_caption); + } + *_os << std::endl; + for (typename Attributes::iterator it = _attributes.begin(); + it != _attributes.end(); ++it) { + _writer_bits::writeToken(*_os, it->first) << ' '; + _writer_bits::writeToken(*_os, it->second->get()); + *_os << std::endl; + } + } + + public: + + /// \name Execution of the Writer + /// @{ + + /// \brief Start the batch processing + /// + /// This function starts the batch processing. + void run() { + if (!_skip_nodes) { + writeRedNodes(); + writeBlueNodes(); + } else { + createRedNodeIndex(); + createBlueNodeIndex(); + } + if (!_skip_edges) { + writeEdges(); + } else { + createEdgeIndex(); + } + writeAttributes(); + } + + /// \brief Give back the stream of the writer + /// + /// Give back the stream of the writer + std::ostream& ostream() { + return *_os; + } + + /// @} + }; + + /// \ingroup lemon_io + /// + /// \brief Return a \ref lemon::BpGraphWriter "BpGraphWriter" class + /// + /// This function just returns a \ref lemon::BpGraphWriter + /// "BpGraphWriter" class. + /// + /// With this function a bipartite graph can be write to a file or output + /// stream in \ref lgf-format "LGF" format with several maps and + /// attributes. For example, with the following code a bipartite + /// weighted matching problem can be written to the standard output, + /// i.e. a graph with a \e weight map on the edges: + /// + ///\code + ///ListBpGraph graph; + ///ListBpGraph::EdgeMap weight(graph); + /// // Setting the weight map + ///bpGraphWriter(graph, std::cout). + /// edgeMap("weight", weight). + /// run(); + ///\endcode + /// + /// For a complete documentation, please see the + /// \ref lemon::BpGraphWriter "BpGraphWriter" + /// class documentation. + /// \warning Don't forget to put the \ref lemon::BpGraphWriter::run() "run()" + /// to the end of the parameter list. + /// \relates BpGraphWriter + /// \sa bpGraphWriter(const TBGR& graph, const std::string& fn) + /// \sa bpGraphWriter(const TBGR& graph, const char* fn) + template + BpGraphWriter bpGraphWriter(const TBGR& graph, std::ostream& os) { + BpGraphWriter tmp(graph, os); + return tmp; + } + + /// \brief Return a \ref BpGraphWriter class + /// + /// This function just returns a \ref BpGraphWriter class. + /// \relates BpGraphWriter + /// \sa graphWriter(const TBGR& graph, std::ostream& os) + template + BpGraphWriter bpGraphWriter(const TBGR& graph, const std::string& fn) { + BpGraphWriter tmp(graph, fn); + return tmp; + } + + /// \brief Return a \ref BpGraphWriter class + /// + /// This function just returns a \ref BpGraphWriter class. + /// \relates BpGraphWriter + /// \sa graphWriter(const TBGR& graph, std::ostream& os) + template + BpGraphWriter bpGraphWriter(const TBGR& graph, const char* fn) { + BpGraphWriter tmp(graph, fn); + return tmp; + } + + class SectionWriter; + + SectionWriter sectionWriter(std::istream& is); + SectionWriter sectionWriter(const std::string& fn); + SectionWriter sectionWriter(const char* fn); + + /// \ingroup lemon_io + /// + /// \brief Section writer class + /// + /// In the \ref lgf-format "LGF" file extra sections can be placed, + /// which contain any data in arbitrary format. Such sections can be + /// written with this class. A writing rule can be added to the + /// class with two different functions. With the \c sectionLines() + /// function a generator can write the section line-by-line, while + /// with the \c sectionStream() member the section can be written to + /// an output stream. + class SectionWriter { + private: + + std::ostream* _os; + bool local_os; + + typedef std::vector > + Sections; + + Sections _sections; + + public: + + /// \brief Constructor + /// + /// Construct a section writer, which writes to the given output + /// stream. + SectionWriter(std::ostream& os) + : _os(&os), local_os(false) {} + + /// \brief Constructor + /// + /// Construct a section writer, which writes into the given file. + SectionWriter(const std::string& fn) + : _os(new std::ofstream(fn.c_str())), local_os(true) { + if (!(*_os)) { + delete _os; + throw IoError("Cannot write file", fn); + } + } + + /// \brief Constructor + /// + /// Construct a section writer, which writes into the given file. + SectionWriter(const char* fn) + : _os(new std::ofstream(fn)), local_os(true) { + if (!(*_os)) { + delete _os; + throw IoError("Cannot write file", fn); + } + } + + /// \brief Destructor + ~SectionWriter() { + for (Sections::iterator it = _sections.begin(); + it != _sections.end(); ++it) { + delete it->second; + } + + if (local_os) { + delete _os; + } + + } + + private: + + friend SectionWriter sectionWriter(std::ostream& os); + friend SectionWriter sectionWriter(const std::string& fn); + friend SectionWriter sectionWriter(const char* fn); + + SectionWriter(SectionWriter& other) + : _os(other._os), local_os(other.local_os) { + + other._os = 0; + other.local_os = false; + + _sections.swap(other._sections); + } + + SectionWriter& operator=(const SectionWriter&); + + public: + + /// \name Section Writers + /// @{ + + /// \brief Add a section writer with line oriented writing + /// + /// The first parameter is the type descriptor of the section, the + /// second is a generator with std::string values. At the writing + /// process, the returned \c std::string will be written into the + /// output file until it is an empty string. + /// + /// For example, an integer vector is written into a section. + ///\code + /// @numbers + /// 12 45 23 78 + /// 4 28 38 28 + /// 23 6 16 + ///\endcode + /// + /// The generator is implemented as a struct. + ///\code + /// struct NumberSection { + /// std::vector::const_iterator _it, _end; + /// NumberSection(const std::vector& data) + /// : _it(data.begin()), _end(data.end()) {} + /// std::string operator()() { + /// int rem_in_line = 4; + /// std::ostringstream ls; + /// while (rem_in_line > 0 && _it != _end) { + /// ls << *(_it++) << ' '; + /// --rem_in_line; + /// } + /// return ls.str(); + /// } + /// }; + /// + /// // ... + /// + /// writer.sectionLines("numbers", NumberSection(vec)); + ///\endcode + template + SectionWriter& sectionLines(const std::string& type, Functor functor) { + LEMON_ASSERT(!type.empty(), "Type is empty."); + _sections.push_back(std::make_pair(type, + new _writer_bits::LineSection(functor))); + return *this; + } + + + /// \brief Add a section writer with stream oriented writing + /// + /// The first parameter is the type of the section, the second is + /// a functor, which takes a \c std::ostream& parameter. The + /// functor writes the section to the output stream. + /// \warning The last line must be closed with end-line character. + template + SectionWriter& sectionStream(const std::string& type, Functor functor) { + LEMON_ASSERT(!type.empty(), "Type is empty."); + _sections.push_back(std::make_pair(type, + new _writer_bits::StreamSection(functor))); + return *this; + } + + /// @} + + public: + + + /// \name Execution of the Writer + /// @{ + + /// \brief Start the batch processing + /// + /// This function starts the batch processing. + void run() { + + LEMON_ASSERT(_os != 0, "This writer is assigned to an other writer"); + + for (Sections::iterator it = _sections.begin(); + it != _sections.end(); ++it) { + (*_os) << '@' << it->first << std::endl; + it->second->process(*_os); + } + } + + /// \brief Give back the stream of the writer + /// + /// Returns the stream of the writer + std::ostream& ostream() { + return *_os; + } + + /// @} + + }; + + /// \ingroup lemon_io + /// + /// \brief Return a \ref SectionWriter class + /// + /// This function just returns a \ref SectionWriter class. + /// + /// Please see SectionWriter documentation about the custom section + /// output. + /// + /// \relates SectionWriter + /// \sa sectionWriter(const std::string& fn) + /// \sa sectionWriter(const char *fn) + inline SectionWriter sectionWriter(std::ostream& os) { + SectionWriter tmp(os); + return tmp; + } + + /// \brief Return a \ref SectionWriter class + /// + /// This function just returns a \ref SectionWriter class. + /// \relates SectionWriter + /// \sa sectionWriter(std::ostream& os) + inline SectionWriter sectionWriter(const std::string& fn) { + SectionWriter tmp(fn); + return tmp; + } + + /// \brief Return a \ref SectionWriter class + /// + /// This function just returns a \ref SectionWriter class. + /// \relates SectionWriter + /// \sa sectionWriter(std::ostream& os) + inline SectionWriter sectionWriter(const char* fn) { + SectionWriter tmp(fn); + return tmp; + } +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/list_graph.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/list_graph.h new file mode 100644 index 00000000000..2a236cf91de --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/list_graph.h @@ -0,0 +1,2510 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_LIST_GRAPH_H +#define LEMON_LIST_GRAPH_H + +///\ingroup graphs +///\file +///\brief ListDigraph and ListGraph classes. + +#include +#include +#include + +#include +#include + +namespace lemon { + + class ListDigraph; + + class ListDigraphBase { + + protected: + struct NodeT { + int first_in, first_out; + int prev, next; + }; + + struct ArcT { + int target, source; + int prev_in, prev_out; + int next_in, next_out; + }; + + std::vector nodes; + + int first_node; + + int first_free_node; + + std::vector arcs; + + int first_free_arc; + + public: + + typedef ListDigraphBase Digraph; + + class Node { + friend class ListDigraphBase; + friend class ListDigraph; + protected: + + int id; + explicit Node(int pid) { id = pid;} + + public: + Node() {} + Node (Invalid) { id = -1; } + bool operator==(const Node& node) const {return id == node.id;} + bool operator!=(const Node& node) const {return id != node.id;} + bool operator<(const Node& node) const {return id < node.id;} + }; + + class Arc { + friend class ListDigraphBase; + friend class ListDigraph; + protected: + + int id; + explicit Arc(int pid) { id = pid;} + + public: + Arc() {} + Arc (Invalid) { id = -1; } + bool operator==(const Arc& arc) const {return id == arc.id;} + bool operator!=(const Arc& arc) const {return id != arc.id;} + bool operator<(const Arc& arc) const {return id < arc.id;} + }; + + + + ListDigraphBase() + : nodes(), first_node(-1), + first_free_node(-1), arcs(), first_free_arc(-1) {} + + + int maxNodeId() const { return nodes.size()-1; } + int maxArcId() const { return arcs.size()-1; } + + Node source(Arc e) const { return Node(arcs[e.id].source); } + Node target(Arc e) const { return Node(arcs[e.id].target); } + + + void first(Node& node) const { + node.id = first_node; + } + + void next(Node& node) const { + node.id = nodes[node.id].next; + } + + + void first(Arc& arc) const { + int n; + for(n = first_node; + n != -1 && nodes[n].first_out == -1; + n = nodes[n].next) {} + arc.id = (n == -1) ? -1 : nodes[n].first_out; + } + + void next(Arc& arc) const { + if (arcs[arc.id].next_out != -1) { + arc.id = arcs[arc.id].next_out; + } else { + int n; + for(n = nodes[arcs[arc.id].source].next; + n != -1 && nodes[n].first_out == -1; + n = nodes[n].next) {} + arc.id = (n == -1) ? -1 : nodes[n].first_out; + } + } + + void firstOut(Arc &e, const Node& v) const { + e.id = nodes[v.id].first_out; + } + void nextOut(Arc &e) const { + e.id=arcs[e.id].next_out; + } + + void firstIn(Arc &e, const Node& v) const { + e.id = nodes[v.id].first_in; + } + void nextIn(Arc &e) const { + e.id=arcs[e.id].next_in; + } + + + static int id(Node v) { return v.id; } + static int id(Arc e) { return e.id; } + + static Node nodeFromId(int id) { return Node(id);} + static Arc arcFromId(int id) { return Arc(id);} + + bool valid(Node n) const { + return n.id >= 0 && n.id < static_cast(nodes.size()) && + nodes[n.id].prev != -2; + } + + bool valid(Arc a) const { + return a.id >= 0 && a.id < static_cast(arcs.size()) && + arcs[a.id].prev_in != -2; + } + + Node addNode() { + int n; + + if(first_free_node==-1) { + n = nodes.size(); + nodes.push_back(NodeT()); + } else { + n = first_free_node; + first_free_node = nodes[n].next; + } + + nodes[n].next = first_node; + if(first_node != -1) nodes[first_node].prev = n; + first_node = n; + nodes[n].prev = -1; + + nodes[n].first_in = nodes[n].first_out = -1; + + return Node(n); + } + + Arc addArc(Node u, Node v) { + int n; + + if (first_free_arc == -1) { + n = arcs.size(); + arcs.push_back(ArcT()); + } else { + n = first_free_arc; + first_free_arc = arcs[n].next_in; + } + + arcs[n].source = u.id; + arcs[n].target = v.id; + + arcs[n].next_out = nodes[u.id].first_out; + if(nodes[u.id].first_out != -1) { + arcs[nodes[u.id].first_out].prev_out = n; + } + + arcs[n].next_in = nodes[v.id].first_in; + if(nodes[v.id].first_in != -1) { + arcs[nodes[v.id].first_in].prev_in = n; + } + + arcs[n].prev_in = arcs[n].prev_out = -1; + + nodes[u.id].first_out = nodes[v.id].first_in = n; + + return Arc(n); + } + + void erase(const Node& node) { + int n = node.id; + + if(nodes[n].next != -1) { + nodes[nodes[n].next].prev = nodes[n].prev; + } + + if(nodes[n].prev != -1) { + nodes[nodes[n].prev].next = nodes[n].next; + } else { + first_node = nodes[n].next; + } + + nodes[n].next = first_free_node; + first_free_node = n; + nodes[n].prev = -2; + + } + + void erase(const Arc& arc) { + int n = arc.id; + + if(arcs[n].next_in!=-1) { + arcs[arcs[n].next_in].prev_in = arcs[n].prev_in; + } + + if(arcs[n].prev_in!=-1) { + arcs[arcs[n].prev_in].next_in = arcs[n].next_in; + } else { + nodes[arcs[n].target].first_in = arcs[n].next_in; + } + + + if(arcs[n].next_out!=-1) { + arcs[arcs[n].next_out].prev_out = arcs[n].prev_out; + } + + if(arcs[n].prev_out!=-1) { + arcs[arcs[n].prev_out].next_out = arcs[n].next_out; + } else { + nodes[arcs[n].source].first_out = arcs[n].next_out; + } + + arcs[n].next_in = first_free_arc; + first_free_arc = n; + arcs[n].prev_in = -2; + } + + void clear() { + arcs.clear(); + nodes.clear(); + first_node = first_free_node = first_free_arc = -1; + } + + protected: + void changeTarget(Arc e, Node n) + { + if(arcs[e.id].next_in != -1) + arcs[arcs[e.id].next_in].prev_in = arcs[e.id].prev_in; + if(arcs[e.id].prev_in != -1) + arcs[arcs[e.id].prev_in].next_in = arcs[e.id].next_in; + else nodes[arcs[e.id].target].first_in = arcs[e.id].next_in; + if (nodes[n.id].first_in != -1) { + arcs[nodes[n.id].first_in].prev_in = e.id; + } + arcs[e.id].target = n.id; + arcs[e.id].prev_in = -1; + arcs[e.id].next_in = nodes[n.id].first_in; + nodes[n.id].first_in = e.id; + } + void changeSource(Arc e, Node n) + { + if(arcs[e.id].next_out != -1) + arcs[arcs[e.id].next_out].prev_out = arcs[e.id].prev_out; + if(arcs[e.id].prev_out != -1) + arcs[arcs[e.id].prev_out].next_out = arcs[e.id].next_out; + else nodes[arcs[e.id].source].first_out = arcs[e.id].next_out; + if (nodes[n.id].first_out != -1) { + arcs[nodes[n.id].first_out].prev_out = e.id; + } + arcs[e.id].source = n.id; + arcs[e.id].prev_out = -1; + arcs[e.id].next_out = nodes[n.id].first_out; + nodes[n.id].first_out = e.id; + } + + }; + + typedef DigraphExtender ExtendedListDigraphBase; + + /// \addtogroup graphs + /// @{ + + ///A general directed graph structure. + + ///\ref ListDigraph is a versatile and fast directed graph + ///implementation based on linked lists that are stored in + ///\c std::vector structures. + /// + ///This type fully conforms to the \ref concepts::Digraph "Digraph concept" + ///and it also provides several useful additional functionalities. + ///Most of its member functions and nested classes are documented + ///only in the concept class. + /// + ///This class provides only linear time counting for nodes and arcs. + /// + ///\sa concepts::Digraph + ///\sa ListGraph + class ListDigraph : public ExtendedListDigraphBase { + typedef ExtendedListDigraphBase Parent; + + private: + /// Digraphs are \e not copy constructible. Use DigraphCopy instead. + ListDigraph(const ListDigraph &) :ExtendedListDigraphBase() {}; + /// \brief Assignment of a digraph to another one is \e not allowed. + /// Use DigraphCopy instead. + void operator=(const ListDigraph &) {} + public: + + /// Constructor + + /// Constructor. + /// + ListDigraph() {} + + ///Add a new node to the digraph. + + ///This function adds a new node to the digraph. + ///\return The new node. + Node addNode() { return Parent::addNode(); } + + ///Add a new arc to the digraph. + + ///This function adds a new arc to the digraph with source node \c s + ///and target node \c t. + ///\return The new arc. + Arc addArc(Node s, Node t) { + return Parent::addArc(s, t); + } + + ///\brief Erase a node from the digraph. + /// + ///This function erases the given node along with its outgoing and + ///incoming arcs from the digraph. + /// + ///\note All iterators referencing the removed node or the connected + ///arcs are invalidated, of course. + void erase(Node n) { Parent::erase(n); } + + ///\brief Erase an arc from the digraph. + /// + ///This function erases the given arc from the digraph. + /// + ///\note All iterators referencing the removed arc are invalidated, + ///of course. + void erase(Arc a) { Parent::erase(a); } + + /// Node validity check + + /// This function gives back \c true if the given node is valid, + /// i.e. it is a real node of the digraph. + /// + /// \warning A removed node could become valid again if new nodes are + /// added to the digraph. + bool valid(Node n) const { return Parent::valid(n); } + + /// Arc validity check + + /// This function gives back \c true if the given arc is valid, + /// i.e. it is a real arc of the digraph. + /// + /// \warning A removed arc could become valid again if new arcs are + /// added to the digraph. + bool valid(Arc a) const { return Parent::valid(a); } + + /// Change the target node of an arc + + /// This function changes the target node of the given arc \c a to \c n. + /// + ///\note \c ArcIt and \c OutArcIt iterators referencing the changed + ///arc remain valid, but \c InArcIt iterators are invalidated. + /// + ///\warning This functionality cannot be used together with the Snapshot + ///feature. + void changeTarget(Arc a, Node n) { + Parent::changeTarget(a,n); + } + /// Change the source node of an arc + + /// This function changes the source node of the given arc \c a to \c n. + /// + ///\note \c InArcIt iterators referencing the changed arc remain + ///valid, but \c ArcIt and \c OutArcIt iterators are invalidated. + /// + ///\warning This functionality cannot be used together with the Snapshot + ///feature. + void changeSource(Arc a, Node n) { + Parent::changeSource(a,n); + } + + /// Reverse the direction of an arc. + + /// This function reverses the direction of the given arc. + ///\note \c ArcIt, \c OutArcIt and \c InArcIt iterators referencing + ///the changed arc are invalidated. + /// + ///\warning This functionality cannot be used together with the Snapshot + ///feature. + void reverseArc(Arc a) { + Node t=target(a); + changeTarget(a,source(a)); + changeSource(a,t); + } + + ///Contract two nodes. + + ///This function contracts the given two nodes. + ///Node \c v is removed, but instead of deleting its + ///incident arcs, they are joined to node \c u. + ///If the last parameter \c r is \c true (this is the default value), + ///then the newly created loops are removed. + /// + ///\note The moved arcs are joined to node \c u using changeSource() + ///or changeTarget(), thus \c ArcIt and \c OutArcIt iterators are + ///invalidated for the outgoing arcs of node \c v and \c InArcIt + ///iterators are invalidated for the incoming arcs of \c v. + ///Moreover all iterators referencing node \c v or the removed + ///loops are also invalidated. Other iterators remain valid. + /// + ///\warning This functionality cannot be used together with the Snapshot + ///feature. + void contract(Node u, Node v, bool r = true) + { + for(OutArcIt e(*this,v);e!=INVALID;) { + OutArcIt f=e; + ++f; + if(r && target(e)==u) erase(e); + else changeSource(e,u); + e=f; + } + for(InArcIt e(*this,v);e!=INVALID;) { + InArcIt f=e; + ++f; + if(r && source(e)==u) erase(e); + else changeTarget(e,u); + e=f; + } + erase(v); + } + + ///Split a node. + + ///This function splits the given node. First, a new node is added + ///to the digraph, then the source of each outgoing arc of node \c n + ///is moved to this new node. + ///If the second parameter \c connect is \c true (this is the default + ///value), then a new arc from node \c n to the newly created node + ///is also added. + ///\return The newly created node. + /// + ///\note All iterators remain valid. + /// + ///\warning This functionality cannot be used together with the + ///Snapshot feature. + Node split(Node n, bool connect = true) { + Node b = addNode(); + nodes[b.id].first_out=nodes[n.id].first_out; + nodes[n.id].first_out=-1; + for(int i=nodes[b.id].first_out; i!=-1; i=arcs[i].next_out) { + arcs[i].source=b.id; + } + if (connect) addArc(n,b); + return b; + } + + ///Split an arc. + + ///This function splits the given arc. First, a new node \c v is + ///added to the digraph, then the target node of the original arc + ///is set to \c v. Finally, an arc from \c v to the original target + ///is added. + ///\return The newly created node. + /// + ///\note \c InArcIt iterators referencing the original arc are + ///invalidated. Other iterators remain valid. + /// + ///\warning This functionality cannot be used together with the + ///Snapshot feature. + Node split(Arc a) { + Node v = addNode(); + addArc(v,target(a)); + changeTarget(a,v); + return v; + } + + ///Clear the digraph. + + ///This function erases all nodes and arcs from the digraph. + /// + ///\note All iterators of the digraph are invalidated, of course. + void clear() { + Parent::clear(); + } + + /// Reserve memory for nodes. + + /// Using this function, it is possible to avoid superfluous memory + /// allocation: if you know that the digraph you want to build will + /// be large (e.g. it will contain millions of nodes and/or arcs), + /// then it is worth reserving space for this amount before starting + /// to build the digraph. + /// \sa reserveArc() + void reserveNode(int n) { nodes.reserve(n); }; + + /// Reserve memory for arcs. + + /// Using this function, it is possible to avoid superfluous memory + /// allocation: if you know that the digraph you want to build will + /// be large (e.g. it will contain millions of nodes and/or arcs), + /// then it is worth reserving space for this amount before starting + /// to build the digraph. + /// \sa reserveNode() + void reserveArc(int m) { arcs.reserve(m); }; + + /// \brief Class to make a snapshot of the digraph and restore + /// it later. + /// + /// Class to make a snapshot of the digraph and restore it later. + /// + /// The newly added nodes and arcs can be removed using the + /// restore() function. + /// + /// \note After a state is restored, you cannot restore a later state, + /// i.e. you cannot add the removed nodes and arcs again using + /// another Snapshot instance. + /// + /// \warning Node and arc deletions and other modifications (e.g. + /// reversing, contracting, splitting arcs or nodes) cannot be + /// restored. These events invalidate the snapshot. + /// However, the arcs and nodes that were added to the digraph after + /// making the current snapshot can be removed without invalidating it. + class Snapshot { + protected: + + typedef Parent::NodeNotifier NodeNotifier; + + class NodeObserverProxy : public NodeNotifier::ObserverBase { + public: + + NodeObserverProxy(Snapshot& _snapshot) + : snapshot(_snapshot) {} + + using NodeNotifier::ObserverBase::attach; + using NodeNotifier::ObserverBase::detach; + using NodeNotifier::ObserverBase::attached; + + protected: + + virtual void add(const Node& node) { + snapshot.addNode(node); + } + virtual void add(const std::vector& nodes) { + for (int i = nodes.size() - 1; i >= 0; ++i) { + snapshot.addNode(nodes[i]); + } + } + virtual void erase(const Node& node) { + snapshot.eraseNode(node); + } + virtual void erase(const std::vector& nodes) { + for (int i = 0; i < int(nodes.size()); ++i) { + snapshot.eraseNode(nodes[i]); + } + } + virtual void build() { + Node node; + std::vector nodes; + for (notifier()->first(node); node != INVALID; + notifier()->next(node)) { + nodes.push_back(node); + } + for (int i = nodes.size() - 1; i >= 0; --i) { + snapshot.addNode(nodes[i]); + } + } + virtual void clear() { + Node node; + for (notifier()->first(node); node != INVALID; + notifier()->next(node)) { + snapshot.eraseNode(node); + } + } + + Snapshot& snapshot; + }; + + class ArcObserverProxy : public ArcNotifier::ObserverBase { + public: + + ArcObserverProxy(Snapshot& _snapshot) + : snapshot(_snapshot) {} + + using ArcNotifier::ObserverBase::attach; + using ArcNotifier::ObserverBase::detach; + using ArcNotifier::ObserverBase::attached; + + protected: + + virtual void add(const Arc& arc) { + snapshot.addArc(arc); + } + virtual void add(const std::vector& arcs) { + for (int i = arcs.size() - 1; i >= 0; ++i) { + snapshot.addArc(arcs[i]); + } + } + virtual void erase(const Arc& arc) { + snapshot.eraseArc(arc); + } + virtual void erase(const std::vector& arcs) { + for (int i = 0; i < int(arcs.size()); ++i) { + snapshot.eraseArc(arcs[i]); + } + } + virtual void build() { + Arc arc; + std::vector arcs; + for (notifier()->first(arc); arc != INVALID; + notifier()->next(arc)) { + arcs.push_back(arc); + } + for (int i = arcs.size() - 1; i >= 0; --i) { + snapshot.addArc(arcs[i]); + } + } + virtual void clear() { + Arc arc; + for (notifier()->first(arc); arc != INVALID; + notifier()->next(arc)) { + snapshot.eraseArc(arc); + } + } + + Snapshot& snapshot; + }; + + ListDigraph *digraph; + + NodeObserverProxy node_observer_proxy; + ArcObserverProxy arc_observer_proxy; + + std::list added_nodes; + std::list added_arcs; + + + void addNode(const Node& node) { + added_nodes.push_front(node); + } + void eraseNode(const Node& node) { + std::list::iterator it = + std::find(added_nodes.begin(), added_nodes.end(), node); + if (it == added_nodes.end()) { + clear(); + arc_observer_proxy.detach(); + throw NodeNotifier::ImmediateDetach(); + } else { + added_nodes.erase(it); + } + } + + void addArc(const Arc& arc) { + added_arcs.push_front(arc); + } + void eraseArc(const Arc& arc) { + std::list::iterator it = + std::find(added_arcs.begin(), added_arcs.end(), arc); + if (it == added_arcs.end()) { + clear(); + node_observer_proxy.detach(); + throw ArcNotifier::ImmediateDetach(); + } else { + added_arcs.erase(it); + } + } + + void attach(ListDigraph &_digraph) { + digraph = &_digraph; + node_observer_proxy.attach(digraph->notifier(Node())); + arc_observer_proxy.attach(digraph->notifier(Arc())); + } + + void detach() { + node_observer_proxy.detach(); + arc_observer_proxy.detach(); + } + + bool attached() const { + return node_observer_proxy.attached(); + } + + void clear() { + added_nodes.clear(); + added_arcs.clear(); + } + + public: + + /// \brief Default constructor. + /// + /// Default constructor. + /// You have to call save() to actually make a snapshot. + Snapshot() + : digraph(0), node_observer_proxy(*this), + arc_observer_proxy(*this) {} + + /// \brief Constructor that immediately makes a snapshot. + /// + /// This constructor immediately makes a snapshot of the given digraph. + Snapshot(ListDigraph &gr) + : node_observer_proxy(*this), + arc_observer_proxy(*this) { + attach(gr); + } + + /// \brief Make a snapshot. + /// + /// This function makes a snapshot of the given digraph. + /// It can be called more than once. In case of a repeated + /// call, the previous snapshot gets lost. + void save(ListDigraph &gr) { + if (attached()) { + detach(); + clear(); + } + attach(gr); + } + + /// \brief Undo the changes until the last snapshot. + /// + /// This function undos the changes until the last snapshot + /// created by save() or Snapshot(ListDigraph&). + /// + /// \warning This method invalidates the snapshot, i.e. repeated + /// restoring is not supported unless you call save() again. + void restore() { + detach(); + for(std::list::iterator it = added_arcs.begin(); + it != added_arcs.end(); ++it) { + digraph->erase(*it); + } + for(std::list::iterator it = added_nodes.begin(); + it != added_nodes.end(); ++it) { + digraph->erase(*it); + } + clear(); + } + + /// \brief Returns \c true if the snapshot is valid. + /// + /// This function returns \c true if the snapshot is valid. + bool valid() const { + return attached(); + } + }; + + }; + + ///@} + + class ListGraphBase { + + protected: + + struct NodeT { + int first_out; + int prev, next; + }; + + struct ArcT { + int target; + int prev_out, next_out; + }; + + std::vector nodes; + + int first_node; + + int first_free_node; + + std::vector arcs; + + int first_free_arc; + + public: + + typedef ListGraphBase Graph; + + class Node { + friend class ListGraphBase; + protected: + + int id; + explicit Node(int pid) { id = pid;} + + public: + Node() {} + Node (Invalid) { id = -1; } + bool operator==(const Node& node) const {return id == node.id;} + bool operator!=(const Node& node) const {return id != node.id;} + bool operator<(const Node& node) const {return id < node.id;} + }; + + class Edge { + friend class ListGraphBase; + protected: + + int id; + explicit Edge(int pid) { id = pid;} + + public: + Edge() {} + Edge (Invalid) { id = -1; } + bool operator==(const Edge& edge) const {return id == edge.id;} + bool operator!=(const Edge& edge) const {return id != edge.id;} + bool operator<(const Edge& edge) const {return id < edge.id;} + }; + + class Arc { + friend class ListGraphBase; + protected: + + int id; + explicit Arc(int pid) { id = pid;} + + public: + operator Edge() const { + return id != -1 ? edgeFromId(id / 2) : INVALID; + } + + Arc() {} + Arc (Invalid) { id = -1; } + bool operator==(const Arc& arc) const {return id == arc.id;} + bool operator!=(const Arc& arc) const {return id != arc.id;} + bool operator<(const Arc& arc) const {return id < arc.id;} + }; + + ListGraphBase() + : nodes(), first_node(-1), + first_free_node(-1), arcs(), first_free_arc(-1) {} + + + int maxNodeId() const { return nodes.size()-1; } + int maxEdgeId() const { return arcs.size() / 2 - 1; } + int maxArcId() const { return arcs.size()-1; } + + Node source(Arc e) const { return Node(arcs[e.id ^ 1].target); } + Node target(Arc e) const { return Node(arcs[e.id].target); } + + Node u(Edge e) const { return Node(arcs[2 * e.id].target); } + Node v(Edge e) const { return Node(arcs[2 * e.id + 1].target); } + + static bool direction(Arc e) { + return (e.id & 1) == 1; + } + + static Arc direct(Edge e, bool d) { + return Arc(e.id * 2 + (d ? 1 : 0)); + } + + void first(Node& node) const { + node.id = first_node; + } + + void next(Node& node) const { + node.id = nodes[node.id].next; + } + + void first(Arc& e) const { + int n = first_node; + while (n != -1 && nodes[n].first_out == -1) { + n = nodes[n].next; + } + e.id = (n == -1) ? -1 : nodes[n].first_out; + } + + void next(Arc& e) const { + if (arcs[e.id].next_out != -1) { + e.id = arcs[e.id].next_out; + } else { + int n = nodes[arcs[e.id ^ 1].target].next; + while(n != -1 && nodes[n].first_out == -1) { + n = nodes[n].next; + } + e.id = (n == -1) ? -1 : nodes[n].first_out; + } + } + + void first(Edge& e) const { + int n = first_node; + while (n != -1) { + e.id = nodes[n].first_out; + while ((e.id & 1) != 1) { + e.id = arcs[e.id].next_out; + } + if (e.id != -1) { + e.id /= 2; + return; + } + n = nodes[n].next; + } + e.id = -1; + } + + void next(Edge& e) const { + int n = arcs[e.id * 2].target; + e.id = arcs[(e.id * 2) | 1].next_out; + while ((e.id & 1) != 1) { + e.id = arcs[e.id].next_out; + } + if (e.id != -1) { + e.id /= 2; + return; + } + n = nodes[n].next; + while (n != -1) { + e.id = nodes[n].first_out; + while ((e.id & 1) != 1) { + e.id = arcs[e.id].next_out; + } + if (e.id != -1) { + e.id /= 2; + return; + } + n = nodes[n].next; + } + e.id = -1; + } + + void firstOut(Arc &e, const Node& v) const { + e.id = nodes[v.id].first_out; + } + void nextOut(Arc &e) const { + e.id = arcs[e.id].next_out; + } + + void firstIn(Arc &e, const Node& v) const { + e.id = ((nodes[v.id].first_out) ^ 1); + if (e.id == -2) e.id = -1; + } + void nextIn(Arc &e) const { + e.id = ((arcs[e.id ^ 1].next_out) ^ 1); + if (e.id == -2) e.id = -1; + } + + void firstInc(Edge &e, bool& d, const Node& v) const { + int a = nodes[v.id].first_out; + if (a != -1 ) { + e.id = a / 2; + d = ((a & 1) == 1); + } else { + e.id = -1; + d = true; + } + } + void nextInc(Edge &e, bool& d) const { + int a = (arcs[(e.id * 2) | (d ? 1 : 0)].next_out); + if (a != -1 ) { + e.id = a / 2; + d = ((a & 1) == 1); + } else { + e.id = -1; + d = true; + } + } + + static int id(Node v) { return v.id; } + static int id(Arc e) { return e.id; } + static int id(Edge e) { return e.id; } + + static Node nodeFromId(int id) { return Node(id);} + static Arc arcFromId(int id) { return Arc(id);} + static Edge edgeFromId(int id) { return Edge(id);} + + bool valid(Node n) const { + return n.id >= 0 && n.id < static_cast(nodes.size()) && + nodes[n.id].prev != -2; + } + + bool valid(Arc a) const { + return a.id >= 0 && a.id < static_cast(arcs.size()) && + arcs[a.id].prev_out != -2; + } + + bool valid(Edge e) const { + return e.id >= 0 && 2 * e.id < static_cast(arcs.size()) && + arcs[2 * e.id].prev_out != -2; + } + + Node addNode() { + int n; + + if(first_free_node==-1) { + n = nodes.size(); + nodes.push_back(NodeT()); + } else { + n = first_free_node; + first_free_node = nodes[n].next; + } + + nodes[n].next = first_node; + if (first_node != -1) nodes[first_node].prev = n; + first_node = n; + nodes[n].prev = -1; + + nodes[n].first_out = -1; + + return Node(n); + } + + Edge addEdge(Node u, Node v) { + int n; + + if (first_free_arc == -1) { + n = arcs.size(); + arcs.push_back(ArcT()); + arcs.push_back(ArcT()); + } else { + n = first_free_arc; + first_free_arc = arcs[n].next_out; + } + + arcs[n].target = u.id; + arcs[n | 1].target = v.id; + + arcs[n].next_out = nodes[v.id].first_out; + if (nodes[v.id].first_out != -1) { + arcs[nodes[v.id].first_out].prev_out = n; + } + arcs[n].prev_out = -1; + nodes[v.id].first_out = n; + + arcs[n | 1].next_out = nodes[u.id].first_out; + if (nodes[u.id].first_out != -1) { + arcs[nodes[u.id].first_out].prev_out = (n | 1); + } + arcs[n | 1].prev_out = -1; + nodes[u.id].first_out = (n | 1); + + return Edge(n / 2); + } + + void erase(const Node& node) { + int n = node.id; + + if(nodes[n].next != -1) { + nodes[nodes[n].next].prev = nodes[n].prev; + } + + if(nodes[n].prev != -1) { + nodes[nodes[n].prev].next = nodes[n].next; + } else { + first_node = nodes[n].next; + } + + nodes[n].next = first_free_node; + first_free_node = n; + nodes[n].prev = -2; + } + + void erase(const Edge& edge) { + int n = edge.id * 2; + + if (arcs[n].next_out != -1) { + arcs[arcs[n].next_out].prev_out = arcs[n].prev_out; + } + + if (arcs[n].prev_out != -1) { + arcs[arcs[n].prev_out].next_out = arcs[n].next_out; + } else { + nodes[arcs[n | 1].target].first_out = arcs[n].next_out; + } + + if (arcs[n | 1].next_out != -1) { + arcs[arcs[n | 1].next_out].prev_out = arcs[n | 1].prev_out; + } + + if (arcs[n | 1].prev_out != -1) { + arcs[arcs[n | 1].prev_out].next_out = arcs[n | 1].next_out; + } else { + nodes[arcs[n].target].first_out = arcs[n | 1].next_out; + } + + arcs[n].next_out = first_free_arc; + first_free_arc = n; + arcs[n].prev_out = -2; + arcs[n | 1].prev_out = -2; + + } + + void clear() { + arcs.clear(); + nodes.clear(); + first_node = first_free_node = first_free_arc = -1; + } + + protected: + + void changeV(Edge e, Node n) { + if(arcs[2 * e.id].next_out != -1) { + arcs[arcs[2 * e.id].next_out].prev_out = arcs[2 * e.id].prev_out; + } + if(arcs[2 * e.id].prev_out != -1) { + arcs[arcs[2 * e.id].prev_out].next_out = + arcs[2 * e.id].next_out; + } else { + nodes[arcs[(2 * e.id) | 1].target].first_out = + arcs[2 * e.id].next_out; + } + + if (nodes[n.id].first_out != -1) { + arcs[nodes[n.id].first_out].prev_out = 2 * e.id; + } + arcs[(2 * e.id) | 1].target = n.id; + arcs[2 * e.id].prev_out = -1; + arcs[2 * e.id].next_out = nodes[n.id].first_out; + nodes[n.id].first_out = 2 * e.id; + } + + void changeU(Edge e, Node n) { + if(arcs[(2 * e.id) | 1].next_out != -1) { + arcs[arcs[(2 * e.id) | 1].next_out].prev_out = + arcs[(2 * e.id) | 1].prev_out; + } + if(arcs[(2 * e.id) | 1].prev_out != -1) { + arcs[arcs[(2 * e.id) | 1].prev_out].next_out = + arcs[(2 * e.id) | 1].next_out; + } else { + nodes[arcs[2 * e.id].target].first_out = + arcs[(2 * e.id) | 1].next_out; + } + + if (nodes[n.id].first_out != -1) { + arcs[nodes[n.id].first_out].prev_out = ((2 * e.id) | 1); + } + arcs[2 * e.id].target = n.id; + arcs[(2 * e.id) | 1].prev_out = -1; + arcs[(2 * e.id) | 1].next_out = nodes[n.id].first_out; + nodes[n.id].first_out = ((2 * e.id) | 1); + } + + }; + + typedef GraphExtender ExtendedListGraphBase; + + + /// \addtogroup graphs + /// @{ + + ///A general undirected graph structure. + + ///\ref ListGraph is a versatile and fast undirected graph + ///implementation based on linked lists that are stored in + ///\c std::vector structures. + /// + ///This type fully conforms to the \ref concepts::Graph "Graph concept" + ///and it also provides several useful additional functionalities. + ///Most of its member functions and nested classes are documented + ///only in the concept class. + /// + ///This class provides only linear time counting for nodes, edges and arcs. + /// + ///\sa concepts::Graph + ///\sa ListDigraph + class ListGraph : public ExtendedListGraphBase { + typedef ExtendedListGraphBase Parent; + + private: + /// Graphs are \e not copy constructible. Use GraphCopy instead. + ListGraph(const ListGraph &) :ExtendedListGraphBase() {}; + /// \brief Assignment of a graph to another one is \e not allowed. + /// Use GraphCopy instead. + void operator=(const ListGraph &) {} + public: + /// Constructor + + /// Constructor. + /// + ListGraph() {} + + typedef Parent::OutArcIt IncEdgeIt; + + /// \brief Add a new node to the graph. + /// + /// This function adds a new node to the graph. + /// \return The new node. + Node addNode() { return Parent::addNode(); } + + /// \brief Add a new edge to the graph. + /// + /// This function adds a new edge to the graph between nodes + /// \c u and \c v with inherent orientation from node \c u to + /// node \c v. + /// \return The new edge. + Edge addEdge(Node u, Node v) { + return Parent::addEdge(u, v); + } + + ///\brief Erase a node from the graph. + /// + /// This function erases the given node along with its incident arcs + /// from the graph. + /// + /// \note All iterators referencing the removed node or the incident + /// edges are invalidated, of course. + void erase(Node n) { Parent::erase(n); } + + ///\brief Erase an edge from the graph. + /// + /// This function erases the given edge from the graph. + /// + /// \note All iterators referencing the removed edge are invalidated, + /// of course. + void erase(Edge e) { Parent::erase(e); } + /// Node validity check + + /// This function gives back \c true if the given node is valid, + /// i.e. it is a real node of the graph. + /// + /// \warning A removed node could become valid again if new nodes are + /// added to the graph. + bool valid(Node n) const { return Parent::valid(n); } + /// Edge validity check + + /// This function gives back \c true if the given edge is valid, + /// i.e. it is a real edge of the graph. + /// + /// \warning A removed edge could become valid again if new edges are + /// added to the graph. + bool valid(Edge e) const { return Parent::valid(e); } + /// Arc validity check + + /// This function gives back \c true if the given arc is valid, + /// i.e. it is a real arc of the graph. + /// + /// \warning A removed arc could become valid again if new edges are + /// added to the graph. + bool valid(Arc a) const { return Parent::valid(a); } + + /// \brief Change the first node of an edge. + /// + /// This function changes the first node of the given edge \c e to \c n. + /// + ///\note \c EdgeIt and \c ArcIt iterators referencing the + ///changed edge are invalidated and all other iterators whose + ///base node is the changed node are also invalidated. + /// + ///\warning This functionality cannot be used together with the + ///Snapshot feature. + void changeU(Edge e, Node n) { + Parent::changeU(e,n); + } + /// \brief Change the second node of an edge. + /// + /// This function changes the second node of the given edge \c e to \c n. + /// + ///\note \c EdgeIt iterators referencing the changed edge remain + ///valid, but \c ArcIt iterators referencing the changed edge and + ///all other iterators whose base node is the changed node are also + ///invalidated. + /// + ///\warning This functionality cannot be used together with the + ///Snapshot feature. + void changeV(Edge e, Node n) { + Parent::changeV(e,n); + } + + /// \brief Contract two nodes. + /// + /// This function contracts the given two nodes. + /// Node \c b is removed, but instead of deleting + /// its incident edges, they are joined to node \c a. + /// If the last parameter \c r is \c true (this is the default value), + /// then the newly created loops are removed. + /// + /// \note The moved edges are joined to node \c a using changeU() + /// or changeV(), thus all edge and arc iterators whose base node is + /// \c b are invalidated. + /// Moreover all iterators referencing node \c b or the removed + /// loops are also invalidated. Other iterators remain valid. + /// + ///\warning This functionality cannot be used together with the + ///Snapshot feature. + void contract(Node a, Node b, bool r = true) { + for(IncEdgeIt e(*this, b); e!=INVALID;) { + IncEdgeIt f = e; ++f; + if (r && runningNode(e) == a) { + erase(e); + } else if (u(e) == b) { + changeU(e, a); + } else { + changeV(e, a); + } + e = f; + } + erase(b); + } + + ///Clear the graph. + + ///This function erases all nodes and arcs from the graph. + /// + ///\note All iterators of the graph are invalidated, of course. + void clear() { + Parent::clear(); + } + + /// Reserve memory for nodes. + + /// Using this function, it is possible to avoid superfluous memory + /// allocation: if you know that the graph you want to build will + /// be large (e.g. it will contain millions of nodes and/or edges), + /// then it is worth reserving space for this amount before starting + /// to build the graph. + /// \sa reserveEdge() + void reserveNode(int n) { nodes.reserve(n); }; + + /// Reserve memory for edges. + + /// Using this function, it is possible to avoid superfluous memory + /// allocation: if you know that the graph you want to build will + /// be large (e.g. it will contain millions of nodes and/or edges), + /// then it is worth reserving space for this amount before starting + /// to build the graph. + /// \sa reserveNode() + void reserveEdge(int m) { arcs.reserve(2 * m); }; + + /// \brief Class to make a snapshot of the graph and restore + /// it later. + /// + /// Class to make a snapshot of the graph and restore it later. + /// + /// The newly added nodes and edges can be removed + /// using the restore() function. + /// + /// \note After a state is restored, you cannot restore a later state, + /// i.e. you cannot add the removed nodes and edges again using + /// another Snapshot instance. + /// + /// \warning Node and edge deletions and other modifications + /// (e.g. changing the end-nodes of edges or contracting nodes) + /// cannot be restored. These events invalidate the snapshot. + /// However, the edges and nodes that were added to the graph after + /// making the current snapshot can be removed without invalidating it. + class Snapshot { + protected: + + typedef Parent::NodeNotifier NodeNotifier; + + class NodeObserverProxy : public NodeNotifier::ObserverBase { + public: + + NodeObserverProxy(Snapshot& _snapshot) + : snapshot(_snapshot) {} + + using NodeNotifier::ObserverBase::attach; + using NodeNotifier::ObserverBase::detach; + using NodeNotifier::ObserverBase::attached; + + protected: + + virtual void add(const Node& node) { + snapshot.addNode(node); + } + virtual void add(const std::vector& nodes) { + for (int i = nodes.size() - 1; i >= 0; ++i) { + snapshot.addNode(nodes[i]); + } + } + virtual void erase(const Node& node) { + snapshot.eraseNode(node); + } + virtual void erase(const std::vector& nodes) { + for (int i = 0; i < int(nodes.size()); ++i) { + snapshot.eraseNode(nodes[i]); + } + } + virtual void build() { + Node node; + std::vector nodes; + for (notifier()->first(node); node != INVALID; + notifier()->next(node)) { + nodes.push_back(node); + } + for (int i = nodes.size() - 1; i >= 0; --i) { + snapshot.addNode(nodes[i]); + } + } + virtual void clear() { + Node node; + for (notifier()->first(node); node != INVALID; + notifier()->next(node)) { + snapshot.eraseNode(node); + } + } + + Snapshot& snapshot; + }; + + class EdgeObserverProxy : public EdgeNotifier::ObserverBase { + public: + + EdgeObserverProxy(Snapshot& _snapshot) + : snapshot(_snapshot) {} + + using EdgeNotifier::ObserverBase::attach; + using EdgeNotifier::ObserverBase::detach; + using EdgeNotifier::ObserverBase::attached; + + protected: + + virtual void add(const Edge& edge) { + snapshot.addEdge(edge); + } + virtual void add(const std::vector& edges) { + for (int i = edges.size() - 1; i >= 0; ++i) { + snapshot.addEdge(edges[i]); + } + } + virtual void erase(const Edge& edge) { + snapshot.eraseEdge(edge); + } + virtual void erase(const std::vector& edges) { + for (int i = 0; i < int(edges.size()); ++i) { + snapshot.eraseEdge(edges[i]); + } + } + virtual void build() { + Edge edge; + std::vector edges; + for (notifier()->first(edge); edge != INVALID; + notifier()->next(edge)) { + edges.push_back(edge); + } + for (int i = edges.size() - 1; i >= 0; --i) { + snapshot.addEdge(edges[i]); + } + } + virtual void clear() { + Edge edge; + for (notifier()->first(edge); edge != INVALID; + notifier()->next(edge)) { + snapshot.eraseEdge(edge); + } + } + + Snapshot& snapshot; + }; + + ListGraph *graph; + + NodeObserverProxy node_observer_proxy; + EdgeObserverProxy edge_observer_proxy; + + std::list added_nodes; + std::list added_edges; + + + void addNode(const Node& node) { + added_nodes.push_front(node); + } + void eraseNode(const Node& node) { + std::list::iterator it = + std::find(added_nodes.begin(), added_nodes.end(), node); + if (it == added_nodes.end()) { + clear(); + edge_observer_proxy.detach(); + throw NodeNotifier::ImmediateDetach(); + } else { + added_nodes.erase(it); + } + } + + void addEdge(const Edge& edge) { + added_edges.push_front(edge); + } + void eraseEdge(const Edge& edge) { + std::list::iterator it = + std::find(added_edges.begin(), added_edges.end(), edge); + if (it == added_edges.end()) { + clear(); + node_observer_proxy.detach(); + throw EdgeNotifier::ImmediateDetach(); + } else { + added_edges.erase(it); + } + } + + void attach(ListGraph &_graph) { + graph = &_graph; + node_observer_proxy.attach(graph->notifier(Node())); + edge_observer_proxy.attach(graph->notifier(Edge())); + } + + void detach() { + node_observer_proxy.detach(); + edge_observer_proxy.detach(); + } + + bool attached() const { + return node_observer_proxy.attached(); + } + + void clear() { + added_nodes.clear(); + added_edges.clear(); + } + + public: + + /// \brief Default constructor. + /// + /// Default constructor. + /// You have to call save() to actually make a snapshot. + Snapshot() + : graph(0), node_observer_proxy(*this), + edge_observer_proxy(*this) {} + + /// \brief Constructor that immediately makes a snapshot. + /// + /// This constructor immediately makes a snapshot of the given graph. + Snapshot(ListGraph &gr) + : node_observer_proxy(*this), + edge_observer_proxy(*this) { + attach(gr); + } + + /// \brief Make a snapshot. + /// + /// This function makes a snapshot of the given graph. + /// It can be called more than once. In case of a repeated + /// call, the previous snapshot gets lost. + void save(ListGraph &gr) { + if (attached()) { + detach(); + clear(); + } + attach(gr); + } + + /// \brief Undo the changes until the last snapshot. + /// + /// This function undos the changes until the last snapshot + /// created by save() or Snapshot(ListGraph&). + /// + /// \warning This method invalidates the snapshot, i.e. repeated + /// restoring is not supported unless you call save() again. + void restore() { + detach(); + for(std::list::iterator it = added_edges.begin(); + it != added_edges.end(); ++it) { + graph->erase(*it); + } + for(std::list::iterator it = added_nodes.begin(); + it != added_nodes.end(); ++it) { + graph->erase(*it); + } + clear(); + } + + /// \brief Returns \c true if the snapshot is valid. + /// + /// This function returns \c true if the snapshot is valid. + bool valid() const { + return attached(); + } + }; + }; + + /// @} + + class ListBpGraphBase { + + protected: + + struct NodeT { + int first_out; + int prev, next; + int partition_prev, partition_next; + int partition_index; + bool red; + }; + + struct ArcT { + int target; + int prev_out, next_out; + }; + + std::vector nodes; + + int first_node, first_red, first_blue; + int max_red, max_blue; + + int first_free_red, first_free_blue; + + std::vector arcs; + + int first_free_arc; + + public: + + typedef ListBpGraphBase BpGraph; + + class Node { + friend class ListBpGraphBase; + protected: + + int id; + explicit Node(int pid) { id = pid;} + + public: + Node() {} + Node (Invalid) { id = -1; } + bool operator==(const Node& node) const {return id == node.id;} + bool operator!=(const Node& node) const {return id != node.id;} + bool operator<(const Node& node) const {return id < node.id;} + }; + + class RedNode : public Node { + friend class ListBpGraphBase; + protected: + + explicit RedNode(int pid) : Node(pid) {} + + public: + RedNode() {} + RedNode(const RedNode& node) : Node(node) {} + RedNode(Invalid) : Node(INVALID){} + }; + + class BlueNode : public Node { + friend class ListBpGraphBase; + protected: + + explicit BlueNode(int pid) : Node(pid) {} + + public: + BlueNode() {} + BlueNode(const BlueNode& node) : Node(node) {} + BlueNode(Invalid) : Node(INVALID){} + }; + + class Edge { + friend class ListBpGraphBase; + protected: + + int id; + explicit Edge(int pid) { id = pid;} + + public: + Edge() {} + Edge (Invalid) { id = -1; } + bool operator==(const Edge& edge) const {return id == edge.id;} + bool operator!=(const Edge& edge) const {return id != edge.id;} + bool operator<(const Edge& edge) const {return id < edge.id;} + }; + + class Arc { + friend class ListBpGraphBase; + protected: + + int id; + explicit Arc(int pid) { id = pid;} + + public: + operator Edge() const { + return id != -1 ? edgeFromId(id / 2) : INVALID; + } + + Arc() {} + Arc (Invalid) { id = -1; } + bool operator==(const Arc& arc) const {return id == arc.id;} + bool operator!=(const Arc& arc) const {return id != arc.id;} + bool operator<(const Arc& arc) const {return id < arc.id;} + }; + + ListBpGraphBase() + : nodes(), first_node(-1), + first_red(-1), first_blue(-1), + max_red(-1), max_blue(-1), + first_free_red(-1), first_free_blue(-1), + arcs(), first_free_arc(-1) {} + + + bool red(Node n) const { return nodes[n.id].red; } + bool blue(Node n) const { return !nodes[n.id].red; } + + static RedNode asRedNodeUnsafe(Node n) { return RedNode(n.id); } + static BlueNode asBlueNodeUnsafe(Node n) { return BlueNode(n.id); } + + int maxNodeId() const { return nodes.size()-1; } + int maxRedId() const { return max_red; } + int maxBlueId() const { return max_blue; } + int maxEdgeId() const { return arcs.size() / 2 - 1; } + int maxArcId() const { return arcs.size()-1; } + + Node source(Arc e) const { return Node(arcs[e.id ^ 1].target); } + Node target(Arc e) const { return Node(arcs[e.id].target); } + + RedNode redNode(Edge e) const { + return RedNode(arcs[2 * e.id].target); + } + BlueNode blueNode(Edge e) const { + return BlueNode(arcs[2 * e.id + 1].target); + } + + static bool direction(Arc e) { + return (e.id & 1) == 1; + } + + static Arc direct(Edge e, bool d) { + return Arc(e.id * 2 + (d ? 1 : 0)); + } + + void first(Node& node) const { + node.id = first_node; + } + + void next(Node& node) const { + node.id = nodes[node.id].next; + } + + void first(RedNode& node) const { + node.id = first_red; + } + + void next(RedNode& node) const { + node.id = nodes[node.id].partition_next; + } + + void first(BlueNode& node) const { + node.id = first_blue; + } + + void next(BlueNode& node) const { + node.id = nodes[node.id].partition_next; + } + + void first(Arc& e) const { + int n = first_node; + while (n != -1 && nodes[n].first_out == -1) { + n = nodes[n].next; + } + e.id = (n == -1) ? -1 : nodes[n].first_out; + } + + void next(Arc& e) const { + if (arcs[e.id].next_out != -1) { + e.id = arcs[e.id].next_out; + } else { + int n = nodes[arcs[e.id ^ 1].target].next; + while(n != -1 && nodes[n].first_out == -1) { + n = nodes[n].next; + } + e.id = (n == -1) ? -1 : nodes[n].first_out; + } + } + + void first(Edge& e) const { + int n = first_node; + while (n != -1) { + e.id = nodes[n].first_out; + while ((e.id & 1) != 1) { + e.id = arcs[e.id].next_out; + } + if (e.id != -1) { + e.id /= 2; + return; + } + n = nodes[n].next; + } + e.id = -1; + } + + void next(Edge& e) const { + int n = arcs[e.id * 2].target; + e.id = arcs[(e.id * 2) | 1].next_out; + while ((e.id & 1) != 1) { + e.id = arcs[e.id].next_out; + } + if (e.id != -1) { + e.id /= 2; + return; + } + n = nodes[n].next; + while (n != -1) { + e.id = nodes[n].first_out; + while ((e.id & 1) != 1) { + e.id = arcs[e.id].next_out; + } + if (e.id != -1) { + e.id /= 2; + return; + } + n = nodes[n].next; + } + e.id = -1; + } + + void firstOut(Arc &e, const Node& v) const { + e.id = nodes[v.id].first_out; + } + void nextOut(Arc &e) const { + e.id = arcs[e.id].next_out; + } + + void firstIn(Arc &e, const Node& v) const { + e.id = ((nodes[v.id].first_out) ^ 1); + if (e.id == -2) e.id = -1; + } + void nextIn(Arc &e) const { + e.id = ((arcs[e.id ^ 1].next_out) ^ 1); + if (e.id == -2) e.id = -1; + } + + void firstInc(Edge &e, bool& d, const Node& v) const { + int a = nodes[v.id].first_out; + if (a != -1 ) { + e.id = a / 2; + d = ((a & 1) == 1); + } else { + e.id = -1; + d = true; + } + } + void nextInc(Edge &e, bool& d) const { + int a = (arcs[(e.id * 2) | (d ? 1 : 0)].next_out); + if (a != -1 ) { + e.id = a / 2; + d = ((a & 1) == 1); + } else { + e.id = -1; + d = true; + } + } + + static int id(Node v) { return v.id; } + int id(RedNode v) const { return nodes[v.id].partition_index; } + int id(BlueNode v) const { return nodes[v.id].partition_index; } + static int id(Arc e) { return e.id; } + static int id(Edge e) { return e.id; } + + static Node nodeFromId(int id) { return Node(id);} + static Arc arcFromId(int id) { return Arc(id);} + static Edge edgeFromId(int id) { return Edge(id);} + + bool valid(Node n) const { + return n.id >= 0 && n.id < static_cast(nodes.size()) && + nodes[n.id].prev != -2; + } + + bool valid(Arc a) const { + return a.id >= 0 && a.id < static_cast(arcs.size()) && + arcs[a.id].prev_out != -2; + } + + bool valid(Edge e) const { + return e.id >= 0 && 2 * e.id < static_cast(arcs.size()) && + arcs[2 * e.id].prev_out != -2; + } + + RedNode addRedNode() { + int n; + + if(first_free_red==-1) { + n = nodes.size(); + nodes.push_back(NodeT()); + nodes[n].partition_index = ++max_red; + nodes[n].red = true; + } else { + n = first_free_red; + first_free_red = nodes[n].next; + } + + nodes[n].next = first_node; + if (first_node != -1) nodes[first_node].prev = n; + first_node = n; + nodes[n].prev = -1; + + nodes[n].partition_next = first_red; + if (first_red != -1) nodes[first_red].partition_prev = n; + first_red = n; + nodes[n].partition_prev = -1; + + nodes[n].first_out = -1; + + return RedNode(n); + } + + BlueNode addBlueNode() { + int n; + + if(first_free_blue==-1) { + n = nodes.size(); + nodes.push_back(NodeT()); + nodes[n].partition_index = ++max_blue; + nodes[n].red = false; + } else { + n = first_free_blue; + first_free_blue = nodes[n].next; + } + + nodes[n].next = first_node; + if (first_node != -1) nodes[first_node].prev = n; + first_node = n; + nodes[n].prev = -1; + + nodes[n].partition_next = first_blue; + if (first_blue != -1) nodes[first_blue].partition_prev = n; + first_blue = n; + nodes[n].partition_prev = -1; + + nodes[n].first_out = -1; + + return BlueNode(n); + } + + Edge addEdge(Node u, Node v) { + int n; + + if (first_free_arc == -1) { + n = arcs.size(); + arcs.push_back(ArcT()); + arcs.push_back(ArcT()); + } else { + n = first_free_arc; + first_free_arc = arcs[n].next_out; + } + + arcs[n].target = u.id; + arcs[n | 1].target = v.id; + + arcs[n].next_out = nodes[v.id].first_out; + if (nodes[v.id].first_out != -1) { + arcs[nodes[v.id].first_out].prev_out = n; + } + arcs[n].prev_out = -1; + nodes[v.id].first_out = n; + + arcs[n | 1].next_out = nodes[u.id].first_out; + if (nodes[u.id].first_out != -1) { + arcs[nodes[u.id].first_out].prev_out = (n | 1); + } + arcs[n | 1].prev_out = -1; + nodes[u.id].first_out = (n | 1); + + return Edge(n / 2); + } + + void erase(const Node& node) { + int n = node.id; + + if(nodes[n].next != -1) { + nodes[nodes[n].next].prev = nodes[n].prev; + } + + if(nodes[n].prev != -1) { + nodes[nodes[n].prev].next = nodes[n].next; + } else { + first_node = nodes[n].next; + } + + if (nodes[n].partition_next != -1) { + nodes[nodes[n].partition_next].partition_prev = nodes[n].partition_prev; + } + + if (nodes[n].partition_prev != -1) { + nodes[nodes[n].partition_prev].partition_next = nodes[n].partition_next; + } else { + if (nodes[n].red) { + first_red = nodes[n].partition_next; + } else { + first_blue = nodes[n].partition_next; + } + } + + if (nodes[n].red) { + nodes[n].next = first_free_red; + first_free_red = n; + } else { + nodes[n].next = first_free_blue; + first_free_blue = n; + } + nodes[n].prev = -2; + } + + void erase(const Edge& edge) { + int n = edge.id * 2; + + if (arcs[n].next_out != -1) { + arcs[arcs[n].next_out].prev_out = arcs[n].prev_out; + } + + if (arcs[n].prev_out != -1) { + arcs[arcs[n].prev_out].next_out = arcs[n].next_out; + } else { + nodes[arcs[n | 1].target].first_out = arcs[n].next_out; + } + + if (arcs[n | 1].next_out != -1) { + arcs[arcs[n | 1].next_out].prev_out = arcs[n | 1].prev_out; + } + + if (arcs[n | 1].prev_out != -1) { + arcs[arcs[n | 1].prev_out].next_out = arcs[n | 1].next_out; + } else { + nodes[arcs[n].target].first_out = arcs[n | 1].next_out; + } + + arcs[n].next_out = first_free_arc; + first_free_arc = n; + arcs[n].prev_out = -2; + arcs[n | 1].prev_out = -2; + + } + + void clear() { + arcs.clear(); + nodes.clear(); + first_node = first_free_arc = first_red = first_blue = + max_red = max_blue = first_free_red = first_free_blue = -1; + } + + protected: + + void changeRed(Edge e, RedNode n) { + if(arcs[(2 * e.id) | 1].next_out != -1) { + arcs[arcs[(2 * e.id) | 1].next_out].prev_out = + arcs[(2 * e.id) | 1].prev_out; + } + if(arcs[(2 * e.id) | 1].prev_out != -1) { + arcs[arcs[(2 * e.id) | 1].prev_out].next_out = + arcs[(2 * e.id) | 1].next_out; + } else { + nodes[arcs[2 * e.id].target].first_out = + arcs[(2 * e.id) | 1].next_out; + } + + if (nodes[n.id].first_out != -1) { + arcs[nodes[n.id].first_out].prev_out = ((2 * e.id) | 1); + } + arcs[2 * e.id].target = n.id; + arcs[(2 * e.id) | 1].prev_out = -1; + arcs[(2 * e.id) | 1].next_out = nodes[n.id].first_out; + nodes[n.id].first_out = ((2 * e.id) | 1); + } + + void changeBlue(Edge e, BlueNode n) { + if(arcs[2 * e.id].next_out != -1) { + arcs[arcs[2 * e.id].next_out].prev_out = arcs[2 * e.id].prev_out; + } + if(arcs[2 * e.id].prev_out != -1) { + arcs[arcs[2 * e.id].prev_out].next_out = + arcs[2 * e.id].next_out; + } else { + nodes[arcs[(2 * e.id) | 1].target].first_out = + arcs[2 * e.id].next_out; + } + + if (nodes[n.id].first_out != -1) { + arcs[nodes[n.id].first_out].prev_out = 2 * e.id; + } + arcs[(2 * e.id) | 1].target = n.id; + arcs[2 * e.id].prev_out = -1; + arcs[2 * e.id].next_out = nodes[n.id].first_out; + nodes[n.id].first_out = 2 * e.id; + } + + }; + + typedef BpGraphExtender ExtendedListBpGraphBase; + + + /// \addtogroup graphs + /// @{ + + ///A general undirected graph structure. + + ///\ref ListBpGraph is a versatile and fast undirected graph + ///implementation based on linked lists that are stored in + ///\c std::vector structures. + /// + ///This type fully conforms to the \ref concepts::BpGraph "BpGraph concept" + ///and it also provides several useful additional functionalities. + ///Most of its member functions and nested classes are documented + ///only in the concept class. + /// + ///This class provides only linear time counting for nodes, edges and arcs. + /// + ///\sa concepts::BpGraph + ///\sa ListDigraph + class ListBpGraph : public ExtendedListBpGraphBase { + typedef ExtendedListBpGraphBase Parent; + + private: + /// BpGraphs are \e not copy constructible. Use BpGraphCopy instead. + ListBpGraph(const ListBpGraph &) :ExtendedListBpGraphBase() {}; + /// \brief Assignment of a graph to another one is \e not allowed. + /// Use BpGraphCopy instead. + void operator=(const ListBpGraph &) {} + public: + /// Constructor + + /// Constructor. + /// + ListBpGraph() {} + + typedef Parent::OutArcIt IncEdgeIt; + + /// \brief Add a new red node to the graph. + /// + /// This function adds a red new node to the graph. + /// \return The new node. + RedNode addRedNode() { return Parent::addRedNode(); } + + /// \brief Add a new blue node to the graph. + /// + /// This function adds a blue new node to the graph. + /// \return The new node. + BlueNode addBlueNode() { return Parent::addBlueNode(); } + + /// \brief Add a new edge to the graph. + /// + /// This function adds a new edge to the graph between nodes + /// \c u and \c v with inherent orientation from node \c u to + /// node \c v. + /// \return The new edge. + Edge addEdge(RedNode u, BlueNode v) { + return Parent::addEdge(u, v); + } + Edge addEdge(BlueNode v, RedNode u) { + return Parent::addEdge(u, v); + } + + ///\brief Erase a node from the graph. + /// + /// This function erases the given node along with its incident arcs + /// from the graph. + /// + /// \note All iterators referencing the removed node or the incident + /// edges are invalidated, of course. + void erase(Node n) { Parent::erase(n); } + + ///\brief Erase an edge from the graph. + /// + /// This function erases the given edge from the graph. + /// + /// \note All iterators referencing the removed edge are invalidated, + /// of course. + void erase(Edge e) { Parent::erase(e); } + /// Node validity check + + /// This function gives back \c true if the given node is valid, + /// i.e. it is a real node of the graph. + /// + /// \warning A removed node could become valid again if new nodes are + /// added to the graph. + bool valid(Node n) const { return Parent::valid(n); } + /// Edge validity check + + /// This function gives back \c true if the given edge is valid, + /// i.e. it is a real edge of the graph. + /// + /// \warning A removed edge could become valid again if new edges are + /// added to the graph. + bool valid(Edge e) const { return Parent::valid(e); } + /// Arc validity check + + /// This function gives back \c true if the given arc is valid, + /// i.e. it is a real arc of the graph. + /// + /// \warning A removed arc could become valid again if new edges are + /// added to the graph. + bool valid(Arc a) const { return Parent::valid(a); } + + /// \brief Change the red node of an edge. + /// + /// This function changes the red node of the given edge \c e to \c n. + /// + ///\note \c EdgeIt and \c ArcIt iterators referencing the + ///changed edge are invalidated and all other iterators whose + ///base node is the changed node are also invalidated. + /// + ///\warning This functionality cannot be used together with the + ///Snapshot feature. + void changeRed(Edge e, RedNode n) { + Parent::changeRed(e, n); + } + /// \brief Change the blue node of an edge. + /// + /// This function changes the blue node of the given edge \c e to \c n. + /// + ///\note \c EdgeIt iterators referencing the changed edge remain + ///valid, but \c ArcIt iterators referencing the changed edge and + ///all other iterators whose base node is the changed node are also + ///invalidated. + /// + ///\warning This functionality cannot be used together with the + ///Snapshot feature. + void changeBlue(Edge e, BlueNode n) { + Parent::changeBlue(e, n); + } + + ///Clear the graph. + + ///This function erases all nodes and arcs from the graph. + /// + ///\note All iterators of the graph are invalidated, of course. + void clear() { + Parent::clear(); + } + + /// Reserve memory for nodes. + + /// Using this function, it is possible to avoid superfluous memory + /// allocation: if you know that the graph you want to build will + /// be large (e.g. it will contain millions of nodes and/or edges), + /// then it is worth reserving space for this amount before starting + /// to build the graph. + /// \sa reserveEdge() + void reserveNode(int n) { nodes.reserve(n); }; + + /// Reserve memory for edges. + + /// Using this function, it is possible to avoid superfluous memory + /// allocation: if you know that the graph you want to build will + /// be large (e.g. it will contain millions of nodes and/or edges), + /// then it is worth reserving space for this amount before starting + /// to build the graph. + /// \sa reserveNode() + void reserveEdge(int m) { arcs.reserve(2 * m); }; + + /// \brief Class to make a snapshot of the graph and restore + /// it later. + /// + /// Class to make a snapshot of the graph and restore it later. + /// + /// The newly added nodes and edges can be removed + /// using the restore() function. + /// + /// \note After a state is restored, you cannot restore a later state, + /// i.e. you cannot add the removed nodes and edges again using + /// another Snapshot instance. + /// + /// \warning Node and edge deletions and other modifications + /// (e.g. changing the end-nodes of edges or contracting nodes) + /// cannot be restored. These events invalidate the snapshot. + /// However, the edges and nodes that were added to the graph after + /// making the current snapshot can be removed without invalidating it. + class Snapshot { + protected: + + typedef Parent::NodeNotifier NodeNotifier; + + class NodeObserverProxy : public NodeNotifier::ObserverBase { + public: + + NodeObserverProxy(Snapshot& _snapshot) + : snapshot(_snapshot) {} + + using NodeNotifier::ObserverBase::attach; + using NodeNotifier::ObserverBase::detach; + using NodeNotifier::ObserverBase::attached; + + protected: + + virtual void add(const Node& node) { + snapshot.addNode(node); + } + virtual void add(const std::vector& nodes) { + for (int i = nodes.size() - 1; i >= 0; ++i) { + snapshot.addNode(nodes[i]); + } + } + virtual void erase(const Node& node) { + snapshot.eraseNode(node); + } + virtual void erase(const std::vector& nodes) { + for (int i = 0; i < int(nodes.size()); ++i) { + snapshot.eraseNode(nodes[i]); + } + } + virtual void build() { + Node node; + std::vector nodes; + for (notifier()->first(node); node != INVALID; + notifier()->next(node)) { + nodes.push_back(node); + } + for (int i = nodes.size() - 1; i >= 0; --i) { + snapshot.addNode(nodes[i]); + } + } + virtual void clear() { + Node node; + for (notifier()->first(node); node != INVALID; + notifier()->next(node)) { + snapshot.eraseNode(node); + } + } + + Snapshot& snapshot; + }; + + class EdgeObserverProxy : public EdgeNotifier::ObserverBase { + public: + + EdgeObserverProxy(Snapshot& _snapshot) + : snapshot(_snapshot) {} + + using EdgeNotifier::ObserverBase::attach; + using EdgeNotifier::ObserverBase::detach; + using EdgeNotifier::ObserverBase::attached; + + protected: + + virtual void add(const Edge& edge) { + snapshot.addEdge(edge); + } + virtual void add(const std::vector& edges) { + for (int i = edges.size() - 1; i >= 0; ++i) { + snapshot.addEdge(edges[i]); + } + } + virtual void erase(const Edge& edge) { + snapshot.eraseEdge(edge); + } + virtual void erase(const std::vector& edges) { + for (int i = 0; i < int(edges.size()); ++i) { + snapshot.eraseEdge(edges[i]); + } + } + virtual void build() { + Edge edge; + std::vector edges; + for (notifier()->first(edge); edge != INVALID; + notifier()->next(edge)) { + edges.push_back(edge); + } + for (int i = edges.size() - 1; i >= 0; --i) { + snapshot.addEdge(edges[i]); + } + } + virtual void clear() { + Edge edge; + for (notifier()->first(edge); edge != INVALID; + notifier()->next(edge)) { + snapshot.eraseEdge(edge); + } + } + + Snapshot& snapshot; + }; + + ListBpGraph *graph; + + NodeObserverProxy node_observer_proxy; + EdgeObserverProxy edge_observer_proxy; + + std::list added_nodes; + std::list added_edges; + + + void addNode(const Node& node) { + added_nodes.push_front(node); + } + void eraseNode(const Node& node) { + std::list::iterator it = + std::find(added_nodes.begin(), added_nodes.end(), node); + if (it == added_nodes.end()) { + clear(); + edge_observer_proxy.detach(); + throw NodeNotifier::ImmediateDetach(); + } else { + added_nodes.erase(it); + } + } + + void addEdge(const Edge& edge) { + added_edges.push_front(edge); + } + void eraseEdge(const Edge& edge) { + std::list::iterator it = + std::find(added_edges.begin(), added_edges.end(), edge); + if (it == added_edges.end()) { + clear(); + node_observer_proxy.detach(); + throw EdgeNotifier::ImmediateDetach(); + } else { + added_edges.erase(it); + } + } + + void attach(ListBpGraph &_graph) { + graph = &_graph; + node_observer_proxy.attach(graph->notifier(Node())); + edge_observer_proxy.attach(graph->notifier(Edge())); + } + + void detach() { + node_observer_proxy.detach(); + edge_observer_proxy.detach(); + } + + bool attached() const { + return node_observer_proxy.attached(); + } + + void clear() { + added_nodes.clear(); + added_edges.clear(); + } + + public: + + /// \brief Default constructor. + /// + /// Default constructor. + /// You have to call save() to actually make a snapshot. + Snapshot() + : graph(0), node_observer_proxy(*this), + edge_observer_proxy(*this) {} + + /// \brief Constructor that immediately makes a snapshot. + /// + /// This constructor immediately makes a snapshot of the given graph. + Snapshot(ListBpGraph &gr) + : node_observer_proxy(*this), + edge_observer_proxy(*this) { + attach(gr); + } + + /// \brief Make a snapshot. + /// + /// This function makes a snapshot of the given graph. + /// It can be called more than once. In case of a repeated + /// call, the previous snapshot gets lost. + void save(ListBpGraph &gr) { + if (attached()) { + detach(); + clear(); + } + attach(gr); + } + + /// \brief Undo the changes until the last snapshot. + /// + /// This function undos the changes until the last snapshot + /// created by save() or Snapshot(ListBpGraph&). + /// + /// \warning This method invalidates the snapshot, i.e. repeated + /// restoring is not supported unless you call save() again. + void restore() { + detach(); + for(std::list::iterator it = added_edges.begin(); + it != added_edges.end(); ++it) { + graph->erase(*it); + } + for(std::list::iterator it = added_nodes.begin(); + it != added_nodes.end(); ++it) { + graph->erase(*it); + } + clear(); + } + + /// \brief Returns \c true if the snapshot is valid. + /// + /// This function returns \c true if the snapshot is valid. + bool valid() const { + return attached(); + } + }; + }; + + /// @} +} //namespace lemon + + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp.h new file mode 100644 index 00000000000..567763f0222 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp.h @@ -0,0 +1,95 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_LP_H +#define LEMON_LP_H + +#include + + +#ifdef LEMON_HAVE_GLPK +#include +#elif LEMON_HAVE_CPLEX +#include +#elif LEMON_HAVE_SOPLEX +#include +#elif LEMON_HAVE_CLP +#include +#elif LEMON_HAVE_CBC +#include +#endif + +///\file +///\brief Defines a default LP solver +///\ingroup lp_group +namespace lemon { + +#ifdef DOXYGEN + ///The default LP solver identifier + + ///The default LP solver identifier. + ///\ingroup lp_group + /// + ///Currently, the possible values are \c _LEMON_GLPK, \c LEMON__CPLEX, + ///\c _LEMON_SOPLEX or \c LEMON__CLP +#define LEMON_DEFAULT_LP SOLVER + ///The default LP solver + + ///The default LP solver. + ///\ingroup lp_group + /// + ///Currently, it is either \c GlpkLp, \c CplexLp, \c SoplexLp or \c ClpLp + typedef GlpkLp Lp; + + ///The default MIP solver identifier + + ///The default MIP solver identifier. + ///\ingroup lp_group + /// + ///Currently, the possible values are \c _LEMON_GLPK, \c LEMON__CPLEX + ///or \c _LEMON_CBC +#define LEMON_DEFAULT_MIP SOLVER + ///The default MIP solver. + + ///The default MIP solver. + ///\ingroup lp_group + /// + ///Currently, it is either \c GlpkMip, \c CplexMip , \c CbcMip + typedef GlpkMip Mip; +#else +#if LEMON_DEFAULT_LP == _LEMON_GLPK + typedef GlpkLp Lp; +#elif LEMON_DEFAULT_LP == _LEMON_CPLEX + typedef CplexLp Lp; +#elif LEMON_DEFAULT_LP == _LEMON_SOPLEX + typedef SoplexLp Lp; +#elif LEMON_DEFAULT_LP == _LEMON_CLP + typedef ClpLp Lp; +#endif +#if LEMON_DEFAULT_MIP == _LEMON_GLPK + typedef GlpkMip Mip; +#elif LEMON_DEFAULT_MIP == _LEMON_CPLEX + typedef CplexMip Mip; +#elif LEMON_DEFAULT_MIP == _LEMON_CBC + typedef CbcMip Mip; +#endif +#endif + +} //namespace lemon + +#endif //LEMON_LP_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_base.cc b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_base.cc new file mode 100644 index 00000000000..312fd631f9a --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_base.cc @@ -0,0 +1,30 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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. + * + */ + +///\file +///\brief The implementation of the LP solver interface. + +#include +namespace lemon { + + const LpBase::Value LpBase::INF = + std::numeric_limits::infinity(); + const LpBase::Value LpBase::NaN = + std::numeric_limits::quiet_NaN(); + +} //namespace lemon diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_base.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_base.h new file mode 100644 index 00000000000..22d3e4899fe --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_base.h @@ -0,0 +1,2147 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_LP_BASE_H +#define LEMON_LP_BASE_H + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +///\file +///\brief The interface of the LP solver interface. +///\ingroup lp_group +namespace lemon { + + ///Common base class for LP and MIP solvers + + ///Usually this class is not used directly, please use one of the concrete + ///implementations of the solver interface. + ///\ingroup lp_group + class LpBase { + + protected: + + _solver_bits::VarIndex rows; + _solver_bits::VarIndex cols; + + public: + + ///Possible outcomes of an LP solving procedure + enum SolveExitStatus { + /// = 0. It means that the problem has been successfully solved: either + ///an optimal solution has been found or infeasibility/unboundedness + ///has been proved. + SOLVED = 0, + /// = 1. Any other case (including the case when some user specified + ///limit has been exceeded). + UNSOLVED = 1 + }; + + ///Direction of the optimization + enum Sense { + /// Minimization + MIN, + /// Maximization + MAX + }; + + ///Enum for \c messageLevel() parameter + enum MessageLevel { + /// No output (default value). + MESSAGE_NOTHING, + /// Error messages only. + MESSAGE_ERROR, + /// Warnings. + MESSAGE_WARNING, + /// Normal output. + MESSAGE_NORMAL, + /// Verbose output. + MESSAGE_VERBOSE + }; + + + ///The floating point type used by the solver + typedef double Value; + ///The infinity constant + static const Value INF; + ///The not a number constant + static const Value NaN; + + friend class Col; + friend class ColIt; + friend class Row; + friend class RowIt; + + ///Refer to a column of the LP. + + ///This type is used to refer to a column of the LP. + /// + ///Its value remains valid and correct even after the addition or erase of + ///other columns. + /// + ///\note This class is similar to other Item types in LEMON, like + ///Node and Arc types in digraph. + class Col { + friend class LpBase; + protected: + int _id; + explicit Col(int id) : _id(id) {} + public: + typedef Value ExprValue; + typedef True LpCol; + /// Default constructor + + /// \warning The default constructor sets the Col to an + /// undefined value. + Col() {} + /// Invalid constructor \& conversion. + + /// This constructor initializes the Col to be invalid. + /// \sa Invalid for more details. + Col(const Invalid&) : _id(-1) {} + /// Equality operator + + /// Two \ref Col "Col"s are equal if and only if they point to + /// the same LP column or both are invalid. + bool operator==(Col c) const {return _id == c._id;} + /// Inequality operator + + /// \sa operator==(Col c) + /// + bool operator!=(Col c) const {return _id != c._id;} + /// Artificial ordering operator. + + /// To allow the use of this object in std::map or similar + /// associative container we require this. + /// + /// \note This operator only have to define some strict ordering of + /// the items; this order has nothing to do with the iteration + /// ordering of the items. + bool operator<(Col c) const {return _id < c._id;} + }; + + ///Iterator for iterate over the columns of an LP problem + + /// Its usage is quite simple, for example, you can count the number + /// of columns in an LP \c lp: + ///\code + /// int count=0; + /// for (LpBase::ColIt c(lp); c!=INVALID; ++c) ++count; + ///\endcode + class ColIt : public Col { + const LpBase *_solver; + public: + /// Default constructor + + /// \warning The default constructor sets the iterator + /// to an undefined value. + ColIt() {} + /// Sets the iterator to the first Col + + /// Sets the iterator to the first Col. + /// + ColIt(const LpBase &solver) : _solver(&solver) + { + _solver->cols.firstItem(_id); + } + /// Invalid constructor \& conversion + + /// Initialize the iterator to be invalid. + /// \sa Invalid for more details. + ColIt(const Invalid&) : Col(INVALID) {} + /// Next column + + /// Assign the iterator to the next column. + /// + ColIt &operator++() + { + _solver->cols.nextItem(_id); + return *this; + } + }; + + /// \brief Returns the ID of the column. + static int id(const Col& col) { return col._id; } + /// \brief Returns the column with the given ID. + /// + /// \pre The argument should be a valid column ID in the LP problem. + static Col colFromId(int id) { return Col(id); } + + ///Refer to a row of the LP. + + ///This type is used to refer to a row of the LP. + /// + ///Its value remains valid and correct even after the addition or erase of + ///other rows. + /// + ///\note This class is similar to other Item types in LEMON, like + ///Node and Arc types in digraph. + class Row { + friend class LpBase; + protected: + int _id; + explicit Row(int id) : _id(id) {} + public: + typedef Value ExprValue; + typedef True LpRow; + /// Default constructor + + /// \warning The default constructor sets the Row to an + /// undefined value. + Row() {} + /// Invalid constructor \& conversion. + + /// This constructor initializes the Row to be invalid. + /// \sa Invalid for more details. + Row(const Invalid&) : _id(-1) {} + /// Equality operator + + /// Two \ref Row "Row"s are equal if and only if they point to + /// the same LP row or both are invalid. + bool operator==(Row r) const {return _id == r._id;} + /// Inequality operator + + /// \sa operator==(Row r) + /// + bool operator!=(Row r) const {return _id != r._id;} + /// Artificial ordering operator. + + /// To allow the use of this object in std::map or similar + /// associative container we require this. + /// + /// \note This operator only have to define some strict ordering of + /// the items; this order has nothing to do with the iteration + /// ordering of the items. + bool operator<(Row r) const {return _id < r._id;} + }; + + ///Iterator for iterate over the rows of an LP problem + + /// Its usage is quite simple, for example, you can count the number + /// of rows in an LP \c lp: + ///\code + /// int count=0; + /// for (LpBase::RowIt c(lp); c!=INVALID; ++c) ++count; + ///\endcode + class RowIt : public Row { + const LpBase *_solver; + public: + /// Default constructor + + /// \warning The default constructor sets the iterator + /// to an undefined value. + RowIt() {} + /// Sets the iterator to the first Row + + /// Sets the iterator to the first Row. + /// + RowIt(const LpBase &solver) : _solver(&solver) + { + _solver->rows.firstItem(_id); + } + /// Invalid constructor \& conversion + + /// Initialize the iterator to be invalid. + /// \sa Invalid for more details. + RowIt(const Invalid&) : Row(INVALID) {} + /// Next row + + /// Assign the iterator to the next row. + /// + RowIt &operator++() + { + _solver->rows.nextItem(_id); + return *this; + } + }; + + /// \brief Returns the ID of the row. + static int id(const Row& row) { return row._id; } + /// \brief Returns the row with the given ID. + /// + /// \pre The argument should be a valid row ID in the LP problem. + static Row rowFromId(int id) { return Row(id); } + + public: + + ///Linear expression of variables and a constant component + + ///This data structure stores a linear expression of the variables + ///(\ref Col "Col"s) and also has a constant component. + /// + ///There are several ways to access and modify the contents of this + ///container. + ///\code + ///e[v]=5; + ///e[v]+=12; + ///e.erase(v); + ///\endcode + ///or you can also iterate through its elements. + ///\code + ///double s=0; + ///for(LpBase::Expr::ConstCoeffIt i(e);i!=INVALID;++i) + /// s+=*i * primal(i); + ///\endcode + ///(This code computes the primal value of the expression). + ///- Numbers (double's) + ///and variables (\ref Col "Col"s) directly convert to an + ///\ref Expr and the usual linear operations are defined, so + ///\code + ///v+w + ///2*v-3.12*(v-w/2)+2 + ///v*2.1+(3*v+(v*12+w+6)*3)/2 + ///\endcode + ///are valid expressions. + ///The usual assignment operations are also defined. + ///\code + ///e=v+w; + ///e+=2*v-3.12*(v-w/2)+2; + ///e*=3.4; + ///e/=5; + ///\endcode + ///- The constant member can be set and read by dereference + /// operator (unary *) + /// + ///\code + ///*e=12; + ///double c=*e; + ///\endcode + /// + ///\sa Constr + class Expr { + friend class LpBase; + public: + /// The key type of the expression + typedef LpBase::Col Key; + /// The value type of the expression + typedef LpBase::Value Value; + + protected: + Value const_comp; + std::map comps; + + public: + typedef True SolverExpr; + /// Default constructor + + /// Construct an empty expression, the coefficients and + /// the constant component are initialized to zero. + Expr() : const_comp(0) {} + /// Construct an expression from a column + + /// Construct an expression, which has a term with \c c variable + /// and 1.0 coefficient. + Expr(const Col &c) : const_comp(0) { + typedef std::map::value_type pair_type; + comps.insert(pair_type(id(c), 1)); + } + /// Construct an expression from a constant + + /// Construct an expression, which's constant component is \c v. + /// + Expr(const Value &v) : const_comp(v) {} + /// Returns the coefficient of the column + Value operator[](const Col& c) const { + std::map::const_iterator it=comps.find(id(c)); + if (it != comps.end()) { + return it->second; + } else { + return 0; + } + } + /// Returns the coefficient of the column + Value& operator[](const Col& c) { + return comps[id(c)]; + } + /// Sets the coefficient of the column + void set(const Col &c, const Value &v) { + if (v != 0.0) { + typedef std::map::value_type pair_type; + comps.insert(pair_type(id(c), v)); + } else { + comps.erase(id(c)); + } + } + /// Returns the constant component of the expression + Value& operator*() { return const_comp; } + /// Returns the constant component of the expression + const Value& operator*() const { return const_comp; } + /// \brief Removes the coefficients which's absolute value does + /// not exceed \c epsilon. It also sets to zero the constant + /// component, if it does not exceed epsilon in absolute value. + void simplify(Value epsilon = 0.0) { + std::map::iterator it=comps.begin(); + while (it != comps.end()) { + std::map::iterator jt=it; + ++jt; + if (std::fabs((*it).second) <= epsilon) comps.erase(it); + it=jt; + } + if (std::fabs(const_comp) <= epsilon) const_comp = 0; + } + + void simplify(Value epsilon = 0.0) const { + const_cast(this)->simplify(epsilon); + } + + ///Sets all coefficients and the constant component to 0. + void clear() { + comps.clear(); + const_comp=0; + } + + ///Compound assignment + Expr &operator+=(const Expr &e) { + for (std::map::const_iterator it=e.comps.begin(); + it!=e.comps.end(); ++it) + comps[it->first]+=it->second; + const_comp+=e.const_comp; + return *this; + } + ///Compound assignment + Expr &operator-=(const Expr &e) { + for (std::map::const_iterator it=e.comps.begin(); + it!=e.comps.end(); ++it) + comps[it->first]-=it->second; + const_comp-=e.const_comp; + return *this; + } + ///Multiply with a constant + Expr &operator*=(const Value &v) { + for (std::map::iterator it=comps.begin(); + it!=comps.end(); ++it) + it->second*=v; + const_comp*=v; + return *this; + } + ///Division with a constant + Expr &operator/=(const Value &c) { + for (std::map::iterator it=comps.begin(); + it!=comps.end(); ++it) + it->second/=c; + const_comp/=c; + return *this; + } + + ///Iterator over the expression + + ///The iterator iterates over the terms of the expression. + /// + ///\code + ///double s=0; + ///for(LpBase::Expr::CoeffIt i(e);i!=INVALID;++i) + /// s+= *i * primal(i); + ///\endcode + class CoeffIt { + private: + + std::map::iterator _it, _end; + + public: + + /// Sets the iterator to the first term + + /// Sets the iterator to the first term of the expression. + /// + CoeffIt(Expr& e) + : _it(e.comps.begin()), _end(e.comps.end()){} + + /// Convert the iterator to the column of the term + operator Col() const { + return colFromId(_it->first); + } + + /// Returns the coefficient of the term + Value& operator*() { return _it->second; } + + /// Returns the coefficient of the term + const Value& operator*() const { return _it->second; } + /// Next term + + /// Assign the iterator to the next term. + /// + CoeffIt& operator++() { ++_it; return *this; } + + /// Equality operator + bool operator==(Invalid) const { return _it == _end; } + /// Inequality operator + bool operator!=(Invalid) const { return _it != _end; } + }; + + /// Const iterator over the expression + + ///The iterator iterates over the terms of the expression. + /// + ///\code + ///double s=0; + ///for(LpBase::Expr::ConstCoeffIt i(e);i!=INVALID;++i) + /// s+=*i * primal(i); + ///\endcode + class ConstCoeffIt { + private: + + std::map::const_iterator _it, _end; + + public: + + /// Sets the iterator to the first term + + /// Sets the iterator to the first term of the expression. + /// + ConstCoeffIt(const Expr& e) + : _it(e.comps.begin()), _end(e.comps.end()){} + + /// Convert the iterator to the column of the term + operator Col() const { + return colFromId(_it->first); + } + + /// Returns the coefficient of the term + const Value& operator*() const { return _it->second; } + + /// Next term + + /// Assign the iterator to the next term. + /// + ConstCoeffIt& operator++() { ++_it; return *this; } + + /// Equality operator + bool operator==(Invalid) const { return _it == _end; } + /// Inequality operator + bool operator!=(Invalid) const { return _it != _end; } + }; + + }; + + ///Linear constraint + + ///This data stucture represents a linear constraint in the LP. + ///Basically it is a linear expression with a lower or an upper bound + ///(or both). These parts of the constraint can be obtained by the member + ///functions \ref expr(), \ref lowerBound() and \ref upperBound(), + ///respectively. + ///There are two ways to construct a constraint. + ///- You can set the linear expression and the bounds directly + /// by the functions above. + ///- The operators \<=, == and \>= + /// are defined between expressions, or even between constraints whenever + /// it makes sense. Therefore if \c e and \c f are linear expressions and + /// \c s and \c t are numbers, then the followings are valid expressions + /// and thus they can be used directly e.g. in \ref addRow() whenever + /// it makes sense. + ///\code + /// e<=s + /// e<=f + /// e==f + /// s<=e<=t + /// e>=t + ///\endcode + ///\warning The validity of a constraint is checked only at run + ///time, so e.g. \ref addRow(x[1]\<=x[2]<=5) will + ///compile, but will fail an assertion. + class Constr + { + public: + typedef LpBase::Expr Expr; + typedef Expr::Key Key; + typedef Expr::Value Value; + + protected: + Expr _expr; + Value _lb,_ub; + public: + ///\e + Constr() : _expr(), _lb(NaN), _ub(NaN) {} + ///\e + Constr(Value lb, const Expr &e, Value ub) : + _expr(e), _lb(lb), _ub(ub) {} + Constr(const Expr &e) : + _expr(e), _lb(NaN), _ub(NaN) {} + ///\e + void clear() + { + _expr.clear(); + _lb=_ub=NaN; + } + + ///Reference to the linear expression + Expr &expr() { return _expr; } + ///Cont reference to the linear expression + const Expr &expr() const { return _expr; } + ///Reference to the lower bound. + + ///\return + ///- \ref INF "INF": the constraint is lower unbounded. + ///- \ref NaN "NaN": lower bound has not been set. + ///- finite number: the lower bound + Value &lowerBound() { return _lb; } + ///The const version of \ref lowerBound() + const Value &lowerBound() const { return _lb; } + ///Reference to the upper bound. + + ///\return + ///- \ref INF "INF": the constraint is upper unbounded. + ///- \ref NaN "NaN": upper bound has not been set. + ///- finite number: the upper bound + Value &upperBound() { return _ub; } + ///The const version of \ref upperBound() + const Value &upperBound() const { return _ub; } + ///Is the constraint lower bounded? + bool lowerBounded() const { + return _lb != -INF && !isNaN(_lb); + } + ///Is the constraint upper bounded? + bool upperBounded() const { + return _ub != INF && !isNaN(_ub); + } + + }; + + ///Linear expression of rows + + ///This data structure represents a column of the matrix, + ///thas is it strores a linear expression of the dual variables + ///(\ref Row "Row"s). + /// + ///There are several ways to access and modify the contents of this + ///container. + ///\code + ///e[v]=5; + ///e[v]+=12; + ///e.erase(v); + ///\endcode + ///or you can also iterate through its elements. + ///\code + ///double s=0; + ///for(LpBase::DualExpr::ConstCoeffIt i(e);i!=INVALID;++i) + /// s+=*i; + ///\endcode + ///(This code computes the sum of all coefficients). + ///- Numbers (double's) + ///and variables (\ref Row "Row"s) directly convert to an + ///\ref DualExpr and the usual linear operations are defined, so + ///\code + ///v+w + ///2*v-3.12*(v-w/2) + ///v*2.1+(3*v+(v*12+w)*3)/2 + ///\endcode + ///are valid \ref DualExpr dual expressions. + ///The usual assignment operations are also defined. + ///\code + ///e=v+w; + ///e+=2*v-3.12*(v-w/2); + ///e*=3.4; + ///e/=5; + ///\endcode + /// + ///\sa Expr + class DualExpr { + friend class LpBase; + public: + /// The key type of the expression + typedef LpBase::Row Key; + /// The value type of the expression + typedef LpBase::Value Value; + + protected: + std::map comps; + + public: + typedef True SolverExpr; + /// Default constructor + + /// Construct an empty expression, the coefficients are + /// initialized to zero. + DualExpr() {} + /// Construct an expression from a row + + /// Construct an expression, which has a term with \c r dual + /// variable and 1.0 coefficient. + DualExpr(const Row &r) { + typedef std::map::value_type pair_type; + comps.insert(pair_type(id(r), 1)); + } + /// Returns the coefficient of the row + Value operator[](const Row& r) const { + std::map::const_iterator it = comps.find(id(r)); + if (it != comps.end()) { + return it->second; + } else { + return 0; + } + } + /// Returns the coefficient of the row + Value& operator[](const Row& r) { + return comps[id(r)]; + } + /// Sets the coefficient of the row + void set(const Row &r, const Value &v) { + if (v != 0.0) { + typedef std::map::value_type pair_type; + comps.insert(pair_type(id(r), v)); + } else { + comps.erase(id(r)); + } + } + /// \brief Removes the coefficients which's absolute value does + /// not exceed \c epsilon. + void simplify(Value epsilon = 0.0) { + std::map::iterator it=comps.begin(); + while (it != comps.end()) { + std::map::iterator jt=it; + ++jt; + if (std::fabs((*it).second) <= epsilon) comps.erase(it); + it=jt; + } + } + + void simplify(Value epsilon = 0.0) const { + const_cast(this)->simplify(epsilon); + } + + ///Sets all coefficients to 0. + void clear() { + comps.clear(); + } + ///Compound assignment + DualExpr &operator+=(const DualExpr &e) { + for (std::map::const_iterator it=e.comps.begin(); + it!=e.comps.end(); ++it) + comps[it->first]+=it->second; + return *this; + } + ///Compound assignment + DualExpr &operator-=(const DualExpr &e) { + for (std::map::const_iterator it=e.comps.begin(); + it!=e.comps.end(); ++it) + comps[it->first]-=it->second; + return *this; + } + ///Multiply with a constant + DualExpr &operator*=(const Value &v) { + for (std::map::iterator it=comps.begin(); + it!=comps.end(); ++it) + it->second*=v; + return *this; + } + ///Division with a constant + DualExpr &operator/=(const Value &v) { + for (std::map::iterator it=comps.begin(); + it!=comps.end(); ++it) + it->second/=v; + return *this; + } + + ///Iterator over the expression + + ///The iterator iterates over the terms of the expression. + /// + ///\code + ///double s=0; + ///for(LpBase::DualExpr::CoeffIt i(e);i!=INVALID;++i) + /// s+= *i * dual(i); + ///\endcode + class CoeffIt { + private: + + std::map::iterator _it, _end; + + public: + + /// Sets the iterator to the first term + + /// Sets the iterator to the first term of the expression. + /// + CoeffIt(DualExpr& e) + : _it(e.comps.begin()), _end(e.comps.end()){} + + /// Convert the iterator to the row of the term + operator Row() const { + return rowFromId(_it->first); + } + + /// Returns the coefficient of the term + Value& operator*() { return _it->second; } + + /// Returns the coefficient of the term + const Value& operator*() const { return _it->second; } + + /// Next term + + /// Assign the iterator to the next term. + /// + CoeffIt& operator++() { ++_it; return *this; } + + /// Equality operator + bool operator==(Invalid) const { return _it == _end; } + /// Inequality operator + bool operator!=(Invalid) const { return _it != _end; } + }; + + ///Iterator over the expression + + ///The iterator iterates over the terms of the expression. + /// + ///\code + ///double s=0; + ///for(LpBase::DualExpr::ConstCoeffIt i(e);i!=INVALID;++i) + /// s+= *i * dual(i); + ///\endcode + class ConstCoeffIt { + private: + + std::map::const_iterator _it, _end; + + public: + + /// Sets the iterator to the first term + + /// Sets the iterator to the first term of the expression. + /// + ConstCoeffIt(const DualExpr& e) + : _it(e.comps.begin()), _end(e.comps.end()){} + + /// Convert the iterator to the row of the term + operator Row() const { + return rowFromId(_it->first); + } + + /// Returns the coefficient of the term + const Value& operator*() const { return _it->second; } + + /// Next term + + /// Assign the iterator to the next term. + /// + ConstCoeffIt& operator++() { ++_it; return *this; } + + /// Equality operator + bool operator==(Invalid) const { return _it == _end; } + /// Inequality operator + bool operator!=(Invalid) const { return _it != _end; } + }; + }; + + + protected: + + class InsertIterator { + private: + + std::map& _host; + const _solver_bits::VarIndex& _index; + + public: + + typedef std::output_iterator_tag iterator_category; + typedef void difference_type; + typedef void value_type; + typedef void reference; + typedef void pointer; + + InsertIterator(std::map& host, + const _solver_bits::VarIndex& index) + : _host(host), _index(index) {} + + InsertIterator& operator=(const std::pair& value) { + typedef std::map::value_type pair_type; + _host.insert(pair_type(_index[value.first], value.second)); + return *this; + } + + InsertIterator& operator*() { return *this; } + InsertIterator& operator++() { return *this; } + InsertIterator operator++(int) { return *this; } + + }; + + class ExprIterator { + private: + std::map::const_iterator _host_it; + const _solver_bits::VarIndex& _index; + public: + + typedef std::bidirectional_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + typedef const std::pair value_type; + typedef value_type reference; + + class pointer { + public: + pointer(value_type& _value) : value(_value) {} + value_type* operator->() { return &value; } + private: + value_type value; + }; + + ExprIterator(const std::map::const_iterator& host_it, + const _solver_bits::VarIndex& index) + : _host_it(host_it), _index(index) {} + + reference operator*() { + return std::make_pair(_index(_host_it->first), _host_it->second); + } + + pointer operator->() { + return pointer(operator*()); + } + + ExprIterator& operator++() { ++_host_it; return *this; } + ExprIterator operator++(int) { + ExprIterator tmp(*this); ++_host_it; return tmp; + } + + ExprIterator& operator--() { --_host_it; return *this; } + ExprIterator operator--(int) { + ExprIterator tmp(*this); --_host_it; return tmp; + } + + bool operator==(const ExprIterator& it) const { + return _host_it == it._host_it; + } + + bool operator!=(const ExprIterator& it) const { + return _host_it != it._host_it; + } + + }; + + protected: + + //Abstract virtual functions + + virtual int _addColId(int col) { return cols.addIndex(col); } + virtual int _addRowId(int row) { return rows.addIndex(row); } + + virtual void _eraseColId(int col) { cols.eraseIndex(col); } + virtual void _eraseRowId(int row) { rows.eraseIndex(row); } + + virtual int _addCol() = 0; + virtual int _addRow() = 0; + + virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u) { + int row = _addRow(); + _setRowCoeffs(row, b, e); + _setRowLowerBound(row, l); + _setRowUpperBound(row, u); + return row; + } + + virtual void _eraseCol(int col) = 0; + virtual void _eraseRow(int row) = 0; + + virtual void _getColName(int col, std::string& name) const = 0; + virtual void _setColName(int col, const std::string& name) = 0; + virtual int _colByName(const std::string& name) const = 0; + + virtual void _getRowName(int row, std::string& name) const = 0; + virtual void _setRowName(int row, const std::string& name) = 0; + virtual int _rowByName(const std::string& name) const = 0; + + virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e) = 0; + virtual void _getRowCoeffs(int i, InsertIterator b) const = 0; + + virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e) = 0; + virtual void _getColCoeffs(int i, InsertIterator b) const = 0; + + virtual void _setCoeff(int row, int col, Value value) = 0; + virtual Value _getCoeff(int row, int col) const = 0; + + virtual void _setColLowerBound(int i, Value value) = 0; + virtual Value _getColLowerBound(int i) const = 0; + + virtual void _setColUpperBound(int i, Value value) = 0; + virtual Value _getColUpperBound(int i) const = 0; + + virtual void _setRowLowerBound(int i, Value value) = 0; + virtual Value _getRowLowerBound(int i) const = 0; + + virtual void _setRowUpperBound(int i, Value value) = 0; + virtual Value _getRowUpperBound(int i) const = 0; + + virtual void _setObjCoeffs(ExprIterator b, ExprIterator e) = 0; + virtual void _getObjCoeffs(InsertIterator b) const = 0; + + virtual void _setObjCoeff(int i, Value obj_coef) = 0; + virtual Value _getObjCoeff(int i) const = 0; + + virtual void _setSense(Sense) = 0; + virtual Sense _getSense() const = 0; + + virtual void _clear() = 0; + + virtual const char* _solverName() const = 0; + + virtual void _messageLevel(MessageLevel level) = 0; + + //Own protected stuff + + //Constant component of the objective function + Value obj_const_comp; + + LpBase() : rows(), cols(), obj_const_comp(0) {} + + public: + + ///Unsupported file format exception + class UnsupportedFormatError : public Exception + { + std::string _format; + mutable std::string _what; + public: + explicit UnsupportedFormatError(std::string format) throw() + : _format(format) { } + virtual ~UnsupportedFormatError() throw() {} + virtual const char* what() const throw() { + try { + _what.clear(); + std::ostringstream oss; + oss << "lemon::UnsupportedFormatError: " << _format; + _what = oss.str(); + } + catch (...) {} + if (!_what.empty()) return _what.c_str(); + else return "lemon::UnsupportedFormatError"; + } + }; + + protected: + virtual void _write(std::string, std::string format) const + { + throw UnsupportedFormatError(format); + } + + public: + + /// Virtual destructor + virtual ~LpBase() {} + + ///Gives back the name of the solver. + const char* solverName() const {return _solverName();} + + ///\name Build Up and Modify the LP + + ///@{ + + ///Add a new empty column (i.e a new variable) to the LP + Col addCol() { Col c; c._id = _addColId(_addCol()); return c;} + + ///\brief Adds several new columns (i.e variables) at once + /// + ///This magic function takes a container as its argument and fills + ///its elements with new columns (i.e. variables) + ///\param t can be + ///- a standard STL compatible iterable container with + ///\ref Col as its \c values_type like + ///\code + ///std::vector + ///std::list + ///\endcode + ///- a standard STL compatible iterable container with + ///\ref Col as its \c mapped_type like + ///\code + ///std::map + ///\endcode + ///- an iterable lemon \ref concepts::WriteMap "write map" like + ///\code + ///ListGraph::NodeMap + ///ListGraph::ArcMap + ///\endcode + ///\return The number of the created column. +#ifdef DOXYGEN + template + int addColSet(T &t) { return 0;} +#else + template + typename enable_if::type + addColSet(T &t,dummy<0> = 0) { + int s=0; + for(typename T::iterator i=t.begin();i!=t.end();++i) {*i=addCol();s++;} + return s; + } + template + typename enable_if::type + addColSet(T &t,dummy<1> = 1) { + int s=0; + for(typename T::iterator i=t.begin();i!=t.end();++i) { + i->second=addCol(); + s++; + } + return s; + } + template + typename enable_if::type + addColSet(T &t,dummy<2> = 2) { + int s=0; + for(typename T::MapIt i(t); i!=INVALID; ++i) + { + i.set(addCol()); + s++; + } + return s; + } +#endif + + ///Set a column (i.e a dual constraint) of the LP + + ///\param c is the column to be modified + ///\param e is a dual linear expression (see \ref DualExpr) + ///a better one. + void col(Col c, const DualExpr &e) { + e.simplify(); + _setColCoeffs(cols(id(c)), ExprIterator(e.comps.begin(), rows), + ExprIterator(e.comps.end(), rows)); + } + + ///Get a column (i.e a dual constraint) of the LP + + ///\param c is the column to get + ///\return the dual expression associated to the column + DualExpr col(Col c) const { + DualExpr e; + _getColCoeffs(cols(id(c)), InsertIterator(e.comps, rows)); + return e; + } + + ///Add a new column to the LP + + ///\param e is a dual linear expression (see \ref DualExpr) + ///\param o is the corresponding component of the objective + ///function. It is 0 by default. + ///\return The created column. + Col addCol(const DualExpr &e, Value o = 0) { + Col c=addCol(); + col(c,e); + objCoeff(c,o); + return c; + } + + ///Add a new empty row (i.e a new constraint) to the LP + + ///This function adds a new empty row (i.e a new constraint) to the LP. + ///\return The created row + Row addRow() { Row r; r._id = _addRowId(_addRow()); return r;} + + ///\brief Add several new rows (i.e constraints) at once + /// + ///This magic function takes a container as its argument and fills + ///its elements with new row (i.e. variables) + ///\param t can be + ///- a standard STL compatible iterable container with + ///\ref Row as its \c values_type like + ///\code + ///std::vector + ///std::list + ///\endcode + ///- a standard STL compatible iterable container with + ///\ref Row as its \c mapped_type like + ///\code + ///std::map + ///\endcode + ///- an iterable lemon \ref concepts::WriteMap "write map" like + ///\code + ///ListGraph::NodeMap + ///ListGraph::ArcMap + ///\endcode + ///\return The number of rows created. +#ifdef DOXYGEN + template + int addRowSet(T &t) { return 0;} +#else + template + typename enable_if::type + addRowSet(T &t, dummy<0> = 0) { + int s=0; + for(typename T::iterator i=t.begin();i!=t.end();++i) {*i=addRow();s++;} + return s; + } + template + typename enable_if::type + addRowSet(T &t, dummy<1> = 1) { + int s=0; + for(typename T::iterator i=t.begin();i!=t.end();++i) { + i->second=addRow(); + s++; + } + return s; + } + template + typename enable_if::type + addRowSet(T &t, dummy<2> = 2) { + int s=0; + for(typename T::MapIt i(t); i!=INVALID; ++i) + { + i.set(addRow()); + s++; + } + return s; + } +#endif + + ///Set a row (i.e a constraint) of the LP + + ///\param r is the row to be modified + ///\param l is lower bound (-\ref INF means no bound) + ///\param e is a linear expression (see \ref Expr) + ///\param u is the upper bound (\ref INF means no bound) + void row(Row r, Value l, const Expr &e, Value u) { + e.simplify(); + _setRowCoeffs(rows(id(r)), ExprIterator(e.comps.begin(), cols), + ExprIterator(e.comps.end(), cols)); + _setRowLowerBound(rows(id(r)),l - *e); + _setRowUpperBound(rows(id(r)),u - *e); + } + + ///Set a row (i.e a constraint) of the LP + + ///\param r is the row to be modified + ///\param c is a linear expression (see \ref Constr) + void row(Row r, const Constr &c) { + row(r, c.lowerBounded()?c.lowerBound():-INF, + c.expr(), c.upperBounded()?c.upperBound():INF); + } + + + ///Get a row (i.e a constraint) of the LP + + ///\param r is the row to get + ///\return the expression associated to the row + Expr row(Row r) const { + Expr e; + _getRowCoeffs(rows(id(r)), InsertIterator(e.comps, cols)); + return e; + } + + ///Add a new row (i.e a new constraint) to the LP + + ///\param l is the lower bound (-\ref INF means no bound) + ///\param e is a linear expression (see \ref Expr) + ///\param u is the upper bound (\ref INF means no bound) + ///\return The created row. + Row addRow(Value l,const Expr &e, Value u) { + Row r; + e.simplify(); + r._id = _addRowId(_addRow(l - *e, ExprIterator(e.comps.begin(), cols), + ExprIterator(e.comps.end(), cols), u - *e)); + return r; + } + + ///Add a new row (i.e a new constraint) to the LP + + ///\param c is a linear expression (see \ref Constr) + ///\return The created row. + Row addRow(const Constr &c) { + Row r; + c.expr().simplify(); + r._id = _addRowId(_addRow(c.lowerBounded()?c.lowerBound()-*c.expr():-INF, + ExprIterator(c.expr().comps.begin(), cols), + ExprIterator(c.expr().comps.end(), cols), + c.upperBounded()?c.upperBound()-*c.expr():INF)); + return r; + } + ///Erase a column (i.e a variable) from the LP + + ///\param c is the column to be deleted + void erase(Col c) { + _eraseCol(cols(id(c))); + _eraseColId(cols(id(c))); + } + ///Erase a row (i.e a constraint) from the LP + + ///\param r is the row to be deleted + void erase(Row r) { + _eraseRow(rows(id(r))); + _eraseRowId(rows(id(r))); + } + + /// Get the name of a column + + ///\param c is the coresponding column + ///\return The name of the colunm + std::string colName(Col c) const { + std::string name; + _getColName(cols(id(c)), name); + return name; + } + + /// Set the name of a column + + ///\param c is the coresponding column + ///\param name The name to be given + void colName(Col c, const std::string& name) { + _setColName(cols(id(c)), name); + } + + /// Get the column by its name + + ///\param name The name of the column + ///\return the proper column or \c INVALID + Col colByName(const std::string& name) const { + int k = _colByName(name); + return k != -1 ? Col(cols[k]) : Col(INVALID); + } + + /// Get the name of a row + + ///\param r is the coresponding row + ///\return The name of the row + std::string rowName(Row r) const { + std::string name; + _getRowName(rows(id(r)), name); + return name; + } + + /// Set the name of a row + + ///\param r is the coresponding row + ///\param name The name to be given + void rowName(Row r, const std::string& name) { + _setRowName(rows(id(r)), name); + } + + /// Get the row by its name + + ///\param name The name of the row + ///\return the proper row or \c INVALID + Row rowByName(const std::string& name) const { + int k = _rowByName(name); + return k != -1 ? Row(rows[k]) : Row(INVALID); + } + + /// Set an element of the coefficient matrix of the LP + + ///\param r is the row of the element to be modified + ///\param c is the column of the element to be modified + ///\param val is the new value of the coefficient + void coeff(Row r, Col c, Value val) { + _setCoeff(rows(id(r)),cols(id(c)), val); + } + + /// Get an element of the coefficient matrix of the LP + + ///\param r is the row of the element + ///\param c is the column of the element + ///\return the corresponding coefficient + Value coeff(Row r, Col c) const { + return _getCoeff(rows(id(r)),cols(id(c))); + } + + /// Set the lower bound of a column (i.e a variable) + + /// The lower bound of a variable (column) has to be given by an + /// extended number of type Value, i.e. a finite number of type + /// Value or -\ref INF. + void colLowerBound(Col c, Value value) { + _setColLowerBound(cols(id(c)),value); + } + + /// Get the lower bound of a column (i.e a variable) + + /// This function returns the lower bound for column (variable) \c c + /// (this might be -\ref INF as well). + ///\return The lower bound for column \c c + Value colLowerBound(Col c) const { + return _getColLowerBound(cols(id(c))); + } + + ///\brief Set the lower bound of several columns + ///(i.e variables) at once + /// + ///This magic function takes a container as its argument + ///and applies the function on all of its elements. + ///The lower bound of a variable (column) has to be given by an + ///extended number of type Value, i.e. a finite number of type + ///Value or -\ref INF. +#ifdef DOXYGEN + template + void colLowerBound(T &t, Value value) { return 0;} +#else + template + typename enable_if::type + colLowerBound(T &t, Value value,dummy<0> = 0) { + for(typename T::iterator i=t.begin();i!=t.end();++i) { + colLowerBound(*i, value); + } + } + template + typename enable_if::type + colLowerBound(T &t, Value value,dummy<1> = 1) { + for(typename T::iterator i=t.begin();i!=t.end();++i) { + colLowerBound(i->second, value); + } + } + template + typename enable_if::type + colLowerBound(T &t, Value value,dummy<2> = 2) { + for(typename T::MapIt i(t); i!=INVALID; ++i){ + colLowerBound(*i, value); + } + } +#endif + + /// Set the upper bound of a column (i.e a variable) + + /// The upper bound of a variable (column) has to be given by an + /// extended number of type Value, i.e. a finite number of type + /// Value or \ref INF. + void colUpperBound(Col c, Value value) { + _setColUpperBound(cols(id(c)),value); + }; + + /// Get the upper bound of a column (i.e a variable) + + /// This function returns the upper bound for column (variable) \c c + /// (this might be \ref INF as well). + /// \return The upper bound for column \c c + Value colUpperBound(Col c) const { + return _getColUpperBound(cols(id(c))); + } + + ///\brief Set the upper bound of several columns + ///(i.e variables) at once + /// + ///This magic function takes a container as its argument + ///and applies the function on all of its elements. + ///The upper bound of a variable (column) has to be given by an + ///extended number of type Value, i.e. a finite number of type + ///Value or \ref INF. +#ifdef DOXYGEN + template + void colUpperBound(T &t, Value value) { return 0;} +#else + template + typename enable_if::type + colUpperBound(T1 &t, Value value,dummy<0> = 0) { + for(typename T1::iterator i=t.begin();i!=t.end();++i) { + colUpperBound(*i, value); + } + } + template + typename enable_if::type + colUpperBound(T1 &t, Value value,dummy<1> = 1) { + for(typename T1::iterator i=t.begin();i!=t.end();++i) { + colUpperBound(i->second, value); + } + } + template + typename enable_if::type + colUpperBound(T1 &t, Value value,dummy<2> = 2) { + for(typename T1::MapIt i(t); i!=INVALID; ++i){ + colUpperBound(*i, value); + } + } +#endif + + /// Set the lower and the upper bounds of a column (i.e a variable) + + /// The lower and the upper bounds of + /// a variable (column) have to be given by an + /// extended number of type Value, i.e. a finite number of type + /// Value, -\ref INF or \ref INF. + void colBounds(Col c, Value lower, Value upper) { + _setColLowerBound(cols(id(c)),lower); + _setColUpperBound(cols(id(c)),upper); + } + + ///\brief Set the lower and the upper bound of several columns + ///(i.e variables) at once + /// + ///This magic function takes a container as its argument + ///and applies the function on all of its elements. + /// The lower and the upper bounds of + /// a variable (column) have to be given by an + /// extended number of type Value, i.e. a finite number of type + /// Value, -\ref INF or \ref INF. +#ifdef DOXYGEN + template + void colBounds(T &t, Value lower, Value upper) { return 0;} +#else + template + typename enable_if::type + colBounds(T2 &t, Value lower, Value upper,dummy<0> = 0) { + for(typename T2::iterator i=t.begin();i!=t.end();++i) { + colBounds(*i, lower, upper); + } + } + template + typename enable_if::type + colBounds(T2 &t, Value lower, Value upper,dummy<1> = 1) { + for(typename T2::iterator i=t.begin();i!=t.end();++i) { + colBounds(i->second, lower, upper); + } + } + template + typename enable_if::type + colBounds(T2 &t, Value lower, Value upper,dummy<2> = 2) { + for(typename T2::MapIt i(t); i!=INVALID; ++i){ + colBounds(*i, lower, upper); + } + } +#endif + + /// Set the lower bound of a row (i.e a constraint) + + /// The lower bound of a constraint (row) has to be given by an + /// extended number of type Value, i.e. a finite number of type + /// Value or -\ref INF. + void rowLowerBound(Row r, Value value) { + _setRowLowerBound(rows(id(r)),value); + } + + /// Get the lower bound of a row (i.e a constraint) + + /// This function returns the lower bound for row (constraint) \c c + /// (this might be -\ref INF as well). + ///\return The lower bound for row \c r + Value rowLowerBound(Row r) const { + return _getRowLowerBound(rows(id(r))); + } + + /// Set the upper bound of a row (i.e a constraint) + + /// The upper bound of a constraint (row) has to be given by an + /// extended number of type Value, i.e. a finite number of type + /// Value or -\ref INF. + void rowUpperBound(Row r, Value value) { + _setRowUpperBound(rows(id(r)),value); + } + + /// Get the upper bound of a row (i.e a constraint) + + /// This function returns the upper bound for row (constraint) \c c + /// (this might be -\ref INF as well). + ///\return The upper bound for row \c r + Value rowUpperBound(Row r) const { + return _getRowUpperBound(rows(id(r))); + } + + ///Set an element of the objective function + void objCoeff(Col c, Value v) {_setObjCoeff(cols(id(c)),v); }; + + ///Get an element of the objective function + Value objCoeff(Col c) const { return _getObjCoeff(cols(id(c))); }; + + ///Set the objective function + + ///\param e is a linear expression of type \ref Expr. + /// + void obj(const Expr& e) { + _setObjCoeffs(ExprIterator(e.comps.begin(), cols), + ExprIterator(e.comps.end(), cols)); + obj_const_comp = *e; + } + + ///Get the objective function + + ///\return the objective function as a linear expression of type + ///Expr. + Expr obj() const { + Expr e; + _getObjCoeffs(InsertIterator(e.comps, cols)); + *e = obj_const_comp; + return e; + } + + + ///Set the direction of optimization + void sense(Sense sense) { _setSense(sense); } + + ///Query the direction of the optimization + Sense sense() const {return _getSense(); } + + ///Set the sense to maximization + void max() { _setSense(MAX); } + + ///Set the sense to maximization + void min() { _setSense(MIN); } + + ///Clear the problem + void clear() { _clear(); rows.clear(); cols.clear(); } + + /// Set the message level of the solver + void messageLevel(MessageLevel level) { _messageLevel(level); } + + /// Write the problem to a file in the given format + + /// This function writes the problem to a file in the given format. + /// Different solver backends may support different formats. + /// Trying to write in an unsupported format will trigger + /// \ref UnsupportedFormatError. For the supported formats, + /// visit the documentation of the base class of the related backends + /// (\ref CplexBase, \ref GlpkBase etc.) + /// \param file The file path + /// \param format The output file format. + void write(std::string file, std::string format = "MPS") const + { + _write(file.c_str(),format.c_str()); + } + + ///@} + + }; + + /// Addition + + ///\relates LpBase::Expr + /// + inline LpBase::Expr operator+(const LpBase::Expr &a, const LpBase::Expr &b) { + LpBase::Expr tmp(a); + tmp+=b; + return tmp; + } + ///Substraction + + ///\relates LpBase::Expr + /// + inline LpBase::Expr operator-(const LpBase::Expr &a, const LpBase::Expr &b) { + LpBase::Expr tmp(a); + tmp-=b; + return tmp; + } + ///Multiply with constant + + ///\relates LpBase::Expr + /// + inline LpBase::Expr operator*(const LpBase::Expr &a, const LpBase::Value &b) { + LpBase::Expr tmp(a); + tmp*=b; + return tmp; + } + + ///Multiply with constant + + ///\relates LpBase::Expr + /// + inline LpBase::Expr operator*(const LpBase::Value &a, const LpBase::Expr &b) { + LpBase::Expr tmp(b); + tmp*=a; + return tmp; + } + ///Divide with constant + + ///\relates LpBase::Expr + /// + inline LpBase::Expr operator/(const LpBase::Expr &a, const LpBase::Value &b) { + LpBase::Expr tmp(a); + tmp/=b; + return tmp; + } + + ///Create constraint + + ///\relates LpBase::Constr + /// + inline LpBase::Constr operator<=(const LpBase::Expr &e, + const LpBase::Expr &f) { + return LpBase::Constr(0, f - e, LpBase::NaN); + } + + ///Create constraint + + ///\relates LpBase::Constr + /// + inline LpBase::Constr operator<=(const LpBase::Value &e, + const LpBase::Expr &f) { + return LpBase::Constr(e, f, LpBase::NaN); + } + + ///Create constraint + + ///\relates LpBase::Constr + /// + inline LpBase::Constr operator<=(const LpBase::Expr &e, + const LpBase::Value &f) { + return LpBase::Constr(LpBase::NaN, e, f); + } + + ///Create constraint + + ///\relates LpBase::Constr + /// + inline LpBase::Constr operator>=(const LpBase::Expr &e, + const LpBase::Expr &f) { + return LpBase::Constr(0, e - f, LpBase::NaN); + } + + + ///Create constraint + + ///\relates LpBase::Constr + /// + inline LpBase::Constr operator>=(const LpBase::Value &e, + const LpBase::Expr &f) { + return LpBase::Constr(LpBase::NaN, f, e); + } + + + ///Create constraint + + ///\relates LpBase::Constr + /// + inline LpBase::Constr operator>=(const LpBase::Expr &e, + const LpBase::Value &f) { + return LpBase::Constr(f, e, LpBase::NaN); + } + + ///Create constraint + + ///\relates LpBase::Constr + /// + inline LpBase::Constr operator==(const LpBase::Expr &e, + const LpBase::Value &f) { + return LpBase::Constr(f, e, f); + } + + ///Create constraint + + ///\relates LpBase::Constr + /// + inline LpBase::Constr operator==(const LpBase::Expr &e, + const LpBase::Expr &f) { + return LpBase::Constr(0, f - e, 0); + } + + ///Create constraint + + ///\relates LpBase::Constr + /// + inline LpBase::Constr operator<=(const LpBase::Value &n, + const LpBase::Constr &c) { + LpBase::Constr tmp(c); + LEMON_ASSERT(isNaN(tmp.lowerBound()), "Wrong LP constraint"); + tmp.lowerBound()=n; + return tmp; + } + ///Create constraint + + ///\relates LpBase::Constr + /// + inline LpBase::Constr operator<=(const LpBase::Constr &c, + const LpBase::Value &n) + { + LpBase::Constr tmp(c); + LEMON_ASSERT(isNaN(tmp.upperBound()), "Wrong LP constraint"); + tmp.upperBound()=n; + return tmp; + } + + ///Create constraint + + ///\relates LpBase::Constr + /// + inline LpBase::Constr operator>=(const LpBase::Value &n, + const LpBase::Constr &c) { + LpBase::Constr tmp(c); + LEMON_ASSERT(isNaN(tmp.upperBound()), "Wrong LP constraint"); + tmp.upperBound()=n; + return tmp; + } + ///Create constraint + + ///\relates LpBase::Constr + /// + inline LpBase::Constr operator>=(const LpBase::Constr &c, + const LpBase::Value &n) + { + LpBase::Constr tmp(c); + LEMON_ASSERT(isNaN(tmp.lowerBound()), "Wrong LP constraint"); + tmp.lowerBound()=n; + return tmp; + } + + ///Addition + + ///\relates LpBase::DualExpr + /// + inline LpBase::DualExpr operator+(const LpBase::DualExpr &a, + const LpBase::DualExpr &b) { + LpBase::DualExpr tmp(a); + tmp+=b; + return tmp; + } + ///Substraction + + ///\relates LpBase::DualExpr + /// + inline LpBase::DualExpr operator-(const LpBase::DualExpr &a, + const LpBase::DualExpr &b) { + LpBase::DualExpr tmp(a); + tmp-=b; + return tmp; + } + ///Multiply with constant + + ///\relates LpBase::DualExpr + /// + inline LpBase::DualExpr operator*(const LpBase::DualExpr &a, + const LpBase::Value &b) { + LpBase::DualExpr tmp(a); + tmp*=b; + return tmp; + } + + ///Multiply with constant + + ///\relates LpBase::DualExpr + /// + inline LpBase::DualExpr operator*(const LpBase::Value &a, + const LpBase::DualExpr &b) { + LpBase::DualExpr tmp(b); + tmp*=a; + return tmp; + } + ///Divide with constant + + ///\relates LpBase::DualExpr + /// + inline LpBase::DualExpr operator/(const LpBase::DualExpr &a, + const LpBase::Value &b) { + LpBase::DualExpr tmp(a); + tmp/=b; + return tmp; + } + + /// \ingroup lp_group + /// + /// \brief Common base class for LP solvers + /// + /// This class is an abstract base class for LP solvers. This class + /// provides a full interface for set and modify an LP problem, + /// solve it and retrieve the solution. You can use one of the + /// descendants as a concrete implementation, or the \c Lp + /// default LP solver. However, if you would like to handle LP + /// solvers as reference or pointer in a generic way, you can use + /// this class directly. + class LpSolver : virtual public LpBase { + public: + + /// The problem types for primal and dual problems + enum ProblemType { + /// = 0. Feasible solution hasn't been found (but may exist). + UNDEFINED = 0, + /// = 1. The problem has no feasible solution. + INFEASIBLE = 1, + /// = 2. Feasible solution found. + FEASIBLE = 2, + /// = 3. Optimal solution exists and found. + OPTIMAL = 3, + /// = 4. The cost function is unbounded. + UNBOUNDED = 4 + }; + + ///The basis status of variables + enum VarStatus { + /// The variable is in the basis + BASIC, + /// The variable is free, but not basic + FREE, + /// The variable has active lower bound + LOWER, + /// The variable has active upper bound + UPPER, + /// The variable is non-basic and fixed + FIXED + }; + + protected: + + virtual SolveExitStatus _solve() = 0; + + virtual Value _getPrimal(int i) const = 0; + virtual Value _getDual(int i) const = 0; + + virtual Value _getPrimalRay(int i) const = 0; + virtual Value _getDualRay(int i) const = 0; + + virtual Value _getPrimalValue() const = 0; + + virtual VarStatus _getColStatus(int i) const = 0; + virtual VarStatus _getRowStatus(int i) const = 0; + + virtual ProblemType _getPrimalType() const = 0; + virtual ProblemType _getDualType() const = 0; + + public: + + ///Allocate a new LP problem instance + virtual LpSolver* newSolver() const = 0; + ///Make a copy of the LP problem + virtual LpSolver* cloneSolver() const = 0; + + ///\name Solve the LP + + ///@{ + + ///\e Solve the LP problem at hand + /// + ///\return The result of the optimization procedure. Possible + ///values and their meanings can be found in the documentation of + ///\ref SolveExitStatus. + SolveExitStatus solve() { return _solve(); } + + ///@} + + ///\name Obtain the Solution + + ///@{ + + /// The type of the primal problem + ProblemType primalType() const { + return _getPrimalType(); + } + + /// The type of the dual problem + ProblemType dualType() const { + return _getDualType(); + } + + /// Return the primal value of the column + + /// Return the primal value of the column. + /// \pre The problem is solved. + Value primal(Col c) const { return _getPrimal(cols(id(c))); } + + /// Return the primal value of the expression + + /// Return the primal value of the expression, i.e. the dot + /// product of the primal solution and the expression. + /// \pre The problem is solved. + Value primal(const Expr& e) const { + double res = *e; + for (Expr::ConstCoeffIt c(e); c != INVALID; ++c) { + res += *c * primal(c); + } + return res; + } + /// Returns a component of the primal ray + + /// The primal ray is solution of the modified primal problem, + /// where we change each finite bound to 0, and we looking for a + /// negative objective value in case of minimization, and positive + /// objective value for maximization. If there is such solution, + /// that proofs the unsolvability of the dual problem, and if a + /// feasible primal solution exists, then the unboundness of + /// primal problem. + /// + /// \pre The problem is solved and the dual problem is infeasible. + /// \note Some solvers does not provide primal ray calculation + /// functions. + Value primalRay(Col c) const { return _getPrimalRay(cols(id(c))); } + + /// Return the dual value of the row + + /// Return the dual value of the row. + /// \pre The problem is solved. + Value dual(Row r) const { return _getDual(rows(id(r))); } + + /// Return the dual value of the dual expression + + /// Return the dual value of the dual expression, i.e. the dot + /// product of the dual solution and the dual expression. + /// \pre The problem is solved. + Value dual(const DualExpr& e) const { + double res = 0.0; + for (DualExpr::ConstCoeffIt r(e); r != INVALID; ++r) { + res += *r * dual(r); + } + return res; + } + + /// Returns a component of the dual ray + + /// The dual ray is solution of the modified primal problem, where + /// we change each finite bound to 0 (i.e. the objective function + /// coefficients in the primal problem), and we looking for a + /// ositive objective value. If there is such solution, that + /// proofs the unsolvability of the primal problem, and if a + /// feasible dual solution exists, then the unboundness of + /// dual problem. + /// + /// \pre The problem is solved and the primal problem is infeasible. + /// \note Some solvers does not provide dual ray calculation + /// functions. + Value dualRay(Row r) const { return _getDualRay(rows(id(r))); } + + /// Return the basis status of the column + + /// \see VarStatus + VarStatus colStatus(Col c) const { return _getColStatus(cols(id(c))); } + + /// Return the basis status of the row + + /// \see VarStatus + VarStatus rowStatus(Row r) const { return _getRowStatus(rows(id(r))); } + + ///The value of the objective function + + ///\return + ///- \ref INF or -\ref INF means either infeasibility or unboundedness + /// of the primal problem, depending on whether we minimize or maximize. + ///- \ref NaN if no primal solution is found. + ///- The (finite) objective value if an optimal solution is found. + Value primal() const { return _getPrimalValue()+obj_const_comp;} + ///@} + + protected: + + }; + + + /// \ingroup lp_group + /// + /// \brief Common base class for MIP solvers + /// + /// This class is an abstract base class for MIP solvers. This class + /// provides a full interface for set and modify an MIP problem, + /// solve it and retrieve the solution. You can use one of the + /// descendants as a concrete implementation, or the \c Lp + /// default MIP solver. However, if you would like to handle MIP + /// solvers as reference or pointer in a generic way, you can use + /// this class directly. + class MipSolver : virtual public LpBase { + public: + + /// The problem types for MIP problems + enum ProblemType { + /// = 0. Feasible solution hasn't been found (but may exist). + UNDEFINED = 0, + /// = 1. The problem has no feasible solution. + INFEASIBLE = 1, + /// = 2. Feasible solution found. + FEASIBLE = 2, + /// = 3. Optimal solution exists and found. + OPTIMAL = 3, + /// = 4. The cost function is unbounded. + ///The Mip or at least the relaxed problem is unbounded. + UNBOUNDED = 4 + }; + + ///Allocate a new MIP problem instance + virtual MipSolver* newSolver() const = 0; + ///Make a copy of the MIP problem + virtual MipSolver* cloneSolver() const = 0; + + ///\name Solve the MIP + + ///@{ + + /// Solve the MIP problem at hand + /// + ///\return The result of the optimization procedure. Possible + ///values and their meanings can be found in the documentation of + ///\ref SolveExitStatus. + SolveExitStatus solve() { return _solve(); } + + ///@} + + ///\name Set Column Type + ///@{ + + ///Possible variable (column) types (e.g. real, integer, binary etc.) + enum ColTypes { + /// = 0. Continuous variable (default). + REAL = 0, + /// = 1. Integer variable. + INTEGER = 1 + }; + + ///Sets the type of the given column to the given type + + ///Sets the type of the given column to the given type. + /// + void colType(Col c, ColTypes col_type) { + _setColType(cols(id(c)),col_type); + } + + ///Gives back the type of the column. + + ///Gives back the type of the column. + /// + ColTypes colType(Col c) const { + return _getColType(cols(id(c))); + } + ///@} + + ///\name Obtain the Solution + + ///@{ + + /// The type of the MIP problem + ProblemType type() const { + return _getType(); + } + + /// Return the value of the row in the solution + + /// Return the value of the row in the solution. + /// \pre The problem is solved. + Value sol(Col c) const { return _getSol(cols(id(c))); } + + /// Return the value of the expression in the solution + + /// Return the value of the expression in the solution, i.e. the + /// dot product of the solution and the expression. + /// \pre The problem is solved. + Value sol(const Expr& e) const { + double res = *e; + for (Expr::ConstCoeffIt c(e); c != INVALID; ++c) { + res += *c * sol(c); + } + return res; + } + ///The value of the objective function + + ///\return + ///- \ref INF or -\ref INF means either infeasibility or unboundedness + /// of the problem, depending on whether we minimize or maximize. + ///- \ref NaN if no primal solution is found. + ///- The (finite) objective value if an optimal solution is found. + Value solValue() const { return _getSolValue()+obj_const_comp;} + ///@} + + protected: + + virtual SolveExitStatus _solve() = 0; + virtual ColTypes _getColType(int col) const = 0; + virtual void _setColType(int col, ColTypes col_type) = 0; + virtual ProblemType _getType() const = 0; + virtual Value _getSol(int i) const = 0; + virtual Value _getSolValue() const = 0; + + }; + + + +} //namespace lemon + +#endif //LEMON_LP_BASE_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_skeleton.cc b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_skeleton.cc new file mode 100644 index 00000000000..fc1c143f3ca --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_skeleton.cc @@ -0,0 +1,143 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 + +///\file +///\brief A skeleton file to implement LP solver interfaces +namespace lemon { + + int SkeletonSolverBase::_addCol() + { + return ++col_num; + } + + int SkeletonSolverBase::_addRow() + { + return ++row_num; + } + + int SkeletonSolverBase::_addRow(Value, ExprIterator, ExprIterator, Value) + { + return ++row_num; + } + + void SkeletonSolverBase::_eraseCol(int) {} + void SkeletonSolverBase::_eraseRow(int) {} + + void SkeletonSolverBase::_getColName(int, std::string &) const {} + void SkeletonSolverBase::_setColName(int, const std::string &) {} + int SkeletonSolverBase::_colByName(const std::string&) const { return -1; } + + void SkeletonSolverBase::_getRowName(int, std::string &) const {} + void SkeletonSolverBase::_setRowName(int, const std::string &) {} + int SkeletonSolverBase::_rowByName(const std::string&) const { return -1; } + + void SkeletonSolverBase::_setRowCoeffs(int, ExprIterator, ExprIterator) {} + void SkeletonSolverBase::_getRowCoeffs(int, InsertIterator) const {} + + void SkeletonSolverBase::_setColCoeffs(int, ExprIterator, ExprIterator) {} + void SkeletonSolverBase::_getColCoeffs(int, InsertIterator) const {} + + void SkeletonSolverBase::_setCoeff(int, int, Value) {} + SkeletonSolverBase::Value SkeletonSolverBase::_getCoeff(int, int) const + { return 0; } + + void SkeletonSolverBase::_setColLowerBound(int, Value) {} + SkeletonSolverBase::Value SkeletonSolverBase::_getColLowerBound(int) const + { return 0; } + + void SkeletonSolverBase::_setColUpperBound(int, Value) {} + SkeletonSolverBase::Value SkeletonSolverBase::_getColUpperBound(int) const + { return 0; } + + void SkeletonSolverBase::_setRowLowerBound(int, Value) {} + SkeletonSolverBase::Value SkeletonSolverBase::_getRowLowerBound(int) const + { return 0; } + + void SkeletonSolverBase::_setRowUpperBound(int, Value) {} + SkeletonSolverBase::Value SkeletonSolverBase::_getRowUpperBound(int) const + { return 0; } + + void SkeletonSolverBase::_setObjCoeffs(ExprIterator, ExprIterator) {} + void SkeletonSolverBase::_getObjCoeffs(InsertIterator) const {}; + + void SkeletonSolverBase::_setObjCoeff(int, Value) {} + SkeletonSolverBase::Value SkeletonSolverBase::_getObjCoeff(int) const + { return 0; } + + void SkeletonSolverBase::_setSense(Sense) {} + SkeletonSolverBase::Sense SkeletonSolverBase::_getSense() const + { return MIN; } + + void SkeletonSolverBase::_clear() { + row_num = col_num = 0; + } + + void SkeletonSolverBase::_messageLevel(MessageLevel) {} + + void SkeletonSolverBase::_write(std::string, std::string) const {} + + LpSkeleton::SolveExitStatus LpSkeleton::_solve() { return SOLVED; } + + LpSkeleton::Value LpSkeleton::_getPrimal(int) const { return 0; } + LpSkeleton::Value LpSkeleton::_getDual(int) const { return 0; } + LpSkeleton::Value LpSkeleton::_getPrimalValue() const { return 0; } + + LpSkeleton::Value LpSkeleton::_getPrimalRay(int) const { return 0; } + LpSkeleton::Value LpSkeleton::_getDualRay(int) const { return 0; } + + LpSkeleton::ProblemType LpSkeleton::_getPrimalType() const + { return UNDEFINED; } + + LpSkeleton::ProblemType LpSkeleton::_getDualType() const + { return UNDEFINED; } + + LpSkeleton::VarStatus LpSkeleton::_getColStatus(int) const + { return BASIC; } + + LpSkeleton::VarStatus LpSkeleton::_getRowStatus(int) const + { return BASIC; } + + LpSkeleton* LpSkeleton::newSolver() const + { return static_cast(0); } + + LpSkeleton* LpSkeleton::cloneSolver() const + { return static_cast(0); } + + const char* LpSkeleton::_solverName() const { return "LpSkeleton"; } + + MipSkeleton::SolveExitStatus MipSkeleton::_solve() + { return SOLVED; } + + MipSkeleton::Value MipSkeleton::_getSol(int) const { return 0; } + MipSkeleton::Value MipSkeleton::_getSolValue() const { return 0; } + + MipSkeleton::ProblemType MipSkeleton::_getType() const + { return UNDEFINED; } + + MipSkeleton* MipSkeleton::newSolver() const + { return static_cast(0); } + + MipSkeleton* MipSkeleton::cloneSolver() const + { return static_cast(0); } + + const char* MipSkeleton::_solverName() const { return "MipSkeleton"; } + +} //namespace lemon + diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_skeleton.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_skeleton.h new file mode 100644 index 00000000000..27285a4982a --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lp_skeleton.h @@ -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-2013 + * 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_LP_SKELETON_H +#define LEMON_LP_SKELETON_H + +#include + +///\file +///\brief Skeleton file to implement LP/MIP solver interfaces +/// +///The classes in this file do nothing, but they can serve as skeletons when +///implementing an interface to new solvers. +namespace lemon { + + ///A skeleton class to implement LP/MIP solver base interface + + ///This class does nothing, but it can serve as a skeleton when + ///implementing an interface to new solvers. + class SkeletonSolverBase : public virtual LpBase { + int col_num,row_num; + + protected: + + SkeletonSolverBase() + : col_num(-1), row_num(-1) {} + + /// \e + virtual int _addCol(); + /// \e + virtual int _addRow(); + /// \e + virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u); + /// \e + virtual void _eraseCol(int i); + /// \e + virtual void _eraseRow(int i); + + /// \e + virtual void _getColName(int col, std::string& name) const; + /// \e + virtual void _setColName(int col, const std::string& name); + /// \e + virtual int _colByName(const std::string& name) const; + + /// \e + virtual void _getRowName(int row, std::string& name) const; + /// \e + virtual void _setRowName(int row, const std::string& name); + /// \e + virtual int _rowByName(const std::string& name) const; + + /// \e + virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e); + /// \e + virtual void _getRowCoeffs(int i, InsertIterator b) const; + /// \e + virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e); + /// \e + virtual void _getColCoeffs(int i, InsertIterator b) const; + + /// Set one element of the coefficient matrix + virtual void _setCoeff(int row, int col, Value value); + + /// Get one element of the coefficient matrix + virtual Value _getCoeff(int row, int col) const; + + /// The lower bound of a variable (column) have to be given by an + /// extended number of type Value, i.e. a finite number of type + /// Value or -\ref INF. + virtual void _setColLowerBound(int i, Value value); + /// \e + + /// The lower bound of a variable (column) is an + /// extended number of type Value, i.e. a finite number of type + /// Value or -\ref INF. + virtual Value _getColLowerBound(int i) const; + + /// The upper bound of a variable (column) have to be given by an + /// extended number of type Value, i.e. a finite number of type + /// Value or \ref INF. + virtual void _setColUpperBound(int i, Value value); + /// \e + + /// The upper bound of a variable (column) is an + /// extended number of type Value, i.e. a finite number of type + /// Value or \ref INF. + virtual Value _getColUpperBound(int i) const; + + /// The lower bound of a constraint (row) have to be given by an + /// extended number of type Value, i.e. a finite number of type + /// Value or -\ref INF. + virtual void _setRowLowerBound(int i, Value value); + /// \e + + /// The lower bound of a constraint (row) is an + /// extended number of type Value, i.e. a finite number of type + /// Value or -\ref INF. + virtual Value _getRowLowerBound(int i) const; + + /// The upper bound of a constraint (row) have to be given by an + /// extended number of type Value, i.e. a finite number of type + /// Value or \ref INF. + virtual void _setRowUpperBound(int i, Value value); + /// \e + + /// The upper bound of a constraint (row) is an + /// extended number of type Value, i.e. a finite number of type + /// Value or \ref INF. + virtual Value _getRowUpperBound(int i) const; + + /// \e + virtual void _setObjCoeffs(ExprIterator b, ExprIterator e); + /// \e + virtual void _getObjCoeffs(InsertIterator b) const; + + /// \e + virtual void _setObjCoeff(int i, Value obj_coef); + /// \e + virtual Value _getObjCoeff(int i) const; + + ///\e + virtual void _setSense(Sense); + ///\e + virtual Sense _getSense() const; + + ///\e + virtual void _clear(); + + ///\e + virtual void _messageLevel(MessageLevel); + + ///\e + virtual void _write(std::string file, std::string format) const; + + }; + + /// \brief Skeleton class for an LP solver interface + /// + ///This class does nothing, but it can serve as a skeleton when + ///implementing an interface to new solvers. + + ///\ingroup lp_group + class LpSkeleton : public LpSolver, public SkeletonSolverBase { + public: + ///\e + LpSkeleton() : LpSolver(), SkeletonSolverBase() {} + ///\e + virtual LpSkeleton* newSolver() const; + ///\e + virtual LpSkeleton* cloneSolver() const; + protected: + + ///\e + virtual SolveExitStatus _solve(); + + ///\e + virtual Value _getPrimal(int i) const; + ///\e + virtual Value _getDual(int i) const; + + ///\e + virtual Value _getPrimalValue() const; + + ///\e + virtual Value _getPrimalRay(int i) const; + ///\e + virtual Value _getDualRay(int i) const; + + ///\e + virtual ProblemType _getPrimalType() const; + ///\e + virtual ProblemType _getDualType() const; + + ///\e + virtual VarStatus _getColStatus(int i) const; + ///\e + virtual VarStatus _getRowStatus(int i) const; + + ///\e + virtual const char* _solverName() const; + + }; + + /// \brief Skeleton class for a MIP solver interface + /// + ///This class does nothing, but it can serve as a skeleton when + ///implementing an interface to new solvers. + ///\ingroup lp_group + class MipSkeleton : public MipSolver, public SkeletonSolverBase { + public: + ///\e + MipSkeleton() : MipSolver(), SkeletonSolverBase() {} + ///\e + virtual MipSkeleton* newSolver() const; + ///\e + virtual MipSkeleton* cloneSolver() const; + + protected: + ///\e + virtual SolveExitStatus _solve(); + + ///\e + virtual Value _getSol(int i) const; + + ///\e + virtual Value _getSolValue() const; + + ///\e + virtual ProblemType _getType() const; + + ///\e + virtual const char* _solverName() const; + + }; + +} //namespace lemon + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/maps.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/maps.h new file mode 100644 index 00000000000..1bc49e911ca --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/maps.h @@ -0,0 +1,4057 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_MAPS_H +#define LEMON_MAPS_H + +#include +#include +#include +#include + +#include + +///\file +///\ingroup maps +///\brief Miscellaneous property maps + +namespace lemon { + + /// \addtogroup maps + /// @{ + + /// Base class of maps. + + /// Base class of maps. It provides the necessary type definitions + /// required by the map %concepts. + template + class MapBase { + public: + /// \brief The key type of the map. + typedef K Key; + /// \brief The value type of the map. + /// (The type of objects associated with the keys). + typedef V Value; + }; + + + /// Null map. (a.k.a. DoNothingMap) + + /// This map can be used if you have to provide a map only for + /// its type definitions, or if you have to provide a writable map, + /// but data written to it is not required (i.e. it will be sent to + /// /dev/null). + /// It conforms to the \ref concepts::ReadWriteMap "ReadWriteMap" concept. + /// + /// \sa ConstMap + template + class NullMap : public MapBase { + public: + ///\e + typedef K Key; + ///\e + typedef V Value; + + /// Gives back a default constructed element. + Value operator[](const Key&) const { return Value(); } + /// Absorbs the value. + void set(const Key&, const Value&) {} + }; + + /// Returns a \c NullMap class + + /// This function just returns a \c NullMap class. + /// \relates NullMap + template + NullMap nullMap() { + return NullMap(); + } + + + /// Constant map. + + /// This \ref concepts::ReadMap "readable map" assigns a specified + /// value to each key. + /// + /// In other aspects it is equivalent to \c NullMap. + /// So it conforms to the \ref concepts::ReadWriteMap "ReadWriteMap" + /// concept, but it absorbs the data written to it. + /// + /// The simplest way of using this map is through the constMap() + /// function. + /// + /// \sa NullMap + /// \sa IdentityMap + template + class ConstMap : public MapBase { + private: + V _value; + public: + ///\e + typedef K Key; + ///\e + typedef V Value; + + /// Default constructor + + /// Default constructor. + /// The value of the map will be default constructed. + ConstMap() {} + + /// Constructor with specified initial value + + /// Constructor with specified initial value. + /// \param v The initial value of the map. + ConstMap(const Value &v) : _value(v) {} + + /// Gives back the specified value. + Value operator[](const Key&) const { return _value; } + + /// Absorbs the value. + void set(const Key&, const Value&) {} + + /// Sets the value that is assigned to each key. + void setAll(const Value &v) { + _value = v; + } + + template + ConstMap(const ConstMap &, const Value &v) : _value(v) {} + }; + + /// Returns a \c ConstMap class + + /// This function just returns a \c ConstMap class. + /// \relates ConstMap + template + inline ConstMap constMap(const V &v) { + return ConstMap(v); + } + + template + inline ConstMap constMap() { + return ConstMap(); + } + + + template + struct Const {}; + + /// Constant map with inlined constant value. + + /// This \ref concepts::ReadMap "readable map" assigns a specified + /// value to each key. + /// + /// In other aspects it is equivalent to \c NullMap. + /// So it conforms to the \ref concepts::ReadWriteMap "ReadWriteMap" + /// concept, but it absorbs the data written to it. + /// + /// The simplest way of using this map is through the constMap() + /// function. + /// + /// \sa NullMap + /// \sa IdentityMap + template + class ConstMap > : public MapBase { + public: + ///\e + typedef K Key; + ///\e + typedef V Value; + + /// Constructor. + ConstMap() {} + + /// Gives back the specified value. + Value operator[](const Key&) const { return v; } + + /// Absorbs the value. + void set(const Key&, const Value&) {} + }; + + /// Returns a \c ConstMap class with inlined constant value + + /// This function just returns a \c ConstMap class with inlined + /// constant value. + /// \relates ConstMap + template + inline ConstMap > constMap() { + return ConstMap >(); + } + + + /// Identity map. + + /// This \ref concepts::ReadMap "read-only map" gives back the given + /// key as value without any modification. + /// + /// \sa ConstMap + template + class IdentityMap : public MapBase { + public: + ///\e + typedef T Key; + ///\e + typedef T Value; + + /// Gives back the given value without any modification. + Value operator[](const Key &k) const { + return k; + } + }; + + /// Returns an \c IdentityMap class + + /// This function just returns an \c IdentityMap class. + /// \relates IdentityMap + template + inline IdentityMap identityMap() { + return IdentityMap(); + } + + + /// \brief Map for storing values for integer keys from the range + /// [0..size-1]. + /// + /// This map is essentially a wrapper for \c std::vector. It assigns + /// values to integer keys from the range [0..size-1]. + /// It can be used together with some data structures, e.g. + /// heap types and \c UnionFind, when the used items are small + /// integers. This map conforms to the \ref concepts::ReferenceMap + /// "ReferenceMap" concept. + /// + /// The simplest way of using this map is through the rangeMap() + /// function. + template + class RangeMap : public MapBase { + template + friend class RangeMap; + private: + + typedef std::vector Vector; + Vector _vector; + + public: + + /// Key type + typedef int Key; + /// Value type + typedef V Value; + /// Reference type + typedef typename Vector::reference Reference; + /// Const reference type + typedef typename Vector::const_reference ConstReference; + + typedef True ReferenceMapTag; + + public: + + /// Constructor with specified default value. + RangeMap(int size = 0, const Value &value = Value()) + : _vector(size, value) {} + + /// Constructs the map from an appropriate \c std::vector. + template + RangeMap(const std::vector& vector) + : _vector(vector.begin(), vector.end()) {} + + /// Constructs the map from another \c RangeMap. + template + RangeMap(const RangeMap &c) + : _vector(c._vector.begin(), c._vector.end()) {} + + /// Returns the size of the map. + int size() { + return _vector.size(); + } + + /// Resizes the map. + + /// Resizes the underlying \c std::vector container, so changes the + /// keyset of the map. + /// \param size The new size of the map. The new keyset will be the + /// range [0..size-1]. + /// \param value The default value to assign to the new keys. + void resize(int size, const Value &value = Value()) { + _vector.resize(size, value); + } + + private: + + RangeMap& operator=(const RangeMap&); + + public: + + ///\e + Reference operator[](const Key &k) { + return _vector[k]; + } + + ///\e + ConstReference operator[](const Key &k) const { + return _vector[k]; + } + + ///\e + void set(const Key &k, const Value &v) { + _vector[k] = v; + } + }; + + /// Returns a \c RangeMap class + + /// This function just returns a \c RangeMap class. + /// \relates RangeMap + template + inline RangeMap rangeMap(int size = 0, const V &value = V()) { + return RangeMap(size, value); + } + + /// \brief Returns a \c RangeMap class created from an appropriate + /// \c std::vector + + /// This function just returns a \c RangeMap class created from an + /// appropriate \c std::vector. + /// \relates RangeMap + template + inline RangeMap rangeMap(const std::vector &vector) { + return RangeMap(vector); + } + + + /// Map type based on \c std::map + + /// This map is essentially a wrapper for \c std::map with addition + /// that you can specify a default value for the keys that are not + /// stored actually. This value can be different from the default + /// contructed value (i.e. \c %Value()). + /// This type conforms to the \ref concepts::ReferenceMap "ReferenceMap" + /// concept. + /// + /// This map is useful if a default value should be assigned to most of + /// the keys and different values should be assigned only to a few + /// keys (i.e. the map is "sparse"). + /// The name of this type also refers to this important usage. + /// + /// Apart form that, this map can be used in many other cases since it + /// is based on \c std::map, which is a general associative container. + /// However, keep in mind that it is usually not as efficient as other + /// maps. + /// + /// The simplest way of using this map is through the sparseMap() + /// function. + template > + class SparseMap : public MapBase { + template + friend class SparseMap; + public: + + /// Key type + typedef K Key; + /// Value type + typedef V Value; + /// Reference type + typedef Value& Reference; + /// Const reference type + typedef const Value& ConstReference; + + typedef True ReferenceMapTag; + + private: + + typedef std::map Map; + Map _map; + Value _value; + + public: + + /// \brief Constructor with specified default value. + SparseMap(const Value &value = Value()) : _value(value) {} + /// \brief Constructs the map from an appropriate \c std::map, and + /// explicitly specifies a default value. + template + SparseMap(const std::map &map, + const Value &value = Value()) + : _map(map.begin(), map.end()), _value(value) {} + + /// \brief Constructs the map from another \c SparseMap. + template + SparseMap(const SparseMap &c) + : _map(c._map.begin(), c._map.end()), _value(c._value) {} + + private: + + SparseMap& operator=(const SparseMap&); + + public: + + ///\e + Reference operator[](const Key &k) { + typename Map::iterator it = _map.lower_bound(k); + if (it != _map.end() && !_map.key_comp()(k, it->first)) + return it->second; + else + return _map.insert(it, std::make_pair(k, _value))->second; + } + + ///\e + ConstReference operator[](const Key &k) const { + typename Map::const_iterator it = _map.find(k); + if (it != _map.end()) + return it->second; + else + return _value; + } + + ///\e + void set(const Key &k, const Value &v) { + typename Map::iterator it = _map.lower_bound(k); + if (it != _map.end() && !_map.key_comp()(k, it->first)) + it->second = v; + else + _map.insert(it, std::make_pair(k, v)); + } + + ///\e + void setAll(const Value &v) { + _value = v; + _map.clear(); + } + }; + + /// Returns a \c SparseMap class + + /// This function just returns a \c SparseMap class with specified + /// default value. + /// \relates SparseMap + template + inline SparseMap sparseMap(const V& value = V()) { + return SparseMap(value); + } + + template + inline SparseMap > sparseMap(const V& value = V()) { + return SparseMap >(value); + } + + /// \brief Returns a \c SparseMap class created from an appropriate + /// \c std::map + + /// This function just returns a \c SparseMap class created from an + /// appropriate \c std::map. + /// \relates SparseMap + template + inline SparseMap + sparseMap(const std::map &map, const V& value = V()) + { + return SparseMap(map, value); + } + + /// @} + + /// \addtogroup map_adaptors + /// @{ + + /// Composition of two maps + + /// This \ref concepts::ReadMap "read-only map" returns the + /// composition of two given maps. That is to say, if \c m1 is of + /// type \c M1 and \c m2 is of \c M2, then for + /// \code + /// ComposeMap cm(m1,m2); + /// \endcode + /// cm[x] will be equal to m1[m2[x]]. + /// + /// The \c Key type of the map is inherited from \c M2 and the + /// \c Value type is from \c M1. + /// \c M2::Value must be convertible to \c M1::Key. + /// + /// The simplest way of using this map is through the composeMap() + /// function. + /// + /// \sa CombineMap + template + class ComposeMap : public MapBase { + const M1 &_m1; + const M2 &_m2; + public: + ///\e + typedef typename M2::Key Key; + ///\e + typedef typename M1::Value Value; + + /// Constructor + ComposeMap(const M1 &m1, const M2 &m2) : _m1(m1), _m2(m2) {} + + ///\e + typename MapTraits::ConstReturnValue + operator[](const Key &k) const { return _m1[_m2[k]]; } + }; + + /// Returns a \c ComposeMap class + + /// This function just returns a \c ComposeMap class. + /// + /// If \c m1 and \c m2 are maps and the \c Value type of \c m2 is + /// convertible to the \c Key of \c m1, then composeMap(m1,m2)[x] + /// will be equal to m1[m2[x]]. + /// + /// \relates ComposeMap + template + inline ComposeMap composeMap(const M1 &m1, const M2 &m2) { + return ComposeMap(m1, m2); + } + + + /// Combination of two maps using an STL (binary) functor. + + /// This \ref concepts::ReadMap "read-only map" takes two maps and a + /// binary functor and returns the combination of the two given maps + /// using the functor. + /// That is to say, if \c m1 is of type \c M1 and \c m2 is of \c M2 + /// and \c f is of \c F, then for + /// \code + /// CombineMap cm(m1,m2,f); + /// \endcode + /// cm[x] will be equal to f(m1[x],m2[x]). + /// + /// The \c Key type of the map is inherited from \c M1 (\c M1::Key + /// must be convertible to \c M2::Key) and the \c Value type is \c V. + /// \c M2::Value and \c M1::Value must be convertible to the + /// corresponding input parameter of \c F and the return type of \c F + /// must be convertible to \c V. + /// + /// The simplest way of using this map is through the combineMap() + /// function. + /// + /// \sa ComposeMap + template + class CombineMap : public MapBase { + const M1 &_m1; + const M2 &_m2; + F _f; + public: + ///\e + typedef typename M1::Key Key; + ///\e + typedef V Value; + + /// Constructor + CombineMap(const M1 &m1, const M2 &m2, const F &f = F()) + : _m1(m1), _m2(m2), _f(f) {} + ///\e + Value operator[](const Key &k) const { return _f(_m1[k],_m2[k]); } + }; + + /// Returns a \c CombineMap class + + /// This function just returns a \c CombineMap class. + /// + /// For example, if \c m1 and \c m2 are both maps with \c double + /// values, then + /// \code + /// combineMap(m1,m2,std::plus()) + /// \endcode + /// is equivalent to + /// \code + /// addMap(m1,m2) + /// \endcode + /// + /// This function is specialized for adaptable binary function + /// classes and C++ functions. + /// + /// \relates CombineMap + template + inline CombineMap + combineMap(const M1 &m1, const M2 &m2, const F &f) { + return CombineMap(m1,m2,f); + } + + template + inline CombineMap + combineMap(const M1 &m1, const M2 &m2, const F &f) { + return combineMap(m1,m2,f); + } + + template + inline CombineMap + combineMap(const M1 &m1, const M2 &m2, V (*f)(K1, K2)) { + return combineMap(m1,m2,f); + } + + + /// Converts an STL style (unary) functor to a map + + /// This \ref concepts::ReadMap "read-only map" returns the value + /// of a given functor. Actually, it just wraps the functor and + /// provides the \c Key and \c Value typedefs. + /// + /// Template parameters \c K and \c V will become its \c Key and + /// \c Value. In most cases they have to be given explicitly because + /// a functor typically does not provide \c argument_type and + /// \c result_type typedefs. + /// Parameter \c F is the type of the used functor. + /// + /// The simplest way of using this map is through the functorToMap() + /// function. + /// + /// \sa MapToFunctor + template + class FunctorToMap : public MapBase { + F _f; + public: + ///\e + typedef K Key; + ///\e + typedef V Value; + + /// Constructor + FunctorToMap(const F &f = F()) : _f(f) {} + ///\e + Value operator[](const Key &k) const { return _f(k); } + }; + + /// Returns a \c FunctorToMap class + + /// This function just returns a \c FunctorToMap class. + /// + /// This function is specialized for adaptable binary function + /// classes and C++ functions. + /// + /// \relates FunctorToMap + template + inline FunctorToMap functorToMap(const F &f) { + return FunctorToMap(f); + } + + template + inline FunctorToMap + functorToMap(const F &f) + { + return FunctorToMap(f); + } + + template + inline FunctorToMap functorToMap(V (*f)(K)) { + return FunctorToMap(f); + } + + + /// Converts a map to an STL style (unary) functor + + /// This class converts a map to an STL style (unary) functor. + /// That is it provides an operator() to read its values. + /// + /// For the sake of convenience it also works as a usual + /// \ref concepts::ReadMap "readable map", i.e. operator[] + /// and the \c Key and \c Value typedefs also exist. + /// + /// The simplest way of using this map is through the mapToFunctor() + /// function. + /// + ///\sa FunctorToMap + template + class MapToFunctor : public MapBase { + const M &_m; + public: + ///\e + typedef typename M::Key Key; + ///\e + typedef typename M::Value Value; + + typedef typename M::Key argument_type; + typedef typename M::Value result_type; + + /// Constructor + MapToFunctor(const M &m) : _m(m) {} + ///\e + Value operator()(const Key &k) const { return _m[k]; } + ///\e + Value operator[](const Key &k) const { return _m[k]; } + }; + + /// Returns a \c MapToFunctor class + + /// This function just returns a \c MapToFunctor class. + /// \relates MapToFunctor + template + inline MapToFunctor mapToFunctor(const M &m) { + return MapToFunctor(m); + } + + + /// \brief Map adaptor to convert the \c Value type of a map to + /// another type using the default conversion. + + /// Map adaptor to convert the \c Value type of a \ref concepts::ReadMap + /// "readable map" to another type using the default conversion. + /// The \c Key type of it is inherited from \c M and the \c Value + /// type is \c V. + /// This type conforms to the \ref concepts::ReadMap "ReadMap" concept. + /// + /// The simplest way of using this map is through the convertMap() + /// function. + template + class ConvertMap : public MapBase { + const M &_m; + public: + ///\e + typedef typename M::Key Key; + ///\e + typedef V Value; + + /// Constructor + + /// Constructor. + /// \param m The underlying map. + ConvertMap(const M &m) : _m(m) {} + + ///\e + Value operator[](const Key &k) const { return _m[k]; } + }; + + /// Returns a \c ConvertMap class + + /// This function just returns a \c ConvertMap class. + /// \relates ConvertMap + template + inline ConvertMap convertMap(const M &map) { + return ConvertMap(map); + } + + + /// Applies all map setting operations to two maps + + /// This map has two \ref concepts::WriteMap "writable map" parameters + /// and each write request will be passed to both of them. + /// If \c M1 is also \ref concepts::ReadMap "readable", then the read + /// operations will return the corresponding values of \c M1. + /// + /// The \c Key and \c Value types are inherited from \c M1. + /// The \c Key and \c Value of \c M2 must be convertible from those + /// of \c M1. + /// + /// The simplest way of using this map is through the forkMap() + /// function. + template + class ForkMap : public MapBase { + M1 &_m1; + M2 &_m2; + public: + ///\e + typedef typename M1::Key Key; + ///\e + typedef typename M1::Value Value; + + /// Constructor + ForkMap(M1 &m1, M2 &m2) : _m1(m1), _m2(m2) {} + /// Returns the value associated with the given key in the first map. + Value operator[](const Key &k) const { return _m1[k]; } + /// Sets the value associated with the given key in both maps. + void set(const Key &k, const Value &v) { _m1.set(k,v); _m2.set(k,v); } + }; + + /// Returns a \c ForkMap class + + /// This function just returns a \c ForkMap class. + /// \relates ForkMap + template + inline ForkMap forkMap(M1 &m1, M2 &m2) { + return ForkMap(m1,m2); + } + + + /// Sum of two maps + + /// This \ref concepts::ReadMap "read-only map" returns the sum + /// of the values of the two given maps. + /// Its \c Key and \c Value types are inherited from \c M1. + /// The \c Key and \c Value of \c M2 must be convertible to those of + /// \c M1. + /// + /// If \c m1 is of type \c M1 and \c m2 is of \c M2, then for + /// \code + /// AddMap am(m1,m2); + /// \endcode + /// am[x] will be equal to m1[x]+m2[x]. + /// + /// The simplest way of using this map is through the addMap() + /// function. + /// + /// \sa SubMap, MulMap, DivMap + /// \sa ShiftMap, ShiftWriteMap + template + class AddMap : public MapBase { + const M1 &_m1; + const M2 &_m2; + public: + ///\e + typedef typename M1::Key Key; + ///\e + typedef typename M1::Value Value; + + /// Constructor + AddMap(const M1 &m1, const M2 &m2) : _m1(m1), _m2(m2) {} + ///\e + Value operator[](const Key &k) const { return _m1[k]+_m2[k]; } + }; + + /// Returns an \c AddMap class + + /// This function just returns an \c AddMap class. + /// + /// For example, if \c m1 and \c m2 are both maps with \c double + /// values, then addMap(m1,m2)[x] will be equal to + /// m1[x]+m2[x]. + /// + /// \relates AddMap + template + inline AddMap addMap(const M1 &m1, const M2 &m2) { + return AddMap(m1,m2); + } + + + /// Difference of two maps + + /// This \ref concepts::ReadMap "read-only map" returns the difference + /// of the values of the two given maps. + /// Its \c Key and \c Value types are inherited from \c M1. + /// The \c Key and \c Value of \c M2 must be convertible to those of + /// \c M1. + /// + /// If \c m1 is of type \c M1 and \c m2 is of \c M2, then for + /// \code + /// SubMap sm(m1,m2); + /// \endcode + /// sm[x] will be equal to m1[x]-m2[x]. + /// + /// The simplest way of using this map is through the subMap() + /// function. + /// + /// \sa AddMap, MulMap, DivMap + template + class SubMap : public MapBase { + const M1 &_m1; + const M2 &_m2; + public: + ///\e + typedef typename M1::Key Key; + ///\e + typedef typename M1::Value Value; + + /// Constructor + SubMap(const M1 &m1, const M2 &m2) : _m1(m1), _m2(m2) {} + ///\e + Value operator[](const Key &k) const { return _m1[k]-_m2[k]; } + }; + + /// Returns a \c SubMap class + + /// This function just returns a \c SubMap class. + /// + /// For example, if \c m1 and \c m2 are both maps with \c double + /// values, then subMap(m1,m2)[x] will be equal to + /// m1[x]-m2[x]. + /// + /// \relates SubMap + template + inline SubMap subMap(const M1 &m1, const M2 &m2) { + return SubMap(m1,m2); + } + + + /// Product of two maps + + /// This \ref concepts::ReadMap "read-only map" returns the product + /// of the values of the two given maps. + /// Its \c Key and \c Value types are inherited from \c M1. + /// The \c Key and \c Value of \c M2 must be convertible to those of + /// \c M1. + /// + /// If \c m1 is of type \c M1 and \c m2 is of \c M2, then for + /// \code + /// MulMap mm(m1,m2); + /// \endcode + /// mm[x] will be equal to m1[x]*m2[x]. + /// + /// The simplest way of using this map is through the mulMap() + /// function. + /// + /// \sa AddMap, SubMap, DivMap + /// \sa ScaleMap, ScaleWriteMap + template + class MulMap : public MapBase { + const M1 &_m1; + const M2 &_m2; + public: + ///\e + typedef typename M1::Key Key; + ///\e + typedef typename M1::Value Value; + + /// Constructor + MulMap(const M1 &m1,const M2 &m2) : _m1(m1), _m2(m2) {} + ///\e + Value operator[](const Key &k) const { return _m1[k]*_m2[k]; } + }; + + /// Returns a \c MulMap class + + /// This function just returns a \c MulMap class. + /// + /// For example, if \c m1 and \c m2 are both maps with \c double + /// values, then mulMap(m1,m2)[x] will be equal to + /// m1[x]*m2[x]. + /// + /// \relates MulMap + template + inline MulMap mulMap(const M1 &m1,const M2 &m2) { + return MulMap(m1,m2); + } + + + /// Quotient of two maps + + /// This \ref concepts::ReadMap "read-only map" returns the quotient + /// of the values of the two given maps. + /// Its \c Key and \c Value types are inherited from \c M1. + /// The \c Key and \c Value of \c M2 must be convertible to those of + /// \c M1. + /// + /// If \c m1 is of type \c M1 and \c m2 is of \c M2, then for + /// \code + /// DivMap dm(m1,m2); + /// \endcode + /// dm[x] will be equal to m1[x]/m2[x]. + /// + /// The simplest way of using this map is through the divMap() + /// function. + /// + /// \sa AddMap, SubMap, MulMap + template + class DivMap : public MapBase { + const M1 &_m1; + const M2 &_m2; + public: + ///\e + typedef typename M1::Key Key; + ///\e + typedef typename M1::Value Value; + + /// Constructor + DivMap(const M1 &m1,const M2 &m2) : _m1(m1), _m2(m2) {} + ///\e + Value operator[](const Key &k) const { return _m1[k]/_m2[k]; } + }; + + /// Returns a \c DivMap class + + /// This function just returns a \c DivMap class. + /// + /// For example, if \c m1 and \c m2 are both maps with \c double + /// values, then divMap(m1,m2)[x] will be equal to + /// m1[x]/m2[x]. + /// + /// \relates DivMap + template + inline DivMap divMap(const M1 &m1,const M2 &m2) { + return DivMap(m1,m2); + } + + + /// Shifts a map with a constant. + + /// This \ref concepts::ReadMap "read-only map" returns the sum of + /// the given map and a constant value (i.e. it shifts the map with + /// the constant). Its \c Key and \c Value are inherited from \c M. + /// + /// Actually, + /// \code + /// ShiftMap sh(m,v); + /// \endcode + /// is equivalent to + /// \code + /// ConstMap cm(v); + /// AddMap > sh(m,cm); + /// \endcode + /// + /// The simplest way of using this map is through the shiftMap() + /// function. + /// + /// \sa ShiftWriteMap + template + class ShiftMap : public MapBase { + const M &_m; + C _v; + public: + ///\e + typedef typename M::Key Key; + ///\e + typedef typename M::Value Value; + + /// Constructor + + /// Constructor. + /// \param m The undelying map. + /// \param v The constant value. + ShiftMap(const M &m, const C &v) : _m(m), _v(v) {} + ///\e + Value operator[](const Key &k) const { return _m[k]+_v; } + }; + + /// Shifts a map with a constant (read-write version). + + /// This \ref concepts::ReadWriteMap "read-write map" returns the sum + /// of the given map and a constant value (i.e. it shifts the map with + /// the constant). Its \c Key and \c Value are inherited from \c M. + /// It makes also possible to write the map. + /// + /// The simplest way of using this map is through the shiftWriteMap() + /// function. + /// + /// \sa ShiftMap + template + class ShiftWriteMap : public MapBase { + M &_m; + C _v; + public: + ///\e + typedef typename M::Key Key; + ///\e + typedef typename M::Value Value; + + /// Constructor + + /// Constructor. + /// \param m The undelying map. + /// \param v The constant value. + ShiftWriteMap(M &m, const C &v) : _m(m), _v(v) {} + ///\e + Value operator[](const Key &k) const { return _m[k]+_v; } + ///\e + void set(const Key &k, const Value &v) { _m.set(k, v-_v); } + }; + + /// Returns a \c ShiftMap class + + /// This function just returns a \c ShiftMap class. + /// + /// For example, if \c m is a map with \c double values and \c v is + /// \c double, then shiftMap(m,v)[x] will be equal to + /// m[x]+v. + /// + /// \relates ShiftMap + template + inline ShiftMap shiftMap(const M &m, const C &v) { + return ShiftMap(m,v); + } + + /// Returns a \c ShiftWriteMap class + + /// This function just returns a \c ShiftWriteMap class. + /// + /// For example, if \c m is a map with \c double values and \c v is + /// \c double, then shiftWriteMap(m,v)[x] will be equal to + /// m[x]+v. + /// Moreover it makes also possible to write the map. + /// + /// \relates ShiftWriteMap + template + inline ShiftWriteMap shiftWriteMap(M &m, const C &v) { + return ShiftWriteMap(m,v); + } + + + /// Scales a map with a constant. + + /// This \ref concepts::ReadMap "read-only map" returns the value of + /// the given map multiplied from the left side with a constant value. + /// Its \c Key and \c Value are inherited from \c M. + /// + /// Actually, + /// \code + /// ScaleMap sc(m,v); + /// \endcode + /// is equivalent to + /// \code + /// ConstMap cm(v); + /// MulMap, M> sc(cm,m); + /// \endcode + /// + /// The simplest way of using this map is through the scaleMap() + /// function. + /// + /// \sa ScaleWriteMap + template + class ScaleMap : public MapBase { + const M &_m; + C _v; + public: + ///\e + typedef typename M::Key Key; + ///\e + typedef typename M::Value Value; + + /// Constructor + + /// Constructor. + /// \param m The undelying map. + /// \param v The constant value. + ScaleMap(const M &m, const C &v) : _m(m), _v(v) {} + ///\e + Value operator[](const Key &k) const { return _v*_m[k]; } + }; + + /// Scales a map with a constant (read-write version). + + /// This \ref concepts::ReadWriteMap "read-write map" returns the value of + /// the given map multiplied from the left side with a constant value. + /// Its \c Key and \c Value are inherited from \c M. + /// It can also be used as write map if the \c / operator is defined + /// between \c Value and \c C and the given multiplier is not zero. + /// + /// The simplest way of using this map is through the scaleWriteMap() + /// function. + /// + /// \sa ScaleMap + template + class ScaleWriteMap : public MapBase { + M &_m; + C _v; + public: + ///\e + typedef typename M::Key Key; + ///\e + typedef typename M::Value Value; + + /// Constructor + + /// Constructor. + /// \param m The undelying map. + /// \param v The constant value. + ScaleWriteMap(M &m, const C &v) : _m(m), _v(v) {} + ///\e + Value operator[](const Key &k) const { return _v*_m[k]; } + ///\e + void set(const Key &k, const Value &v) { _m.set(k, v/_v); } + }; + + /// Returns a \c ScaleMap class + + /// This function just returns a \c ScaleMap class. + /// + /// For example, if \c m is a map with \c double values and \c v is + /// \c double, then scaleMap(m,v)[x] will be equal to + /// v*m[x]. + /// + /// \relates ScaleMap + template + inline ScaleMap scaleMap(const M &m, const C &v) { + return ScaleMap(m,v); + } + + /// Returns a \c ScaleWriteMap class + + /// This function just returns a \c ScaleWriteMap class. + /// + /// For example, if \c m is a map with \c double values and \c v is + /// \c double, then scaleWriteMap(m,v)[x] will be equal to + /// v*m[x]. + /// Moreover it makes also possible to write the map. + /// + /// \relates ScaleWriteMap + template + inline ScaleWriteMap scaleWriteMap(M &m, const C &v) { + return ScaleWriteMap(m,v); + } + + + /// Negative of a map + + /// This \ref concepts::ReadMap "read-only map" returns the negative + /// of the values of the given map (using the unary \c - operator). + /// Its \c Key and \c Value are inherited from \c M. + /// + /// If M::Value is \c int, \c double etc., then + /// \code + /// NegMap neg(m); + /// \endcode + /// is equivalent to + /// \code + /// ScaleMap neg(m,-1); + /// \endcode + /// + /// The simplest way of using this map is through the negMap() + /// function. + /// + /// \sa NegWriteMap + template + class NegMap : public MapBase { + const M& _m; + public: + ///\e + typedef typename M::Key Key; + ///\e + typedef typename M::Value Value; + + /// Constructor + NegMap(const M &m) : _m(m) {} + ///\e + Value operator[](const Key &k) const { return -_m[k]; } + }; + + /// Negative of a map (read-write version) + + /// This \ref concepts::ReadWriteMap "read-write map" returns the + /// negative of the values of the given map (using the unary \c - + /// operator). + /// Its \c Key and \c Value are inherited from \c M. + /// It makes also possible to write the map. + /// + /// If M::Value is \c int, \c double etc., then + /// \code + /// NegWriteMap neg(m); + /// \endcode + /// is equivalent to + /// \code + /// ScaleWriteMap neg(m,-1); + /// \endcode + /// + /// The simplest way of using this map is through the negWriteMap() + /// function. + /// + /// \sa NegMap + template + class NegWriteMap : public MapBase { + M &_m; + public: + ///\e + typedef typename M::Key Key; + ///\e + typedef typename M::Value Value; + + /// Constructor + NegWriteMap(M &m) : _m(m) {} + ///\e + Value operator[](const Key &k) const { return -_m[k]; } + ///\e + void set(const Key &k, const Value &v) { _m.set(k, -v); } + }; + + /// Returns a \c NegMap class + + /// This function just returns a \c NegMap class. + /// + /// For example, if \c m is a map with \c double values, then + /// negMap(m)[x] will be equal to -m[x]. + /// + /// \relates NegMap + template + inline NegMap negMap(const M &m) { + return NegMap(m); + } + + /// Returns a \c NegWriteMap class + + /// This function just returns a \c NegWriteMap class. + /// + /// For example, if \c m is a map with \c double values, then + /// negWriteMap(m)[x] will be equal to -m[x]. + /// Moreover it makes also possible to write the map. + /// + /// \relates NegWriteMap + template + inline NegWriteMap negWriteMap(M &m) { + return NegWriteMap(m); + } + + + /// Absolute value of a map + + /// This \ref concepts::ReadMap "read-only map" returns the absolute + /// value of the values of the given map. + /// Its \c Key and \c Value are inherited from \c M. + /// \c Value must be comparable to \c 0 and the unary \c - + /// operator must be defined for it, of course. + /// + /// The simplest way of using this map is through the absMap() + /// function. + template + class AbsMap : public MapBase { + const M &_m; + public: + ///\e + typedef typename M::Key Key; + ///\e + typedef typename M::Value Value; + + /// Constructor + AbsMap(const M &m) : _m(m) {} + ///\e + Value operator[](const Key &k) const { + Value tmp = _m[k]; + return tmp >= 0 ? tmp : -tmp; + } + + }; + + /// Returns an \c AbsMap class + + /// This function just returns an \c AbsMap class. + /// + /// For example, if \c m is a map with \c double values, then + /// absMap(m)[x] will be equal to m[x] if + /// it is positive or zero and -m[x] if m[x] is + /// negative. + /// + /// \relates AbsMap + template + inline AbsMap absMap(const M &m) { + return AbsMap(m); + } + + /// @} + + // Logical maps and map adaptors: + + /// \addtogroup maps + /// @{ + + /// Constant \c true map. + + /// This \ref concepts::ReadMap "read-only map" assigns \c true to + /// each key. + /// + /// Note that + /// \code + /// TrueMap tm; + /// \endcode + /// is equivalent to + /// \code + /// ConstMap tm(true); + /// \endcode + /// + /// \sa FalseMap + /// \sa ConstMap + template + class TrueMap : public MapBase { + public: + ///\e + typedef K Key; + ///\e + typedef bool Value; + + /// Gives back \c true. + Value operator[](const Key&) const { return true; } + }; + + /// Returns a \c TrueMap class + + /// This function just returns a \c TrueMap class. + /// \relates TrueMap + template + inline TrueMap trueMap() { + return TrueMap(); + } + + + /// Constant \c false map. + + /// This \ref concepts::ReadMap "read-only map" assigns \c false to + /// each key. + /// + /// Note that + /// \code + /// FalseMap fm; + /// \endcode + /// is equivalent to + /// \code + /// ConstMap fm(false); + /// \endcode + /// + /// \sa TrueMap + /// \sa ConstMap + template + class FalseMap : public MapBase { + public: + ///\e + typedef K Key; + ///\e + typedef bool Value; + + /// Gives back \c false. + Value operator[](const Key&) const { return false; } + }; + + /// Returns a \c FalseMap class + + /// This function just returns a \c FalseMap class. + /// \relates FalseMap + template + inline FalseMap falseMap() { + return FalseMap(); + } + + /// @} + + /// \addtogroup map_adaptors + /// @{ + + /// Logical 'and' of two maps + + /// This \ref concepts::ReadMap "read-only map" returns the logical + /// 'and' of the values of the two given maps. + /// Its \c Key type is inherited from \c M1 and its \c Value type is + /// \c bool. \c M2::Key must be convertible to \c M1::Key. + /// + /// If \c m1 is of type \c M1 and \c m2 is of \c M2, then for + /// \code + /// AndMap am(m1,m2); + /// \endcode + /// am[x] will be equal to m1[x]&&m2[x]. + /// + /// The simplest way of using this map is through the andMap() + /// function. + /// + /// \sa OrMap + /// \sa NotMap, NotWriteMap + template + class AndMap : public MapBase { + const M1 &_m1; + const M2 &_m2; + public: + ///\e + typedef typename M1::Key Key; + ///\e + typedef bool Value; + + /// Constructor + AndMap(const M1 &m1, const M2 &m2) : _m1(m1), _m2(m2) {} + ///\e + Value operator[](const Key &k) const { return _m1[k]&&_m2[k]; } + }; + + /// Returns an \c AndMap class + + /// This function just returns an \c AndMap class. + /// + /// For example, if \c m1 and \c m2 are both maps with \c bool values, + /// then andMap(m1,m2)[x] will be equal to + /// m1[x]&&m2[x]. + /// + /// \relates AndMap + template + inline AndMap andMap(const M1 &m1, const M2 &m2) { + return AndMap(m1,m2); + } + + + /// Logical 'or' of two maps + + /// This \ref concepts::ReadMap "read-only map" returns the logical + /// 'or' of the values of the two given maps. + /// Its \c Key type is inherited from \c M1 and its \c Value type is + /// \c bool. \c M2::Key must be convertible to \c M1::Key. + /// + /// If \c m1 is of type \c M1 and \c m2 is of \c M2, then for + /// \code + /// OrMap om(m1,m2); + /// \endcode + /// om[x] will be equal to m1[x]||m2[x]. + /// + /// The simplest way of using this map is through the orMap() + /// function. + /// + /// \sa AndMap + /// \sa NotMap, NotWriteMap + template + class OrMap : public MapBase { + const M1 &_m1; + const M2 &_m2; + public: + ///\e + typedef typename M1::Key Key; + ///\e + typedef bool Value; + + /// Constructor + OrMap(const M1 &m1, const M2 &m2) : _m1(m1), _m2(m2) {} + ///\e + Value operator[](const Key &k) const { return _m1[k]||_m2[k]; } + }; + + /// Returns an \c OrMap class + + /// This function just returns an \c OrMap class. + /// + /// For example, if \c m1 and \c m2 are both maps with \c bool values, + /// then orMap(m1,m2)[x] will be equal to + /// m1[x]||m2[x]. + /// + /// \relates OrMap + template + inline OrMap orMap(const M1 &m1, const M2 &m2) { + return OrMap(m1,m2); + } + + + /// Logical 'not' of a map + + /// This \ref concepts::ReadMap "read-only map" returns the logical + /// negation of the values of the given map. + /// Its \c Key is inherited from \c M and its \c Value is \c bool. + /// + /// The simplest way of using this map is through the notMap() + /// function. + /// + /// \sa NotWriteMap + template + class NotMap : public MapBase { + const M &_m; + public: + ///\e + typedef typename M::Key Key; + ///\e + typedef bool Value; + + /// Constructor + NotMap(const M &m) : _m(m) {} + ///\e + Value operator[](const Key &k) const { return !_m[k]; } + }; + + /// Logical 'not' of a map (read-write version) + + /// This \ref concepts::ReadWriteMap "read-write map" returns the + /// logical negation of the values of the given map. + /// Its \c Key is inherited from \c M and its \c Value is \c bool. + /// It makes also possible to write the map. When a value is set, + /// the opposite value is set to the original map. + /// + /// The simplest way of using this map is through the notWriteMap() + /// function. + /// + /// \sa NotMap + template + class NotWriteMap : public MapBase { + M &_m; + public: + ///\e + typedef typename M::Key Key; + ///\e + typedef bool Value; + + /// Constructor + NotWriteMap(M &m) : _m(m) {} + ///\e + Value operator[](const Key &k) const { return !_m[k]; } + ///\e + void set(const Key &k, bool v) { _m.set(k, !v); } + }; + + /// Returns a \c NotMap class + + /// This function just returns a \c NotMap class. + /// + /// For example, if \c m is a map with \c bool values, then + /// notMap(m)[x] will be equal to !m[x]. + /// + /// \relates NotMap + template + inline NotMap notMap(const M &m) { + return NotMap(m); + } + + /// Returns a \c NotWriteMap class + + /// This function just returns a \c NotWriteMap class. + /// + /// For example, if \c m is a map with \c bool values, then + /// notWriteMap(m)[x] will be equal to !m[x]. + /// Moreover it makes also possible to write the map. + /// + /// \relates NotWriteMap + template + inline NotWriteMap notWriteMap(M &m) { + return NotWriteMap(m); + } + + + /// Combination of two maps using the \c == operator + + /// This \ref concepts::ReadMap "read-only map" assigns \c true to + /// the keys for which the corresponding values of the two maps are + /// equal. + /// Its \c Key type is inherited from \c M1 and its \c Value type is + /// \c bool. \c M2::Key must be convertible to \c M1::Key. + /// + /// If \c m1 is of type \c M1 and \c m2 is of \c M2, then for + /// \code + /// EqualMap em(m1,m2); + /// \endcode + /// em[x] will be equal to m1[x]==m2[x]. + /// + /// The simplest way of using this map is through the equalMap() + /// function. + /// + /// \sa LessMap + template + class EqualMap : public MapBase { + const M1 &_m1; + const M2 &_m2; + public: + ///\e + typedef typename M1::Key Key; + ///\e + typedef bool Value; + + /// Constructor + EqualMap(const M1 &m1, const M2 &m2) : _m1(m1), _m2(m2) {} + ///\e + Value operator[](const Key &k) const { return _m1[k]==_m2[k]; } + }; + + /// Returns an \c EqualMap class + + /// This function just returns an \c EqualMap class. + /// + /// For example, if \c m1 and \c m2 are maps with keys and values of + /// the same type, then equalMap(m1,m2)[x] will be equal to + /// m1[x]==m2[x]. + /// + /// \relates EqualMap + template + inline EqualMap equalMap(const M1 &m1, const M2 &m2) { + return EqualMap(m1,m2); + } + + + /// Combination of two maps using the \c < operator + + /// This \ref concepts::ReadMap "read-only map" assigns \c true to + /// the keys for which the corresponding value of the first map is + /// less then the value of the second map. + /// Its \c Key type is inherited from \c M1 and its \c Value type is + /// \c bool. \c M2::Key must be convertible to \c M1::Key. + /// + /// If \c m1 is of type \c M1 and \c m2 is of \c M2, then for + /// \code + /// LessMap lm(m1,m2); + /// \endcode + /// lm[x] will be equal to m1[x]. + /// + /// The simplest way of using this map is through the lessMap() + /// function. + /// + /// \sa EqualMap + template + class LessMap : public MapBase { + const M1 &_m1; + const M2 &_m2; + public: + ///\e + typedef typename M1::Key Key; + ///\e + typedef bool Value; + + /// Constructor + LessMap(const M1 &m1, const M2 &m2) : _m1(m1), _m2(m2) {} + ///\e + Value operator[](const Key &k) const { return _m1[k]<_m2[k]; } + }; + + /// Returns an \c LessMap class + + /// This function just returns an \c LessMap class. + /// + /// For example, if \c m1 and \c m2 are maps with keys and values of + /// the same type, then lessMap(m1,m2)[x] will be equal to + /// m1[x]. + /// + /// \relates LessMap + template + inline LessMap lessMap(const M1 &m1, const M2 &m2) { + return LessMap(m1,m2); + } + + namespace _maps_bits { + + template + struct IteratorTraits { + typedef typename std::iterator_traits<_Iterator>::value_type Value; + }; + + template + struct IteratorTraits<_Iterator, + typename exists::type> + { + typedef typename _Iterator::container_type::value_type Value; + }; + + } + + /// @} + + /// \addtogroup maps + /// @{ + + /// \brief Writable bool map for logging each \c true assigned element + /// + /// A \ref concepts::WriteMap "writable" bool map for logging + /// each \c true assigned element, i.e it copies subsequently each + /// keys set to \c true to the given iterator. + /// The most important usage of it is storing certain nodes or arcs + /// that were marked \c true by an algorithm. + /// + /// There are several algorithms that provide solutions through bool + /// maps and most of them assign \c true at most once for each key. + /// In these cases it is a natural request to store each \c true + /// assigned elements (in order of the assignment), which can be + /// easily done with LoggerBoolMap. + /// + /// The simplest way of using this map is through the loggerBoolMap() + /// function. + /// + /// \tparam IT The type of the iterator. + /// \tparam KEY The key type of the map. The default value set + /// according to the iterator type should work in most cases. + /// + /// \note The container of the iterator must contain enough space + /// for the elements or the iterator should be an inserter iterator. +#ifdef DOXYGEN + template +#else + template ::Value> +#endif + class LoggerBoolMap : public MapBase { + public: + + ///\e + typedef KEY Key; + ///\e + typedef bool Value; + ///\e + typedef IT Iterator; + + /// Constructor + LoggerBoolMap(Iterator it) + : _begin(it), _end(it) {} + + /// Gives back the given iterator set for the first key + Iterator begin() const { + return _begin; + } + + /// Gives back the the 'after the last' iterator + Iterator end() const { + return _end; + } + + /// The set function of the map + void set(const Key& key, Value value) { + if (value) { + *_end++ = key; + } + } + + private: + Iterator _begin; + Iterator _end; + }; + + /// Returns a \c LoggerBoolMap class + + /// This function just returns a \c LoggerBoolMap class. + /// + /// The most important usage of it is storing certain nodes or arcs + /// that were marked \c true by an algorithm. + /// For example, it makes easier to store the nodes in the processing + /// order of Dfs algorithm, as the following examples show. + /// \code + /// std::vector v; + /// dfs(g).processedMap(loggerBoolMap(std::back_inserter(v))).run(s); + /// \endcode + /// \code + /// std::vector v(countNodes(g)); + /// dfs(g).processedMap(loggerBoolMap(v.begin())).run(s); + /// \endcode + /// + /// \note The container of the iterator must contain enough space + /// for the elements or the iterator should be an inserter iterator. + /// + /// \note LoggerBoolMap is just \ref concepts::WriteMap "writable", so + /// it cannot be used when a readable map is needed, for example, as + /// \c ReachedMap for \c Bfs, \c Dfs and \c Dijkstra algorithms. + /// + /// \relates LoggerBoolMap + template + inline LoggerBoolMap loggerBoolMap(Iterator it) { + return LoggerBoolMap(it); + } + + /// @} + + /// \addtogroup graph_maps + /// @{ + + /// \brief Provides an immutable and unique id for each item in a graph. + /// + /// IdMap provides a unique and immutable id for each item of the + /// same type (\c Node, \c Arc or \c Edge) in a graph. This id is + /// - \b unique: different items get different ids, + /// - \b immutable: the id of an item does not change (even if you + /// delete other nodes). + /// + /// Using this map you get access (i.e. can read) the inner id values of + /// the items stored in the graph, which is returned by the \c id() + /// function of the graph. This map can be inverted with its member + /// class \c InverseMap or with the \c operator()() member. + /// + /// \tparam GR The graph type. + /// \tparam K The key type of the map (\c GR::Node, \c GR::Arc or + /// \c GR::Edge). + /// + /// \see RangeIdMap + template + class IdMap : public MapBase { + public: + /// The graph type of IdMap. + typedef GR Graph; + typedef GR Digraph; + /// The key type of IdMap (\c Node, \c Arc or \c Edge). + typedef K Item; + /// The key type of IdMap (\c Node, \c Arc or \c Edge). + typedef K Key; + /// The value type of IdMap. + typedef int Value; + + /// \brief Constructor. + /// + /// Constructor of the map. + explicit IdMap(const Graph& graph) : _graph(&graph) {} + + /// \brief Gives back the \e id of the item. + /// + /// Gives back the immutable and unique \e id of the item. + int operator[](const Item& item) const { return _graph->id(item);} + + /// \brief Gives back the \e item by its id. + /// + /// Gives back the \e item by its id. + Item operator()(int id) { return _graph->fromId(id, Item()); } + + private: + const Graph* _graph; + + public: + + /// \brief The inverse map type of IdMap. + /// + /// The inverse map type of IdMap. The subscript operator gives back + /// an item by its id. + /// This type conforms to the \ref concepts::ReadMap "ReadMap" concept. + /// \see inverse() + class InverseMap { + public: + + /// \brief Constructor. + /// + /// Constructor for creating an id-to-item map. + explicit InverseMap(const Graph& graph) : _graph(&graph) {} + + /// \brief Constructor. + /// + /// Constructor for creating an id-to-item map. + explicit InverseMap(const IdMap& map) : _graph(map._graph) {} + + /// \brief Gives back an item by its id. + /// + /// Gives back an item by its id. + Item operator[](int id) const { return _graph->fromId(id, Item());} + + private: + const Graph* _graph; + }; + + /// \brief Gives back the inverse of the map. + /// + /// Gives back the inverse of the IdMap. + InverseMap inverse() const { return InverseMap(*_graph);} + }; + + /// \brief Returns an \c IdMap class. + /// + /// This function just returns an \c IdMap class. + /// \relates IdMap + template + inline IdMap idMap(const GR& graph) { + return IdMap(graph); + } + + /// \brief General cross reference graph map type. + + /// This class provides simple invertable graph maps. + /// It wraps a standard graph map (\c NodeMap, \c ArcMap or \c EdgeMap) + /// and if a key is set to a new value, then stores it in the inverse map. + /// The graph items can be accessed by their values either using + /// \c InverseMap or \c operator()(), and the values of the map can be + /// accessed with an STL compatible forward iterator (\c ValueIt). + /// + /// This map is intended to be used when all associated values are + /// different (the map is actually invertable) or there are only a few + /// items with the same value. + /// Otherwise consider to use \c IterableValueMap, which is more + /// suitable and more efficient for such cases. It provides iterators + /// to traverse the items with the same associated value, but + /// it does not have \c InverseMap. + /// + /// This type is not reference map, so it cannot be modified with + /// the subscript operator. + /// + /// \tparam GR The graph type. + /// \tparam K The key type of the map (\c GR::Node, \c GR::Arc or + /// \c GR::Edge). + /// \tparam V The value type of the map. + /// + /// \see IterableValueMap + template + class CrossRefMap + : protected ItemSetTraits::template Map::Type { + private: + + typedef typename ItemSetTraits:: + template Map::Type Map; + + typedef std::multimap Container; + Container _inv_map; + + public: + + /// The graph type of CrossRefMap. + typedef GR Graph; + typedef GR Digraph; + /// The key type of CrossRefMap (\c Node, \c Arc or \c Edge). + typedef K Item; + /// The key type of CrossRefMap (\c Node, \c Arc or \c Edge). + typedef K Key; + /// The value type of CrossRefMap. + typedef V Value; + + /// \brief Constructor. + /// + /// Construct a new CrossRefMap for the given graph. + explicit CrossRefMap(const Graph& graph) : Map(graph) {} + + /// \brief Forward iterator for values. + /// + /// This iterator is an STL compatible forward + /// iterator on the values of the map. The values can + /// be accessed in the [beginValue, endValue) range. + /// They are considered with multiplicity, so each value is + /// traversed for each item it is assigned to. + class ValueIt + : public std::iterator { + friend class CrossRefMap; + private: + ValueIt(typename Container::const_iterator _it) + : it(_it) {} + public: + + /// Constructor + ValueIt() {} + + /// \e + ValueIt& operator++() { ++it; return *this; } + /// \e + ValueIt operator++(int) { + ValueIt tmp(*this); + operator++(); + return tmp; + } + + /// \e + const Value& operator*() const { return it->first; } + /// \e + const Value* operator->() const { return &(it->first); } + + /// \e + bool operator==(ValueIt jt) const { return it == jt.it; } + /// \e + bool operator!=(ValueIt jt) const { return it != jt.it; } + + private: + typename Container::const_iterator it; + }; + + /// Alias for \c ValueIt + typedef ValueIt ValueIterator; + + /// \brief Returns an iterator to the first value. + /// + /// Returns an STL compatible iterator to the + /// first value of the map. The values of the + /// map can be accessed in the [beginValue, endValue) + /// range. + ValueIt beginValue() const { + return ValueIt(_inv_map.begin()); + } + + /// \brief Returns an iterator after the last value. + /// + /// Returns an STL compatible iterator after the + /// last value of the map. The values of the + /// map can be accessed in the [beginValue, endValue) + /// range. + ValueIt endValue() const { + return ValueIt(_inv_map.end()); + } + + /// \brief Sets the value associated with the given key. + /// + /// Sets the value associated with the given key. + void set(const Key& key, const Value& val) { + Value oldval = Map::operator[](key); + typename Container::iterator it; + for (it = _inv_map.equal_range(oldval).first; + it != _inv_map.equal_range(oldval).second; ++it) { + if (it->second == key) { + _inv_map.erase(it); + break; + } + } + _inv_map.insert(std::make_pair(val, key)); + Map::set(key, val); + } + + /// \brief Returns the value associated with the given key. + /// + /// Returns the value associated with the given key. + typename MapTraits::ConstReturnValue + operator[](const Key& key) const { + return Map::operator[](key); + } + + /// \brief Gives back an item by its value. + /// + /// This function gives back an item that is assigned to + /// the given value or \c INVALID if no such item exists. + /// If there are more items with the same associated value, + /// only one of them is returned. + Key operator()(const Value& val) const { + typename Container::const_iterator it = _inv_map.find(val); + return it != _inv_map.end() ? it->second : INVALID; + } + + /// \brief Returns the number of items with the given value. + /// + /// This function returns the number of items with the given value + /// associated with it. + int count(const Value &val) const { + return _inv_map.count(val); + } + + protected: + + /// \brief Erase the key from the map and the inverse map. + /// + /// Erase the key from the map and the inverse map. It is called by the + /// \c AlterationNotifier. + virtual void erase(const Key& key) { + Value val = Map::operator[](key); + typename Container::iterator it; + for (it = _inv_map.equal_range(val).first; + it != _inv_map.equal_range(val).second; ++it) { + if (it->second == key) { + _inv_map.erase(it); + break; + } + } + Map::erase(key); + } + + /// \brief Erase more keys from the map and the inverse map. + /// + /// Erase more keys from the map and the inverse map. It is called by the + /// \c AlterationNotifier. + virtual void erase(const std::vector& keys) { + for (int i = 0; i < int(keys.size()); ++i) { + Value val = Map::operator[](keys[i]); + typename Container::iterator it; + for (it = _inv_map.equal_range(val).first; + it != _inv_map.equal_range(val).second; ++it) { + if (it->second == keys[i]) { + _inv_map.erase(it); + break; + } + } + } + Map::erase(keys); + } + + /// \brief Clear the keys from the map and the inverse map. + /// + /// Clear the keys from the map and the inverse map. It is called by the + /// \c AlterationNotifier. + virtual void clear() { + _inv_map.clear(); + Map::clear(); + } + + public: + + /// \brief The inverse map type of CrossRefMap. + /// + /// The inverse map type of CrossRefMap. The subscript operator gives + /// back an item by its value. + /// This type conforms to the \ref concepts::ReadMap "ReadMap" concept. + /// \see inverse() + class InverseMap { + public: + /// \brief Constructor + /// + /// Constructor of the InverseMap. + explicit InverseMap(const CrossRefMap& inverted) + : _inverted(inverted) {} + + /// The value type of the InverseMap. + typedef typename CrossRefMap::Key Value; + /// The key type of the InverseMap. + typedef typename CrossRefMap::Value Key; + + /// \brief Subscript operator. + /// + /// Subscript operator. It gives back an item + /// that is assigned to the given value or \c INVALID + /// if no such item exists. + Value operator[](const Key& key) const { + return _inverted(key); + } + + private: + const CrossRefMap& _inverted; + }; + + /// \brief Gives back the inverse of the map. + /// + /// Gives back the inverse of the CrossRefMap. + InverseMap inverse() const { + return InverseMap(*this); + } + + }; + + /// \brief Provides continuous and unique id for the + /// items of a graph. + /// + /// RangeIdMap provides a unique and continuous + /// id for each item of a given type (\c Node, \c Arc or + /// \c Edge) in a graph. This id is + /// - \b unique: different items get different ids, + /// - \b continuous: the range of the ids is the set of integers + /// between 0 and \c n-1, where \c n is the number of the items of + /// this type (\c Node, \c Arc or \c Edge). + /// - So, the ids can change when deleting an item of the same type. + /// + /// Thus this id is not (necessarily) the same as what can get using + /// the \c id() function of the graph or \ref IdMap. + /// This map can be inverted with its member class \c InverseMap, + /// or with the \c operator()() member. + /// + /// \tparam GR The graph type. + /// \tparam K The key type of the map (\c GR::Node, \c GR::Arc or + /// \c GR::Edge). + /// + /// \see IdMap + template + class RangeIdMap + : protected ItemSetTraits::template Map::Type { + + typedef typename ItemSetTraits::template Map::Type Map; + + public: + /// The graph type of RangeIdMap. + typedef GR Graph; + typedef GR Digraph; + /// The key type of RangeIdMap (\c Node, \c Arc or \c Edge). + typedef K Item; + /// The key type of RangeIdMap (\c Node, \c Arc or \c Edge). + typedef K Key; + /// The value type of RangeIdMap. + typedef int Value; + + /// \brief Constructor. + /// + /// Constructor. + explicit RangeIdMap(const Graph& gr) : Map(gr) { + Item it; + const typename Map::Notifier* nf = Map::notifier(); + for (nf->first(it); it != INVALID; nf->next(it)) { + Map::set(it, _inv_map.size()); + _inv_map.push_back(it); + } + } + + protected: + + /// \brief Adds a new key to the map. + /// + /// Add a new key to the map. It is called by the + /// \c AlterationNotifier. + virtual void add(const Item& item) { + Map::add(item); + Map::set(item, _inv_map.size()); + _inv_map.push_back(item); + } + + /// \brief Add more new keys to the map. + /// + /// Add more new keys to the map. It is called by the + /// \c AlterationNotifier. + virtual void add(const std::vector& items) { + Map::add(items); + for (int i = 0; i < int(items.size()); ++i) { + Map::set(items[i], _inv_map.size()); + _inv_map.push_back(items[i]); + } + } + + /// \brief Erase the key from the map. + /// + /// Erase the key from the map. It is called by the + /// \c AlterationNotifier. + virtual void erase(const Item& item) { + Map::set(_inv_map.back(), Map::operator[](item)); + _inv_map[Map::operator[](item)] = _inv_map.back(); + _inv_map.pop_back(); + Map::erase(item); + } + + /// \brief Erase more keys from the map. + /// + /// Erase more keys from the map. It is called by the + /// \c AlterationNotifier. + virtual void erase(const std::vector& items) { + for (int i = 0; i < int(items.size()); ++i) { + Map::set(_inv_map.back(), Map::operator[](items[i])); + _inv_map[Map::operator[](items[i])] = _inv_map.back(); + _inv_map.pop_back(); + } + Map::erase(items); + } + + /// \brief Build the unique map. + /// + /// Build the unique map. It is called by the + /// \c AlterationNotifier. + virtual void build() { + Map::build(); + Item it; + const typename Map::Notifier* nf = Map::notifier(); + for (nf->first(it); it != INVALID; nf->next(it)) { + Map::set(it, _inv_map.size()); + _inv_map.push_back(it); + } + } + + /// \brief Clear the keys from the map. + /// + /// Clear the keys from the map. It is called by the + /// \c AlterationNotifier. + virtual void clear() { + _inv_map.clear(); + Map::clear(); + } + + public: + + /// \brief Returns the maximal value plus one. + /// + /// Returns the maximal value plus one in the map. + unsigned int size() const { + return _inv_map.size(); + } + + /// \brief Swaps the position of the two items in the map. + /// + /// Swaps the position of the two items in the map. + void swap(const Item& p, const Item& q) { + int pi = Map::operator[](p); + int qi = Map::operator[](q); + Map::set(p, qi); + _inv_map[qi] = p; + Map::set(q, pi); + _inv_map[pi] = q; + } + + /// \brief Gives back the \e range \e id of the item + /// + /// Gives back the \e range \e id of the item. + int operator[](const Item& item) const { + return Map::operator[](item); + } + + /// \brief Gives back the item belonging to a \e range \e id + /// + /// Gives back the item belonging to the given \e range \e id. + Item operator()(int id) const { + return _inv_map[id]; + } + + private: + + typedef std::vector Container; + Container _inv_map; + + public: + + /// \brief The inverse map type of RangeIdMap. + /// + /// The inverse map type of RangeIdMap. The subscript operator gives + /// back an item by its \e range \e id. + /// This type conforms to the \ref concepts::ReadMap "ReadMap" concept. + class InverseMap { + public: + /// \brief Constructor + /// + /// Constructor of the InverseMap. + explicit InverseMap(const RangeIdMap& inverted) + : _inverted(inverted) {} + + + /// The value type of the InverseMap. + typedef typename RangeIdMap::Key Value; + /// The key type of the InverseMap. + typedef typename RangeIdMap::Value Key; + + /// \brief Subscript operator. + /// + /// Subscript operator. It gives back the item + /// that the given \e range \e id currently belongs to. + Value operator[](const Key& key) const { + return _inverted(key); + } + + /// \brief Size of the map. + /// + /// Returns the size of the map. + unsigned int size() const { + return _inverted.size(); + } + + private: + const RangeIdMap& _inverted; + }; + + /// \brief Gives back the inverse of the map. + /// + /// Gives back the inverse of the RangeIdMap. + const InverseMap inverse() const { + return InverseMap(*this); + } + }; + + /// \brief Returns a \c RangeIdMap class. + /// + /// This function just returns an \c RangeIdMap class. + /// \relates RangeIdMap + template + inline RangeIdMap rangeIdMap(const GR& graph) { + return RangeIdMap(graph); + } + + /// \brief Dynamic iterable \c bool map. + /// + /// This class provides a special graph map type which can store a + /// \c bool value for graph items (\c Node, \c Arc or \c Edge). + /// For both \c true and \c false values it is possible to iterate on + /// the keys mapped to the value. + /// + /// This type is a reference map, so it can be modified with the + /// subscript operator. + /// + /// \tparam GR The graph type. + /// \tparam K The key type of the map (\c GR::Node, \c GR::Arc or + /// \c GR::Edge). + /// + /// \see IterableIntMap, IterableValueMap + /// \see CrossRefMap + template + class IterableBoolMap + : protected ItemSetTraits::template Map::Type { + private: + typedef GR Graph; + + typedef typename ItemSetTraits::ItemIt KeyIt; + typedef typename ItemSetTraits::template Map::Type Parent; + + std::vector _array; + int _sep; + + public: + + /// Indicates that the map is reference map. + typedef True ReferenceMapTag; + + /// The key type + typedef K Key; + /// The value type + typedef bool Value; + /// The const reference type. + typedef const Value& ConstReference; + + private: + + int position(const Key& key) const { + return Parent::operator[](key); + } + + public: + + /// \brief Reference to the value of the map. + /// + /// This class is similar to the \c bool type. It can be converted to + /// \c bool and it provides the same operators. + class Reference { + friend class IterableBoolMap; + private: + Reference(IterableBoolMap& map, const Key& key) + : _key(key), _map(map) {} + public: + + Reference& operator=(const Reference& value) { + _map.set(_key, static_cast(value)); + return *this; + } + + operator bool() const { + return static_cast(_map)[_key]; + } + + Reference& operator=(bool value) { + _map.set(_key, value); + return *this; + } + Reference& operator&=(bool value) { + _map.set(_key, _map[_key] & value); + return *this; + } + Reference& operator|=(bool value) { + _map.set(_key, _map[_key] | value); + return *this; + } + Reference& operator^=(bool value) { + _map.set(_key, _map[_key] ^ value); + return *this; + } + private: + Key _key; + IterableBoolMap& _map; + }; + + /// \brief Constructor of the map with a default value. + /// + /// Constructor of the map with a default value. + explicit IterableBoolMap(const Graph& graph, bool def = false) + : Parent(graph) { + typename Parent::Notifier* nf = Parent::notifier(); + Key it; + for (nf->first(it); it != INVALID; nf->next(it)) { + Parent::set(it, _array.size()); + _array.push_back(it); + } + _sep = (def ? _array.size() : 0); + } + + /// \brief Const subscript operator of the map. + /// + /// Const subscript operator of the map. + bool operator[](const Key& key) const { + return position(key) < _sep; + } + + /// \brief Subscript operator of the map. + /// + /// Subscript operator of the map. + Reference operator[](const Key& key) { + return Reference(*this, key); + } + + /// \brief Set operation of the map. + /// + /// Set operation of the map. + void set(const Key& key, bool value) { + int pos = position(key); + if (value) { + if (pos < _sep) return; + Key tmp = _array[_sep]; + _array[_sep] = key; + Parent::set(key, _sep); + _array[pos] = tmp; + Parent::set(tmp, pos); + ++_sep; + } else { + if (pos >= _sep) return; + --_sep; + Key tmp = _array[_sep]; + _array[_sep] = key; + Parent::set(key, _sep); + _array[pos] = tmp; + Parent::set(tmp, pos); + } + } + + /// \brief Set all items. + /// + /// Set all items in the map. + /// \note Constant time operation. + void setAll(bool value) { + _sep = (value ? _array.size() : 0); + } + + /// \brief Returns the number of the keys mapped to \c true. + /// + /// Returns the number of the keys mapped to \c true. + int trueNum() const { + return _sep; + } + + /// \brief Returns the number of the keys mapped to \c false. + /// + /// Returns the number of the keys mapped to \c false. + int falseNum() const { + return _array.size() - _sep; + } + + /// \brief Iterator for the keys mapped to \c true. + /// + /// Iterator for the keys mapped to \c true. It works + /// like a graph item iterator, it can be converted to + /// the key type of the map, incremented with \c ++ operator, and + /// if the iterator leaves the last valid key, it will be equal to + /// \c INVALID. + class TrueIt : public Key { + public: + typedef Key Parent; + + /// \brief Creates an iterator. + /// + /// Creates an iterator. It iterates on the + /// keys mapped to \c true. + /// \param map The IterableBoolMap. + explicit TrueIt(const IterableBoolMap& map) + : Parent(map._sep > 0 ? map._array[map._sep - 1] : INVALID), + _map(&map) {} + + /// \brief Invalid constructor \& conversion. + /// + /// This constructor initializes the iterator to be invalid. + /// \sa Invalid for more details. + TrueIt(Invalid) : Parent(INVALID), _map(0) {} + + /// \brief Increment operator. + /// + /// Increment operator. + TrueIt& operator++() { + int pos = _map->position(*this); + Parent::operator=(pos > 0 ? _map->_array[pos - 1] : INVALID); + return *this; + } + + private: + const IterableBoolMap* _map; + }; + + /// \brief Iterator for the keys mapped to \c false. + /// + /// Iterator for the keys mapped to \c false. It works + /// like a graph item iterator, it can be converted to + /// the key type of the map, incremented with \c ++ operator, and + /// if the iterator leaves the last valid key, it will be equal to + /// \c INVALID. + class FalseIt : public Key { + public: + typedef Key Parent; + + /// \brief Creates an iterator. + /// + /// Creates an iterator. It iterates on the + /// keys mapped to \c false. + /// \param map The IterableBoolMap. + explicit FalseIt(const IterableBoolMap& map) + : Parent(map._sep < int(map._array.size()) ? + map._array.back() : INVALID), _map(&map) {} + + /// \brief Invalid constructor \& conversion. + /// + /// This constructor initializes the iterator to be invalid. + /// \sa Invalid for more details. + FalseIt(Invalid) : Parent(INVALID), _map(0) {} + + /// \brief Increment operator. + /// + /// Increment operator. + FalseIt& operator++() { + int pos = _map->position(*this); + Parent::operator=(pos > _map->_sep ? _map->_array[pos - 1] : INVALID); + return *this; + } + + private: + const IterableBoolMap* _map; + }; + + /// \brief Iterator for the keys mapped to a given value. + /// + /// Iterator for the keys mapped to a given value. It works + /// like a graph item iterator, it can be converted to + /// the key type of the map, incremented with \c ++ operator, and + /// if the iterator leaves the last valid key, it will be equal to + /// \c INVALID. + class ItemIt : public Key { + public: + typedef Key Parent; + + /// \brief Creates an iterator with a value. + /// + /// Creates an iterator with a value. It iterates on the + /// keys mapped to the given value. + /// \param map The IterableBoolMap. + /// \param value The value. + ItemIt(const IterableBoolMap& map, bool value) + : Parent(value ? + (map._sep > 0 ? + map._array[map._sep - 1] : INVALID) : + (map._sep < int(map._array.size()) ? + map._array.back() : INVALID)), _map(&map) {} + + /// \brief Invalid constructor \& conversion. + /// + /// This constructor initializes the iterator to be invalid. + /// \sa Invalid for more details. + ItemIt(Invalid) : Parent(INVALID), _map(0) {} + + /// \brief Increment operator. + /// + /// Increment operator. + ItemIt& operator++() { + int pos = _map->position(*this); + int _sep = pos >= _map->_sep ? _map->_sep : 0; + Parent::operator=(pos > _sep ? _map->_array[pos - 1] : INVALID); + return *this; + } + + private: + const IterableBoolMap* _map; + }; + + protected: + + virtual void add(const Key& key) { + Parent::add(key); + Parent::set(key, _array.size()); + _array.push_back(key); + } + + virtual void add(const std::vector& keys) { + Parent::add(keys); + for (int i = 0; i < int(keys.size()); ++i) { + Parent::set(keys[i], _array.size()); + _array.push_back(keys[i]); + } + } + + virtual void erase(const Key& key) { + int pos = position(key); + if (pos < _sep) { + --_sep; + Parent::set(_array[_sep], pos); + _array[pos] = _array[_sep]; + Parent::set(_array.back(), _sep); + _array[_sep] = _array.back(); + _array.pop_back(); + } else { + Parent::set(_array.back(), pos); + _array[pos] = _array.back(); + _array.pop_back(); + } + Parent::erase(key); + } + + virtual void erase(const std::vector& keys) { + for (int i = 0; i < int(keys.size()); ++i) { + int pos = position(keys[i]); + if (pos < _sep) { + --_sep; + Parent::set(_array[_sep], pos); + _array[pos] = _array[_sep]; + Parent::set(_array.back(), _sep); + _array[_sep] = _array.back(); + _array.pop_back(); + } else { + Parent::set(_array.back(), pos); + _array[pos] = _array.back(); + _array.pop_back(); + } + } + Parent::erase(keys); + } + + virtual void build() { + Parent::build(); + typename Parent::Notifier* nf = Parent::notifier(); + Key it; + for (nf->first(it); it != INVALID; nf->next(it)) { + Parent::set(it, _array.size()); + _array.push_back(it); + } + _sep = 0; + } + + virtual void clear() { + _array.clear(); + _sep = 0; + Parent::clear(); + } + + }; + + + namespace _maps_bits { + template + struct IterableIntMapNode { + IterableIntMapNode() : value(-1) {} + IterableIntMapNode(int _value) : value(_value) {} + Item prev, next; + int value; + }; + } + + /// \brief Dynamic iterable integer map. + /// + /// This class provides a special graph map type which can store an + /// integer value for graph items (\c Node, \c Arc or \c Edge). + /// For each non-negative value it is possible to iterate on the keys + /// mapped to the value. + /// + /// This map is intended to be used with small integer values, for which + /// it is efficient, and supports iteration only for non-negative values. + /// If you need large values and/or iteration for negative integers, + /// consider to use \ref IterableValueMap instead. + /// + /// This type is a reference map, so it can be modified with the + /// subscript operator. + /// + /// \note The size of the data structure depends on the largest + /// value in the map. + /// + /// \tparam GR The graph type. + /// \tparam K The key type of the map (\c GR::Node, \c GR::Arc or + /// \c GR::Edge). + /// + /// \see IterableBoolMap, IterableValueMap + /// \see CrossRefMap + template + class IterableIntMap + : protected ItemSetTraits:: + template Map<_maps_bits::IterableIntMapNode >::Type { + public: + typedef typename ItemSetTraits:: + template Map<_maps_bits::IterableIntMapNode >::Type Parent; + + /// The key type + typedef K Key; + /// The value type + typedef int Value; + /// The graph type + typedef GR Graph; + + /// \brief Constructor of the map. + /// + /// Constructor of the map. It sets all values to -1. + explicit IterableIntMap(const Graph& graph) + : Parent(graph) {} + + /// \brief Constructor of the map with a given value. + /// + /// Constructor of the map with a given value. + explicit IterableIntMap(const Graph& graph, int value) + : Parent(graph, _maps_bits::IterableIntMapNode(value)) { + if (value >= 0) { + for (typename Parent::ItemIt it(*this); it != INVALID; ++it) { + lace(it); + } + } + } + + private: + + void unlace(const Key& key) { + typename Parent::Value& node = Parent::operator[](key); + if (node.value < 0) return; + if (node.prev != INVALID) { + Parent::operator[](node.prev).next = node.next; + } else { + _first[node.value] = node.next; + } + if (node.next != INVALID) { + Parent::operator[](node.next).prev = node.prev; + } + while (!_first.empty() && _first.back() == INVALID) { + _first.pop_back(); + } + } + + void lace(const Key& key) { + typename Parent::Value& node = Parent::operator[](key); + if (node.value < 0) return; + if (node.value >= int(_first.size())) { + _first.resize(node.value + 1, INVALID); + } + node.prev = INVALID; + node.next = _first[node.value]; + if (node.next != INVALID) { + Parent::operator[](node.next).prev = key; + } + _first[node.value] = key; + } + + public: + + /// Indicates that the map is reference map. + typedef True ReferenceMapTag; + + /// \brief Reference to the value of the map. + /// + /// This class is similar to the \c int type. It can + /// be converted to \c int and it has the same operators. + class Reference { + friend class IterableIntMap; + private: + Reference(IterableIntMap& map, const Key& key) + : _key(key), _map(map) {} + public: + + Reference& operator=(const Reference& value) { + _map.set(_key, static_cast(value)); + return *this; + } + + operator const int&() const { + return static_cast(_map)[_key]; + } + + Reference& operator=(int value) { + _map.set(_key, value); + return *this; + } + Reference& operator++() { + _map.set(_key, _map[_key] + 1); + return *this; + } + int operator++(int) { + int value = _map[_key]; + _map.set(_key, value + 1); + return value; + } + Reference& operator--() { + _map.set(_key, _map[_key] - 1); + return *this; + } + int operator--(int) { + int value = _map[_key]; + _map.set(_key, value - 1); + return value; + } + Reference& operator+=(int value) { + _map.set(_key, _map[_key] + value); + return *this; + } + Reference& operator-=(int value) { + _map.set(_key, _map[_key] - value); + return *this; + } + Reference& operator*=(int value) { + _map.set(_key, _map[_key] * value); + return *this; + } + Reference& operator/=(int value) { + _map.set(_key, _map[_key] / value); + return *this; + } + Reference& operator%=(int value) { + _map.set(_key, _map[_key] % value); + return *this; + } + Reference& operator&=(int value) { + _map.set(_key, _map[_key] & value); + return *this; + } + Reference& operator|=(int value) { + _map.set(_key, _map[_key] | value); + return *this; + } + Reference& operator^=(int value) { + _map.set(_key, _map[_key] ^ value); + return *this; + } + Reference& operator<<=(int value) { + _map.set(_key, _map[_key] << value); + return *this; + } + Reference& operator>>=(int value) { + _map.set(_key, _map[_key] >> value); + return *this; + } + + private: + Key _key; + IterableIntMap& _map; + }; + + /// The const reference type. + typedef const Value& ConstReference; + + /// \brief Gives back the maximal value plus one. + /// + /// Gives back the maximal value plus one. + int size() const { + return _first.size(); + } + + /// \brief Set operation of the map. + /// + /// Set operation of the map. + void set(const Key& key, const Value& value) { + unlace(key); + Parent::operator[](key).value = value; + lace(key); + } + + /// \brief Const subscript operator of the map. + /// + /// Const subscript operator of the map. + const Value& operator[](const Key& key) const { + return Parent::operator[](key).value; + } + + /// \brief Subscript operator of the map. + /// + /// Subscript operator of the map. + Reference operator[](const Key& key) { + return Reference(*this, key); + } + + /// \brief Iterator for the keys with the same value. + /// + /// Iterator for the keys with the same value. It works + /// like a graph item iterator, it can be converted to + /// the item type of the map, incremented with \c ++ operator, and + /// if the iterator leaves the last valid item, it will be equal to + /// \c INVALID. + class ItemIt : public Key { + public: + typedef Key Parent; + + /// \brief Invalid constructor \& conversion. + /// + /// This constructor initializes the iterator to be invalid. + /// \sa Invalid for more details. + ItemIt(Invalid) : Parent(INVALID), _map(0) {} + + /// \brief Creates an iterator with a value. + /// + /// Creates an iterator with a value. It iterates on the + /// keys mapped to the given value. + /// \param map The IterableIntMap. + /// \param value The value. + ItemIt(const IterableIntMap& map, int value) : _map(&map) { + if (value < 0 || value >= int(_map->_first.size())) { + Parent::operator=(INVALID); + } else { + Parent::operator=(_map->_first[value]); + } + } + + /// \brief Increment operator. + /// + /// Increment operator. + ItemIt& operator++() { + Parent::operator=(_map->IterableIntMap::Parent:: + operator[](static_cast(*this)).next); + return *this; + } + + private: + const IterableIntMap* _map; + }; + + protected: + + virtual void erase(const Key& key) { + unlace(key); + Parent::erase(key); + } + + virtual void erase(const std::vector& keys) { + for (int i = 0; i < int(keys.size()); ++i) { + unlace(keys[i]); + } + Parent::erase(keys); + } + + virtual void clear() { + _first.clear(); + Parent::clear(); + } + + private: + std::vector _first; + }; + + namespace _maps_bits { + template + struct IterableValueMapNode { + IterableValueMapNode(Value _value = Value()) : value(_value) {} + Item prev, next; + Value value; + }; + } + + /// \brief Dynamic iterable map for comparable values. + /// + /// This class provides a special graph map type which can store a + /// comparable value for graph items (\c Node, \c Arc or \c Edge). + /// For each value it is possible to iterate on the keys mapped to + /// the value (\c ItemIt), and the values of the map can be accessed + /// with an STL compatible forward iterator (\c ValueIt). + /// The map stores a linked list for each value, which contains + /// the items mapped to the value, and the used values are stored + /// in balanced binary tree (\c std::map). + /// + /// \ref IterableBoolMap and \ref IterableIntMap are similar classes + /// specialized for \c bool and \c int values, respectively. + /// + /// This type is not reference map, so it cannot be modified with + /// the subscript operator. + /// + /// \tparam GR The graph type. + /// \tparam K The key type of the map (\c GR::Node, \c GR::Arc or + /// \c GR::Edge). + /// \tparam V The value type of the map. It can be any comparable + /// value type. + /// + /// \see IterableBoolMap, IterableIntMap + /// \see CrossRefMap + template + class IterableValueMap + : protected ItemSetTraits:: + template Map<_maps_bits::IterableValueMapNode >::Type { + public: + typedef typename ItemSetTraits:: + template Map<_maps_bits::IterableValueMapNode >::Type Parent; + + /// The key type + typedef K Key; + /// The value type + typedef V Value; + /// The graph type + typedef GR Graph; + + public: + + /// \brief Constructor of the map with a given value. + /// + /// Constructor of the map with a given value. + explicit IterableValueMap(const Graph& graph, + const Value& value = Value()) + : Parent(graph, _maps_bits::IterableValueMapNode(value)) { + for (typename Parent::ItemIt it(*this); it != INVALID; ++it) { + lace(it); + } + } + + protected: + + void unlace(const Key& key) { + typename Parent::Value& node = Parent::operator[](key); + if (node.prev != INVALID) { + Parent::operator[](node.prev).next = node.next; + } else { + if (node.next != INVALID) { + _first[node.value] = node.next; + } else { + _first.erase(node.value); + } + } + if (node.next != INVALID) { + Parent::operator[](node.next).prev = node.prev; + } + } + + void lace(const Key& key) { + typename Parent::Value& node = Parent::operator[](key); + typename std::map::iterator it = _first.find(node.value); + if (it == _first.end()) { + node.prev = node.next = INVALID; + _first.insert(std::make_pair(node.value, key)); + } else { + node.prev = INVALID; + node.next = it->second; + if (node.next != INVALID) { + Parent::operator[](node.next).prev = key; + } + it->second = key; + } + } + + public: + + /// \brief Forward iterator for values. + /// + /// This iterator is an STL compatible forward + /// iterator on the values of the map. The values can + /// be accessed in the [beginValue, endValue) range. + class ValueIt + : public std::iterator { + friend class IterableValueMap; + private: + ValueIt(typename std::map::const_iterator _it) + : it(_it) {} + public: + + /// Constructor + ValueIt() {} + + /// \e + ValueIt& operator++() { ++it; return *this; } + /// \e + ValueIt operator++(int) { + ValueIt tmp(*this); + operator++(); + return tmp; + } + + /// \e + const Value& operator*() const { return it->first; } + /// \e + const Value* operator->() const { return &(it->first); } + + /// \e + bool operator==(ValueIt jt) const { return it == jt.it; } + /// \e + bool operator!=(ValueIt jt) const { return it != jt.it; } + + private: + typename std::map::const_iterator it; + }; + + /// \brief Returns an iterator to the first value. + /// + /// Returns an STL compatible iterator to the + /// first value of the map. The values of the + /// map can be accessed in the [beginValue, endValue) + /// range. + ValueIt beginValue() const { + return ValueIt(_first.begin()); + } + + /// \brief Returns an iterator after the last value. + /// + /// Returns an STL compatible iterator after the + /// last value of the map. The values of the + /// map can be accessed in the [beginValue, endValue) + /// range. + ValueIt endValue() const { + return ValueIt(_first.end()); + } + + /// \brief Set operation of the map. + /// + /// Set operation of the map. + void set(const Key& key, const Value& value) { + unlace(key); + Parent::operator[](key).value = value; + lace(key); + } + + /// \brief Const subscript operator of the map. + /// + /// Const subscript operator of the map. + const Value& operator[](const Key& key) const { + return Parent::operator[](key).value; + } + + /// \brief Iterator for the keys with the same value. + /// + /// Iterator for the keys with the same value. It works + /// like a graph item iterator, it can be converted to + /// the item type of the map, incremented with \c ++ operator, and + /// if the iterator leaves the last valid item, it will be equal to + /// \c INVALID. + class ItemIt : public Key { + public: + typedef Key Parent; + + /// \brief Invalid constructor \& conversion. + /// + /// This constructor initializes the iterator to be invalid. + /// \sa Invalid for more details. + ItemIt(Invalid) : Parent(INVALID), _map(0) {} + + /// \brief Creates an iterator with a value. + /// + /// Creates an iterator with a value. It iterates on the + /// keys which have the given value. + /// \param map The IterableValueMap + /// \param value The value + ItemIt(const IterableValueMap& map, const Value& value) : _map(&map) { + typename std::map::const_iterator it = + map._first.find(value); + if (it == map._first.end()) { + Parent::operator=(INVALID); + } else { + Parent::operator=(it->second); + } + } + + /// \brief Increment operator. + /// + /// Increment Operator. + ItemIt& operator++() { + Parent::operator=(_map->IterableValueMap::Parent:: + operator[](static_cast(*this)).next); + return *this; + } + + + private: + const IterableValueMap* _map; + }; + + protected: + + virtual void add(const Key& key) { + Parent::add(key); + lace(key); + } + + virtual void add(const std::vector& keys) { + Parent::add(keys); + for (int i = 0; i < int(keys.size()); ++i) { + lace(keys[i]); + } + } + + virtual void erase(const Key& key) { + unlace(key); + Parent::erase(key); + } + + virtual void erase(const std::vector& keys) { + for (int i = 0; i < int(keys.size()); ++i) { + unlace(keys[i]); + } + Parent::erase(keys); + } + + virtual void build() { + Parent::build(); + for (typename Parent::ItemIt it(*this); it != INVALID; ++it) { + lace(it); + } + } + + virtual void clear() { + _first.clear(); + Parent::clear(); + } + + private: + std::map _first; + }; + + /// \brief Map of the source nodes of arcs in a digraph. + /// + /// SourceMap provides access for the source node of each arc in a digraph, + /// which is returned by the \c source() function of the digraph. + /// \tparam GR The digraph type. + /// \see TargetMap + template + class SourceMap { + public: + + /// The key type (the \c Arc type of the digraph). + typedef typename GR::Arc Key; + /// The value type (the \c Node type of the digraph). + typedef typename GR::Node Value; + + /// \brief Constructor + /// + /// Constructor. + /// \param digraph The digraph that the map belongs to. + explicit SourceMap(const GR& digraph) : _graph(digraph) {} + + /// \brief Returns the source node of the given arc. + /// + /// Returns the source node of the given arc. + Value operator[](const Key& arc) const { + return _graph.source(arc); + } + + private: + const GR& _graph; + }; + + /// \brief Returns a \c SourceMap class. + /// + /// This function just returns an \c SourceMap class. + /// \relates SourceMap + template + inline SourceMap sourceMap(const GR& graph) { + return SourceMap(graph); + } + + /// \brief Map of the target nodes of arcs in a digraph. + /// + /// TargetMap provides access for the target node of each arc in a digraph, + /// which is returned by the \c target() function of the digraph. + /// \tparam GR The digraph type. + /// \see SourceMap + template + class TargetMap { + public: + + /// The key type (the \c Arc type of the digraph). + typedef typename GR::Arc Key; + /// The value type (the \c Node type of the digraph). + typedef typename GR::Node Value; + + /// \brief Constructor + /// + /// Constructor. + /// \param digraph The digraph that the map belongs to. + explicit TargetMap(const GR& digraph) : _graph(digraph) {} + + /// \brief Returns the target node of the given arc. + /// + /// Returns the target node of the given arc. + Value operator[](const Key& e) const { + return _graph.target(e); + } + + private: + const GR& _graph; + }; + + /// \brief Returns a \c TargetMap class. + /// + /// This function just returns a \c TargetMap class. + /// \relates TargetMap + template + inline TargetMap targetMap(const GR& graph) { + return TargetMap(graph); + } + + /// \brief Map of the "forward" directed arc view of edges in a graph. + /// + /// ForwardMap provides access for the "forward" directed arc view of + /// each edge in a graph, which is returned by the \c direct() function + /// of the graph with \c true parameter. + /// \tparam GR The graph type. + /// \see BackwardMap + template + class ForwardMap { + public: + + /// The key type (the \c Edge type of the digraph). + typedef typename GR::Edge Key; + /// The value type (the \c Arc type of the digraph). + typedef typename GR::Arc Value; + + /// \brief Constructor + /// + /// Constructor. + /// \param graph The graph that the map belongs to. + explicit ForwardMap(const GR& graph) : _graph(graph) {} + + /// \brief Returns the "forward" directed arc view of the given edge. + /// + /// Returns the "forward" directed arc view of the given edge. + Value operator[](const Key& key) const { + return _graph.direct(key, true); + } + + private: + const GR& _graph; + }; + + /// \brief Returns a \c ForwardMap class. + /// + /// This function just returns an \c ForwardMap class. + /// \relates ForwardMap + template + inline ForwardMap forwardMap(const GR& graph) { + return ForwardMap(graph); + } + + /// \brief Map of the "backward" directed arc view of edges in a graph. + /// + /// BackwardMap provides access for the "backward" directed arc view of + /// each edge in a graph, which is returned by the \c direct() function + /// of the graph with \c false parameter. + /// \tparam GR The graph type. + /// \see ForwardMap + template + class BackwardMap { + public: + + /// The key type (the \c Edge type of the digraph). + typedef typename GR::Edge Key; + /// The value type (the \c Arc type of the digraph). + typedef typename GR::Arc Value; + + /// \brief Constructor + /// + /// Constructor. + /// \param graph The graph that the map belongs to. + explicit BackwardMap(const GR& graph) : _graph(graph) {} + + /// \brief Returns the "backward" directed arc view of the given edge. + /// + /// Returns the "backward" directed arc view of the given edge. + Value operator[](const Key& key) const { + return _graph.direct(key, false); + } + + private: + const GR& _graph; + }; + + /// \brief Returns a \c BackwardMap class + + /// This function just returns a \c BackwardMap class. + /// \relates BackwardMap + template + inline BackwardMap backwardMap(const GR& graph) { + return BackwardMap(graph); + } + + /// \brief Map of the in-degrees of nodes in a digraph. + /// + /// This map returns the in-degree of a node. Once it is constructed, + /// the degrees are stored in a standard \c NodeMap, so each query is done + /// in constant time. On the other hand, the values are updated automatically + /// whenever the digraph changes. + /// + /// \warning Besides \c addNode() and \c addArc(), a digraph structure + /// may provide alternative ways to modify the digraph. + /// The correct behavior of InDegMap is not guarantied if these additional + /// features are used. For example, the functions + /// \ref ListDigraph::changeSource() "changeSource()", + /// \ref ListDigraph::changeTarget() "changeTarget()" and + /// \ref ListDigraph::reverseArc() "reverseArc()" + /// of \ref ListDigraph will \e not update the degree values correctly. + /// + /// \sa OutDegMap + template + class InDegMap + : protected ItemSetTraits + ::ItemNotifier::ObserverBase { + + public: + + /// The graph type of InDegMap + typedef GR Graph; + typedef GR Digraph; + /// The key type + typedef typename Digraph::Node Key; + /// The value type + typedef int Value; + + typedef typename ItemSetTraits + ::ItemNotifier::ObserverBase Parent; + + private: + + class AutoNodeMap + : public ItemSetTraits::template Map::Type { + public: + + typedef typename ItemSetTraits:: + template Map::Type Parent; + + AutoNodeMap(const Digraph& digraph) : Parent(digraph, 0) {} + + virtual void add(const Key& key) { + Parent::add(key); + Parent::set(key, 0); + } + + virtual void add(const std::vector& keys) { + Parent::add(keys); + for (int i = 0; i < int(keys.size()); ++i) { + Parent::set(keys[i], 0); + } + } + + virtual void build() { + Parent::build(); + Key it; + typename Parent::Notifier* nf = Parent::notifier(); + for (nf->first(it); it != INVALID; nf->next(it)) { + Parent::set(it, 0); + } + } + }; + + public: + + /// \brief Constructor. + /// + /// Constructor for creating an in-degree map. + explicit InDegMap(const Digraph& graph) + : _digraph(graph), _deg(graph) { + Parent::attach(_digraph.notifier(typename Digraph::Arc())); + + for(typename Digraph::NodeIt it(_digraph); it != INVALID; ++it) { + _deg[it] = countInArcs(_digraph, it); + } + } + + /// \brief Gives back the in-degree of a Node. + /// + /// Gives back the in-degree of a Node. + int operator[](const Key& key) const { + return _deg[key]; + } + + protected: + + typedef typename Digraph::Arc Arc; + + virtual void add(const Arc& arc) { + ++_deg[_digraph.target(arc)]; + } + + virtual void add(const std::vector& arcs) { + for (int i = 0; i < int(arcs.size()); ++i) { + ++_deg[_digraph.target(arcs[i])]; + } + } + + virtual void erase(const Arc& arc) { + --_deg[_digraph.target(arc)]; + } + + virtual void erase(const std::vector& arcs) { + for (int i = 0; i < int(arcs.size()); ++i) { + --_deg[_digraph.target(arcs[i])]; + } + } + + virtual void build() { + for(typename Digraph::NodeIt it(_digraph); it != INVALID; ++it) { + _deg[it] = countInArcs(_digraph, it); + } + } + + virtual void clear() { + for(typename Digraph::NodeIt it(_digraph); it != INVALID; ++it) { + _deg[it] = 0; + } + } + private: + + const Digraph& _digraph; + AutoNodeMap _deg; + }; + + /// \brief Map of the out-degrees of nodes in a digraph. + /// + /// This map returns the out-degree of a node. Once it is constructed, + /// the degrees are stored in a standard \c NodeMap, so each query is done + /// in constant time. On the other hand, the values are updated automatically + /// whenever the digraph changes. + /// + /// \warning Besides \c addNode() and \c addArc(), a digraph structure + /// may provide alternative ways to modify the digraph. + /// The correct behavior of OutDegMap is not guarantied if these additional + /// features are used. For example, the functions + /// \ref ListDigraph::changeSource() "changeSource()", + /// \ref ListDigraph::changeTarget() "changeTarget()" and + /// \ref ListDigraph::reverseArc() "reverseArc()" + /// of \ref ListDigraph will \e not update the degree values correctly. + /// + /// \sa InDegMap + template + class OutDegMap + : protected ItemSetTraits + ::ItemNotifier::ObserverBase { + + public: + + /// The graph type of OutDegMap + typedef GR Graph; + typedef GR Digraph; + /// The key type + typedef typename Digraph::Node Key; + /// The value type + typedef int Value; + + typedef typename ItemSetTraits + ::ItemNotifier::ObserverBase Parent; + + private: + + class AutoNodeMap + : public ItemSetTraits::template Map::Type { + public: + + typedef typename ItemSetTraits:: + template Map::Type Parent; + + AutoNodeMap(const Digraph& digraph) : Parent(digraph, 0) {} + + virtual void add(const Key& key) { + Parent::add(key); + Parent::set(key, 0); + } + virtual void add(const std::vector& keys) { + Parent::add(keys); + for (int i = 0; i < int(keys.size()); ++i) { + Parent::set(keys[i], 0); + } + } + virtual void build() { + Parent::build(); + Key it; + typename Parent::Notifier* nf = Parent::notifier(); + for (nf->first(it); it != INVALID; nf->next(it)) { + Parent::set(it, 0); + } + } + }; + + public: + + /// \brief Constructor. + /// + /// Constructor for creating an out-degree map. + explicit OutDegMap(const Digraph& graph) + : _digraph(graph), _deg(graph) { + Parent::attach(_digraph.notifier(typename Digraph::Arc())); + + for(typename Digraph::NodeIt it(_digraph); it != INVALID; ++it) { + _deg[it] = countOutArcs(_digraph, it); + } + } + + /// \brief Gives back the out-degree of a Node. + /// + /// Gives back the out-degree of a Node. + int operator[](const Key& key) const { + return _deg[key]; + } + + protected: + + typedef typename Digraph::Arc Arc; + + virtual void add(const Arc& arc) { + ++_deg[_digraph.source(arc)]; + } + + virtual void add(const std::vector& arcs) { + for (int i = 0; i < int(arcs.size()); ++i) { + ++_deg[_digraph.source(arcs[i])]; + } + } + + virtual void erase(const Arc& arc) { + --_deg[_digraph.source(arc)]; + } + + virtual void erase(const std::vector& arcs) { + for (int i = 0; i < int(arcs.size()); ++i) { + --_deg[_digraph.source(arcs[i])]; + } + } + + virtual void build() { + for(typename Digraph::NodeIt it(_digraph); it != INVALID; ++it) { + _deg[it] = countOutArcs(_digraph, it); + } + } + + virtual void clear() { + for(typename Digraph::NodeIt it(_digraph); it != INVALID; ++it) { + _deg[it] = 0; + } + } + private: + + const Digraph& _digraph; + AutoNodeMap _deg; + }; + + /// \brief Potential difference map + /// + /// PotentialDifferenceMap returns the difference between the potentials of + /// the source and target nodes of each arc in a digraph, i.e. it returns + /// \code + /// potential[gr.target(arc)] - potential[gr.source(arc)]. + /// \endcode + /// \tparam GR The digraph type. + /// \tparam POT A node map storing the potentials. + template + class PotentialDifferenceMap { + public: + /// Key type + typedef typename GR::Arc Key; + /// Value type + typedef typename POT::Value Value; + + /// \brief Constructor + /// + /// Contructor of the map. + explicit PotentialDifferenceMap(const GR& gr, + const POT& potential) + : _digraph(gr), _potential(potential) {} + + /// \brief Returns the potential difference for the given arc. + /// + /// Returns the potential difference for the given arc, i.e. + /// \code + /// potential[gr.target(arc)] - potential[gr.source(arc)]. + /// \endcode + Value operator[](const Key& arc) const { + return _potential[_digraph.target(arc)] - + _potential[_digraph.source(arc)]; + } + + private: + const GR& _digraph; + const POT& _potential; + }; + + /// \brief Returns a PotentialDifferenceMap. + /// + /// This function just returns a PotentialDifferenceMap. + /// \relates PotentialDifferenceMap + template + PotentialDifferenceMap + potentialDifferenceMap(const GR& gr, const POT& potential) { + return PotentialDifferenceMap(gr, potential); + } + + + /// \brief Copy the values of a graph map to another map. + /// + /// This function copies the values of a graph map to another graph map. + /// \c To::Key must be equal or convertible to \c From::Key and + /// \c From::Value must be equal or convertible to \c To::Value. + /// + /// For example, an edge map of \c int value type can be copied to + /// an arc map of \c double value type in an undirected graph, but + /// an arc map cannot be copied to an edge map. + /// Note that even a \ref ConstMap can be copied to a standard graph map, + /// but \ref mapFill() can also be used for this purpose. + /// + /// \param gr The graph for which the maps are defined. + /// \param from The map from which the values have to be copied. + /// It must conform to the \ref concepts::ReadMap "ReadMap" concept. + /// \param to The map to which the values have to be copied. + /// It must conform to the \ref concepts::WriteMap "WriteMap" concept. + template + void mapCopy(const GR& gr, const From& from, To& to) { + typedef typename To::Key Item; + typedef typename ItemSetTraits::ItemIt ItemIt; + + for (ItemIt it(gr); it != INVALID; ++it) { + to.set(it, from[it]); + } + } + + /// \brief Compare two graph maps. + /// + /// This function compares the values of two graph maps. It returns + /// \c true if the maps assign the same value for all items in the graph. + /// The \c Key type of the maps (\c Node, \c Arc or \c Edge) must be equal + /// and their \c Value types must be comparable using \c %operator==(). + /// + /// \param gr The graph for which the maps are defined. + /// \param map1 The first map. + /// \param map2 The second map. + template + bool mapCompare(const GR& gr, const Map1& map1, const Map2& map2) { + typedef typename Map2::Key Item; + typedef typename ItemSetTraits::ItemIt ItemIt; + + for (ItemIt it(gr); it != INVALID; ++it) { + if (!(map1[it] == map2[it])) return false; + } + return true; + } + + /// \brief Return an item having minimum value of a graph map. + /// + /// This function returns an item (\c Node, \c Arc or \c Edge) having + /// minimum value of the given graph map. + /// If the item set is empty, it returns \c INVALID. + /// + /// \param gr The graph for which the map is defined. + /// \param map The graph map. + template + typename Map::Key mapMin(const GR& gr, const Map& map) { + return mapMin(gr, map, std::less()); + } + + /// \brief Return an item having minimum value of a graph map. + /// + /// This function returns an item (\c Node, \c Arc or \c Edge) having + /// minimum value of the given graph map. + /// If the item set is empty, it returns \c INVALID. + /// + /// \param gr The graph for which the map is defined. + /// \param map The graph map. + /// \param comp Comparison function object. + template + typename Map::Key mapMin(const GR& gr, const Map& map, const Comp& comp) { + typedef typename Map::Key Item; + typedef typename Map::Value Value; + typedef typename ItemSetTraits::ItemIt ItemIt; + + ItemIt min_item(gr); + if (min_item == INVALID) return INVALID; + Value min = map[min_item]; + for (ItemIt it(gr); it != INVALID; ++it) { + if (comp(map[it], min)) { + min = map[it]; + min_item = it; + } + } + return min_item; + } + + /// \brief Return an item having maximum value of a graph map. + /// + /// This function returns an item (\c Node, \c Arc or \c Edge) having + /// maximum value of the given graph map. + /// If the item set is empty, it returns \c INVALID. + /// + /// \param gr The graph for which the map is defined. + /// \param map The graph map. + template + typename Map::Key mapMax(const GR& gr, const Map& map) { + return mapMax(gr, map, std::less()); + } + + /// \brief Return an item having maximum value of a graph map. + /// + /// This function returns an item (\c Node, \c Arc or \c Edge) having + /// maximum value of the given graph map. + /// If the item set is empty, it returns \c INVALID. + /// + /// \param gr The graph for which the map is defined. + /// \param map The graph map. + /// \param comp Comparison function object. + template + typename Map::Key mapMax(const GR& gr, const Map& map, const Comp& comp) { + typedef typename Map::Key Item; + typedef typename Map::Value Value; + typedef typename ItemSetTraits::ItemIt ItemIt; + + ItemIt max_item(gr); + if (max_item == INVALID) return INVALID; + Value max = map[max_item]; + for (ItemIt it(gr); it != INVALID; ++it) { + if (comp(max, map[it])) { + max = map[it]; + max_item = it; + } + } + return max_item; + } + + /// \brief Return the minimum value of a graph map. + /// + /// This function returns the minimum value of the given graph map. + /// The corresponding item set of the graph must not be empty. + /// + /// \param gr The graph for which the map is defined. + /// \param map The graph map. + template + typename Map::Value mapMinValue(const GR& gr, const Map& map) { + return map[mapMin(gr, map, std::less())]; + } + + /// \brief Return the minimum value of a graph map. + /// + /// This function returns the minimum value of the given graph map. + /// The corresponding item set of the graph must not be empty. + /// + /// \param gr The graph for which the map is defined. + /// \param map The graph map. + /// \param comp Comparison function object. + template + typename Map::Value + mapMinValue(const GR& gr, const Map& map, const Comp& comp) { + return map[mapMin(gr, map, comp)]; + } + + /// \brief Return the maximum value of a graph map. + /// + /// This function returns the maximum value of the given graph map. + /// The corresponding item set of the graph must not be empty. + /// + /// \param gr The graph for which the map is defined. + /// \param map The graph map. + template + typename Map::Value mapMaxValue(const GR& gr, const Map& map) { + return map[mapMax(gr, map, std::less())]; + } + + /// \brief Return the maximum value of a graph map. + /// + /// This function returns the maximum value of the given graph map. + /// The corresponding item set of the graph must not be empty. + /// + /// \param gr The graph for which the map is defined. + /// \param map The graph map. + /// \param comp Comparison function object. + template + typename Map::Value + mapMaxValue(const GR& gr, const Map& map, const Comp& comp) { + return map[mapMax(gr, map, comp)]; + } + + /// \brief Return an item having a specified value in a graph map. + /// + /// This function returns an item (\c Node, \c Arc or \c Edge) having + /// the specified assigned value in the given graph map. + /// If no such item exists, it returns \c INVALID. + /// + /// \param gr The graph for which the map is defined. + /// \param map The graph map. + /// \param val The value that have to be found. + template + typename Map::Key + mapFind(const GR& gr, const Map& map, const typename Map::Value& val) { + typedef typename Map::Key Item; + typedef typename ItemSetTraits::ItemIt ItemIt; + + for (ItemIt it(gr); it != INVALID; ++it) { + if (map[it] == val) return it; + } + return INVALID; + } + + /// \brief Return an item having value for which a certain predicate is + /// true in a graph map. + /// + /// This function returns an item (\c Node, \c Arc or \c Edge) having + /// such assigned value for which the specified predicate is true + /// in the given graph map. + /// If no such item exists, it returns \c INVALID. + /// + /// \param gr The graph for which the map is defined. + /// \param map The graph map. + /// \param pred The predicate function object. + template + typename Map::Key + mapFindIf(const GR& gr, const Map& map, const Pred& pred) { + typedef typename Map::Key Item; + typedef typename ItemSetTraits::ItemIt ItemIt; + + for (ItemIt it(gr); it != INVALID; ++it) { + if (pred(map[it])) return it; + } + return INVALID; + } + + /// \brief Return the number of items having a specified value in a + /// graph map. + /// + /// This function returns the number of items (\c Node, \c Arc or \c Edge) + /// having the specified assigned value in the given graph map. + /// + /// \param gr The graph for which the map is defined. + /// \param map The graph map. + /// \param val The value that have to be counted. + template + int mapCount(const GR& gr, const Map& map, const typename Map::Value& val) { + typedef typename Map::Key Item; + typedef typename ItemSetTraits::ItemIt ItemIt; + + int cnt = 0; + for (ItemIt it(gr); it != INVALID; ++it) { + if (map[it] == val) ++cnt; + } + return cnt; + } + + /// \brief Return the number of items having values for which a certain + /// predicate is true in a graph map. + /// + /// This function returns the number of items (\c Node, \c Arc or \c Edge) + /// having such assigned values for which the specified predicate is true + /// in the given graph map. + /// + /// \param gr The graph for which the map is defined. + /// \param map The graph map. + /// \param pred The predicate function object. + template + int mapCountIf(const GR& gr, const Map& map, const Pred& pred) { + typedef typename Map::Key Item; + typedef typename ItemSetTraits::ItemIt ItemIt; + + int cnt = 0; + for (ItemIt it(gr); it != INVALID; ++it) { + if (pred(map[it])) ++cnt; + } + return cnt; + } + + /// \brief Fill a graph map with a certain value. + /// + /// This function sets the specified value for all items (\c Node, + /// \c Arc or \c Edge) in the given graph map. + /// + /// \param gr The graph for which the map is defined. + /// \param map The graph map. It must conform to the + /// \ref concepts::WriteMap "WriteMap" concept. + /// \param val The value. + template + void mapFill(const GR& gr, Map& map, const typename Map::Value& val) { + typedef typename Map::Key Item; + typedef typename ItemSetTraits::ItemIt ItemIt; + + for (ItemIt it(gr); it != INVALID; ++it) { + map.set(it, val); + } + } + + /// @} +} + +#endif // LEMON_MAPS_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/matching.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/matching.h new file mode 100644 index 00000000000..5ee23412835 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/matching.h @@ -0,0 +1,3505 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_MATCHING_H +#define LEMON_MATCHING_H + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +///\ingroup matching +///\file +///\brief Maximum matching algorithms in general graphs. + +namespace lemon { + + /// \ingroup matching + /// + /// \brief Maximum cardinality matching in general graphs + /// + /// This class implements Edmonds' alternating forest matching algorithm + /// for finding a maximum cardinality matching in a general undirected graph. + /// It can be started from an arbitrary initial matching + /// (the default is the empty one). + /// + /// The dual solution of the problem is a map of the nodes to + /// \ref MaxMatching::Status "Status", having values \c EVEN (or \c D), + /// \c ODD (or \c A) and \c MATCHED (or \c C) defining the Gallai-Edmonds + /// decomposition of the graph. The nodes in \c EVEN/D induce a subgraph + /// with factor-critical components, the nodes in \c ODD/A form the + /// canonical barrier, and the nodes in \c MATCHED/C induce a graph having + /// a perfect matching. The number of the factor-critical components + /// minus the number of barrier nodes is a lower bound on the + /// unmatched nodes, and the matching is optimal if and only if this bound is + /// tight. This decomposition can be obtained using \ref status() or + /// \ref statusMap() after running the algorithm. + /// + /// \tparam GR The undirected graph type the algorithm runs on. + template + class MaxMatching { + public: + + /// The graph type of the algorithm + typedef GR Graph; + /// The type of the matching map + typedef typename Graph::template NodeMap + MatchingMap; + + ///\brief Status constants for Gallai-Edmonds decomposition. + /// + ///These constants are used for indicating the Gallai-Edmonds + ///decomposition of a graph. The nodes with status \c EVEN (or \c D) + ///induce a subgraph with factor-critical components, the nodes with + ///status \c ODD (or \c A) form the canonical barrier, and the nodes + ///with status \c MATCHED (or \c C) induce a subgraph having a + ///perfect matching. + enum Status { + EVEN = 1, ///< = 1. (\c D is an alias for \c EVEN.) + D = 1, + MATCHED = 0, ///< = 0. (\c C is an alias for \c MATCHED.) + C = 0, + ODD = -1, ///< = -1. (\c A is an alias for \c ODD.) + A = -1, + UNMATCHED = -2 ///< = -2. + }; + + /// The type of the status map + typedef typename Graph::template NodeMap StatusMap; + + private: + + TEMPLATE_GRAPH_TYPEDEFS(Graph); + + typedef UnionFindEnum BlossomSet; + typedef ExtendFindEnum TreeSet; + typedef RangeMap NodeIntMap; + typedef MatchingMap EarMap; + typedef std::vector NodeQueue; + + const Graph& _graph; + MatchingMap* _matching; + StatusMap* _status; + + EarMap* _ear; + + IntNodeMap* _blossom_set_index; + BlossomSet* _blossom_set; + NodeIntMap* _blossom_rep; + + IntNodeMap* _tree_set_index; + TreeSet* _tree_set; + + NodeQueue _node_queue; + int _process, _postpone, _last; + + int _node_num; + + private: + + void createStructures() { + _node_num = countNodes(_graph); + if (!_matching) { + _matching = new MatchingMap(_graph); + } + if (!_status) { + _status = new StatusMap(_graph); + } + if (!_ear) { + _ear = new EarMap(_graph); + } + if (!_blossom_set) { + _blossom_set_index = new IntNodeMap(_graph); + _blossom_set = new BlossomSet(*_blossom_set_index); + } + if (!_blossom_rep) { + _blossom_rep = new NodeIntMap(_node_num); + } + if (!_tree_set) { + _tree_set_index = new IntNodeMap(_graph); + _tree_set = new TreeSet(*_tree_set_index); + } + _node_queue.resize(_node_num); + } + + void destroyStructures() { + if (_matching) { + delete _matching; + } + if (_status) { + delete _status; + } + if (_ear) { + delete _ear; + } + if (_blossom_set) { + delete _blossom_set; + delete _blossom_set_index; + } + if (_blossom_rep) { + delete _blossom_rep; + } + if (_tree_set) { + delete _tree_set_index; + delete _tree_set; + } + } + + void processDense(const Node& n) { + _process = _postpone = _last = 0; + _node_queue[_last++] = n; + + while (_process != _last) { + Node u = _node_queue[_process++]; + for (OutArcIt a(_graph, u); a != INVALID; ++a) { + Node v = _graph.target(a); + if ((*_status)[v] == MATCHED) { + extendOnArc(a); + } else if ((*_status)[v] == UNMATCHED) { + augmentOnArc(a); + return; + } + } + } + + while (_postpone != _last) { + Node u = _node_queue[_postpone++]; + + for (OutArcIt a(_graph, u); a != INVALID ; ++a) { + Node v = _graph.target(a); + + if ((*_status)[v] == EVEN) { + if (_blossom_set->find(u) != _blossom_set->find(v)) { + shrinkOnEdge(a); + } + } + + while (_process != _last) { + Node w = _node_queue[_process++]; + for (OutArcIt b(_graph, w); b != INVALID; ++b) { + Node x = _graph.target(b); + if ((*_status)[x] == MATCHED) { + extendOnArc(b); + } else if ((*_status)[x] == UNMATCHED) { + augmentOnArc(b); + return; + } + } + } + } + } + } + + void processSparse(const Node& n) { + _process = _last = 0; + _node_queue[_last++] = n; + while (_process != _last) { + Node u = _node_queue[_process++]; + for (OutArcIt a(_graph, u); a != INVALID; ++a) { + Node v = _graph.target(a); + + if ((*_status)[v] == EVEN) { + if (_blossom_set->find(u) != _blossom_set->find(v)) { + shrinkOnEdge(a); + } + } else if ((*_status)[v] == MATCHED) { + extendOnArc(a); + } else if ((*_status)[v] == UNMATCHED) { + augmentOnArc(a); + return; + } + } + } + } + + void shrinkOnEdge(const Edge& e) { + Node nca = INVALID; + + { + std::set left_set, right_set; + + Node left = (*_blossom_rep)[_blossom_set->find(_graph.u(e))]; + left_set.insert(left); + + Node right = (*_blossom_rep)[_blossom_set->find(_graph.v(e))]; + right_set.insert(right); + + while (true) { + if ((*_matching)[left] == INVALID) break; + left = _graph.target((*_matching)[left]); + left = (*_blossom_rep)[_blossom_set-> + find(_graph.target((*_ear)[left]))]; + if (right_set.find(left) != right_set.end()) { + nca = left; + break; + } + left_set.insert(left); + + if ((*_matching)[right] == INVALID) break; + right = _graph.target((*_matching)[right]); + right = (*_blossom_rep)[_blossom_set-> + find(_graph.target((*_ear)[right]))]; + if (left_set.find(right) != left_set.end()) { + nca = right; + break; + } + right_set.insert(right); + } + + if (nca == INVALID) { + if ((*_matching)[left] == INVALID) { + nca = right; + while (left_set.find(nca) == left_set.end()) { + nca = _graph.target((*_matching)[nca]); + nca =(*_blossom_rep)[_blossom_set-> + find(_graph.target((*_ear)[nca]))]; + } + } else { + nca = left; + while (right_set.find(nca) == right_set.end()) { + nca = _graph.target((*_matching)[nca]); + nca = (*_blossom_rep)[_blossom_set-> + find(_graph.target((*_ear)[nca]))]; + } + } + } + } + + { + + Node node = _graph.u(e); + Arc arc = _graph.direct(e, true); + Node base = (*_blossom_rep)[_blossom_set->find(node)]; + + while (base != nca) { + (*_ear)[node] = arc; + + Node n = node; + while (n != base) { + n = _graph.target((*_matching)[n]); + Arc a = (*_ear)[n]; + n = _graph.target(a); + (*_ear)[n] = _graph.oppositeArc(a); + } + node = _graph.target((*_matching)[base]); + _tree_set->erase(base); + _tree_set->erase(node); + _blossom_set->insert(node, _blossom_set->find(base)); + (*_status)[node] = EVEN; + _node_queue[_last++] = node; + arc = _graph.oppositeArc((*_ear)[node]); + node = _graph.target((*_ear)[node]); + base = (*_blossom_rep)[_blossom_set->find(node)]; + _blossom_set->join(_graph.target(arc), base); + } + } + + (*_blossom_rep)[_blossom_set->find(nca)] = nca; + + { + + Node node = _graph.v(e); + Arc arc = _graph.direct(e, false); + Node base = (*_blossom_rep)[_blossom_set->find(node)]; + + while (base != nca) { + (*_ear)[node] = arc; + + Node n = node; + while (n != base) { + n = _graph.target((*_matching)[n]); + Arc a = (*_ear)[n]; + n = _graph.target(a); + (*_ear)[n] = _graph.oppositeArc(a); + } + node = _graph.target((*_matching)[base]); + _tree_set->erase(base); + _tree_set->erase(node); + _blossom_set->insert(node, _blossom_set->find(base)); + (*_status)[node] = EVEN; + _node_queue[_last++] = node; + arc = _graph.oppositeArc((*_ear)[node]); + node = _graph.target((*_ear)[node]); + base = (*_blossom_rep)[_blossom_set->find(node)]; + _blossom_set->join(_graph.target(arc), base); + } + } + + (*_blossom_rep)[_blossom_set->find(nca)] = nca; + } + + void extendOnArc(const Arc& a) { + Node base = _graph.source(a); + Node odd = _graph.target(a); + + (*_ear)[odd] = _graph.oppositeArc(a); + Node even = _graph.target((*_matching)[odd]); + (*_blossom_rep)[_blossom_set->insert(even)] = even; + (*_status)[odd] = ODD; + (*_status)[even] = EVEN; + int tree = _tree_set->find((*_blossom_rep)[_blossom_set->find(base)]); + _tree_set->insert(odd, tree); + _tree_set->insert(even, tree); + _node_queue[_last++] = even; + + } + + void augmentOnArc(const Arc& a) { + Node even = _graph.source(a); + Node odd = _graph.target(a); + + int tree = _tree_set->find((*_blossom_rep)[_blossom_set->find(even)]); + + (*_matching)[odd] = _graph.oppositeArc(a); + (*_status)[odd] = MATCHED; + + Arc arc = (*_matching)[even]; + (*_matching)[even] = a; + + while (arc != INVALID) { + odd = _graph.target(arc); + arc = (*_ear)[odd]; + even = _graph.target(arc); + (*_matching)[odd] = arc; + arc = (*_matching)[even]; + (*_matching)[even] = _graph.oppositeArc((*_matching)[odd]); + } + + for (typename TreeSet::ItemIt it(*_tree_set, tree); + it != INVALID; ++it) { + if ((*_status)[it] == ODD) { + (*_status)[it] = MATCHED; + } else { + int blossom = _blossom_set->find(it); + for (typename BlossomSet::ItemIt jt(*_blossom_set, blossom); + jt != INVALID; ++jt) { + (*_status)[jt] = MATCHED; + } + _blossom_set->eraseClass(blossom); + } + } + _tree_set->eraseClass(tree); + + } + + public: + + /// \brief Constructor + /// + /// Constructor. + MaxMatching(const Graph& graph) + : _graph(graph), _matching(0), _status(0), _ear(0), + _blossom_set_index(0), _blossom_set(0), _blossom_rep(0), + _tree_set_index(0), _tree_set(0) {} + + ~MaxMatching() { + destroyStructures(); + } + + /// \name Execution Control + /// The simplest way to execute the algorithm is to use the + /// \c run() member function.\n + /// If you need better control on the execution, you have to call + /// one of the functions \ref init(), \ref greedyInit() or + /// \ref matchingInit() first, then you can start the algorithm with + /// \ref startSparse() or \ref startDense(). + + ///@{ + + /// \brief Set the initial matching to the empty matching. + /// + /// This function sets the initial matching to the empty matching. + void init() { + createStructures(); + for(NodeIt n(_graph); n != INVALID; ++n) { + (*_matching)[n] = INVALID; + (*_status)[n] = UNMATCHED; + } + } + + /// \brief Find an initial matching in a greedy way. + /// + /// This function finds an initial matching in a greedy way. + void greedyInit() { + createStructures(); + for (NodeIt n(_graph); n != INVALID; ++n) { + (*_matching)[n] = INVALID; + (*_status)[n] = UNMATCHED; + } + for (NodeIt n(_graph); n != INVALID; ++n) { + if ((*_matching)[n] == INVALID) { + for (OutArcIt a(_graph, n); a != INVALID ; ++a) { + Node v = _graph.target(a); + if ((*_matching)[v] == INVALID && v != n) { + (*_matching)[n] = a; + (*_status)[n] = MATCHED; + (*_matching)[v] = _graph.oppositeArc(a); + (*_status)[v] = MATCHED; + break; + } + } + } + } + } + + + /// \brief Initialize the matching from a map. + /// + /// This function initializes the matching from a \c bool valued edge + /// map. This map should have the property that there are no two incident + /// edges with \c true value, i.e. it really contains a matching. + /// \return \c true if the map contains a matching. + template + bool matchingInit(const MatchingMap& matching) { + createStructures(); + + for (NodeIt n(_graph); n != INVALID; ++n) { + (*_matching)[n] = INVALID; + (*_status)[n] = UNMATCHED; + } + for(EdgeIt e(_graph); e!=INVALID; ++e) { + if (matching[e]) { + + Node u = _graph.u(e); + if ((*_matching)[u] != INVALID) return false; + (*_matching)[u] = _graph.direct(e, true); + (*_status)[u] = MATCHED; + + Node v = _graph.v(e); + if ((*_matching)[v] != INVALID) return false; + (*_matching)[v] = _graph.direct(e, false); + (*_status)[v] = MATCHED; + } + } + return true; + } + + /// \brief Start Edmonds' algorithm + /// + /// This function runs the original Edmonds' algorithm. + /// + /// \pre \ref init(), \ref greedyInit() or \ref matchingInit() must be + /// called before using this function. + void startSparse() { + for(NodeIt n(_graph); n != INVALID; ++n) { + if ((*_status)[n] == UNMATCHED) { + (*_blossom_rep)[_blossom_set->insert(n)] = n; + _tree_set->insert(n); + (*_status)[n] = EVEN; + processSparse(n); + } + } + } + + /// \brief Start Edmonds' algorithm with a heuristic improvement + /// for dense graphs + /// + /// This function runs Edmonds' algorithm with a heuristic of postponing + /// shrinks, therefore resulting in a faster algorithm for dense graphs. + /// + /// \pre \ref init(), \ref greedyInit() or \ref matchingInit() must be + /// called before using this function. + void startDense() { + for(NodeIt n(_graph); n != INVALID; ++n) { + if ((*_status)[n] == UNMATCHED) { + (*_blossom_rep)[_blossom_set->insert(n)] = n; + _tree_set->insert(n); + (*_status)[n] = EVEN; + processDense(n); + } + } + } + + + /// \brief Run Edmonds' algorithm + /// + /// This function runs Edmonds' algorithm. An additional heuristic of + /// postponing shrinks is used for relatively dense graphs + /// (for which m>=2*n holds). + void run() { + if (countEdges(_graph) < 2 * countNodes(_graph)) { + greedyInit(); + startSparse(); + } else { + init(); + startDense(); + } + } + + /// @} + + /// \name Primal Solution + /// Functions to get the primal solution, i.e. the maximum matching. + + /// @{ + + /// \brief Return the size (cardinality) of the matching. + /// + /// This function returns the size (cardinality) of the current matching. + /// After run() it returns the size of the maximum matching in the graph. + int matchingSize() const { + int size = 0; + for (NodeIt n(_graph); n != INVALID; ++n) { + if ((*_matching)[n] != INVALID) { + ++size; + } + } + return size / 2; + } + + /// \brief Return \c true if the given edge is in the matching. + /// + /// This function returns \c true if the given edge is in the current + /// matching. + bool matching(const Edge& edge) const { + return edge == (*_matching)[_graph.u(edge)]; + } + + /// \brief Return the matching arc (or edge) incident to the given node. + /// + /// This function returns the matching arc (or edge) incident to the + /// given node in the current matching or \c INVALID if the node is + /// not covered by the matching. + Arc matching(const Node& n) const { + return (*_matching)[n]; + } + + /// \brief Return a const reference to the matching map. + /// + /// This function returns a const reference to a node map that stores + /// the matching arc (or edge) incident to each node. + const MatchingMap& matchingMap() const { + return *_matching; + } + + /// \brief Return the mate of the given node. + /// + /// This function returns the mate of the given node in the current + /// matching or \c INVALID if the node is not covered by the matching. + Node mate(const Node& n) const { + return (*_matching)[n] != INVALID ? + _graph.target((*_matching)[n]) : INVALID; + } + + /// @} + + /// \name Dual Solution + /// Functions to get the dual solution, i.e. the Gallai-Edmonds + /// decomposition. + + /// @{ + + /// \brief Return the status of the given node in the Edmonds-Gallai + /// decomposition. + /// + /// This function returns the \ref Status "status" of the given node + /// in the Edmonds-Gallai decomposition. + Status status(const Node& n) const { + return (*_status)[n]; + } + + /// \brief Return a const reference to the status map, which stores + /// the Edmonds-Gallai decomposition. + /// + /// This function returns a const reference to a node map that stores the + /// \ref Status "status" of each node in the Edmonds-Gallai decomposition. + const StatusMap& statusMap() const { + return *_status; + } + + /// \brief Return \c true if the given node is in the barrier. + /// + /// This function returns \c true if the given node is in the barrier. + bool barrier(const Node& n) const { + return (*_status)[n] == ODD; + } + + /// @} + + }; + + /// \ingroup matching + /// + /// \brief Weighted matching in general graphs + /// + /// This class provides an efficient implementation of Edmond's + /// maximum weighted matching algorithm. The implementation is based + /// on extensive use of priority queues and provides + /// \f$O(nm\log n)\f$ time complexity. + /// + /// The maximum weighted matching problem is to find a subset of the + /// edges in an undirected graph with maximum overall weight for which + /// each node has at most one incident edge. + /// It can be formulated with the following linear program. + /// \f[ \sum_{e \in \delta(u)}x_e \le 1 \quad \forall u\in V\f] + /** \f[ \sum_{e \in \gamma(B)}x_e \le \frac{\vert B \vert - 1}{2} + \quad \forall B\in\mathcal{O}\f] */ + /// \f[x_e \ge 0\quad \forall e\in E\f] + /// \f[\max \sum_{e\in E}x_ew_e\f] + /// where \f$\delta(X)\f$ is the set of edges incident to a node in + /// \f$X\f$, \f$\gamma(X)\f$ is the set of edges with both ends in + /// \f$X\f$ and \f$\mathcal{O}\f$ is the set of odd cardinality + /// subsets of the nodes. + /// + /// The algorithm calculates an optimal matching and a proof of the + /// optimality. The solution of the dual problem can be used to check + /// the result of the algorithm. The dual linear problem is the + /// following. + /** \f[ y_u + y_v + \sum_{B \in \mathcal{O}, uv \in \gamma(B)} + z_B \ge w_{uv} \quad \forall uv\in E\f] */ + /// \f[y_u \ge 0 \quad \forall u \in V\f] + /// \f[z_B \ge 0 \quad \forall B \in \mathcal{O}\f] + /** \f[\min \sum_{u \in V}y_u + \sum_{B \in \mathcal{O}} + \frac{\vert B \vert - 1}{2}z_B\f] */ + /// + /// The algorithm can be executed with the run() function. + /// After it the matching (the primal solution) and the dual solution + /// can be obtained using the query functions and the + /// \ref MaxWeightedMatching::BlossomIt "BlossomIt" nested class, + /// which is able to iterate on the nodes of a blossom. + /// If the value type is integer, then the dual solution is multiplied + /// by \ref MaxWeightedMatching::dualScale "4". + /// + /// \tparam GR The undirected graph type the algorithm runs on. + /// \tparam WM The type edge weight map. The default type is + /// \ref concepts::Graph::EdgeMap "GR::EdgeMap". +#ifdef DOXYGEN + template +#else + template > +#endif + class MaxWeightedMatching { + public: + + /// The graph type of the algorithm + typedef GR Graph; + /// The type of the edge weight map + typedef WM WeightMap; + /// The value type of the edge weights + typedef typename WeightMap::Value Value; + + /// The type of the matching map + typedef typename Graph::template NodeMap + MatchingMap; + + /// \brief Scaling factor for dual solution + /// + /// Scaling factor for dual solution. It is equal to 4 or 1 + /// according to the value type. + static const int dualScale = + std::numeric_limits::is_integer ? 4 : 1; + + private: + + TEMPLATE_GRAPH_TYPEDEFS(Graph); + + typedef typename Graph::template NodeMap NodePotential; + typedef std::vector BlossomNodeList; + + struct BlossomVariable { + int begin, end; + Value value; + + BlossomVariable(int _begin, int _end, Value _value) + : begin(_begin), end(_end), value(_value) {} + + }; + + typedef std::vector BlossomPotential; + + const Graph& _graph; + const WeightMap& _weight; + + MatchingMap* _matching; + + NodePotential* _node_potential; + + BlossomPotential _blossom_potential; + BlossomNodeList _blossom_node_list; + + int _node_num; + int _blossom_num; + + typedef RangeMap IntIntMap; + + enum Status { + EVEN = -1, MATCHED = 0, ODD = 1 + }; + + typedef HeapUnionFind BlossomSet; + struct BlossomData { + int tree; + Status status; + Arc pred, next; + Value pot, offset; + Node base; + }; + + IntNodeMap *_blossom_index; + BlossomSet *_blossom_set; + RangeMap* _blossom_data; + + IntNodeMap *_node_index; + IntArcMap *_node_heap_index; + + struct NodeData { + + NodeData(IntArcMap& node_heap_index) + : heap(node_heap_index) {} + + int blossom; + Value pot; + BinHeap heap; + std::map heap_index; + + int tree; + }; + + RangeMap* _node_data; + + typedef ExtendFindEnum TreeSet; + + IntIntMap *_tree_set_index; + TreeSet *_tree_set; + + IntNodeMap *_delta1_index; + BinHeap *_delta1; + + IntIntMap *_delta2_index; + BinHeap *_delta2; + + IntEdgeMap *_delta3_index; + BinHeap *_delta3; + + IntIntMap *_delta4_index; + BinHeap *_delta4; + + Value _delta_sum; + int _unmatched; + + typedef MaxWeightedFractionalMatching FractionalMatching; + FractionalMatching *_fractional; + + void createStructures() { + _node_num = countNodes(_graph); + _blossom_num = _node_num * 3 / 2; + + if (!_matching) { + _matching = new MatchingMap(_graph); + } + + if (!_node_potential) { + _node_potential = new NodePotential(_graph); + } + + if (!_blossom_set) { + _blossom_index = new IntNodeMap(_graph); + _blossom_set = new BlossomSet(*_blossom_index); + _blossom_data = new RangeMap(_blossom_num); + } else if (_blossom_data->size() != _blossom_num) { + delete _blossom_data; + _blossom_data = new RangeMap(_blossom_num); + } + + if (!_node_index) { + _node_index = new IntNodeMap(_graph); + _node_heap_index = new IntArcMap(_graph); + _node_data = new RangeMap(_node_num, + NodeData(*_node_heap_index)); + } else { + delete _node_data; + _node_data = new RangeMap(_node_num, + NodeData(*_node_heap_index)); + } + + if (!_tree_set) { + _tree_set_index = new IntIntMap(_blossom_num); + _tree_set = new TreeSet(*_tree_set_index); + } else { + _tree_set_index->resize(_blossom_num); + } + + if (!_delta1) { + _delta1_index = new IntNodeMap(_graph); + _delta1 = new BinHeap(*_delta1_index); + } + + if (!_delta2) { + _delta2_index = new IntIntMap(_blossom_num); + _delta2 = new BinHeap(*_delta2_index); + } else { + _delta2_index->resize(_blossom_num); + } + + if (!_delta3) { + _delta3_index = new IntEdgeMap(_graph); + _delta3 = new BinHeap(*_delta3_index); + } + + if (!_delta4) { + _delta4_index = new IntIntMap(_blossom_num); + _delta4 = new BinHeap(*_delta4_index); + } else { + _delta4_index->resize(_blossom_num); + } + } + + void destroyStructures() { + if (_matching) { + delete _matching; + } + if (_node_potential) { + delete _node_potential; + } + if (_blossom_set) { + delete _blossom_index; + delete _blossom_set; + delete _blossom_data; + } + + if (_node_index) { + delete _node_index; + delete _node_heap_index; + delete _node_data; + } + + if (_tree_set) { + delete _tree_set_index; + delete _tree_set; + } + if (_delta1) { + delete _delta1_index; + delete _delta1; + } + if (_delta2) { + delete _delta2_index; + delete _delta2; + } + if (_delta3) { + delete _delta3_index; + delete _delta3; + } + if (_delta4) { + delete _delta4_index; + delete _delta4; + } + } + + void matchedToEven(int blossom, int tree) { + if (_delta2->state(blossom) == _delta2->IN_HEAP) { + _delta2->erase(blossom); + } + + if (!_blossom_set->trivial(blossom)) { + (*_blossom_data)[blossom].pot -= + 2 * (_delta_sum - (*_blossom_data)[blossom].offset); + } + + for (typename BlossomSet::ItemIt n(*_blossom_set, blossom); + n != INVALID; ++n) { + + _blossom_set->increase(n, std::numeric_limits::max()); + int ni = (*_node_index)[n]; + + (*_node_data)[ni].heap.clear(); + (*_node_data)[ni].heap_index.clear(); + + (*_node_data)[ni].pot += _delta_sum - (*_blossom_data)[blossom].offset; + + _delta1->push(n, (*_node_data)[ni].pot); + + for (InArcIt e(_graph, n); e != INVALID; ++e) { + Node v = _graph.source(e); + int vb = _blossom_set->find(v); + int vi = (*_node_index)[v]; + + Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot - + dualScale * _weight[e]; + + if ((*_blossom_data)[vb].status == EVEN) { + if (_delta3->state(e) != _delta3->IN_HEAP && blossom != vb) { + _delta3->push(e, rw / 2); + } + } else { + typename std::map::iterator it = + (*_node_data)[vi].heap_index.find(tree); + + if (it != (*_node_data)[vi].heap_index.end()) { + if ((*_node_data)[vi].heap[it->second] > rw) { + (*_node_data)[vi].heap.replace(it->second, e); + (*_node_data)[vi].heap.decrease(e, rw); + it->second = e; + } + } else { + (*_node_data)[vi].heap.push(e, rw); + (*_node_data)[vi].heap_index.insert(std::make_pair(tree, e)); + } + + if ((*_blossom_set)[v] > (*_node_data)[vi].heap.prio()) { + _blossom_set->decrease(v, (*_node_data)[vi].heap.prio()); + + if ((*_blossom_data)[vb].status == MATCHED) { + if (_delta2->state(vb) != _delta2->IN_HEAP) { + _delta2->push(vb, _blossom_set->classPrio(vb) - + (*_blossom_data)[vb].offset); + } else if ((*_delta2)[vb] > _blossom_set->classPrio(vb) - + (*_blossom_data)[vb].offset) { + _delta2->decrease(vb, _blossom_set->classPrio(vb) - + (*_blossom_data)[vb].offset); + } + } + } + } + } + } + (*_blossom_data)[blossom].offset = 0; + } + + void matchedToOdd(int blossom) { + if (_delta2->state(blossom) == _delta2->IN_HEAP) { + _delta2->erase(blossom); + } + (*_blossom_data)[blossom].offset += _delta_sum; + if (!_blossom_set->trivial(blossom)) { + _delta4->push(blossom, (*_blossom_data)[blossom].pot / 2 + + (*_blossom_data)[blossom].offset); + } + } + + void evenToMatched(int blossom, int tree) { + if (!_blossom_set->trivial(blossom)) { + (*_blossom_data)[blossom].pot += 2 * _delta_sum; + } + + for (typename BlossomSet::ItemIt n(*_blossom_set, blossom); + n != INVALID; ++n) { + int ni = (*_node_index)[n]; + (*_node_data)[ni].pot -= _delta_sum; + + _delta1->erase(n); + + for (InArcIt e(_graph, n); e != INVALID; ++e) { + Node v = _graph.source(e); + int vb = _blossom_set->find(v); + int vi = (*_node_index)[v]; + + Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot - + dualScale * _weight[e]; + + if (vb == blossom) { + if (_delta3->state(e) == _delta3->IN_HEAP) { + _delta3->erase(e); + } + } else if ((*_blossom_data)[vb].status == EVEN) { + + if (_delta3->state(e) == _delta3->IN_HEAP) { + _delta3->erase(e); + } + + int vt = _tree_set->find(vb); + + if (vt != tree) { + + Arc r = _graph.oppositeArc(e); + + typename std::map::iterator it = + (*_node_data)[ni].heap_index.find(vt); + + if (it != (*_node_data)[ni].heap_index.end()) { + if ((*_node_data)[ni].heap[it->second] > rw) { + (*_node_data)[ni].heap.replace(it->second, r); + (*_node_data)[ni].heap.decrease(r, rw); + it->second = r; + } + } else { + (*_node_data)[ni].heap.push(r, rw); + (*_node_data)[ni].heap_index.insert(std::make_pair(vt, r)); + } + + if ((*_blossom_set)[n] > (*_node_data)[ni].heap.prio()) { + _blossom_set->decrease(n, (*_node_data)[ni].heap.prio()); + + if (_delta2->state(blossom) != _delta2->IN_HEAP) { + _delta2->push(blossom, _blossom_set->classPrio(blossom) - + (*_blossom_data)[blossom].offset); + } else if ((*_delta2)[blossom] > + _blossom_set->classPrio(blossom) - + (*_blossom_data)[blossom].offset){ + _delta2->decrease(blossom, _blossom_set->classPrio(blossom) - + (*_blossom_data)[blossom].offset); + } + } + } + } else { + + typename std::map::iterator it = + (*_node_data)[vi].heap_index.find(tree); + + if (it != (*_node_data)[vi].heap_index.end()) { + (*_node_data)[vi].heap.erase(it->second); + (*_node_data)[vi].heap_index.erase(it); + if ((*_node_data)[vi].heap.empty()) { + _blossom_set->increase(v, std::numeric_limits::max()); + } else if ((*_blossom_set)[v] < (*_node_data)[vi].heap.prio()) { + _blossom_set->increase(v, (*_node_data)[vi].heap.prio()); + } + + if ((*_blossom_data)[vb].status == MATCHED) { + if (_blossom_set->classPrio(vb) == + std::numeric_limits::max()) { + _delta2->erase(vb); + } else if ((*_delta2)[vb] < _blossom_set->classPrio(vb) - + (*_blossom_data)[vb].offset) { + _delta2->increase(vb, _blossom_set->classPrio(vb) - + (*_blossom_data)[vb].offset); + } + } + } + } + } + } + } + + void oddToMatched(int blossom) { + (*_blossom_data)[blossom].offset -= _delta_sum; + + if (_blossom_set->classPrio(blossom) != + std::numeric_limits::max()) { + _delta2->push(blossom, _blossom_set->classPrio(blossom) - + (*_blossom_data)[blossom].offset); + } + + if (!_blossom_set->trivial(blossom)) { + _delta4->erase(blossom); + } + } + + void oddToEven(int blossom, int tree) { + if (!_blossom_set->trivial(blossom)) { + _delta4->erase(blossom); + (*_blossom_data)[blossom].pot -= + 2 * (2 * _delta_sum - (*_blossom_data)[blossom].offset); + } + + for (typename BlossomSet::ItemIt n(*_blossom_set, blossom); + n != INVALID; ++n) { + int ni = (*_node_index)[n]; + + _blossom_set->increase(n, std::numeric_limits::max()); + + (*_node_data)[ni].heap.clear(); + (*_node_data)[ni].heap_index.clear(); + (*_node_data)[ni].pot += + 2 * _delta_sum - (*_blossom_data)[blossom].offset; + + _delta1->push(n, (*_node_data)[ni].pot); + + for (InArcIt e(_graph, n); e != INVALID; ++e) { + Node v = _graph.source(e); + int vb = _blossom_set->find(v); + int vi = (*_node_index)[v]; + + Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot - + dualScale * _weight[e]; + + if ((*_blossom_data)[vb].status == EVEN) { + if (_delta3->state(e) != _delta3->IN_HEAP && blossom != vb) { + _delta3->push(e, rw / 2); + } + } else { + + typename std::map::iterator it = + (*_node_data)[vi].heap_index.find(tree); + + if (it != (*_node_data)[vi].heap_index.end()) { + if ((*_node_data)[vi].heap[it->second] > rw) { + (*_node_data)[vi].heap.replace(it->second, e); + (*_node_data)[vi].heap.decrease(e, rw); + it->second = e; + } + } else { + (*_node_data)[vi].heap.push(e, rw); + (*_node_data)[vi].heap_index.insert(std::make_pair(tree, e)); + } + + if ((*_blossom_set)[v] > (*_node_data)[vi].heap.prio()) { + _blossom_set->decrease(v, (*_node_data)[vi].heap.prio()); + + if ((*_blossom_data)[vb].status == MATCHED) { + if (_delta2->state(vb) != _delta2->IN_HEAP) { + _delta2->push(vb, _blossom_set->classPrio(vb) - + (*_blossom_data)[vb].offset); + } else if ((*_delta2)[vb] > _blossom_set->classPrio(vb) - + (*_blossom_data)[vb].offset) { + _delta2->decrease(vb, _blossom_set->classPrio(vb) - + (*_blossom_data)[vb].offset); + } + } + } + } + } + } + (*_blossom_data)[blossom].offset = 0; + } + + void alternatePath(int even, int tree) { + int odd; + + evenToMatched(even, tree); + (*_blossom_data)[even].status = MATCHED; + + while ((*_blossom_data)[even].pred != INVALID) { + odd = _blossom_set->find(_graph.target((*_blossom_data)[even].pred)); + (*_blossom_data)[odd].status = MATCHED; + oddToMatched(odd); + (*_blossom_data)[odd].next = (*_blossom_data)[odd].pred; + + even = _blossom_set->find(_graph.target((*_blossom_data)[odd].pred)); + (*_blossom_data)[even].status = MATCHED; + evenToMatched(even, tree); + (*_blossom_data)[even].next = + _graph.oppositeArc((*_blossom_data)[odd].pred); + } + + } + + void destroyTree(int tree) { + for (TreeSet::ItemIt b(*_tree_set, tree); b != INVALID; ++b) { + if ((*_blossom_data)[b].status == EVEN) { + (*_blossom_data)[b].status = MATCHED; + evenToMatched(b, tree); + } else if ((*_blossom_data)[b].status == ODD) { + (*_blossom_data)[b].status = MATCHED; + oddToMatched(b); + } + } + _tree_set->eraseClass(tree); + } + + + void unmatchNode(const Node& node) { + int blossom = _blossom_set->find(node); + int tree = _tree_set->find(blossom); + + alternatePath(blossom, tree); + destroyTree(tree); + + (*_blossom_data)[blossom].base = node; + (*_blossom_data)[blossom].next = INVALID; + } + + void augmentOnEdge(const Edge& edge) { + + int left = _blossom_set->find(_graph.u(edge)); + int right = _blossom_set->find(_graph.v(edge)); + + int left_tree = _tree_set->find(left); + alternatePath(left, left_tree); + destroyTree(left_tree); + + int right_tree = _tree_set->find(right); + alternatePath(right, right_tree); + destroyTree(right_tree); + + (*_blossom_data)[left].next = _graph.direct(edge, true); + (*_blossom_data)[right].next = _graph.direct(edge, false); + } + + void augmentOnArc(const Arc& arc) { + + int left = _blossom_set->find(_graph.source(arc)); + int right = _blossom_set->find(_graph.target(arc)); + + (*_blossom_data)[left].status = MATCHED; + + int right_tree = _tree_set->find(right); + alternatePath(right, right_tree); + destroyTree(right_tree); + + (*_blossom_data)[left].next = arc; + (*_blossom_data)[right].next = _graph.oppositeArc(arc); + } + + void extendOnArc(const Arc& arc) { + int base = _blossom_set->find(_graph.target(arc)); + int tree = _tree_set->find(base); + + int odd = _blossom_set->find(_graph.source(arc)); + _tree_set->insert(odd, tree); + (*_blossom_data)[odd].status = ODD; + matchedToOdd(odd); + (*_blossom_data)[odd].pred = arc; + + int even = _blossom_set->find(_graph.target((*_blossom_data)[odd].next)); + (*_blossom_data)[even].pred = (*_blossom_data)[even].next; + _tree_set->insert(even, tree); + (*_blossom_data)[even].status = EVEN; + matchedToEven(even, tree); + } + + void shrinkOnEdge(const Edge& edge, int tree) { + int nca = -1; + std::vector left_path, right_path; + + { + std::set left_set, right_set; + int left = _blossom_set->find(_graph.u(edge)); + left_path.push_back(left); + left_set.insert(left); + + int right = _blossom_set->find(_graph.v(edge)); + right_path.push_back(right); + right_set.insert(right); + + while (true) { + + if ((*_blossom_data)[left].pred == INVALID) break; + + left = + _blossom_set->find(_graph.target((*_blossom_data)[left].pred)); + left_path.push_back(left); + left = + _blossom_set->find(_graph.target((*_blossom_data)[left].pred)); + left_path.push_back(left); + + left_set.insert(left); + + if (right_set.find(left) != right_set.end()) { + nca = left; + break; + } + + if ((*_blossom_data)[right].pred == INVALID) break; + + right = + _blossom_set->find(_graph.target((*_blossom_data)[right].pred)); + right_path.push_back(right); + right = + _blossom_set->find(_graph.target((*_blossom_data)[right].pred)); + right_path.push_back(right); + + right_set.insert(right); + + if (left_set.find(right) != left_set.end()) { + nca = right; + break; + } + + } + + if (nca == -1) { + if ((*_blossom_data)[left].pred == INVALID) { + nca = right; + while (left_set.find(nca) == left_set.end()) { + nca = + _blossom_set->find(_graph.target((*_blossom_data)[nca].pred)); + right_path.push_back(nca); + nca = + _blossom_set->find(_graph.target((*_blossom_data)[nca].pred)); + right_path.push_back(nca); + } + } else { + nca = left; + while (right_set.find(nca) == right_set.end()) { + nca = + _blossom_set->find(_graph.target((*_blossom_data)[nca].pred)); + left_path.push_back(nca); + nca = + _blossom_set->find(_graph.target((*_blossom_data)[nca].pred)); + left_path.push_back(nca); + } + } + } + } + + std::vector subblossoms; + Arc prev; + + prev = _graph.direct(edge, true); + for (int i = 0; left_path[i] != nca; i += 2) { + subblossoms.push_back(left_path[i]); + (*_blossom_data)[left_path[i]].next = prev; + _tree_set->erase(left_path[i]); + + subblossoms.push_back(left_path[i + 1]); + (*_blossom_data)[left_path[i + 1]].status = EVEN; + oddToEven(left_path[i + 1], tree); + _tree_set->erase(left_path[i + 1]); + prev = _graph.oppositeArc((*_blossom_data)[left_path[i + 1]].pred); + } + + int k = 0; + while (right_path[k] != nca) ++k; + + subblossoms.push_back(nca); + (*_blossom_data)[nca].next = prev; + + for (int i = k - 2; i >= 0; i -= 2) { + subblossoms.push_back(right_path[i + 1]); + (*_blossom_data)[right_path[i + 1]].status = EVEN; + oddToEven(right_path[i + 1], tree); + _tree_set->erase(right_path[i + 1]); + + (*_blossom_data)[right_path[i + 1]].next = + (*_blossom_data)[right_path[i + 1]].pred; + + subblossoms.push_back(right_path[i]); + _tree_set->erase(right_path[i]); + } + + int surface = + _blossom_set->join(subblossoms.begin(), subblossoms.end()); + + for (int i = 0; i < int(subblossoms.size()); ++i) { + if (!_blossom_set->trivial(subblossoms[i])) { + (*_blossom_data)[subblossoms[i]].pot += 2 * _delta_sum; + } + (*_blossom_data)[subblossoms[i]].status = MATCHED; + } + + (*_blossom_data)[surface].pot = -2 * _delta_sum; + (*_blossom_data)[surface].offset = 0; + (*_blossom_data)[surface].status = EVEN; + (*_blossom_data)[surface].pred = (*_blossom_data)[nca].pred; + (*_blossom_data)[surface].next = (*_blossom_data)[nca].pred; + + _tree_set->insert(surface, tree); + _tree_set->erase(nca); + } + + void splitBlossom(int blossom) { + Arc next = (*_blossom_data)[blossom].next; + Arc pred = (*_blossom_data)[blossom].pred; + + int tree = _tree_set->find(blossom); + + (*_blossom_data)[blossom].status = MATCHED; + oddToMatched(blossom); + if (_delta2->state(blossom) == _delta2->IN_HEAP) { + _delta2->erase(blossom); + } + + std::vector subblossoms; + _blossom_set->split(blossom, std::back_inserter(subblossoms)); + + Value offset = (*_blossom_data)[blossom].offset; + int b = _blossom_set->find(_graph.source(pred)); + int d = _blossom_set->find(_graph.source(next)); + + int ib = -1, id = -1; + for (int i = 0; i < int(subblossoms.size()); ++i) { + if (subblossoms[i] == b) ib = i; + if (subblossoms[i] == d) id = i; + + (*_blossom_data)[subblossoms[i]].offset = offset; + if (!_blossom_set->trivial(subblossoms[i])) { + (*_blossom_data)[subblossoms[i]].pot -= 2 * offset; + } + if (_blossom_set->classPrio(subblossoms[i]) != + std::numeric_limits::max()) { + _delta2->push(subblossoms[i], + _blossom_set->classPrio(subblossoms[i]) - + (*_blossom_data)[subblossoms[i]].offset); + } + } + + if (id > ib ? ((id - ib) % 2 == 0) : ((ib - id) % 2 == 1)) { + for (int i = (id + 1) % subblossoms.size(); + i != ib; i = (i + 2) % subblossoms.size()) { + int sb = subblossoms[i]; + int tb = subblossoms[(i + 1) % subblossoms.size()]; + (*_blossom_data)[sb].next = + _graph.oppositeArc((*_blossom_data)[tb].next); + } + + for (int i = ib; i != id; i = (i + 2) % subblossoms.size()) { + int sb = subblossoms[i]; + int tb = subblossoms[(i + 1) % subblossoms.size()]; + int ub = subblossoms[(i + 2) % subblossoms.size()]; + + (*_blossom_data)[sb].status = ODD; + matchedToOdd(sb); + _tree_set->insert(sb, tree); + (*_blossom_data)[sb].pred = pred; + (*_blossom_data)[sb].next = + _graph.oppositeArc((*_blossom_data)[tb].next); + + pred = (*_blossom_data)[ub].next; + + (*_blossom_data)[tb].status = EVEN; + matchedToEven(tb, tree); + _tree_set->insert(tb, tree); + (*_blossom_data)[tb].pred = (*_blossom_data)[tb].next; + } + + (*_blossom_data)[subblossoms[id]].status = ODD; + matchedToOdd(subblossoms[id]); + _tree_set->insert(subblossoms[id], tree); + (*_blossom_data)[subblossoms[id]].next = next; + (*_blossom_data)[subblossoms[id]].pred = pred; + + } else { + + for (int i = (ib + 1) % subblossoms.size(); + i != id; i = (i + 2) % subblossoms.size()) { + int sb = subblossoms[i]; + int tb = subblossoms[(i + 1) % subblossoms.size()]; + (*_blossom_data)[sb].next = + _graph.oppositeArc((*_blossom_data)[tb].next); + } + + for (int i = id; i != ib; i = (i + 2) % subblossoms.size()) { + int sb = subblossoms[i]; + int tb = subblossoms[(i + 1) % subblossoms.size()]; + int ub = subblossoms[(i + 2) % subblossoms.size()]; + + (*_blossom_data)[sb].status = ODD; + matchedToOdd(sb); + _tree_set->insert(sb, tree); + (*_blossom_data)[sb].next = next; + (*_blossom_data)[sb].pred = + _graph.oppositeArc((*_blossom_data)[tb].next); + + (*_blossom_data)[tb].status = EVEN; + matchedToEven(tb, tree); + _tree_set->insert(tb, tree); + (*_blossom_data)[tb].pred = + (*_blossom_data)[tb].next = + _graph.oppositeArc((*_blossom_data)[ub].next); + next = (*_blossom_data)[ub].next; + } + + (*_blossom_data)[subblossoms[ib]].status = ODD; + matchedToOdd(subblossoms[ib]); + _tree_set->insert(subblossoms[ib], tree); + (*_blossom_data)[subblossoms[ib]].next = next; + (*_blossom_data)[subblossoms[ib]].pred = pred; + } + _tree_set->erase(blossom); + } + + void extractBlossom(int blossom, const Node& base, const Arc& matching) { + if (_blossom_set->trivial(blossom)) { + int bi = (*_node_index)[base]; + Value pot = (*_node_data)[bi].pot; + + (*_matching)[base] = matching; + _blossom_node_list.push_back(base); + (*_node_potential)[base] = pot; + } else { + + Value pot = (*_blossom_data)[blossom].pot; + int bn = _blossom_node_list.size(); + + std::vector subblossoms; + _blossom_set->split(blossom, std::back_inserter(subblossoms)); + int b = _blossom_set->find(base); + int ib = -1; + for (int i = 0; i < int(subblossoms.size()); ++i) { + if (subblossoms[i] == b) { ib = i; break; } + } + + for (int i = 1; i < int(subblossoms.size()); i += 2) { + int sb = subblossoms[(ib + i) % subblossoms.size()]; + int tb = subblossoms[(ib + i + 1) % subblossoms.size()]; + + Arc m = (*_blossom_data)[tb].next; + extractBlossom(sb, _graph.target(m), _graph.oppositeArc(m)); + extractBlossom(tb, _graph.source(m), m); + } + extractBlossom(subblossoms[ib], base, matching); + + int en = _blossom_node_list.size(); + + _blossom_potential.push_back(BlossomVariable(bn, en, pot)); + } + } + + void extractMatching() { + std::vector blossoms; + for (typename BlossomSet::ClassIt c(*_blossom_set); c != INVALID; ++c) { + blossoms.push_back(c); + } + + for (int i = 0; i < int(blossoms.size()); ++i) { + if ((*_blossom_data)[blossoms[i]].next != INVALID) { + + Value offset = (*_blossom_data)[blossoms[i]].offset; + (*_blossom_data)[blossoms[i]].pot += 2 * offset; + for (typename BlossomSet::ItemIt n(*_blossom_set, blossoms[i]); + n != INVALID; ++n) { + (*_node_data)[(*_node_index)[n]].pot -= offset; + } + + Arc matching = (*_blossom_data)[blossoms[i]].next; + Node base = _graph.source(matching); + extractBlossom(blossoms[i], base, matching); + } else { + Node base = (*_blossom_data)[blossoms[i]].base; + extractBlossom(blossoms[i], base, INVALID); + } + } + } + + public: + + /// \brief Constructor + /// + /// Constructor. + MaxWeightedMatching(const Graph& graph, const WeightMap& weight) + : _graph(graph), _weight(weight), _matching(0), + _node_potential(0), _blossom_potential(), _blossom_node_list(), + _node_num(0), _blossom_num(0), + + _blossom_index(0), _blossom_set(0), _blossom_data(0), + _node_index(0), _node_heap_index(0), _node_data(0), + _tree_set_index(0), _tree_set(0), + + _delta1_index(0), _delta1(0), + _delta2_index(0), _delta2(0), + _delta3_index(0), _delta3(0), + _delta4_index(0), _delta4(0), + + _delta_sum(), _unmatched(0), + + _fractional(0) + {} + + ~MaxWeightedMatching() { + destroyStructures(); + if (_fractional) { + delete _fractional; + } + } + + /// \name Execution Control + /// The simplest way to execute the algorithm is to use the + /// \ref run() member function. + + ///@{ + + /// \brief Initialize the algorithm + /// + /// This function initializes the algorithm. + void init() { + createStructures(); + + _blossom_node_list.clear(); + _blossom_potential.clear(); + + for (ArcIt e(_graph); e != INVALID; ++e) { + (*_node_heap_index)[e] = BinHeap::PRE_HEAP; + } + for (NodeIt n(_graph); n != INVALID; ++n) { + (*_delta1_index)[n] = _delta1->PRE_HEAP; + } + for (EdgeIt e(_graph); e != INVALID; ++e) { + (*_delta3_index)[e] = _delta3->PRE_HEAP; + } + for (int i = 0; i < _blossom_num; ++i) { + (*_delta2_index)[i] = _delta2->PRE_HEAP; + (*_delta4_index)[i] = _delta4->PRE_HEAP; + } + + _unmatched = _node_num; + + _delta1->clear(); + _delta2->clear(); + _delta3->clear(); + _delta4->clear(); + _blossom_set->clear(); + _tree_set->clear(); + + int index = 0; + for (NodeIt n(_graph); n != INVALID; ++n) { + Value max = 0; + for (OutArcIt e(_graph, n); e != INVALID; ++e) { + if (_graph.target(e) == n) continue; + if ((dualScale * _weight[e]) / 2 > max) { + max = (dualScale * _weight[e]) / 2; + } + } + (*_node_index)[n] = index; + (*_node_data)[index].heap_index.clear(); + (*_node_data)[index].heap.clear(); + (*_node_data)[index].pot = max; + _delta1->push(n, max); + int blossom = + _blossom_set->insert(n, std::numeric_limits::max()); + + _tree_set->insert(blossom); + + (*_blossom_data)[blossom].status = EVEN; + (*_blossom_data)[blossom].pred = INVALID; + (*_blossom_data)[blossom].next = INVALID; + (*_blossom_data)[blossom].pot = 0; + (*_blossom_data)[blossom].offset = 0; + ++index; + } + for (EdgeIt e(_graph); e != INVALID; ++e) { + int si = (*_node_index)[_graph.u(e)]; + int ti = (*_node_index)[_graph.v(e)]; + if (_graph.u(e) != _graph.v(e)) { + _delta3->push(e, ((*_node_data)[si].pot + (*_node_data)[ti].pot - + dualScale * _weight[e]) / 2); + } + } + } + + /// \brief Initialize the algorithm with fractional matching + /// + /// This function initializes the algorithm with a fractional + /// matching. This initialization is also called jumpstart heuristic. + void fractionalInit() { + createStructures(); + + _blossom_node_list.clear(); + _blossom_potential.clear(); + + if (_fractional == 0) { + _fractional = new FractionalMatching(_graph, _weight, false); + } + _fractional->run(); + + for (ArcIt e(_graph); e != INVALID; ++e) { + (*_node_heap_index)[e] = BinHeap::PRE_HEAP; + } + for (NodeIt n(_graph); n != INVALID; ++n) { + (*_delta1_index)[n] = _delta1->PRE_HEAP; + } + for (EdgeIt e(_graph); e != INVALID; ++e) { + (*_delta3_index)[e] = _delta3->PRE_HEAP; + } + for (int i = 0; i < _blossom_num; ++i) { + (*_delta2_index)[i] = _delta2->PRE_HEAP; + (*_delta4_index)[i] = _delta4->PRE_HEAP; + } + + _unmatched = 0; + + _delta1->clear(); + _delta2->clear(); + _delta3->clear(); + _delta4->clear(); + _blossom_set->clear(); + _tree_set->clear(); + + int index = 0; + for (NodeIt n(_graph); n != INVALID; ++n) { + Value pot = _fractional->nodeValue(n); + (*_node_index)[n] = index; + (*_node_data)[index].pot = pot; + (*_node_data)[index].heap_index.clear(); + (*_node_data)[index].heap.clear(); + int blossom = + _blossom_set->insert(n, std::numeric_limits::max()); + + (*_blossom_data)[blossom].status = MATCHED; + (*_blossom_data)[blossom].pred = INVALID; + (*_blossom_data)[blossom].next = _fractional->matching(n); + if (_fractional->matching(n) == INVALID) { + (*_blossom_data)[blossom].base = n; + } + (*_blossom_data)[blossom].pot = 0; + (*_blossom_data)[blossom].offset = 0; + ++index; + } + + typename Graph::template NodeMap processed(_graph, false); + for (NodeIt n(_graph); n != INVALID; ++n) { + if (processed[n]) continue; + processed[n] = true; + if (_fractional->matching(n) == INVALID) continue; + int num = 1; + Node v = _graph.target(_fractional->matching(n)); + while (n != v) { + processed[v] = true; + v = _graph.target(_fractional->matching(v)); + ++num; + } + + if (num % 2 == 1) { + std::vector subblossoms(num); + + subblossoms[--num] = _blossom_set->find(n); + _delta1->push(n, _fractional->nodeValue(n)); + v = _graph.target(_fractional->matching(n)); + while (n != v) { + subblossoms[--num] = _blossom_set->find(v); + _delta1->push(v, _fractional->nodeValue(v)); + v = _graph.target(_fractional->matching(v)); + } + + int surface = + _blossom_set->join(subblossoms.begin(), subblossoms.end()); + (*_blossom_data)[surface].status = EVEN; + (*_blossom_data)[surface].pred = INVALID; + (*_blossom_data)[surface].next = INVALID; + (*_blossom_data)[surface].pot = 0; + (*_blossom_data)[surface].offset = 0; + + _tree_set->insert(surface); + ++_unmatched; + } + } + + for (EdgeIt e(_graph); e != INVALID; ++e) { + int si = (*_node_index)[_graph.u(e)]; + int sb = _blossom_set->find(_graph.u(e)); + int ti = (*_node_index)[_graph.v(e)]; + int tb = _blossom_set->find(_graph.v(e)); + if ((*_blossom_data)[sb].status == EVEN && + (*_blossom_data)[tb].status == EVEN && sb != tb) { + _delta3->push(e, ((*_node_data)[si].pot + (*_node_data)[ti].pot - + dualScale * _weight[e]) / 2); + } + } + + for (NodeIt n(_graph); n != INVALID; ++n) { + int nb = _blossom_set->find(n); + if ((*_blossom_data)[nb].status != MATCHED) continue; + int ni = (*_node_index)[n]; + + for (OutArcIt e(_graph, n); e != INVALID; ++e) { + Node v = _graph.target(e); + int vb = _blossom_set->find(v); + int vi = (*_node_index)[v]; + + Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot - + dualScale * _weight[e]; + + if ((*_blossom_data)[vb].status == EVEN) { + + int vt = _tree_set->find(vb); + + typename std::map::iterator it = + (*_node_data)[ni].heap_index.find(vt); + + if (it != (*_node_data)[ni].heap_index.end()) { + if ((*_node_data)[ni].heap[it->second] > rw) { + (*_node_data)[ni].heap.replace(it->second, e); + (*_node_data)[ni].heap.decrease(e, rw); + it->second = e; + } + } else { + (*_node_data)[ni].heap.push(e, rw); + (*_node_data)[ni].heap_index.insert(std::make_pair(vt, e)); + } + } + } + + if (!(*_node_data)[ni].heap.empty()) { + _blossom_set->decrease(n, (*_node_data)[ni].heap.prio()); + _delta2->push(nb, _blossom_set->classPrio(nb)); + } + } + } + + /// \brief Start the algorithm + /// + /// This function starts the algorithm. + /// + /// \pre \ref init() or \ref fractionalInit() must be called + /// before using this function. + void start() { + enum OpType { + D1, D2, D3, D4 + }; + + while (_unmatched > 0) { + Value d1 = !_delta1->empty() ? + _delta1->prio() : std::numeric_limits::max(); + + Value d2 = !_delta2->empty() ? + _delta2->prio() : std::numeric_limits::max(); + + Value d3 = !_delta3->empty() ? + _delta3->prio() : std::numeric_limits::max(); + + Value d4 = !_delta4->empty() ? + _delta4->prio() : std::numeric_limits::max(); + + _delta_sum = d3; OpType ot = D3; + if (d1 < _delta_sum) { _delta_sum = d1; ot = D1; } + if (d2 < _delta_sum) { _delta_sum = d2; ot = D2; } + if (d4 < _delta_sum) { _delta_sum = d4; ot = D4; } + + switch (ot) { + case D1: + { + Node n = _delta1->top(); + unmatchNode(n); + --_unmatched; + } + break; + case D2: + { + int blossom = _delta2->top(); + Node n = _blossom_set->classTop(blossom); + Arc a = (*_node_data)[(*_node_index)[n]].heap.top(); + if ((*_blossom_data)[blossom].next == INVALID) { + augmentOnArc(a); + --_unmatched; + } else { + extendOnArc(a); + } + } + break; + case D3: + { + Edge e = _delta3->top(); + + int left_blossom = _blossom_set->find(_graph.u(e)); + int right_blossom = _blossom_set->find(_graph.v(e)); + + if (left_blossom == right_blossom) { + _delta3->pop(); + } else { + int left_tree = _tree_set->find(left_blossom); + int right_tree = _tree_set->find(right_blossom); + + if (left_tree == right_tree) { + shrinkOnEdge(e, left_tree); + } else { + augmentOnEdge(e); + _unmatched -= 2; + } + } + } break; + case D4: + splitBlossom(_delta4->top()); + break; + } + } + extractMatching(); + } + + /// \brief Run the algorithm. + /// + /// This method runs the \c %MaxWeightedMatching algorithm. + /// + /// \note mwm.run() is just a shortcut of the following code. + /// \code + /// mwm.fractionalInit(); + /// mwm.start(); + /// \endcode + void run() { + fractionalInit(); + start(); + } + + /// @} + + /// \name Primal Solution + /// Functions to get the primal solution, i.e. the maximum weighted + /// matching.\n + /// Either \ref run() or \ref start() function should be called before + /// using them. + + /// @{ + + /// \brief Return the weight of the matching. + /// + /// This function returns the weight of the found matching. + /// + /// \pre Either run() or start() must be called before using this function. + Value matchingWeight() const { + Value sum = 0; + for (NodeIt n(_graph); n != INVALID; ++n) { + if ((*_matching)[n] != INVALID) { + sum += _weight[(*_matching)[n]]; + } + } + return sum / 2; + } + + /// \brief Return the size (cardinality) of the matching. + /// + /// This function returns the size (cardinality) of the found matching. + /// + /// \pre Either run() or start() must be called before using this function. + int matchingSize() const { + int num = 0; + for (NodeIt n(_graph); n != INVALID; ++n) { + if ((*_matching)[n] != INVALID) { + ++num; + } + } + return num /= 2; + } + + /// \brief Return \c true if the given edge is in the matching. + /// + /// This function returns \c true if the given edge is in the found + /// matching. + /// + /// \pre Either run() or start() must be called before using this function. + bool matching(const Edge& edge) const { + return edge == (*_matching)[_graph.u(edge)]; + } + + /// \brief Return the matching arc (or edge) incident to the given node. + /// + /// This function returns the matching arc (or edge) incident to the + /// given node in the found matching or \c INVALID if the node is + /// not covered by the matching. + /// + /// \pre Either run() or start() must be called before using this function. + Arc matching(const Node& node) const { + return (*_matching)[node]; + } + + /// \brief Return a const reference to the matching map. + /// + /// This function returns a const reference to a node map that stores + /// the matching arc (or edge) incident to each node. + const MatchingMap& matchingMap() const { + return *_matching; + } + + /// \brief Return the mate of the given node. + /// + /// This function returns the mate of the given node in the found + /// matching or \c INVALID if the node is not covered by the matching. + /// + /// \pre Either run() or start() must be called before using this function. + Node mate(const Node& node) const { + return (*_matching)[node] != INVALID ? + _graph.target((*_matching)[node]) : INVALID; + } + + /// @} + + /// \name Dual Solution + /// Functions to get the dual solution.\n + /// Either \ref run() or \ref start() function should be called before + /// using them. + + /// @{ + + /// \brief Return the value of the dual solution. + /// + /// This function returns the value of the dual solution. + /// It should be equal to the primal value scaled by \ref dualScale + /// "dual scale". + /// + /// \pre Either run() or start() must be called before using this function. + Value dualValue() const { + Value sum = 0; + for (NodeIt n(_graph); n != INVALID; ++n) { + sum += nodeValue(n); + } + for (int i = 0; i < blossomNum(); ++i) { + sum += blossomValue(i) * (blossomSize(i) / 2); + } + return sum; + } + + /// \brief Return the dual value (potential) of the given node. + /// + /// This function returns the dual value (potential) of the given node. + /// + /// \pre Either run() or start() must be called before using this function. + Value nodeValue(const Node& n) const { + return (*_node_potential)[n]; + } + + /// \brief Return the number of the blossoms in the basis. + /// + /// This function returns the number of the blossoms in the basis. + /// + /// \pre Either run() or start() must be called before using this function. + /// \see BlossomIt + int blossomNum() const { + return _blossom_potential.size(); + } + + /// \brief Return the number of the nodes in the given blossom. + /// + /// This function returns the number of the nodes in the given blossom. + /// + /// \pre Either run() or start() must be called before using this function. + /// \see BlossomIt + int blossomSize(int k) const { + return _blossom_potential[k].end - _blossom_potential[k].begin; + } + + /// \brief Return the dual value (ptential) of the given blossom. + /// + /// This function returns the dual value (ptential) of the given blossom. + /// + /// \pre Either run() or start() must be called before using this function. + Value blossomValue(int k) const { + return _blossom_potential[k].value; + } + + /// \brief Iterator for obtaining the nodes of a blossom. + /// + /// This class provides an iterator for obtaining the nodes of the + /// given blossom. It lists a subset of the nodes. + /// Before using this iterator, you must allocate a + /// MaxWeightedMatching class and execute it. + class BlossomIt { + public: + + /// \brief Constructor. + /// + /// Constructor to get the nodes of the given variable. + /// + /// \pre Either \ref MaxWeightedMatching::run() "algorithm.run()" or + /// \ref MaxWeightedMatching::start() "algorithm.start()" must be + /// called before initializing this iterator. + BlossomIt(const MaxWeightedMatching& algorithm, int variable) + : _algorithm(&algorithm) + { + _index = _algorithm->_blossom_potential[variable].begin; + _last = _algorithm->_blossom_potential[variable].end; + } + + /// \brief Conversion to \c Node. + /// + /// Conversion to \c Node. + operator Node() const { + return _algorithm->_blossom_node_list[_index]; + } + + /// \brief Increment operator. + /// + /// Increment operator. + BlossomIt& operator++() { + ++_index; + return *this; + } + + /// \brief Validity checking + /// + /// Checks whether the iterator is invalid. + bool operator==(Invalid) const { return _index == _last; } + + /// \brief Validity checking + /// + /// Checks whether the iterator is valid. + bool operator!=(Invalid) const { return _index != _last; } + + private: + const MaxWeightedMatching* _algorithm; + int _last; + int _index; + }; + + /// @} + + }; + + /// \ingroup matching + /// + /// \brief Weighted perfect matching in general graphs + /// + /// This class provides an efficient implementation of Edmond's + /// maximum weighted perfect matching algorithm. The implementation + /// is based on extensive use of priority queues and provides + /// \f$O(nm\log n)\f$ time complexity. + /// + /// The maximum weighted perfect matching problem is to find a subset of + /// the edges in an undirected graph with maximum overall weight for which + /// each node has exactly one incident edge. + /// It can be formulated with the following linear program. + /// \f[ \sum_{e \in \delta(u)}x_e = 1 \quad \forall u\in V\f] + /** \f[ \sum_{e \in \gamma(B)}x_e \le \frac{\vert B \vert - 1}{2} + \quad \forall B\in\mathcal{O}\f] */ + /// \f[x_e \ge 0\quad \forall e\in E\f] + /// \f[\max \sum_{e\in E}x_ew_e\f] + /// where \f$\delta(X)\f$ is the set of edges incident to a node in + /// \f$X\f$, \f$\gamma(X)\f$ is the set of edges with both ends in + /// \f$X\f$ and \f$\mathcal{O}\f$ is the set of odd cardinality + /// subsets of the nodes. + /// + /// The algorithm calculates an optimal matching and a proof of the + /// optimality. The solution of the dual problem can be used to check + /// the result of the algorithm. The dual linear problem is the + /// following. + /** \f[ y_u + y_v + \sum_{B \in \mathcal{O}, uv \in \gamma(B)}z_B \ge + w_{uv} \quad \forall uv\in E\f] */ + /// \f[z_B \ge 0 \quad \forall B \in \mathcal{O}\f] + /** \f[\min \sum_{u \in V}y_u + \sum_{B \in \mathcal{O}} + \frac{\vert B \vert - 1}{2}z_B\f] */ + /// + /// The algorithm can be executed with the run() function. + /// After it the matching (the primal solution) and the dual solution + /// can be obtained using the query functions and the + /// \ref MaxWeightedPerfectMatching::BlossomIt "BlossomIt" nested class, + /// which is able to iterate on the nodes of a blossom. + /// If the value type is integer, then the dual solution is multiplied + /// by \ref MaxWeightedMatching::dualScale "4". + /// + /// \tparam GR The undirected graph type the algorithm runs on. + /// \tparam WM The type edge weight map. The default type is + /// \ref concepts::Graph::EdgeMap "GR::EdgeMap". +#ifdef DOXYGEN + template +#else + template > +#endif + class MaxWeightedPerfectMatching { + public: + + /// The graph type of the algorithm + typedef GR Graph; + /// The type of the edge weight map + typedef WM WeightMap; + /// The value type of the edge weights + typedef typename WeightMap::Value Value; + + /// \brief Scaling factor for dual solution + /// + /// Scaling factor for dual solution, it is equal to 4 or 1 + /// according to the value type. + static const int dualScale = + std::numeric_limits::is_integer ? 4 : 1; + + /// The type of the matching map + typedef typename Graph::template NodeMap + MatchingMap; + + private: + + TEMPLATE_GRAPH_TYPEDEFS(Graph); + + typedef typename Graph::template NodeMap NodePotential; + typedef std::vector BlossomNodeList; + + struct BlossomVariable { + int begin, end; + Value value; + + BlossomVariable(int _begin, int _end, Value _value) + : begin(_begin), end(_end), value(_value) {} + + }; + + typedef std::vector BlossomPotential; + + const Graph& _graph; + const WeightMap& _weight; + + MatchingMap* _matching; + + NodePotential* _node_potential; + + BlossomPotential _blossom_potential; + BlossomNodeList _blossom_node_list; + + int _node_num; + int _blossom_num; + + typedef RangeMap IntIntMap; + + enum Status { + EVEN = -1, MATCHED = 0, ODD = 1 + }; + + typedef HeapUnionFind BlossomSet; + struct BlossomData { + int tree; + Status status; + Arc pred, next; + Value pot, offset; + }; + + IntNodeMap *_blossom_index; + BlossomSet *_blossom_set; + RangeMap* _blossom_data; + + IntNodeMap *_node_index; + IntArcMap *_node_heap_index; + + struct NodeData { + + NodeData(IntArcMap& node_heap_index) + : heap(node_heap_index) {} + + int blossom; + Value pot; + BinHeap heap; + std::map heap_index; + + int tree; + }; + + RangeMap* _node_data; + + typedef ExtendFindEnum TreeSet; + + IntIntMap *_tree_set_index; + TreeSet *_tree_set; + + IntIntMap *_delta2_index; + BinHeap *_delta2; + + IntEdgeMap *_delta3_index; + BinHeap *_delta3; + + IntIntMap *_delta4_index; + BinHeap *_delta4; + + Value _delta_sum; + int _unmatched; + + typedef MaxWeightedPerfectFractionalMatching + FractionalMatching; + FractionalMatching *_fractional; + + void createStructures() { + _node_num = countNodes(_graph); + _blossom_num = _node_num * 3 / 2; + + if (!_matching) { + _matching = new MatchingMap(_graph); + } + + if (!_node_potential) { + _node_potential = new NodePotential(_graph); + } + + if (!_blossom_set) { + _blossom_index = new IntNodeMap(_graph); + _blossom_set = new BlossomSet(*_blossom_index); + _blossom_data = new RangeMap(_blossom_num); + } else if (_blossom_data->size() != _blossom_num) { + delete _blossom_data; + _blossom_data = new RangeMap(_blossom_num); + } + + if (!_node_index) { + _node_index = new IntNodeMap(_graph); + _node_heap_index = new IntArcMap(_graph); + _node_data = new RangeMap(_node_num, + NodeData(*_node_heap_index)); + } else if (_node_data->size() != _node_num) { + delete _node_data; + _node_data = new RangeMap(_node_num, + NodeData(*_node_heap_index)); + } + + if (!_tree_set) { + _tree_set_index = new IntIntMap(_blossom_num); + _tree_set = new TreeSet(*_tree_set_index); + } else { + _tree_set_index->resize(_blossom_num); + } + + if (!_delta2) { + _delta2_index = new IntIntMap(_blossom_num); + _delta2 = new BinHeap(*_delta2_index); + } else { + _delta2_index->resize(_blossom_num); + } + + if (!_delta3) { + _delta3_index = new IntEdgeMap(_graph); + _delta3 = new BinHeap(*_delta3_index); + } + + if (!_delta4) { + _delta4_index = new IntIntMap(_blossom_num); + _delta4 = new BinHeap(*_delta4_index); + } else { + _delta4_index->resize(_blossom_num); + } + } + + void destroyStructures() { + if (_matching) { + delete _matching; + } + if (_node_potential) { + delete _node_potential; + } + if (_blossom_set) { + delete _blossom_index; + delete _blossom_set; + delete _blossom_data; + } + + if (_node_index) { + delete _node_index; + delete _node_heap_index; + delete _node_data; + } + + if (_tree_set) { + delete _tree_set_index; + delete _tree_set; + } + if (_delta2) { + delete _delta2_index; + delete _delta2; + } + if (_delta3) { + delete _delta3_index; + delete _delta3; + } + if (_delta4) { + delete _delta4_index; + delete _delta4; + } + } + + void matchedToEven(int blossom, int tree) { + if (_delta2->state(blossom) == _delta2->IN_HEAP) { + _delta2->erase(blossom); + } + + if (!_blossom_set->trivial(blossom)) { + (*_blossom_data)[blossom].pot -= + 2 * (_delta_sum - (*_blossom_data)[blossom].offset); + } + + for (typename BlossomSet::ItemIt n(*_blossom_set, blossom); + n != INVALID; ++n) { + + _blossom_set->increase(n, std::numeric_limits::max()); + int ni = (*_node_index)[n]; + + (*_node_data)[ni].heap.clear(); + (*_node_data)[ni].heap_index.clear(); + + (*_node_data)[ni].pot += _delta_sum - (*_blossom_data)[blossom].offset; + + for (InArcIt e(_graph, n); e != INVALID; ++e) { + Node v = _graph.source(e); + int vb = _blossom_set->find(v); + int vi = (*_node_index)[v]; + + Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot - + dualScale * _weight[e]; + + if ((*_blossom_data)[vb].status == EVEN) { + if (_delta3->state(e) != _delta3->IN_HEAP && blossom != vb) { + _delta3->push(e, rw / 2); + } + } else { + typename std::map::iterator it = + (*_node_data)[vi].heap_index.find(tree); + + if (it != (*_node_data)[vi].heap_index.end()) { + if ((*_node_data)[vi].heap[it->second] > rw) { + (*_node_data)[vi].heap.replace(it->second, e); + (*_node_data)[vi].heap.decrease(e, rw); + it->second = e; + } + } else { + (*_node_data)[vi].heap.push(e, rw); + (*_node_data)[vi].heap_index.insert(std::make_pair(tree, e)); + } + + if ((*_blossom_set)[v] > (*_node_data)[vi].heap.prio()) { + _blossom_set->decrease(v, (*_node_data)[vi].heap.prio()); + + if ((*_blossom_data)[vb].status == MATCHED) { + if (_delta2->state(vb) != _delta2->IN_HEAP) { + _delta2->push(vb, _blossom_set->classPrio(vb) - + (*_blossom_data)[vb].offset); + } else if ((*_delta2)[vb] > _blossom_set->classPrio(vb) - + (*_blossom_data)[vb].offset){ + _delta2->decrease(vb, _blossom_set->classPrio(vb) - + (*_blossom_data)[vb].offset); + } + } + } + } + } + } + (*_blossom_data)[blossom].offset = 0; + } + + void matchedToOdd(int blossom) { + if (_delta2->state(blossom) == _delta2->IN_HEAP) { + _delta2->erase(blossom); + } + (*_blossom_data)[blossom].offset += _delta_sum; + if (!_blossom_set->trivial(blossom)) { + _delta4->push(blossom, (*_blossom_data)[blossom].pot / 2 + + (*_blossom_data)[blossom].offset); + } + } + + void evenToMatched(int blossom, int tree) { + if (!_blossom_set->trivial(blossom)) { + (*_blossom_data)[blossom].pot += 2 * _delta_sum; + } + + for (typename BlossomSet::ItemIt n(*_blossom_set, blossom); + n != INVALID; ++n) { + int ni = (*_node_index)[n]; + (*_node_data)[ni].pot -= _delta_sum; + + for (InArcIt e(_graph, n); e != INVALID; ++e) { + Node v = _graph.source(e); + int vb = _blossom_set->find(v); + int vi = (*_node_index)[v]; + + Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot - + dualScale * _weight[e]; + + if (vb == blossom) { + if (_delta3->state(e) == _delta3->IN_HEAP) { + _delta3->erase(e); + } + } else if ((*_blossom_data)[vb].status == EVEN) { + + if (_delta3->state(e) == _delta3->IN_HEAP) { + _delta3->erase(e); + } + + int vt = _tree_set->find(vb); + + if (vt != tree) { + + Arc r = _graph.oppositeArc(e); + + typename std::map::iterator it = + (*_node_data)[ni].heap_index.find(vt); + + if (it != (*_node_data)[ni].heap_index.end()) { + if ((*_node_data)[ni].heap[it->second] > rw) { + (*_node_data)[ni].heap.replace(it->second, r); + (*_node_data)[ni].heap.decrease(r, rw); + it->second = r; + } + } else { + (*_node_data)[ni].heap.push(r, rw); + (*_node_data)[ni].heap_index.insert(std::make_pair(vt, r)); + } + + if ((*_blossom_set)[n] > (*_node_data)[ni].heap.prio()) { + _blossom_set->decrease(n, (*_node_data)[ni].heap.prio()); + + if (_delta2->state(blossom) != _delta2->IN_HEAP) { + _delta2->push(blossom, _blossom_set->classPrio(blossom) - + (*_blossom_data)[blossom].offset); + } else if ((*_delta2)[blossom] > + _blossom_set->classPrio(blossom) - + (*_blossom_data)[blossom].offset){ + _delta2->decrease(blossom, _blossom_set->classPrio(blossom) - + (*_blossom_data)[blossom].offset); + } + } + } + } else { + + typename std::map::iterator it = + (*_node_data)[vi].heap_index.find(tree); + + if (it != (*_node_data)[vi].heap_index.end()) { + (*_node_data)[vi].heap.erase(it->second); + (*_node_data)[vi].heap_index.erase(it); + if ((*_node_data)[vi].heap.empty()) { + _blossom_set->increase(v, std::numeric_limits::max()); + } else if ((*_blossom_set)[v] < (*_node_data)[vi].heap.prio()) { + _blossom_set->increase(v, (*_node_data)[vi].heap.prio()); + } + + if ((*_blossom_data)[vb].status == MATCHED) { + if (_blossom_set->classPrio(vb) == + std::numeric_limits::max()) { + _delta2->erase(vb); + } else if ((*_delta2)[vb] < _blossom_set->classPrio(vb) - + (*_blossom_data)[vb].offset) { + _delta2->increase(vb, _blossom_set->classPrio(vb) - + (*_blossom_data)[vb].offset); + } + } + } + } + } + } + } + + void oddToMatched(int blossom) { + (*_blossom_data)[blossom].offset -= _delta_sum; + + if (_blossom_set->classPrio(blossom) != + std::numeric_limits::max()) { + _delta2->push(blossom, _blossom_set->classPrio(blossom) - + (*_blossom_data)[blossom].offset); + } + + if (!_blossom_set->trivial(blossom)) { + _delta4->erase(blossom); + } + } + + void oddToEven(int blossom, int tree) { + if (!_blossom_set->trivial(blossom)) { + _delta4->erase(blossom); + (*_blossom_data)[blossom].pot -= + 2 * (2 * _delta_sum - (*_blossom_data)[blossom].offset); + } + + for (typename BlossomSet::ItemIt n(*_blossom_set, blossom); + n != INVALID; ++n) { + int ni = (*_node_index)[n]; + + _blossom_set->increase(n, std::numeric_limits::max()); + + (*_node_data)[ni].heap.clear(); + (*_node_data)[ni].heap_index.clear(); + (*_node_data)[ni].pot += + 2 * _delta_sum - (*_blossom_data)[blossom].offset; + + for (InArcIt e(_graph, n); e != INVALID; ++e) { + Node v = _graph.source(e); + int vb = _blossom_set->find(v); + int vi = (*_node_index)[v]; + + Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot - + dualScale * _weight[e]; + + if ((*_blossom_data)[vb].status == EVEN) { + if (_delta3->state(e) != _delta3->IN_HEAP && blossom != vb) { + _delta3->push(e, rw / 2); + } + } else { + + typename std::map::iterator it = + (*_node_data)[vi].heap_index.find(tree); + + if (it != (*_node_data)[vi].heap_index.end()) { + if ((*_node_data)[vi].heap[it->second] > rw) { + (*_node_data)[vi].heap.replace(it->second, e); + (*_node_data)[vi].heap.decrease(e, rw); + it->second = e; + } + } else { + (*_node_data)[vi].heap.push(e, rw); + (*_node_data)[vi].heap_index.insert(std::make_pair(tree, e)); + } + + if ((*_blossom_set)[v] > (*_node_data)[vi].heap.prio()) { + _blossom_set->decrease(v, (*_node_data)[vi].heap.prio()); + + if ((*_blossom_data)[vb].status == MATCHED) { + if (_delta2->state(vb) != _delta2->IN_HEAP) { + _delta2->push(vb, _blossom_set->classPrio(vb) - + (*_blossom_data)[vb].offset); + } else if ((*_delta2)[vb] > _blossom_set->classPrio(vb) - + (*_blossom_data)[vb].offset) { + _delta2->decrease(vb, _blossom_set->classPrio(vb) - + (*_blossom_data)[vb].offset); + } + } + } + } + } + } + (*_blossom_data)[blossom].offset = 0; + } + + void alternatePath(int even, int tree) { + int odd; + + evenToMatched(even, tree); + (*_blossom_data)[even].status = MATCHED; + + while ((*_blossom_data)[even].pred != INVALID) { + odd = _blossom_set->find(_graph.target((*_blossom_data)[even].pred)); + (*_blossom_data)[odd].status = MATCHED; + oddToMatched(odd); + (*_blossom_data)[odd].next = (*_blossom_data)[odd].pred; + + even = _blossom_set->find(_graph.target((*_blossom_data)[odd].pred)); + (*_blossom_data)[even].status = MATCHED; + evenToMatched(even, tree); + (*_blossom_data)[even].next = + _graph.oppositeArc((*_blossom_data)[odd].pred); + } + + } + + void destroyTree(int tree) { + for (TreeSet::ItemIt b(*_tree_set, tree); b != INVALID; ++b) { + if ((*_blossom_data)[b].status == EVEN) { + (*_blossom_data)[b].status = MATCHED; + evenToMatched(b, tree); + } else if ((*_blossom_data)[b].status == ODD) { + (*_blossom_data)[b].status = MATCHED; + oddToMatched(b); + } + } + _tree_set->eraseClass(tree); + } + + void augmentOnEdge(const Edge& edge) { + + int left = _blossom_set->find(_graph.u(edge)); + int right = _blossom_set->find(_graph.v(edge)); + + int left_tree = _tree_set->find(left); + alternatePath(left, left_tree); + destroyTree(left_tree); + + int right_tree = _tree_set->find(right); + alternatePath(right, right_tree); + destroyTree(right_tree); + + (*_blossom_data)[left].next = _graph.direct(edge, true); + (*_blossom_data)[right].next = _graph.direct(edge, false); + } + + void extendOnArc(const Arc& arc) { + int base = _blossom_set->find(_graph.target(arc)); + int tree = _tree_set->find(base); + + int odd = _blossom_set->find(_graph.source(arc)); + _tree_set->insert(odd, tree); + (*_blossom_data)[odd].status = ODD; + matchedToOdd(odd); + (*_blossom_data)[odd].pred = arc; + + int even = _blossom_set->find(_graph.target((*_blossom_data)[odd].next)); + (*_blossom_data)[even].pred = (*_blossom_data)[even].next; + _tree_set->insert(even, tree); + (*_blossom_data)[even].status = EVEN; + matchedToEven(even, tree); + } + + void shrinkOnEdge(const Edge& edge, int tree) { + int nca = -1; + std::vector left_path, right_path; + + { + std::set left_set, right_set; + int left = _blossom_set->find(_graph.u(edge)); + left_path.push_back(left); + left_set.insert(left); + + int right = _blossom_set->find(_graph.v(edge)); + right_path.push_back(right); + right_set.insert(right); + + while (true) { + + if ((*_blossom_data)[left].pred == INVALID) break; + + left = + _blossom_set->find(_graph.target((*_blossom_data)[left].pred)); + left_path.push_back(left); + left = + _blossom_set->find(_graph.target((*_blossom_data)[left].pred)); + left_path.push_back(left); + + left_set.insert(left); + + if (right_set.find(left) != right_set.end()) { + nca = left; + break; + } + + if ((*_blossom_data)[right].pred == INVALID) break; + + right = + _blossom_set->find(_graph.target((*_blossom_data)[right].pred)); + right_path.push_back(right); + right = + _blossom_set->find(_graph.target((*_blossom_data)[right].pred)); + right_path.push_back(right); + + right_set.insert(right); + + if (left_set.find(right) != left_set.end()) { + nca = right; + break; + } + + } + + if (nca == -1) { + if ((*_blossom_data)[left].pred == INVALID) { + nca = right; + while (left_set.find(nca) == left_set.end()) { + nca = + _blossom_set->find(_graph.target((*_blossom_data)[nca].pred)); + right_path.push_back(nca); + nca = + _blossom_set->find(_graph.target((*_blossom_data)[nca].pred)); + right_path.push_back(nca); + } + } else { + nca = left; + while (right_set.find(nca) == right_set.end()) { + nca = + _blossom_set->find(_graph.target((*_blossom_data)[nca].pred)); + left_path.push_back(nca); + nca = + _blossom_set->find(_graph.target((*_blossom_data)[nca].pred)); + left_path.push_back(nca); + } + } + } + } + + std::vector subblossoms; + Arc prev; + + prev = _graph.direct(edge, true); + for (int i = 0; left_path[i] != nca; i += 2) { + subblossoms.push_back(left_path[i]); + (*_blossom_data)[left_path[i]].next = prev; + _tree_set->erase(left_path[i]); + + subblossoms.push_back(left_path[i + 1]); + (*_blossom_data)[left_path[i + 1]].status = EVEN; + oddToEven(left_path[i + 1], tree); + _tree_set->erase(left_path[i + 1]); + prev = _graph.oppositeArc((*_blossom_data)[left_path[i + 1]].pred); + } + + int k = 0; + while (right_path[k] != nca) ++k; + + subblossoms.push_back(nca); + (*_blossom_data)[nca].next = prev; + + for (int i = k - 2; i >= 0; i -= 2) { + subblossoms.push_back(right_path[i + 1]); + (*_blossom_data)[right_path[i + 1]].status = EVEN; + oddToEven(right_path[i + 1], tree); + _tree_set->erase(right_path[i + 1]); + + (*_blossom_data)[right_path[i + 1]].next = + (*_blossom_data)[right_path[i + 1]].pred; + + subblossoms.push_back(right_path[i]); + _tree_set->erase(right_path[i]); + } + + int surface = + _blossom_set->join(subblossoms.begin(), subblossoms.end()); + + for (int i = 0; i < int(subblossoms.size()); ++i) { + if (!_blossom_set->trivial(subblossoms[i])) { + (*_blossom_data)[subblossoms[i]].pot += 2 * _delta_sum; + } + (*_blossom_data)[subblossoms[i]].status = MATCHED; + } + + (*_blossom_data)[surface].pot = -2 * _delta_sum; + (*_blossom_data)[surface].offset = 0; + (*_blossom_data)[surface].status = EVEN; + (*_blossom_data)[surface].pred = (*_blossom_data)[nca].pred; + (*_blossom_data)[surface].next = (*_blossom_data)[nca].pred; + + _tree_set->insert(surface, tree); + _tree_set->erase(nca); + } + + void splitBlossom(int blossom) { + Arc next = (*_blossom_data)[blossom].next; + Arc pred = (*_blossom_data)[blossom].pred; + + int tree = _tree_set->find(blossom); + + (*_blossom_data)[blossom].status = MATCHED; + oddToMatched(blossom); + if (_delta2->state(blossom) == _delta2->IN_HEAP) { + _delta2->erase(blossom); + } + + std::vector subblossoms; + _blossom_set->split(blossom, std::back_inserter(subblossoms)); + + Value offset = (*_blossom_data)[blossom].offset; + int b = _blossom_set->find(_graph.source(pred)); + int d = _blossom_set->find(_graph.source(next)); + + int ib = -1, id = -1; + for (int i = 0; i < int(subblossoms.size()); ++i) { + if (subblossoms[i] == b) ib = i; + if (subblossoms[i] == d) id = i; + + (*_blossom_data)[subblossoms[i]].offset = offset; + if (!_blossom_set->trivial(subblossoms[i])) { + (*_blossom_data)[subblossoms[i]].pot -= 2 * offset; + } + if (_blossom_set->classPrio(subblossoms[i]) != + std::numeric_limits::max()) { + _delta2->push(subblossoms[i], + _blossom_set->classPrio(subblossoms[i]) - + (*_blossom_data)[subblossoms[i]].offset); + } + } + + if (id > ib ? ((id - ib) % 2 == 0) : ((ib - id) % 2 == 1)) { + for (int i = (id + 1) % subblossoms.size(); + i != ib; i = (i + 2) % subblossoms.size()) { + int sb = subblossoms[i]; + int tb = subblossoms[(i + 1) % subblossoms.size()]; + (*_blossom_data)[sb].next = + _graph.oppositeArc((*_blossom_data)[tb].next); + } + + for (int i = ib; i != id; i = (i + 2) % subblossoms.size()) { + int sb = subblossoms[i]; + int tb = subblossoms[(i + 1) % subblossoms.size()]; + int ub = subblossoms[(i + 2) % subblossoms.size()]; + + (*_blossom_data)[sb].status = ODD; + matchedToOdd(sb); + _tree_set->insert(sb, tree); + (*_blossom_data)[sb].pred = pred; + (*_blossom_data)[sb].next = + _graph.oppositeArc((*_blossom_data)[tb].next); + + pred = (*_blossom_data)[ub].next; + + (*_blossom_data)[tb].status = EVEN; + matchedToEven(tb, tree); + _tree_set->insert(tb, tree); + (*_blossom_data)[tb].pred = (*_blossom_data)[tb].next; + } + + (*_blossom_data)[subblossoms[id]].status = ODD; + matchedToOdd(subblossoms[id]); + _tree_set->insert(subblossoms[id], tree); + (*_blossom_data)[subblossoms[id]].next = next; + (*_blossom_data)[subblossoms[id]].pred = pred; + + } else { + + for (int i = (ib + 1) % subblossoms.size(); + i != id; i = (i + 2) % subblossoms.size()) { + int sb = subblossoms[i]; + int tb = subblossoms[(i + 1) % subblossoms.size()]; + (*_blossom_data)[sb].next = + _graph.oppositeArc((*_blossom_data)[tb].next); + } + + for (int i = id; i != ib; i = (i + 2) % subblossoms.size()) { + int sb = subblossoms[i]; + int tb = subblossoms[(i + 1) % subblossoms.size()]; + int ub = subblossoms[(i + 2) % subblossoms.size()]; + + (*_blossom_data)[sb].status = ODD; + matchedToOdd(sb); + _tree_set->insert(sb, tree); + (*_blossom_data)[sb].next = next; + (*_blossom_data)[sb].pred = + _graph.oppositeArc((*_blossom_data)[tb].next); + + (*_blossom_data)[tb].status = EVEN; + matchedToEven(tb, tree); + _tree_set->insert(tb, tree); + (*_blossom_data)[tb].pred = + (*_blossom_data)[tb].next = + _graph.oppositeArc((*_blossom_data)[ub].next); + next = (*_blossom_data)[ub].next; + } + + (*_blossom_data)[subblossoms[ib]].status = ODD; + matchedToOdd(subblossoms[ib]); + _tree_set->insert(subblossoms[ib], tree); + (*_blossom_data)[subblossoms[ib]].next = next; + (*_blossom_data)[subblossoms[ib]].pred = pred; + } + _tree_set->erase(blossom); + } + + void extractBlossom(int blossom, const Node& base, const Arc& matching) { + if (_blossom_set->trivial(blossom)) { + int bi = (*_node_index)[base]; + Value pot = (*_node_data)[bi].pot; + + (*_matching)[base] = matching; + _blossom_node_list.push_back(base); + (*_node_potential)[base] = pot; + } else { + + Value pot = (*_blossom_data)[blossom].pot; + int bn = _blossom_node_list.size(); + + std::vector subblossoms; + _blossom_set->split(blossom, std::back_inserter(subblossoms)); + int b = _blossom_set->find(base); + int ib = -1; + for (int i = 0; i < int(subblossoms.size()); ++i) { + if (subblossoms[i] == b) { ib = i; break; } + } + + for (int i = 1; i < int(subblossoms.size()); i += 2) { + int sb = subblossoms[(ib + i) % subblossoms.size()]; + int tb = subblossoms[(ib + i + 1) % subblossoms.size()]; + + Arc m = (*_blossom_data)[tb].next; + extractBlossom(sb, _graph.target(m), _graph.oppositeArc(m)); + extractBlossom(tb, _graph.source(m), m); + } + extractBlossom(subblossoms[ib], base, matching); + + int en = _blossom_node_list.size(); + + _blossom_potential.push_back(BlossomVariable(bn, en, pot)); + } + } + + void extractMatching() { + std::vector blossoms; + for (typename BlossomSet::ClassIt c(*_blossom_set); c != INVALID; ++c) { + blossoms.push_back(c); + } + + for (int i = 0; i < int(blossoms.size()); ++i) { + + Value offset = (*_blossom_data)[blossoms[i]].offset; + (*_blossom_data)[blossoms[i]].pot += 2 * offset; + for (typename BlossomSet::ItemIt n(*_blossom_set, blossoms[i]); + n != INVALID; ++n) { + (*_node_data)[(*_node_index)[n]].pot -= offset; + } + + Arc matching = (*_blossom_data)[blossoms[i]].next; + Node base = _graph.source(matching); + extractBlossom(blossoms[i], base, matching); + } + } + + public: + + /// \brief Constructor + /// + /// Constructor. + MaxWeightedPerfectMatching(const Graph& graph, const WeightMap& weight) + : _graph(graph), _weight(weight), _matching(0), + _node_potential(0), _blossom_potential(), _blossom_node_list(), + _node_num(0), _blossom_num(0), + + _blossom_index(0), _blossom_set(0), _blossom_data(0), + _node_index(0), _node_heap_index(0), _node_data(0), + _tree_set_index(0), _tree_set(0), + + _delta2_index(0), _delta2(0), + _delta3_index(0), _delta3(0), + _delta4_index(0), _delta4(0), + + _delta_sum(), _unmatched(0), + + _fractional(0) + {} + + ~MaxWeightedPerfectMatching() { + destroyStructures(); + if (_fractional) { + delete _fractional; + } + } + + /// \name Execution Control + /// The simplest way to execute the algorithm is to use the + /// \ref run() member function. + + ///@{ + + /// \brief Initialize the algorithm + /// + /// This function initializes the algorithm. + void init() { + createStructures(); + + _blossom_node_list.clear(); + _blossom_potential.clear(); + + for (ArcIt e(_graph); e != INVALID; ++e) { + (*_node_heap_index)[e] = BinHeap::PRE_HEAP; + } + for (EdgeIt e(_graph); e != INVALID; ++e) { + (*_delta3_index)[e] = _delta3->PRE_HEAP; + } + for (int i = 0; i < _blossom_num; ++i) { + (*_delta2_index)[i] = _delta2->PRE_HEAP; + (*_delta4_index)[i] = _delta4->PRE_HEAP; + } + + _unmatched = _node_num; + + _delta2->clear(); + _delta3->clear(); + _delta4->clear(); + _blossom_set->clear(); + _tree_set->clear(); + + int index = 0; + for (NodeIt n(_graph); n != INVALID; ++n) { + Value max = - std::numeric_limits::max(); + for (OutArcIt e(_graph, n); e != INVALID; ++e) { + if (_graph.target(e) == n) continue; + if ((dualScale * _weight[e]) / 2 > max) { + max = (dualScale * _weight[e]) / 2; + } + } + (*_node_index)[n] = index; + (*_node_data)[index].heap_index.clear(); + (*_node_data)[index].heap.clear(); + (*_node_data)[index].pot = max; + int blossom = + _blossom_set->insert(n, std::numeric_limits::max()); + + _tree_set->insert(blossom); + + (*_blossom_data)[blossom].status = EVEN; + (*_blossom_data)[blossom].pred = INVALID; + (*_blossom_data)[blossom].next = INVALID; + (*_blossom_data)[blossom].pot = 0; + (*_blossom_data)[blossom].offset = 0; + ++index; + } + for (EdgeIt e(_graph); e != INVALID; ++e) { + int si = (*_node_index)[_graph.u(e)]; + int ti = (*_node_index)[_graph.v(e)]; + if (_graph.u(e) != _graph.v(e)) { + _delta3->push(e, ((*_node_data)[si].pot + (*_node_data)[ti].pot - + dualScale * _weight[e]) / 2); + } + } + } + + /// \brief Initialize the algorithm with fractional matching + /// + /// This function initializes the algorithm with a fractional + /// matching. This initialization is also called jumpstart heuristic. + void fractionalInit() { + createStructures(); + + _blossom_node_list.clear(); + _blossom_potential.clear(); + + if (_fractional == 0) { + _fractional = new FractionalMatching(_graph, _weight, false); + } + if (!_fractional->run()) { + _unmatched = -1; + return; + } + + for (ArcIt e(_graph); e != INVALID; ++e) { + (*_node_heap_index)[e] = BinHeap::PRE_HEAP; + } + for (EdgeIt e(_graph); e != INVALID; ++e) { + (*_delta3_index)[e] = _delta3->PRE_HEAP; + } + for (int i = 0; i < _blossom_num; ++i) { + (*_delta2_index)[i] = _delta2->PRE_HEAP; + (*_delta4_index)[i] = _delta4->PRE_HEAP; + } + + _unmatched = 0; + + _delta2->clear(); + _delta3->clear(); + _delta4->clear(); + _blossom_set->clear(); + _tree_set->clear(); + + int index = 0; + for (NodeIt n(_graph); n != INVALID; ++n) { + Value pot = _fractional->nodeValue(n); + (*_node_index)[n] = index; + (*_node_data)[index].pot = pot; + (*_node_data)[index].heap_index.clear(); + (*_node_data)[index].heap.clear(); + int blossom = + _blossom_set->insert(n, std::numeric_limits::max()); + + (*_blossom_data)[blossom].status = MATCHED; + (*_blossom_data)[blossom].pred = INVALID; + (*_blossom_data)[blossom].next = _fractional->matching(n); + (*_blossom_data)[blossom].pot = 0; + (*_blossom_data)[blossom].offset = 0; + ++index; + } + + typename Graph::template NodeMap processed(_graph, false); + for (NodeIt n(_graph); n != INVALID; ++n) { + if (processed[n]) continue; + processed[n] = true; + if (_fractional->matching(n) == INVALID) continue; + int num = 1; + Node v = _graph.target(_fractional->matching(n)); + while (n != v) { + processed[v] = true; + v = _graph.target(_fractional->matching(v)); + ++num; + } + + if (num % 2 == 1) { + std::vector subblossoms(num); + + subblossoms[--num] = _blossom_set->find(n); + v = _graph.target(_fractional->matching(n)); + while (n != v) { + subblossoms[--num] = _blossom_set->find(v); + v = _graph.target(_fractional->matching(v)); + } + + int surface = + _blossom_set->join(subblossoms.begin(), subblossoms.end()); + (*_blossom_data)[surface].status = EVEN; + (*_blossom_data)[surface].pred = INVALID; + (*_blossom_data)[surface].next = INVALID; + (*_blossom_data)[surface].pot = 0; + (*_blossom_data)[surface].offset = 0; + + _tree_set->insert(surface); + ++_unmatched; + } + } + + for (EdgeIt e(_graph); e != INVALID; ++e) { + int si = (*_node_index)[_graph.u(e)]; + int sb = _blossom_set->find(_graph.u(e)); + int ti = (*_node_index)[_graph.v(e)]; + int tb = _blossom_set->find(_graph.v(e)); + if ((*_blossom_data)[sb].status == EVEN && + (*_blossom_data)[tb].status == EVEN && sb != tb) { + _delta3->push(e, ((*_node_data)[si].pot + (*_node_data)[ti].pot - + dualScale * _weight[e]) / 2); + } + } + + for (NodeIt n(_graph); n != INVALID; ++n) { + int nb = _blossom_set->find(n); + if ((*_blossom_data)[nb].status != MATCHED) continue; + int ni = (*_node_index)[n]; + + for (OutArcIt e(_graph, n); e != INVALID; ++e) { + Node v = _graph.target(e); + int vb = _blossom_set->find(v); + int vi = (*_node_index)[v]; + + Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot - + dualScale * _weight[e]; + + if ((*_blossom_data)[vb].status == EVEN) { + + int vt = _tree_set->find(vb); + + typename std::map::iterator it = + (*_node_data)[ni].heap_index.find(vt); + + if (it != (*_node_data)[ni].heap_index.end()) { + if ((*_node_data)[ni].heap[it->second] > rw) { + (*_node_data)[ni].heap.replace(it->second, e); + (*_node_data)[ni].heap.decrease(e, rw); + it->second = e; + } + } else { + (*_node_data)[ni].heap.push(e, rw); + (*_node_data)[ni].heap_index.insert(std::make_pair(vt, e)); + } + } + } + + if (!(*_node_data)[ni].heap.empty()) { + _blossom_set->decrease(n, (*_node_data)[ni].heap.prio()); + _delta2->push(nb, _blossom_set->classPrio(nb)); + } + } + } + + /// \brief Start the algorithm + /// + /// This function starts the algorithm. + /// + /// \pre \ref init() or \ref fractionalInit() must be called before + /// using this function. + bool start() { + enum OpType { + D2, D3, D4 + }; + + if (_unmatched == -1) return false; + + while (_unmatched > 0) { + Value d2 = !_delta2->empty() ? + _delta2->prio() : std::numeric_limits::max(); + + Value d3 = !_delta3->empty() ? + _delta3->prio() : std::numeric_limits::max(); + + Value d4 = !_delta4->empty() ? + _delta4->prio() : std::numeric_limits::max(); + + _delta_sum = d3; OpType ot = D3; + if (d2 < _delta_sum) { _delta_sum = d2; ot = D2; } + if (d4 < _delta_sum) { _delta_sum = d4; ot = D4; } + + if (_delta_sum == std::numeric_limits::max()) { + return false; + } + + switch (ot) { + case D2: + { + int blossom = _delta2->top(); + Node n = _blossom_set->classTop(blossom); + Arc e = (*_node_data)[(*_node_index)[n]].heap.top(); + extendOnArc(e); + } + break; + case D3: + { + Edge e = _delta3->top(); + + int left_blossom = _blossom_set->find(_graph.u(e)); + int right_blossom = _blossom_set->find(_graph.v(e)); + + if (left_blossom == right_blossom) { + _delta3->pop(); + } else { + int left_tree = _tree_set->find(left_blossom); + int right_tree = _tree_set->find(right_blossom); + + if (left_tree == right_tree) { + shrinkOnEdge(e, left_tree); + } else { + augmentOnEdge(e); + _unmatched -= 2; + } + } + } break; + case D4: + splitBlossom(_delta4->top()); + break; + } + } + extractMatching(); + return true; + } + + /// \brief Run the algorithm. + /// + /// This method runs the \c %MaxWeightedPerfectMatching algorithm. + /// + /// \note mwpm.run() is just a shortcut of the following code. + /// \code + /// mwpm.fractionalInit(); + /// mwpm.start(); + /// \endcode + bool run() { + fractionalInit(); + return start(); + } + + /// @} + + /// \name Primal Solution + /// Functions to get the primal solution, i.e. the maximum weighted + /// perfect matching.\n + /// Either \ref run() or \ref start() function should be called before + /// using them. + + /// @{ + + /// \brief Return the weight of the matching. + /// + /// This function returns the weight of the found matching. + /// + /// \pre Either run() or start() must be called before using this function. + Value matchingWeight() const { + Value sum = 0; + for (NodeIt n(_graph); n != INVALID; ++n) { + if ((*_matching)[n] != INVALID) { + sum += _weight[(*_matching)[n]]; + } + } + return sum / 2; + } + + /// \brief Return \c true if the given edge is in the matching. + /// + /// This function returns \c true if the given edge is in the found + /// matching. + /// + /// \pre Either run() or start() must be called before using this function. + bool matching(const Edge& edge) const { + return static_cast((*_matching)[_graph.u(edge)]) == edge; + } + + /// \brief Return the matching arc (or edge) incident to the given node. + /// + /// This function returns the matching arc (or edge) incident to the + /// given node in the found matching or \c INVALID if the node is + /// not covered by the matching. + /// + /// \pre Either run() or start() must be called before using this function. + Arc matching(const Node& node) const { + return (*_matching)[node]; + } + + /// \brief Return a const reference to the matching map. + /// + /// This function returns a const reference to a node map that stores + /// the matching arc (or edge) incident to each node. + const MatchingMap& matchingMap() const { + return *_matching; + } + + /// \brief Return the mate of the given node. + /// + /// This function returns the mate of the given node in the found + /// matching or \c INVALID if the node is not covered by the matching. + /// + /// \pre Either run() or start() must be called before using this function. + Node mate(const Node& node) const { + return _graph.target((*_matching)[node]); + } + + /// @} + + /// \name Dual Solution + /// Functions to get the dual solution.\n + /// Either \ref run() or \ref start() function should be called before + /// using them. + + /// @{ + + /// \brief Return the value of the dual solution. + /// + /// This function returns the value of the dual solution. + /// It should be equal to the primal value scaled by \ref dualScale + /// "dual scale". + /// + /// \pre Either run() or start() must be called before using this function. + Value dualValue() const { + Value sum = 0; + for (NodeIt n(_graph); n != INVALID; ++n) { + sum += nodeValue(n); + } + for (int i = 0; i < blossomNum(); ++i) { + sum += blossomValue(i) * (blossomSize(i) / 2); + } + return sum; + } + + /// \brief Return the dual value (potential) of the given node. + /// + /// This function returns the dual value (potential) of the given node. + /// + /// \pre Either run() or start() must be called before using this function. + Value nodeValue(const Node& n) const { + return (*_node_potential)[n]; + } + + /// \brief Return the number of the blossoms in the basis. + /// + /// This function returns the number of the blossoms in the basis. + /// + /// \pre Either run() or start() must be called before using this function. + /// \see BlossomIt + int blossomNum() const { + return _blossom_potential.size(); + } + + /// \brief Return the number of the nodes in the given blossom. + /// + /// This function returns the number of the nodes in the given blossom. + /// + /// \pre Either run() or start() must be called before using this function. + /// \see BlossomIt + int blossomSize(int k) const { + return _blossom_potential[k].end - _blossom_potential[k].begin; + } + + /// \brief Return the dual value (ptential) of the given blossom. + /// + /// This function returns the dual value (ptential) of the given blossom. + /// + /// \pre Either run() or start() must be called before using this function. + Value blossomValue(int k) const { + return _blossom_potential[k].value; + } + + /// \brief Iterator for obtaining the nodes of a blossom. + /// + /// This class provides an iterator for obtaining the nodes of the + /// given blossom. It lists a subset of the nodes. + /// Before using this iterator, you must allocate a + /// MaxWeightedPerfectMatching class and execute it. + class BlossomIt { + public: + + /// \brief Constructor. + /// + /// Constructor to get the nodes of the given variable. + /// + /// \pre Either \ref MaxWeightedPerfectMatching::run() "algorithm.run()" + /// or \ref MaxWeightedPerfectMatching::start() "algorithm.start()" + /// must be called before initializing this iterator. + BlossomIt(const MaxWeightedPerfectMatching& algorithm, int variable) + : _algorithm(&algorithm) + { + _index = _algorithm->_blossom_potential[variable].begin; + _last = _algorithm->_blossom_potential[variable].end; + } + + /// \brief Conversion to \c Node. + /// + /// Conversion to \c Node. + operator Node() const { + return _algorithm->_blossom_node_list[_index]; + } + + /// \brief Increment operator. + /// + /// Increment operator. + BlossomIt& operator++() { + ++_index; + return *this; + } + + /// \brief Validity checking + /// + /// This function checks whether the iterator is invalid. + bool operator==(Invalid) const { return _index == _last; } + + /// \brief Validity checking + /// + /// This function checks whether the iterator is valid. + bool operator!=(Invalid) const { return _index != _last; } + + private: + const MaxWeightedPerfectMatching* _algorithm; + int _last; + int _index; + }; + + /// @} + + }; + +} //END OF NAMESPACE LEMON + +#endif //LEMON_MATCHING_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/math.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/math.h new file mode 100644 index 00000000000..5da50b07a9d --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/math.h @@ -0,0 +1,77 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_MATH_H +#define LEMON_MATH_H + +///\ingroup misc +///\file +///\brief Some extensions to the standard \c cmath library. +/// +///Some extensions to the standard \c cmath library. +/// +///This file includes the standard math library (cmath). + +#include + +namespace lemon { + + /// \addtogroup misc + /// @{ + + /// The Euler constant + const long double E = 2.7182818284590452353602874713526625L; + /// log_2(e) + const long double LOG2E = 1.4426950408889634073599246810018921L; + /// log_10(e) + const long double LOG10E = 0.4342944819032518276511289189166051L; + /// ln(2) + const long double LN2 = 0.6931471805599453094172321214581766L; + /// ln(10) + const long double LN10 = 2.3025850929940456840179914546843642L; + /// pi + const long double PI = 3.1415926535897932384626433832795029L; + /// pi/2 + const long double PI_2 = 1.5707963267948966192313216916397514L; + /// pi/4 + const long double PI_4 = 0.7853981633974483096156608458198757L; + /// sqrt(2) + const long double SQRT2 = 1.4142135623730950488016887242096981L; + /// 1/sqrt(2) + const long double SQRT1_2 = 0.7071067811865475244008443621048490L; + + ///Check whether the parameter is NaN or not + + ///This function checks whether the parameter is NaN or not. + ///Is should be equivalent with std::isnan(), but it is not + ///provided by all compilers. + inline bool isNaN(double v) + { + return v!=v; + } + + ///Round a value to its closest integer + inline double round(double r) { + return (r > 0.0) ? std::floor(r + 0.5) : std::ceil(r - 0.5); + } + + /// @} + +} //namespace lemon + +#endif //LEMON_MATH_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/max_cardinality_search.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/max_cardinality_search.h new file mode 100644 index 00000000000..bfa9edb7734 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/max_cardinality_search.h @@ -0,0 +1,794 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_MAX_CARDINALITY_SEARCH_H +#define LEMON_MAX_CARDINALITY_SEARCH_H + + +/// \ingroup search +/// \file +/// \brief Maximum cardinality search in undirected digraphs. + +#include +#include + +#include +#include + +#include + +namespace lemon { + + /// \brief Default traits class of MaxCardinalitySearch class. + /// + /// Default traits class of MaxCardinalitySearch class. + /// \param Digraph Digraph type. + /// \param CapacityMap Type of capacity map. + template + struct MaxCardinalitySearchDefaultTraits { + /// The digraph type the algorithm runs on. + typedef GR Digraph; + + template + struct CapMapSelector { + + typedef CM CapacityMap; + + static CapacityMap *createCapacityMap(const Digraph& g) { + return new CapacityMap(g); + } + }; + + template + struct CapMapSelector > > { + + typedef ConstMap > CapacityMap; + + static CapacityMap *createCapacityMap(const Digraph&) { + return new CapacityMap; + } + }; + + /// \brief The type of the map that stores the arc capacities. + /// + /// The type of the map that stores the arc capacities. + /// It must meet the \ref concepts::ReadMap "ReadMap" concept. + typedef typename CapMapSelector::CapacityMap CapacityMap; + + /// \brief The type of the capacity of the arcs. + typedef typename CapacityMap::Value Value; + + /// \brief Instantiates a CapacityMap. + /// + /// This function instantiates a \ref CapacityMap. + /// \param digraph is the digraph, to which we would like to define + /// the CapacityMap. + static CapacityMap *createCapacityMap(const Digraph& digraph) { + return CapMapSelector::createCapacityMap(digraph); + } + + /// \brief The cross reference type used by heap. + /// + /// The cross reference type used by heap. + /// Usually it is \c Digraph::NodeMap. + typedef typename Digraph::template NodeMap HeapCrossRef; + + /// \brief Instantiates a HeapCrossRef. + /// + /// This function instantiates a \ref HeapCrossRef. + /// \param digraph is the digraph, to which we would like to define the + /// HeapCrossRef. + static HeapCrossRef *createHeapCrossRef(const Digraph &digraph) { + return new HeapCrossRef(digraph); + } + + template + struct HeapSelector { + template + struct Selector { + typedef BinHeap > Heap; + }; + }; + + template + struct HeapSelector > > { + template + struct Selector { + typedef BucketHeap Heap; + }; + }; + + /// \brief The heap type used by MaxCardinalitySearch algorithm. + /// + /// The heap type used by MaxCardinalitySearch algorithm. It should + /// maximalize the priorities. The default heap type is + /// the \ref BinHeap, but it is specialized when the + /// CapacityMap is ConstMap > + /// to BucketHeap. + /// + /// \sa MaxCardinalitySearch + typedef typename HeapSelector + ::template Selector + ::Heap Heap; + + /// \brief Instantiates a Heap. + /// + /// This function instantiates a \ref Heap. + /// \param crossref The cross reference of the heap. + static Heap *createHeap(HeapCrossRef& crossref) { + return new Heap(crossref); + } + + /// \brief The type of the map that stores whether a node is processed. + /// + /// The type of the map that stores whether a node is processed. + /// It must meet the \ref concepts::WriteMap "WriteMap" concept. + /// By default it is a NullMap. + typedef NullMap ProcessedMap; + + /// \brief Instantiates a ProcessedMap. + /// + /// This function instantiates a \ref ProcessedMap. + /// \param digraph is the digraph, to which + /// we would like to define the \ref ProcessedMap +#ifdef DOXYGEN + static ProcessedMap *createProcessedMap(const Digraph &digraph) +#else + static ProcessedMap *createProcessedMap(const Digraph &) +#endif + { + return new ProcessedMap(); + } + + /// \brief The type of the map that stores the cardinalities of the nodes. + /// + /// The type of the map that stores the cardinalities of the nodes. + /// It must meet the \ref concepts::WriteMap "WriteMap" concept. + typedef typename Digraph::template NodeMap CardinalityMap; + + /// \brief Instantiates a CardinalityMap. + /// + /// This function instantiates a \ref CardinalityMap. + /// \param digraph is the digraph, to which we would like to + /// define the \ref CardinalityMap + static CardinalityMap *createCardinalityMap(const Digraph &digraph) { + return new CardinalityMap(digraph); + } + + + }; + + /// \ingroup search + /// + /// \brief Maximum Cardinality Search algorithm class. + /// + /// This class provides an efficient implementation of Maximum Cardinality + /// Search algorithm. The maximum cardinality search first chooses any + /// node of the digraph. Then every time it chooses one unprocessed node + /// with maximum cardinality, i.e the sum of capacities on out arcs + /// to the nodes + /// which were previusly processed. + /// If there is a cut in the digraph the algorithm should choose + /// again any unprocessed node of the digraph. + + /// The arc capacities are passed to the algorithm using a + /// \ref concepts::ReadMap "ReadMap", so it is easy to change it to any + /// kind of capacity. + /// + /// The type of the capacity is determined by the \ref + /// concepts::ReadMap::Value "Value" of the capacity map. + /// + /// It is also possible to change the underlying priority heap. + /// + /// + /// \param GR The digraph type the algorithm runs on. The value of + /// Digraph is not used directly by the search algorithm, it + /// is only passed to \ref MaxCardinalitySearchDefaultTraits. + /// \param CAP This read-only ArcMap determines the capacities of + /// the arcs. It is read once for each arc, so the map may involve in + /// relatively time consuming process to compute the arc capacity if + /// it is necessary. The default map type is \ref + /// ConstMap "ConstMap >". The value + /// of CapacityMap is not used directly by search algorithm, it is only + /// passed to \ref MaxCardinalitySearchDefaultTraits. + /// \param TR Traits class to set various data types used by the + /// algorithm. The default traits class is + /// \ref MaxCardinalitySearchDefaultTraits + /// "MaxCardinalitySearchDefaultTraits". + /// See \ref MaxCardinalitySearchDefaultTraits + /// for the documentation of a MaxCardinalitySearch traits class. + +#ifdef DOXYGEN + template +#else + template >, + typename TR = + MaxCardinalitySearchDefaultTraits > +#endif + class MaxCardinalitySearch { + public: + + typedef TR Traits; + ///The type of the underlying digraph. + typedef typename Traits::Digraph Digraph; + + ///The type of the capacity of the arcs. + typedef typename Traits::CapacityMap::Value Value; + ///The type of the map that stores the arc capacities. + typedef typename Traits::CapacityMap CapacityMap; + ///The type of the map indicating if a node is processed. + typedef typename Traits::ProcessedMap ProcessedMap; + ///The type of the map that stores the cardinalities of the nodes. + typedef typename Traits::CardinalityMap CardinalityMap; + ///The cross reference type used for the current heap. + typedef typename Traits::HeapCrossRef HeapCrossRef; + ///The heap type used by the algorithm. It maximizes the priorities. + typedef typename Traits::Heap Heap; + private: + // Pointer to the underlying digraph. + const Digraph *_graph; + // Pointer to the capacity map + const CapacityMap *_capacity; + // Indicates if \ref _capacity is locally allocated (\c true) or not. + bool local_capacity; + // Pointer to the map of cardinality. + CardinalityMap *_cardinality; + // Indicates if \ref _cardinality is locally allocated (\c true) or not. + bool local_cardinality; + // Pointer to the map of processed status of the nodes. + ProcessedMap *_processed; + // Indicates if \ref _processed is locally allocated (\c true) or not. + bool local_processed; + // Pointer to the heap cross references. + HeapCrossRef *_heap_cross_ref; + // Indicates if \ref _heap_cross_ref is locally allocated (\c true) or not. + bool local_heap_cross_ref; + // Pointer to the heap. + Heap *_heap; + // Indicates if \ref _heap is locally allocated (\c true) or not. + bool local_heap; + + public : + + typedef MaxCardinalitySearch Create; + + ///\name Named template parameters + + ///@{ + + template + struct DefCapacityMapTraits : public Traits { + typedef T CapacityMap; + static CapacityMap *createCapacityMap(const Digraph &) { + LEMON_ASSERT(false,"Uninitialized parameter."); + return 0; + } + }; + /// \brief \ref named-templ-param "Named parameter" for setting + /// CapacityMap type + /// + /// \ref named-templ-param "Named parameter" for setting CapacityMap type + /// for the algorithm. + template + struct SetCapacityMap + : public MaxCardinalitySearch > { + typedef MaxCardinalitySearch > Create; + }; + + template + struct DefCardinalityMapTraits : public Traits { + typedef T CardinalityMap; + static CardinalityMap *createCardinalityMap(const Digraph &) + { + LEMON_ASSERT(false,"Uninitialized parameter."); + return 0; + } + }; + /// \brief \ref named-templ-param "Named parameter" for setting + /// CardinalityMap type + /// + /// \ref named-templ-param "Named parameter" for setting CardinalityMap + /// type for the algorithm. + template + struct SetCardinalityMap + : public MaxCardinalitySearch > { + typedef MaxCardinalitySearch > Create; + }; + + template + struct DefProcessedMapTraits : public Traits { + typedef T ProcessedMap; + static ProcessedMap *createProcessedMap(const Digraph &) { + LEMON_ASSERT(false,"Uninitialized parameter."); + return 0; + } + }; + /// \brief \ref named-templ-param "Named parameter" for setting + /// ProcessedMap type + /// + /// \ref named-templ-param "Named parameter" for setting ProcessedMap type + /// for the algorithm. + template + struct SetProcessedMap + : public MaxCardinalitySearch > { + typedef MaxCardinalitySearch > Create; + }; + + template + struct DefHeapTraits : public Traits { + typedef CR HeapCrossRef; + typedef H Heap; + static HeapCrossRef *createHeapCrossRef(const Digraph &) { + LEMON_ASSERT(false,"Uninitialized parameter."); + return 0; + } + static Heap *createHeap(HeapCrossRef &) { + LEMON_ASSERT(false,"Uninitialized parameter."); + return 0; + } + }; + /// \brief \ref named-templ-param "Named parameter" for setting heap + /// and cross reference type + /// + /// \ref named-templ-param "Named parameter" for setting heap and cross + /// reference type for the algorithm. + template > + struct SetHeap + : public MaxCardinalitySearch > { + typedef MaxCardinalitySearch< Digraph, CapacityMap, + DefHeapTraits > Create; + }; + + template + struct DefStandardHeapTraits : public Traits { + typedef CR HeapCrossRef; + typedef H Heap; + static HeapCrossRef *createHeapCrossRef(const Digraph &digraph) { + return new HeapCrossRef(digraph); + } + static Heap *createHeap(HeapCrossRef &crossref) { + return new Heap(crossref); + } + }; + + /// \brief \ref named-templ-param "Named parameter" for setting heap and + /// cross reference type with automatic allocation + /// + /// \ref named-templ-param "Named parameter" for setting heap and cross + /// reference type. It can allocate the heap and the cross reference + /// object if the cross reference's constructor waits for the digraph as + /// parameter and the heap's constructor waits for the cross reference. + template > + struct SetStandardHeap + : public MaxCardinalitySearch > { + typedef MaxCardinalitySearch > + Create; + }; + + ///@} + + + protected: + + MaxCardinalitySearch() {} + + public: + + /// \brief Constructor. + /// + ///\param digraph the digraph the algorithm will run on. + ///\param capacity the capacity map used by the algorithm. + MaxCardinalitySearch(const Digraph& digraph, + const CapacityMap& capacity) : + _graph(&digraph), + _capacity(&capacity), local_capacity(false), + _cardinality(0), local_cardinality(false), + _processed(0), local_processed(false), + _heap_cross_ref(0), local_heap_cross_ref(false), + _heap(0), local_heap(false) + { } + + /// \brief Constructor. + /// + ///\param digraph the digraph the algorithm will run on. + /// + ///A constant 1 capacity map will be allocated. + MaxCardinalitySearch(const Digraph& digraph) : + _graph(&digraph), + _capacity(0), local_capacity(false), + _cardinality(0), local_cardinality(false), + _processed(0), local_processed(false), + _heap_cross_ref(0), local_heap_cross_ref(false), + _heap(0), local_heap(false) + { } + + /// \brief Destructor. + ~MaxCardinalitySearch() { + if(local_capacity) delete _capacity; + if(local_cardinality) delete _cardinality; + if(local_processed) delete _processed; + if(local_heap_cross_ref) delete _heap_cross_ref; + if(local_heap) delete _heap; + } + + /// \brief Sets the capacity map. + /// + /// Sets the capacity map. + /// \return (*this) + MaxCardinalitySearch &capacityMap(const CapacityMap &m) { + if (local_capacity) { + delete _capacity; + local_capacity=false; + } + _capacity=&m; + return *this; + } + + /// \brief Returns a const reference to the capacity map. + /// + /// Returns a const reference to the capacity map used by + /// the algorithm. + const CapacityMap &capacityMap() const { + return *_capacity; + } + + /// \brief Sets the map storing the cardinalities calculated by the + /// algorithm. + /// + /// Sets the map storing the cardinalities calculated by the algorithm. + /// If you don't use this function before calling \ref run(), + /// it will allocate one. The destuctor deallocates this + /// automatically allocated map, of course. + /// \return (*this) + MaxCardinalitySearch &cardinalityMap(CardinalityMap &m) { + if(local_cardinality) { + delete _cardinality; + local_cardinality=false; + } + _cardinality = &m; + return *this; + } + + /// \brief Sets the map storing the processed nodes. + /// + /// Sets the map storing the processed nodes. + /// If you don't use this function before calling \ref run(), + /// it will allocate one. The destuctor deallocates this + /// automatically allocated map, of course. + /// \return (*this) + MaxCardinalitySearch &processedMap(ProcessedMap &m) + { + if(local_processed) { + delete _processed; + local_processed=false; + } + _processed = &m; + return *this; + } + + /// \brief Returns a const reference to the cardinality map. + /// + /// Returns a const reference to the cardinality map used by + /// the algorithm. + const ProcessedMap &processedMap() const { + return *_processed; + } + + /// \brief Sets the heap and the cross reference used by algorithm. + /// + /// Sets the heap and the cross reference used by algorithm. + /// If you don't use this function before calling \ref run(), + /// it will allocate one. The destuctor deallocates this + /// automatically allocated map, of course. + /// \return (*this) + MaxCardinalitySearch &heap(Heap& hp, HeapCrossRef &cr) { + if(local_heap_cross_ref) { + delete _heap_cross_ref; + local_heap_cross_ref = false; + } + _heap_cross_ref = &cr; + if(local_heap) { + delete _heap; + local_heap = false; + } + _heap = &hp; + return *this; + } + + /// \brief Returns a const reference to the heap. + /// + /// Returns a const reference to the heap used by + /// the algorithm. + const Heap &heap() const { + return *_heap; + } + + /// \brief Returns a const reference to the cross reference. + /// + /// Returns a const reference to the cross reference + /// of the heap. + const HeapCrossRef &heapCrossRef() const { + return *_heap_cross_ref; + } + + private: + + typedef typename Digraph::Node Node; + typedef typename Digraph::NodeIt NodeIt; + typedef typename Digraph::Arc Arc; + typedef typename Digraph::InArcIt InArcIt; + + void create_maps() { + if(!_capacity) { + local_capacity = true; + _capacity = Traits::createCapacityMap(*_graph); + } + if(!_cardinality) { + local_cardinality = true; + _cardinality = Traits::createCardinalityMap(*_graph); + } + if(!_processed) { + local_processed = true; + _processed = Traits::createProcessedMap(*_graph); + } + if (!_heap_cross_ref) { + local_heap_cross_ref = true; + _heap_cross_ref = Traits::createHeapCrossRef(*_graph); + } + if (!_heap) { + local_heap = true; + _heap = Traits::createHeap(*_heap_cross_ref); + } + } + + void finalizeNodeData(Node node, Value capacity) { + _processed->set(node, true); + _cardinality->set(node, capacity); + } + + public: + /// \name Execution control + /// The simplest way to execute the algorithm is to use + /// one of the member functions called \ref run(). + /// \n + /// If you need more control on the execution, + /// first you must call \ref init(), then you can add several source nodes + /// with \ref addSource(). + /// Finally \ref start() will perform the computation. + + ///@{ + + /// \brief Initializes the internal data structures. + /// + /// Initializes the internal data structures, and clears the heap. + void init() { + create_maps(); + _heap->clear(); + for (NodeIt it(*_graph) ; it != INVALID ; ++it) { + _processed->set(it, false); + _heap_cross_ref->set(it, Heap::PRE_HEAP); + } + } + + /// \brief Adds a new source node. + /// + /// Adds a new source node to the priority heap. + /// + /// It checks if the node has not yet been added to the heap. + void addSource(Node source, Value capacity = 0) { + if(_heap->state(source) == Heap::PRE_HEAP) { + _heap->push(source, capacity); + } + } + + /// \brief Processes the next node in the priority heap + /// + /// Processes the next node in the priority heap. + /// + /// \return The processed node. + /// + /// \warning The priority heap must not be empty! + Node processNextNode() { + Node node = _heap->top(); + finalizeNodeData(node, _heap->prio()); + _heap->pop(); + + for (InArcIt it(*_graph, node); it != INVALID; ++it) { + Node source = _graph->source(it); + switch (_heap->state(source)) { + case Heap::PRE_HEAP: + _heap->push(source, (*_capacity)[it]); + break; + case Heap::IN_HEAP: + _heap->decrease(source, (*_heap)[source] + (*_capacity)[it]); + break; + case Heap::POST_HEAP: + break; + } + } + return node; + } + + /// \brief Next node to be processed. + /// + /// Next node to be processed. + /// + /// \return The next node to be processed or INVALID if the + /// priority heap is empty. + Node nextNode() { + return !_heap->empty() ? _heap->top() : INVALID; + } + + /// \brief Returns \c false if there are nodes + /// to be processed in the priority heap + /// + /// Returns \c false if there are nodes + /// to be processed in the priority heap + bool emptyQueue() { return _heap->empty(); } + /// \brief Returns the number of the nodes to be processed + /// in the priority heap + /// + /// Returns the number of the nodes to be processed in the priority heap + int emptySize() { return _heap->size(); } + + /// \brief Executes the algorithm. + /// + /// Executes the algorithm. + /// + ///\pre init() must be called and at least one node should be added + /// with addSource() before using this function. + /// + /// This method runs the Maximum Cardinality Search algorithm from the + /// source node(s). + void start() { + while ( !_heap->empty() ) processNextNode(); + } + + /// \brief Executes the algorithm until \c dest is reached. + /// + /// Executes the algorithm until \c dest is reached. + /// + /// \pre init() must be called and at least one node should be added + /// with addSource() before using this function. + /// + /// This method runs the %MaxCardinalitySearch algorithm from the source + /// nodes. + void start(Node dest) { + while ( !_heap->empty() && _heap->top()!=dest ) processNextNode(); + if ( !_heap->empty() ) finalizeNodeData(_heap->top(), _heap->prio()); + } + + /// \brief Executes the algorithm until a condition is met. + /// + /// Executes the algorithm until a condition is met. + /// + /// \pre init() must be called and at least one node should be added + /// with addSource() before using this function. + /// + /// \param nm must be a bool (or convertible) node map. The algorithm + /// will stop when it reaches a node \c v with nm[v]==true. + template + void start(const NodeBoolMap &nm) { + while ( !_heap->empty() && !nm[_heap->top()] ) processNextNode(); + if ( !_heap->empty() ) finalizeNodeData(_heap->top(),_heap->prio()); + } + + /// \brief Runs the maximum cardinality search algorithm from node \c s. + /// + /// This method runs the %MaxCardinalitySearch algorithm from a root + /// node \c s. + /// + ///\note d.run(s) is just a shortcut of the following code. + ///\code + /// d.init(); + /// d.addSource(s); + /// d.start(); + ///\endcode + void run(Node s) { + init(); + addSource(s); + start(); + } + + /// \brief Runs the maximum cardinality search algorithm for the + /// whole digraph. + /// + /// This method runs the %MaxCardinalitySearch algorithm from all + /// unprocessed node of the digraph. + /// + ///\note d.run(s) is just a shortcut of the following code. + ///\code + /// d.init(); + /// for (NodeIt it(digraph); it != INVALID; ++it) { + /// if (!d.reached(it)) { + /// d.addSource(s); + /// d.start(); + /// } + /// } + ///\endcode + void run() { + init(); + for (NodeIt it(*_graph); it != INVALID; ++it) { + if (!reached(it)) { + addSource(it); + start(); + } + } + } + + ///@} + + /// \name Query Functions + /// The results of the maximum cardinality search algorithm can be + /// obtained using these functions. + /// \n + /// Before the use of these functions, either run() or start() must be + /// called. + + ///@{ + + /// \brief The cardinality of a node. + /// + /// Returns the cardinality of a node. + /// \pre \ref run() must be called before using this function. + /// \warning If node \c v in unreachable from the root the return value + /// of this funcion is undefined. + Value cardinality(Node node) const { return (*_cardinality)[node]; } + + /// \brief The current cardinality of a node. + /// + /// Returns the current cardinality of a node. + /// \pre the given node should be reached but not processed + Value currentCardinality(Node node) const { return (*_heap)[node]; } + + /// \brief Returns a reference to the NodeMap of cardinalities. + /// + /// Returns a reference to the NodeMap of cardinalities. \pre \ref run() + /// must be called before using this function. + const CardinalityMap &cardinalityMap() const { return *_cardinality;} + + /// \brief Checks if a node is reachable from the root. + /// + /// Returns \c true if \c v is reachable from the root. + /// \warning The source nodes are initated as unreached. + /// \pre \ref run() must be called before using this function. + bool reached(Node v) { return (*_heap_cross_ref)[v] != Heap::PRE_HEAP; } + + /// \brief Checks if a node is processed. + /// + /// Returns \c true if \c v is processed, i.e. the shortest + /// path to \c v has already found. + /// \pre \ref run() must be called before using this function. + bool processed(Node v) { return (*_heap_cross_ref)[v] == Heap::POST_HEAP; } + + ///@} + }; + +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/min_cost_arborescence.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/min_cost_arborescence.h new file mode 100644 index 00000000000..1d0a2b19d81 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/min_cost_arborescence.h @@ -0,0 +1,808 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_MIN_COST_ARBORESCENCE_H +#define LEMON_MIN_COST_ARBORESCENCE_H + +///\ingroup spantree +///\file +///\brief Minimum Cost Arborescence algorithm. + +#include + +#include +#include +#include + +namespace lemon { + + + /// \brief Default traits class for MinCostArborescence class. + /// + /// Default traits class for MinCostArborescence class. + /// \param GR Digraph type. + /// \param CM Type of the cost map. + template + struct MinCostArborescenceDefaultTraits{ + + /// \brief The digraph type the algorithm runs on. + typedef GR Digraph; + + /// \brief The type of the map that stores the arc costs. + /// + /// The type of the map that stores the arc costs. + /// It must conform to the \ref concepts::ReadMap "ReadMap" concept. + typedef CM CostMap; + + /// \brief The value type of the costs. + /// + /// The value type of the costs. + typedef typename CostMap::Value Value; + + /// \brief The type of the map that stores which arcs are in the + /// arborescence. + /// + /// The type of the map that stores which arcs are in the + /// arborescence. It must conform to the \ref concepts::WriteMap + /// "WriteMap" concept, and its value type must be \c bool + /// (or convertible). Initially it will be set to \c false on each + /// arc, then it will be set on each arborescence arc once. + typedef typename Digraph::template ArcMap ArborescenceMap; + + /// \brief Instantiates a \c ArborescenceMap. + /// + /// This function instantiates a \c ArborescenceMap. + /// \param digraph The digraph to which we would like to calculate + /// the \c ArborescenceMap. + static ArborescenceMap *createArborescenceMap(const Digraph &digraph){ + return new ArborescenceMap(digraph); + } + + /// \brief The type of the \c PredMap + /// + /// The type of the \c PredMap. It must confrom to the + /// \ref concepts::WriteMap "WriteMap" concept, and its value type + /// must be the \c Arc type of the digraph. + typedef typename Digraph::template NodeMap PredMap; + + /// \brief Instantiates a \c PredMap. + /// + /// This function instantiates a \c PredMap. + /// \param digraph The digraph to which we would like to define the + /// \c PredMap. + static PredMap *createPredMap(const Digraph &digraph){ + return new PredMap(digraph); + } + + }; + + /// \ingroup spantree + /// + /// \brief Minimum Cost Arborescence algorithm class. + /// + /// This class provides an efficient implementation of the + /// Minimum Cost Arborescence algorithm. The arborescence is a tree + /// which is directed from a given source node of the digraph. One or + /// more sources should be given to the algorithm and it will calculate + /// the minimum cost subgraph that is the union of arborescences with the + /// given sources and spans all the nodes which are reachable from the + /// sources. The time complexity of the algorithm is O(n2+m). + /// + /// The algorithm also provides an optimal dual solution, therefore + /// the optimality of the solution can be checked. + /// + /// \param GR The digraph type the algorithm runs on. + /// \param CM A read-only arc map storing the costs of the + /// arcs. It is read once for each arc, so the map may involve in + /// relatively time consuming process to compute the arc costs if + /// it is necessary. The default map type is \ref + /// concepts::Digraph::ArcMap "Digraph::ArcMap". + /// \tparam TR The traits class that defines various types used by the + /// algorithm. By default, it is \ref MinCostArborescenceDefaultTraits + /// "MinCostArborescenceDefaultTraits". + /// In most cases, this parameter should not be set directly, + /// consider to use the named template parameters instead. +#ifndef DOXYGEN + template , + typename TR = + MinCostArborescenceDefaultTraits > +#else + template +#endif + class MinCostArborescence { + public: + + /// \brief The \ref lemon::MinCostArborescenceDefaultTraits "traits class" + /// of the algorithm. + typedef TR Traits; + /// The type of the underlying digraph. + typedef typename Traits::Digraph Digraph; + /// The type of the map that stores the arc costs. + typedef typename Traits::CostMap CostMap; + ///The type of the costs of the arcs. + typedef typename Traits::Value Value; + ///The type of the predecessor map. + typedef typename Traits::PredMap PredMap; + ///The type of the map that stores which arcs are in the arborescence. + typedef typename Traits::ArborescenceMap ArborescenceMap; + + typedef MinCostArborescence Create; + + private: + + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + + struct CostArc { + + Arc arc; + Value value; + + CostArc() {} + CostArc(Arc _arc, Value _value) : arc(_arc), value(_value) {} + + }; + + const Digraph *_digraph; + const CostMap *_cost; + + PredMap *_pred; + bool local_pred; + + ArborescenceMap *_arborescence; + bool local_arborescence; + + typedef typename Digraph::template ArcMap ArcOrder; + ArcOrder *_arc_order; + + typedef typename Digraph::template NodeMap NodeOrder; + NodeOrder *_node_order; + + typedef typename Digraph::template NodeMap CostArcMap; + CostArcMap *_cost_arcs; + + struct StackLevel { + + std::vector arcs; + int node_level; + + }; + + std::vector level_stack; + std::vector queue; + + typedef std::vector DualNodeList; + + DualNodeList _dual_node_list; + + struct DualVariable { + int begin, end; + Value value; + + DualVariable(int _begin, int _end, Value _value) + : begin(_begin), end(_end), value(_value) {} + + }; + + typedef std::vector DualVariables; + + DualVariables _dual_variables; + + typedef typename Digraph::template NodeMap HeapCrossRef; + + HeapCrossRef *_heap_cross_ref; + + typedef BinHeap Heap; + + Heap *_heap; + + protected: + + MinCostArborescence() {} + + private: + + void createStructures() { + if (!_pred) { + local_pred = true; + _pred = Traits::createPredMap(*_digraph); + } + if (!_arborescence) { + local_arborescence = true; + _arborescence = Traits::createArborescenceMap(*_digraph); + } + if (!_arc_order) { + _arc_order = new ArcOrder(*_digraph); + } + if (!_node_order) { + _node_order = new NodeOrder(*_digraph); + } + if (!_cost_arcs) { + _cost_arcs = new CostArcMap(*_digraph); + } + if (!_heap_cross_ref) { + _heap_cross_ref = new HeapCrossRef(*_digraph, -1); + } + if (!_heap) { + _heap = new Heap(*_heap_cross_ref); + } + } + + void destroyStructures() { + if (local_arborescence) { + delete _arborescence; + } + if (local_pred) { + delete _pred; + } + if (_arc_order) { + delete _arc_order; + } + if (_node_order) { + delete _node_order; + } + if (_cost_arcs) { + delete _cost_arcs; + } + if (_heap) { + delete _heap; + } + if (_heap_cross_ref) { + delete _heap_cross_ref; + } + } + + Arc prepare(Node node) { + std::vector nodes; + (*_node_order)[node] = _dual_node_list.size(); + StackLevel level; + level.node_level = _dual_node_list.size(); + _dual_node_list.push_back(node); + for (InArcIt it(*_digraph, node); it != INVALID; ++it) { + Arc arc = it; + Node source = _digraph->source(arc); + Value value = (*_cost)[it]; + if (source == node || (*_node_order)[source] == -3) continue; + if ((*_cost_arcs)[source].arc == INVALID) { + (*_cost_arcs)[source].arc = arc; + (*_cost_arcs)[source].value = value; + nodes.push_back(source); + } else { + if ((*_cost_arcs)[source].value > value) { + (*_cost_arcs)[source].arc = arc; + (*_cost_arcs)[source].value = value; + } + } + } + CostArc minimum = (*_cost_arcs)[nodes[0]]; + for (int i = 1; i < int(nodes.size()); ++i) { + if ((*_cost_arcs)[nodes[i]].value < minimum.value) { + minimum = (*_cost_arcs)[nodes[i]]; + } + } + (*_arc_order)[minimum.arc] = _dual_variables.size(); + DualVariable var(_dual_node_list.size() - 1, + _dual_node_list.size(), minimum.value); + _dual_variables.push_back(var); + for (int i = 0; i < int(nodes.size()); ++i) { + (*_cost_arcs)[nodes[i]].value -= minimum.value; + level.arcs.push_back((*_cost_arcs)[nodes[i]]); + (*_cost_arcs)[nodes[i]].arc = INVALID; + } + level_stack.push_back(level); + return minimum.arc; + } + + Arc contract(Node node) { + int node_bottom = bottom(node); + std::vector nodes; + while (!level_stack.empty() && + level_stack.back().node_level >= node_bottom) { + for (int i = 0; i < int(level_stack.back().arcs.size()); ++i) { + Arc arc = level_stack.back().arcs[i].arc; + Node source = _digraph->source(arc); + Value value = level_stack.back().arcs[i].value; + if ((*_node_order)[source] >= node_bottom) continue; + if ((*_cost_arcs)[source].arc == INVALID) { + (*_cost_arcs)[source].arc = arc; + (*_cost_arcs)[source].value = value; + nodes.push_back(source); + } else { + if ((*_cost_arcs)[source].value > value) { + (*_cost_arcs)[source].arc = arc; + (*_cost_arcs)[source].value = value; + } + } + } + level_stack.pop_back(); + } + CostArc minimum = (*_cost_arcs)[nodes[0]]; + for (int i = 1; i < int(nodes.size()); ++i) { + if ((*_cost_arcs)[nodes[i]].value < minimum.value) { + minimum = (*_cost_arcs)[nodes[i]]; + } + } + (*_arc_order)[minimum.arc] = _dual_variables.size(); + DualVariable var(node_bottom, _dual_node_list.size(), minimum.value); + _dual_variables.push_back(var); + StackLevel level; + level.node_level = node_bottom; + for (int i = 0; i < int(nodes.size()); ++i) { + (*_cost_arcs)[nodes[i]].value -= minimum.value; + level.arcs.push_back((*_cost_arcs)[nodes[i]]); + (*_cost_arcs)[nodes[i]].arc = INVALID; + } + level_stack.push_back(level); + return minimum.arc; + } + + int bottom(Node node) { + int k = level_stack.size() - 1; + while (level_stack[k].node_level > (*_node_order)[node]) { + --k; + } + return level_stack[k].node_level; + } + + void finalize(Arc arc) { + Node node = _digraph->target(arc); + _heap->push(node, (*_arc_order)[arc]); + _pred->set(node, arc); + while (!_heap->empty()) { + Node source = _heap->top(); + _heap->pop(); + (*_node_order)[source] = -1; + for (OutArcIt it(*_digraph, source); it != INVALID; ++it) { + if ((*_arc_order)[it] < 0) continue; + Node target = _digraph->target(it); + switch(_heap->state(target)) { + case Heap::PRE_HEAP: + _heap->push(target, (*_arc_order)[it]); + _pred->set(target, it); + break; + case Heap::IN_HEAP: + if ((*_arc_order)[it] < (*_heap)[target]) { + _heap->decrease(target, (*_arc_order)[it]); + _pred->set(target, it); + } + break; + case Heap::POST_HEAP: + break; + } + } + _arborescence->set((*_pred)[source], true); + } + } + + + public: + + /// \name Named Template Parameters + + /// @{ + + template + struct SetArborescenceMapTraits : public Traits { + typedef T ArborescenceMap; + static ArborescenceMap *createArborescenceMap(const Digraph &) + { + LEMON_ASSERT(false, "ArborescenceMap is not initialized"); + return 0; // ignore warnings + } + }; + + /// \brief \ref named-templ-param "Named parameter" for + /// setting \c ArborescenceMap type + /// + /// \ref named-templ-param "Named parameter" for setting + /// \c ArborescenceMap type. + /// It must conform to the \ref concepts::WriteMap "WriteMap" concept, + /// and its value type must be \c bool (or convertible). + /// Initially it will be set to \c false on each arc, + /// then it will be set on each arborescence arc once. + template + struct SetArborescenceMap + : public MinCostArborescence > { + }; + + template + struct SetPredMapTraits : public Traits { + typedef T PredMap; + static PredMap *createPredMap(const Digraph &) + { + LEMON_ASSERT(false, "PredMap is not initialized"); + return 0; // ignore warnings + } + }; + + /// \brief \ref named-templ-param "Named parameter" for + /// setting \c PredMap type + /// + /// \ref named-templ-param "Named parameter" for setting + /// \c PredMap type. + /// It must meet the \ref concepts::WriteMap "WriteMap" concept, + /// and its value type must be the \c Arc type of the digraph. + template + struct SetPredMap + : public MinCostArborescence > { + }; + + /// @} + + /// \brief Constructor. + /// + /// \param digraph The digraph the algorithm will run on. + /// \param cost The cost map used by the algorithm. + MinCostArborescence(const Digraph& digraph, const CostMap& cost) + : _digraph(&digraph), _cost(&cost), _pred(0), local_pred(false), + _arborescence(0), local_arborescence(false), + _arc_order(0), _node_order(0), _cost_arcs(0), + _heap_cross_ref(0), _heap(0) {} + + /// \brief Destructor. + ~MinCostArborescence() { + destroyStructures(); + } + + /// \brief Sets the arborescence map. + /// + /// Sets the arborescence map. + /// \return (*this) + MinCostArborescence& arborescenceMap(ArborescenceMap& m) { + if (local_arborescence) { + delete _arborescence; + } + local_arborescence = false; + _arborescence = &m; + return *this; + } + + /// \brief Sets the predecessor map. + /// + /// Sets the predecessor map. + /// \return (*this) + MinCostArborescence& predMap(PredMap& m) { + if (local_pred) { + delete _pred; + } + local_pred = false; + _pred = &m; + return *this; + } + + /// \name Execution Control + /// The simplest way to execute the algorithm is to use + /// one of the member functions called \c run(...). \n + /// If you need better control on the execution, + /// you have to call \ref init() first, then you can add several + /// source nodes with \ref addSource(). + /// Finally \ref start() will perform the arborescence + /// computation. + + ///@{ + + /// \brief Initializes the internal data structures. + /// + /// Initializes the internal data structures. + /// + void init() { + createStructures(); + _heap->clear(); + for (NodeIt it(*_digraph); it != INVALID; ++it) { + (*_cost_arcs)[it].arc = INVALID; + (*_node_order)[it] = -3; + (*_heap_cross_ref)[it] = Heap::PRE_HEAP; + _pred->set(it, INVALID); + } + for (ArcIt it(*_digraph); it != INVALID; ++it) { + _arborescence->set(it, false); + (*_arc_order)[it] = -1; + } + _dual_node_list.clear(); + _dual_variables.clear(); + } + + /// \brief Adds a new source node. + /// + /// Adds a new source node to the algorithm. + void addSource(Node source) { + std::vector nodes; + nodes.push_back(source); + while (!nodes.empty()) { + Node node = nodes.back(); + nodes.pop_back(); + for (OutArcIt it(*_digraph, node); it != INVALID; ++it) { + Node target = _digraph->target(it); + if ((*_node_order)[target] == -3) { + (*_node_order)[target] = -2; + nodes.push_back(target); + queue.push_back(target); + } + } + } + (*_node_order)[source] = -1; + } + + /// \brief Processes the next node in the priority queue. + /// + /// Processes the next node in the priority queue. + /// + /// \return The processed node. + /// + /// \warning The queue must not be empty. + Node processNextNode() { + Node node = queue.back(); + queue.pop_back(); + if ((*_node_order)[node] == -2) { + Arc arc = prepare(node); + Node source = _digraph->source(arc); + while ((*_node_order)[source] != -1) { + if ((*_node_order)[source] >= 0) { + arc = contract(source); + } else { + arc = prepare(source); + } + source = _digraph->source(arc); + } + finalize(arc); + level_stack.clear(); + } + return node; + } + + /// \brief Returns the number of the nodes to be processed. + /// + /// Returns the number of the nodes to be processed in the priority + /// queue. + int queueSize() const { + return queue.size(); + } + + /// \brief Returns \c false if there are nodes to be processed. + /// + /// Returns \c false if there are nodes to be processed. + bool emptyQueue() const { + return queue.empty(); + } + + /// \brief Executes the algorithm. + /// + /// Executes the algorithm. + /// + /// \pre init() must be called and at least one node should be added + /// with addSource() before using this function. + /// + ///\note mca.start() is just a shortcut of the following code. + ///\code + ///while (!mca.emptyQueue()) { + /// mca.processNextNode(); + ///} + ///\endcode + void start() { + while (!emptyQueue()) { + processNextNode(); + } + } + + /// \brief Runs %MinCostArborescence algorithm from node \c s. + /// + /// This method runs the %MinCostArborescence algorithm from + /// a root node \c s. + /// + /// \note mca.run(s) is just a shortcut of the following code. + /// \code + /// mca.init(); + /// mca.addSource(s); + /// mca.start(); + /// \endcode + void run(Node s) { + init(); + addSource(s); + start(); + } + + ///@} + + /// \name Query Functions + /// The result of the %MinCostArborescence algorithm can be obtained + /// using these functions.\n + /// Either run() or start() must be called before using them. + + /// @{ + + /// \brief Returns the cost of the arborescence. + /// + /// Returns the cost of the arborescence. + Value arborescenceCost() const { + Value sum = 0; + for (ArcIt it(*_digraph); it != INVALID; ++it) { + if (arborescence(it)) { + sum += (*_cost)[it]; + } + } + return sum; + } + + /// \brief Returns \c true if the arc is in the arborescence. + /// + /// Returns \c true if the given arc is in the arborescence. + /// \param arc An arc of the digraph. + /// \pre \ref run() must be called before using this function. + bool arborescence(Arc arc) const { + return (*_pred)[_digraph->target(arc)] == arc; + } + + /// \brief Returns a const reference to the arborescence map. + /// + /// Returns a const reference to the arborescence map. + /// \pre \ref run() must be called before using this function. + const ArborescenceMap& arborescenceMap() const { + return *_arborescence; + } + + /// \brief Returns the predecessor arc of the given node. + /// + /// Returns the predecessor arc of the given node. + /// \pre \ref run() must be called before using this function. + Arc pred(Node node) const { + return (*_pred)[node]; + } + + /// \brief Returns a const reference to the pred map. + /// + /// Returns a const reference to the pred map. + /// \pre \ref run() must be called before using this function. + const PredMap& predMap() const { + return *_pred; + } + + /// \brief Indicates that a node is reachable from the sources. + /// + /// Indicates that a node is reachable from the sources. + bool reached(Node node) const { + return (*_node_order)[node] != -3; + } + + /// \brief Indicates that a node is processed. + /// + /// Indicates that a node is processed. The arborescence path exists + /// from the source to the given node. + bool processed(Node node) const { + return (*_node_order)[node] == -1; + } + + /// \brief Returns the number of the dual variables in basis. + /// + /// Returns the number of the dual variables in basis. + int dualNum() const { + return _dual_variables.size(); + } + + /// \brief Returns the value of the dual solution. + /// + /// Returns the value of the dual solution. It should be + /// equal to the arborescence value. + Value dualValue() const { + Value sum = 0; + for (int i = 0; i < int(_dual_variables.size()); ++i) { + sum += _dual_variables[i].value; + } + return sum; + } + + /// \brief Returns the number of the nodes in the dual variable. + /// + /// Returns the number of the nodes in the dual variable. + int dualSize(int k) const { + return _dual_variables[k].end - _dual_variables[k].begin; + } + + /// \brief Returns the value of the dual variable. + /// + /// Returns the the value of the dual variable. + Value dualValue(int k) const { + return _dual_variables[k].value; + } + + /// \brief LEMON iterator for getting a dual variable. + /// + /// This class provides a common style LEMON iterator for getting a + /// dual variable of \ref MinCostArborescence algorithm. + /// It iterates over a subset of the nodes. + class DualIt { + public: + + /// \brief Constructor. + /// + /// Constructor for getting the nodeset of the dual variable + /// of \ref MinCostArborescence algorithm. + DualIt(const MinCostArborescence& algorithm, int variable) + : _algorithm(&algorithm) + { + _index = _algorithm->_dual_variables[variable].begin; + _last = _algorithm->_dual_variables[variable].end; + } + + /// \brief Conversion to \c Node. + /// + /// Conversion to \c Node. + operator Node() const { + return _algorithm->_dual_node_list[_index]; + } + + /// \brief Increment operator. + /// + /// Increment operator. + DualIt& operator++() { + ++_index; + return *this; + } + + /// \brief Validity checking + /// + /// Checks whether the iterator is invalid. + bool operator==(Invalid) const { + return _index == _last; + } + + /// \brief Validity checking + /// + /// Checks whether the iterator is valid. + bool operator!=(Invalid) const { + return _index != _last; + } + + private: + const MinCostArborescence* _algorithm; + int _index, _last; + }; + + /// @} + + }; + + /// \ingroup spantree + /// + /// \brief Function type interface for MinCostArborescence algorithm. + /// + /// Function type interface for MinCostArborescence algorithm. + /// \param digraph The digraph the algorithm runs on. + /// \param cost An arc map storing the costs. + /// \param source The source node of the arborescence. + /// \retval arborescence An arc map with \c bool (or convertible) value + /// type that stores the arborescence. + /// \return The total cost of the arborescence. + /// + /// \sa MinCostArborescence + template + typename CostMap::Value minCostArborescence(const Digraph& digraph, + const CostMap& cost, + typename Digraph::Node source, + ArborescenceMap& arborescence) { + typename MinCostArborescence + ::template SetArborescenceMap + ::Create mca(digraph, cost); + mca.arborescenceMap(arborescence); + mca.run(source); + return mca.arborescenceCost(); + } + +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/nagamochi_ibaraki.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/nagamochi_ibaraki.h new file mode 100644 index 00000000000..57a6ba64d2b --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/nagamochi_ibaraki.h @@ -0,0 +1,702 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_NAGAMOCHI_IBARAKI_H +#define LEMON_NAGAMOCHI_IBARAKI_H + + +/// \ingroup min_cut +/// \file +/// \brief Implementation of the Nagamochi-Ibaraki algorithm. + +#include +#include +#include +#include +#include +#include + +#include + +namespace lemon { + + /// \brief Default traits class for NagamochiIbaraki class. + /// + /// Default traits class for NagamochiIbaraki class. + /// \param GR The undirected graph type. + /// \param CM Type of capacity map. + template + struct NagamochiIbarakiDefaultTraits { + /// The type of the capacity map. + typedef typename CM::Value Value; + + /// The undirected graph type the algorithm runs on. + typedef GR Graph; + + /// \brief The type of the map that stores the edge capacities. + /// + /// The type of the map that stores the edge capacities. + /// It must meet the \ref concepts::ReadMap "ReadMap" concept. + typedef CM CapacityMap; + + /// \brief Instantiates a CapacityMap. + /// + /// This function instantiates a \ref CapacityMap. +#ifdef DOXYGEN + static CapacityMap *createCapacityMap(const Graph& graph) +#else + static CapacityMap *createCapacityMap(const Graph&) +#endif + { + LEMON_ASSERT(false, "CapacityMap is not initialized"); + return 0; // ignore warnings + } + + /// \brief The cross reference type used by heap. + /// + /// The cross reference type used by heap. + /// Usually \c Graph::NodeMap. + typedef typename Graph::template NodeMap HeapCrossRef; + + /// \brief Instantiates a HeapCrossRef. + /// + /// This function instantiates a \ref HeapCrossRef. + /// \param g is the graph, to which we would like to define the + /// \ref HeapCrossRef. + static HeapCrossRef *createHeapCrossRef(const Graph& g) { + return new HeapCrossRef(g); + } + + /// \brief The heap type used by NagamochiIbaraki algorithm. + /// + /// The heap type used by NagamochiIbaraki algorithm. It has to + /// maximize the priorities. + /// + /// \sa BinHeap + /// \sa NagamochiIbaraki + typedef BinHeap > Heap; + + /// \brief Instantiates a Heap. + /// + /// This function instantiates a \ref Heap. + /// \param r is the cross reference of the heap. + static Heap *createHeap(HeapCrossRef& r) { + return new Heap(r); + } + }; + + /// \ingroup min_cut + /// + /// \brief Calculates the minimum cut in an undirected graph. + /// + /// Calculates the minimum cut in an undirected graph with the + /// Nagamochi-Ibaraki algorithm. The algorithm separates the graph's + /// nodes into two partitions with the minimum sum of edge capacities + /// between the two partitions. The algorithm can be used to test + /// the network reliability, especially to test how many links have + /// to be destroyed in the network to split it to at least two + /// distinict subnetworks. + /// + /// The complexity of the algorithm is \f$ O(nm\log(n)) \f$ but with + /// \ref FibHeap "Fibonacci heap" it can be decreased to + /// \f$ O(nm+n^2\log(n)) \f$. When the edges have unit capacities, + /// \c BucketHeap can be used which yields \f$ O(nm) \f$ time + /// complexity. + /// + /// \warning The value type of the capacity map should be able to + /// hold any cut value of the graph, otherwise the result can + /// overflow. + /// \note This capacity is supposed to be integer type. +#ifdef DOXYGEN + template +#else + template , + typename TR = NagamochiIbarakiDefaultTraits > +#endif + class NagamochiIbaraki { + public: + + typedef TR Traits; + /// The type of the underlying graph. + typedef typename Traits::Graph Graph; + + /// The type of the capacity map. + typedef typename Traits::CapacityMap CapacityMap; + /// The value type of the capacity map. + typedef typename Traits::CapacityMap::Value Value; + + /// The heap type used by the algorithm. + typedef typename Traits::Heap Heap; + /// The cross reference type used for the heap. + typedef typename Traits::HeapCrossRef HeapCrossRef; + + ///\name Named template parameters + + ///@{ + + struct SetUnitCapacityTraits : public Traits { + typedef ConstMap > CapacityMap; + static CapacityMap *createCapacityMap(const Graph&) { + return new CapacityMap(); + } + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// the capacity map to a constMap() instance + /// + /// \ref named-templ-param "Named parameter" for setting + /// the capacity map to a constMap() instance + struct SetUnitCapacity + : public NagamochiIbaraki { + typedef NagamochiIbaraki Create; + }; + + + template + struct SetHeapTraits : public Traits { + typedef CR HeapCrossRef; + typedef H Heap; + static HeapCrossRef *createHeapCrossRef(int num) { + LEMON_ASSERT(false, "HeapCrossRef is not initialized"); + return 0; // ignore warnings + } + static Heap *createHeap(HeapCrossRef &) { + LEMON_ASSERT(false, "Heap is not initialized"); + return 0; // ignore warnings + } + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// heap and cross reference type + /// + /// \ref named-templ-param "Named parameter" for setting heap and + /// cross reference type. The heap has to maximize the priorities. + template > + struct SetHeap + : public NagamochiIbaraki > { + typedef NagamochiIbaraki< Graph, CapacityMap, SetHeapTraits > + Create; + }; + + template + struct SetStandardHeapTraits : public Traits { + typedef CR HeapCrossRef; + typedef H Heap; + static HeapCrossRef *createHeapCrossRef(int size) { + return new HeapCrossRef(size); + } + static Heap *createHeap(HeapCrossRef &crossref) { + return new Heap(crossref); + } + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// heap and cross reference type with automatic allocation + /// + /// \ref named-templ-param "Named parameter" for setting heap and + /// cross reference type with automatic allocation. They should + /// have standard constructor interfaces to be able to + /// automatically created by the algorithm (i.e. the graph should + /// be passed to the constructor of the cross reference and the + /// cross reference should be passed to the constructor of the + /// heap). However, external heap and cross reference objects + /// could also be passed to the algorithm using the \ref heap() + /// function before calling \ref run() or \ref init(). The heap + /// has to maximize the priorities. + /// \sa SetHeap + template > + struct SetStandardHeap + : public NagamochiIbaraki > { + typedef NagamochiIbaraki > Create; + }; + + ///@} + + + private: + + const Graph &_graph; + const CapacityMap *_capacity; + bool _local_capacity; // unit capacity + + struct ArcData { + typename Graph::Node target; + int prev, next; + }; + struct EdgeData { + Value capacity; + Value cut; + }; + + struct NodeData { + int first_arc; + typename Graph::Node prev, next; + int curr_arc; + typename Graph::Node last_rep; + Value sum; + }; + + typename Graph::template NodeMap *_nodes; + std::vector _arcs; + std::vector _edges; + + typename Graph::Node _first_node; + int _node_num; + + Value _min_cut; + + HeapCrossRef *_heap_cross_ref; + bool _local_heap_cross_ref; + Heap *_heap; + bool _local_heap; + + typedef typename Graph::template NodeMap NodeList; + NodeList *_next_rep; + + typedef typename Graph::template NodeMap MinCutMap; + MinCutMap *_cut_map; + + void createStructures() { + if (!_nodes) { + _nodes = new (typename Graph::template NodeMap)(_graph); + } + if (!_capacity) { + _local_capacity = true; + _capacity = Traits::createCapacityMap(_graph); + } + if (!_heap_cross_ref) { + _local_heap_cross_ref = true; + _heap_cross_ref = Traits::createHeapCrossRef(_graph); + } + if (!_heap) { + _local_heap = true; + _heap = Traits::createHeap(*_heap_cross_ref); + } + if (!_next_rep) { + _next_rep = new NodeList(_graph); + } + if (!_cut_map) { + _cut_map = new MinCutMap(_graph); + } + } + + protected: + //This is here to avoid a gcc-3.3 compilation error. + //It should never be called. + NagamochiIbaraki() {} + + public: + + typedef NagamochiIbaraki Create; + + + /// \brief Constructor. + /// + /// \param graph The graph the algorithm runs on. + /// \param capacity The capacity map used by the algorithm. + NagamochiIbaraki(const Graph& graph, const CapacityMap& capacity) + : _graph(graph), _capacity(&capacity), _local_capacity(false), + _nodes(0), _arcs(), _edges(), _min_cut(), + _heap_cross_ref(0), _local_heap_cross_ref(false), + _heap(0), _local_heap(false), + _next_rep(0), _cut_map(0) {} + + /// \brief Constructor. + /// + /// This constructor can be used only when the Traits class + /// defines how can the local capacity map be instantiated. + /// If the SetUnitCapacity used the algorithm automatically + /// constructs the capacity map. + /// + ///\param graph The graph the algorithm runs on. + NagamochiIbaraki(const Graph& graph) + : _graph(graph), _capacity(0), _local_capacity(false), + _nodes(0), _arcs(), _edges(), _min_cut(), + _heap_cross_ref(0), _local_heap_cross_ref(false), + _heap(0), _local_heap(false), + _next_rep(0), _cut_map(0) {} + + /// \brief Destructor. + /// + /// Destructor. + ~NagamochiIbaraki() { + if (_local_capacity) delete _capacity; + if (_nodes) delete _nodes; + if (_local_heap) delete _heap; + if (_local_heap_cross_ref) delete _heap_cross_ref; + if (_next_rep) delete _next_rep; + if (_cut_map) delete _cut_map; + } + + /// \brief Sets the heap and the cross reference used by algorithm. + /// + /// Sets the heap and the cross reference used by algorithm. + /// If you don't use this function before calling \ref run(), + /// it will allocate one. The destuctor deallocates this + /// automatically allocated heap and cross reference, of course. + /// \return (*this) + NagamochiIbaraki &heap(Heap& hp, HeapCrossRef &cr) + { + if (_local_heap_cross_ref) { + delete _heap_cross_ref; + _local_heap_cross_ref = false; + } + _heap_cross_ref = &cr; + if (_local_heap) { + delete _heap; + _local_heap = false; + } + _heap = &hp; + return *this; + } + + /// \name Execution control + /// The simplest way to execute the algorithm is to use + /// one of the member functions called \c run(). + /// \n + /// If you need more control on the execution, + /// first you must call \ref init() and then call the start() + /// or proper times the processNextPhase() member functions. + + ///@{ + + /// \brief Initializes the internal data structures. + /// + /// Initializes the internal data structures. + void init() { + createStructures(); + + int edge_num = countEdges(_graph); + _edges.resize(edge_num); + _arcs.resize(2 * edge_num); + + typename Graph::Node prev = INVALID; + _node_num = 0; + for (typename Graph::NodeIt n(_graph); n != INVALID; ++n) { + (*_cut_map)[n] = false; + (*_next_rep)[n] = INVALID; + (*_nodes)[n].last_rep = n; + (*_nodes)[n].first_arc = -1; + (*_nodes)[n].curr_arc = -1; + (*_nodes)[n].prev = prev; + if (prev != INVALID) { + (*_nodes)[prev].next = n; + } + (*_nodes)[n].next = INVALID; + (*_nodes)[n].sum = 0; + prev = n; + ++_node_num; + } + + _first_node = typename Graph::NodeIt(_graph); + + int index = 0; + for (typename Graph::NodeIt n(_graph); n != INVALID; ++n) { + for (typename Graph::OutArcIt a(_graph, n); a != INVALID; ++a) { + typename Graph::Node m = _graph.target(a); + + if (!(n < m)) continue; + + (*_nodes)[n].sum += (*_capacity)[a]; + (*_nodes)[m].sum += (*_capacity)[a]; + + int c = (*_nodes)[m].curr_arc; + if (c != -1 && _arcs[c ^ 1].target == n) { + _edges[c >> 1].capacity += (*_capacity)[a]; + } else { + _edges[index].capacity = (*_capacity)[a]; + + _arcs[index << 1].prev = -1; + if ((*_nodes)[n].first_arc != -1) { + _arcs[(*_nodes)[n].first_arc].prev = (index << 1); + } + _arcs[index << 1].next = (*_nodes)[n].first_arc; + (*_nodes)[n].first_arc = (index << 1); + _arcs[index << 1].target = m; + + (*_nodes)[m].curr_arc = (index << 1); + + _arcs[(index << 1) | 1].prev = -1; + if ((*_nodes)[m].first_arc != -1) { + _arcs[(*_nodes)[m].first_arc].prev = ((index << 1) | 1); + } + _arcs[(index << 1) | 1].next = (*_nodes)[m].first_arc; + (*_nodes)[m].first_arc = ((index << 1) | 1); + _arcs[(index << 1) | 1].target = n; + + ++index; + } + } + } + + typename Graph::Node cut_node = INVALID; + _min_cut = std::numeric_limits::max(); + + for (typename Graph::Node n = _first_node; + n != INVALID; n = (*_nodes)[n].next) { + if ((*_nodes)[n].sum < _min_cut) { + cut_node = n; + _min_cut = (*_nodes)[n].sum; + } + } + (*_cut_map)[cut_node] = true; + if (_min_cut == 0) { + _first_node = INVALID; + } + } + + public: + + /// \brief Processes the next phase + /// + /// Processes the next phase in the algorithm. It must be called + /// at most one less the number of the nodes in the graph. + /// + ///\return %True when the algorithm finished. + bool processNextPhase() { + if (_first_node == INVALID) return true; + + _heap->clear(); + for (typename Graph::Node n = _first_node; + n != INVALID; n = (*_nodes)[n].next) { + (*_heap_cross_ref)[n] = Heap::PRE_HEAP; + } + + std::vector order; + order.reserve(_node_num); + int sep = 0; + + Value alpha = 0; + Value pmc = std::numeric_limits::max(); + + _heap->push(_first_node, static_cast(0)); + while (!_heap->empty()) { + typename Graph::Node n = _heap->top(); + Value v = _heap->prio(); + + _heap->pop(); + for (int a = (*_nodes)[n].first_arc; a != -1; a = _arcs[a].next) { + switch (_heap->state(_arcs[a].target)) { + case Heap::PRE_HEAP: + { + Value nv = _edges[a >> 1].capacity; + _heap->push(_arcs[a].target, nv); + _edges[a >> 1].cut = nv; + } break; + case Heap::IN_HEAP: + { + Value nv = _edges[a >> 1].capacity + (*_heap)[_arcs[a].target]; + _heap->decrease(_arcs[a].target, nv); + _edges[a >> 1].cut = nv; + } break; + case Heap::POST_HEAP: + break; + } + } + + alpha += (*_nodes)[n].sum; + alpha -= 2 * v; + + order.push_back(n); + if (!_heap->empty()) { + if (alpha < pmc) { + pmc = alpha; + sep = order.size(); + } + } + } + + if (static_cast(order.size()) < _node_num) { + _first_node = INVALID; + for (typename Graph::NodeIt n(_graph); n != INVALID; ++n) { + (*_cut_map)[n] = false; + } + for (int i = 0; i < static_cast(order.size()); ++i) { + typename Graph::Node n = order[i]; + while (n != INVALID) { + (*_cut_map)[n] = true; + n = (*_next_rep)[n]; + } + } + _min_cut = 0; + return true; + } + + if (pmc < _min_cut) { + for (typename Graph::NodeIt n(_graph); n != INVALID; ++n) { + (*_cut_map)[n] = false; + } + for (int i = 0; i < sep; ++i) { + typename Graph::Node n = order[i]; + while (n != INVALID) { + (*_cut_map)[n] = true; + n = (*_next_rep)[n]; + } + } + _min_cut = pmc; + } + + for (typename Graph::Node n = _first_node; + n != INVALID; n = (*_nodes)[n].next) { + bool merged = false; + for (int a = (*_nodes)[n].first_arc; a != -1; a = _arcs[a].next) { + if (!(_edges[a >> 1].cut < pmc)) { + if (!merged) { + for (int b = (*_nodes)[n].first_arc; b != -1; b = _arcs[b].next) { + (*_nodes)[_arcs[b].target].curr_arc = b; + } + merged = true; + } + typename Graph::Node m = _arcs[a].target; + int nb = 0; + for (int b = (*_nodes)[m].first_arc; b != -1; b = nb) { + nb = _arcs[b].next; + if ((b ^ a) == 1) continue; + typename Graph::Node o = _arcs[b].target; + int c = (*_nodes)[o].curr_arc; + if (c != -1 && _arcs[c ^ 1].target == n) { + _edges[c >> 1].capacity += _edges[b >> 1].capacity; + (*_nodes)[n].sum += _edges[b >> 1].capacity; + if (_edges[b >> 1].cut < _edges[c >> 1].cut) { + _edges[b >> 1].cut = _edges[c >> 1].cut; + } + if (_arcs[b ^ 1].prev != -1) { + _arcs[_arcs[b ^ 1].prev].next = _arcs[b ^ 1].next; + } else { + (*_nodes)[o].first_arc = _arcs[b ^ 1].next; + } + if (_arcs[b ^ 1].next != -1) { + _arcs[_arcs[b ^ 1].next].prev = _arcs[b ^ 1].prev; + } + } else { + if (_arcs[a].next != -1) { + _arcs[_arcs[a].next].prev = b; + } + _arcs[b].next = _arcs[a].next; + _arcs[b].prev = a; + _arcs[a].next = b; + _arcs[b ^ 1].target = n; + + (*_nodes)[n].sum += _edges[b >> 1].capacity; + (*_nodes)[o].curr_arc = b; + } + } + + if (_arcs[a].prev != -1) { + _arcs[_arcs[a].prev].next = _arcs[a].next; + } else { + (*_nodes)[n].first_arc = _arcs[a].next; + } + if (_arcs[a].next != -1) { + _arcs[_arcs[a].next].prev = _arcs[a].prev; + } + + (*_nodes)[n].sum -= _edges[a >> 1].capacity; + (*_next_rep)[(*_nodes)[n].last_rep] = m; + (*_nodes)[n].last_rep = (*_nodes)[m].last_rep; + + if ((*_nodes)[m].prev != INVALID) { + (*_nodes)[(*_nodes)[m].prev].next = (*_nodes)[m].next; + } else{ + _first_node = (*_nodes)[m].next; + } + if ((*_nodes)[m].next != INVALID) { + (*_nodes)[(*_nodes)[m].next].prev = (*_nodes)[m].prev; + } + --_node_num; + } + } + } + + if (_node_num == 1) { + _first_node = INVALID; + return true; + } + + return false; + } + + /// \brief Executes the algorithm. + /// + /// Executes the algorithm. + /// + /// \pre init() must be called + void start() { + while (!processNextPhase()) {} + } + + + /// \brief Runs %NagamochiIbaraki algorithm. + /// + /// This method runs the %Min cut algorithm + /// + /// \note mc.run(s) is just a shortcut of the following code. + ///\code + /// mc.init(); + /// mc.start(); + ///\endcode + void run() { + init(); + start(); + } + + ///@} + + /// \name Query Functions + /// + /// The result of the %NagamochiIbaraki + /// algorithm can be obtained using these functions.\n + /// Before the use of these functions, either run() or start() + /// must be called. + + ///@{ + + /// \brief Returns the min cut value. + /// + /// Returns the min cut value if the algorithm finished. + /// After the first processNextPhase() it is a value of a + /// valid cut in the graph. + Value minCutValue() const { + return _min_cut; + } + + /// \brief Returns a min cut in a NodeMap. + /// + /// It sets the nodes of one of the two partitions to true and + /// the other partition to false. + /// \param cutMap A \ref concepts::WriteMap "writable" node map with + /// \c bool (or convertible) value type. + template + Value minCutMap(CutMap& cutMap) const { + for (typename Graph::NodeIt n(_graph); n != INVALID; ++n) { + cutMap.set(n, (*_cut_map)[n]); + } + return minCutValue(); + } + + ///@} + + }; +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/nauty_reader.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/nauty_reader.h new file mode 100644 index 00000000000..896f2a606bb --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/nauty_reader.h @@ -0,0 +1,113 @@ +/* -*- 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_NAUTY_READER_H +#define LEMON_NAUTY_READER_H + +#include +#include +#include + +/// \ingroup nauty_group +/// \file +/// \brief Nauty file reader. + +namespace lemon { + + /// \ingroup nauty_group + /// + /// \brief Nauty file reader + /// + /// The \e geng program is in the \e gtools suite of the nauty + /// package. This tool can generate all non-isomorphic undirected + /// graphs of several classes with given node number (e.g. + /// general, connected, biconnected, triangle-free, 4-cycle-free, + /// bipartite and graphs with given edge number and degree + /// constraints). This function reads a \e nauty \e graph6 \e format + /// line from the given stream and builds it in the given graph. + /// + /// The site of nauty package: http://cs.anu.edu.au/~bdm/nauty/ + /// + /// For example, the number of all non-isomorphic planar graphs + /// can be computed with the following code. + ///\code + /// int num = 0; + /// SmartGraph graph; + /// while (readNautyGraph(graph, std::cin)) { + /// PlanarityChecking pc(graph); + /// if (pc.run()) ++num; + /// } + /// std::cout << "Number of planar graphs: " << num << std::endl; + ///\endcode + /// + /// The nauty files are quite huge, therefore instead of the direct + /// file generation pipelining is recommended. For example, + ///\code + /// ./geng -c 10 | ./num_of_planar_graphs + ///\endcode + template + std::istream& readNautyGraph(Graph& graph, std::istream& is = std::cin) { + graph.clear(); + + std::string line; + if (getline(is, line)) { + int index = 0; + + int n; + + if (line[index] == '>') { + index += 10; + } + + char c = line[index++]; c -= 63; + if (c != 63) { + n = int(c); + } else { + c = line[index++]; c -= 63; + n = (int(c) << 12); + c = line[index++]; c -= 63; + n |= (int(c) << 6); + c = line[index++]; c -= 63; + n |= int(c); + } + + std::vector nodes; + for (int i = 0; i < n; ++i) { + nodes.push_back(graph.addNode()); + } + + int bit = -1; + for (int j = 0; j < n; ++j) { + for (int i = 0; i < j; ++i) { + if (bit == -1) { + c = line[index++]; c -= 63; + bit = 5; + } + bool b = (c & (1 << (bit--))) != 0; + + if (b) { + graph.addEdge(nodes[i], nodes[j]); + } + } + } + } + return is; + } +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/nearest_neighbor_tsp.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/nearest_neighbor_tsp.h new file mode 100644 index 00000000000..065e145df08 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/nearest_neighbor_tsp.h @@ -0,0 +1,238 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_NEAREST_NEIGHBOUR_TSP_H +#define LEMON_NEAREST_NEIGHBOUR_TSP_H + +/// \ingroup tsp +/// \file +/// \brief Nearest neighbor algorithm for symmetric TSP + +#include +#include +#include +#include +#include + +namespace lemon { + + /// \ingroup tsp + /// + /// \brief Nearest neighbor algorithm for symmetric TSP. + /// + /// NearestNeighborTsp implements the nearest neighbor heuristic for solving + /// symmetric \ref tsp "TSP". + /// + /// This is probably the simplest TSP heuristic. + /// It starts with a minimum cost edge and at each step, it connects the + /// nearest unvisited node to the current path. + /// Finally, it connects the two end points of the path to form a tour. + /// + /// This method runs in O(n2) time. + /// It quickly finds a relatively short tour for most TSP instances, + /// but it could also yield a really bad (or even the worst) solution + /// in special cases. + /// + /// \tparam CM Type of the cost map. + template + class NearestNeighborTsp + { + public: + + /// Type of the cost map + typedef CM CostMap; + /// Type of the edge costs + typedef typename CM::Value Cost; + + private: + + GRAPH_TYPEDEFS(FullGraph); + + const FullGraph &_gr; + const CostMap &_cost; + Cost _sum; + std::vector _path; + + public: + + /// \brief Constructor + /// + /// Constructor. + /// \param gr The \ref FullGraph "full graph" the algorithm runs on. + /// \param cost The cost map. + NearestNeighborTsp(const FullGraph &gr, const CostMap &cost) + : _gr(gr), _cost(cost) {} + + /// \name Execution Control + /// @{ + + /// \brief Runs the algorithm. + /// + /// This function runs the algorithm. + /// + /// \return The total cost of the found tour. + Cost run() { + _path.clear(); + if (_gr.nodeNum() == 0) { + return _sum = 0; + } + else if (_gr.nodeNum() == 1) { + _path.push_back(_gr(0)); + return _sum = 0; + } + + std::deque path_dq; + Edge min_edge1 = INVALID, + min_edge2 = INVALID; + + min_edge1 = mapMin(_gr, _cost); + Node n1 = _gr.u(min_edge1), + n2 = _gr.v(min_edge1); + path_dq.push_back(n1); + path_dq.push_back(n2); + + FullGraph::NodeMap used(_gr, false); + used[n1] = true; + used[n2] = true; + + min_edge1 = INVALID; + while (int(path_dq.size()) != _gr.nodeNum()) { + if (min_edge1 == INVALID) { + for (IncEdgeIt e(_gr, n1); e != INVALID; ++e) { + if (!used[_gr.runningNode(e)] && + (min_edge1 == INVALID || _cost[e] < _cost[min_edge1])) { + min_edge1 = e; + } + } + } + + if (min_edge2 == INVALID) { + for (IncEdgeIt e(_gr, n2); e != INVALID; ++e) { + if (!used[_gr.runningNode(e)] && + (min_edge2 == INVALID||_cost[e] < _cost[min_edge2])) { + min_edge2 = e; + } + } + } + + if (_cost[min_edge1] < _cost[min_edge2]) { + n1 = _gr.oppositeNode(n1, min_edge1); + path_dq.push_front(n1); + + used[n1] = true; + min_edge1 = INVALID; + + if (_gr.u(min_edge2) == n1 || _gr.v(min_edge2) == n1) + min_edge2 = INVALID; + } else { + n2 = _gr.oppositeNode(n2, min_edge2); + path_dq.push_back(n2); + + used[n2] = true; + min_edge2 = INVALID; + + if (_gr.u(min_edge1) == n2 || _gr.v(min_edge1) == n2) + min_edge1 = INVALID; + } + } + + n1 = path_dq.back(); + n2 = path_dq.front(); + _path.push_back(n2); + _sum = _cost[_gr.edge(n1, n2)]; + for (int i = 1; i < int(path_dq.size()); ++i) { + n1 = n2; + n2 = path_dq[i]; + _path.push_back(n2); + _sum += _cost[_gr.edge(n1, n2)]; + } + + return _sum; + } + + /// @} + + /// \name Query Functions + /// @{ + + /// \brief The total cost of the found tour. + /// + /// This function returns the total cost of the found tour. + /// + /// \pre run() must be called before using this function. + Cost tourCost() const { + return _sum; + } + + /// \brief Returns a const reference to the node sequence of the + /// found tour. + /// + /// This function returns a const reference to a vector + /// that stores the node sequence of the found tour. + /// + /// \pre run() must be called before using this function. + const std::vector& tourNodes() const { + return _path; + } + + /// \brief Gives back the node sequence of the found tour. + /// + /// This function copies the node sequence of the found tour into + /// an STL container through the given output iterator. The + /// value_type of the container must be FullGraph::Node. + /// For example, + /// \code + /// std::vector nodes(countNodes(graph)); + /// tsp.tourNodes(nodes.begin()); + /// \endcode + /// or + /// \code + /// std::list nodes; + /// tsp.tourNodes(std::back_inserter(nodes)); + /// \endcode + /// + /// \pre run() must be called before using this function. + template + void tourNodes(Iterator out) const { + std::copy(_path.begin(), _path.end(), out); + } + + /// \brief Gives back the found tour as a path. + /// + /// This function copies the found tour as a list of arcs/edges into + /// the given \ref lemon::concepts::Path "path structure". + /// + /// \pre run() must be called before using this function. + template + void tour(Path &path) const { + path.clear(); + for (int i = 0; i < int(_path.size()) - 1; ++i) { + path.addBack(_gr.arc(_path[i], _path[i+1])); + } + if (int(_path.size()) >= 2) { + path.addBack(_gr.arc(_path.back(), _path.front())); + } + } + + /// @} + + }; + +}; // namespace lemon + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/network_simplex.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/network_simplex.h new file mode 100644 index 00000000000..6ccad33e68e --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/network_simplex.h @@ -0,0 +1,1659 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_NETWORK_SIMPLEX_H +#define LEMON_NETWORK_SIMPLEX_H + +/// \ingroup min_cost_flow_algs +/// +/// \file +/// \brief Network Simplex algorithm for finding a minimum cost flow. + +#include +#include +#include + +#include +#include + +namespace lemon { + + /// \addtogroup min_cost_flow_algs + /// @{ + + /// \brief Implementation of the primal Network Simplex algorithm + /// for finding a \ref min_cost_flow "minimum cost flow". + /// + /// \ref NetworkSimplex implements the primal Network Simplex algorithm + /// for finding a \ref min_cost_flow "minimum cost flow" + /// \cite amo93networkflows, \cite dantzig63linearprog, + /// \cite kellyoneill91netsimplex. + /// This algorithm is a highly efficient specialized version of the + /// linear programming simplex method directly for the minimum cost + /// flow problem. + /// + /// In general, \ref NetworkSimplex and \ref CostScaling are the fastest + /// implementations available in LEMON for solving this problem. + /// (For more information, see \ref min_cost_flow_algs "the module page".) + /// Furthermore, this class supports both directions of the supply/demand + /// inequality constraints. For more information, see \ref SupplyType. + /// + /// Most of the parameters of the problem (except for the digraph) + /// can be given using separate functions, and the algorithm can be + /// executed using the \ref run() function. If some parameters are not + /// specified, then default values will be used. + /// + /// \tparam GR The digraph type the algorithm runs on. + /// \tparam V The number type used for flow amounts, capacity bounds + /// and supply values in the algorithm. By default, it is \c int. + /// \tparam C The number type used for costs and potentials in the + /// algorithm. By default, it is the same as \c V. + /// + /// \warning Both \c V and \c C must be signed number types. + /// \warning All input data (capacities, supply values, and costs) must + /// be integer. + /// + /// \note %NetworkSimplex provides five different pivot rule + /// implementations, from which the most efficient one is used + /// by default. For more information, see \ref PivotRule. + template + class NetworkSimplex + { + public: + + /// The type of the flow amounts, capacity bounds and supply values + typedef V Value; + /// The type of the arc costs + typedef C Cost; + + public: + + /// \brief Problem type constants for the \c run() function. + /// + /// Enum type containing the problem type constants that can be + /// returned by the \ref run() function of the algorithm. + enum ProblemType { + /// The problem has no feasible solution (flow). + INFEASIBLE, + /// The problem has optimal solution (i.e. it is feasible and + /// bounded), and the algorithm has found optimal flow and node + /// potentials (primal and dual solutions). + OPTIMAL, + /// The objective function of the problem is unbounded, i.e. + /// there is a directed cycle having negative total cost and + /// infinite upper bound. + UNBOUNDED + }; + + /// \brief Constants for selecting the type of the supply constraints. + /// + /// Enum type containing constants for selecting the supply type, + /// i.e. the direction of the inequalities in the supply/demand + /// constraints of the \ref min_cost_flow "minimum cost flow problem". + /// + /// The default supply type is \c GEQ, the \c LEQ type can be + /// selected using \ref supplyType(). + /// The equality form is a special case of both supply types. + enum SupplyType { + /// This option means that there are "greater or equal" + /// supply/demand constraints in the definition of the problem. + GEQ, + /// This option means that there are "less or equal" + /// supply/demand constraints in the definition of the problem. + LEQ + }; + + /// \brief Constants for selecting the pivot rule. + /// + /// Enum type containing constants for selecting the pivot rule for + /// the \ref run() function. + /// + /// \ref NetworkSimplex provides five different implementations for + /// the pivot strategy that significantly affects the running time + /// of the algorithm. + /// According to experimental tests conducted on various problem + /// instances, \ref BLOCK_SEARCH "Block Search" and + /// \ref ALTERING_LIST "Altering Candidate List" rules turned out + /// to be the most efficient. + /// Since \ref BLOCK_SEARCH "Block Search" is a simpler strategy that + /// seemed to be slightly more robust, it is used by default. + /// However, another pivot rule can easily be selected using the + /// \ref run() function with the proper parameter. + enum PivotRule { + + /// The \e First \e Eligible pivot rule. + /// The next eligible arc is selected in a wraparound fashion + /// in every iteration. + FIRST_ELIGIBLE, + + /// The \e Best \e Eligible pivot rule. + /// The best eligible arc is selected in every iteration. + BEST_ELIGIBLE, + + /// The \e Block \e Search pivot rule. + /// A specified number of arcs are examined in every iteration + /// in a wraparound fashion and the best eligible arc is selected + /// from this block. + BLOCK_SEARCH, + + /// The \e Candidate \e List pivot rule. + /// In a major iteration a candidate list is built from eligible arcs + /// in a wraparound fashion and in the following minor iterations + /// the best eligible arc is selected from this list. + CANDIDATE_LIST, + + /// The \e Altering \e Candidate \e List pivot rule. + /// It is a modified version of the Candidate List method. + /// It keeps only a few of the best eligible arcs from the former + /// candidate list and extends this list in every iteration. + ALTERING_LIST + }; + + private: + + TEMPLATE_DIGRAPH_TYPEDEFS(GR); + + typedef std::vector IntVector; + typedef std::vector ValueVector; + typedef std::vector CostVector; + typedef std::vector CharVector; + // Note: vector is used instead of vector and + // vector for efficiency reasons + + // State constants for arcs + enum ArcState { + STATE_UPPER = -1, + STATE_TREE = 0, + STATE_LOWER = 1 + }; + + // Direction constants for tree arcs + enum ArcDirection { + DIR_DOWN = -1, + DIR_UP = 1 + }; + + private: + + // Data related to the underlying digraph + const GR &_graph; + int _node_num; + int _arc_num; + int _all_arc_num; + int _search_arc_num; + + // Parameters of the problem + bool _has_lower; + SupplyType _stype; + Value _sum_supply; + + // Data structures for storing the digraph + IntNodeMap _node_id; + IntArcMap _arc_id; + IntVector _source; + IntVector _target; + bool _arc_mixing; + + // Node and arc data + ValueVector _lower; + ValueVector _upper; + ValueVector _cap; + CostVector _cost; + ValueVector _supply; + ValueVector _flow; + CostVector _pi; + + // Data for storing the spanning tree structure + IntVector _parent; + IntVector _pred; + IntVector _thread; + IntVector _rev_thread; + IntVector _succ_num; + IntVector _last_succ; + CharVector _pred_dir; + CharVector _state; + IntVector _dirty_revs; + int _root; + + // Temporary data used in the current pivot iteration + int in_arc, join, u_in, v_in, u_out, v_out; + Value delta; + + const Value MAX; + + public: + + /// \brief Constant for infinite upper bounds (capacities). + /// + /// Constant for infinite upper bounds (capacities). + /// It is \c std::numeric_limits::infinity() if available, + /// \c std::numeric_limits::max() otherwise. + const Value INF; + + private: + + // Implementation of the First Eligible pivot rule + class FirstEligiblePivotRule + { + private: + + // References to the NetworkSimplex class + const IntVector &_source; + const IntVector &_target; + const CostVector &_cost; + const CharVector &_state; + const CostVector &_pi; + int &_in_arc; + int _search_arc_num; + + // Pivot rule data + int _next_arc; + + public: + + // Constructor + FirstEligiblePivotRule(NetworkSimplex &ns) : + _source(ns._source), _target(ns._target), + _cost(ns._cost), _state(ns._state), _pi(ns._pi), + _in_arc(ns.in_arc), _search_arc_num(ns._search_arc_num), + _next_arc(0) + {} + + // Find next entering arc + bool findEnteringArc() { + Cost c; + for (int e = _next_arc; e != _search_arc_num; ++e) { + c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); + if (c < 0) { + _in_arc = e; + _next_arc = e + 1; + return true; + } + } + for (int e = 0; e != _next_arc; ++e) { + c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); + if (c < 0) { + _in_arc = e; + _next_arc = e + 1; + return true; + } + } + return false; + } + + }; //class FirstEligiblePivotRule + + + // Implementation of the Best Eligible pivot rule + class BestEligiblePivotRule + { + private: + + // References to the NetworkSimplex class + const IntVector &_source; + const IntVector &_target; + const CostVector &_cost; + const CharVector &_state; + const CostVector &_pi; + int &_in_arc; + int _search_arc_num; + + public: + + // Constructor + BestEligiblePivotRule(NetworkSimplex &ns) : + _source(ns._source), _target(ns._target), + _cost(ns._cost), _state(ns._state), _pi(ns._pi), + _in_arc(ns.in_arc), _search_arc_num(ns._search_arc_num) + {} + + // Find next entering arc + bool findEnteringArc() { + Cost c, min = 0; + for (int e = 0; e != _search_arc_num; ++e) { + c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); + if (c < min) { + min = c; + _in_arc = e; + } + } + return min < 0; + } + + }; //class BestEligiblePivotRule + + + // Implementation of the Block Search pivot rule + class BlockSearchPivotRule + { + private: + + // References to the NetworkSimplex class + const IntVector &_source; + const IntVector &_target; + const CostVector &_cost; + const CharVector &_state; + const CostVector &_pi; + int &_in_arc; + int _search_arc_num; + + // Pivot rule data + int _block_size; + int _next_arc; + + public: + + // Constructor + BlockSearchPivotRule(NetworkSimplex &ns) : + _source(ns._source), _target(ns._target), + _cost(ns._cost), _state(ns._state), _pi(ns._pi), + _in_arc(ns.in_arc), _search_arc_num(ns._search_arc_num), + _next_arc(0) + { + // The main parameters of the pivot rule + const double BLOCK_SIZE_FACTOR = 1.0; + const int MIN_BLOCK_SIZE = 10; + + _block_size = std::max( int(BLOCK_SIZE_FACTOR * + std::sqrt(double(_search_arc_num))), + MIN_BLOCK_SIZE ); + } + + // Find next entering arc + bool findEnteringArc() { + Cost c, min = 0; + int cnt = _block_size; + int e; + for (e = _next_arc; e != _search_arc_num; ++e) { + c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); + if (c < min) { + min = c; + _in_arc = e; + } + if (--cnt == 0) { + if (min < 0) goto search_end; + cnt = _block_size; + } + } + for (e = 0; e != _next_arc; ++e) { + c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); + if (c < min) { + min = c; + _in_arc = e; + } + if (--cnt == 0) { + if (min < 0) goto search_end; + cnt = _block_size; + } + } + if (min >= 0) return false; + + search_end: + _next_arc = e; + return true; + } + + }; //class BlockSearchPivotRule + + + // Implementation of the Candidate List pivot rule + class CandidateListPivotRule + { + private: + + // References to the NetworkSimplex class + const IntVector &_source; + const IntVector &_target; + const CostVector &_cost; + const CharVector &_state; + const CostVector &_pi; + int &_in_arc; + int _search_arc_num; + + // Pivot rule data + IntVector _candidates; + int _list_length, _minor_limit; + int _curr_length, _minor_count; + int _next_arc; + + public: + + /// Constructor + CandidateListPivotRule(NetworkSimplex &ns) : + _source(ns._source), _target(ns._target), + _cost(ns._cost), _state(ns._state), _pi(ns._pi), + _in_arc(ns.in_arc), _search_arc_num(ns._search_arc_num), + _next_arc(0) + { + // The main parameters of the pivot rule + const double LIST_LENGTH_FACTOR = 0.25; + const int MIN_LIST_LENGTH = 10; + const double MINOR_LIMIT_FACTOR = 0.1; + const int MIN_MINOR_LIMIT = 3; + + _list_length = std::max( int(LIST_LENGTH_FACTOR * + std::sqrt(double(_search_arc_num))), + MIN_LIST_LENGTH ); + _minor_limit = std::max( int(MINOR_LIMIT_FACTOR * _list_length), + MIN_MINOR_LIMIT ); + _curr_length = _minor_count = 0; + _candidates.resize(_list_length); + } + + /// Find next entering arc + bool findEnteringArc() { + Cost min, c; + int e; + if (_curr_length > 0 && _minor_count < _minor_limit) { + // Minor iteration: select the best eligible arc from the + // current candidate list + ++_minor_count; + min = 0; + for (int i = 0; i < _curr_length; ++i) { + e = _candidates[i]; + c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); + if (c < min) { + min = c; + _in_arc = e; + } + else if (c >= 0) { + _candidates[i--] = _candidates[--_curr_length]; + } + } + if (min < 0) return true; + } + + // Major iteration: build a new candidate list + min = 0; + _curr_length = 0; + for (e = _next_arc; e != _search_arc_num; ++e) { + c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); + if (c < 0) { + _candidates[_curr_length++] = e; + if (c < min) { + min = c; + _in_arc = e; + } + if (_curr_length == _list_length) goto search_end; + } + } + for (e = 0; e != _next_arc; ++e) { + c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); + if (c < 0) { + _candidates[_curr_length++] = e; + if (c < min) { + min = c; + _in_arc = e; + } + if (_curr_length == _list_length) goto search_end; + } + } + if (_curr_length == 0) return false; + + search_end: + _minor_count = 1; + _next_arc = e; + return true; + } + + }; //class CandidateListPivotRule + + + // Implementation of the Altering Candidate List pivot rule + class AlteringListPivotRule + { + private: + + // References to the NetworkSimplex class + const IntVector &_source; + const IntVector &_target; + const CostVector &_cost; + const CharVector &_state; + const CostVector &_pi; + int &_in_arc; + int _search_arc_num; + + // Pivot rule data + int _block_size, _head_length, _curr_length; + int _next_arc; + IntVector _candidates; + CostVector _cand_cost; + + // Functor class to compare arcs during sort of the candidate list + class SortFunc + { + private: + const CostVector &_map; + public: + SortFunc(const CostVector &map) : _map(map) {} + bool operator()(int left, int right) { + return _map[left] < _map[right]; + } + }; + + SortFunc _sort_func; + + public: + + // Constructor + AlteringListPivotRule(NetworkSimplex &ns) : + _source(ns._source), _target(ns._target), + _cost(ns._cost), _state(ns._state), _pi(ns._pi), + _in_arc(ns.in_arc), _search_arc_num(ns._search_arc_num), + _next_arc(0), _cand_cost(ns._search_arc_num), _sort_func(_cand_cost) + { + // The main parameters of the pivot rule + const double BLOCK_SIZE_FACTOR = 1.0; + const int MIN_BLOCK_SIZE = 10; + const double HEAD_LENGTH_FACTOR = 0.01; + const int MIN_HEAD_LENGTH = 3; + + _block_size = std::max( int(BLOCK_SIZE_FACTOR * + std::sqrt(double(_search_arc_num))), + MIN_BLOCK_SIZE ); + _head_length = std::max( int(HEAD_LENGTH_FACTOR * _block_size), + MIN_HEAD_LENGTH ); + _candidates.resize(_head_length + _block_size); + _curr_length = 0; + } + + // Find next entering arc + bool findEnteringArc() { + // Check the current candidate list + int e; + Cost c; + for (int i = 0; i != _curr_length; ++i) { + e = _candidates[i]; + c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); + if (c < 0) { + _cand_cost[e] = c; + } else { + _candidates[i--] = _candidates[--_curr_length]; + } + } + + // Extend the list + int cnt = _block_size; + int limit = _head_length; + + for (e = _next_arc; e != _search_arc_num; ++e) { + c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); + if (c < 0) { + _cand_cost[e] = c; + _candidates[_curr_length++] = e; + } + if (--cnt == 0) { + if (_curr_length > limit) goto search_end; + limit = 0; + cnt = _block_size; + } + } + for (e = 0; e != _next_arc; ++e) { + c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); + if (c < 0) { + _cand_cost[e] = c; + _candidates[_curr_length++] = e; + } + if (--cnt == 0) { + if (_curr_length > limit) goto search_end; + limit = 0; + cnt = _block_size; + } + } + if (_curr_length == 0) return false; + + search_end: + + // Perform partial sort operation on the candidate list + int new_length = std::min(_head_length + 1, _curr_length); + std::partial_sort(_candidates.begin(), _candidates.begin() + new_length, + _candidates.begin() + _curr_length, _sort_func); + + // Select the entering arc and remove it from the list + _in_arc = _candidates[0]; + _next_arc = e; + _candidates[0] = _candidates[new_length - 1]; + _curr_length = new_length - 1; + return true; + } + + }; //class AlteringListPivotRule + + public: + + /// \brief Constructor. + /// + /// The constructor of the class. + /// + /// \param graph The digraph the algorithm runs on. + /// \param arc_mixing Indicate if the arcs will be stored in a + /// mixed order in the internal data structure. + /// In general, it leads to similar performance as using the original + /// arc order, but it makes the algorithm more robust and in special + /// cases, even significantly faster. Therefore, it is enabled by default. + NetworkSimplex(const GR& graph, bool arc_mixing = true) : + _graph(graph), _node_id(graph), _arc_id(graph), + _arc_mixing(arc_mixing), + MAX(std::numeric_limits::max()), + INF(std::numeric_limits::has_infinity ? + std::numeric_limits::infinity() : MAX) + { + // Check the number types + LEMON_ASSERT(std::numeric_limits::is_signed, + "The flow type of NetworkSimplex must be signed"); + LEMON_ASSERT(std::numeric_limits::is_signed, + "The cost type of NetworkSimplex must be signed"); + + // Reset data structures + reset(); + } + + /// \name Parameters + /// The parameters of the algorithm can be specified using these + /// functions. + + /// @{ + + /// \brief Set the lower bounds on the arcs. + /// + /// This function sets the lower bounds on the arcs. + /// If it is not used before calling \ref run(), the lower bounds + /// will be set to zero on all arcs. + /// + /// \param map An arc map storing the lower bounds. + /// Its \c Value type must be convertible to the \c Value type + /// of the algorithm. + /// + /// \return (*this) + template + NetworkSimplex& lowerMap(const LowerMap& map) { + _has_lower = true; + for (ArcIt a(_graph); a != INVALID; ++a) { + _lower[_arc_id[a]] = map[a]; + } + return *this; + } + + /// \brief Set the upper bounds (capacities) on the arcs. + /// + /// This function sets the upper bounds (capacities) on the arcs. + /// If it is not used before calling \ref run(), the upper bounds + /// will be set to \ref INF on all arcs (i.e. the flow value will be + /// unbounded from above). + /// + /// \param map An arc map storing the upper bounds. + /// Its \c Value type must be convertible to the \c Value type + /// of the algorithm. + /// + /// \return (*this) + template + NetworkSimplex& upperMap(const UpperMap& map) { + for (ArcIt a(_graph); a != INVALID; ++a) { + _upper[_arc_id[a]] = map[a]; + } + return *this; + } + + /// \brief Set the costs of the arcs. + /// + /// This function sets the costs of the arcs. + /// If it is not used before calling \ref run(), the costs + /// will be set to \c 1 on all arcs. + /// + /// \param map An arc map storing the costs. + /// Its \c Value type must be convertible to the \c Cost type + /// of the algorithm. + /// + /// \return (*this) + template + NetworkSimplex& costMap(const CostMap& map) { + for (ArcIt a(_graph); a != INVALID; ++a) { + _cost[_arc_id[a]] = map[a]; + } + return *this; + } + + /// \brief Set the supply values of the nodes. + /// + /// This function sets the supply values of the nodes. + /// If neither this function nor \ref stSupply() is used before + /// calling \ref run(), the supply of each node will be set to zero. + /// + /// \param map A node map storing the supply values. + /// Its \c Value type must be convertible to the \c Value type + /// of the algorithm. + /// + /// \return (*this) + /// + /// \sa supplyType() + template + NetworkSimplex& supplyMap(const SupplyMap& map) { + for (NodeIt n(_graph); n != INVALID; ++n) { + _supply[_node_id[n]] = map[n]; + } + return *this; + } + + /// \brief Set single source and target nodes and a supply value. + /// + /// This function sets a single source node and a single target node + /// and the required flow value. + /// If neither this function nor \ref supplyMap() is used before + /// calling \ref run(), the supply of each node will be set to zero. + /// + /// Using this function has the same effect as using \ref supplyMap() + /// with a map in which \c k is assigned to \c s, \c -k is + /// assigned to \c t and all other nodes have zero supply value. + /// + /// \param s The source node. + /// \param t The target node. + /// \param k The required amount of flow from node \c s to node \c t + /// (i.e. the supply of \c s and the demand of \c t). + /// + /// \return (*this) + NetworkSimplex& stSupply(const Node& s, const Node& t, Value k) { + for (int i = 0; i != _node_num; ++i) { + _supply[i] = 0; + } + _supply[_node_id[s]] = k; + _supply[_node_id[t]] = -k; + return *this; + } + + /// \brief Set the type of the supply constraints. + /// + /// This function sets the type of the supply/demand constraints. + /// If it is not used before calling \ref run(), the \ref GEQ supply + /// type will be used. + /// + /// For more information, see \ref SupplyType. + /// + /// \return (*this) + NetworkSimplex& supplyType(SupplyType supply_type) { + _stype = supply_type; + return *this; + } + + /// @} + + /// \name Execution Control + /// The algorithm can be executed using \ref run(). + + /// @{ + + /// \brief Run the algorithm. + /// + /// This function runs the algorithm. + /// The paramters can be specified using functions \ref lowerMap(), + /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply(), + /// \ref supplyType(). + /// For example, + /// \code + /// NetworkSimplex ns(graph); + /// ns.lowerMap(lower).upperMap(upper).costMap(cost) + /// .supplyMap(sup).run(); + /// \endcode + /// + /// This function can be called more than once. All the given parameters + /// are kept for the next call, unless \ref resetParams() or \ref reset() + /// is used, thus only the modified parameters have to be set again. + /// If the underlying digraph was also modified after the construction + /// of the class (or the last \ref reset() call), then the \ref reset() + /// function must be called. + /// + /// \param pivot_rule The pivot rule that will be used during the + /// algorithm. For more information, see \ref PivotRule. + /// + /// \return \c INFEASIBLE if no feasible flow exists, + /// \n \c OPTIMAL if the problem has optimal solution + /// (i.e. it is feasible and bounded), and the algorithm has found + /// optimal flow and node potentials (primal and dual solutions), + /// \n \c UNBOUNDED if the objective function of the problem is + /// unbounded, i.e. there is a directed cycle having negative total + /// cost and infinite upper bound. + /// + /// \see ProblemType, PivotRule + /// \see resetParams(), reset() + ProblemType run(PivotRule pivot_rule = BLOCK_SEARCH) { + if (!init()) return INFEASIBLE; + return start(pivot_rule); + } + + /// \brief Reset all the parameters that have been given before. + /// + /// This function resets all the paramaters that have been given + /// before using functions \ref lowerMap(), \ref upperMap(), + /// \ref costMap(), \ref supplyMap(), \ref stSupply(), \ref supplyType(). + /// + /// It is useful for multiple \ref run() calls. Basically, all the given + /// parameters are kept for the next \ref run() call, unless + /// \ref resetParams() or \ref reset() is used. + /// If the underlying digraph was also modified after the construction + /// of the class or the last \ref reset() call, then the \ref reset() + /// function must be used, otherwise \ref resetParams() is sufficient. + /// + /// For example, + /// \code + /// NetworkSimplex ns(graph); + /// + /// // First run + /// ns.lowerMap(lower).upperMap(upper).costMap(cost) + /// .supplyMap(sup).run(); + /// + /// // Run again with modified cost map (resetParams() is not called, + /// // so only the cost map have to be set again) + /// cost[e] += 100; + /// ns.costMap(cost).run(); + /// + /// // Run again from scratch using resetParams() + /// // (the lower bounds will be set to zero on all arcs) + /// ns.resetParams(); + /// ns.upperMap(capacity).costMap(cost) + /// .supplyMap(sup).run(); + /// \endcode + /// + /// \return (*this) + /// + /// \see reset(), run() + NetworkSimplex& resetParams() { + for (int i = 0; i != _node_num; ++i) { + _supply[i] = 0; + } + for (int i = 0; i != _arc_num; ++i) { + _lower[i] = 0; + _upper[i] = INF; + _cost[i] = 1; + } + _has_lower = false; + _stype = GEQ; + return *this; + } + + /// \brief Reset the internal data structures and all the parameters + /// that have been given before. + /// + /// This function resets the internal data structures and all the + /// paramaters that have been given before using functions \ref lowerMap(), + /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply(), + /// \ref supplyType(). + /// + /// It is useful for multiple \ref run() calls. Basically, all the given + /// parameters are kept for the next \ref run() call, unless + /// \ref resetParams() or \ref reset() is used. + /// If the underlying digraph was also modified after the construction + /// of the class or the last \ref reset() call, then the \ref reset() + /// function must be used, otherwise \ref resetParams() is sufficient. + /// + /// See \ref resetParams() for examples. + /// + /// \return (*this) + /// + /// \see resetParams(), run() + NetworkSimplex& reset() { + // Resize vectors + _node_num = countNodes(_graph); + _arc_num = countArcs(_graph); + int all_node_num = _node_num + 1; + int max_arc_num = _arc_num + 2 * _node_num; + + _source.resize(max_arc_num); + _target.resize(max_arc_num); + + _lower.resize(_arc_num); + _upper.resize(_arc_num); + _cap.resize(max_arc_num); + _cost.resize(max_arc_num); + _supply.resize(all_node_num); + _flow.resize(max_arc_num); + _pi.resize(all_node_num); + + _parent.resize(all_node_num); + _pred.resize(all_node_num); + _pred_dir.resize(all_node_num); + _thread.resize(all_node_num); + _rev_thread.resize(all_node_num); + _succ_num.resize(all_node_num); + _last_succ.resize(all_node_num); + _state.resize(max_arc_num); + + // Copy the graph + int i = 0; + for (NodeIt n(_graph); n != INVALID; ++n, ++i) { + _node_id[n] = i; + } + if (_arc_mixing && _node_num > 1) { + // Store the arcs in a mixed order + const int skip = std::max(_arc_num / _node_num, 3); + int i = 0, j = 0; + for (ArcIt a(_graph); a != INVALID; ++a) { + _arc_id[a] = i; + _source[i] = _node_id[_graph.source(a)]; + _target[i] = _node_id[_graph.target(a)]; + if ((i += skip) >= _arc_num) i = ++j; + } + } else { + // Store the arcs in the original order + int i = 0; + for (ArcIt a(_graph); a != INVALID; ++a, ++i) { + _arc_id[a] = i; + _source[i] = _node_id[_graph.source(a)]; + _target[i] = _node_id[_graph.target(a)]; + } + } + + // Reset parameters + resetParams(); + return *this; + } + + /// @} + + /// \name Query Functions + /// The results of the algorithm can be obtained using these + /// functions.\n + /// The \ref run() function must be called before using them. + + /// @{ + + /// \brief Return the total cost of the found flow. + /// + /// This function returns the total cost of the found flow. + /// Its complexity is O(m). + /// + /// \note The return type of the function can be specified as a + /// template parameter. For example, + /// \code + /// ns.totalCost(); + /// \endcode + /// It is useful if the total cost cannot be stored in the \c Cost + /// type of the algorithm, which is the default return type of the + /// function. + /// + /// \pre \ref run() must be called before using this function. + template + Number totalCost() const { + Number c = 0; + for (ArcIt a(_graph); a != INVALID; ++a) { + int i = _arc_id[a]; + c += Number(_flow[i]) * Number(_cost[i]); + } + return c; + } + +#ifndef DOXYGEN + Cost totalCost() const { + return totalCost(); + } +#endif + + /// \brief Return the flow on the given arc. + /// + /// This function returns the flow on the given arc. + /// + /// \pre \ref run() must be called before using this function. + Value flow(const Arc& a) const { + return _flow[_arc_id[a]]; + } + + /// \brief Copy the flow values (the primal solution) into the + /// given map. + /// + /// This function copies the flow value on each arc into the given + /// map. The \c Value type of the algorithm must be convertible to + /// the \c Value type of the map. + /// + /// \pre \ref run() must be called before using this function. + template + void flowMap(FlowMap &map) const { + for (ArcIt a(_graph); a != INVALID; ++a) { + map.set(a, _flow[_arc_id[a]]); + } + } + + /// \brief Return the potential (dual value) of the given node. + /// + /// This function returns the potential (dual value) of the + /// given node. + /// + /// \pre \ref run() must be called before using this function. + Cost potential(const Node& n) const { + return _pi[_node_id[n]]; + } + + /// \brief Copy the potential values (the dual solution) into the + /// given map. + /// + /// This function copies the potential (dual value) of each node + /// into the given map. + /// The \c Cost type of the algorithm must be convertible to the + /// \c Value type of the map. + /// + /// \pre \ref run() must be called before using this function. + template + void potentialMap(PotentialMap &map) const { + for (NodeIt n(_graph); n != INVALID; ++n) { + map.set(n, _pi[_node_id[n]]); + } + } + + /// @} + + private: + + // Initialize internal data structures + bool init() { + if (_node_num == 0) return false; + + // Check the sum of supply values + _sum_supply = 0; + for (int i = 0; i != _node_num; ++i) { + _sum_supply += _supply[i]; + } + if ( !((_stype == GEQ && _sum_supply <= 0) || + (_stype == LEQ && _sum_supply >= 0)) ) return false; + + // Check lower and upper bounds + LEMON_DEBUG(checkBoundMaps(), + "Upper bounds must be greater or equal to the lower bounds"); + + // Remove non-zero lower bounds + if (_has_lower) { + for (int i = 0; i != _arc_num; ++i) { + Value c = _lower[i]; + if (c >= 0) { + _cap[i] = _upper[i] < MAX ? _upper[i] - c : INF; + } else { + _cap[i] = _upper[i] < MAX + c ? _upper[i] - c : INF; + } + _supply[_source[i]] -= c; + _supply[_target[i]] += c; + } + } else { + for (int i = 0; i != _arc_num; ++i) { + _cap[i] = _upper[i]; + } + } + + // Initialize artifical cost + Cost ART_COST; + if (std::numeric_limits::is_exact) { + ART_COST = std::numeric_limits::max() / 2 + 1; + } else { + ART_COST = 0; + for (int i = 0; i != _arc_num; ++i) { + if (_cost[i] > ART_COST) ART_COST = _cost[i]; + } + ART_COST = (ART_COST + 1) * _node_num; + } + + // Initialize arc maps + for (int i = 0; i != _arc_num; ++i) { + _flow[i] = 0; + _state[i] = STATE_LOWER; + } + + // Set data for the artificial root node + _root = _node_num; + _parent[_root] = -1; + _pred[_root] = -1; + _thread[_root] = 0; + _rev_thread[0] = _root; + _succ_num[_root] = _node_num + 1; + _last_succ[_root] = _root - 1; + _supply[_root] = -_sum_supply; + _pi[_root] = 0; + + // Add artificial arcs and initialize the spanning tree data structure + if (_sum_supply == 0) { + // EQ supply constraints + _search_arc_num = _arc_num; + _all_arc_num = _arc_num + _node_num; + for (int u = 0, e = _arc_num; u != _node_num; ++u, ++e) { + _parent[u] = _root; + _pred[u] = e; + _thread[u] = u + 1; + _rev_thread[u + 1] = u; + _succ_num[u] = 1; + _last_succ[u] = u; + _cap[e] = INF; + _state[e] = STATE_TREE; + if (_supply[u] >= 0) { + _pred_dir[u] = DIR_UP; + _pi[u] = 0; + _source[e] = u; + _target[e] = _root; + _flow[e] = _supply[u]; + _cost[e] = 0; + } else { + _pred_dir[u] = DIR_DOWN; + _pi[u] = ART_COST; + _source[e] = _root; + _target[e] = u; + _flow[e] = -_supply[u]; + _cost[e] = ART_COST; + } + } + } + else if (_sum_supply > 0) { + // LEQ supply constraints + _search_arc_num = _arc_num + _node_num; + int f = _arc_num + _node_num; + for (int u = 0, e = _arc_num; u != _node_num; ++u, ++e) { + _parent[u] = _root; + _thread[u] = u + 1; + _rev_thread[u + 1] = u; + _succ_num[u] = 1; + _last_succ[u] = u; + if (_supply[u] >= 0) { + _pred_dir[u] = DIR_UP; + _pi[u] = 0; + _pred[u] = e; + _source[e] = u; + _target[e] = _root; + _cap[e] = INF; + _flow[e] = _supply[u]; + _cost[e] = 0; + _state[e] = STATE_TREE; + } else { + _pred_dir[u] = DIR_DOWN; + _pi[u] = ART_COST; + _pred[u] = f; + _source[f] = _root; + _target[f] = u; + _cap[f] = INF; + _flow[f] = -_supply[u]; + _cost[f] = ART_COST; + _state[f] = STATE_TREE; + _source[e] = u; + _target[e] = _root; + _cap[e] = INF; + _flow[e] = 0; + _cost[e] = 0; + _state[e] = STATE_LOWER; + ++f; + } + } + _all_arc_num = f; + } + else { + // GEQ supply constraints + _search_arc_num = _arc_num + _node_num; + int f = _arc_num + _node_num; + for (int u = 0, e = _arc_num; u != _node_num; ++u, ++e) { + _parent[u] = _root; + _thread[u] = u + 1; + _rev_thread[u + 1] = u; + _succ_num[u] = 1; + _last_succ[u] = u; + if (_supply[u] <= 0) { + _pred_dir[u] = DIR_DOWN; + _pi[u] = 0; + _pred[u] = e; + _source[e] = _root; + _target[e] = u; + _cap[e] = INF; + _flow[e] = -_supply[u]; + _cost[e] = 0; + _state[e] = STATE_TREE; + } else { + _pred_dir[u] = DIR_UP; + _pi[u] = -ART_COST; + _pred[u] = f; + _source[f] = u; + _target[f] = _root; + _cap[f] = INF; + _flow[f] = _supply[u]; + _state[f] = STATE_TREE; + _cost[f] = ART_COST; + _source[e] = _root; + _target[e] = u; + _cap[e] = INF; + _flow[e] = 0; + _cost[e] = 0; + _state[e] = STATE_LOWER; + ++f; + } + } + _all_arc_num = f; + } + + return true; + } + + // Check if the upper bound is greater than or equal to the lower bound + // on each arc. + bool checkBoundMaps() { + for (int j = 0; j != _arc_num; ++j) { + if (_upper[j] < _lower[j]) return false; + } + return true; + } + + // Find the join node + void findJoinNode() { + int u = _source[in_arc]; + int v = _target[in_arc]; + while (u != v) { + if (_succ_num[u] < _succ_num[v]) { + u = _parent[u]; + } else { + v = _parent[v]; + } + } + join = u; + } + + // Find the leaving arc of the cycle and returns true if the + // leaving arc is not the same as the entering arc + bool findLeavingArc() { + // Initialize first and second nodes according to the direction + // of the cycle + int first, second; + if (_state[in_arc] == STATE_LOWER) { + first = _source[in_arc]; + second = _target[in_arc]; + } else { + first = _target[in_arc]; + second = _source[in_arc]; + } + delta = _cap[in_arc]; + int result = 0; + Value c, d; + int e; + + // Search the cycle form the first node to the join node + for (int u = first; u != join; u = _parent[u]) { + e = _pred[u]; + d = _flow[e]; + if (_pred_dir[u] == DIR_DOWN) { + c = _cap[e]; + d = c >= MAX ? INF : c - d; + } + if (d < delta) { + delta = d; + u_out = u; + result = 1; + } + } + + // Search the cycle form the second node to the join node + for (int u = second; u != join; u = _parent[u]) { + e = _pred[u]; + d = _flow[e]; + if (_pred_dir[u] == DIR_UP) { + c = _cap[e]; + d = c >= MAX ? INF : c - d; + } + if (d <= delta) { + delta = d; + u_out = u; + result = 2; + } + } + + if (result == 1) { + u_in = first; + v_in = second; + } else { + u_in = second; + v_in = first; + } + return result != 0; + } + + // Change _flow and _state vectors + void changeFlow(bool change) { + // Augment along the cycle + if (delta > 0) { + Value val = _state[in_arc] * delta; + _flow[in_arc] += val; + for (int u = _source[in_arc]; u != join; u = _parent[u]) { + _flow[_pred[u]] -= _pred_dir[u] * val; + } + for (int u = _target[in_arc]; u != join; u = _parent[u]) { + _flow[_pred[u]] += _pred_dir[u] * val; + } + } + // Update the state of the entering and leaving arcs + if (change) { + _state[in_arc] = STATE_TREE; + _state[_pred[u_out]] = + (_flow[_pred[u_out]] == 0) ? STATE_LOWER : STATE_UPPER; + } else { + _state[in_arc] = -_state[in_arc]; + } + } + + // Update the tree structure + void updateTreeStructure() { + int old_rev_thread = _rev_thread[u_out]; + int old_succ_num = _succ_num[u_out]; + int old_last_succ = _last_succ[u_out]; + v_out = _parent[u_out]; + + // Check if u_in and u_out coincide + if (u_in == u_out) { + // Update _parent, _pred, _pred_dir + _parent[u_in] = v_in; + _pred[u_in] = in_arc; + _pred_dir[u_in] = u_in == _source[in_arc] ? DIR_UP : DIR_DOWN; + + // Update _thread and _rev_thread + if (_thread[v_in] != u_out) { + int after = _thread[old_last_succ]; + _thread[old_rev_thread] = after; + _rev_thread[after] = old_rev_thread; + after = _thread[v_in]; + _thread[v_in] = u_out; + _rev_thread[u_out] = v_in; + _thread[old_last_succ] = after; + _rev_thread[after] = old_last_succ; + } + } else { + // Handle the case when old_rev_thread equals to v_in + // (it also means that join and v_out coincide) + int thread_continue = old_rev_thread == v_in ? + _thread[old_last_succ] : _thread[v_in]; + + // Update _thread and _parent along the stem nodes (i.e. the nodes + // between u_in and u_out, whose parent have to be changed) + int stem = u_in; // the current stem node + int par_stem = v_in; // the new parent of stem + int next_stem; // the next stem node + int last = _last_succ[u_in]; // the last successor of stem + int before, after = _thread[last]; + _thread[v_in] = u_in; + _dirty_revs.clear(); + _dirty_revs.push_back(v_in); + while (stem != u_out) { + // Insert the next stem node into the thread list + next_stem = _parent[stem]; + _thread[last] = next_stem; + _dirty_revs.push_back(last); + + // Remove the subtree of stem from the thread list + before = _rev_thread[stem]; + _thread[before] = after; + _rev_thread[after] = before; + + // Change the parent node and shift stem nodes + _parent[stem] = par_stem; + par_stem = stem; + stem = next_stem; + + // Update last and after + last = _last_succ[stem] == _last_succ[par_stem] ? + _rev_thread[par_stem] : _last_succ[stem]; + after = _thread[last]; + } + _parent[u_out] = par_stem; + _thread[last] = thread_continue; + _rev_thread[thread_continue] = last; + _last_succ[u_out] = last; + + // Remove the subtree of u_out from the thread list except for + // the case when old_rev_thread equals to v_in + if (old_rev_thread != v_in) { + _thread[old_rev_thread] = after; + _rev_thread[after] = old_rev_thread; + } + + // Update _rev_thread using the new _thread values + for (int i = 0; i != int(_dirty_revs.size()); ++i) { + int u = _dirty_revs[i]; + _rev_thread[_thread[u]] = u; + } + + // Update _pred, _pred_dir, _last_succ and _succ_num for the + // stem nodes from u_out to u_in + int tmp_sc = 0, tmp_ls = _last_succ[u_out]; + for (int u = u_out, p = _parent[u]; u != u_in; u = p, p = _parent[u]) { + _pred[u] = _pred[p]; + _pred_dir[u] = -_pred_dir[p]; + tmp_sc += _succ_num[u] - _succ_num[p]; + _succ_num[u] = tmp_sc; + _last_succ[p] = tmp_ls; + } + _pred[u_in] = in_arc; + _pred_dir[u_in] = u_in == _source[in_arc] ? DIR_UP : DIR_DOWN; + _succ_num[u_in] = old_succ_num; + } + + // Update _last_succ from v_in towards the root + int up_limit_out = _last_succ[join] == v_in ? join : -1; + int last_succ_out = _last_succ[u_out]; + for (int u = v_in; u != -1 && _last_succ[u] == v_in; u = _parent[u]) { + _last_succ[u] = last_succ_out; + } + + // Update _last_succ from v_out towards the root + if (join != old_rev_thread && v_in != old_rev_thread) { + for (int u = v_out; u != up_limit_out && _last_succ[u] == old_last_succ; + u = _parent[u]) { + _last_succ[u] = old_rev_thread; + } + } + else if (last_succ_out != old_last_succ) { + for (int u = v_out; u != up_limit_out && _last_succ[u] == old_last_succ; + u = _parent[u]) { + _last_succ[u] = last_succ_out; + } + } + + // Update _succ_num from v_in to join + for (int u = v_in; u != join; u = _parent[u]) { + _succ_num[u] += old_succ_num; + } + // Update _succ_num from v_out to join + for (int u = v_out; u != join; u = _parent[u]) { + _succ_num[u] -= old_succ_num; + } + } + + // Update potentials in the subtree that has been moved + void updatePotential() { + Cost sigma = _pi[v_in] - _pi[u_in] - + _pred_dir[u_in] * _cost[in_arc]; + int end = _thread[_last_succ[u_in]]; + for (int u = u_in; u != end; u = _thread[u]) { + _pi[u] += sigma; + } + } + + // Heuristic initial pivots + bool initialPivots() { + Value curr, total = 0; + std::vector supply_nodes, demand_nodes; + for (NodeIt u(_graph); u != INVALID; ++u) { + curr = _supply[_node_id[u]]; + if (curr > 0) { + total += curr; + supply_nodes.push_back(u); + } + else if (curr < 0) { + demand_nodes.push_back(u); + } + } + if (_sum_supply > 0) total -= _sum_supply; + if (total <= 0) return true; + + IntVector arc_vector; + if (_sum_supply >= 0) { + if (supply_nodes.size() == 1 && demand_nodes.size() == 1) { + // Perform a reverse graph search from the sink to the source + typename GR::template NodeMap reached(_graph, false); + Node s = supply_nodes[0], t = demand_nodes[0]; + std::vector stack; + reached[t] = true; + stack.push_back(t); + while (!stack.empty()) { + Node u, v = stack.back(); + stack.pop_back(); + if (v == s) break; + for (InArcIt a(_graph, v); a != INVALID; ++a) { + if (reached[u = _graph.source(a)]) continue; + int j = _arc_id[a]; + if (_cap[j] >= total) { + arc_vector.push_back(j); + reached[u] = true; + stack.push_back(u); + } + } + } + } else { + // Find the min. cost incoming arc for each demand node + for (int i = 0; i != int(demand_nodes.size()); ++i) { + Node v = demand_nodes[i]; + Cost c, min_cost = std::numeric_limits::max(); + Arc min_arc = INVALID; + for (InArcIt a(_graph, v); a != INVALID; ++a) { + c = _cost[_arc_id[a]]; + if (c < min_cost) { + min_cost = c; + min_arc = a; + } + } + if (min_arc != INVALID) { + arc_vector.push_back(_arc_id[min_arc]); + } + } + } + } else { + // Find the min. cost outgoing arc for each supply node + for (int i = 0; i != int(supply_nodes.size()); ++i) { + Node u = supply_nodes[i]; + Cost c, min_cost = std::numeric_limits::max(); + Arc min_arc = INVALID; + for (OutArcIt a(_graph, u); a != INVALID; ++a) { + c = _cost[_arc_id[a]]; + if (c < min_cost) { + min_cost = c; + min_arc = a; + } + } + if (min_arc != INVALID) { + arc_vector.push_back(_arc_id[min_arc]); + } + } + } + + // Perform heuristic initial pivots + for (int i = 0; i != int(arc_vector.size()); ++i) { + in_arc = arc_vector[i]; + if (_state[in_arc] * (_cost[in_arc] + _pi[_source[in_arc]] - + _pi[_target[in_arc]]) >= 0) continue; + findJoinNode(); + bool change = findLeavingArc(); + if (delta >= MAX) return false; + changeFlow(change); + if (change) { + updateTreeStructure(); + updatePotential(); + } + } + return true; + } + + // Execute the algorithm + ProblemType start(PivotRule pivot_rule) { + // Select the pivot rule implementation + switch (pivot_rule) { + case FIRST_ELIGIBLE: + return start(); + case BEST_ELIGIBLE: + return start(); + case BLOCK_SEARCH: + return start(); + case CANDIDATE_LIST: + return start(); + case ALTERING_LIST: + return start(); + } + return INFEASIBLE; // avoid warning + } + + template + ProblemType start() { + PivotRuleImpl pivot(*this); + + // Perform heuristic initial pivots + if (!initialPivots()) return UNBOUNDED; + + // Execute the Network Simplex algorithm + while (pivot.findEnteringArc()) { + findJoinNode(); + bool change = findLeavingArc(); + if (delta >= MAX) return UNBOUNDED; + changeFlow(change); + if (change) { + updateTreeStructure(); + updatePotential(); + } + } + + // Check feasibility + for (int e = _search_arc_num; e != _all_arc_num; ++e) { + if (_flow[e] != 0) return INFEASIBLE; + } + + // Transform the solution and the supply map to the original form + if (_has_lower) { + for (int i = 0; i != _arc_num; ++i) { + Value c = _lower[i]; + if (c != 0) { + _flow[i] += c; + _supply[_source[i]] += c; + _supply[_target[i]] -= c; + } + } + } + + // Shift potentials to meet the requirements of the GEQ/LEQ type + // optimality conditions + if (_sum_supply == 0) { + if (_stype == GEQ) { + Cost max_pot = -std::numeric_limits::max(); + for (int i = 0; i != _node_num; ++i) { + if (_pi[i] > max_pot) max_pot = _pi[i]; + } + if (max_pot > 0) { + for (int i = 0; i != _node_num; ++i) + _pi[i] -= max_pot; + } + } else { + Cost min_pot = std::numeric_limits::max(); + for (int i = 0; i != _node_num; ++i) { + if (_pi[i] < min_pot) min_pot = _pi[i]; + } + if (min_pot < 0) { + for (int i = 0; i != _node_num; ++i) + _pi[i] -= min_pot; + } + } + } + + return OPTIMAL; + } + + }; //class NetworkSimplex + + ///@} + +} //namespace lemon + +#endif //LEMON_NETWORK_SIMPLEX_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/opt2_tsp.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/opt2_tsp.h new file mode 100644 index 00000000000..686cc9cb89d --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/opt2_tsp.h @@ -0,0 +1,367 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_OPT2_TSP_H +#define LEMON_OPT2_TSP_H + +/// \ingroup tsp +/// \file +/// \brief 2-opt algorithm for symmetric TSP. + +#include +#include + +namespace lemon { + + /// \ingroup tsp + /// + /// \brief 2-opt algorithm for symmetric TSP. + /// + /// Opt2Tsp implements the 2-opt heuristic for solving + /// symmetric \ref tsp "TSP". + /// + /// This algorithm starts with an initial tour and iteratively improves it. + /// At each step, it removes two edges and the reconnects the created two + /// paths in the other way if the resulting tour is shorter. + /// The algorithm finishes when no such 2-opt move can be applied, and so + /// the tour is 2-optimal. + /// + /// If no starting tour is given to the \ref run() function, then the + /// algorithm uses the node sequence determined by the node IDs. + /// Oherwise, it starts with the given tour. + /// + /// This is a rather slow but effective method. + /// Its typical usage is the improvement of the result of a fast tour + /// construction heuristic (e.g. the InsertionTsp algorithm). + /// + /// \tparam CM Type of the cost map. + template + class Opt2Tsp + { + public: + + /// Type of the cost map + typedef CM CostMap; + /// Type of the edge costs + typedef typename CM::Value Cost; + + private: + + GRAPH_TYPEDEFS(FullGraph); + + const FullGraph &_gr; + const CostMap &_cost; + Cost _sum; + std::vector _plist; + std::vector _path; + + public: + + /// \brief Constructor + /// + /// Constructor. + /// \param gr The \ref FullGraph "full graph" the algorithm runs on. + /// \param cost The cost map. + Opt2Tsp(const FullGraph &gr, const CostMap &cost) + : _gr(gr), _cost(cost) {} + + /// \name Execution Control + /// @{ + + /// \brief Runs the algorithm from scratch. + /// + /// This function runs the algorithm starting from the tour that is + /// determined by the node ID sequence. + /// + /// \return The total cost of the found tour. + Cost run() { + _path.clear(); + + if (_gr.nodeNum() == 0) return _sum = 0; + else if (_gr.nodeNum() == 1) { + _path.push_back(_gr(0)); + return _sum = 0; + } + else if (_gr.nodeNum() == 2) { + _path.push_back(_gr(0)); + _path.push_back(_gr(1)); + return _sum = 2 * _cost[_gr.edge(_gr(0), _gr(1))]; + } + + _plist.resize(2*_gr.nodeNum()); + for (int i = 1; i < _gr.nodeNum()-1; ++i) { + _plist[2*i] = i-1; + _plist[2*i+1] = i+1; + } + _plist[0] = _gr.nodeNum()-1; + _plist[1] = 1; + _plist[2*_gr.nodeNum()-2] = _gr.nodeNum()-2; + _plist[2*_gr.nodeNum()-1] = 0; + + return start(); + } + + /// \brief Runs the algorithm starting from the given tour. + /// + /// This function runs the algorithm starting from the given tour. + /// + /// \param tour The tour as a path structure. It must be a + /// \ref checkPath() "valid path" containing excactly n arcs. + /// + /// \return The total cost of the found tour. + template + Cost run(const Path& tour) { + _path.clear(); + + if (_gr.nodeNum() == 0) return _sum = 0; + else if (_gr.nodeNum() == 1) { + _path.push_back(_gr(0)); + return _sum = 0; + } + else if (_gr.nodeNum() == 2) { + _path.push_back(_gr(0)); + _path.push_back(_gr(1)); + return _sum = 2 * _cost[_gr.edge(_gr(0), _gr(1))]; + } + + _plist.resize(2*_gr.nodeNum()); + typename Path::ArcIt it(tour); + int first = _gr.id(_gr.source(it)), + prev = first, + curr = _gr.id(_gr.target(it)), + next = -1; + _plist[2*first+1] = curr; + for (++it; it != INVALID; ++it) { + next = _gr.id(_gr.target(it)); + _plist[2*curr] = prev; + _plist[2*curr+1] = next; + prev = curr; + curr = next; + } + _plist[2*first] = prev; + + return start(); + } + + /// \brief Runs the algorithm starting from the given tour. + /// + /// This function runs the algorithm starting from the given tour + /// (node sequence). + /// + /// \param tour A vector that stores all Nodes of the graph + /// in the desired order. + /// + /// \return The total cost of the found tour. + Cost run(const std::vector& tour) { + _path.clear(); + + if (_gr.nodeNum() == 0) return _sum = 0; + else if (_gr.nodeNum() == 1) { + _path.push_back(_gr(0)); + return _sum = 0; + } + else if (_gr.nodeNum() == 2) { + _path.push_back(_gr(0)); + _path.push_back(_gr(1)); + return _sum = 2 * _cost[_gr.edge(_gr(0), _gr(1))]; + } + + _plist.resize(2*_gr.nodeNum()); + typename std::vector::const_iterator it = tour.begin(); + int first = _gr.id(*it), + prev = first, + curr = _gr.id(*(++it)), + next = -1; + _plist[2*first+1] = curr; + for (++it; it != tour.end(); ++it) { + next = _gr.id(*it); + _plist[2*curr] = prev; + _plist[2*curr+1] = next; + prev = curr; + curr = next; + } + _plist[2*first] = curr; + _plist[2*curr] = prev; + _plist[2*curr+1] = first; + + return start(); + } + + /// @} + + /// \name Query Functions + /// @{ + + /// \brief The total cost of the found tour. + /// + /// This function returns the total cost of the found tour. + /// + /// \pre run() must be called before using this function. + Cost tourCost() const { + return _sum; + } + + /// \brief Returns a const reference to the node sequence of the + /// found tour. + /// + /// This function returns a const reference to a vector + /// that stores the node sequence of the found tour. + /// + /// \pre run() must be called before using this function. + const std::vector& tourNodes() const { + return _path; + } + + /// \brief Gives back the node sequence of the found tour. + /// + /// This function copies the node sequence of the found tour into + /// an STL container through the given output iterator. The + /// value_type of the container must be FullGraph::Node. + /// For example, + /// \code + /// std::vector nodes(countNodes(graph)); + /// tsp.tourNodes(nodes.begin()); + /// \endcode + /// or + /// \code + /// std::list nodes; + /// tsp.tourNodes(std::back_inserter(nodes)); + /// \endcode + /// + /// \pre run() must be called before using this function. + template + void tourNodes(Iterator out) const { + std::copy(_path.begin(), _path.end(), out); + } + + /// \brief Gives back the found tour as a path. + /// + /// This function copies the found tour as a list of arcs/edges into + /// the given \ref lemon::concepts::Path "path structure". + /// + /// \pre run() must be called before using this function. + template + void tour(Path &path) const { + path.clear(); + for (int i = 0; i < int(_path.size()) - 1; ++i) { + path.addBack(_gr.arc(_path[i], _path[i+1])); + } + if (int(_path.size()) >= 2) { + path.addBack(_gr.arc(_path.back(), _path.front())); + } + } + + /// @} + + private: + + // Iterator class for the linked list storage of the tour + class PathListIt { + public: + PathListIt(const std::vector &pl, int i=0) + : plist(&pl), act(i), last(pl[2*act]) {} + PathListIt(const std::vector &pl, int i, int l) + : plist(&pl), act(i), last(l) {} + + int nextIndex() const { + return (*plist)[2*act] == last ? 2*act+1 : 2*act; + } + + int prevIndex() const { + return (*plist)[2*act] == last ? 2*act : 2*act+1; + } + + int next() const { + int x = (*plist)[2*act]; + return x == last ? (*plist)[2*act+1] : x; + } + + int prev() const { + return last; + } + + PathListIt& operator++() { + int tmp = act; + act = next(); + last = tmp; + return *this; + } + + operator int() const { + return act; + } + + private: + const std::vector *plist; + int act; + int last; + }; + + // Checks and applies 2-opt move (if it improves the tour) + bool checkOpt2(const PathListIt& i, const PathListIt& j) { + Node u = _gr.nodeFromId(i), + un = _gr.nodeFromId(i.next()), + v = _gr.nodeFromId(j), + vn = _gr.nodeFromId(j.next()); + + if (_cost[_gr.edge(u, un)] + _cost[_gr.edge(v, vn)] > + _cost[_gr.edge(u, v)] + _cost[_gr.edge(un, vn)]) + { + _plist[PathListIt(_plist, i.next(), i).prevIndex()] = j.next(); + _plist[PathListIt(_plist, j.next(), j).prevIndex()] = i.next(); + + _plist[i.nextIndex()] = j; + _plist[j.nextIndex()] = i; + + return true; + } + + return false; + } + + // Executes the algorithm from the initial tour + Cost start() { + + restart_search: + for (PathListIt i(_plist); true; ++i) { + PathListIt j = i; + if (++j == 0 || ++j == 0) break; + for (; j != 0 && j != i.prev(); ++j) { + if (checkOpt2(i, j)) + goto restart_search; + } + } + + PathListIt i(_plist); + _path.push_back(_gr.nodeFromId(i)); + for (++i; i != 0; ++i) + _path.push_back(_gr.nodeFromId(i)); + + _sum = _cost[_gr.edge(_path.back(), _path.front())]; + for (int i = 0; i < int(_path.size())-1; ++i) { + _sum += _cost[_gr.edge(_path[i], _path[i+1])]; + } + + return _sum; + } + + }; + +}; // namespace lemon + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/pairing_heap.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/pairing_heap.h new file mode 100644 index 00000000000..da6ebcb1552 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/pairing_heap.h @@ -0,0 +1,474 @@ +/* -*- 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_PAIRING_HEAP_H +#define LEMON_PAIRING_HEAP_H + +///\file +///\ingroup heaps +///\brief Pairing heap implementation. + +#include +#include +#include +#include + +namespace lemon { + + /// \ingroup heaps + /// + ///\brief Pairing Heap. + /// + /// This class implements the \e pairing \e heap data structure. + /// It fully conforms to the \ref concepts::Heap "heap concept". + /// + /// The methods \ref increase() and \ref erase() are not efficient + /// in a pairing heap. In case of many calls of these operations, + /// it is better to use other heap structure, e.g. \ref BinHeap + /// "binary heap". + /// + /// \tparam PR Type of the priorities of the items. + /// \tparam IM A read-writable item map with \c int values, used + /// internally to handle the cross references. + /// \tparam CMP A functor class for comparing the priorities. + /// The default is \c std::less. +#ifdef DOXYGEN + template +#else + template > +#endif + class PairingHeap { + public: + /// Type of the item-int map. + typedef IM ItemIntMap; + /// Type of the priorities. + typedef PR Prio; + /// Type of the items stored in the heap. + typedef typename ItemIntMap::Key Item; + /// Functor type for comparing the priorities. + typedef CMP Compare; + + /// \brief Type to represent the states of the items. + /// + /// Each item has a state associated to it. It can be "in heap", + /// "pre-heap" or "post-heap". The latter two are indifferent from the + /// heap's point of view, but may be useful to the user. + /// + /// The item-int map must be initialized in such way that it assigns + /// \c PRE_HEAP (-1) to any element to be put in the heap. + enum State { + IN_HEAP = 0, ///< = 0. + PRE_HEAP = -1, ///< = -1. + POST_HEAP = -2 ///< = -2. + }; + + private: + class store; + + std::vector _data; + int _min; + ItemIntMap &_iim; + Compare _comp; + int _num_items; + + public: + /// \brief Constructor. + /// + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. + explicit PairingHeap(ItemIntMap &map) + : _min(0), _iim(map), _num_items(0) {} + + /// \brief Constructor. + /// + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. + /// \param comp The function object used for comparing the priorities. + PairingHeap(ItemIntMap &map, const Compare &comp) + : _min(0), _iim(map), _comp(comp), _num_items(0) {} + + /// \brief The number of items stored in the heap. + /// + /// This function returns the number of items stored in the heap. + int size() const { return _num_items; } + + /// \brief Check if the heap is empty. + /// + /// This function returns \c true if the heap is empty. + bool empty() const { return _num_items==0; } + + /// \brief Make the heap empty. + /// + /// This functon makes the heap empty. + /// It does not change the cross reference map. If you want to reuse + /// a heap that is not surely empty, you should first clear it and + /// then you should set the cross reference map to \c PRE_HEAP + /// for each item. + void clear() { + _data.clear(); + _min = 0; + _num_items = 0; + } + + /// \brief Set the priority of an item or insert it, if it is + /// not stored in the heap. + /// + /// This method sets the priority of the given item if it is + /// already stored in the heap. Otherwise it inserts the given + /// item into the heap with the given priority. + /// \param item The item. + /// \param value The priority. + void set (const Item& item, const Prio& value) { + int i=_iim[item]; + if ( i>=0 && _data[i].in ) { + if ( _comp(value, _data[i].prio) ) decrease(item, value); + if ( _comp(_data[i].prio, value) ) increase(item, value); + } else push(item, value); + } + + /// \brief Insert an item into the heap with the given priority. + /// + /// This function inserts the given item into the heap with the + /// given priority. + /// \param item The item to insert. + /// \param value The priority of the item. + /// \pre \e item must not be stored in the heap. + void push (const Item& item, const Prio& value) { + int i=_iim[item]; + if( i<0 ) { + int s=_data.size(); + _iim.set(item, s); + store st; + st.name=item; + _data.push_back(st); + i=s; + } else { + _data[i].parent=_data[i].child=-1; + _data[i].left_child=false; + _data[i].degree=0; + _data[i].in=true; + } + + _data[i].prio=value; + + if ( _num_items!=0 ) { + if ( _comp( value, _data[_min].prio) ) { + fuse(i,_min); + _min=i; + } + else fuse(_min,i); + } + else _min=i; + + ++_num_items; + } + + /// \brief Return the item having minimum priority. + /// + /// This function returns the item having minimum priority. + /// \pre The heap must be non-empty. + Item top() const { return _data[_min].name; } + + /// \brief The minimum priority. + /// + /// This function returns the minimum priority. + /// \pre The heap must be non-empty. + const Prio& prio() const { return _data[_min].prio; } + + /// \brief The priority of the given item. + /// + /// This function returns the priority of the given item. + /// \param item The item. + /// \pre \e item must be in the heap. + const Prio& operator[](const Item& item) const { + return _data[_iim[item]].prio; + } + + /// \brief Remove the item having minimum priority. + /// + /// This function removes the item having minimum priority. + /// \pre The heap must be non-empty. + void pop() { + std::vector trees; + int i=0, child_right = 0; + _data[_min].in=false; + + if( -1!=_data[_min].child ) { + i=_data[_min].child; + trees.push_back(i); + _data[i].parent = -1; + _data[_min].child = -1; + + int ch=-1; + while( _data[i].child!=-1 ) { + ch=_data[i].child; + if( _data[ch].left_child && i==_data[ch].parent ) { + break; + } else { + if( _data[ch].left_child ) { + child_right=_data[ch].parent; + _data[ch].parent = i; + --_data[i].degree; + } + else { + child_right=ch; + _data[i].child=-1; + _data[i].degree=0; + } + _data[child_right].parent = -1; + trees.push_back(child_right); + i = child_right; + } + } + + int num_child = trees.size(); + int other; + for( i=0; i=2) { + if ( _comp(_data[trees[i]].prio, _data[trees[i-2]].prio) ) { + other=trees[i]; + trees[i]=trees[i-2]; + trees[i-2]=other; + } + fuse( trees[i-2], trees[i] ); + i-=2; + } + _min = trees[0]; + } + else { + _min = _data[_min].child; + } + + if (_min >= 0) _data[_min].left_child = false; + --_num_items; + } + + /// \brief Remove the given item from the heap. + /// + /// This function removes the given item from the heap if it is + /// already stored. + /// \param item The item to delete. + /// \pre \e item must be in the heap. + void erase (const Item& item) { + int i=_iim[item]; + if ( i>=0 && _data[i].in ) { + decrease( item, _data[_min].prio-1 ); + pop(); + } + } + + /// \brief Decrease the priority of an item to the given value. + /// + /// This function decreases the priority of an item to the given value. + /// \param item The item. + /// \param value The priority. + /// \pre \e item must be stored in the heap with priority at least \e value. + void decrease (Item item, const Prio& value) { + int i=_iim[item]; + _data[i].prio=value; + int p=_data[i].parent; + + if( _data[i].left_child && i!=_data[p].child ) { + p=_data[p].parent; + } + + if ( p!=-1 && _comp(value,_data[p].prio) ) { + cut(i,p); + if ( _comp(_data[_min].prio,value) ) { + fuse(_min,i); + } else { + fuse(i,_min); + _min=i; + } + } + } + + /// \brief Increase the priority of an item to the given value. + /// + /// This function increases the priority of an item to the given value. + /// \param item The item. + /// \param value The priority. + /// \pre \e item must be stored in the heap with priority at most \e value. + void increase (Item item, const Prio& value) { + erase(item); + push(item,value); + } + + /// \brief Return the state of an item. + /// + /// This method returns \c PRE_HEAP if the given item has never + /// been in the heap, \c IN_HEAP if it is in the heap at the moment, + /// and \c POST_HEAP otherwise. + /// In the latter case it is possible that the item will get back + /// to the heap again. + /// \param item The item. + State state(const Item &item) const { + int i=_iim[item]; + if( i>=0 ) { + if( _data[i].in ) i=0; + else i=-2; + } + return State(i); + } + + /// \brief Set the state of an item in the heap. + /// + /// This function sets the state of the given item in the heap. + /// It can be used to manually clear the heap when it is important + /// to achive better time complexity. + /// \param i The item. + /// \param st The state. It should not be \c IN_HEAP. + void state(const Item& i, State st) { + switch (st) { + case POST_HEAP: + case PRE_HEAP: + if (state(i) == IN_HEAP) erase(i); + _iim[i]=st; + break; + case IN_HEAP: + break; + } + } + + private: + + void cut(int a, int b) { + int child_a; + switch (_data[a].degree) { + case 2: + child_a = _data[_data[a].child].parent; + if( _data[a].left_child ) { + _data[child_a].left_child=true; + _data[b].child=child_a; + _data[child_a].parent=_data[a].parent; + } + else { + _data[child_a].left_child=false; + _data[child_a].parent=b; + if( a!=_data[b].child ) + _data[_data[b].child].parent=child_a; + else + _data[b].child=child_a; + } + --_data[a].degree; + _data[_data[a].child].parent=a; + break; + + case 1: + child_a = _data[a].child; + if( !_data[child_a].left_child ) { + --_data[a].degree; + if( _data[a].left_child ) { + _data[child_a].left_child=true; + _data[child_a].parent=_data[a].parent; + _data[b].child=child_a; + } + else { + _data[child_a].left_child=false; + _data[child_a].parent=b; + if( a!=_data[b].child ) + _data[_data[b].child].parent=child_a; + else + _data[b].child=child_a; + } + _data[a].child=-1; + } + else { + --_data[b].degree; + if( _data[a].left_child ) { + _data[b].child = + (1==_data[b].degree) ? _data[a].parent : -1; + } else { + if (1==_data[b].degree) + _data[_data[b].child].parent=b; + else + _data[b].child=-1; + } + } + break; + + case 0: + --_data[b].degree; + if( _data[a].left_child ) { + _data[b].child = + (0!=_data[b].degree) ? _data[a].parent : -1; + } else { + if( 0!=_data[b].degree ) + _data[_data[b].child].parent=b; + else + _data[b].child=-1; + } + break; + } + _data[a].parent=-1; + _data[a].left_child=false; + } + + void fuse(int a, int b) { + int child_a = _data[a].child; + int child_b = _data[b].child; + _data[a].child=b; + _data[b].parent=a; + _data[b].left_child=true; + + if( -1!=child_a ) { + _data[b].child=child_a; + _data[child_a].parent=b; + _data[child_a].left_child=false; + ++_data[b].degree; + + if( -1!=child_b ) { + _data[b].child=child_b; + _data[child_b].parent=child_a; + } + } + else { ++_data[a].degree; } + } + + class store { + friend class PairingHeap; + + Item name; + int parent; + int child; + bool left_child; + int degree; + bool in; + Prio prio; + + store() : parent(-1), child(-1), left_child(false), degree(0), in(true) {} + }; + }; + +} //namespace lemon + +#endif //LEMON_PAIRING_HEAP_H + diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/path.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/path.h new file mode 100644 index 00000000000..baa92c48baa --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/path.h @@ -0,0 +1,1164 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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. + * + */ + +///\ingroup paths +///\file +///\brief Classes for representing paths in digraphs. +/// + +#ifndef LEMON_PATH_H +#define LEMON_PATH_H + +#include +#include + +#include +#include +#include + +namespace lemon { + + /// \addtogroup paths + /// @{ + + + /// \brief A structure for representing directed paths in a digraph. + /// + /// A structure for representing directed path in a digraph. + /// \tparam GR The digraph type in which the path is. + /// + /// In a sense, the path can be treated as a list of arcs. The + /// LEMON path type stores just this list. As a consequence, it + /// cannot enumerate the nodes of the path and the source node of + /// a zero length path is undefined. + /// + /// This implementation is a back and front insertable and erasable + /// path type. It can be indexed in O(1) time. The front and back + /// insertion and erase is done in O(1) (amortized) time. The + /// implementation uses two vectors for storing the front and back + /// insertions. + template + class Path { + public: + + typedef GR Digraph; + typedef typename Digraph::Arc Arc; + + /// \brief Default constructor + /// + /// Default constructor + Path() {} + + /// \brief Copy constructor + /// + Path(const Path& cpath) { + pathCopy(cpath, *this); + } + + /// \brief Template copy constructor + /// + /// This constuctor initializes the path from any other path type. + /// It simply makes a copy of the given path. + template + Path(const CPath& cpath) { + pathCopy(cpath, *this); + } + + /// \brief Copy assignment + /// + Path& operator=(const Path& cpath) { + pathCopy(cpath, *this); + return *this; + } + + /// \brief Template copy assignment + /// + /// This operator makes a copy of a path of any other type. + template + Path& operator=(const CPath& cpath) { + pathCopy(cpath, *this); + return *this; + } + + /// \brief LEMON style iterator for path arcs + /// + /// This class is used to iterate on the arcs of the paths. + class ArcIt { + friend class Path; + public: + /// \brief Default constructor + ArcIt() {} + /// \brief Invalid constructor + ArcIt(Invalid) : path(0), idx(-1) {} + /// \brief Initializate the iterator to the first arc of path + ArcIt(const Path &_path) + : path(&_path), idx(_path.empty() ? -1 : 0) {} + + private: + + ArcIt(const Path &_path, int _idx) + : path(&_path), idx(_idx) {} + + public: + + /// \brief Conversion to Arc + operator const Arc&() const { + return path->nth(idx); + } + + /// \brief Next arc + ArcIt& operator++() { + ++idx; + if (idx >= path->length()) idx = -1; + return *this; + } + + /// \brief Comparison operator + bool operator==(const ArcIt& e) const { return idx==e.idx; } + /// \brief Comparison operator + bool operator!=(const ArcIt& e) const { return idx!=e.idx; } + /// \brief Comparison operator + bool operator<(const ArcIt& e) const { return idx[0..length() - 1] range. + const Arc& nth(int n) const { + return n < int(head.size()) ? *(head.rbegin() + n) : + *(tail.begin() + (n - head.size())); + } + + /// \brief Initialize arc iterator to point to the n-th arc + /// + /// \pre \c n is in the [0..length() - 1] range. + ArcIt nthIt(int n) const { + return ArcIt(*this, n); + } + + /// \brief The first arc of the path + const Arc& front() const { + return head.empty() ? tail.front() : head.back(); + } + + /// \brief Add a new arc before the current path + void addFront(const Arc& arc) { + head.push_back(arc); + } + + /// \brief Erase the first arc of the path + void eraseFront() { + if (!head.empty()) { + head.pop_back(); + } else { + head.clear(); + int halfsize = tail.size() / 2; + head.resize(halfsize); + std::copy(tail.begin() + 1, tail.begin() + halfsize + 1, + head.rbegin()); + std::copy(tail.begin() + halfsize + 1, tail.end(), tail.begin()); + tail.resize(tail.size() - halfsize - 1); + } + } + + /// \brief The last arc of the path + const Arc& back() const { + return tail.empty() ? head.front() : tail.back(); + } + + /// \brief Add a new arc behind the current path + void addBack(const Arc& arc) { + tail.push_back(arc); + } + + /// \brief Erase the last arc of the path + void eraseBack() { + if (!tail.empty()) { + tail.pop_back(); + } else { + int halfsize = head.size() / 2; + tail.resize(halfsize); + std::copy(head.begin() + 1, head.begin() + halfsize + 1, + tail.rbegin()); + std::copy(head.begin() + halfsize + 1, head.end(), head.begin()); + head.resize(head.size() - halfsize - 1); + } + } + + typedef True BuildTag; + + template + void build(const CPath& path) { + int len = path.length(); + tail.reserve(len); + for (typename CPath::ArcIt it(path); it != INVALID; ++it) { + tail.push_back(it); + } + } + + template + void buildRev(const CPath& path) { + int len = path.length(); + head.reserve(len); + for (typename CPath::RevArcIt it(path); it != INVALID; ++it) { + head.push_back(it); + } + } + + protected: + typedef std::vector Container; + Container head, tail; + + }; + + /// \brief A structure for representing directed paths in a digraph. + /// + /// A structure for representing directed path in a digraph. + /// \tparam GR The digraph type in which the path is. + /// + /// In a sense, the path can be treated as a list of arcs. The + /// LEMON path type stores just this list. As a consequence it + /// cannot enumerate the nodes in the path and the zero length paths + /// cannot store the source. + /// + /// This implementation is a just back insertable and erasable path + /// type. It can be indexed in O(1) time. The back insertion and + /// erasure is amortized O(1) time. This implementation is faster + /// then the \c Path type because it use just one vector for the + /// arcs. + template + class SimplePath { + public: + + typedef GR Digraph; + typedef typename Digraph::Arc Arc; + + /// \brief Default constructor + /// + /// Default constructor + SimplePath() {} + + /// \brief Copy constructor + /// + SimplePath(const SimplePath& cpath) { + pathCopy(cpath, *this); + } + + /// \brief Template copy constructor + /// + /// This path can be initialized with any other path type. It just + /// makes a copy of the given path. + template + SimplePath(const CPath& cpath) { + pathCopy(cpath, *this); + } + + /// \brief Copy assignment + /// + SimplePath& operator=(const SimplePath& cpath) { + pathCopy(cpath, *this); + return *this; + } + + /// \brief Template copy assignment + /// + /// This path can be initialized with any other path type. It just + /// makes a copy of the given path. + template + SimplePath& operator=(const CPath& cpath) { + pathCopy(cpath, *this); + return *this; + } + + /// \brief Iterator class to iterate on the arcs of the paths + /// + /// This class is used to iterate on the arcs of the paths + /// + /// Of course it converts to Digraph::Arc + class ArcIt { + friend class SimplePath; + public: + /// Default constructor + ArcIt() {} + /// Invalid constructor + ArcIt(Invalid) : path(0), idx(-1) {} + /// \brief Initializate the constructor to the first arc of path + ArcIt(const SimplePath &_path) + : path(&_path), idx(_path.empty() ? -1 : 0) {} + + private: + + /// Constructor with starting point + ArcIt(const SimplePath &_path, int _idx) + : path(&_path), idx(_idx) {} + + public: + + ///Conversion to Digraph::Arc + operator const Arc&() const { + return path->nth(idx); + } + + /// Next arc + ArcIt& operator++() { + ++idx; + if (idx >= path->length()) idx = -1; + return *this; + } + + /// Comparison operator + bool operator==(const ArcIt& e) const { return idx==e.idx; } + /// Comparison operator + bool operator!=(const ArcIt& e) const { return idx!=e.idx; } + /// Comparison operator + bool operator<(const ArcIt& e) const { return idx[0..length() - 1] range. + const Arc& nth(int n) const { + return data[n]; + } + + /// \brief Initializes arc iterator to point to the n-th arc. + ArcIt nthIt(int n) const { + return ArcIt(*this, n); + } + + /// \brief The first arc of the path. + const Arc& front() const { + return data.front(); + } + + /// \brief The last arc of the path. + const Arc& back() const { + return data.back(); + } + + /// \brief Add a new arc behind the current path. + void addBack(const Arc& arc) { + data.push_back(arc); + } + + /// \brief Erase the last arc of the path + void eraseBack() { + data.pop_back(); + } + + typedef True BuildTag; + + template + void build(const CPath& path) { + int len = path.length(); + data.resize(len); + int index = 0; + for (typename CPath::ArcIt it(path); it != INVALID; ++it) { + data[index] = it;; + ++index; + } + } + + template + void buildRev(const CPath& path) { + int len = path.length(); + data.resize(len); + int index = len; + for (typename CPath::RevArcIt it(path); it != INVALID; ++it) { + --index; + data[index] = it;; + } + } + + protected: + typedef std::vector Container; + Container data; + + }; + + /// \brief A structure for representing directed paths in a digraph. + /// + /// A structure for representing directed path in a digraph. + /// \tparam GR The digraph type in which the path is. + /// + /// In a sense, the path can be treated as a list of arcs. The + /// LEMON path type stores just this list. As a consequence it + /// cannot enumerate the nodes in the path and the zero length paths + /// cannot store the source. + /// + /// This implementation is a back and front insertable and erasable + /// path type. It can be indexed in O(k) time, where k is the rank + /// of the arc in the path. The length can be computed in O(n) + /// time. The front and back insertion and erasure is O(1) time + /// and it can be splited and spliced in O(1) time. + template + class ListPath { + public: + + typedef GR Digraph; + typedef typename Digraph::Arc Arc; + + protected: + + // the std::list<> is incompatible + // hard to create invalid iterator + struct Node { + Arc arc; + Node *next, *prev; + }; + + Node *first, *last; + + std::allocator alloc; + + public: + + /// \brief Default constructor + /// + /// Default constructor + ListPath() : first(0), last(0) {} + + /// \brief Copy constructor + /// + ListPath(const ListPath& cpath) : first(0), last(0) { + pathCopy(cpath, *this); + } + + /// \brief Template copy constructor + /// + /// This path can be initialized with any other path type. It just + /// makes a copy of the given path. + template + ListPath(const CPath& cpath) : first(0), last(0) { + pathCopy(cpath, *this); + } + + /// \brief Destructor of the path + /// + /// Destructor of the path + ~ListPath() { + clear(); + } + + /// \brief Copy assignment + /// + ListPath& operator=(const ListPath& cpath) { + pathCopy(cpath, *this); + return *this; + } + + /// \brief Template copy assignment + /// + /// This path can be initialized with any other path type. It just + /// makes a copy of the given path. + template + ListPath& operator=(const CPath& cpath) { + pathCopy(cpath, *this); + return *this; + } + + /// \brief Iterator class to iterate on the arcs of the paths + /// + /// This class is used to iterate on the arcs of the paths + /// + /// Of course it converts to Digraph::Arc + class ArcIt { + friend class ListPath; + public: + /// Default constructor + ArcIt() {} + /// Invalid constructor + ArcIt(Invalid) : path(0), node(0) {} + /// \brief Initializate the constructor to the first arc of path + ArcIt(const ListPath &_path) + : path(&_path), node(_path.first) {} + + protected: + + ArcIt(const ListPath &_path, Node *_node) + : path(&_path), node(_node) {} + + + public: + + ///Conversion to Digraph::Arc + operator const Arc&() const { + return node->arc; + } + + /// Next arc + ArcIt& operator++() { + node = node->next; + return *this; + } + + /// Comparison operator + bool operator==(const ArcIt& e) const { return node==e.node; } + /// Comparison operator + bool operator!=(const ArcIt& e) const { return node!=e.node; } + /// Comparison operator + bool operator<(const ArcIt& e) const { return node[0..length() - 1] range. + const Arc& nth(int n) const { + Node *node = first; + for (int i = 0; i < n; ++i) { + node = node->next; + } + return node->arc; + } + + /// \brief Initializes arc iterator to point to the n-th arc. + ArcIt nthIt(int n) const { + Node *node = first; + for (int i = 0; i < n; ++i) { + node = node->next; + } + return ArcIt(*this, node); + } + + /// \brief Length of the path. + int length() const { + int len = 0; + Node *node = first; + while (node != 0) { + node = node->next; + ++len; + } + return len; + } + + /// \brief Return true if the path is empty. + bool empty() const { return first == 0; } + + /// \brief Reset the path to an empty one. + void clear() { + while (first != 0) { + last = first->next; + alloc.destroy(first); + alloc.deallocate(first, 1); + first = last; + } + } + + /// \brief The first arc of the path + const Arc& front() const { + return first->arc; + } + + /// \brief Add a new arc before the current path + void addFront(const Arc& arc) { + Node *node = alloc.allocate(1); + alloc.construct(node, Node()); + node->prev = 0; + node->next = first; + node->arc = arc; + if (first) { + first->prev = node; + first = node; + } else { + first = last = node; + } + } + + /// \brief Erase the first arc of the path + void eraseFront() { + Node *node = first; + first = first->next; + if (first) { + first->prev = 0; + } else { + last = 0; + } + alloc.destroy(node); + alloc.deallocate(node, 1); + } + + /// \brief The last arc of the path. + const Arc& back() const { + return last->arc; + } + + /// \brief Add a new arc behind the current path. + void addBack(const Arc& arc) { + Node *node = alloc.allocate(1); + alloc.construct(node, Node()); + node->next = 0; + node->prev = last; + node->arc = arc; + if (last) { + last->next = node; + last = node; + } else { + last = first = node; + } + } + + /// \brief Erase the last arc of the path + void eraseBack() { + Node *node = last; + last = last->prev; + if (last) { + last->next = 0; + } else { + first = 0; + } + alloc.destroy(node); + alloc.deallocate(node, 1); + } + + /// \brief Splice a path to the back of the current path. + /// + /// It splices \c tpath to the back of the current path and \c + /// tpath becomes empty. The time complexity of this function is + /// O(1). + void spliceBack(ListPath& tpath) { + if (first) { + if (tpath.first) { + last->next = tpath.first; + tpath.first->prev = last; + last = tpath.last; + } + } else { + first = tpath.first; + last = tpath.last; + } + tpath.first = tpath.last = 0; + } + + /// \brief Splice a path to the front of the current path. + /// + /// It splices \c tpath before the current path and \c tpath + /// becomes empty. The time complexity of this function + /// is O(1). + void spliceFront(ListPath& tpath) { + if (first) { + if (tpath.first) { + first->prev = tpath.last; + tpath.last->next = first; + first = tpath.first; + } + } else { + first = tpath.first; + last = tpath.last; + } + tpath.first = tpath.last = 0; + } + + /// \brief Splice a path into the current path. + /// + /// It splices the \c tpath into the current path before the + /// position of \c it iterator and \c tpath becomes empty. The + /// time complexity of this function is O(1). If the \c it is + /// \c INVALID then it will splice behind the current path. + void splice(ArcIt it, ListPath& tpath) { + if (it.node) { + if (tpath.first) { + tpath.first->prev = it.node->prev; + if (it.node->prev) { + it.node->prev->next = tpath.first; + } else { + first = tpath.first; + } + it.node->prev = tpath.last; + tpath.last->next = it.node; + } + } else { + if (first) { + if (tpath.first) { + last->next = tpath.first; + tpath.first->prev = last; + last = tpath.last; + } + } else { + first = tpath.first; + last = tpath.last; + } + } + tpath.first = tpath.last = 0; + } + + /// \brief Split the current path. + /// + /// It splits the current path into two parts. The part before + /// the iterator \c it will remain in the current path and the part + /// starting with + /// \c it will put into \c tpath. If \c tpath have arcs + /// before the operation they are removed first. The time + /// complexity of this function is O(1) plus the the time of emtying + /// \c tpath. If \c it is \c INVALID then it just clears \c tpath + void split(ArcIt it, ListPath& tpath) { + tpath.clear(); + if (it.node) { + tpath.first = it.node; + tpath.last = last; + if (it.node->prev) { + last = it.node->prev; + last->next = 0; + } else { + first = last = 0; + } + it.node->prev = 0; + } + } + + + typedef True BuildTag; + + template + void build(const CPath& path) { + for (typename CPath::ArcIt it(path); it != INVALID; ++it) { + addBack(it); + } + } + + template + void buildRev(const CPath& path) { + for (typename CPath::RevArcIt it(path); it != INVALID; ++it) { + addFront(it); + } + } + + }; + + /// \brief A structure for representing directed paths in a digraph. + /// + /// A structure for representing directed path in a digraph. + /// \tparam GR The digraph type in which the path is. + /// + /// In a sense, the path can be treated as a list of arcs. The + /// LEMON path type stores just this list. As a consequence it + /// cannot enumerate the nodes in the path and the source node of + /// a zero length path is undefined. + /// + /// This implementation is completly static, i.e. it can be copy constucted + /// or copy assigned from another path, but otherwise it cannot be + /// modified. + /// + /// Being the the most memory efficient path type in LEMON, + /// it is intented to be + /// used when you want to store a large number of paths. + template + class StaticPath { + public: + + typedef GR Digraph; + typedef typename Digraph::Arc Arc; + + /// \brief Default constructor + /// + /// Default constructor + StaticPath() : len(0), arcs(0) {} + + /// \brief Copy constructor + /// + StaticPath(const StaticPath& cpath) : arcs(0) { + pathCopy(cpath, *this); + } + + /// \brief Template copy constructor + /// + /// This path can be initialized from any other path type. + template + StaticPath(const CPath& cpath) : arcs(0) { + pathCopy(cpath, *this); + } + + /// \brief Destructor of the path + /// + /// Destructor of the path + ~StaticPath() { + if (arcs) delete[] arcs; + } + + /// \brief Copy assignment + /// + StaticPath& operator=(const StaticPath& cpath) { + pathCopy(cpath, *this); + return *this; + } + + /// \brief Template copy assignment + /// + /// This path can be made equal to any other path type. It simply + /// makes a copy of the given path. + template + StaticPath& operator=(const CPath& cpath) { + pathCopy(cpath, *this); + return *this; + } + + /// \brief Iterator class to iterate on the arcs of the paths + /// + /// This class is used to iterate on the arcs of the paths + /// + /// Of course it converts to Digraph::Arc + class ArcIt { + friend class StaticPath; + public: + /// Default constructor + ArcIt() {} + /// Invalid constructor + ArcIt(Invalid) : path(0), idx(-1) {} + /// Initializate the constructor to the first arc of path + ArcIt(const StaticPath &_path) + : path(&_path), idx(_path.empty() ? -1 : 0) {} + + private: + + /// Constructor with starting point + ArcIt(const StaticPath &_path, int _idx) + : idx(_idx), path(&_path) {} + + public: + + ///Conversion to Digraph::Arc + operator const Arc&() const { + return path->nth(idx); + } + + /// Next arc + ArcIt& operator++() { + ++idx; + if (idx >= path->length()) idx = -1; + return *this; + } + + /// Comparison operator + bool operator==(const ArcIt& e) const { return idx==e.idx; } + /// Comparison operator + bool operator!=(const ArcIt& e) const { return idx!=e.idx; } + /// Comparison operator + bool operator<(const ArcIt& e) const { return idx[0..length() - 1] range. + const Arc& nth(int n) const { + return arcs[n]; + } + + /// \brief The arc iterator pointing to the n-th arc. + ArcIt nthIt(int n) const { + return ArcIt(*this, n); + } + + /// \brief The length of the path. + int length() const { return len; } + + /// \brief Return true when the path is empty. + int empty() const { return len == 0; } + + /// \brief Erase all arcs in the digraph. + void clear() { + len = 0; + if (arcs) delete[] arcs; + arcs = 0; + } + + /// \brief The first arc of the path. + const Arc& front() const { + return arcs[0]; + } + + /// \brief The last arc of the path. + const Arc& back() const { + return arcs[len - 1]; + } + + + typedef True BuildTag; + + template + void build(const CPath& path) { + len = path.length(); + arcs = new Arc[len]; + int index = 0; + for (typename CPath::ArcIt it(path); it != INVALID; ++it) { + arcs[index] = it; + ++index; + } + } + + template + void buildRev(const CPath& path) { + len = path.length(); + arcs = new Arc[len]; + int index = len; + for (typename CPath::RevArcIt it(path); it != INVALID; ++it) { + --index; + arcs[index] = it; + } + } + + private: + int len; + Arc* arcs; + }; + + /////////////////////////////////////////////////////////////////////// + // Additional utilities + /////////////////////////////////////////////////////////////////////// + + namespace _path_bits { + + template + struct RevPathTagIndicator { + static const bool value = false; + }; + + template + struct RevPathTagIndicator< + Path, + typename enable_if::type + > { + static const bool value = true; + }; + + template + struct BuildTagIndicator { + static const bool value = false; + }; + + template + struct BuildTagIndicator< + Path, + typename enable_if::type + > { + static const bool value = true; + }; + + template ::value> + struct PathCopySelectorForward { + static void copy(const From& from, To& to) { + to.clear(); + for (typename From::ArcIt it(from); it != INVALID; ++it) { + to.addBack(it); + } + } + }; + + template + struct PathCopySelectorForward { + static void copy(const From& from, To& to) { + to.clear(); + to.build(from); + } + }; + + template ::value> + struct PathCopySelectorBackward { + static void copy(const From& from, To& to) { + to.clear(); + for (typename From::RevArcIt it(from); it != INVALID; ++it) { + to.addFront(it); + } + } + }; + + template + struct PathCopySelectorBackward { + static void copy(const From& from, To& to) { + to.clear(); + to.buildRev(from); + } + }; + + + template ::value> + struct PathCopySelector { + static void copy(const From& from, To& to) { + PathCopySelectorForward::copy(from, to); + } + }; + + template + struct PathCopySelector { + static void copy(const From& from, To& to) { + PathCopySelectorBackward::copy(from, to); + } + }; + + } + + + /// \brief Make a copy of a path. + /// + /// This function makes a copy of a path. + template + void pathCopy(const From& from, To& to) { + checkConcept, From>(); + _path_bits::PathCopySelector::copy(from, to); + } + + /// \brief Deprecated version of \ref pathCopy(). + /// + /// Deprecated version of \ref pathCopy() (only for reverse compatibility). + template + void copyPath(To& to, const From& from) { + pathCopy(from, to); + } + + /// \brief Check the consistency of a path. + /// + /// This function checks that the target of each arc is the same + /// as the source of the next one. + /// + template + bool checkPath(const Digraph& digraph, const Path& path) { + typename Path::ArcIt it(path); + if (it == INVALID) return true; + typename Digraph::Node node = digraph.target(it); + ++it; + while (it != INVALID) { + if (digraph.source(it) != node) return false; + node = digraph.target(it); + ++it; + } + return true; + } + + /// \brief The source of a path + /// + /// This function returns the source node of the given path. + /// If the path is empty, then it returns \c INVALID. + template + typename Digraph::Node pathSource(const Digraph& digraph, const Path& path) { + return path.empty() ? INVALID : digraph.source(path.front()); + } + + /// \brief The target of a path + /// + /// This function returns the target node of the given path. + /// If the path is empty, then it returns \c INVALID. + template + typename Digraph::Node pathTarget(const Digraph& digraph, const Path& path) { + return path.empty() ? INVALID : digraph.target(path.back()); + } + + /// \brief Class which helps to iterate through the nodes of a path + /// + /// In a sense, the path can be treated as a list of arcs. The + /// LEMON path type stores only this list. As a consequence, it + /// cannot enumerate the nodes in the path and the zero length paths + /// cannot have a source node. + /// + /// This class implements the node iterator of a path structure. To + /// provide this feature, the underlying digraph should be passed to + /// the constructor of the iterator. + template + class PathNodeIt { + private: + const typename Path::Digraph *_digraph; + typename Path::ArcIt _it; + typename Path::Digraph::Node _nd; + + public: + + typedef typename Path::Digraph Digraph; + typedef typename Digraph::Node Node; + + /// Default constructor + PathNodeIt() {} + /// Invalid constructor + PathNodeIt(Invalid) + : _digraph(0), _it(INVALID), _nd(INVALID) {} + /// Constructor + PathNodeIt(const Digraph& digraph, const Path& path) + : _digraph(&digraph), _it(path) { + _nd = (_it != INVALID ? _digraph->source(_it) : INVALID); + } + /// Constructor + PathNodeIt(const Digraph& digraph, const Path& path, const Node& src) + : _digraph(&digraph), _it(path), _nd(src) {} + + ///Conversion to Digraph::Node + operator Node() const { + return _nd; + } + + /// Next node + PathNodeIt& operator++() { + if (_it == INVALID) _nd = INVALID; + else { + _nd = _digraph->target(_it); + ++_it; + } + return *this; + } + + /// Comparison operator + bool operator==(const PathNodeIt& n) const { + return _it == n._it && _nd == n._nd; + } + /// Comparison operator + bool operator!=(const PathNodeIt& n) const { + return _it != n._it || _nd != n._nd; + } + /// Comparison operator + bool operator<(const PathNodeIt& n) const { + return (_it < n._it && _nd != INVALID); + } + + }; + + ///@} + +} // namespace lemon + +#endif // LEMON_PATH_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/planarity.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/planarity.h new file mode 100644 index 00000000000..bfe8e85dc4d --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/planarity.h @@ -0,0 +1,2754 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_PLANARITY_H +#define LEMON_PLANARITY_H + +/// \ingroup planar +/// \file +/// \brief Planarity checking, embedding, drawing and coloring + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace lemon { + + namespace _planarity_bits { + + template + struct PlanarityVisitor : DfsVisitor { + + TEMPLATE_GRAPH_TYPEDEFS(Graph); + + typedef typename Graph::template NodeMap PredMap; + + typedef typename Graph::template EdgeMap TreeMap; + + typedef typename Graph::template NodeMap OrderMap; + typedef std::vector OrderList; + + typedef typename Graph::template NodeMap LowMap; + typedef typename Graph::template NodeMap AncestorMap; + + PlanarityVisitor(const Graph& graph, + PredMap& pred_map, TreeMap& tree_map, + OrderMap& order_map, OrderList& order_list, + AncestorMap& ancestor_map, LowMap& low_map) + : _graph(graph), _pred_map(pred_map), _tree_map(tree_map), + _order_map(order_map), _order_list(order_list), + _ancestor_map(ancestor_map), _low_map(low_map) {} + + void reach(const Node& node) { + _order_map[node] = _order_list.size(); + _low_map[node] = _order_list.size(); + _ancestor_map[node] = _order_list.size(); + _order_list.push_back(node); + } + + void discover(const Arc& arc) { + Node target = _graph.target(arc); + + _tree_map[arc] = true; + _pred_map[target] = arc; + } + + void examine(const Arc& arc) { + Node source = _graph.source(arc); + Node target = _graph.target(arc); + + if (_order_map[target] < _order_map[source] && !_tree_map[arc]) { + if (_low_map[source] > _order_map[target]) { + _low_map[source] = _order_map[target]; + } + if (_ancestor_map[source] > _order_map[target]) { + _ancestor_map[source] = _order_map[target]; + } + } + } + + void backtrack(const Arc& arc) { + Node source = _graph.source(arc); + Node target = _graph.target(arc); + + if (_low_map[source] > _low_map[target]) { + _low_map[source] = _low_map[target]; + } + } + + const Graph& _graph; + PredMap& _pred_map; + TreeMap& _tree_map; + OrderMap& _order_map; + OrderList& _order_list; + AncestorMap& _ancestor_map; + LowMap& _low_map; + }; + + template + struct NodeDataNode { + int prev, next; + int visited; + typename Graph::Arc first; + bool inverted; + }; + + template + struct NodeDataNode { + int prev, next; + int visited; + }; + + template + struct ChildListNode { + typedef typename Graph::Node Node; + Node first; + Node prev, next; + }; + + template + struct ArcListNode { + typename Graph::Arc prev, next; + }; + + template + class PlanarityChecking { + private: + + TEMPLATE_GRAPH_TYPEDEFS(Graph); + + const Graph& _graph; + + private: + + typedef typename Graph::template NodeMap PredMap; + + typedef typename Graph::template EdgeMap TreeMap; + + typedef typename Graph::template NodeMap OrderMap; + typedef std::vector OrderList; + + typedef typename Graph::template NodeMap LowMap; + typedef typename Graph::template NodeMap AncestorMap; + + typedef _planarity_bits::NodeDataNode NodeDataNode; + typedef std::vector NodeData; + + typedef _planarity_bits::ChildListNode ChildListNode; + typedef typename Graph::template NodeMap ChildLists; + + typedef typename Graph::template NodeMap > MergeRoots; + + typedef typename Graph::template NodeMap EmbedArc; + + public: + + PlanarityChecking(const Graph& graph) : _graph(graph) {} + + bool run() { + typedef _planarity_bits::PlanarityVisitor Visitor; + + PredMap pred_map(_graph, INVALID); + TreeMap tree_map(_graph, false); + + OrderMap order_map(_graph, -1); + OrderList order_list; + + AncestorMap ancestor_map(_graph, -1); + LowMap low_map(_graph, -1); + + Visitor visitor(_graph, pred_map, tree_map, + order_map, order_list, ancestor_map, low_map); + DfsVisit visit(_graph, visitor); + visit.run(); + + ChildLists child_lists(_graph); + createChildLists(tree_map, order_map, low_map, child_lists); + + NodeData node_data(2 * order_list.size()); + + EmbedArc embed_arc(_graph, false); + + MergeRoots merge_roots(_graph); + + for (int i = order_list.size() - 1; i >= 0; --i) { + + Node node = order_list[i]; + + Node source = node; + for (OutArcIt e(_graph, node); e != INVALID; ++e) { + Node target = _graph.target(e); + + if (order_map[source] < order_map[target] && tree_map[e]) { + initFace(target, node_data, order_map, order_list); + } + } + + for (OutArcIt e(_graph, node); e != INVALID; ++e) { + Node target = _graph.target(e); + + if (order_map[source] < order_map[target] && !tree_map[e]) { + embed_arc[target] = true; + walkUp(target, source, i, pred_map, low_map, + order_map, order_list, node_data, merge_roots); + } + } + + for (typename MergeRoots::Value::iterator it = + merge_roots[node].begin(); + it != merge_roots[node].end(); ++it) { + int rn = *it; + walkDown(rn, i, node_data, order_list, child_lists, + ancestor_map, low_map, embed_arc, merge_roots); + } + merge_roots[node].clear(); + + for (OutArcIt e(_graph, node); e != INVALID; ++e) { + Node target = _graph.target(e); + + if (order_map[source] < order_map[target] && !tree_map[e]) { + if (embed_arc[target]) { + return false; + } + } + } + } + + return true; + } + + private: + + void createChildLists(const TreeMap& tree_map, const OrderMap& order_map, + const LowMap& low_map, ChildLists& child_lists) { + + for (NodeIt n(_graph); n != INVALID; ++n) { + Node source = n; + + std::vector targets; + for (OutArcIt e(_graph, n); e != INVALID; ++e) { + Node target = _graph.target(e); + + if (order_map[source] < order_map[target] && tree_map[e]) { + targets.push_back(target); + } + } + + if (targets.size() == 0) { + child_lists[source].first = INVALID; + } else if (targets.size() == 1) { + child_lists[source].first = targets[0]; + child_lists[targets[0]].prev = INVALID; + child_lists[targets[0]].next = INVALID; + } else { + radixSort(targets.begin(), targets.end(), mapToFunctor(low_map)); + for (int i = 1; i < int(targets.size()); ++i) { + child_lists[targets[i]].prev = targets[i - 1]; + child_lists[targets[i - 1]].next = targets[i]; + } + child_lists[targets.back()].next = INVALID; + child_lists[targets.front()].prev = INVALID; + child_lists[source].first = targets.front(); + } + } + } + + void walkUp(const Node& node, Node root, int rorder, + const PredMap& pred_map, const LowMap& low_map, + const OrderMap& order_map, const OrderList& order_list, + NodeData& node_data, MergeRoots& merge_roots) { + + int na, nb; + bool da, db; + + na = nb = order_map[node]; + da = true; db = false; + + while (true) { + + if (node_data[na].visited == rorder) break; + if (node_data[nb].visited == rorder) break; + + node_data[na].visited = rorder; + node_data[nb].visited = rorder; + + int rn = -1; + + if (na >= int(order_list.size())) { + rn = na; + } else if (nb >= int(order_list.size())) { + rn = nb; + } + + if (rn == -1) { + int nn; + + nn = da ? node_data[na].prev : node_data[na].next; + da = node_data[nn].prev != na; + na = nn; + + nn = db ? node_data[nb].prev : node_data[nb].next; + db = node_data[nn].prev != nb; + nb = nn; + + } else { + + Node rep = order_list[rn - order_list.size()]; + Node parent = _graph.source(pred_map[rep]); + + if (low_map[rep] < rorder) { + merge_roots[parent].push_back(rn); + } else { + merge_roots[parent].push_front(rn); + } + + if (parent != root) { + na = nb = order_map[parent]; + da = true; db = false; + } else { + break; + } + } + } + } + + void walkDown(int rn, int rorder, NodeData& node_data, + OrderList& order_list, ChildLists& child_lists, + AncestorMap& ancestor_map, LowMap& low_map, + EmbedArc& embed_arc, MergeRoots& merge_roots) { + + std::vector > merge_stack; + + for (int di = 0; di < 2; ++di) { + bool rd = di == 0; + int pn = rn; + int n = rd ? node_data[rn].next : node_data[rn].prev; + + while (n != rn) { + + Node node = order_list[n]; + + if (embed_arc[node]) { + + // Merging components on the critical path + while (!merge_stack.empty()) { + + // Component root + int cn = merge_stack.back().first; + bool cd = merge_stack.back().second; + merge_stack.pop_back(); + + // Parent of component + int dn = merge_stack.back().first; + bool dd = merge_stack.back().second; + merge_stack.pop_back(); + + Node parent = order_list[dn]; + + // Erasing from merge_roots + merge_roots[parent].pop_front(); + + Node child = order_list[cn - order_list.size()]; + + // Erasing from child_lists + if (child_lists[child].prev != INVALID) { + child_lists[child_lists[child].prev].next = + child_lists[child].next; + } else { + child_lists[parent].first = child_lists[child].next; + } + + if (child_lists[child].next != INVALID) { + child_lists[child_lists[child].next].prev = + child_lists[child].prev; + } + + // Merging external faces + { + int en = cn; + cn = cd ? node_data[cn].prev : node_data[cn].next; + cd = node_data[cn].next == en; + + } + + if (cd) node_data[cn].next = dn; else node_data[cn].prev = dn; + if (dd) node_data[dn].prev = cn; else node_data[dn].next = cn; + + } + + bool d = pn == node_data[n].prev; + + if (node_data[n].prev == node_data[n].next && + node_data[n].inverted) { + d = !d; + } + + // Embedding arc into external face + if (rd) node_data[rn].next = n; else node_data[rn].prev = n; + if (d) node_data[n].prev = rn; else node_data[n].next = rn; + pn = rn; + + embed_arc[order_list[n]] = false; + } + + if (!merge_roots[node].empty()) { + + bool d = pn == node_data[n].prev; + + merge_stack.push_back(std::make_pair(n, d)); + + int rn = merge_roots[node].front(); + + int xn = node_data[rn].next; + Node xnode = order_list[xn]; + + int yn = node_data[rn].prev; + Node ynode = order_list[yn]; + + bool rd; + if (!external(xnode, rorder, child_lists, + ancestor_map, low_map)) { + rd = true; + } else if (!external(ynode, rorder, child_lists, + ancestor_map, low_map)) { + rd = false; + } else if (pertinent(xnode, embed_arc, merge_roots)) { + rd = true; + } else { + rd = false; + } + + merge_stack.push_back(std::make_pair(rn, rd)); + + pn = rn; + n = rd ? xn : yn; + + } else if (!external(node, rorder, child_lists, + ancestor_map, low_map)) { + int nn = (node_data[n].next != pn ? + node_data[n].next : node_data[n].prev); + + bool nd = n == node_data[nn].prev; + + if (nd) node_data[nn].prev = pn; + else node_data[nn].next = pn; + + if (n == node_data[pn].prev) node_data[pn].prev = nn; + else node_data[pn].next = nn; + + node_data[nn].inverted = + (node_data[nn].prev == node_data[nn].next && nd != rd); + + n = nn; + } + else break; + + } + + if (!merge_stack.empty() || n == rn) { + break; + } + } + } + + void initFace(const Node& node, NodeData& node_data, + const OrderMap& order_map, const OrderList& order_list) { + int n = order_map[node]; + int rn = n + order_list.size(); + + node_data[n].next = node_data[n].prev = rn; + node_data[rn].next = node_data[rn].prev = n; + + node_data[n].visited = order_list.size(); + node_data[rn].visited = order_list.size(); + + } + + bool external(const Node& node, int rorder, + ChildLists& child_lists, AncestorMap& ancestor_map, + LowMap& low_map) { + Node child = child_lists[node].first; + + if (child != INVALID) { + if (low_map[child] < rorder) return true; + } + + if (ancestor_map[node] < rorder) return true; + + return false; + } + + bool pertinent(const Node& node, const EmbedArc& embed_arc, + const MergeRoots& merge_roots) { + return !merge_roots[node].empty() || embed_arc[node]; + } + + }; + + } + + /// \ingroup planar + /// + /// \brief Planarity checking of an undirected simple graph + /// + /// This function implements the Boyer-Myrvold algorithm for + /// planarity checking of an undirected simple graph. It is a simplified + /// version of the PlanarEmbedding algorithm class because neither + /// the embedding nor the Kuratowski subdivisons are computed. + template + bool checkPlanarity(const GR& graph) { + _planarity_bits::PlanarityChecking pc(graph); + return pc.run(); + } + + /// \ingroup planar + /// + /// \brief Planar embedding of an undirected simple graph + /// + /// This class implements the Boyer-Myrvold algorithm for planar + /// embedding of an undirected simple graph. The planar embedding is an + /// ordering of the outgoing edges of the nodes, which is a possible + /// configuration to draw the graph in the plane. If there is not + /// such ordering then the graph contains a K5 (full graph + /// with 5 nodes) or a K3,3 (complete bipartite graph on + /// 3 Red and 3 Blue nodes) subdivision. + /// + /// The current implementation calculates either an embedding or a + /// Kuratowski subdivision. The running time of the algorithm is O(n). + /// + /// \see PlanarDrawing, checkPlanarity() + template + class PlanarEmbedding { + private: + + TEMPLATE_GRAPH_TYPEDEFS(Graph); + + const Graph& _graph; + typename Graph::template ArcMap _embedding; + + typename Graph::template EdgeMap _kuratowski; + + private: + + typedef typename Graph::template NodeMap PredMap; + + typedef typename Graph::template EdgeMap TreeMap; + + typedef typename Graph::template NodeMap OrderMap; + typedef std::vector OrderList; + + typedef typename Graph::template NodeMap LowMap; + typedef typename Graph::template NodeMap AncestorMap; + + typedef _planarity_bits::NodeDataNode NodeDataNode; + typedef std::vector NodeData; + + typedef _planarity_bits::ChildListNode ChildListNode; + typedef typename Graph::template NodeMap ChildLists; + + typedef typename Graph::template NodeMap > MergeRoots; + + typedef typename Graph::template NodeMap EmbedArc; + + typedef _planarity_bits::ArcListNode ArcListNode; + typedef typename Graph::template ArcMap ArcLists; + + typedef typename Graph::template NodeMap FlipMap; + + typedef typename Graph::template NodeMap TypeMap; + + enum IsolatorNodeType { + HIGHX = 6, LOWX = 7, + HIGHY = 8, LOWY = 9, + ROOT = 10, PERTINENT = 11, + INTERNAL = 12 + }; + + public: + + /// \brief The map type for storing the embedding + /// + /// The map type for storing the embedding. + /// \see embeddingMap() + typedef typename Graph::template ArcMap EmbeddingMap; + + /// \brief Constructor + /// + /// Constructor. + /// \pre The graph must be simple, i.e. it should not + /// contain parallel or loop arcs. + PlanarEmbedding(const Graph& graph) + : _graph(graph), _embedding(_graph), _kuratowski(graph, false) {} + + /// \brief Run the algorithm. + /// + /// This function runs the algorithm. + /// \param kuratowski If this parameter is set to \c false, then the + /// algorithm does not compute a Kuratowski subdivision. + /// \return \c true if the graph is planar. + bool run(bool kuratowski = true) { + typedef _planarity_bits::PlanarityVisitor Visitor; + + PredMap pred_map(_graph, INVALID); + TreeMap tree_map(_graph, false); + + OrderMap order_map(_graph, -1); + OrderList order_list; + + AncestorMap ancestor_map(_graph, -1); + LowMap low_map(_graph, -1); + + Visitor visitor(_graph, pred_map, tree_map, + order_map, order_list, ancestor_map, low_map); + DfsVisit visit(_graph, visitor); + visit.run(); + + ChildLists child_lists(_graph); + createChildLists(tree_map, order_map, low_map, child_lists); + + NodeData node_data(2 * order_list.size()); + + EmbedArc embed_arc(_graph, INVALID); + + MergeRoots merge_roots(_graph); + + ArcLists arc_lists(_graph); + + FlipMap flip_map(_graph, false); + + for (int i = order_list.size() - 1; i >= 0; --i) { + + Node node = order_list[i]; + + node_data[i].first = INVALID; + + Node source = node; + for (OutArcIt e(_graph, node); e != INVALID; ++e) { + Node target = _graph.target(e); + + if (order_map[source] < order_map[target] && tree_map[e]) { + initFace(target, arc_lists, node_data, + pred_map, order_map, order_list); + } + } + + for (OutArcIt e(_graph, node); e != INVALID; ++e) { + Node target = _graph.target(e); + + if (order_map[source] < order_map[target] && !tree_map[e]) { + embed_arc[target] = e; + walkUp(target, source, i, pred_map, low_map, + order_map, order_list, node_data, merge_roots); + } + } + + for (typename MergeRoots::Value::iterator it = + merge_roots[node].begin(); it != merge_roots[node].end(); ++it) { + int rn = *it; + walkDown(rn, i, node_data, arc_lists, flip_map, order_list, + child_lists, ancestor_map, low_map, embed_arc, merge_roots); + } + merge_roots[node].clear(); + + for (OutArcIt e(_graph, node); e != INVALID; ++e) { + Node target = _graph.target(e); + + if (order_map[source] < order_map[target] && !tree_map[e]) { + if (embed_arc[target] != INVALID) { + if (kuratowski) { + isolateKuratowski(e, node_data, arc_lists, flip_map, + order_map, order_list, pred_map, child_lists, + ancestor_map, low_map, + embed_arc, merge_roots); + } + return false; + } + } + } + } + + for (int i = 0; i < int(order_list.size()); ++i) { + + mergeRemainingFaces(order_list[i], node_data, order_list, order_map, + child_lists, arc_lists); + storeEmbedding(order_list[i], node_data, order_map, pred_map, + arc_lists, flip_map); + } + + return true; + } + + /// \brief Give back the successor of an arc + /// + /// This function gives back the successor of an arc. It makes + /// possible to query the cyclic order of the outgoing arcs from + /// a node. + Arc next(const Arc& arc) const { + return _embedding[arc]; + } + + /// \brief Give back the calculated embedding map + /// + /// This function gives back the calculated embedding map, which + /// contains the successor of each arc in the cyclic order of the + /// outgoing arcs of its source node. + const EmbeddingMap& embeddingMap() const { + return _embedding; + } + + /// \brief Give back \c true if the given edge is in the Kuratowski + /// subdivision + /// + /// This function gives back \c true if the given edge is in the found + /// Kuratowski subdivision. + /// \pre The \c run() function must be called with \c true parameter + /// before using this function. + bool kuratowski(const Edge& edge) const { + return _kuratowski[edge]; + } + + private: + + void createChildLists(const TreeMap& tree_map, const OrderMap& order_map, + const LowMap& low_map, ChildLists& child_lists) { + + for (NodeIt n(_graph); n != INVALID; ++n) { + Node source = n; + + std::vector targets; + for (OutArcIt e(_graph, n); e != INVALID; ++e) { + Node target = _graph.target(e); + + if (order_map[source] < order_map[target] && tree_map[e]) { + targets.push_back(target); + } + } + + if (targets.size() == 0) { + child_lists[source].first = INVALID; + } else if (targets.size() == 1) { + child_lists[source].first = targets[0]; + child_lists[targets[0]].prev = INVALID; + child_lists[targets[0]].next = INVALID; + } else { + radixSort(targets.begin(), targets.end(), mapToFunctor(low_map)); + for (int i = 1; i < int(targets.size()); ++i) { + child_lists[targets[i]].prev = targets[i - 1]; + child_lists[targets[i - 1]].next = targets[i]; + } + child_lists[targets.back()].next = INVALID; + child_lists[targets.front()].prev = INVALID; + child_lists[source].first = targets.front(); + } + } + } + + void walkUp(const Node& node, Node root, int rorder, + const PredMap& pred_map, const LowMap& low_map, + const OrderMap& order_map, const OrderList& order_list, + NodeData& node_data, MergeRoots& merge_roots) { + + int na, nb; + bool da, db; + + na = nb = order_map[node]; + da = true; db = false; + + while (true) { + + if (node_data[na].visited == rorder) break; + if (node_data[nb].visited == rorder) break; + + node_data[na].visited = rorder; + node_data[nb].visited = rorder; + + int rn = -1; + + if (na >= int(order_list.size())) { + rn = na; + } else if (nb >= int(order_list.size())) { + rn = nb; + } + + if (rn == -1) { + int nn; + + nn = da ? node_data[na].prev : node_data[na].next; + da = node_data[nn].prev != na; + na = nn; + + nn = db ? node_data[nb].prev : node_data[nb].next; + db = node_data[nn].prev != nb; + nb = nn; + + } else { + + Node rep = order_list[rn - order_list.size()]; + Node parent = _graph.source(pred_map[rep]); + + if (low_map[rep] < rorder) { + merge_roots[parent].push_back(rn); + } else { + merge_roots[parent].push_front(rn); + } + + if (parent != root) { + na = nb = order_map[parent]; + da = true; db = false; + } else { + break; + } + } + } + } + + void walkDown(int rn, int rorder, NodeData& node_data, + ArcLists& arc_lists, FlipMap& flip_map, + OrderList& order_list, ChildLists& child_lists, + AncestorMap& ancestor_map, LowMap& low_map, + EmbedArc& embed_arc, MergeRoots& merge_roots) { + + std::vector > merge_stack; + + for (int di = 0; di < 2; ++di) { + bool rd = di == 0; + int pn = rn; + int n = rd ? node_data[rn].next : node_data[rn].prev; + + while (n != rn) { + + Node node = order_list[n]; + + if (embed_arc[node] != INVALID) { + + // Merging components on the critical path + while (!merge_stack.empty()) { + + // Component root + int cn = merge_stack.back().first; + bool cd = merge_stack.back().second; + merge_stack.pop_back(); + + // Parent of component + int dn = merge_stack.back().first; + bool dd = merge_stack.back().second; + merge_stack.pop_back(); + + Node parent = order_list[dn]; + + // Erasing from merge_roots + merge_roots[parent].pop_front(); + + Node child = order_list[cn - order_list.size()]; + + // Erasing from child_lists + if (child_lists[child].prev != INVALID) { + child_lists[child_lists[child].prev].next = + child_lists[child].next; + } else { + child_lists[parent].first = child_lists[child].next; + } + + if (child_lists[child].next != INVALID) { + child_lists[child_lists[child].next].prev = + child_lists[child].prev; + } + + // Merging arcs + flipping + Arc de = node_data[dn].first; + Arc ce = node_data[cn].first; + + flip_map[order_list[cn - order_list.size()]] = cd != dd; + if (cd != dd) { + std::swap(arc_lists[ce].prev, arc_lists[ce].next); + ce = arc_lists[ce].prev; + std::swap(arc_lists[ce].prev, arc_lists[ce].next); + } + + { + Arc dne = arc_lists[de].next; + Arc cne = arc_lists[ce].next; + + arc_lists[de].next = cne; + arc_lists[ce].next = dne; + + arc_lists[dne].prev = ce; + arc_lists[cne].prev = de; + } + + if (dd) { + node_data[dn].first = ce; + } + + // Merging external faces + { + int en = cn; + cn = cd ? node_data[cn].prev : node_data[cn].next; + cd = node_data[cn].next == en; + + if (node_data[cn].prev == node_data[cn].next && + node_data[cn].inverted) { + cd = !cd; + } + } + + if (cd) node_data[cn].next = dn; else node_data[cn].prev = dn; + if (dd) node_data[dn].prev = cn; else node_data[dn].next = cn; + + } + + bool d = pn == node_data[n].prev; + + if (node_data[n].prev == node_data[n].next && + node_data[n].inverted) { + d = !d; + } + + // Add new arc + { + Arc arc = embed_arc[node]; + Arc re = node_data[rn].first; + + arc_lists[arc_lists[re].next].prev = arc; + arc_lists[arc].next = arc_lists[re].next; + arc_lists[arc].prev = re; + arc_lists[re].next = arc; + + if (!rd) { + node_data[rn].first = arc; + } + + Arc rev = _graph.oppositeArc(arc); + Arc e = node_data[n].first; + + arc_lists[arc_lists[e].next].prev = rev; + arc_lists[rev].next = arc_lists[e].next; + arc_lists[rev].prev = e; + arc_lists[e].next = rev; + + if (d) { + node_data[n].first = rev; + } + + } + + // Embedding arc into external face + if (rd) node_data[rn].next = n; else node_data[rn].prev = n; + if (d) node_data[n].prev = rn; else node_data[n].next = rn; + pn = rn; + + embed_arc[order_list[n]] = INVALID; + } + + if (!merge_roots[node].empty()) { + + bool d = pn == node_data[n].prev; + if (node_data[n].prev == node_data[n].next && + node_data[n].inverted) { + d = !d; + } + + merge_stack.push_back(std::make_pair(n, d)); + + int rn = merge_roots[node].front(); + + int xn = node_data[rn].next; + Node xnode = order_list[xn]; + + int yn = node_data[rn].prev; + Node ynode = order_list[yn]; + + bool rd; + if (!external(xnode, rorder, child_lists, ancestor_map, low_map)) { + rd = true; + } else if (!external(ynode, rorder, child_lists, + ancestor_map, low_map)) { + rd = false; + } else if (pertinent(xnode, embed_arc, merge_roots)) { + rd = true; + } else { + rd = false; + } + + merge_stack.push_back(std::make_pair(rn, rd)); + + pn = rn; + n = rd ? xn : yn; + + } else if (!external(node, rorder, child_lists, + ancestor_map, low_map)) { + int nn = (node_data[n].next != pn ? + node_data[n].next : node_data[n].prev); + + bool nd = n == node_data[nn].prev; + + if (nd) node_data[nn].prev = pn; + else node_data[nn].next = pn; + + if (n == node_data[pn].prev) node_data[pn].prev = nn; + else node_data[pn].next = nn; + + node_data[nn].inverted = + (node_data[nn].prev == node_data[nn].next && nd != rd); + + n = nn; + } + else break; + + } + + if (!merge_stack.empty() || n == rn) { + break; + } + } + } + + void initFace(const Node& node, ArcLists& arc_lists, + NodeData& node_data, const PredMap& pred_map, + const OrderMap& order_map, const OrderList& order_list) { + int n = order_map[node]; + int rn = n + order_list.size(); + + node_data[n].next = node_data[n].prev = rn; + node_data[rn].next = node_data[rn].prev = n; + + node_data[n].visited = order_list.size(); + node_data[rn].visited = order_list.size(); + + node_data[n].inverted = false; + node_data[rn].inverted = false; + + Arc arc = pred_map[node]; + Arc rev = _graph.oppositeArc(arc); + + node_data[rn].first = arc; + node_data[n].first = rev; + + arc_lists[arc].prev = arc; + arc_lists[arc].next = arc; + + arc_lists[rev].prev = rev; + arc_lists[rev].next = rev; + + } + + void mergeRemainingFaces(const Node& node, NodeData& node_data, + OrderList& order_list, OrderMap& order_map, + ChildLists& child_lists, ArcLists& arc_lists) { + while (child_lists[node].first != INVALID) { + int dd = order_map[node]; + Node child = child_lists[node].first; + int cd = order_map[child] + order_list.size(); + child_lists[node].first = child_lists[child].next; + + Arc de = node_data[dd].first; + Arc ce = node_data[cd].first; + + if (de != INVALID) { + Arc dne = arc_lists[de].next; + Arc cne = arc_lists[ce].next; + + arc_lists[de].next = cne; + arc_lists[ce].next = dne; + + arc_lists[dne].prev = ce; + arc_lists[cne].prev = de; + } + + node_data[dd].first = ce; + + } + } + + void storeEmbedding(const Node& node, NodeData& node_data, + OrderMap& order_map, PredMap& pred_map, + ArcLists& arc_lists, FlipMap& flip_map) { + + if (node_data[order_map[node]].first == INVALID) return; + + if (pred_map[node] != INVALID) { + Node source = _graph.source(pred_map[node]); + flip_map[node] = flip_map[node] != flip_map[source]; + } + + Arc first = node_data[order_map[node]].first; + Arc prev = first; + + Arc arc = flip_map[node] ? + arc_lists[prev].prev : arc_lists[prev].next; + + _embedding[prev] = arc; + + while (arc != first) { + Arc next = arc_lists[arc].prev == prev ? + arc_lists[arc].next : arc_lists[arc].prev; + prev = arc; arc = next; + _embedding[prev] = arc; + } + } + + + bool external(const Node& node, int rorder, + ChildLists& child_lists, AncestorMap& ancestor_map, + LowMap& low_map) { + Node child = child_lists[node].first; + + if (child != INVALID) { + if (low_map[child] < rorder) return true; + } + + if (ancestor_map[node] < rorder) return true; + + return false; + } + + bool pertinent(const Node& node, const EmbedArc& embed_arc, + const MergeRoots& merge_roots) { + return !merge_roots[node].empty() || embed_arc[node] != INVALID; + } + + int lowPoint(const Node& node, OrderMap& order_map, ChildLists& child_lists, + AncestorMap& ancestor_map, LowMap& low_map) { + int low_point; + + Node child = child_lists[node].first; + + if (child != INVALID) { + low_point = low_map[child]; + } else { + low_point = order_map[node]; + } + + if (low_point > ancestor_map[node]) { + low_point = ancestor_map[node]; + } + + return low_point; + } + + int findComponentRoot(Node root, Node node, ChildLists& child_lists, + OrderMap& order_map, OrderList& order_list) { + + int order = order_map[root]; + int norder = order_map[node]; + + Node child = child_lists[root].first; + while (child != INVALID) { + int corder = order_map[child]; + if (corder > order && corder < norder) { + order = corder; + } + child = child_lists[child].next; + } + return order + order_list.size(); + } + + Node findPertinent(Node node, OrderMap& order_map, NodeData& node_data, + EmbedArc& embed_arc, MergeRoots& merge_roots) { + Node wnode =_graph.target(node_data[order_map[node]].first); + while (!pertinent(wnode, embed_arc, merge_roots)) { + wnode = _graph.target(node_data[order_map[wnode]].first); + } + return wnode; + } + + + Node findExternal(Node node, int rorder, OrderMap& order_map, + ChildLists& child_lists, AncestorMap& ancestor_map, + LowMap& low_map, NodeData& node_data) { + Node wnode =_graph.target(node_data[order_map[node]].first); + while (!external(wnode, rorder, child_lists, ancestor_map, low_map)) { + wnode = _graph.target(node_data[order_map[wnode]].first); + } + return wnode; + } + + void markCommonPath(Node node, int rorder, Node& wnode, Node& znode, + OrderList& order_list, OrderMap& order_map, + NodeData& node_data, ArcLists& arc_lists, + EmbedArc& embed_arc, MergeRoots& merge_roots, + ChildLists& child_lists, AncestorMap& ancestor_map, + LowMap& low_map) { + + Node cnode = node; + Node pred = INVALID; + + while (true) { + + bool pert = pertinent(cnode, embed_arc, merge_roots); + bool ext = external(cnode, rorder, child_lists, ancestor_map, low_map); + + if (pert && ext) { + if (!merge_roots[cnode].empty()) { + int cn = merge_roots[cnode].back(); + + if (low_map[order_list[cn - order_list.size()]] < rorder) { + Arc arc = node_data[cn].first; + _kuratowski.set(arc, true); + + pred = cnode; + cnode = _graph.target(arc); + + continue; + } + } + wnode = znode = cnode; + return; + + } else if (pert) { + wnode = cnode; + + while (!external(cnode, rorder, child_lists, ancestor_map, low_map)) { + Arc arc = node_data[order_map[cnode]].first; + + if (_graph.target(arc) == pred) { + arc = arc_lists[arc].next; + } + _kuratowski.set(arc, true); + + Node next = _graph.target(arc); + pred = cnode; cnode = next; + } + + znode = cnode; + return; + + } else if (ext) { + znode = cnode; + + while (!pertinent(cnode, embed_arc, merge_roots)) { + Arc arc = node_data[order_map[cnode]].first; + + if (_graph.target(arc) == pred) { + arc = arc_lists[arc].next; + } + _kuratowski.set(arc, true); + + Node next = _graph.target(arc); + pred = cnode; cnode = next; + } + + wnode = cnode; + return; + + } else { + Arc arc = node_data[order_map[cnode]].first; + + if (_graph.target(arc) == pred) { + arc = arc_lists[arc].next; + } + _kuratowski.set(arc, true); + + Node next = _graph.target(arc); + pred = cnode; cnode = next; + } + + } + + } + + void orientComponent(Node root, int rn, OrderMap& order_map, + PredMap& pred_map, NodeData& node_data, + ArcLists& arc_lists, FlipMap& flip_map, + TypeMap& type_map) { + node_data[order_map[root]].first = node_data[rn].first; + type_map[root] = 1; + + std::vector st, qu; + + st.push_back(root); + while (!st.empty()) { + Node node = st.back(); + st.pop_back(); + qu.push_back(node); + + Arc arc = node_data[order_map[node]].first; + + if (type_map[_graph.target(arc)] == 0) { + st.push_back(_graph.target(arc)); + type_map[_graph.target(arc)] = 1; + } + + Arc last = arc, pred = arc; + arc = arc_lists[arc].next; + while (arc != last) { + + if (type_map[_graph.target(arc)] == 0) { + st.push_back(_graph.target(arc)); + type_map[_graph.target(arc)] = 1; + } + + Arc next = arc_lists[arc].next != pred ? + arc_lists[arc].next : arc_lists[arc].prev; + pred = arc; arc = next; + } + + } + + type_map[root] = 2; + flip_map[root] = false; + + for (int i = 1; i < int(qu.size()); ++i) { + + Node node = qu[i]; + + while (type_map[node] != 2) { + st.push_back(node); + type_map[node] = 2; + node = _graph.source(pred_map[node]); + } + + bool flip = flip_map[node]; + + while (!st.empty()) { + node = st.back(); + st.pop_back(); + + flip_map[node] = flip != flip_map[node]; + flip = flip_map[node]; + + if (flip) { + Arc arc = node_data[order_map[node]].first; + std::swap(arc_lists[arc].prev, arc_lists[arc].next); + arc = arc_lists[arc].prev; + std::swap(arc_lists[arc].prev, arc_lists[arc].next); + node_data[order_map[node]].first = arc; + } + } + } + + for (int i = 0; i < int(qu.size()); ++i) { + + Arc arc = node_data[order_map[qu[i]]].first; + Arc last = arc, pred = arc; + + arc = arc_lists[arc].next; + while (arc != last) { + + if (arc_lists[arc].next == pred) { + std::swap(arc_lists[arc].next, arc_lists[arc].prev); + } + pred = arc; arc = arc_lists[arc].next; + } + + } + } + + void setFaceFlags(Node root, Node wnode, Node ynode, Node xnode, + OrderMap& order_map, NodeData& node_data, + TypeMap& type_map) { + Node node = _graph.target(node_data[order_map[root]].first); + + while (node != ynode) { + type_map[node] = HIGHY; + node = _graph.target(node_data[order_map[node]].first); + } + + while (node != wnode) { + type_map[node] = LOWY; + node = _graph.target(node_data[order_map[node]].first); + } + + node = _graph.target(node_data[order_map[wnode]].first); + + while (node != xnode) { + type_map[node] = LOWX; + node = _graph.target(node_data[order_map[node]].first); + } + type_map[node] = LOWX; + + node = _graph.target(node_data[order_map[xnode]].first); + while (node != root) { + type_map[node] = HIGHX; + node = _graph.target(node_data[order_map[node]].first); + } + + type_map[wnode] = PERTINENT; + type_map[root] = ROOT; + } + + void findInternalPath(std::vector& ipath, + Node wnode, Node root, TypeMap& type_map, + OrderMap& order_map, NodeData& node_data, + ArcLists& arc_lists) { + std::vector st; + + Node node = wnode; + + while (node != root) { + Arc arc = arc_lists[node_data[order_map[node]].first].next; + st.push_back(arc); + node = _graph.target(arc); + } + + while (true) { + Arc arc = st.back(); + if (type_map[_graph.target(arc)] == LOWX || + type_map[_graph.target(arc)] == HIGHX) { + break; + } + if (type_map[_graph.target(arc)] == 2) { + type_map[_graph.target(arc)] = 3; + + arc = arc_lists[_graph.oppositeArc(arc)].next; + st.push_back(arc); + } else { + st.pop_back(); + arc = arc_lists[arc].next; + + while (_graph.oppositeArc(arc) == st.back()) { + arc = st.back(); + st.pop_back(); + arc = arc_lists[arc].next; + } + st.push_back(arc); + } + } + + for (int i = 0; i < int(st.size()); ++i) { + if (type_map[_graph.target(st[i])] != LOWY && + type_map[_graph.target(st[i])] != HIGHY) { + for (; i < int(st.size()); ++i) { + ipath.push_back(st[i]); + } + } + } + } + + void setInternalFlags(std::vector& ipath, TypeMap& type_map) { + for (int i = 1; i < int(ipath.size()); ++i) { + type_map[_graph.source(ipath[i])] = INTERNAL; + } + } + + void findPilePath(std::vector& ppath, + Node root, TypeMap& type_map, OrderMap& order_map, + NodeData& node_data, ArcLists& arc_lists) { + std::vector st; + + st.push_back(_graph.oppositeArc(node_data[order_map[root]].first)); + st.push_back(node_data[order_map[root]].first); + + while (st.size() > 1) { + Arc arc = st.back(); + if (type_map[_graph.target(arc)] == INTERNAL) { + break; + } + if (type_map[_graph.target(arc)] == 3) { + type_map[_graph.target(arc)] = 4; + + arc = arc_lists[_graph.oppositeArc(arc)].next; + st.push_back(arc); + } else { + st.pop_back(); + arc = arc_lists[arc].next; + + while (!st.empty() && _graph.oppositeArc(arc) == st.back()) { + arc = st.back(); + st.pop_back(); + arc = arc_lists[arc].next; + } + st.push_back(arc); + } + } + + for (int i = 1; i < int(st.size()); ++i) { + ppath.push_back(st[i]); + } + } + + + int markExternalPath(Node node, OrderMap& order_map, + ChildLists& child_lists, PredMap& pred_map, + AncestorMap& ancestor_map, LowMap& low_map) { + int lp = lowPoint(node, order_map, child_lists, + ancestor_map, low_map); + + if (ancestor_map[node] != lp) { + node = child_lists[node].first; + _kuratowski[pred_map[node]] = true; + + while (ancestor_map[node] != lp) { + for (OutArcIt e(_graph, node); e != INVALID; ++e) { + Node tnode = _graph.target(e); + if (order_map[tnode] > order_map[node] && low_map[tnode] == lp) { + node = tnode; + _kuratowski[e] = true; + break; + } + } + } + } + + for (OutArcIt e(_graph, node); e != INVALID; ++e) { + if (order_map[_graph.target(e)] == lp) { + _kuratowski[e] = true; + break; + } + } + + return lp; + } + + void markPertinentPath(Node node, OrderMap& order_map, + NodeData& node_data, ArcLists& arc_lists, + EmbedArc& embed_arc, MergeRoots& merge_roots) { + while (embed_arc[node] == INVALID) { + int n = merge_roots[node].front(); + Arc arc = node_data[n].first; + + _kuratowski.set(arc, true); + + Node pred = node; + node = _graph.target(arc); + while (!pertinent(node, embed_arc, merge_roots)) { + arc = node_data[order_map[node]].first; + if (_graph.target(arc) == pred) { + arc = arc_lists[arc].next; + } + _kuratowski.set(arc, true); + pred = node; + node = _graph.target(arc); + } + } + _kuratowski.set(embed_arc[node], true); + } + + void markPredPath(Node node, Node snode, PredMap& pred_map) { + while (node != snode) { + _kuratowski.set(pred_map[node], true); + node = _graph.source(pred_map[node]); + } + } + + void markFacePath(Node ynode, Node xnode, + OrderMap& order_map, NodeData& node_data) { + Arc arc = node_data[order_map[ynode]].first; + Node node = _graph.target(arc); + _kuratowski.set(arc, true); + + while (node != xnode) { + arc = node_data[order_map[node]].first; + _kuratowski.set(arc, true); + node = _graph.target(arc); + } + } + + void markInternalPath(std::vector& path) { + for (int i = 0; i < int(path.size()); ++i) { + _kuratowski.set(path[i], true); + } + } + + void markPilePath(std::vector& path) { + for (int i = 0; i < int(path.size()); ++i) { + _kuratowski.set(path[i], true); + } + } + + void isolateKuratowski(Arc arc, NodeData& node_data, + ArcLists& arc_lists, FlipMap& flip_map, + OrderMap& order_map, OrderList& order_list, + PredMap& pred_map, ChildLists& child_lists, + AncestorMap& ancestor_map, LowMap& low_map, + EmbedArc& embed_arc, MergeRoots& merge_roots) { + + Node root = _graph.source(arc); + Node enode = _graph.target(arc); + + int rorder = order_map[root]; + + TypeMap type_map(_graph, 0); + + int rn = findComponentRoot(root, enode, child_lists, + order_map, order_list); + + Node xnode = order_list[node_data[rn].next]; + Node ynode = order_list[node_data[rn].prev]; + + // Minor-A + { + while (!merge_roots[xnode].empty() || !merge_roots[ynode].empty()) { + + if (!merge_roots[xnode].empty()) { + root = xnode; + rn = merge_roots[xnode].front(); + } else { + root = ynode; + rn = merge_roots[ynode].front(); + } + + xnode = order_list[node_data[rn].next]; + ynode = order_list[node_data[rn].prev]; + } + + if (root != _graph.source(arc)) { + orientComponent(root, rn, order_map, pred_map, + node_data, arc_lists, flip_map, type_map); + markFacePath(root, root, order_map, node_data); + int xlp = markExternalPath(xnode, order_map, child_lists, + pred_map, ancestor_map, low_map); + int ylp = markExternalPath(ynode, order_map, child_lists, + pred_map, ancestor_map, low_map); + markPredPath(root, order_list[xlp < ylp ? xlp : ylp], pred_map); + Node lwnode = findPertinent(ynode, order_map, node_data, + embed_arc, merge_roots); + + markPertinentPath(lwnode, order_map, node_data, arc_lists, + embed_arc, merge_roots); + + return; + } + } + + orientComponent(root, rn, order_map, pred_map, + node_data, arc_lists, flip_map, type_map); + + Node wnode = findPertinent(ynode, order_map, node_data, + embed_arc, merge_roots); + setFaceFlags(root, wnode, ynode, xnode, order_map, node_data, type_map); + + + //Minor-B + if (!merge_roots[wnode].empty()) { + int cn = merge_roots[wnode].back(); + Node rep = order_list[cn - order_list.size()]; + if (low_map[rep] < rorder) { + markFacePath(root, root, order_map, node_data); + int xlp = markExternalPath(xnode, order_map, child_lists, + pred_map, ancestor_map, low_map); + int ylp = markExternalPath(ynode, order_map, child_lists, + pred_map, ancestor_map, low_map); + + Node lwnode, lznode; + markCommonPath(wnode, rorder, lwnode, lznode, order_list, + order_map, node_data, arc_lists, embed_arc, + merge_roots, child_lists, ancestor_map, low_map); + + markPertinentPath(lwnode, order_map, node_data, arc_lists, + embed_arc, merge_roots); + int zlp = markExternalPath(lznode, order_map, child_lists, + pred_map, ancestor_map, low_map); + + int minlp = xlp < ylp ? xlp : ylp; + if (zlp < minlp) minlp = zlp; + + int maxlp = xlp > ylp ? xlp : ylp; + if (zlp > maxlp) maxlp = zlp; + + markPredPath(order_list[maxlp], order_list[minlp], pred_map); + + return; + } + } + + Node pxnode, pynode; + std::vector ipath; + findInternalPath(ipath, wnode, root, type_map, order_map, + node_data, arc_lists); + setInternalFlags(ipath, type_map); + pynode = _graph.source(ipath.front()); + pxnode = _graph.target(ipath.back()); + + wnode = findPertinent(pynode, order_map, node_data, + embed_arc, merge_roots); + + // Minor-C + { + if (type_map[_graph.source(ipath.front())] == HIGHY) { + if (type_map[_graph.target(ipath.back())] == HIGHX) { + markFacePath(xnode, pxnode, order_map, node_data); + } + markFacePath(root, xnode, order_map, node_data); + markPertinentPath(wnode, order_map, node_data, arc_lists, + embed_arc, merge_roots); + markInternalPath(ipath); + int xlp = markExternalPath(xnode, order_map, child_lists, + pred_map, ancestor_map, low_map); + int ylp = markExternalPath(ynode, order_map, child_lists, + pred_map, ancestor_map, low_map); + markPredPath(root, order_list[xlp < ylp ? xlp : ylp], pred_map); + return; + } + + if (type_map[_graph.target(ipath.back())] == HIGHX) { + markFacePath(ynode, root, order_map, node_data); + markPertinentPath(wnode, order_map, node_data, arc_lists, + embed_arc, merge_roots); + markInternalPath(ipath); + int xlp = markExternalPath(xnode, order_map, child_lists, + pred_map, ancestor_map, low_map); + int ylp = markExternalPath(ynode, order_map, child_lists, + pred_map, ancestor_map, low_map); + markPredPath(root, order_list[xlp < ylp ? xlp : ylp], pred_map); + return; + } + } + + std::vector ppath; + findPilePath(ppath, root, type_map, order_map, node_data, arc_lists); + + // Minor-D + if (!ppath.empty()) { + markFacePath(ynode, xnode, order_map, node_data); + markPertinentPath(wnode, order_map, node_data, arc_lists, + embed_arc, merge_roots); + markPilePath(ppath); + markInternalPath(ipath); + int xlp = markExternalPath(xnode, order_map, child_lists, + pred_map, ancestor_map, low_map); + int ylp = markExternalPath(ynode, order_map, child_lists, + pred_map, ancestor_map, low_map); + markPredPath(root, order_list[xlp < ylp ? xlp : ylp], pred_map); + return; + } + + // Minor-E* + { + + if (!external(wnode, rorder, child_lists, ancestor_map, low_map)) { + Node znode = findExternal(pynode, rorder, order_map, + child_lists, ancestor_map, + low_map, node_data); + + if (type_map[znode] == LOWY) { + markFacePath(root, xnode, order_map, node_data); + markPertinentPath(wnode, order_map, node_data, arc_lists, + embed_arc, merge_roots); + markInternalPath(ipath); + int xlp = markExternalPath(xnode, order_map, child_lists, + pred_map, ancestor_map, low_map); + int zlp = markExternalPath(znode, order_map, child_lists, + pred_map, ancestor_map, low_map); + markPredPath(root, order_list[xlp < zlp ? xlp : zlp], pred_map); + } else { + markFacePath(ynode, root, order_map, node_data); + markPertinentPath(wnode, order_map, node_data, arc_lists, + embed_arc, merge_roots); + markInternalPath(ipath); + int ylp = markExternalPath(ynode, order_map, child_lists, + pred_map, ancestor_map, low_map); + int zlp = markExternalPath(znode, order_map, child_lists, + pred_map, ancestor_map, low_map); + markPredPath(root, order_list[ylp < zlp ? ylp : zlp], pred_map); + } + return; + } + + int xlp = markExternalPath(xnode, order_map, child_lists, + pred_map, ancestor_map, low_map); + int ylp = markExternalPath(ynode, order_map, child_lists, + pred_map, ancestor_map, low_map); + int wlp = markExternalPath(wnode, order_map, child_lists, + pred_map, ancestor_map, low_map); + + if (wlp > xlp && wlp > ylp) { + markFacePath(root, root, order_map, node_data); + markPredPath(root, order_list[xlp < ylp ? xlp : ylp], pred_map); + return; + } + + markInternalPath(ipath); + markPertinentPath(wnode, order_map, node_data, arc_lists, + embed_arc, merge_roots); + + if (xlp > ylp && xlp > wlp) { + markFacePath(root, pynode, order_map, node_data); + markFacePath(wnode, xnode, order_map, node_data); + markPredPath(root, order_list[ylp < wlp ? ylp : wlp], pred_map); + return; + } + + if (ylp > xlp && ylp > wlp) { + markFacePath(pxnode, root, order_map, node_data); + markFacePath(ynode, wnode, order_map, node_data); + markPredPath(root, order_list[xlp < wlp ? xlp : wlp], pred_map); + return; + } + + if (pynode != ynode) { + markFacePath(pxnode, wnode, order_map, node_data); + + int minlp = xlp < ylp ? xlp : ylp; + if (wlp < minlp) minlp = wlp; + + int maxlp = xlp > ylp ? xlp : ylp; + if (wlp > maxlp) maxlp = wlp; + + markPredPath(order_list[maxlp], order_list[minlp], pred_map); + return; + } + + if (pxnode != xnode) { + markFacePath(wnode, pynode, order_map, node_data); + + int minlp = xlp < ylp ? xlp : ylp; + if (wlp < minlp) minlp = wlp; + + int maxlp = xlp > ylp ? xlp : ylp; + if (wlp > maxlp) maxlp = wlp; + + markPredPath(order_list[maxlp], order_list[minlp], pred_map); + return; + } + + markFacePath(root, root, order_map, node_data); + int minlp = xlp < ylp ? xlp : ylp; + if (wlp < minlp) minlp = wlp; + markPredPath(root, order_list[minlp], pred_map); + return; + } + + } + + }; + + namespace _planarity_bits { + + template + void makeConnected(Graph& graph, EmbeddingMap& embedding) { + DfsVisitor null_visitor; + DfsVisit > dfs(graph, null_visitor); + dfs.init(); + + typename Graph::Node u = INVALID; + for (typename Graph::NodeIt n(graph); n != INVALID; ++n) { + if (!dfs.reached(n)) { + dfs.addSource(n); + dfs.start(); + if (u == INVALID) { + u = n; + } else { + typename Graph::Node v = n; + + typename Graph::Arc ue = typename Graph::OutArcIt(graph, u); + typename Graph::Arc ve = typename Graph::OutArcIt(graph, v); + + typename Graph::Arc e = graph.direct(graph.addEdge(u, v), true); + + if (ue != INVALID) { + embedding[e] = embedding[ue]; + embedding[ue] = e; + } else { + embedding[e] = e; + } + + if (ve != INVALID) { + embedding[graph.oppositeArc(e)] = embedding[ve]; + embedding[ve] = graph.oppositeArc(e); + } else { + embedding[graph.oppositeArc(e)] = graph.oppositeArc(e); + } + } + } + } + } + + template + void makeBiNodeConnected(Graph& graph, EmbeddingMap& embedding) { + typename Graph::template ArcMap processed(graph); + + std::vector arcs; + for (typename Graph::ArcIt e(graph); e != INVALID; ++e) { + arcs.push_back(e); + } + + IterableBoolMap visited(graph, false); + + for (int i = 0; i < int(arcs.size()); ++i) { + typename Graph::Arc pp = arcs[i]; + if (processed[pp]) continue; + + typename Graph::Arc e = embedding[graph.oppositeArc(pp)]; + processed[e] = true; + visited.set(graph.source(e), true); + + typename Graph::Arc p = e, l = e; + e = embedding[graph.oppositeArc(e)]; + + while (e != l) { + processed[e] = true; + + if (visited[graph.source(e)]) { + + typename Graph::Arc n = + graph.direct(graph.addEdge(graph.source(p), + graph.target(e)), true); + embedding[n] = p; + embedding[graph.oppositeArc(pp)] = n; + + embedding[graph.oppositeArc(n)] = + embedding[graph.oppositeArc(e)]; + embedding[graph.oppositeArc(e)] = + graph.oppositeArc(n); + + p = n; + e = embedding[graph.oppositeArc(n)]; + } else { + visited.set(graph.source(e), true); + pp = p; + p = e; + e = embedding[graph.oppositeArc(e)]; + } + } + visited.setAll(false); + } + } + + + template + void makeMaxPlanar(Graph& graph, EmbeddingMap& embedding) { + + typename Graph::template NodeMap degree(graph); + + for (typename Graph::NodeIt n(graph); n != INVALID; ++n) { + degree[n] = countIncEdges(graph, n); + } + + typename Graph::template ArcMap processed(graph); + IterableBoolMap visited(graph, false); + + std::vector arcs; + for (typename Graph::ArcIt e(graph); e != INVALID; ++e) { + arcs.push_back(e); + } + + for (int i = 0; i < int(arcs.size()); ++i) { + typename Graph::Arc e = arcs[i]; + + if (processed[e]) continue; + processed[e] = true; + + typename Graph::Arc mine = e; + int mind = degree[graph.source(e)]; + + int face_size = 1; + + typename Graph::Arc l = e; + e = embedding[graph.oppositeArc(e)]; + while (l != e) { + processed[e] = true; + + ++face_size; + + if (degree[graph.source(e)] < mind) { + mine = e; + mind = degree[graph.source(e)]; + } + + e = embedding[graph.oppositeArc(e)]; + } + + if (face_size < 4) { + continue; + } + + typename Graph::Node s = graph.source(mine); + for (typename Graph::OutArcIt e(graph, s); e != INVALID; ++e) { + visited.set(graph.target(e), true); + } + + typename Graph::Arc oppe = INVALID; + + e = embedding[graph.oppositeArc(mine)]; + e = embedding[graph.oppositeArc(e)]; + while (graph.target(e) != s) { + if (visited[graph.source(e)]) { + oppe = e; + break; + } + e = embedding[graph.oppositeArc(e)]; + } + visited.setAll(false); + + if (oppe == INVALID) { + + e = embedding[graph.oppositeArc(mine)]; + typename Graph::Arc pn = mine, p = e; + + e = embedding[graph.oppositeArc(e)]; + while (graph.target(e) != s) { + typename Graph::Arc n = + graph.direct(graph.addEdge(s, graph.source(e)), true); + + embedding[n] = pn; + embedding[graph.oppositeArc(n)] = e; + embedding[graph.oppositeArc(p)] = graph.oppositeArc(n); + + pn = n; + + p = e; + e = embedding[graph.oppositeArc(e)]; + } + + embedding[graph.oppositeArc(e)] = pn; + + } else { + + mine = embedding[graph.oppositeArc(mine)]; + s = graph.source(mine); + oppe = embedding[graph.oppositeArc(oppe)]; + typename Graph::Node t = graph.source(oppe); + + typename Graph::Arc ce = graph.direct(graph.addEdge(s, t), true); + embedding[ce] = mine; + embedding[graph.oppositeArc(ce)] = oppe; + + typename Graph::Arc pn = ce, p = oppe; + e = embedding[graph.oppositeArc(oppe)]; + while (graph.target(e) != s) { + typename Graph::Arc n = + graph.direct(graph.addEdge(s, graph.source(e)), true); + + embedding[n] = pn; + embedding[graph.oppositeArc(n)] = e; + embedding[graph.oppositeArc(p)] = graph.oppositeArc(n); + + pn = n; + + p = e; + e = embedding[graph.oppositeArc(e)]; + + } + embedding[graph.oppositeArc(e)] = pn; + + pn = graph.oppositeArc(ce), p = mine; + e = embedding[graph.oppositeArc(mine)]; + while (graph.target(e) != t) { + typename Graph::Arc n = + graph.direct(graph.addEdge(t, graph.source(e)), true); + + embedding[n] = pn; + embedding[graph.oppositeArc(n)] = e; + embedding[graph.oppositeArc(p)] = graph.oppositeArc(n); + + pn = n; + + p = e; + e = embedding[graph.oppositeArc(e)]; + + } + embedding[graph.oppositeArc(e)] = pn; + } + } + } + + } + + /// \ingroup planar + /// + /// \brief Schnyder's planar drawing algorithm + /// + /// The planar drawing algorithm calculates positions for the nodes + /// in the plane. These coordinates satisfy that if the edges are + /// represented with straight lines, then they will not intersect + /// each other. + /// + /// Scnyder's algorithm embeds the graph on an \c (n-2)x(n-2) size grid, + /// i.e. each node will be located in the \c [0..n-2]x[0..n-2] square. + /// The time complexity of the algorithm is O(n). + /// + /// \see PlanarEmbedding + template + class PlanarDrawing { + public: + + TEMPLATE_GRAPH_TYPEDEFS(Graph); + + /// \brief The point type for storing coordinates + typedef dim2::Point Point; + /// \brief The map type for storing the coordinates of the nodes + typedef typename Graph::template NodeMap PointMap; + + + /// \brief Constructor + /// + /// Constructor + /// \pre The graph must be simple, i.e. it should not + /// contain parallel or loop arcs. + PlanarDrawing(const Graph& graph) + : _graph(graph), _point_map(graph) {} + + private: + + template + void drawing(const AuxGraph& graph, + const AuxEmbeddingMap& next, + PointMap& point_map) { + TEMPLATE_GRAPH_TYPEDEFS(AuxGraph); + + typename AuxGraph::template ArcMap prev(graph); + + for (NodeIt n(graph); n != INVALID; ++n) { + Arc e = OutArcIt(graph, n); + + Arc p = e, l = e; + + e = next[e]; + while (e != l) { + prev[e] = p; + p = e; + e = next[e]; + } + prev[e] = p; + } + + Node anode, bnode, cnode; + + { + Arc e = ArcIt(graph); + anode = graph.source(e); + bnode = graph.target(e); + cnode = graph.target(next[graph.oppositeArc(e)]); + } + + IterableBoolMap proper(graph, false); + typename AuxGraph::template NodeMap conn(graph, -1); + + conn[anode] = conn[bnode] = -2; + { + for (OutArcIt e(graph, anode); e != INVALID; ++e) { + Node m = graph.target(e); + if (conn[m] == -1) { + conn[m] = 1; + } + } + conn[cnode] = 2; + + for (OutArcIt e(graph, bnode); e != INVALID; ++e) { + Node m = graph.target(e); + if (conn[m] == -1) { + conn[m] = 1; + } else if (conn[m] != -2) { + conn[m] += 1; + Arc pe = graph.oppositeArc(e); + if (conn[graph.target(next[pe])] == -2) { + conn[m] -= 1; + } + if (conn[graph.target(prev[pe])] == -2) { + conn[m] -= 1; + } + + proper.set(m, conn[m] == 1); + } + } + } + + + typename AuxGraph::template ArcMap angle(graph, -1); + + while (proper.trueNum() != 0) { + Node n = typename IterableBoolMap::TrueIt(proper); + proper.set(n, false); + conn[n] = -2; + + for (OutArcIt e(graph, n); e != INVALID; ++e) { + Node m = graph.target(e); + if (conn[m] == -1) { + conn[m] = 1; + } else if (conn[m] != -2) { + conn[m] += 1; + Arc pe = graph.oppositeArc(e); + if (conn[graph.target(next[pe])] == -2) { + conn[m] -= 1; + } + if (conn[graph.target(prev[pe])] == -2) { + conn[m] -= 1; + } + + proper.set(m, conn[m] == 1); + } + } + + { + Arc e = OutArcIt(graph, n); + Arc p = e, l = e; + + e = next[e]; + while (e != l) { + + if (conn[graph.target(e)] == -2 && conn[graph.target(p)] == -2) { + Arc f = e; + angle[f] = 0; + f = next[graph.oppositeArc(f)]; + angle[f] = 1; + f = next[graph.oppositeArc(f)]; + angle[f] = 2; + } + + p = e; + e = next[e]; + } + + if (conn[graph.target(e)] == -2 && conn[graph.target(p)] == -2) { + Arc f = e; + angle[f] = 0; + f = next[graph.oppositeArc(f)]; + angle[f] = 1; + f = next[graph.oppositeArc(f)]; + angle[f] = 2; + } + } + } + + typename AuxGraph::template NodeMap apred(graph, INVALID); + typename AuxGraph::template NodeMap bpred(graph, INVALID); + typename AuxGraph::template NodeMap cpred(graph, INVALID); + + typename AuxGraph::template NodeMap apredid(graph, -1); + typename AuxGraph::template NodeMap bpredid(graph, -1); + typename AuxGraph::template NodeMap cpredid(graph, -1); + + for (ArcIt e(graph); e != INVALID; ++e) { + if (angle[e] == angle[next[e]]) { + switch (angle[e]) { + case 2: + apred[graph.target(e)] = graph.source(e); + apredid[graph.target(e)] = graph.id(graph.source(e)); + break; + case 1: + bpred[graph.target(e)] = graph.source(e); + bpredid[graph.target(e)] = graph.id(graph.source(e)); + break; + case 0: + cpred[graph.target(e)] = graph.source(e); + cpredid[graph.target(e)] = graph.id(graph.source(e)); + break; + } + } + } + + cpred[anode] = INVALID; + cpred[bnode] = INVALID; + + std::vector aorder, border, corder; + + { + typename AuxGraph::template NodeMap processed(graph, false); + std::vector st; + for (NodeIt n(graph); n != INVALID; ++n) { + if (!processed[n] && n != bnode && n != cnode) { + st.push_back(n); + processed[n] = true; + Node m = apred[n]; + while (m != INVALID && !processed[m]) { + st.push_back(m); + processed[m] = true; + m = apred[m]; + } + while (!st.empty()) { + aorder.push_back(st.back()); + st.pop_back(); + } + } + } + } + + { + typename AuxGraph::template NodeMap processed(graph, false); + std::vector st; + for (NodeIt n(graph); n != INVALID; ++n) { + if (!processed[n] && n != cnode && n != anode) { + st.push_back(n); + processed[n] = true; + Node m = bpred[n]; + while (m != INVALID && !processed[m]) { + st.push_back(m); + processed[m] = true; + m = bpred[m]; + } + while (!st.empty()) { + border.push_back(st.back()); + st.pop_back(); + } + } + } + } + + { + typename AuxGraph::template NodeMap processed(graph, false); + std::vector st; + for (NodeIt n(graph); n != INVALID; ++n) { + if (!processed[n] && n != anode && n != bnode) { + st.push_back(n); + processed[n] = true; + Node m = cpred[n]; + while (m != INVALID && !processed[m]) { + st.push_back(m); + processed[m] = true; + m = cpred[m]; + } + while (!st.empty()) { + corder.push_back(st.back()); + st.pop_back(); + } + } + } + } + + typename AuxGraph::template NodeMap atree(graph, 0); + for (int i = aorder.size() - 1; i >= 0; --i) { + Node n = aorder[i]; + atree[n] = 1; + for (OutArcIt e(graph, n); e != INVALID; ++e) { + if (apred[graph.target(e)] == n) { + atree[n] += atree[graph.target(e)]; + } + } + } + + typename AuxGraph::template NodeMap btree(graph, 0); + for (int i = border.size() - 1; i >= 0; --i) { + Node n = border[i]; + btree[n] = 1; + for (OutArcIt e(graph, n); e != INVALID; ++e) { + if (bpred[graph.target(e)] == n) { + btree[n] += btree[graph.target(e)]; + } + } + } + + typename AuxGraph::template NodeMap apath(graph, 0); + apath[bnode] = apath[cnode] = 1; + typename AuxGraph::template NodeMap apath_btree(graph, 0); + apath_btree[bnode] = btree[bnode]; + for (int i = 1; i < int(aorder.size()); ++i) { + Node n = aorder[i]; + apath[n] = apath[apred[n]] + 1; + apath_btree[n] = btree[n] + apath_btree[apred[n]]; + } + + typename AuxGraph::template NodeMap bpath_atree(graph, 0); + bpath_atree[anode] = atree[anode]; + for (int i = 1; i < int(border.size()); ++i) { + Node n = border[i]; + bpath_atree[n] = atree[n] + bpath_atree[bpred[n]]; + } + + typename AuxGraph::template NodeMap cpath(graph, 0); + cpath[anode] = cpath[bnode] = 1; + typename AuxGraph::template NodeMap cpath_atree(graph, 0); + cpath_atree[anode] = atree[anode]; + typename AuxGraph::template NodeMap cpath_btree(graph, 0); + cpath_btree[bnode] = btree[bnode]; + for (int i = 1; i < int(corder.size()); ++i) { + Node n = corder[i]; + cpath[n] = cpath[cpred[n]] + 1; + cpath_atree[n] = atree[n] + cpath_atree[cpred[n]]; + cpath_btree[n] = btree[n] + cpath_btree[cpred[n]]; + } + + typename AuxGraph::template NodeMap third(graph); + for (NodeIt n(graph); n != INVALID; ++n) { + point_map[n].x = + bpath_atree[n] + cpath_atree[n] - atree[n] - cpath[n] + 1; + point_map[n].y = + cpath_btree[n] + apath_btree[n] - btree[n] - apath[n] + 1; + } + + } + + public: + + /// \brief Calculate the node positions + /// + /// This function calculates the node positions on the plane. + /// \return \c true if the graph is planar. + bool run() { + PlanarEmbedding pe(_graph); + if (!pe.run()) return false; + + run(pe); + return true; + } + + /// \brief Calculate the node positions according to a + /// combinatorical embedding + /// + /// This function calculates the node positions on the plane. + /// The given \c embedding map should contain a valid combinatorical + /// embedding, i.e. a valid cyclic order of the arcs. + /// It can be computed using PlanarEmbedding. + template + void run(const EmbeddingMap& embedding) { + typedef SmartEdgeSet AuxGraph; + + if (3 * countNodes(_graph) - 6 == countEdges(_graph)) { + drawing(_graph, embedding, _point_map); + return; + } + + AuxGraph aux_graph(_graph); + typename AuxGraph::template ArcMap + aux_embedding(aux_graph); + + { + + typename Graph::template EdgeMap + ref(_graph); + + for (EdgeIt e(_graph); e != INVALID; ++e) { + ref[e] = aux_graph.addEdge(_graph.u(e), _graph.v(e)); + } + + for (EdgeIt e(_graph); e != INVALID; ++e) { + Arc ee = embedding[_graph.direct(e, true)]; + aux_embedding[aux_graph.direct(ref[e], true)] = + aux_graph.direct(ref[ee], _graph.direction(ee)); + ee = embedding[_graph.direct(e, false)]; + aux_embedding[aux_graph.direct(ref[e], false)] = + aux_graph.direct(ref[ee], _graph.direction(ee)); + } + } + _planarity_bits::makeConnected(aux_graph, aux_embedding); + _planarity_bits::makeBiNodeConnected(aux_graph, aux_embedding); + _planarity_bits::makeMaxPlanar(aux_graph, aux_embedding); + drawing(aux_graph, aux_embedding, _point_map); + } + + /// \brief The coordinate of the given node + /// + /// This function returns the coordinate of the given node. + Point operator[](const Node& node) const { + return _point_map[node]; + } + + /// \brief Return the grid embedding in a node map + /// + /// This function returns the grid embedding in a node map of + /// \c dim2::Point coordinates. + const PointMap& coords() const { + return _point_map; + } + + private: + + const Graph& _graph; + PointMap _point_map; + + }; + + namespace _planarity_bits { + + template + class KempeFilter { + public: + typedef typename ColorMap::Key Key; + typedef bool Value; + + KempeFilter(const ColorMap& color_map, + const typename ColorMap::Value& first, + const typename ColorMap::Value& second) + : _color_map(color_map), _first(first), _second(second) {} + + Value operator[](const Key& key) const { + return _color_map[key] == _first || _color_map[key] == _second; + } + + private: + const ColorMap& _color_map; + typename ColorMap::Value _first, _second; + }; + } + + /// \ingroup planar + /// + /// \brief Coloring planar graphs + /// + /// The graph coloring problem is the coloring of the graph nodes + /// so that there are no adjacent nodes with the same color. The + /// planar graphs can always be colored with four colors, which is + /// proved by Appel and Haken. Their proofs provide a quadratic + /// time algorithm for four coloring, but it could not be used to + /// implement an efficient algorithm. The five and six coloring can be + /// made in linear time, but in this class, the five coloring has + /// quadratic worst case time complexity. The two coloring (if + /// possible) is solvable with a graph search algorithm and it is + /// implemented in \ref bipartitePartitions() function in LEMON. To + /// decide whether a planar graph is three colorable is NP-complete. + /// + /// This class contains member functions for calculate colorings + /// with five and six colors. The six coloring algorithm is a simple + /// greedy coloring on the backward minimum outgoing order of nodes. + /// This order can be computed by selecting the node with least + /// outgoing arcs to unprocessed nodes in each phase. This order + /// guarantees that when a node is chosen for coloring it has at + /// most five already colored adjacents. The five coloring algorithm + /// use the same method, but if the greedy approach fails to color + /// with five colors, i.e. the node has five already different + /// colored neighbours, it swaps the colors in one of the connected + /// two colored sets with the Kempe recoloring method. + template + class PlanarColoring { + public: + + TEMPLATE_GRAPH_TYPEDEFS(Graph); + + /// \brief The map type for storing color indices + typedef typename Graph::template NodeMap IndexMap; + /// \brief The map type for storing colors + /// + /// The map type for storing colors. + /// \see Palette, Color + typedef ComposeMap ColorMap; + + /// \brief Constructor + /// + /// Constructor. + /// \pre The graph must be simple, i.e. it should not + /// contain parallel or loop arcs. + PlanarColoring(const Graph& graph) + : _graph(graph), _color_map(graph), _palette(0) { + _palette.add(Color(1,0,0)); + _palette.add(Color(0,1,0)); + _palette.add(Color(0,0,1)); + _palette.add(Color(1,1,0)); + _palette.add(Color(1,0,1)); + _palette.add(Color(0,1,1)); + } + + /// \brief Return the node map of color indices + /// + /// This function returns the node map of color indices. The values are + /// in the range \c [0..4] or \c [0..5] according to the coloring method. + IndexMap colorIndexMap() const { + return _color_map; + } + + /// \brief Return the node map of colors + /// + /// This function returns the node map of colors. The values are among + /// five or six distinct \ref lemon::Color "colors". + ColorMap colorMap() const { + return composeMap(_palette, _color_map); + } + + /// \brief Return the color index of the node + /// + /// This function returns the color index of the given node. The value is + /// in the range \c [0..4] or \c [0..5] according to the coloring method. + int colorIndex(const Node& node) const { + return _color_map[node]; + } + + /// \brief Return the color of the node + /// + /// This function returns the color of the given node. The value is among + /// five or six distinct \ref lemon::Color "colors". + Color color(const Node& node) const { + return _palette[_color_map[node]]; + } + + + /// \brief Calculate a coloring with at most six colors + /// + /// This function calculates a coloring with at most six colors. The time + /// complexity of this variant is linear in the size of the graph. + /// \return \c true if the algorithm could color the graph with six colors. + /// If the algorithm fails, then the graph is not planar. + /// \note This function can return \c true if the graph is not + /// planar, but it can be colored with at most six colors. + bool runSixColoring() { + + typename Graph::template NodeMap heap_index(_graph, -1); + BucketHeap > heap(heap_index); + + for (NodeIt n(_graph); n != INVALID; ++n) { + _color_map[n] = -2; + heap.push(n, countOutArcs(_graph, n)); + } + + std::vector order; + + while (!heap.empty()) { + Node n = heap.top(); + heap.pop(); + _color_map[n] = -1; + order.push_back(n); + for (OutArcIt e(_graph, n); e != INVALID; ++e) { + Node t = _graph.runningNode(e); + if (_color_map[t] == -2) { + heap.decrease(t, heap[t] - 1); + } + } + } + + for (int i = order.size() - 1; i >= 0; --i) { + std::vector forbidden(6, false); + for (OutArcIt e(_graph, order[i]); e != INVALID; ++e) { + Node t = _graph.runningNode(e); + if (_color_map[t] != -1) { + forbidden[_color_map[t]] = true; + } + } + for (int k = 0; k < 6; ++k) { + if (!forbidden[k]) { + _color_map[order[i]] = k; + break; + } + } + if (_color_map[order[i]] == -1) { + return false; + } + } + return true; + } + + private: + + bool recolor(const Node& u, const Node& v) { + int ucolor = _color_map[u]; + int vcolor = _color_map[v]; + typedef _planarity_bits::KempeFilter KempeFilter; + KempeFilter filter(_color_map, ucolor, vcolor); + + typedef FilterNodes KempeGraph; + KempeGraph kempe_graph(_graph, filter); + + std::vector comp; + Bfs bfs(kempe_graph); + bfs.init(); + bfs.addSource(u); + while (!bfs.emptyQueue()) { + Node n = bfs.nextNode(); + if (n == v) return false; + comp.push_back(n); + bfs.processNextNode(); + } + + int scolor = ucolor + vcolor; + for (int i = 0; i < static_cast(comp.size()); ++i) { + _color_map[comp[i]] = scolor - _color_map[comp[i]]; + } + + return true; + } + + template + void kempeRecoloring(const Node& node, const EmbeddingMap& embedding) { + std::vector nodes; + nodes.reserve(4); + + for (Arc e = OutArcIt(_graph, node); e != INVALID; e = embedding[e]) { + Node t = _graph.target(e); + if (_color_map[t] != -1) { + nodes.push_back(t); + if (nodes.size() == 4) break; + } + } + + int color = _color_map[nodes[0]]; + if (recolor(nodes[0], nodes[2])) { + _color_map[node] = color; + } else { + color = _color_map[nodes[1]]; + recolor(nodes[1], nodes[3]); + _color_map[node] = color; + } + } + + public: + + /// \brief Calculate a coloring with at most five colors + /// + /// This function calculates a coloring with at most five + /// colors. The worst case time complexity of this variant is + /// quadratic in the size of the graph. + /// \param embedding This map should contain a valid combinatorical + /// embedding, i.e. a valid cyclic order of the arcs. + /// It can be computed using PlanarEmbedding. + template + void runFiveColoring(const EmbeddingMap& embedding) { + + typename Graph::template NodeMap heap_index(_graph, -1); + BucketHeap > heap(heap_index); + + for (NodeIt n(_graph); n != INVALID; ++n) { + _color_map[n] = -2; + heap.push(n, countOutArcs(_graph, n)); + } + + std::vector order; + + while (!heap.empty()) { + Node n = heap.top(); + heap.pop(); + _color_map[n] = -1; + order.push_back(n); + for (OutArcIt e(_graph, n); e != INVALID; ++e) { + Node t = _graph.runningNode(e); + if (_color_map[t] == -2) { + heap.decrease(t, heap[t] - 1); + } + } + } + + for (int i = order.size() - 1; i >= 0; --i) { + std::vector forbidden(5, false); + for (OutArcIt e(_graph, order[i]); e != INVALID; ++e) { + Node t = _graph.runningNode(e); + if (_color_map[t] != -1) { + forbidden[_color_map[t]] = true; + } + } + for (int k = 0; k < 5; ++k) { + if (!forbidden[k]) { + _color_map[order[i]] = k; + break; + } + } + if (_color_map[order[i]] == -1) { + kempeRecoloring(order[i], embedding); + } + } + } + + /// \brief Calculate a coloring with at most five colors + /// + /// This function calculates a coloring with at most five + /// colors. The worst case time complexity of this variant is + /// quadratic in the size of the graph. + /// \return \c true if the graph is planar. + bool runFiveColoring() { + PlanarEmbedding pe(_graph); + if (!pe.run()) return false; + + runFiveColoring(pe.embeddingMap()); + return true; + } + + private: + + const Graph& _graph; + IndexMap _color_map; + Palette _palette; + }; + +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/preflow.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/preflow.h new file mode 100644 index 00000000000..28ccd67dcf1 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/preflow.h @@ -0,0 +1,985 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_PREFLOW_H +#define LEMON_PREFLOW_H + +#include +#include + +/// \file +/// \ingroup max_flow +/// \brief Implementation of the preflow algorithm. + +namespace lemon { + + /// \brief Default traits class of Preflow class. + /// + /// Default traits class of Preflow class. + /// \tparam GR Digraph type. + /// \tparam CAP Capacity map type. + template + struct PreflowDefaultTraits { + + /// \brief The type of the digraph the algorithm runs on. + typedef GR Digraph; + + /// \brief The type of the map that stores the arc capacities. + /// + /// The type of the map that stores the arc capacities. + /// It must meet the \ref concepts::ReadMap "ReadMap" concept. + typedef CAP CapacityMap; + + /// \brief The type of the flow values. + typedef typename CapacityMap::Value Value; + + /// \brief The type of the map that stores the flow values. + /// + /// The type of the map that stores the flow values. + /// It must meet the \ref concepts::ReadWriteMap "ReadWriteMap" concept. +#ifdef DOXYGEN + typedef GR::ArcMap FlowMap; +#else + typedef typename Digraph::template ArcMap FlowMap; +#endif + + /// \brief Instantiates a FlowMap. + /// + /// This function instantiates a \ref FlowMap. + /// \param digraph The digraph for which we would like to define + /// the flow map. + static FlowMap* createFlowMap(const Digraph& digraph) { + return new FlowMap(digraph); + } + + /// \brief The elevator type used by Preflow algorithm. + /// + /// The elevator type used by Preflow algorithm. + /// + /// \sa Elevator, LinkedElevator +#ifdef DOXYGEN + typedef lemon::Elevator Elevator; +#else + typedef lemon::Elevator Elevator; +#endif + + /// \brief Instantiates an Elevator. + /// + /// This function instantiates an \ref Elevator. + /// \param digraph The digraph for which we would like to define + /// the elevator. + /// \param max_level The maximum level of the elevator. + static Elevator* createElevator(const Digraph& digraph, int max_level) { + return new Elevator(digraph, max_level); + } + + /// \brief The tolerance used by the algorithm + /// + /// The tolerance used by the algorithm to handle inexact computation. + typedef lemon::Tolerance Tolerance; + + }; + + + /// \ingroup max_flow + /// + /// \brief %Preflow algorithm class. + /// + /// This class provides an implementation of Goldberg-Tarjan's \e preflow + /// \e push-relabel algorithm producing a \ref max_flow + /// "flow of maximum value" in a digraph \cite clrs01algorithms, + /// \cite amo93networkflows, \cite goldberg88newapproach. + /// The preflow algorithms are the fastest known maximum + /// flow algorithms. The current implementation uses a mixture of the + /// \e "highest label" and the \e "bound decrease" heuristics. + /// The worst case time complexity of the algorithm is \f$O(n^2\sqrt{m})\f$. + /// + /// The algorithm consists of two phases. After the first phase + /// the maximum flow value and the minimum cut is obtained. The + /// second phase constructs a feasible maximum flow on each arc. + /// + /// \warning This implementation cannot handle infinite or very large + /// capacities (e.g. the maximum value of \c CAP::Value). + /// + /// \tparam GR The type of the digraph the algorithm runs on. + /// \tparam CAP The type of the capacity map. The default map + /// type is \ref concepts::Digraph::ArcMap "GR::ArcMap". + /// \tparam TR The traits class that defines various types used by the + /// algorithm. By default, it is \ref PreflowDefaultTraits + /// "PreflowDefaultTraits". + /// In most cases, this parameter should not be set directly, + /// consider to use the named template parameters instead. +#ifdef DOXYGEN + template +#else + template , + typename TR = PreflowDefaultTraits > +#endif + class Preflow { + public: + + ///The \ref lemon::PreflowDefaultTraits "traits class" of the algorithm. + typedef TR Traits; + ///The type of the digraph the algorithm runs on. + typedef typename Traits::Digraph Digraph; + ///The type of the capacity map. + typedef typename Traits::CapacityMap CapacityMap; + ///The type of the flow values. + typedef typename Traits::Value Value; + + ///The type of the flow map. + typedef typename Traits::FlowMap FlowMap; + ///The type of the elevator. + typedef typename Traits::Elevator Elevator; + ///The type of the tolerance. + typedef typename Traits::Tolerance Tolerance; + + private: + + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + + const Digraph& _graph; + const CapacityMap* _capacity; + + int _node_num; + + Node _source, _target; + + FlowMap* _flow; + bool _local_flow; + + Elevator* _level; + bool _local_level; + + typedef typename Digraph::template NodeMap ExcessMap; + ExcessMap* _excess; + + Tolerance _tolerance; + + bool _phase; + + + void createStructures() { + _node_num = countNodes(_graph); + + if (!_flow) { + _flow = Traits::createFlowMap(_graph); + _local_flow = true; + } + if (!_level) { + _level = Traits::createElevator(_graph, _node_num); + _local_level = true; + } + if (!_excess) { + _excess = new ExcessMap(_graph); + } + } + + void destroyStructures() { + if (_local_flow) { + delete _flow; + } + if (_local_level) { + delete _level; + } + if (_excess) { + delete _excess; + } + } + + public: + + typedef Preflow Create; + + ///\name Named Template Parameters + + ///@{ + + template + struct SetFlowMapTraits : public Traits { + typedef T FlowMap; + static FlowMap *createFlowMap(const Digraph&) { + LEMON_ASSERT(false, "FlowMap is not initialized"); + return 0; // ignore warnings + } + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// FlowMap type + /// + /// \ref named-templ-param "Named parameter" for setting FlowMap + /// type. + template + struct SetFlowMap + : public Preflow > { + typedef Preflow > Create; + }; + + template + struct SetElevatorTraits : public Traits { + typedef T Elevator; + static Elevator *createElevator(const Digraph&, int) { + LEMON_ASSERT(false, "Elevator is not initialized"); + return 0; // ignore warnings + } + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// Elevator type + /// + /// \ref named-templ-param "Named parameter" for setting Elevator + /// type. If this named parameter is used, then an external + /// elevator object must be passed to the algorithm using the + /// \ref elevator(Elevator&) "elevator()" function before calling + /// \ref run() or \ref init(). + /// \sa SetStandardElevator + template + struct SetElevator + : public Preflow > { + typedef Preflow > Create; + }; + + template + struct SetStandardElevatorTraits : public Traits { + typedef T Elevator; + static Elevator *createElevator(const Digraph& digraph, int max_level) { + return new Elevator(digraph, max_level); + } + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// Elevator type with automatic allocation + /// + /// \ref named-templ-param "Named parameter" for setting Elevator + /// type with automatic allocation. + /// The Elevator should have standard constructor interface to be + /// able to automatically created by the algorithm (i.e. the + /// digraph and the maximum level should be passed to it). + /// However, an external elevator object could also be passed to the + /// algorithm with the \ref elevator(Elevator&) "elevator()" function + /// before calling \ref run() or \ref init(). + /// \sa SetElevator + template + struct SetStandardElevator + : public Preflow > { + typedef Preflow > Create; + }; + + /// @} + + protected: + + Preflow() {} + + public: + + + /// \brief The constructor of the class. + /// + /// The constructor of the class. + /// \param digraph The digraph the algorithm runs on. + /// \param capacity The capacity of the arcs. + /// \param source The source node. + /// \param target The target node. + Preflow(const Digraph& digraph, const CapacityMap& capacity, + Node source, Node target) + : _graph(digraph), _capacity(&capacity), + _node_num(0), _source(source), _target(target), + _flow(0), _local_flow(false), + _level(0), _local_level(false), + _excess(0), _tolerance(), _phase() {} + + /// \brief Destructor. + /// + /// Destructor. + ~Preflow() { + destroyStructures(); + } + + /// \brief Sets the capacity map. + /// + /// Sets the capacity map. + /// \return (*this) + Preflow& capacityMap(const CapacityMap& map) { + _capacity = ↦ + return *this; + } + + /// \brief Sets the flow map. + /// + /// Sets the flow map. + /// If you don't use this function before calling \ref run() or + /// \ref init(), an instance will be allocated automatically. + /// The destructor deallocates this automatically allocated map, + /// of course. + /// \return (*this) + Preflow& flowMap(FlowMap& map) { + if (_local_flow) { + delete _flow; + _local_flow = false; + } + _flow = ↦ + return *this; + } + + /// \brief Sets the source node. + /// + /// Sets the source node. + /// \return (*this) + Preflow& source(const Node& node) { + _source = node; + return *this; + } + + /// \brief Sets the target node. + /// + /// Sets the target node. + /// \return (*this) + Preflow& target(const Node& node) { + _target = node; + return *this; + } + + /// \brief Sets the elevator used by algorithm. + /// + /// Sets the elevator used by algorithm. + /// If you don't use this function before calling \ref run() or + /// \ref init(), an instance will be allocated automatically. + /// The destructor deallocates this automatically allocated elevator, + /// of course. + /// \return (*this) + Preflow& elevator(Elevator& elevator) { + if (_local_level) { + delete _level; + _local_level = false; + } + _level = &elevator; + return *this; + } + + /// \brief Returns a const reference to the elevator. + /// + /// Returns a const reference to the elevator. + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + const Elevator& elevator() const { + return *_level; + } + + /// \brief Sets the tolerance used by the algorithm. + /// + /// Sets the tolerance object used by the algorithm. + /// \return (*this) + Preflow& tolerance(const Tolerance& tolerance) { + _tolerance = tolerance; + return *this; + } + + /// \brief Returns a const reference to the tolerance. + /// + /// Returns a const reference to the tolerance object used by + /// the algorithm. + const Tolerance& tolerance() const { + return _tolerance; + } + + /// \name Execution Control + /// The simplest way to execute the preflow algorithm is to use + /// \ref run() or \ref runMinCut().\n + /// If you need better control on the initial solution or the execution, + /// you have to call one of the \ref init() functions first, then + /// \ref startFirstPhase() and if you need it \ref startSecondPhase(). + + ///@{ + + /// \brief Initializes the internal data structures. + /// + /// Initializes the internal data structures and sets the initial + /// flow to zero on each arc. + void init() { + createStructures(); + + _phase = true; + for (NodeIt n(_graph); n != INVALID; ++n) { + (*_excess)[n] = 0; + } + + for (ArcIt e(_graph); e != INVALID; ++e) { + _flow->set(e, 0); + } + + typename Digraph::template NodeMap reached(_graph, false); + + _level->initStart(); + _level->initAddItem(_target); + + std::vector queue; + reached[_source] = true; + + queue.push_back(_target); + reached[_target] = true; + while (!queue.empty()) { + _level->initNewLevel(); + std::vector nqueue; + for (int i = 0; i < int(queue.size()); ++i) { + Node n = queue[i]; + for (InArcIt e(_graph, n); e != INVALID; ++e) { + Node u = _graph.source(e); + if (!reached[u] && _tolerance.positive((*_capacity)[e])) { + reached[u] = true; + _level->initAddItem(u); + nqueue.push_back(u); + } + } + } + queue.swap(nqueue); + } + _level->initFinish(); + + for (OutArcIt e(_graph, _source); e != INVALID; ++e) { + if (_tolerance.positive((*_capacity)[e])) { + Node u = _graph.target(e); + if ((*_level)[u] == _level->maxLevel()) continue; + _flow->set(e, (*_capacity)[e]); + (*_excess)[u] += (*_capacity)[e]; + if (u != _target && !_level->active(u)) { + _level->activate(u); + } + } + } + } + + /// \brief Initializes the internal data structures using the + /// given flow map. + /// + /// Initializes the internal data structures and sets the initial + /// flow to the given \c flowMap. The \c flowMap should contain a + /// flow or at least a preflow, i.e. at each node excluding the + /// source node the incoming flow should greater or equal to the + /// outgoing flow. + /// \return \c false if the given \c flowMap is not a preflow. + template + bool init(const FlowMap& flowMap) { + createStructures(); + + for (ArcIt e(_graph); e != INVALID; ++e) { + _flow->set(e, flowMap[e]); + } + + for (NodeIt n(_graph); n != INVALID; ++n) { + Value excess = 0; + for (InArcIt e(_graph, n); e != INVALID; ++e) { + excess += (*_flow)[e]; + } + for (OutArcIt e(_graph, n); e != INVALID; ++e) { + excess -= (*_flow)[e]; + } + if (excess < 0 && n != _source) return false; + (*_excess)[n] = excess; + } + + typename Digraph::template NodeMap reached(_graph, false); + + _level->initStart(); + _level->initAddItem(_target); + + std::vector queue; + reached[_source] = true; + + queue.push_back(_target); + reached[_target] = true; + while (!queue.empty()) { + _level->initNewLevel(); + std::vector nqueue; + for (int i = 0; i < int(queue.size()); ++i) { + Node n = queue[i]; + for (InArcIt e(_graph, n); e != INVALID; ++e) { + Node u = _graph.source(e); + if (!reached[u] && + _tolerance.positive((*_capacity)[e] - (*_flow)[e])) { + reached[u] = true; + _level->initAddItem(u); + nqueue.push_back(u); + } + } + for (OutArcIt e(_graph, n); e != INVALID; ++e) { + Node v = _graph.target(e); + if (!reached[v] && _tolerance.positive((*_flow)[e])) { + reached[v] = true; + _level->initAddItem(v); + nqueue.push_back(v); + } + } + } + queue.swap(nqueue); + } + _level->initFinish(); + + for (OutArcIt e(_graph, _source); e != INVALID; ++e) { + Value rem = (*_capacity)[e] - (*_flow)[e]; + if (_tolerance.positive(rem)) { + Node u = _graph.target(e); + if ((*_level)[u] == _level->maxLevel()) continue; + _flow->set(e, (*_capacity)[e]); + (*_excess)[u] += rem; + } + } + for (InArcIt e(_graph, _source); e != INVALID; ++e) { + Value rem = (*_flow)[e]; + if (_tolerance.positive(rem)) { + Node v = _graph.source(e); + if ((*_level)[v] == _level->maxLevel()) continue; + _flow->set(e, 0); + (*_excess)[v] += rem; + } + } + for (NodeIt n(_graph); n != INVALID; ++n) + if(n!=_source && n!=_target && _tolerance.positive((*_excess)[n])) + _level->activate(n); + + return true; + } + + /// \brief Starts the first phase of the preflow algorithm. + /// + /// The preflow algorithm consists of two phases, this method runs + /// the first phase. After the first phase the maximum flow value + /// and a minimum value cut can already be computed, although a + /// maximum flow is not yet obtained. So after calling this method + /// \ref flowValue() returns the value of a maximum flow and \ref + /// minCut() returns a minimum cut. + /// \pre One of the \ref init() functions must be called before + /// using this function. + void startFirstPhase() { + _phase = true; + + while (true) { + int num = _node_num; + + Node n = INVALID; + int level = -1; + + while (num > 0) { + n = _level->highestActive(); + if (n == INVALID) goto first_phase_done; + level = _level->highestActiveLevel(); + --num; + + Value excess = (*_excess)[n]; + int new_level = _level->maxLevel(); + + for (OutArcIt e(_graph, n); e != INVALID; ++e) { + Value rem = (*_capacity)[e] - (*_flow)[e]; + if (!_tolerance.positive(rem)) continue; + Node v = _graph.target(e); + if ((*_level)[v] < level) { + if (!_level->active(v) && v != _target) { + _level->activate(v); + } + if (!_tolerance.less(rem, excess)) { + _flow->set(e, (*_flow)[e] + excess); + (*_excess)[v] += excess; + excess = 0; + goto no_more_push_1; + } else { + excess -= rem; + (*_excess)[v] += rem; + _flow->set(e, (*_capacity)[e]); + } + } else if (new_level > (*_level)[v]) { + new_level = (*_level)[v]; + } + } + + for (InArcIt e(_graph, n); e != INVALID; ++e) { + Value rem = (*_flow)[e]; + if (!_tolerance.positive(rem)) continue; + Node v = _graph.source(e); + if ((*_level)[v] < level) { + if (!_level->active(v) && v != _target) { + _level->activate(v); + } + if (!_tolerance.less(rem, excess)) { + _flow->set(e, (*_flow)[e] - excess); + (*_excess)[v] += excess; + excess = 0; + goto no_more_push_1; + } else { + excess -= rem; + (*_excess)[v] += rem; + _flow->set(e, 0); + } + } else if (new_level > (*_level)[v]) { + new_level = (*_level)[v]; + } + } + + no_more_push_1: + + (*_excess)[n] = excess; + + if (excess != 0) { + if (new_level + 1 < _level->maxLevel()) { + _level->liftHighestActive(new_level + 1); + } else { + _level->liftHighestActiveToTop(); + } + if (_level->emptyLevel(level)) { + _level->liftToTop(level); + } + } else { + _level->deactivate(n); + } + } + + num = _node_num * 20; + while (num > 0) { + while (level >= 0 && _level->activeFree(level)) { + --level; + } + if (level == -1) { + n = _level->highestActive(); + level = _level->highestActiveLevel(); + if (n == INVALID) goto first_phase_done; + } else { + n = _level->activeOn(level); + } + --num; + + Value excess = (*_excess)[n]; + int new_level = _level->maxLevel(); + + for (OutArcIt e(_graph, n); e != INVALID; ++e) { + Value rem = (*_capacity)[e] - (*_flow)[e]; + if (!_tolerance.positive(rem)) continue; + Node v = _graph.target(e); + if ((*_level)[v] < level) { + if (!_level->active(v) && v != _target) { + _level->activate(v); + } + if (!_tolerance.less(rem, excess)) { + _flow->set(e, (*_flow)[e] + excess); + (*_excess)[v] += excess; + excess = 0; + goto no_more_push_2; + } else { + excess -= rem; + (*_excess)[v] += rem; + _flow->set(e, (*_capacity)[e]); + } + } else if (new_level > (*_level)[v]) { + new_level = (*_level)[v]; + } + } + + for (InArcIt e(_graph, n); e != INVALID; ++e) { + Value rem = (*_flow)[e]; + if (!_tolerance.positive(rem)) continue; + Node v = _graph.source(e); + if ((*_level)[v] < level) { + if (!_level->active(v) && v != _target) { + _level->activate(v); + } + if (!_tolerance.less(rem, excess)) { + _flow->set(e, (*_flow)[e] - excess); + (*_excess)[v] += excess; + excess = 0; + goto no_more_push_2; + } else { + excess -= rem; + (*_excess)[v] += rem; + _flow->set(e, 0); + } + } else if (new_level > (*_level)[v]) { + new_level = (*_level)[v]; + } + } + + no_more_push_2: + + (*_excess)[n] = excess; + + if (excess != 0) { + if (new_level + 1 < _level->maxLevel()) { + _level->liftActiveOn(level, new_level + 1); + } else { + _level->liftActiveToTop(level); + } + if (_level->emptyLevel(level)) { + _level->liftToTop(level); + } + } else { + _level->deactivate(n); + } + } + } + first_phase_done:; + } + + /// \brief Starts the second phase of the preflow algorithm. + /// + /// The preflow algorithm consists of two phases, this method runs + /// the second phase. After calling one of the \ref init() functions + /// and \ref startFirstPhase() and then \ref startSecondPhase(), + /// \ref flowMap() returns a maximum flow, \ref flowValue() returns the + /// value of a maximum flow, \ref minCut() returns a minimum cut + /// \pre One of the \ref init() functions and \ref startFirstPhase() + /// must be called before using this function. + void startSecondPhase() { + _phase = false; + + typename Digraph::template NodeMap reached(_graph); + for (NodeIt n(_graph); n != INVALID; ++n) { + reached[n] = (*_level)[n] < _level->maxLevel(); + } + + _level->initStart(); + _level->initAddItem(_source); + + std::vector queue; + queue.push_back(_source); + reached[_source] = true; + + while (!queue.empty()) { + _level->initNewLevel(); + std::vector nqueue; + for (int i = 0; i < int(queue.size()); ++i) { + Node n = queue[i]; + for (OutArcIt e(_graph, n); e != INVALID; ++e) { + Node v = _graph.target(e); + if (!reached[v] && _tolerance.positive((*_flow)[e])) { + reached[v] = true; + _level->initAddItem(v); + nqueue.push_back(v); + } + } + for (InArcIt e(_graph, n); e != INVALID; ++e) { + Node u = _graph.source(e); + if (!reached[u] && + _tolerance.positive((*_capacity)[e] - (*_flow)[e])) { + reached[u] = true; + _level->initAddItem(u); + nqueue.push_back(u); + } + } + } + queue.swap(nqueue); + } + _level->initFinish(); + + for (NodeIt n(_graph); n != INVALID; ++n) { + if (!reached[n]) { + _level->dirtyTopButOne(n); + } else if ((*_excess)[n] > 0 && _target != n) { + _level->activate(n); + } + } + + Node n; + while ((n = _level->highestActive()) != INVALID) { + Value excess = (*_excess)[n]; + int level = _level->highestActiveLevel(); + int new_level = _level->maxLevel(); + + for (OutArcIt e(_graph, n); e != INVALID; ++e) { + Value rem = (*_capacity)[e] - (*_flow)[e]; + if (!_tolerance.positive(rem)) continue; + Node v = _graph.target(e); + if ((*_level)[v] < level) { + if (!_level->active(v) && v != _source) { + _level->activate(v); + } + if (!_tolerance.less(rem, excess)) { + _flow->set(e, (*_flow)[e] + excess); + (*_excess)[v] += excess; + excess = 0; + goto no_more_push; + } else { + excess -= rem; + (*_excess)[v] += rem; + _flow->set(e, (*_capacity)[e]); + } + } else if (new_level > (*_level)[v]) { + new_level = (*_level)[v]; + } + } + + for (InArcIt e(_graph, n); e != INVALID; ++e) { + Value rem = (*_flow)[e]; + if (!_tolerance.positive(rem)) continue; + Node v = _graph.source(e); + if ((*_level)[v] < level) { + if (!_level->active(v) && v != _source) { + _level->activate(v); + } + if (!_tolerance.less(rem, excess)) { + _flow->set(e, (*_flow)[e] - excess); + (*_excess)[v] += excess; + excess = 0; + goto no_more_push; + } else { + excess -= rem; + (*_excess)[v] += rem; + _flow->set(e, 0); + } + } else if (new_level > (*_level)[v]) { + new_level = (*_level)[v]; + } + } + + no_more_push: + + (*_excess)[n] = excess; + + if (excess != 0) { + if (new_level + 1 < _level->maxLevel()) { + _level->liftHighestActive(new_level + 1); + } else { + // Calculation error + _level->liftHighestActiveToTop(); + } + if (_level->emptyLevel(level)) { + // Calculation error + _level->liftToTop(level); + } + } else { + _level->deactivate(n); + } + + } + } + + /// \brief Runs the preflow algorithm. + /// + /// Runs the preflow algorithm. + /// \note pf.run() is just a shortcut of the following code. + /// \code + /// pf.init(); + /// pf.startFirstPhase(); + /// pf.startSecondPhase(); + /// \endcode + void run() { + init(); + startFirstPhase(); + startSecondPhase(); + } + + /// \brief Runs the preflow algorithm to compute the minimum cut. + /// + /// Runs the preflow algorithm to compute the minimum cut. + /// \note pf.runMinCut() is just a shortcut of the following code. + /// \code + /// pf.init(); + /// pf.startFirstPhase(); + /// \endcode + void runMinCut() { + init(); + startFirstPhase(); + } + + /// @} + + /// \name Query Functions + /// The results of the preflow algorithm can be obtained using these + /// functions.\n + /// Either one of the \ref run() "run*()" functions or one of the + /// \ref startFirstPhase() "start*()" functions should be called + /// before using them. + + ///@{ + + /// \brief Returns the value of the maximum flow. + /// + /// Returns the value of the maximum flow by returning the excess + /// of the target node. This value equals to the value of + /// the maximum flow already after the first phase of the algorithm. + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + Value flowValue() const { + return (*_excess)[_target]; + } + + /// \brief Returns the flow value on the given arc. + /// + /// Returns the flow value on the given arc. This method can + /// be called after the second phase of the algorithm. + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + Value flow(const Arc& arc) const { + return (*_flow)[arc]; + } + + /// \brief Returns a const reference to the flow map. + /// + /// Returns a const reference to the arc map storing the found flow. + /// This method can be called after the second phase of the algorithm. + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + const FlowMap& flowMap() const { + return *_flow; + } + + /// \brief Returns \c true when the node is on the source side of the + /// minimum cut. + /// + /// Returns true when the node is on the source side of the found + /// minimum cut. This method can be called both after running \ref + /// startFirstPhase() and \ref startSecondPhase(). + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + bool minCut(const Node& node) const { + return ((*_level)[node] == _level->maxLevel()) == _phase; + } + + /// \brief Gives back a minimum value cut. + /// + /// Sets \c cutMap to the characteristic vector of a minimum value + /// cut. \c cutMap should be a \ref concepts::WriteMap "writable" + /// node map with \c bool (or convertible) value type. + /// + /// This method can be called both after running \ref startFirstPhase() + /// and \ref startSecondPhase(). The result after the second phase + /// could be slightly different if inexact computation is used. + /// + /// \note This function calls \ref minCut() for each node, so it runs in + /// O(n) time. + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + template + void minCutMap(CutMap& cutMap) const { + for (NodeIt n(_graph); n != INVALID; ++n) { + cutMap.set(n, minCut(n)); + } + } + + /// @} + }; +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/quad_heap.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/quad_heap.h new file mode 100644 index 00000000000..27c50fd3f60 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/quad_heap.h @@ -0,0 +1,343 @@ +/* -*- 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_QUAD_HEAP_H +#define LEMON_QUAD_HEAP_H + +///\ingroup heaps +///\file +///\brief Fourary (quaternary) heap implementation. + +#include +#include +#include + +namespace lemon { + + /// \ingroup heaps + /// + ///\brief Fourary (quaternary) heap data structure. + /// + /// This class implements the \e Fourary (\e quaternary) \e heap + /// data structure. + /// It fully conforms to the \ref concepts::Heap "heap concept". + /// + /// The fourary heap is a specialization of the \ref DHeap "D-ary heap" + /// for D=4. It is similar to the \ref BinHeap "binary heap", + /// but its nodes have at most four children, instead of two. + /// + /// \tparam PR Type of the priorities of the items. + /// \tparam IM A read-writable item map with \c int values, used + /// internally to handle the cross references. + /// \tparam CMP A functor class for comparing the priorities. + /// The default is \c std::less. + /// + ///\sa BinHeap + ///\sa DHeap +#ifdef DOXYGEN + template +#else + template > +#endif + class QuadHeap { + public: + /// Type of the item-int map. + typedef IM ItemIntMap; + /// Type of the priorities. + typedef PR Prio; + /// Type of the items stored in the heap. + typedef typename ItemIntMap::Key Item; + /// Type of the item-priority pairs. + typedef std::pair Pair; + /// Functor type for comparing the priorities. + typedef CMP Compare; + + /// \brief Type to represent the states of the items. + /// + /// Each item has a state associated to it. It can be "in heap", + /// "pre-heap" or "post-heap". The latter two are indifferent from the + /// heap's point of view, but may be useful to the user. + /// + /// The item-int map must be initialized in such way that it assigns + /// \c PRE_HEAP (-1) to any element to be put in the heap. + enum State { + IN_HEAP = 0, ///< = 0. + PRE_HEAP = -1, ///< = -1. + POST_HEAP = -2 ///< = -2. + }; + + private: + std::vector _data; + Compare _comp; + ItemIntMap &_iim; + + public: + /// \brief Constructor. + /// + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. + explicit QuadHeap(ItemIntMap &map) : _iim(map) {} + + /// \brief Constructor. + /// + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. + /// \param comp The function object used for comparing the priorities. + QuadHeap(ItemIntMap &map, const Compare &comp) + : _iim(map), _comp(comp) {} + + /// \brief The number of items stored in the heap. + /// + /// This function returns the number of items stored in the heap. + int size() const { return _data.size(); } + + /// \brief Check if the heap is empty. + /// + /// This function returns \c true if the heap is empty. + bool empty() const { return _data.empty(); } + + /// \brief Make the heap empty. + /// + /// This functon makes the heap empty. + /// It does not change the cross reference map. If you want to reuse + /// a heap that is not surely empty, you should first clear it and + /// then you should set the cross reference map to \c PRE_HEAP + /// for each item. + void clear() { _data.clear(); } + + private: + static int parent(int i) { return (i-1)/4; } + static int firstChild(int i) { return 4*i+1; } + + bool less(const Pair &p1, const Pair &p2) const { + return _comp(p1.second, p2.second); + } + + void bubbleUp(int hole, Pair p) { + int par = parent(hole); + while( hole>0 && less(p,_data[par]) ) { + move(_data[par],hole); + hole = par; + par = parent(hole); + } + move(p, hole); + } + + void bubbleDown(int hole, Pair p, int length) { + if( length>1 ) { + int child = firstChild(hole); + while( child+30) bubbleDown(0, _data[n], n); + _data.pop_back(); + } + + /// \brief Remove the given item from the heap. + /// + /// This function removes the given item from the heap if it is + /// already stored. + /// \param i The item to delete. + /// \pre \e i must be in the heap. + void erase(const Item &i) { + int h = _iim[i]; + int n = _data.size()-1; + _iim.set(_data[h].first, POST_HEAP); + if( h=0) s=0; + return State(s); + } + + /// \brief Set the state of an item in the heap. + /// + /// This function sets the state of the given item in the heap. + /// It can be used to manually clear the heap when it is important + /// to achive better time complexity. + /// \param i The item. + /// \param st The state. It should not be \c IN_HEAP. + void state(const Item& i, State st) { + switch (st) { + case POST_HEAP: + case PRE_HEAP: + if (state(i) == IN_HEAP) erase(i); + _iim[i] = st; + break; + case IN_HEAP: + break; + } + } + + /// \brief Replace an item in the heap. + /// + /// This function replaces item \c i with item \c j. + /// Item \c i must be in the heap, while \c j must be out of the heap. + /// After calling this method, item \c i will be out of the + /// heap and \c j will be in the heap with the same prioriority + /// as item \c i had before. + void replace(const Item& i, const Item& j) { + int idx = _iim[i]; + _iim.set(i, _iim[j]); + _iim.set(j, idx); + _data[idx].first = j; + } + + }; // class QuadHeap + +} // namespace lemon + +#endif // LEMON_FOURARY_HEAP_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/radix_heap.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/radix_heap.h new file mode 100644 index 00000000000..8701ce7474a --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/radix_heap.h @@ -0,0 +1,438 @@ +/* -*- 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_RADIX_HEAP_H +#define LEMON_RADIX_HEAP_H + +///\ingroup heaps +///\file +///\brief Radix heap implementation. + +#include +#include + +namespace lemon { + + + /// \ingroup heaps + /// + /// \brief Radix heap data structure. + /// + /// This class implements the \e radix \e heap data structure. + /// It practically conforms to the \ref concepts::Heap "heap concept", + /// but it has some limitations due its special implementation. + /// The type of the priorities must be \c int and the priority of an + /// item cannot be decreased under the priority of the last removed item. + /// + /// \tparam IM A read-writable item map with \c int values, used + /// internally to handle the cross references. + template + class RadixHeap { + + public: + + /// Type of the item-int map. + typedef IM ItemIntMap; + /// Type of the priorities. + typedef int Prio; + /// Type of the items stored in the heap. + typedef typename ItemIntMap::Key Item; + + /// \brief Exception thrown by RadixHeap. + /// + /// This exception is thrown when an item is inserted into a + /// RadixHeap with a priority smaller than the last erased one. + /// \see RadixHeap + class PriorityUnderflowError : public Exception { + public: + virtual const char* what() const throw() { + return "lemon::RadixHeap::PriorityUnderflowError"; + } + }; + + /// \brief Type to represent the states of the items. + /// + /// Each item has a state associated to it. It can be "in heap", + /// "pre-heap" or "post-heap". The latter two are indifferent from the + /// heap's point of view, but may be useful to the user. + /// + /// The item-int map must be initialized in such way that it assigns + /// \c PRE_HEAP (-1) to any element to be put in the heap. + enum State { + IN_HEAP = 0, ///< = 0. + PRE_HEAP = -1, ///< = -1. + POST_HEAP = -2 ///< = -2. + }; + + private: + + struct RadixItem { + int prev, next, box; + Item item; + int prio; + RadixItem(Item _item, int _prio) : item(_item), prio(_prio) {} + }; + + struct RadixBox { + int first; + int min, size; + RadixBox(int _min, int _size) : first(-1), min(_min), size(_size) {} + }; + + std::vector _data; + std::vector _boxes; + + ItemIntMap &_iim; + + public: + + /// \brief Constructor. + /// + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. + /// \param minimum The initial minimum value of the heap. + /// \param capacity The initial capacity of the heap. + RadixHeap(ItemIntMap &map, int minimum = 0, int capacity = 0) + : _iim(map) + { + _boxes.push_back(RadixBox(minimum, 1)); + _boxes.push_back(RadixBox(minimum + 1, 1)); + while (lower(_boxes.size() - 1, capacity + minimum - 1)) { + extend(); + } + } + + /// \brief The number of items stored in the heap. + /// + /// This function returns the number of items stored in the heap. + int size() const { return _data.size(); } + + /// \brief Check if the heap is empty. + /// + /// This function returns \c true if the heap is empty. + bool empty() const { return _data.empty(); } + + /// \brief Make the heap empty. + /// + /// This functon makes the heap empty. + /// It does not change the cross reference map. If you want to reuse + /// a heap that is not surely empty, you should first clear it and + /// then you should set the cross reference map to \c PRE_HEAP + /// for each item. + /// \param minimum The minimum value of the heap. + /// \param capacity The capacity of the heap. + void clear(int minimum = 0, int capacity = 0) { + _data.clear(); _boxes.clear(); + _boxes.push_back(RadixBox(minimum, 1)); + _boxes.push_back(RadixBox(minimum + 1, 1)); + while (lower(_boxes.size() - 1, capacity + minimum - 1)) { + extend(); + } + } + + private: + + bool upper(int box, Prio pr) { + return pr < _boxes[box].min; + } + + bool lower(int box, Prio pr) { + return pr >= _boxes[box].min + _boxes[box].size; + } + + // Remove item from the box list + void remove(int index) { + if (_data[index].prev >= 0) { + _data[_data[index].prev].next = _data[index].next; + } else { + _boxes[_data[index].box].first = _data[index].next; + } + if (_data[index].next >= 0) { + _data[_data[index].next].prev = _data[index].prev; + } + } + + // Insert item into the box list + void insert(int box, int index) { + if (_boxes[box].first == -1) { + _boxes[box].first = index; + _data[index].next = _data[index].prev = -1; + } else { + _data[index].next = _boxes[box].first; + _data[_boxes[box].first].prev = index; + _data[index].prev = -1; + _boxes[box].first = index; + } + _data[index].box = box; + } + + // Add a new box to the box list + void extend() { + int min = _boxes.back().min + _boxes.back().size; + int bs = 2 * _boxes.back().size; + _boxes.push_back(RadixBox(min, bs)); + } + + // Move an item up into the proper box. + void bubbleUp(int index) { + if (!lower(_data[index].box, _data[index].prio)) return; + remove(index); + int box = findUp(_data[index].box, _data[index].prio); + insert(box, index); + } + + // Find up the proper box for the item with the given priority + int findUp(int start, int pr) { + while (lower(start, pr)) { + if (++start == int(_boxes.size())) { + extend(); + } + } + return start; + } + + // Move an item down into the proper box + void bubbleDown(int index) { + if (!upper(_data[index].box, _data[index].prio)) return; + remove(index); + int box = findDown(_data[index].box, _data[index].prio); + insert(box, index); + } + + // Find down the proper box for the item with the given priority + int findDown(int start, int pr) { + while (upper(start, pr)) { + if (--start < 0) throw PriorityUnderflowError(); + } + return start; + } + + // Find the first non-empty box + int findFirst() { + int first = 0; + while (_boxes[first].first == -1) ++first; + return first; + } + + // Gives back the minimum priority of the given box + int minValue(int box) { + int min = _data[_boxes[box].first].prio; + for (int k = _boxes[box].first; k != -1; k = _data[k].next) { + if (_data[k].prio < min) min = _data[k].prio; + } + return min; + } + + // Rearrange the items of the heap and make the first box non-empty + void moveDown() { + int box = findFirst(); + if (box == 0) return; + int min = minValue(box); + for (int i = 0; i <= box; ++i) { + _boxes[i].min = min; + min += _boxes[i].size; + } + int curr = _boxes[box].first, next; + while (curr != -1) { + next = _data[curr].next; + bubbleDown(curr); + curr = next; + } + } + + void relocateLast(int index) { + if (index != int(_data.size()) - 1) { + _data[index] = _data.back(); + if (_data[index].prev != -1) { + _data[_data[index].prev].next = index; + } else { + _boxes[_data[index].box].first = index; + } + if (_data[index].next != -1) { + _data[_data[index].next].prev = index; + } + _iim[_data[index].item] = index; + } + _data.pop_back(); + } + + public: + + /// \brief Insert an item into the heap with the given priority. + /// + /// This function inserts the given item into the heap with the + /// given priority. + /// \param i The item to insert. + /// \param p The priority of the item. + /// \pre \e i must not be stored in the heap. + /// \warning This method may throw an \c UnderFlowPriorityException. + void push(const Item &i, const Prio &p) { + int n = _data.size(); + _iim.set(i, n); + _data.push_back(RadixItem(i, p)); + while (lower(_boxes.size() - 1, p)) { + extend(); + } + int box = findDown(_boxes.size() - 1, p); + insert(box, n); + } + + /// \brief Return the item having minimum priority. + /// + /// This function returns the item having minimum priority. + /// \pre The heap must be non-empty. + Item top() const { + const_cast&>(*this).moveDown(); + return _data[_boxes[0].first].item; + } + + /// \brief The minimum priority. + /// + /// This function returns the minimum priority. + /// \pre The heap must be non-empty. + Prio prio() const { + const_cast&>(*this).moveDown(); + return _data[_boxes[0].first].prio; + } + + /// \brief Remove the item having minimum priority. + /// + /// This function removes the item having minimum priority. + /// \pre The heap must be non-empty. + void pop() { + moveDown(); + int index = _boxes[0].first; + _iim[_data[index].item] = POST_HEAP; + remove(index); + relocateLast(index); + } + + /// \brief Remove the given item from the heap. + /// + /// This function removes the given item from the heap if it is + /// already stored. + /// \param i The item to delete. + /// \pre \e i must be in the heap. + void erase(const Item &i) { + int index = _iim[i]; + _iim[i] = POST_HEAP; + remove(index); + relocateLast(index); + } + + /// \brief The priority of the given item. + /// + /// This function returns the priority of the given item. + /// \param i The item. + /// \pre \e i must be in the heap. + Prio operator[](const Item &i) const { + int idx = _iim[i]; + return _data[idx].prio; + } + + /// \brief Set the priority of an item or insert it, if it is + /// not stored in the heap. + /// + /// This method sets the priority of the given item if it is + /// already stored in the heap. Otherwise it inserts the given + /// item into the heap with the given priority. + /// \param i The item. + /// \param p The priority. + /// \pre \e i must be in the heap. + /// \warning This method may throw an \c UnderFlowPriorityException. + void set(const Item &i, const Prio &p) { + int idx = _iim[i]; + if( idx < 0 ) { + push(i, p); + } + else if( p >= _data[idx].prio ) { + _data[idx].prio = p; + bubbleUp(idx); + } else { + _data[idx].prio = p; + bubbleDown(idx); + } + } + + /// \brief Decrease the priority of an item to the given value. + /// + /// This function decreases the priority of an item to the given value. + /// \param i The item. + /// \param p The priority. + /// \pre \e i must be stored in the heap with priority at least \e p. + /// \warning This method may throw an \c UnderFlowPriorityException. + void decrease(const Item &i, const Prio &p) { + int idx = _iim[i]; + _data[idx].prio = p; + bubbleDown(idx); + } + + /// \brief Increase the priority of an item to the given value. + /// + /// This function increases the priority of an item to the given value. + /// \param i The item. + /// \param p The priority. + /// \pre \e i must be stored in the heap with priority at most \e p. + void increase(const Item &i, const Prio &p) { + int idx = _iim[i]; + _data[idx].prio = p; + bubbleUp(idx); + } + + /// \brief Return the state of an item. + /// + /// This method returns \c PRE_HEAP if the given item has never + /// been in the heap, \c IN_HEAP if it is in the heap at the moment, + /// and \c POST_HEAP otherwise. + /// In the latter case it is possible that the item will get back + /// to the heap again. + /// \param i The item. + State state(const Item &i) const { + int s = _iim[i]; + if( s >= 0 ) s = 0; + return State(s); + } + + /// \brief Set the state of an item in the heap. + /// + /// This function sets the state of the given item in the heap. + /// It can be used to manually clear the heap when it is important + /// to achive better time complexity. + /// \param i The item. + /// \param st The state. It should not be \c IN_HEAP. + void state(const Item& i, State st) { + switch (st) { + case POST_HEAP: + case PRE_HEAP: + if (state(i) == IN_HEAP) { + erase(i); + } + _iim[i] = st; + break; + case IN_HEAP: + break; + } + } + + }; // class RadixHeap + +} // namespace lemon + +#endif // LEMON_RADIX_HEAP_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/radix_sort.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/radix_sort.h new file mode 100644 index 00000000000..d80875663b0 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/radix_sort.h @@ -0,0 +1,487 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 RADIX_SORT_H +#define RADIX_SORT_H + +/// \ingroup auxalg +/// \file +/// \brief Radix sort +/// +/// Linear time sorting algorithms + +#include +#include +#include +#include + +namespace lemon { + + namespace _radix_sort_bits { + + template + bool unitRange(Iterator first, Iterator last) { + ++first; + return first == last; + } + + template + struct Identity { + const Value& operator()(const Value& val) { + return val; + } + }; + + + template + Iterator radixSortPartition(Iterator first, Iterator last, + Functor functor, Value mask) { + while (first != last && !(functor(*first) & mask)) { + ++first; + } + if (first == last) { + return first; + } + --last; + while (first != last && (functor(*last) & mask)) { + --last; + } + if (first == last) { + return first; + } + std::iter_swap(first, last); + ++first; + while (true) { + while (!(functor(*first) & mask)) { + ++first; + } + --last; + while (functor(*last) & mask) { + --last; + } + if (unitRange(last, first)) { + return first; + } + std::iter_swap(first, last); + ++first; + } + } + + template + Iterator radixSortSignPartition(Iterator first, Iterator last, + Functor functor) { + while (first != last && functor(*first) < 0) { + ++first; + } + if (first == last) { + return first; + } + --last; + while (first != last && functor(*last) >= 0) { + --last; + } + if (first == last) { + return first; + } + std::iter_swap(first, last); + ++first; + while (true) { + while (functor(*first) < 0) { + ++first; + } + --last; + while (functor(*last) >= 0) { + --last; + } + if (unitRange(last, first)) { + return first; + } + std::iter_swap(first, last); + ++first; + } + } + + template + void radixIntroSort(Iterator first, Iterator last, + Functor functor, Value mask) { + while (mask != 0 && first != last && !unitRange(first, last)) { + Iterator cut = radixSortPartition(first, last, functor, mask); + mask >>= 1; + radixIntroSort(first, cut, functor, mask); + first = cut; + } + } + + template + void radixSignedSort(Iterator first, Iterator last, Functor functor) { + + Iterator cut = radixSortSignPartition(first, last, functor); + + Value mask; + int max_digit; + Iterator it; + + mask = ~0; max_digit = 0; + for (it = first; it != cut; ++it) { + while ((mask & functor(*it)) != mask) { + ++max_digit; + mask <<= 1; + } + } + radixIntroSort(first, cut, functor, 1 << max_digit); + + mask = 0; max_digit = 0; + for (it = cut; it != last; ++it) { + while ((mask | functor(*it)) != mask) { + ++max_digit; + mask <<= 1; mask |= 1; + } + } + radixIntroSort(cut, last, functor, 1 << max_digit); + } + + template + void radixUnsignedSort(Iterator first, Iterator last, Functor functor) { + + Value mask = 0; + int max_digit = 0; + + Iterator it; + for (it = first; it != last; ++it) { + while ((mask | functor(*it)) != mask) { + ++max_digit; + mask <<= 1; mask |= 1; + } + } + radixIntroSort(first, last, functor, 1 << max_digit); + } + + + template ::is_signed > + struct RadixSortSelector { + template + static void sort(Iterator first, Iterator last, Functor functor) { + radixSignedSort(first, last, functor); + } + }; + + template + struct RadixSortSelector { + template + static void sort(Iterator first, Iterator last, Functor functor) { + radixUnsignedSort(first, last, functor); + } + }; + + } + + /// \ingroup auxalg + /// + /// \brief Sorts the STL compatible range into ascending order. + /// + /// The \c radixSort sorts an STL compatible range into ascending + /// order. The radix sort algorithm can sort items which are mapped + /// to integers with an adaptable unary function \c functor and the + /// order will be ascending according to these mapped values. + /// + /// It is also possible to use a normal function instead + /// of the functor object. If the functor is not given it will use + /// the identity function instead. + /// + /// This is a special quick sort algorithm where the pivot + /// values to split the items are choosen to be 2k + /// for each \c k. + /// Therefore, the time complexity of the algorithm is O(log(c)*n) and + /// it uses O(log(c)) additional space, where \c c is the maximal value + /// and \c n is the number of the items in the container. + /// + /// \param first The begin of the given range. + /// \param last The end of the given range. + /// \param functor An adaptible unary function or a normal function + /// which maps the items to any integer type which can be either + /// signed or unsigned. + /// + /// \sa stableRadixSort() + template + void radixSort(Iterator first, Iterator last, Functor functor) { + using namespace _radix_sort_bits; + typedef typename Functor::result_type Value; + RadixSortSelector::sort(first, last, functor); + } + + template + void radixSort(Iterator first, Iterator last, Value (*functor)(Key)) { + using namespace _radix_sort_bits; + RadixSortSelector::sort(first, last, functor); + } + + template + void radixSort(Iterator first, Iterator last, Value& (*functor)(Key)) { + using namespace _radix_sort_bits; + RadixSortSelector::sort(first, last, functor); + } + + template + void radixSort(Iterator first, Iterator last, Value (*functor)(Key&)) { + using namespace _radix_sort_bits; + RadixSortSelector::sort(first, last, functor); + } + + template + void radixSort(Iterator first, Iterator last, Value& (*functor)(Key&)) { + using namespace _radix_sort_bits; + RadixSortSelector::sort(first, last, functor); + } + + template + void radixSort(Iterator first, Iterator last) { + using namespace _radix_sort_bits; + typedef typename std::iterator_traits::value_type Value; + RadixSortSelector::sort(first, last, Identity()); + } + + namespace _radix_sort_bits { + + template + unsigned char valueByte(Value value, int byte) { + return value >> (std::numeric_limits::digits * byte); + } + + template + void stableRadixIntroSort(Key *first, Key *last, Key *target, + int byte, Functor functor) { + const int size = + unsigned(std::numeric_limits::max()) + 1; + std::vector counter(size); + for (int i = 0; i < size; ++i) { + counter[i] = 0; + } + Key *it = first; + while (first != last) { + ++counter[valueByte(functor(*first), byte)]; + ++first; + } + int prev, num = 0; + for (int i = 0; i < size; ++i) { + prev = num; + num += counter[i]; + counter[i] = prev; + } + while (it != last) { + target[counter[valueByte(functor(*it), byte)]++] = *it; + ++it; + } + } + + template + void signedStableRadixIntroSort(Key *first, Key *last, Key *target, + int byte, Functor functor) { + const int size = + unsigned(std::numeric_limits::max()) + 1; + std::vector counter(size); + for (int i = 0; i < size; ++i) { + counter[i] = 0; + } + Key *it = first; + while (first != last) { + counter[valueByte(functor(*first), byte)]++; + ++first; + } + int prev, num = 0; + for (int i = size / 2; i < size; ++i) { + prev = num; + num += counter[i]; + counter[i] = prev; + } + for (int i = 0; i < size / 2; ++i) { + prev = num; + num += counter[i]; + counter[i] = prev; + } + while (it != last) { + target[counter[valueByte(functor(*it), byte)]++] = *it; + ++it; + } + } + + + template + void stableRadixSignedSort(Iterator first, Iterator last, Functor functor) { + if (first == last) return; + typedef typename std::iterator_traits::value_type Key; + typedef std::allocator Allocator; + Allocator allocator; + + int length = std::distance(first, last); + Key* buffer = allocator.allocate(2 * length); + try { + bool dir = true; + std::copy(first, last, buffer); + for (int i = 0; i < int(sizeof(Value)) - 1; ++i) { + if (dir) { + stableRadixIntroSort(buffer, buffer + length, buffer + length, + i, functor); + } else { + stableRadixIntroSort(buffer + length, buffer + 2 * length, buffer, + i, functor); + } + dir = !dir; + } + if (dir) { + signedStableRadixIntroSort(buffer, buffer + length, buffer + length, + sizeof(Value) - 1, functor); + std::copy(buffer + length, buffer + 2 * length, first); + } else { + signedStableRadixIntroSort(buffer + length, buffer + 2 * length, + buffer, sizeof(Value) - 1, functor); + std::copy(buffer, buffer + length, first); + } + } catch (...) { + allocator.deallocate(buffer, 2 * length); + throw; + } + allocator.deallocate(buffer, 2 * length); + } + + template + void stableRadixUnsignedSort(Iterator first, Iterator last, + Functor functor) { + if (first == last) return; + typedef typename std::iterator_traits::value_type Key; + typedef std::allocator Allocator; + Allocator allocator; + + int length = std::distance(first, last); + Key *buffer = allocator.allocate(2 * length); + try { + bool dir = true; + std::copy(first, last, buffer); + for (int i = 0; i < int(sizeof(Value)); ++i) { + if (dir) { + stableRadixIntroSort(buffer, buffer + length, + buffer + length, i, functor); + } else { + stableRadixIntroSort(buffer + length, buffer + 2 * length, + buffer, i, functor); + } + dir = !dir; + } + if (dir) { + std::copy(buffer, buffer + length, first); + } else { + std::copy(buffer + length, buffer + 2 * length, first); + } + } catch (...) { + allocator.deallocate(buffer, 2 * length); + throw; + } + allocator.deallocate(buffer, 2 * length); + } + + + + template ::is_signed > + struct StableRadixSortSelector { + template + static void sort(Iterator first, Iterator last, Functor functor) { + stableRadixSignedSort(first, last, functor); + } + }; + + template + struct StableRadixSortSelector { + template + static void sort(Iterator first, Iterator last, Functor functor) { + stableRadixUnsignedSort(first, last, functor); + } + }; + + } + + /// \ingroup auxalg + /// + /// \brief Sorts the STL compatible range into ascending order in a stable + /// way. + /// + /// This function sorts an STL compatible range into ascending + /// order according to an integer mapping in the same as radixSort() does. + /// + /// This sorting algorithm is stable, i.e. the order of two equal + /// elements remains the same after the sorting. + /// + /// This sort algorithm use a radix forward sort on the + /// bytes of the integer number. The algorithm sorts the items + /// byte-by-byte. First, it counts how many times a byte value occurs + /// in the container, then it copies the corresponding items to + /// another container in asceding order in O(n) time. + /// + /// The time complexity of the algorithm is O(log(c)*n) and + /// it uses O(n) additional space, where \c c is the + /// maximal value and \c n is the number of the items in the + /// container. + /// + + /// \param first The begin of the given range. + /// \param last The end of the given range. + /// \param functor An adaptible unary function or a normal function + /// which maps the items to any integer type which can be either + /// signed or unsigned. + /// \sa radixSort() + template + void stableRadixSort(Iterator first, Iterator last, Functor functor) { + using namespace _radix_sort_bits; + typedef typename Functor::result_type Value; + StableRadixSortSelector::sort(first, last, functor); + } + + template + void stableRadixSort(Iterator first, Iterator last, Value (*functor)(Key)) { + using namespace _radix_sort_bits; + StableRadixSortSelector::sort(first, last, functor); + } + + template + void stableRadixSort(Iterator first, Iterator last, Value& (*functor)(Key)) { + using namespace _radix_sort_bits; + StableRadixSortSelector::sort(first, last, functor); + } + + template + void stableRadixSort(Iterator first, Iterator last, Value (*functor)(Key&)) { + using namespace _radix_sort_bits; + StableRadixSortSelector::sort(first, last, functor); + } + + template + void stableRadixSort(Iterator first, Iterator last, Value& (*functor)(Key&)) { + using namespace _radix_sort_bits; + StableRadixSortSelector::sort(first, last, functor); + } + + template + void stableRadixSort(Iterator first, Iterator last) { + using namespace _radix_sort_bits; + typedef typename std::iterator_traits::value_type Value; + StableRadixSortSelector::sort(first, last, Identity()); + } + +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/random.cc b/extern/quadriflow/3rd/lemon-1.3.1/lemon/random.cc new file mode 100644 index 00000000000..02951210bdf --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/random.cc @@ -0,0 +1,29 @@ +/* -*- 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. + * + */ + +///\file +///\brief Instantiation of the Random class. + +#include + +namespace lemon { + /// \brief Global random number generator instance + /// + /// A global Mersenne Twister random number generator instance. + Random rnd; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/random.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/random.h new file mode 100644 index 00000000000..8de74ede8a9 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/random.h @@ -0,0 +1,1005 @@ +/* -*- 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. + * + */ + +/* + * This file contains the reimplemented version of the Mersenne Twister + * Generator of Matsumoto and Nishimura. + * + * See the appropriate copyright notice below. + * + * Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The names of its contributors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Any feedback is very welcome. + * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html + * email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) + */ + +#ifndef LEMON_RANDOM_H +#define LEMON_RANDOM_H + +#include +#include +#include +#include +#include + +#include +#include + +#ifndef WIN32 +#include +#include +#include +#include +#else +#include +#endif + +///\ingroup misc +///\file +///\brief Mersenne Twister random number generator + +namespace lemon { + + namespace _random_bits { + + template ::digits> + struct RandomTraits {}; + + template + struct RandomTraits<_Word, 32> { + + typedef _Word Word; + static const int bits = 32; + + static const int length = 624; + static const int shift = 397; + + static const Word mul = 0x6c078965u; + static const Word arrayInit = 0x012BD6AAu; + static const Word arrayMul1 = 0x0019660Du; + static const Word arrayMul2 = 0x5D588B65u; + + static const Word mask = 0x9908B0DFu; + static const Word loMask = (1u << 31) - 1; + static const Word hiMask = ~loMask; + + + static Word tempering(Word rnd) { + rnd ^= (rnd >> 11); + rnd ^= (rnd << 7) & 0x9D2C5680u; + rnd ^= (rnd << 15) & 0xEFC60000u; + rnd ^= (rnd >> 18); + return rnd; + } + + }; + + template + struct RandomTraits<_Word, 64> { + + typedef _Word Word; + static const int bits = 64; + + static const int length = 312; + static const int shift = 156; + + static const Word mul = Word(0x5851F42Du) << 32 | Word(0x4C957F2Du); + static const Word arrayInit = Word(0x00000000u) << 32 |Word(0x012BD6AAu); + static const Word arrayMul1 = Word(0x369DEA0Fu) << 32 |Word(0x31A53F85u); + static const Word arrayMul2 = Word(0x27BB2EE6u) << 32 |Word(0x87B0B0FDu); + + static const Word mask = Word(0xB5026F5Au) << 32 | Word(0xA96619E9u); + static const Word loMask = (Word(1u) << 31) - 1; + static const Word hiMask = ~loMask; + + static Word tempering(Word rnd) { + rnd ^= (rnd >> 29) & (Word(0x55555555u) << 32 | Word(0x55555555u)); + rnd ^= (rnd << 17) & (Word(0x71D67FFFu) << 32 | Word(0xEDA60000u)); + rnd ^= (rnd << 37) & (Word(0xFFF7EEE0u) << 32 | Word(0x00000000u)); + rnd ^= (rnd >> 43); + return rnd; + } + + }; + + template + class RandomCore { + public: + + typedef _Word Word; + + private: + + static const int bits = RandomTraits::bits; + + static const int length = RandomTraits::length; + static const int shift = RandomTraits::shift; + + public: + + void initState() { + static const Word seedArray[4] = { + 0x12345u, 0x23456u, 0x34567u, 0x45678u + }; + + initState(seedArray, seedArray + 4); + } + + void initState(Word seed) { + + static const Word mul = RandomTraits::mul; + + current = state; + + Word *curr = state + length - 1; + curr[0] = seed; --curr; + for (int i = 1; i < length; ++i) { + curr[0] = (mul * ( curr[1] ^ (curr[1] >> (bits - 2)) ) + i); + --curr; + } + } + + template + void initState(Iterator begin, Iterator end) { + + static const Word init = RandomTraits::arrayInit; + static const Word mul1 = RandomTraits::arrayMul1; + static const Word mul2 = RandomTraits::arrayMul2; + + + Word *curr = state + length - 1; --curr; + Iterator it = begin; int cnt = 0; + int num; + + initState(init); + + num = length > end - begin ? length : end - begin; + while (num--) { + curr[0] = (curr[0] ^ ((curr[1] ^ (curr[1] >> (bits - 2))) * mul1)) + + *it + cnt; + ++it; ++cnt; + if (it == end) { + it = begin; cnt = 0; + } + if (curr == state) { + curr = state + length - 1; curr[0] = state[0]; + } + --curr; + } + + num = length - 1; cnt = length - (curr - state) - 1; + while (num--) { + curr[0] = (curr[0] ^ ((curr[1] ^ (curr[1] >> (bits - 2))) * mul2)) + - cnt; + --curr; ++cnt; + if (curr == state) { + curr = state + length - 1; curr[0] = state[0]; --curr; + cnt = 1; + } + } + + state[length - 1] = Word(1) << (bits - 1); + } + + void copyState(const RandomCore& other) { + std::copy(other.state, other.state + length, state); + current = state + (other.current - other.state); + } + + Word operator()() { + if (current == state) fillState(); + --current; + Word rnd = *current; + return RandomTraits::tempering(rnd); + } + + private: + + + void fillState() { + static const Word mask[2] = { 0x0ul, RandomTraits::mask }; + static const Word loMask = RandomTraits::loMask; + static const Word hiMask = RandomTraits::hiMask; + + current = state + length; + + register Word *curr = state + length - 1; + register long num; + + num = length - shift; + while (num--) { + curr[0] = (((curr[0] & hiMask) | (curr[-1] & loMask)) >> 1) ^ + curr[- shift] ^ mask[curr[-1] & 1ul]; + --curr; + } + num = shift - 1; + while (num--) { + curr[0] = (((curr[0] & hiMask) | (curr[-1] & loMask)) >> 1) ^ + curr[length - shift] ^ mask[curr[-1] & 1ul]; + --curr; + } + state[0] = (((state[0] & hiMask) | (curr[length - 1] & loMask)) >> 1) ^ + curr[length - shift] ^ mask[curr[length - 1] & 1ul]; + + } + + + Word *current; + Word state[length]; + + }; + + + template ::digits + 1) / 2> + struct Masker { + static Result mask(const Result& result) { + return Masker:: + mask(static_cast(result | (result >> shift))); + } + }; + + template + struct Masker { + static Result mask(const Result& result) { + return static_cast(result | (result >> 1)); + } + }; + + template ::digits, int shift = 0, + bool last = rest <= std::numeric_limits::digits> + struct IntConversion { + static const int bits = std::numeric_limits::digits; + + static Result convert(RandomCore& rnd) { + return static_cast(rnd() >> (bits - rest)) << shift; + } + + }; + + template + struct IntConversion { + static const int bits = std::numeric_limits::digits; + + static Result convert(RandomCore& rnd) { + return (static_cast(rnd()) << shift) | + IntConversion::convert(rnd); + } + }; + + + template ::digits < + std::numeric_limits::digits) > + struct Mapping { + static Result map(RandomCore& rnd, const Result& bound) { + Word max = Word(bound - 1); + Result mask = Masker::mask(bound - 1); + Result num; + do { + num = IntConversion::convert(rnd) & mask; + } while (num > max); + return num; + } + }; + + template + struct Mapping { + static Result map(RandomCore& rnd, const Result& bound) { + Word max = Word(bound - 1); + Word mask = Masker::digits + 1) / 2> + ::mask(max); + Word num; + do { + num = rnd() & mask; + } while (num > max); + return num; + } + }; + + template + struct ShiftMultiplier { + static const Result multiplier() { + Result res = ShiftMultiplier::multiplier(); + res *= res; + if ((exp & 1) == 1) res *= static_cast(0.5); + return res; + } + }; + + template + struct ShiftMultiplier { + static const Result multiplier() { + return static_cast(1.0); + } + }; + + template + struct ShiftMultiplier { + static const Result multiplier() { + return static_cast(1.0/1048576.0); + } + }; + + template + struct ShiftMultiplier { + static const Result multiplier() { + return static_cast(1.0/4294967296.0); + } + }; + + template + struct ShiftMultiplier { + static const Result multiplier() { + return static_cast(1.0/9007199254740992.0); + } + }; + + template + struct ShiftMultiplier { + static const Result multiplier() { + return static_cast(1.0/18446744073709551616.0); + } + }; + + template + struct Shifting { + static Result shift(const Result& result) { + return result * ShiftMultiplier::multiplier(); + } + }; + + template ::digits, int shift = 0, + bool last = rest <= std::numeric_limits::digits> + struct RealConversion{ + static const int bits = std::numeric_limits::digits; + + static Result convert(RandomCore& rnd) { + return Shifting:: + shift(static_cast(rnd() >> (bits - rest))); + } + }; + + template + struct RealConversion { + static const int bits = std::numeric_limits::digits; + + static Result convert(RandomCore& rnd) { + return Shifting:: + shift(static_cast(rnd())) + + RealConversion:: + convert(rnd); + } + }; + + template + struct Initializer { + + template + static void init(RandomCore& rnd, Iterator begin, Iterator end) { + std::vector ws; + for (Iterator it = begin; it != end; ++it) { + ws.push_back(Word(*it)); + } + rnd.initState(ws.begin(), ws.end()); + } + + static void init(RandomCore& rnd, Result seed) { + rnd.initState(seed); + } + }; + + template + struct BoolConversion { + static bool convert(RandomCore& rnd) { + return (rnd() & 1) == 1; + } + }; + + template + struct BoolProducer { + Word buffer; + int num; + + BoolProducer() : num(0) {} + + bool convert(RandomCore& rnd) { + if (num == 0) { + buffer = rnd(); + num = RandomTraits::bits; + } + bool r = (buffer & 1); + buffer >>= 1; + --num; + return r; + } + }; + + } + + /// \ingroup misc + /// + /// \brief Mersenne Twister random number generator + /// + /// The Mersenne Twister is a twisted generalized feedback + /// shift-register generator of Matsumoto and Nishimura. The period + /// of this generator is \f$ 2^{19937} - 1 \f$ and it is + /// equi-distributed in 623 dimensions for 32-bit numbers. The time + /// performance of this generator is comparable to the commonly used + /// generators. + /// + /// This implementation is specialized for both 32-bit and 64-bit + /// architectures. The generators differ sligthly in the + /// initialization and generation phase so they produce two + /// completly different sequences. + /// + /// The generator gives back random numbers of serveral types. To + /// get a random number from a range of a floating point type you + /// can use one form of the \c operator() or the \c real() member + /// function. If you want to get random number from the {0, 1, ..., + /// n-1} integer range use the \c operator[] or the \c integer() + /// method. And to get random number from the whole range of an + /// integer type you can use the argumentless \c integer() or \c + /// uinteger() functions. After all you can get random bool with + /// equal chance of true and false or given probability of true + /// result with the \c boolean() member functions. + /// + ///\code + /// // The commented code is identical to the other + /// double a = rnd(); // [0.0, 1.0) + /// // double a = rnd.real(); // [0.0, 1.0) + /// double b = rnd(100.0); // [0.0, 100.0) + /// // double b = rnd.real(100.0); // [0.0, 100.0) + /// double c = rnd(1.0, 2.0); // [1.0, 2.0) + /// // double c = rnd.real(1.0, 2.0); // [1.0, 2.0) + /// int d = rnd[100000]; // 0..99999 + /// // int d = rnd.integer(100000); // 0..99999 + /// int e = rnd[6] + 1; // 1..6 + /// // int e = rnd.integer(1, 1 + 6); // 1..6 + /// int b = rnd.uinteger(); // 0 .. 2^31 - 1 + /// int c = rnd.integer(); // - 2^31 .. 2^31 - 1 + /// bool g = rnd.boolean(); // P(g = true) = 0.5 + /// bool h = rnd.boolean(0.8); // P(h = true) = 0.8 + ///\endcode + /// + /// LEMON provides a global instance of the random number + /// generator which name is \ref lemon::rnd "rnd". Usually it is a + /// good programming convenience to use this global generator to get + /// random numbers. + class Random { + private: + + // Architecture word + typedef unsigned long Word; + + _random_bits::RandomCore core; + _random_bits::BoolProducer bool_producer; + + + public: + + ///\name Initialization + /// + /// @{ + + /// \brief Default constructor + /// + /// Constructor with constant seeding. + Random() { core.initState(); } + + /// \brief Constructor with seed + /// + /// Constructor with seed. The current number type will be converted + /// to the architecture word type. + template + Random(Number seed) { + _random_bits::Initializer::init(core, seed); + } + + /// \brief Constructor with array seeding + /// + /// Constructor with array seeding. The given range should contain + /// any number type and the numbers will be converted to the + /// architecture word type. + template + Random(Iterator begin, Iterator end) { + typedef typename std::iterator_traits::value_type Number; + _random_bits::Initializer::init(core, begin, end); + } + + /// \brief Copy constructor + /// + /// Copy constructor. The generated sequence will be identical to + /// the other sequence. It can be used to save the current state + /// of the generator and later use it to generate the same + /// sequence. + Random(const Random& other) { + core.copyState(other.core); + } + + /// \brief Assign operator + /// + /// Assign operator. The generated sequence will be identical to + /// the other sequence. It can be used to save the current state + /// of the generator and later use it to generate the same + /// sequence. + Random& operator=(const Random& other) { + if (&other != this) { + core.copyState(other.core); + } + return *this; + } + + /// \brief Seeding random sequence + /// + /// Seeding the random sequence. The current number type will be + /// converted to the architecture word type. + template + void seed(Number seed) { + _random_bits::Initializer::init(core, seed); + } + + /// \brief Seeding random sequence + /// + /// Seeding the random sequence. The given range should contain + /// any number type and the numbers will be converted to the + /// architecture word type. + template + void seed(Iterator begin, Iterator end) { + typedef typename std::iterator_traits::value_type Number; + _random_bits::Initializer::init(core, begin, end); + } + + /// \brief Seeding from file or from process id and time + /// + /// By default, this function calls the \c seedFromFile() member + /// function with the /dev/urandom file. If it does not success, + /// it uses the \c seedFromTime(). + /// \return Currently always \c true. + bool seed() { +#ifndef WIN32 + if (seedFromFile("/dev/urandom", 0)) return true; +#endif + if (seedFromTime()) return true; + return false; + } + + /// \brief Seeding from file + /// + /// Seeding the random sequence from file. The linux kernel has two + /// devices, /dev/random and /dev/urandom which + /// could give good seed values for pseudo random generators (The + /// difference between two devices is that the random may + /// block the reading operation while the kernel can give good + /// source of randomness, while the urandom does not + /// block the input, but it could give back bytes with worse + /// entropy). + /// \param file The source file + /// \param offset The offset, from the file read. + /// \return \c true when the seeding successes. +#ifndef WIN32 + bool seedFromFile(const std::string& file = "/dev/urandom", int offset = 0) +#else + bool seedFromFile(const std::string& file = "", int offset = 0) +#endif + { + std::ifstream rs(file.c_str()); + const int size = 4; + Word buf[size]; + if (offset != 0 && !rs.seekg(offset)) return false; + if (!rs.read(reinterpret_cast(buf), sizeof(buf))) return false; + seed(buf, buf + size); + return true; + } + + /// \brief Seding from process id and time + /// + /// Seding from process id and time. This function uses the + /// current process id and the current time for initialize the + /// random sequence. + /// \return Currently always \c true. + bool seedFromTime() { +#ifndef WIN32 + timeval tv; + gettimeofday(&tv, 0); + seed(getpid() + tv.tv_sec + tv.tv_usec); +#else + seed(bits::getWinRndSeed()); +#endif + return true; + } + + /// @} + + ///\name Uniform Distributions + /// + /// @{ + + /// \brief Returns a random real number from the range [0, 1) + /// + /// It returns a random real number from the range [0, 1). The + /// default Number type is \c double. + template + Number real() { + return _random_bits::RealConversion::convert(core); + } + + double real() { + return real(); + } + + /// \brief Returns a random real number from the range [0, 1) + /// + /// It returns a random double from the range [0, 1). + double operator()() { + return real(); + } + + /// \brief Returns a random real number from the range [0, b) + /// + /// It returns a random real number from the range [0, b). + double operator()(double b) { + return real() * b; + } + + /// \brief Returns a random real number from the range [a, b) + /// + /// It returns a random real number from the range [a, b). + double operator()(double a, double b) { + return real() * (b - a) + a; + } + + /// \brief Returns a random integer from a range + /// + /// It returns a random integer from the range {0, 1, ..., b - 1}. + template + Number integer(Number b) { + return _random_bits::Mapping::map(core, b); + } + + /// \brief Returns a random integer from a range + /// + /// It returns a random integer from the range {a, a + 1, ..., b - 1}. + template + Number integer(Number a, Number b) { + return _random_bits::Mapping::map(core, b - a) + a; + } + + /// \brief Returns a random integer from a range + /// + /// It returns a random integer from the range {0, 1, ..., b - 1}. + template + Number operator[](Number b) { + return _random_bits::Mapping::map(core, b); + } + + /// \brief Returns a random non-negative integer + /// + /// It returns a random non-negative integer uniformly from the + /// whole range of the current \c Number type. The default result + /// type of this function is unsigned int. + template + Number uinteger() { + return _random_bits::IntConversion::convert(core); + } + + unsigned int uinteger() { + return uinteger(); + } + + /// \brief Returns a random integer + /// + /// It returns a random integer uniformly from the whole range of + /// the current \c Number type. The default result type of this + /// function is \c int. + template + Number integer() { + static const int nb = std::numeric_limits::digits + + (std::numeric_limits::is_signed ? 1 : 0); + return _random_bits::IntConversion::convert(core); + } + + int integer() { + return integer(); + } + + /// \brief Returns a random bool + /// + /// It returns a random bool. The generator holds a buffer for + /// random bits. Every time when it become empty the generator makes + /// a new random word and fill the buffer up. + bool boolean() { + return bool_producer.convert(core); + } + + /// @} + + ///\name Non-uniform Distributions + /// + ///@{ + + /// \brief Returns a random bool with given probability of true result. + /// + /// It returns a random bool with given probability of true result. + bool boolean(double p) { + return operator()() < p; + } + + /// Standard normal (Gauss) distribution + + /// Standard normal (Gauss) distribution. + /// \note The Cartesian form of the Box-Muller + /// transformation is used to generate a random normal distribution. + double gauss() + { + double V1,V2,S; + do { + V1=2*real()-1; + V2=2*real()-1; + S=V1*V1+V2*V2; + } while(S>=1); + return std::sqrt(-2*std::log(S)/S)*V1; + } + /// Normal (Gauss) distribution with given mean and standard deviation + + /// Normal (Gauss) distribution with given mean and standard deviation. + /// \sa gauss() + double gauss(double mean,double std_dev) + { + return gauss()*std_dev+mean; + } + + /// Lognormal distribution + + /// Lognormal distribution. The parameters are the mean and the standard + /// deviation of exp(X). + /// + double lognormal(double n_mean,double n_std_dev) + { + return std::exp(gauss(n_mean,n_std_dev)); + } + /// Lognormal distribution + + /// Lognormal distribution. The parameter is an std::pair of + /// the mean and the standard deviation of exp(X). + /// + double lognormal(const std::pair ¶ms) + { + return std::exp(gauss(params.first,params.second)); + } + /// Compute the lognormal parameters from mean and standard deviation + + /// This function computes the lognormal parameters from mean and + /// standard deviation. The return value can direcly be passed to + /// lognormal(). + std::pair lognormalParamsFromMD(double mean, + double std_dev) + { + double fr=std_dev/mean; + fr*=fr; + double lg=std::log(1+fr); + return std::pair(std::log(mean)-lg/2.0,std::sqrt(lg)); + } + /// Lognormal distribution with given mean and standard deviation + + /// Lognormal distribution with given mean and standard deviation. + /// + double lognormalMD(double mean,double std_dev) + { + return lognormal(lognormalParamsFromMD(mean,std_dev)); + } + + /// Exponential distribution with given mean + + /// This function generates an exponential distribution random number + /// with mean 1/lambda. + /// + double exponential(double lambda=1.0) + { + return -std::log(1.0-real())/lambda; + } + + /// Gamma distribution with given integer shape + + /// This function generates a gamma distribution random number. + /// + ///\param k shape parameter (k>0 integer) + double gamma(int k) + { + double s = 0; + for(int i=0;i()); + return s; + } + + /// Gamma distribution with given shape and scale parameter + + /// This function generates a gamma distribution random number. + /// + ///\param k shape parameter (k>0) + ///\param theta scale parameter + /// + double gamma(double k,double theta=1.0) + { + double xi,nu; + const double delta = k-std::floor(k); + const double v0=E/(E-delta); + do { + double V0=1.0-real(); + double V1=1.0-real(); + double V2=1.0-real(); + if(V2<=v0) + { + xi=std::pow(V1,1.0/delta); + nu=V0*std::pow(xi,delta-1.0); + } + else + { + xi=1.0-std::log(V1); + nu=V0*std::exp(-xi); + } + } while(nu>std::pow(xi,delta-1.0)*std::exp(-xi)); + return theta*(xi+gamma(int(std::floor(k)))); + } + + /// Weibull distribution + + /// This function generates a Weibull distribution random number. + /// + ///\param k shape parameter (k>0) + ///\param lambda scale parameter (lambda>0) + /// + double weibull(double k,double lambda) + { + return lambda*pow(-std::log(1.0-real()),1.0/k); + } + + /// Pareto distribution + + /// This function generates a Pareto distribution random number. + /// + ///\param k shape parameter (k>0) + ///\param x_min location parameter (x_min>0) + /// + double pareto(double k,double x_min) + { + return exponential(gamma(k,1.0/x_min))+x_min; + } + + /// Poisson distribution + + /// This function generates a Poisson distribution random number with + /// parameter \c lambda. + /// + /// The probability mass function of this distribusion is + /// \f[ \frac{e^{-\lambda}\lambda^k}{k!} \f] + /// \note The algorithm is taken from the book of Donald E. Knuth titled + /// ''Seminumerical Algorithms'' (1969). Its running time is linear in the + /// return value. + + int poisson(double lambda) + { + const double l = std::exp(-lambda); + int k=0; + double p = 1.0; + do { + k++; + p*=real(); + } while (p>=l); + return k-1; + } + + ///@} + + ///\name Two Dimensional Distributions + /// + ///@{ + + /// Uniform distribution on the full unit circle + + /// Uniform distribution on the full unit circle. + /// + dim2::Point disc() + { + double V1,V2; + do { + V1=2*real()-1; + V2=2*real()-1; + + } while(V1*V1+V2*V2>=1); + return dim2::Point(V1,V2); + } + /// A kind of two dimensional normal (Gauss) distribution + + /// This function provides a turning symmetric two-dimensional distribution. + /// Both coordinates are of standard normal distribution, but they are not + /// independent. + /// + /// \note The coordinates are the two random variables provided by + /// the Box-Muller method. + dim2::Point gauss2() + { + double V1,V2,S; + do { + V1=2*real()-1; + V2=2*real()-1; + S=V1*V1+V2*V2; + } while(S>=1); + double W=std::sqrt(-2*std::log(S)/S); + return dim2::Point(W*V1,W*V2); + } + /// A kind of two dimensional exponential distribution + + /// This function provides a turning symmetric two-dimensional distribution. + /// The x-coordinate is of conditionally exponential distribution + /// with the condition that x is positive and y=0. If x is negative and + /// y=0 then, -x is of exponential distribution. The same is true for the + /// y-coordinate. + dim2::Point exponential2() + { + double V1,V2,S; + do { + V1=2*real()-1; + V2=2*real()-1; + S=V1*V1+V2*V2; + } while(S>=1); + double W=-std::log(S)/S; + return dim2::Point(W*V1,W*V2); + } + + ///@} + }; + + + extern Random rnd; + +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/smart_graph.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/smart_graph.h new file mode 100644 index 00000000000..bdbe369a4df --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/smart_graph.h @@ -0,0 +1,1344 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_SMART_GRAPH_H +#define LEMON_SMART_GRAPH_H + +///\ingroup graphs +///\file +///\brief SmartDigraph and SmartGraph classes. + +#include + +#include +#include +#include + +namespace lemon { + + class SmartDigraph; + + class SmartDigraphBase { + protected: + + struct NodeT + { + int first_in, first_out; + NodeT() {} + }; + struct ArcT + { + int target, source, next_in, next_out; + ArcT() {} + }; + + std::vector nodes; + std::vector arcs; + + public: + + typedef SmartDigraphBase Digraph; + + class Node; + class Arc; + + public: + + SmartDigraphBase() : nodes(), arcs() { } + SmartDigraphBase(const SmartDigraphBase &_g) + : nodes(_g.nodes), arcs(_g.arcs) { } + + typedef True NodeNumTag; + typedef True ArcNumTag; + + int nodeNum() const { return nodes.size(); } + int arcNum() const { return arcs.size(); } + + int maxNodeId() const { return nodes.size()-1; } + int maxArcId() const { return arcs.size()-1; } + + Node addNode() { + int n = nodes.size(); + nodes.push_back(NodeT()); + nodes[n].first_in = -1; + nodes[n].first_out = -1; + return Node(n); + } + + Arc addArc(Node u, Node v) { + int n = arcs.size(); + arcs.push_back(ArcT()); + arcs[n].source = u._id; + arcs[n].target = v._id; + arcs[n].next_out = nodes[u._id].first_out; + arcs[n].next_in = nodes[v._id].first_in; + nodes[u._id].first_out = nodes[v._id].first_in = n; + + return Arc(n); + } + + void clear() { + arcs.clear(); + nodes.clear(); + } + + Node source(Arc a) const { return Node(arcs[a._id].source); } + Node target(Arc a) const { return Node(arcs[a._id].target); } + + static int id(Node v) { return v._id; } + static int id(Arc a) { return a._id; } + + static Node nodeFromId(int id) { return Node(id);} + static Arc arcFromId(int id) { return Arc(id);} + + bool valid(Node n) const { + return n._id >= 0 && n._id < static_cast(nodes.size()); + } + bool valid(Arc a) const { + return a._id >= 0 && a._id < static_cast(arcs.size()); + } + + class Node { + friend class SmartDigraphBase; + friend class SmartDigraph; + + protected: + int _id; + explicit Node(int id) : _id(id) {} + public: + Node() {} + Node (Invalid) : _id(-1) {} + bool operator==(const Node i) const {return _id == i._id;} + bool operator!=(const Node i) const {return _id != i._id;} + bool operator<(const Node i) const {return _id < i._id;} + }; + + + class Arc { + friend class SmartDigraphBase; + friend class SmartDigraph; + + protected: + int _id; + explicit Arc(int id) : _id(id) {} + public: + Arc() { } + Arc (Invalid) : _id(-1) {} + bool operator==(const Arc i) const {return _id == i._id;} + bool operator!=(const Arc i) const {return _id != i._id;} + bool operator<(const Arc i) const {return _id < i._id;} + }; + + void first(Node& node) const { + node._id = nodes.size() - 1; + } + + static void next(Node& node) { + --node._id; + } + + void first(Arc& arc) const { + arc._id = arcs.size() - 1; + } + + static void next(Arc& arc) { + --arc._id; + } + + void firstOut(Arc& arc, const Node& node) const { + arc._id = nodes[node._id].first_out; + } + + void nextOut(Arc& arc) const { + arc._id = arcs[arc._id].next_out; + } + + void firstIn(Arc& arc, const Node& node) const { + arc._id = nodes[node._id].first_in; + } + + void nextIn(Arc& arc) const { + arc._id = arcs[arc._id].next_in; + } + + }; + + typedef DigraphExtender ExtendedSmartDigraphBase; + + ///\ingroup graphs + /// + ///\brief A smart directed graph class. + /// + ///\ref SmartDigraph is a simple and fast digraph implementation. + ///It is also quite memory efficient but at the price + ///that it does not support node and arc deletion + ///(except for the Snapshot feature). + /// + ///This type fully conforms to the \ref concepts::Digraph "Digraph concept" + ///and it also provides some additional functionalities. + ///Most of its member functions and nested classes are documented + ///only in the concept class. + /// + ///This class provides constant time counting for nodes and arcs. + /// + ///\sa concepts::Digraph + ///\sa SmartGraph + class SmartDigraph : public ExtendedSmartDigraphBase { + typedef ExtendedSmartDigraphBase Parent; + + private: + /// Digraphs are \e not copy constructible. Use DigraphCopy instead. + SmartDigraph(const SmartDigraph &) : ExtendedSmartDigraphBase() {}; + /// \brief Assignment of a digraph to another one is \e not allowed. + /// Use DigraphCopy instead. + void operator=(const SmartDigraph &) {} + + public: + + /// Constructor + + /// Constructor. + /// + SmartDigraph() {}; + + ///Add a new node to the digraph. + + ///This function adds a new node to the digraph. + ///\return The new node. + Node addNode() { return Parent::addNode(); } + + ///Add a new arc to the digraph. + + ///This function adds a new arc to the digraph with source node \c s + ///and target node \c t. + ///\return The new arc. + Arc addArc(Node s, Node t) { + return Parent::addArc(s, t); + } + + /// \brief Node validity check + /// + /// This function gives back \c true if the given node is valid, + /// i.e. it is a real node of the digraph. + /// + /// \warning A removed node (using Snapshot) could become valid again + /// if new nodes are added to the digraph. + bool valid(Node n) const { return Parent::valid(n); } + + /// \brief Arc validity check + /// + /// This function gives back \c true if the given arc is valid, + /// i.e. it is a real arc of the digraph. + /// + /// \warning A removed arc (using Snapshot) could become valid again + /// if new arcs are added to the graph. + bool valid(Arc a) const { return Parent::valid(a); } + + ///Split a node. + + ///This function splits the given node. First, a new node is added + ///to the digraph, then the source of each outgoing arc of node \c n + ///is moved to this new node. + ///If the second parameter \c connect is \c true (this is the default + ///value), then a new arc from node \c n to the newly created node + ///is also added. + ///\return The newly created node. + /// + ///\note All iterators remain valid. + /// + ///\warning This functionality cannot be used together with the Snapshot + ///feature. + Node split(Node n, bool connect = true) + { + Node b = addNode(); + nodes[b._id].first_out=nodes[n._id].first_out; + nodes[n._id].first_out=-1; + for(int i=nodes[b._id].first_out; i!=-1; i=arcs[i].next_out) { + arcs[i].source=b._id; + } + if(connect) addArc(n,b); + return b; + } + + ///Clear the digraph. + + ///This function erases all nodes and arcs from the digraph. + /// + void clear() { + Parent::clear(); + } + + /// Reserve memory for nodes. + + /// Using this function, it is possible to avoid superfluous memory + /// allocation: if you know that the digraph you want to build will + /// be large (e.g. it will contain millions of nodes and/or arcs), + /// then it is worth reserving space for this amount before starting + /// to build the digraph. + /// \sa reserveArc() + void reserveNode(int n) { nodes.reserve(n); }; + + /// Reserve memory for arcs. + + /// Using this function, it is possible to avoid superfluous memory + /// allocation: if you know that the digraph you want to build will + /// be large (e.g. it will contain millions of nodes and/or arcs), + /// then it is worth reserving space for this amount before starting + /// to build the digraph. + /// \sa reserveNode() + void reserveArc(int m) { arcs.reserve(m); }; + + public: + + class Snapshot; + + protected: + + void restoreSnapshot(const Snapshot &s) + { + while(s.arc_numnodes.size(); + arc_num=_graph->arcs.size(); + } + + ///Make a snapshot. + + ///This function makes a snapshot of the given digraph. + ///It can be called more than once. In case of a repeated + ///call, the previous snapshot gets lost. + void save(SmartDigraph &gr) { + _graph=&gr; + node_num=_graph->nodes.size(); + arc_num=_graph->arcs.size(); + } + + ///Undo the changes until a snapshot. + + ///This function undos the changes until the last snapshot + ///created by save() or Snapshot(SmartDigraph&). + void restore() + { + _graph->restoreSnapshot(*this); + } + }; + }; + + + class SmartGraphBase { + + protected: + + struct NodeT { + int first_out; + }; + + struct ArcT { + int target; + int next_out; + }; + + std::vector nodes; + std::vector arcs; + + public: + + typedef SmartGraphBase Graph; + + class Node; + class Arc; + class Edge; + + class Node { + friend class SmartGraphBase; + protected: + + int _id; + explicit Node(int id) { _id = id;} + + public: + Node() {} + Node (Invalid) { _id = -1; } + bool operator==(const Node& node) const {return _id == node._id;} + bool operator!=(const Node& node) const {return _id != node._id;} + bool operator<(const Node& node) const {return _id < node._id;} + }; + + class Edge { + friend class SmartGraphBase; + protected: + + int _id; + explicit Edge(int id) { _id = id;} + + public: + Edge() {} + Edge (Invalid) { _id = -1; } + bool operator==(const Edge& arc) const {return _id == arc._id;} + bool operator!=(const Edge& arc) const {return _id != arc._id;} + bool operator<(const Edge& arc) const {return _id < arc._id;} + }; + + class Arc { + friend class SmartGraphBase; + protected: + + int _id; + explicit Arc(int id) { _id = id;} + + public: + operator Edge() const { + return _id != -1 ? edgeFromId(_id / 2) : INVALID; + } + + Arc() {} + Arc (Invalid) { _id = -1; } + bool operator==(const Arc& arc) const {return _id == arc._id;} + bool operator!=(const Arc& arc) const {return _id != arc._id;} + bool operator<(const Arc& arc) const {return _id < arc._id;} + }; + + + + SmartGraphBase() + : nodes(), arcs() {} + + typedef True NodeNumTag; + typedef True EdgeNumTag; + typedef True ArcNumTag; + + int nodeNum() const { return nodes.size(); } + int edgeNum() const { return arcs.size() / 2; } + int arcNum() const { return arcs.size(); } + + int maxNodeId() const { return nodes.size()-1; } + int maxEdgeId() const { return arcs.size() / 2 - 1; } + int maxArcId() const { return arcs.size()-1; } + + Node source(Arc e) const { return Node(arcs[e._id ^ 1].target); } + Node target(Arc e) const { return Node(arcs[e._id].target); } + + Node u(Edge e) const { return Node(arcs[2 * e._id].target); } + Node v(Edge e) const { return Node(arcs[2 * e._id + 1].target); } + + static bool direction(Arc e) { + return (e._id & 1) == 1; + } + + static Arc direct(Edge e, bool d) { + return Arc(e._id * 2 + (d ? 1 : 0)); + } + + void first(Node& node) const { + node._id = nodes.size() - 1; + } + + static void next(Node& node) { + --node._id; + } + + void first(Arc& arc) const { + arc._id = arcs.size() - 1; + } + + static void next(Arc& arc) { + --arc._id; + } + + void first(Edge& arc) const { + arc._id = arcs.size() / 2 - 1; + } + + static void next(Edge& arc) { + --arc._id; + } + + void firstOut(Arc &arc, const Node& v) const { + arc._id = nodes[v._id].first_out; + } + void nextOut(Arc &arc) const { + arc._id = arcs[arc._id].next_out; + } + + void firstIn(Arc &arc, const Node& v) const { + arc._id = ((nodes[v._id].first_out) ^ 1); + if (arc._id == -2) arc._id = -1; + } + void nextIn(Arc &arc) const { + arc._id = ((arcs[arc._id ^ 1].next_out) ^ 1); + if (arc._id == -2) arc._id = -1; + } + + void firstInc(Edge &arc, bool& d, const Node& v) const { + int de = nodes[v._id].first_out; + if (de != -1) { + arc._id = de / 2; + d = ((de & 1) == 1); + } else { + arc._id = -1; + d = true; + } + } + void nextInc(Edge &arc, bool& d) const { + int de = (arcs[(arc._id * 2) | (d ? 1 : 0)].next_out); + if (de != -1) { + arc._id = de / 2; + d = ((de & 1) == 1); + } else { + arc._id = -1; + d = true; + } + } + + static int id(Node v) { return v._id; } + static int id(Arc e) { return e._id; } + static int id(Edge e) { return e._id; } + + static Node nodeFromId(int id) { return Node(id);} + static Arc arcFromId(int id) { return Arc(id);} + static Edge edgeFromId(int id) { return Edge(id);} + + bool valid(Node n) const { + return n._id >= 0 && n._id < static_cast(nodes.size()); + } + bool valid(Arc a) const { + return a._id >= 0 && a._id < static_cast(arcs.size()); + } + bool valid(Edge e) const { + return e._id >= 0 && 2 * e._id < static_cast(arcs.size()); + } + + Node addNode() { + int n = nodes.size(); + nodes.push_back(NodeT()); + nodes[n].first_out = -1; + + return Node(n); + } + + Edge addEdge(Node u, Node v) { + int n = arcs.size(); + arcs.push_back(ArcT()); + arcs.push_back(ArcT()); + + arcs[n].target = u._id; + arcs[n | 1].target = v._id; + + arcs[n].next_out = nodes[v._id].first_out; + nodes[v._id].first_out = n; + + arcs[n | 1].next_out = nodes[u._id].first_out; + nodes[u._id].first_out = (n | 1); + + return Edge(n / 2); + } + + void clear() { + arcs.clear(); + nodes.clear(); + } + + }; + + typedef GraphExtender ExtendedSmartGraphBase; + + /// \ingroup graphs + /// + /// \brief A smart undirected graph class. + /// + /// \ref SmartGraph is a simple and fast graph implementation. + /// It is also quite memory efficient but at the price + /// that it does not support node and edge deletion + /// (except for the Snapshot feature). + /// + /// This type fully conforms to the \ref concepts::Graph "Graph concept" + /// and it also provides some additional functionalities. + /// Most of its member functions and nested classes are documented + /// only in the concept class. + /// + /// This class provides constant time counting for nodes, edges and arcs. + /// + /// \sa concepts::Graph + /// \sa SmartDigraph + class SmartGraph : public ExtendedSmartGraphBase { + typedef ExtendedSmartGraphBase Parent; + + private: + /// Graphs are \e not copy constructible. Use GraphCopy instead. + SmartGraph(const SmartGraph &) : ExtendedSmartGraphBase() {}; + /// \brief Assignment of a graph to another one is \e not allowed. + /// Use GraphCopy instead. + void operator=(const SmartGraph &) {} + + public: + + /// Constructor + + /// Constructor. + /// + SmartGraph() {} + + /// \brief Add a new node to the graph. + /// + /// This function adds a new node to the graph. + /// \return The new node. + Node addNode() { return Parent::addNode(); } + + /// \brief Add a new edge to the graph. + /// + /// This function adds a new edge to the graph between nodes + /// \c u and \c v with inherent orientation from node \c u to + /// node \c v. + /// \return The new edge. + Edge addEdge(Node u, Node v) { + return Parent::addEdge(u, v); + } + + /// \brief Node validity check + /// + /// This function gives back \c true if the given node is valid, + /// i.e. it is a real node of the graph. + /// + /// \warning A removed node (using Snapshot) could become valid again + /// if new nodes are added to the graph. + bool valid(Node n) const { return Parent::valid(n); } + + /// \brief Edge validity check + /// + /// This function gives back \c true if the given edge is valid, + /// i.e. it is a real edge of the graph. + /// + /// \warning A removed edge (using Snapshot) could become valid again + /// if new edges are added to the graph. + bool valid(Edge e) const { return Parent::valid(e); } + + /// \brief Arc validity check + /// + /// This function gives back \c true if the given arc is valid, + /// i.e. it is a real arc of the graph. + /// + /// \warning A removed arc (using Snapshot) could become valid again + /// if new edges are added to the graph. + bool valid(Arc a) const { return Parent::valid(a); } + + ///Clear the graph. + + ///This function erases all nodes and arcs from the graph. + /// + void clear() { + Parent::clear(); + } + + /// Reserve memory for nodes. + + /// Using this function, it is possible to avoid superfluous memory + /// allocation: if you know that the graph you want to build will + /// be large (e.g. it will contain millions of nodes and/or edges), + /// then it is worth reserving space for this amount before starting + /// to build the graph. + /// \sa reserveEdge() + void reserveNode(int n) { nodes.reserve(n); }; + + /// Reserve memory for edges. + + /// Using this function, it is possible to avoid superfluous memory + /// allocation: if you know that the graph you want to build will + /// be large (e.g. it will contain millions of nodes and/or edges), + /// then it is worth reserving space for this amount before starting + /// to build the graph. + /// \sa reserveNode() + void reserveEdge(int m) { arcs.reserve(2 * m); }; + + public: + + class Snapshot; + + protected: + + void saveSnapshot(Snapshot &s) + { + s._graph = this; + s.node_num = nodes.size(); + s.arc_num = arcs.size(); + } + + void restoreSnapshot(const Snapshot &s) + { + while(s.arc_num dir; + dir.push_back(arcFromId(n)); + dir.push_back(arcFromId(n-1)); + Parent::notifier(Arc()).erase(dir); + nodes[arcs[n-1].target].first_out=arcs[n].next_out; + nodes[arcs[n].target].first_out=arcs[n-1].next_out; + arcs.pop_back(); + arcs.pop_back(); + } + while(s.node_numrestoreSnapshot(*this); + } + }; + }; + + class SmartBpGraphBase { + + protected: + + struct NodeT { + int first_out; + int partition_next; + int partition_index; + bool red; + }; + + struct ArcT { + int target; + int next_out; + }; + + std::vector nodes; + std::vector arcs; + + int first_red, first_blue; + int max_red, max_blue; + + public: + + typedef SmartBpGraphBase Graph; + + class Node; + class Arc; + class Edge; + + class Node { + friend class SmartBpGraphBase; + protected: + + int _id; + explicit Node(int id) { _id = id;} + + public: + Node() {} + Node (Invalid) { _id = -1; } + bool operator==(const Node& node) const {return _id == node._id;} + bool operator!=(const Node& node) const {return _id != node._id;} + bool operator<(const Node& node) const {return _id < node._id;} + }; + + class RedNode : public Node { + friend class SmartBpGraphBase; + protected: + + explicit RedNode(int pid) : Node(pid) {} + + public: + RedNode() {} + RedNode(const RedNode& node) : Node(node) {} + RedNode(Invalid) : Node(INVALID){} + }; + + class BlueNode : public Node { + friend class SmartBpGraphBase; + protected: + + explicit BlueNode(int pid) : Node(pid) {} + + public: + BlueNode() {} + BlueNode(const BlueNode& node) : Node(node) {} + BlueNode(Invalid) : Node(INVALID){} + }; + + class Edge { + friend class SmartBpGraphBase; + protected: + + int _id; + explicit Edge(int id) { _id = id;} + + public: + Edge() {} + Edge (Invalid) { _id = -1; } + bool operator==(const Edge& arc) const {return _id == arc._id;} + bool operator!=(const Edge& arc) const {return _id != arc._id;} + bool operator<(const Edge& arc) const {return _id < arc._id;} + }; + + class Arc { + friend class SmartBpGraphBase; + protected: + + int _id; + explicit Arc(int id) { _id = id;} + + public: + operator Edge() const { + return _id != -1 ? edgeFromId(_id / 2) : INVALID; + } + + Arc() {} + Arc (Invalid) { _id = -1; } + bool operator==(const Arc& arc) const {return _id == arc._id;} + bool operator!=(const Arc& arc) const {return _id != arc._id;} + bool operator<(const Arc& arc) const {return _id < arc._id;} + }; + + + + SmartBpGraphBase() + : nodes(), arcs(), first_red(-1), first_blue(-1), + max_red(-1), max_blue(-1) {} + + typedef True NodeNumTag; + typedef True EdgeNumTag; + typedef True ArcNumTag; + + int nodeNum() const { return nodes.size(); } + int redNum() const { return max_red + 1; } + int blueNum() const { return max_blue + 1; } + int edgeNum() const { return arcs.size() / 2; } + int arcNum() const { return arcs.size(); } + + int maxNodeId() const { return nodes.size()-1; } + int maxRedId() const { return max_red; } + int maxBlueId() const { return max_blue; } + int maxEdgeId() const { return arcs.size() / 2 - 1; } + int maxArcId() const { return arcs.size()-1; } + + bool red(Node n) const { return nodes[n._id].red; } + bool blue(Node n) const { return !nodes[n._id].red; } + + static RedNode asRedNodeUnsafe(Node n) { return RedNode(n._id); } + static BlueNode asBlueNodeUnsafe(Node n) { return BlueNode(n._id); } + + Node source(Arc a) const { return Node(arcs[a._id ^ 1].target); } + Node target(Arc a) const { return Node(arcs[a._id].target); } + + RedNode redNode(Edge e) const { + return RedNode(arcs[2 * e._id].target); + } + BlueNode blueNode(Edge e) const { + return BlueNode(arcs[2 * e._id + 1].target); + } + + static bool direction(Arc a) { + return (a._id & 1) == 1; + } + + static Arc direct(Edge e, bool d) { + return Arc(e._id * 2 + (d ? 1 : 0)); + } + + void first(Node& node) const { + node._id = nodes.size() - 1; + } + + static void next(Node& node) { + --node._id; + } + + void first(RedNode& node) const { + node._id = first_red; + } + + void next(RedNode& node) const { + node._id = nodes[node._id].partition_next; + } + + void first(BlueNode& node) const { + node._id = first_blue; + } + + void next(BlueNode& node) const { + node._id = nodes[node._id].partition_next; + } + + void first(Arc& arc) const { + arc._id = arcs.size() - 1; + } + + static void next(Arc& arc) { + --arc._id; + } + + void first(Edge& arc) const { + arc._id = arcs.size() / 2 - 1; + } + + static void next(Edge& arc) { + --arc._id; + } + + void firstOut(Arc &arc, const Node& v) const { + arc._id = nodes[v._id].first_out; + } + void nextOut(Arc &arc) const { + arc._id = arcs[arc._id].next_out; + } + + void firstIn(Arc &arc, const Node& v) const { + arc._id = ((nodes[v._id].first_out) ^ 1); + if (arc._id == -2) arc._id = -1; + } + void nextIn(Arc &arc) const { + arc._id = ((arcs[arc._id ^ 1].next_out) ^ 1); + if (arc._id == -2) arc._id = -1; + } + + void firstInc(Edge &arc, bool& d, const Node& v) const { + int de = nodes[v._id].first_out; + if (de != -1) { + arc._id = de / 2; + d = ((de & 1) == 1); + } else { + arc._id = -1; + d = true; + } + } + void nextInc(Edge &arc, bool& d) const { + int de = (arcs[(arc._id * 2) | (d ? 1 : 0)].next_out); + if (de != -1) { + arc._id = de / 2; + d = ((de & 1) == 1); + } else { + arc._id = -1; + d = true; + } + } + + static int id(Node v) { return v._id; } + int id(RedNode v) const { return nodes[v._id].partition_index; } + int id(BlueNode v) const { return nodes[v._id].partition_index; } + static int id(Arc e) { return e._id; } + static int id(Edge e) { return e._id; } + + static Node nodeFromId(int id) { return Node(id);} + static Arc arcFromId(int id) { return Arc(id);} + static Edge edgeFromId(int id) { return Edge(id);} + + bool valid(Node n) const { + return n._id >= 0 && n._id < static_cast(nodes.size()); + } + bool valid(Arc a) const { + return a._id >= 0 && a._id < static_cast(arcs.size()); + } + bool valid(Edge e) const { + return e._id >= 0 && 2 * e._id < static_cast(arcs.size()); + } + + RedNode addRedNode() { + int n = nodes.size(); + nodes.push_back(NodeT()); + nodes[n].first_out = -1; + nodes[n].red = true; + nodes[n].partition_index = ++max_red; + nodes[n].partition_next = first_red; + first_red = n; + + return RedNode(n); + } + + BlueNode addBlueNode() { + int n = nodes.size(); + nodes.push_back(NodeT()); + nodes[n].first_out = -1; + nodes[n].red = false; + nodes[n].partition_index = ++max_blue; + nodes[n].partition_next = first_blue; + first_blue = n; + + return BlueNode(n); + } + + Edge addEdge(RedNode u, BlueNode v) { + int n = arcs.size(); + arcs.push_back(ArcT()); + arcs.push_back(ArcT()); + + arcs[n].target = u._id; + arcs[n | 1].target = v._id; + + arcs[n].next_out = nodes[v._id].first_out; + nodes[v._id].first_out = n; + + arcs[n | 1].next_out = nodes[u._id].first_out; + nodes[u._id].first_out = (n | 1); + + return Edge(n / 2); + } + + void clear() { + arcs.clear(); + nodes.clear(); + first_red = -1; + first_blue = -1; + max_blue = -1; + max_red = -1; + } + + }; + + typedef BpGraphExtender ExtendedSmartBpGraphBase; + + /// \ingroup graphs + /// + /// \brief A smart undirected bipartite graph class. + /// + /// \ref SmartBpGraph is a simple and fast bipartite graph implementation. + /// It is also quite memory efficient but at the price + /// that it does not support node and edge deletion + /// (except for the Snapshot feature). + /// + /// This type fully conforms to the \ref concepts::BpGraph "BpGraph concept" + /// and it also provides some additional functionalities. + /// Most of its member functions and nested classes are documented + /// only in the concept class. + /// + /// This class provides constant time counting for nodes, edges and arcs. + /// + /// \sa concepts::BpGraph + /// \sa SmartGraph + class SmartBpGraph : public ExtendedSmartBpGraphBase { + typedef ExtendedSmartBpGraphBase Parent; + + private: + /// Graphs are \e not copy constructible. Use GraphCopy instead. + SmartBpGraph(const SmartBpGraph &) : ExtendedSmartBpGraphBase() {}; + /// \brief Assignment of a graph to another one is \e not allowed. + /// Use GraphCopy instead. + void operator=(const SmartBpGraph &) {} + + public: + + /// Constructor + + /// Constructor. + /// + SmartBpGraph() {} + + /// \brief Add a new red node to the graph. + /// + /// This function adds a red new node to the graph. + /// \return The new node. + RedNode addRedNode() { return Parent::addRedNode(); } + + /// \brief Add a new blue node to the graph. + /// + /// This function adds a blue new node to the graph. + /// \return The new node. + BlueNode addBlueNode() { return Parent::addBlueNode(); } + + /// \brief Add a new edge to the graph. + /// + /// This function adds a new edge to the graph between nodes + /// \c u and \c v with inherent orientation from node \c u to + /// node \c v. + /// \return The new edge. + Edge addEdge(RedNode u, BlueNode v) { + return Parent::addEdge(u, v); + } + Edge addEdge(BlueNode v, RedNode u) { + return Parent::addEdge(u, v); + } + + /// \brief Node validity check + /// + /// This function gives back \c true if the given node is valid, + /// i.e. it is a real node of the graph. + /// + /// \warning A removed node (using Snapshot) could become valid again + /// if new nodes are added to the graph. + bool valid(Node n) const { return Parent::valid(n); } + + /// \brief Edge validity check + /// + /// This function gives back \c true if the given edge is valid, + /// i.e. it is a real edge of the graph. + /// + /// \warning A removed edge (using Snapshot) could become valid again + /// if new edges are added to the graph. + bool valid(Edge e) const { return Parent::valid(e); } + + /// \brief Arc validity check + /// + /// This function gives back \c true if the given arc is valid, + /// i.e. it is a real arc of the graph. + /// + /// \warning A removed arc (using Snapshot) could become valid again + /// if new edges are added to the graph. + bool valid(Arc a) const { return Parent::valid(a); } + + ///Clear the graph. + + ///This function erases all nodes and arcs from the graph. + /// + void clear() { + Parent::clear(); + } + + /// Reserve memory for nodes. + + /// Using this function, it is possible to avoid superfluous memory + /// allocation: if you know that the graph you want to build will + /// be large (e.g. it will contain millions of nodes and/or edges), + /// then it is worth reserving space for this amount before starting + /// to build the graph. + /// \sa reserveEdge() + void reserveNode(int n) { nodes.reserve(n); }; + + /// Reserve memory for edges. + + /// Using this function, it is possible to avoid superfluous memory + /// allocation: if you know that the graph you want to build will + /// be large (e.g. it will contain millions of nodes and/or edges), + /// then it is worth reserving space for this amount before starting + /// to build the graph. + /// \sa reserveNode() + void reserveEdge(int m) { arcs.reserve(2 * m); }; + + public: + + class Snapshot; + + protected: + + void saveSnapshot(Snapshot &s) + { + s._graph = this; + s.node_num = nodes.size(); + s.arc_num = arcs.size(); + } + + void restoreSnapshot(const Snapshot &s) + { + while(s.arc_num dir; + dir.push_back(arcFromId(n)); + dir.push_back(arcFromId(n-1)); + Parent::notifier(Arc()).erase(dir); + nodes[arcs[n-1].target].first_out=arcs[n].next_out; + nodes[arcs[n].target].first_out=arcs[n-1].next_out; + arcs.pop_back(); + arcs.pop_back(); + } + while(s.node_numrestoreSnapshot(*this); + } + }; + }; + +} //namespace lemon + + +#endif //LEMON_SMART_GRAPH_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/soplex.cc b/extern/quadriflow/3rd/lemon-1.3.1/lemon/soplex.cc new file mode 100644 index 00000000000..d7517231ce2 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/soplex.cc @@ -0,0 +1,465 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 +#include + +#include +#include + + +///\file +///\brief Implementation of the LEMON-SOPLEX lp solver interface. +namespace lemon { + + SoplexLp::SoplexLp() { + soplex = new soplex::SoPlex; + messageLevel(MESSAGE_NOTHING); + } + + SoplexLp::~SoplexLp() { + delete soplex; + } + + SoplexLp::SoplexLp(const SoplexLp& lp) { + rows = lp.rows; + cols = lp.cols; + + soplex = new soplex::SoPlex; + (*static_cast(soplex)) = *(lp.soplex); + + _col_names = lp._col_names; + _col_names_ref = lp._col_names_ref; + + _row_names = lp._row_names; + _row_names_ref = lp._row_names_ref; + + messageLevel(MESSAGE_NOTHING); + } + + void SoplexLp::_clear_temporals() { + _primal_values.clear(); + _dual_values.clear(); + } + + SoplexLp* SoplexLp::newSolver() const { + SoplexLp* newlp = new SoplexLp(); + return newlp; + } + + SoplexLp* SoplexLp::cloneSolver() const { + SoplexLp* newlp = new SoplexLp(*this); + return newlp; + } + + const char* SoplexLp::_solverName() const { return "SoplexLp"; } + + int SoplexLp::_addCol() { + soplex::LPCol c; + c.setLower(-soplex::infinity); + c.setUpper(soplex::infinity); + soplex->addCol(c); + + _col_names.push_back(std::string()); + + return soplex->nCols() - 1; + } + + int SoplexLp::_addRow() { + soplex::LPRow r; + r.setLhs(-soplex::infinity); + r.setRhs(soplex::infinity); + soplex->addRow(r); + + _row_names.push_back(std::string()); + + return soplex->nRows() - 1; + } + + int SoplexLp::_addRow(Value l, ExprIterator b, ExprIterator e, Value u) { + soplex::DSVector v; + for (ExprIterator it = b; it != e; ++it) { + v.add(it->first, it->second); + } + soplex::LPRow r(l, v, u); + soplex->addRow(r); + + _row_names.push_back(std::string()); + + return soplex->nRows() - 1; + } + + + void SoplexLp::_eraseCol(int i) { + soplex->removeCol(i); + _col_names_ref.erase(_col_names[i]); + _col_names[i] = _col_names.back(); + _col_names_ref[_col_names.back()] = i; + _col_names.pop_back(); + } + + void SoplexLp::_eraseRow(int i) { + soplex->removeRow(i); + _row_names_ref.erase(_row_names[i]); + _row_names[i] = _row_names.back(); + _row_names_ref[_row_names.back()] = i; + _row_names.pop_back(); + } + + void SoplexLp::_eraseColId(int i) { + cols.eraseIndex(i); + cols.relocateIndex(i, cols.maxIndex()); + } + void SoplexLp::_eraseRowId(int i) { + rows.eraseIndex(i); + rows.relocateIndex(i, rows.maxIndex()); + } + + void SoplexLp::_getColName(int c, std::string &name) const { + name = _col_names[c]; + } + + void SoplexLp::_setColName(int c, const std::string &name) { + _col_names_ref.erase(_col_names[c]); + _col_names[c] = name; + if (!name.empty()) { + _col_names_ref.insert(std::make_pair(name, c)); + } + } + + int SoplexLp::_colByName(const std::string& name) const { + std::map::const_iterator it = + _col_names_ref.find(name); + if (it != _col_names_ref.end()) { + return it->second; + } else { + return -1; + } + } + + void SoplexLp::_getRowName(int r, std::string &name) const { + name = _row_names[r]; + } + + void SoplexLp::_setRowName(int r, const std::string &name) { + _row_names_ref.erase(_row_names[r]); + _row_names[r] = name; + if (!name.empty()) { + _row_names_ref.insert(std::make_pair(name, r)); + } + } + + int SoplexLp::_rowByName(const std::string& name) const { + std::map::const_iterator it = + _row_names_ref.find(name); + if (it != _row_names_ref.end()) { + return it->second; + } else { + return -1; + } + } + + + void SoplexLp::_setRowCoeffs(int i, ExprIterator b, ExprIterator e) { + for (int j = 0; j < soplex->nCols(); ++j) { + soplex->changeElement(i, j, 0.0); + } + for(ExprIterator it = b; it != e; ++it) { + soplex->changeElement(i, it->first, it->second); + } + } + + void SoplexLp::_getRowCoeffs(int i, InsertIterator b) const { + const soplex::SVector& vec = soplex->rowVector(i); + for (int k = 0; k < vec.size(); ++k) { + *b = std::make_pair(vec.index(k), vec.value(k)); + ++b; + } + } + + void SoplexLp::_setColCoeffs(int j, ExprIterator b, ExprIterator e) { + for (int i = 0; i < soplex->nRows(); ++i) { + soplex->changeElement(i, j, 0.0); + } + for(ExprIterator it = b; it != e; ++it) { + soplex->changeElement(it->first, j, it->second); + } + } + + void SoplexLp::_getColCoeffs(int i, InsertIterator b) const { + const soplex::SVector& vec = soplex->colVector(i); + for (int k = 0; k < vec.size(); ++k) { + *b = std::make_pair(vec.index(k), vec.value(k)); + ++b; + } + } + + void SoplexLp::_setCoeff(int i, int j, Value value) { + soplex->changeElement(i, j, value); + } + + SoplexLp::Value SoplexLp::_getCoeff(int i, int j) const { + return soplex->rowVector(i)[j]; + } + + void SoplexLp::_setColLowerBound(int i, Value value) { + LEMON_ASSERT(value != INF, "Invalid bound"); + soplex->changeLower(i, value != -INF ? value : -soplex::infinity); + } + + SoplexLp::Value SoplexLp::_getColLowerBound(int i) const { + double value = soplex->lower(i); + return value != -soplex::infinity ? value : -INF; + } + + void SoplexLp::_setColUpperBound(int i, Value value) { + LEMON_ASSERT(value != -INF, "Invalid bound"); + soplex->changeUpper(i, value != INF ? value : soplex::infinity); + } + + SoplexLp::Value SoplexLp::_getColUpperBound(int i) const { + double value = soplex->upper(i); + return value != soplex::infinity ? value : INF; + } + + void SoplexLp::_setRowLowerBound(int i, Value lb) { + LEMON_ASSERT(lb != INF, "Invalid bound"); + soplex->changeRange(i, lb != -INF ? lb : -soplex::infinity, soplex->rhs(i)); + } + + SoplexLp::Value SoplexLp::_getRowLowerBound(int i) const { + double res = soplex->lhs(i); + return res == -soplex::infinity ? -INF : res; + } + + void SoplexLp::_setRowUpperBound(int i, Value ub) { + LEMON_ASSERT(ub != -INF, "Invalid bound"); + soplex->changeRange(i, soplex->lhs(i), ub != INF ? ub : soplex::infinity); + } + + SoplexLp::Value SoplexLp::_getRowUpperBound(int i) const { + double res = soplex->rhs(i); + return res == soplex::infinity ? INF : res; + } + + void SoplexLp::_setObjCoeffs(ExprIterator b, ExprIterator e) { + for (int j = 0; j < soplex->nCols(); ++j) { + soplex->changeObj(j, 0.0); + } + for (ExprIterator it = b; it != e; ++it) { + soplex->changeObj(it->first, it->second); + } + } + + void SoplexLp::_getObjCoeffs(InsertIterator b) const { + for (int j = 0; j < soplex->nCols(); ++j) { + Value coef = soplex->obj(j); + if (coef != 0.0) { + *b = std::make_pair(j, coef); + ++b; + } + } + } + + void SoplexLp::_setObjCoeff(int i, Value obj_coef) { + soplex->changeObj(i, obj_coef); + } + + SoplexLp::Value SoplexLp::_getObjCoeff(int i) const { + return soplex->obj(i); + } + + SoplexLp::SolveExitStatus SoplexLp::_solve() { + + _clear_temporals(); + + _applyMessageLevel(); + + soplex::SPxSolver::Status status = soplex->solve(); + + switch (status) { + case soplex::SPxSolver::OPTIMAL: + case soplex::SPxSolver::INFEASIBLE: + case soplex::SPxSolver::UNBOUNDED: + return SOLVED; + default: + return UNSOLVED; + } + } + + SoplexLp::Value SoplexLp::_getPrimal(int i) const { + if (_primal_values.empty()) { + _primal_values.resize(soplex->nCols()); + soplex::Vector pv(_primal_values.size(), &_primal_values.front()); + soplex->getPrimal(pv); + } + return _primal_values[i]; + } + + SoplexLp::Value SoplexLp::_getDual(int i) const { + if (_dual_values.empty()) { + _dual_values.resize(soplex->nRows()); + soplex::Vector dv(_dual_values.size(), &_dual_values.front()); + soplex->getDual(dv); + } + return _dual_values[i]; + } + + SoplexLp::Value SoplexLp::_getPrimalValue() const { + return soplex->objValue(); + } + + SoplexLp::VarStatus SoplexLp::_getColStatus(int i) const { + switch (soplex->getBasisColStatus(i)) { + case soplex::SPxSolver::BASIC: + return BASIC; + case soplex::SPxSolver::ON_UPPER: + return UPPER; + case soplex::SPxSolver::ON_LOWER: + return LOWER; + case soplex::SPxSolver::FIXED: + return FIXED; + case soplex::SPxSolver::ZERO: + return FREE; + default: + LEMON_ASSERT(false, "Wrong column status"); + return VarStatus(); + } + } + + SoplexLp::VarStatus SoplexLp::_getRowStatus(int i) const { + switch (soplex->getBasisRowStatus(i)) { + case soplex::SPxSolver::BASIC: + return BASIC; + case soplex::SPxSolver::ON_UPPER: + return UPPER; + case soplex::SPxSolver::ON_LOWER: + return LOWER; + case soplex::SPxSolver::FIXED: + return FIXED; + case soplex::SPxSolver::ZERO: + return FREE; + default: + LEMON_ASSERT(false, "Wrong row status"); + return VarStatus(); + } + } + + SoplexLp::Value SoplexLp::_getPrimalRay(int i) const { + if (_primal_ray.empty()) { + _primal_ray.resize(soplex->nCols()); + soplex::Vector pv(_primal_ray.size(), &_primal_ray.front()); + soplex->getDualfarkas(pv); + } + return _primal_ray[i]; + } + + SoplexLp::Value SoplexLp::_getDualRay(int i) const { + if (_dual_ray.empty()) { + _dual_ray.resize(soplex->nRows()); + soplex::Vector dv(_dual_ray.size(), &_dual_ray.front()); + soplex->getDualfarkas(dv); + } + return _dual_ray[i]; + } + + SoplexLp::ProblemType SoplexLp::_getPrimalType() const { + switch (soplex->status()) { + case soplex::SPxSolver::OPTIMAL: + return OPTIMAL; + case soplex::SPxSolver::UNBOUNDED: + return UNBOUNDED; + case soplex::SPxSolver::INFEASIBLE: + return INFEASIBLE; + default: + return UNDEFINED; + } + } + + SoplexLp::ProblemType SoplexLp::_getDualType() const { + switch (soplex->status()) { + case soplex::SPxSolver::OPTIMAL: + return OPTIMAL; + case soplex::SPxSolver::UNBOUNDED: + return UNBOUNDED; + case soplex::SPxSolver::INFEASIBLE: + return INFEASIBLE; + default: + return UNDEFINED; + } + } + + void SoplexLp::_setSense(Sense sense) { + switch (sense) { + case MIN: + soplex->changeSense(soplex::SPxSolver::MINIMIZE); + break; + case MAX: + soplex->changeSense(soplex::SPxSolver::MAXIMIZE); + } + } + + SoplexLp::Sense SoplexLp::_getSense() const { + switch (soplex->spxSense()) { + case soplex::SPxSolver::MAXIMIZE: + return MAX; + case soplex::SPxSolver::MINIMIZE: + return MIN; + default: + LEMON_ASSERT(false, "Wrong sense."); + return SoplexLp::Sense(); + } + } + + void SoplexLp::_clear() { + soplex->clear(); + _col_names.clear(); + _col_names_ref.clear(); + _row_names.clear(); + _row_names_ref.clear(); + cols.clear(); + rows.clear(); + _clear_temporals(); + } + + void SoplexLp::_messageLevel(MessageLevel level) { + switch (level) { + case MESSAGE_NOTHING: + _message_level = -1; + break; + case MESSAGE_ERROR: + _message_level = soplex::SPxOut::ERROR; + break; + case MESSAGE_WARNING: + _message_level = soplex::SPxOut::WARNING; + break; + case MESSAGE_NORMAL: + _message_level = soplex::SPxOut::INFO2; + break; + case MESSAGE_VERBOSE: + _message_level = soplex::SPxOut::DEBUG; + break; + } + } + + void SoplexLp::_applyMessageLevel() { + soplex::Param::setVerbose(_message_level); + } + +} //namespace lemon + diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/soplex.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/soplex.h new file mode 100644 index 00000000000..be73f3abecd --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/soplex.h @@ -0,0 +1,158 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_SOPLEX_H +#define LEMON_SOPLEX_H + +///\file +///\brief Header of the LEMON-SOPLEX lp solver interface. + +#include +#include + +#include + +// Forward declaration +namespace soplex { + class SoPlex; +} + +namespace lemon { + + /// \ingroup lp_group + /// + /// \brief Interface for the SOPLEX solver + /// + /// This class implements an interface for the SoPlex LP solver. + /// The SoPlex library is an object oriented lp solver library + /// developed at the Konrad-Zuse-Zentrum für Informationstechnik + /// Berlin (ZIB). You can find detailed information about it at the + /// http://soplex.zib.de address. + class SoplexLp : public LpSolver { + private: + + soplex::SoPlex* soplex; + + std::vector _col_names; + std::map _col_names_ref; + + std::vector _row_names; + std::map _row_names_ref; + + private: + + // these values cannot be retrieved element by element + mutable std::vector _primal_values; + mutable std::vector _dual_values; + + mutable std::vector _primal_ray; + mutable std::vector _dual_ray; + + void _clear_temporals(); + + public: + + /// \e + SoplexLp(); + /// \e + SoplexLp(const SoplexLp&); + /// \e + ~SoplexLp(); + /// \e + virtual SoplexLp* newSolver() const; + /// \e + virtual SoplexLp* cloneSolver() const; + + protected: + + virtual const char* _solverName() const; + + virtual int _addCol(); + virtual int _addRow(); + virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u); + + virtual void _eraseCol(int i); + virtual void _eraseRow(int i); + + virtual void _eraseColId(int i); + virtual void _eraseRowId(int i); + + virtual void _getColName(int col, std::string& name) const; + virtual void _setColName(int col, const std::string& name); + virtual int _colByName(const std::string& name) const; + + virtual void _getRowName(int row, std::string& name) const; + virtual void _setRowName(int row, const std::string& name); + virtual int _rowByName(const std::string& name) const; + + virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e); + virtual void _getRowCoeffs(int i, InsertIterator b) const; + + virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e); + virtual void _getColCoeffs(int i, InsertIterator b) const; + + virtual void _setCoeff(int row, int col, Value value); + virtual Value _getCoeff(int row, int col) const; + + virtual void _setColLowerBound(int i, Value value); + virtual Value _getColLowerBound(int i) const; + virtual void _setColUpperBound(int i, Value value); + virtual Value _getColUpperBound(int i) const; + + virtual void _setRowLowerBound(int i, Value value); + virtual Value _getRowLowerBound(int i) const; + virtual void _setRowUpperBound(int i, Value value); + virtual Value _getRowUpperBound(int i) const; + + virtual void _setObjCoeffs(ExprIterator b, ExprIterator e); + virtual void _getObjCoeffs(InsertIterator b) const; + + virtual void _setObjCoeff(int i, Value obj_coef); + virtual Value _getObjCoeff(int i) const; + + virtual void _setSense(Sense sense); + virtual Sense _getSense() const; + + virtual SolveExitStatus _solve(); + virtual Value _getPrimal(int i) const; + virtual Value _getDual(int i) const; + + virtual Value _getPrimalValue() const; + + virtual Value _getPrimalRay(int i) const; + virtual Value _getDualRay(int i) const; + + virtual VarStatus _getColStatus(int i) const; + virtual VarStatus _getRowStatus(int i) const; + + virtual ProblemType _getPrimalType() const; + virtual ProblemType _getDualType() const; + + virtual void _clear(); + + void _messageLevel(MessageLevel m); + void _applyMessageLevel(); + + int _message_level; + + }; + +} //END OF NAMESPACE LEMON + +#endif //LEMON_SOPLEX_H + diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/static_graph.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/static_graph.h new file mode 100644 index 00000000000..1f04e40841c --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/static_graph.h @@ -0,0 +1,476 @@ +/* -*- 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_STATIC_GRAPH_H +#define LEMON_STATIC_GRAPH_H + +///\ingroup graphs +///\file +///\brief StaticDigraph class. + +#include +#include + +namespace lemon { + + class StaticDigraphBase { + public: + + StaticDigraphBase() + : built(false), node_num(0), arc_num(0), + node_first_out(NULL), node_first_in(NULL), + arc_source(NULL), arc_target(NULL), + arc_next_in(NULL), arc_next_out(NULL) {} + + ~StaticDigraphBase() { + if (built) { + delete[] node_first_out; + delete[] node_first_in; + delete[] arc_source; + delete[] arc_target; + delete[] arc_next_out; + delete[] arc_next_in; + } + } + + class Node { + friend class StaticDigraphBase; + protected: + int id; + Node(int _id) : id(_id) {} + public: + Node() {} + Node (Invalid) : id(-1) {} + bool operator==(const Node& node) const { return id == node.id; } + bool operator!=(const Node& node) const { return id != node.id; } + bool operator<(const Node& node) const { return id < node.id; } + }; + + class Arc { + friend class StaticDigraphBase; + protected: + int id; + Arc(int _id) : id(_id) {} + public: + Arc() { } + Arc (Invalid) : id(-1) {} + bool operator==(const Arc& arc) const { return id == arc.id; } + bool operator!=(const Arc& arc) const { return id != arc.id; } + bool operator<(const Arc& arc) const { return id < arc.id; } + }; + + Node source(const Arc& e) const { return Node(arc_source[e.id]); } + Node target(const Arc& e) const { return Node(arc_target[e.id]); } + + void first(Node& n) const { n.id = node_num - 1; } + static void next(Node& n) { --n.id; } + + void first(Arc& e) const { e.id = arc_num - 1; } + static void next(Arc& e) { --e.id; } + + void firstOut(Arc& e, const Node& n) const { + e.id = node_first_out[n.id] != node_first_out[n.id + 1] ? + node_first_out[n.id] : -1; + } + void nextOut(Arc& e) const { e.id = arc_next_out[e.id]; } + + void firstIn(Arc& e, const Node& n) const { e.id = node_first_in[n.id]; } + void nextIn(Arc& e) const { e.id = arc_next_in[e.id]; } + + static int id(const Node& n) { return n.id; } + static Node nodeFromId(int id) { return Node(id); } + int maxNodeId() const { return node_num - 1; } + + static int id(const Arc& e) { return e.id; } + static Arc arcFromId(int id) { return Arc(id); } + int maxArcId() const { return arc_num - 1; } + + typedef True NodeNumTag; + typedef True ArcNumTag; + + int nodeNum() const { return node_num; } + int arcNum() const { return arc_num; } + + private: + + template + class ArcLess { + public: + typedef typename Digraph::Arc Arc; + + ArcLess(const Digraph &_graph, const NodeRefMap& _nodeRef) + : digraph(_graph), nodeRef(_nodeRef) {} + + bool operator()(const Arc& left, const Arc& right) const { + return nodeRef[digraph.target(left)] < nodeRef[digraph.target(right)]; + } + private: + const Digraph& digraph; + const NodeRefMap& nodeRef; + }; + + public: + + typedef True BuildTag; + + void clear() { + if (built) { + delete[] node_first_out; + delete[] node_first_in; + delete[] arc_source; + delete[] arc_target; + delete[] arc_next_out; + delete[] arc_next_in; + } + built = false; + node_num = 0; + arc_num = 0; + } + + template + void build(const Digraph& digraph, NodeRefMap& nodeRef, ArcRefMap& arcRef) { + typedef typename Digraph::Node GNode; + typedef typename Digraph::Arc GArc; + + built = true; + + node_num = countNodes(digraph); + arc_num = countArcs(digraph); + + node_first_out = new int[node_num + 1]; + node_first_in = new int[node_num]; + + arc_source = new int[arc_num]; + arc_target = new int[arc_num]; + arc_next_out = new int[arc_num]; + arc_next_in = new int[arc_num]; + + int node_index = 0; + for (typename Digraph::NodeIt n(digraph); n != INVALID; ++n) { + nodeRef[n] = Node(node_index); + node_first_in[node_index] = -1; + ++node_index; + } + + ArcLess arcLess(digraph, nodeRef); + + int arc_index = 0; + for (typename Digraph::NodeIt n(digraph); n != INVALID; ++n) { + int source = nodeRef[n].id; + std::vector arcs; + for (typename Digraph::OutArcIt e(digraph, n); e != INVALID; ++e) { + arcs.push_back(e); + } + if (!arcs.empty()) { + node_first_out[source] = arc_index; + std::sort(arcs.begin(), arcs.end(), arcLess); + for (typename std::vector::iterator it = arcs.begin(); + it != arcs.end(); ++it) { + int target = nodeRef[digraph.target(*it)].id; + arcRef[*it] = Arc(arc_index); + arc_source[arc_index] = source; + arc_target[arc_index] = target; + arc_next_in[arc_index] = node_first_in[target]; + node_first_in[target] = arc_index; + arc_next_out[arc_index] = arc_index + 1; + ++arc_index; + } + arc_next_out[arc_index - 1] = -1; + } else { + node_first_out[source] = arc_index; + } + } + node_first_out[node_num] = arc_num; + } + + template + void build(int n, ArcListIterator first, ArcListIterator last) { + built = true; + + node_num = n; + arc_num = std::distance(first, last); + + node_first_out = new int[node_num + 1]; + node_first_in = new int[node_num]; + + arc_source = new int[arc_num]; + arc_target = new int[arc_num]; + arc_next_out = new int[arc_num]; + arc_next_in = new int[arc_num]; + + for (int i = 0; i != node_num; ++i) { + node_first_in[i] = -1; + } + + int arc_index = 0; + for (int i = 0; i != node_num; ++i) { + node_first_out[i] = arc_index; + for ( ; first != last && (*first).first == i; ++first) { + int j = (*first).second; + LEMON_ASSERT(j >= 0 && j < node_num, + "Wrong arc list for StaticDigraph::build()"); + arc_source[arc_index] = i; + arc_target[arc_index] = j; + arc_next_in[arc_index] = node_first_in[j]; + node_first_in[j] = arc_index; + arc_next_out[arc_index] = arc_index + 1; + ++arc_index; + } + if (arc_index > node_first_out[i]) + arc_next_out[arc_index - 1] = -1; + } + LEMON_ASSERT(first == last, + "Wrong arc list for StaticDigraph::build()"); + node_first_out[node_num] = arc_num; + } + + protected: + + void fastFirstOut(Arc& e, const Node& n) const { + e.id = node_first_out[n.id]; + } + + static void fastNextOut(Arc& e) { + ++e.id; + } + void fastLastOut(Arc& e, const Node& n) const { + e.id = node_first_out[n.id + 1]; + } + + protected: + bool built; + int node_num; + int arc_num; + int *node_first_out; + int *node_first_in; + int *arc_source; + int *arc_target; + int *arc_next_in; + int *arc_next_out; + }; + + typedef DigraphExtender ExtendedStaticDigraphBase; + + + /// \ingroup graphs + /// + /// \brief A static directed graph class. + /// + /// \ref StaticDigraph is a highly efficient digraph implementation, + /// but it is fully static. + /// It stores only two \c int values for each node and only four \c int + /// values for each arc. Moreover it provides faster item iteration than + /// \ref ListDigraph and \ref SmartDigraph, especially using \c OutArcIt + /// iterators, since its arcs are stored in an appropriate order. + /// However it only provides build() and clear() functions and does not + /// support any other modification of the digraph. + /// + /// Since this digraph structure is completely static, its nodes and arcs + /// can be indexed with integers from the ranges [0..nodeNum()-1] + /// and [0..arcNum()-1], respectively. + /// The index of an item is the same as its ID, it can be obtained + /// using the corresponding \ref index() or \ref concepts::Digraph::id() + /// "id()" function. A node or arc with a certain index can be obtained + /// using node() or arc(). + /// + /// This type fully conforms to the \ref concepts::Digraph "Digraph concept". + /// Most of its member functions and nested classes are documented + /// only in the concept class. + /// + /// This class provides constant time counting for nodes and arcs. + /// + /// \sa concepts::Digraph + class StaticDigraph : public ExtendedStaticDigraphBase { + public: + + typedef ExtendedStaticDigraphBase Parent; + + public: + + /// \brief Constructor + /// + /// Default constructor. + StaticDigraph() : Parent() {} + + /// \brief The node with the given index. + /// + /// This function returns the node with the given index. + /// \sa index() + static Node node(int ix) { return Parent::nodeFromId(ix); } + + /// \brief The arc with the given index. + /// + /// This function returns the arc with the given index. + /// \sa index() + static Arc arc(int ix) { return Parent::arcFromId(ix); } + + /// \brief The index of the given node. + /// + /// This function returns the index of the the given node. + /// \sa node() + static int index(Node node) { return Parent::id(node); } + + /// \brief The index of the given arc. + /// + /// This function returns the index of the the given arc. + /// \sa arc() + static int index(Arc arc) { return Parent::id(arc); } + + /// \brief Number of nodes. + /// + /// This function returns the number of nodes. + int nodeNum() const { return node_num; } + + /// \brief Number of arcs. + /// + /// This function returns the number of arcs. + int arcNum() const { return arc_num; } + + /// \brief Build the digraph copying another digraph. + /// + /// This function builds the digraph copying another digraph of any + /// kind. It can be called more than once, but in such case, the whole + /// structure and all maps will be cleared and rebuilt. + /// + /// This method also makes possible to copy a digraph to a StaticDigraph + /// structure using \ref DigraphCopy. + /// + /// \param digraph An existing digraph to be copied. + /// \param nodeRef The node references will be copied into this map. + /// Its key type must be \c Digraph::Node and its value type must be + /// \c StaticDigraph::Node. + /// It must conform to the \ref concepts::ReadWriteMap "ReadWriteMap" + /// concept. + /// \param arcRef The arc references will be copied into this map. + /// Its key type must be \c Digraph::Arc and its value type must be + /// \c StaticDigraph::Arc. + /// It must conform to the \ref concepts::WriteMap "WriteMap" concept. + /// + /// \note If you do not need the arc references, then you could use + /// \ref NullMap for the last parameter. However the node references + /// are required by the function itself, thus they must be readable + /// from the map. + template + void build(const Digraph& digraph, NodeRefMap& nodeRef, ArcRefMap& arcRef) { + if (built) Parent::clear(); + Parent::build(digraph, nodeRef, arcRef); + } + + /// \brief Build the digraph from an arc list. + /// + /// This function builds the digraph from the given arc list. + /// It can be called more than once, but in such case, the whole + /// structure and all maps will be cleared and rebuilt. + /// + /// The list of the arcs must be given in the range [begin, end) + /// specified by STL compatible itartors whose \c value_type must be + /// std::pair. + /// Each arc must be specified by a pair of integer indices + /// from the range [0..n-1]. The pairs must be in a + /// non-decreasing order with respect to their first values. + /// If the k-th pair in the list is (i,j), then + /// arc(k-1) will connect node(i) to node(j). + /// + /// \param n The number of nodes. + /// \param begin An iterator pointing to the beginning of the arc list. + /// \param end An iterator pointing to the end of the arc list. + /// + /// For example, a simple digraph can be constructed like this. + /// \code + /// std::vector > 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)); + /// StaticDigraph gr; + /// gr.build(4, arcs.begin(), arcs.end()); + /// \endcode + template + void build(int n, ArcListIterator begin, ArcListIterator end) { + if (built) Parent::clear(); + StaticDigraphBase::build(n, begin, end); + notifier(Node()).build(); + notifier(Arc()).build(); + } + + /// \brief Clear the digraph. + /// + /// This function erases all nodes and arcs from the digraph. + void clear() { + Parent::clear(); + } + + protected: + + using Parent::fastFirstOut; + using Parent::fastNextOut; + using Parent::fastLastOut; + + public: + + class OutArcIt : public Arc { + public: + + OutArcIt() { } + + OutArcIt(Invalid i) : Arc(i) { } + + OutArcIt(const StaticDigraph& digraph, const Node& node) { + digraph.fastFirstOut(*this, node); + digraph.fastLastOut(last, node); + if (last == *this) *this = INVALID; + } + + OutArcIt(const StaticDigraph& digraph, const Arc& arc) : Arc(arc) { + if (arc != INVALID) { + digraph.fastLastOut(last, digraph.source(arc)); + } + } + + OutArcIt& operator++() { + StaticDigraph::fastNextOut(*this); + if (last == *this) *this = INVALID; + return *this; + } + + private: + Arc last; + }; + + Node baseNode(const OutArcIt &arc) const { + return Parent::source(static_cast(arc)); + } + + Node runningNode(const OutArcIt &arc) const { + return Parent::target(static_cast(arc)); + } + + Node baseNode(const InArcIt &arc) const { + return Parent::target(static_cast(arc)); + } + + Node runningNode(const InArcIt &arc) const { + return Parent::source(static_cast(arc)); + } + + }; + +} + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/suurballe.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/suurballe.h new file mode 100644 index 00000000000..f1338a2948f --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/suurballe.h @@ -0,0 +1,776 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_SUURBALLE_H +#define LEMON_SUURBALLE_H + +///\ingroup shortest_path +///\file +///\brief An algorithm for finding arc-disjoint paths between two +/// nodes having minimum total length. + +#include +#include +#include +#include +#include +#include +#include + +namespace lemon { + + /// \brief Default traits class of Suurballe algorithm. + /// + /// Default traits class of Suurballe algorithm. + /// \tparam GR The digraph type the algorithm runs on. + /// \tparam LEN The type of the length map. + /// The default value is GR::ArcMap. +#ifdef DOXYGEN + template +#else + template < typename GR, + typename LEN = typename GR::template ArcMap > +#endif + struct SuurballeDefaultTraits + { + /// The type of the digraph. + typedef GR Digraph; + /// The type of the length map. + typedef LEN LengthMap; + /// The type of the lengths. + typedef typename LEN::Value Length; + /// The type of the flow map. + typedef typename GR::template ArcMap FlowMap; + /// The type of the potential map. + typedef typename GR::template NodeMap PotentialMap; + + /// \brief The path type + /// + /// The type used for storing the found arc-disjoint paths. + /// It must conform to the \ref lemon::concepts::Path "Path" concept + /// and it must have an \c addBack() function. + typedef lemon::Path Path; + + /// The cross reference type used for the heap. + typedef typename GR::template NodeMap HeapCrossRef; + + /// \brief The heap type used for internal Dijkstra computations. + /// + /// The type of the heap used for internal Dijkstra computations. + /// It must conform to the \ref lemon::concepts::Heap "Heap" concept + /// and its priority type must be \c Length. + typedef BinHeap Heap; + }; + + /// \addtogroup shortest_path + /// @{ + + /// \brief Algorithm for finding arc-disjoint paths between two nodes + /// having minimum total length. + /// + /// \ref lemon::Suurballe "Suurballe" implements an algorithm for + /// finding arc-disjoint paths having minimum total length (cost) + /// from a given source node to a given target node in a digraph. + /// + /// Note that this problem is a special case of the \ref min_cost_flow + /// "minimum cost flow problem". This implementation is actually an + /// efficient specialized version of the \ref CapacityScaling + /// "successive shortest path" algorithm directly for this problem. + /// Therefore this class provides query functions for flow values and + /// node potentials (the dual solution) just like the minimum cost flow + /// algorithms. + /// + /// \tparam GR The digraph type the algorithm runs on. + /// \tparam LEN The type of the length map. + /// The default value is GR::ArcMap. + /// + /// \warning Length values should be \e non-negative. + /// + /// \note For finding \e node-disjoint paths, this algorithm can be used + /// along with the \ref SplitNodes adaptor. +#ifdef DOXYGEN + template +#else + template < typename GR, + typename LEN = typename GR::template ArcMap, + typename TR = SuurballeDefaultTraits > +#endif + class Suurballe + { + TEMPLATE_DIGRAPH_TYPEDEFS(GR); + + typedef ConstMap ConstArcMap; + typedef typename GR::template NodeMap PredMap; + + public: + + /// The type of the digraph. + typedef typename TR::Digraph Digraph; + /// The type of the length map. + typedef typename TR::LengthMap LengthMap; + /// The type of the lengths. + typedef typename TR::Length Length; + + /// The type of the flow map. + typedef typename TR::FlowMap FlowMap; + /// The type of the potential map. + typedef typename TR::PotentialMap PotentialMap; + /// The type of the path structures. + typedef typename TR::Path Path; + /// The cross reference type used for the heap. + typedef typename TR::HeapCrossRef HeapCrossRef; + /// The heap type used for internal Dijkstra computations. + typedef typename TR::Heap Heap; + + /// The \ref lemon::SuurballeDefaultTraits "traits class" of the algorithm. + typedef TR Traits; + + private: + + // ResidualDijkstra is a special implementation of the + // Dijkstra algorithm for finding shortest paths in the + // residual network with respect to the reduced arc lengths + // and modifying the node potentials according to the + // distance of the nodes. + class ResidualDijkstra + { + private: + + const Digraph &_graph; + const LengthMap &_length; + const FlowMap &_flow; + PotentialMap &_pi; + PredMap &_pred; + Node _s; + Node _t; + + PotentialMap _dist; + std::vector _proc_nodes; + + public: + + // Constructor + ResidualDijkstra(Suurballe &srb) : + _graph(srb._graph), _length(srb._length), + _flow(*srb._flow), _pi(*srb._potential), _pred(srb._pred), + _s(srb._s), _t(srb._t), _dist(_graph) {} + + // Run the algorithm and return true if a path is found + // from the source node to the target node. + bool run(int cnt) { + return cnt == 0 ? startFirst() : start(); + } + + private: + + // Execute the algorithm for the first time (the flow and potential + // functions have to be identically zero). + bool startFirst() { + HeapCrossRef heap_cross_ref(_graph, Heap::PRE_HEAP); + Heap heap(heap_cross_ref); + heap.push(_s, 0); + _pred[_s] = INVALID; + _proc_nodes.clear(); + + // Process nodes + while (!heap.empty() && heap.top() != _t) { + Node u = heap.top(), v; + Length d = heap.prio(), dn; + _dist[u] = heap.prio(); + _proc_nodes.push_back(u); + heap.pop(); + + // Traverse outgoing arcs + for (OutArcIt e(_graph, u); e != INVALID; ++e) { + v = _graph.target(e); + switch(heap.state(v)) { + case Heap::PRE_HEAP: + heap.push(v, d + _length[e]); + _pred[v] = e; + break; + case Heap::IN_HEAP: + dn = d + _length[e]; + if (dn < heap[v]) { + heap.decrease(v, dn); + _pred[v] = e; + } + break; + case Heap::POST_HEAP: + break; + } + } + } + if (heap.empty()) return false; + + // Update potentials of processed nodes + Length t_dist = heap.prio(); + for (int i = 0; i < int(_proc_nodes.size()); ++i) + _pi[_proc_nodes[i]] = _dist[_proc_nodes[i]] - t_dist; + return true; + } + + // Execute the algorithm. + bool start() { + HeapCrossRef heap_cross_ref(_graph, Heap::PRE_HEAP); + Heap heap(heap_cross_ref); + heap.push(_s, 0); + _pred[_s] = INVALID; + _proc_nodes.clear(); + + // Process nodes + while (!heap.empty() && heap.top() != _t) { + Node u = heap.top(), v; + Length d = heap.prio() + _pi[u], dn; + _dist[u] = heap.prio(); + _proc_nodes.push_back(u); + heap.pop(); + + // Traverse outgoing arcs + for (OutArcIt e(_graph, u); e != INVALID; ++e) { + if (_flow[e] == 0) { + v = _graph.target(e); + switch(heap.state(v)) { + case Heap::PRE_HEAP: + heap.push(v, d + _length[e] - _pi[v]); + _pred[v] = e; + break; + case Heap::IN_HEAP: + dn = d + _length[e] - _pi[v]; + if (dn < heap[v]) { + heap.decrease(v, dn); + _pred[v] = e; + } + break; + case Heap::POST_HEAP: + break; + } + } + } + + // Traverse incoming arcs + for (InArcIt e(_graph, u); e != INVALID; ++e) { + if (_flow[e] == 1) { + v = _graph.source(e); + switch(heap.state(v)) { + case Heap::PRE_HEAP: + heap.push(v, d - _length[e] - _pi[v]); + _pred[v] = e; + break; + case Heap::IN_HEAP: + dn = d - _length[e] - _pi[v]; + if (dn < heap[v]) { + heap.decrease(v, dn); + _pred[v] = e; + } + break; + case Heap::POST_HEAP: + break; + } + } + } + } + if (heap.empty()) return false; + + // Update potentials of processed nodes + Length t_dist = heap.prio(); + for (int i = 0; i < int(_proc_nodes.size()); ++i) + _pi[_proc_nodes[i]] += _dist[_proc_nodes[i]] - t_dist; + return true; + } + + }; //class ResidualDijkstra + + public: + + /// \name Named Template Parameters + /// @{ + + template + struct SetFlowMapTraits : public Traits { + typedef T FlowMap; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c FlowMap type. + /// + /// \ref named-templ-param "Named parameter" for setting + /// \c FlowMap type. + template + struct SetFlowMap + : public Suurballe > { + typedef Suurballe > Create; + }; + + template + struct SetPotentialMapTraits : public Traits { + typedef T PotentialMap; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c PotentialMap type. + /// + /// \ref named-templ-param "Named parameter" for setting + /// \c PotentialMap type. + template + struct SetPotentialMap + : public Suurballe > { + typedef Suurballe > Create; + }; + + template + struct SetPathTraits : public Traits { + typedef T Path; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c %Path type. + /// + /// \ref named-templ-param "Named parameter" for setting \c %Path type. + /// It must conform to the \ref lemon::concepts::Path "Path" concept + /// and it must have an \c addBack() function. + template + struct SetPath + : public Suurballe > { + typedef Suurballe > Create; + }; + + template + struct SetHeapTraits : public Traits { + typedef H Heap; + typedef CR HeapCrossRef; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c Heap and \c HeapCrossRef types. + /// + /// \ref named-templ-param "Named parameter" for setting \c Heap + /// and \c HeapCrossRef types with automatic allocation. + /// They will be used for internal Dijkstra computations. + /// The heap type must conform to the \ref lemon::concepts::Heap "Heap" + /// concept and its priority type must be \c Length. + template > + struct SetHeap + : public Suurballe > { + typedef Suurballe > Create; + }; + + /// @} + + private: + + // The digraph the algorithm runs on + const Digraph &_graph; + // The length map + const LengthMap &_length; + + // Arc map of the current flow + FlowMap *_flow; + bool _local_flow; + // Node map of the current potentials + PotentialMap *_potential; + bool _local_potential; + + // The source node + Node _s; + // The target node + Node _t; + + // Container to store the found paths + std::vector _paths; + int _path_num; + + // The pred arc map + PredMap _pred; + + // Data for full init + PotentialMap *_init_dist; + PredMap *_init_pred; + bool _full_init; + + protected: + + Suurballe() {} + + public: + + /// \brief Constructor. + /// + /// Constructor. + /// + /// \param graph The digraph the algorithm runs on. + /// \param length The length (cost) values of the arcs. + Suurballe( const Digraph &graph, + const LengthMap &length ) : + _graph(graph), _length(length), _flow(0), _local_flow(false), + _potential(0), _local_potential(false), _pred(graph), + _init_dist(0), _init_pred(0) + {} + + /// Destructor. + ~Suurballe() { + if (_local_flow) delete _flow; + if (_local_potential) delete _potential; + delete _init_dist; + delete _init_pred; + } + + /// \brief Set the flow map. + /// + /// This function sets the flow map. + /// If it is not used before calling \ref run() or \ref init(), + /// an instance will be allocated automatically. The destructor + /// deallocates this automatically allocated map, of course. + /// + /// The found flow contains only 0 and 1 values, since it is the + /// union of the found arc-disjoint paths. + /// + /// \return (*this) + Suurballe& flowMap(FlowMap &map) { + if (_local_flow) { + delete _flow; + _local_flow = false; + } + _flow = ↦ + return *this; + } + + /// \brief Set the potential map. + /// + /// This function sets the potential map. + /// If it is not used before calling \ref run() or \ref init(), + /// an instance will be allocated automatically. The destructor + /// deallocates this automatically allocated map, of course. + /// + /// The node potentials provide the dual solution of the underlying + /// \ref min_cost_flow "minimum cost flow problem". + /// + /// \return (*this) + Suurballe& potentialMap(PotentialMap &map) { + if (_local_potential) { + delete _potential; + _local_potential = false; + } + _potential = ↦ + return *this; + } + + /// \name Execution Control + /// The simplest way to execute the algorithm is to call the run() + /// function.\n + /// If you need to execute the algorithm many times using the same + /// source node, then you may call fullInit() once and start() + /// for each target node.\n + /// If you only need the flow that is the union of the found + /// arc-disjoint paths, then you may call findFlow() instead of + /// start(). + + /// @{ + + /// \brief Run the algorithm. + /// + /// This function runs the algorithm. + /// + /// \param s The source node. + /// \param t The target node. + /// \param k The number of paths to be found. + /// + /// \return \c k if there are at least \c k arc-disjoint paths from + /// \c s to \c t in the digraph. Otherwise it returns the number of + /// arc-disjoint paths found. + /// + /// \note Apart from the return value, s.run(s, t, k) is + /// just a shortcut of the following code. + /// \code + /// s.init(s); + /// s.start(t, k); + /// \endcode + int run(const Node& s, const Node& t, int k = 2) { + init(s); + start(t, k); + return _path_num; + } + + /// \brief Initialize the algorithm. + /// + /// This function initializes the algorithm with the given source node. + /// + /// \param s The source node. + void init(const Node& s) { + _s = s; + + // Initialize maps + if (!_flow) { + _flow = new FlowMap(_graph); + _local_flow = true; + } + if (!_potential) { + _potential = new PotentialMap(_graph); + _local_potential = true; + } + _full_init = false; + } + + /// \brief Initialize the algorithm and perform Dijkstra. + /// + /// This function initializes the algorithm and performs a full + /// Dijkstra search from the given source node. It makes consecutive + /// executions of \ref start() "start(t, k)" faster, since they + /// have to perform %Dijkstra only k-1 times. + /// + /// This initialization is usually worth using instead of \ref init() + /// if the algorithm is executed many times using the same source node. + /// + /// \param s The source node. + void fullInit(const Node& s) { + // Initialize maps + init(s); + if (!_init_dist) { + _init_dist = new PotentialMap(_graph); + } + if (!_init_pred) { + _init_pred = new PredMap(_graph); + } + + // Run a full Dijkstra + typename Dijkstra + ::template SetStandardHeap + ::template SetDistMap + ::template SetPredMap + ::Create dijk(_graph, _length); + dijk.distMap(*_init_dist).predMap(*_init_pred); + dijk.run(s); + + _full_init = true; + } + + /// \brief Execute the algorithm. + /// + /// This function executes the algorithm. + /// + /// \param t The target node. + /// \param k The number of paths to be found. + /// + /// \return \c k if there are at least \c k arc-disjoint paths from + /// \c s to \c t in the digraph. Otherwise it returns the number of + /// arc-disjoint paths found. + /// + /// \note Apart from the return value, s.start(t, k) is + /// just a shortcut of the following code. + /// \code + /// s.findFlow(t, k); + /// s.findPaths(); + /// \endcode + int start(const Node& t, int k = 2) { + findFlow(t, k); + findPaths(); + return _path_num; + } + + /// \brief Execute the algorithm to find an optimal flow. + /// + /// This function executes the successive shortest path algorithm to + /// find a minimum cost flow, which is the union of \c k (or less) + /// arc-disjoint paths. + /// + /// \param t The target node. + /// \param k The number of paths to be found. + /// + /// \return \c k if there are at least \c k arc-disjoint paths from + /// the source node to the given node \c t in the digraph. + /// Otherwise it returns the number of arc-disjoint paths found. + /// + /// \pre \ref init() must be called before using this function. + int findFlow(const Node& t, int k = 2) { + _t = t; + ResidualDijkstra dijkstra(*this); + + // Initialization + for (ArcIt e(_graph); e != INVALID; ++e) { + (*_flow)[e] = 0; + } + if (_full_init) { + for (NodeIt n(_graph); n != INVALID; ++n) { + (*_potential)[n] = (*_init_dist)[n]; + } + Node u = _t; + Arc e; + while ((e = (*_init_pred)[u]) != INVALID) { + (*_flow)[e] = 1; + u = _graph.source(e); + } + _path_num = 1; + } else { + for (NodeIt n(_graph); n != INVALID; ++n) { + (*_potential)[n] = 0; + } + _path_num = 0; + } + + // Find shortest paths + while (_path_num < k) { + // Run Dijkstra + if (!dijkstra.run(_path_num)) break; + ++_path_num; + + // Set the flow along the found shortest path + Node u = _t; + Arc e; + while ((e = _pred[u]) != INVALID) { + if (u == _graph.target(e)) { + (*_flow)[e] = 1; + u = _graph.source(e); + } else { + (*_flow)[e] = 0; + u = _graph.target(e); + } + } + } + return _path_num; + } + + /// \brief Compute the paths from the flow. + /// + /// This function computes arc-disjoint paths from the found minimum + /// cost flow, which is the union of them. + /// + /// \pre \ref init() and \ref findFlow() must be called before using + /// this function. + void findPaths() { + FlowMap res_flow(_graph); + for(ArcIt a(_graph); a != INVALID; ++a) res_flow[a] = (*_flow)[a]; + + _paths.clear(); + _paths.resize(_path_num); + for (int i = 0; i < _path_num; ++i) { + Node n = _s; + while (n != _t) { + OutArcIt e(_graph, n); + for ( ; res_flow[e] == 0; ++e) ; + n = _graph.target(e); + _paths[i].addBack(e); + res_flow[e] = 0; + } + } + } + + /// @} + + /// \name Query Functions + /// The results of the algorithm can be obtained using these + /// functions. + /// \n The algorithm should be executed before using them. + + /// @{ + + /// \brief Return the total length of the found paths. + /// + /// This function returns the total length of the found paths, i.e. + /// the total cost of the found flow. + /// The complexity of the function is O(m). + /// + /// \pre \ref run() or \ref findFlow() must be called before using + /// this function. + Length totalLength() const { + Length c = 0; + for (ArcIt e(_graph); e != INVALID; ++e) + c += (*_flow)[e] * _length[e]; + return c; + } + + /// \brief Return the flow value on the given arc. + /// + /// This function returns the flow value on the given arc. + /// It is \c 1 if the arc is involved in one of the found arc-disjoint + /// paths, otherwise it is \c 0. + /// + /// \pre \ref run() or \ref findFlow() must be called before using + /// this function. + int flow(const Arc& arc) const { + return (*_flow)[arc]; + } + + /// \brief Return a const reference to an arc map storing the + /// found flow. + /// + /// This function returns a const reference to an arc map storing + /// the flow that is the union of the found arc-disjoint paths. + /// + /// \pre \ref run() or \ref findFlow() must be called before using + /// this function. + const FlowMap& flowMap() const { + return *_flow; + } + + /// \brief Return the potential of the given node. + /// + /// This function returns the potential of the given node. + /// The node potentials provide the dual solution of the + /// underlying \ref min_cost_flow "minimum cost flow problem". + /// + /// \pre \ref run() or \ref findFlow() must be called before using + /// this function. + Length potential(const Node& node) const { + return (*_potential)[node]; + } + + /// \brief Return a const reference to a node map storing the + /// found potentials (the dual solution). + /// + /// This function returns a const reference to a node map storing + /// the found potentials that provide the dual solution of the + /// underlying \ref min_cost_flow "minimum cost flow problem". + /// + /// \pre \ref run() or \ref findFlow() must be called before using + /// this function. + const PotentialMap& potentialMap() const { + return *_potential; + } + + /// \brief Return the number of the found paths. + /// + /// This function returns the number of the found paths. + /// + /// \pre \ref run() or \ref findFlow() must be called before using + /// this function. + int pathNum() const { + return _path_num; + } + + /// \brief Return a const reference to the specified path. + /// + /// This function returns a const reference to the specified path. + /// + /// \param i The function returns the i-th path. + /// \c i must be between \c 0 and %pathNum()-1. + /// + /// \pre \ref run() or \ref findPaths() must be called before using + /// this function. + const Path& path(int i) const { + return _paths[i]; + } + + /// @} + + }; //class Suurballe + + ///@} + +} //namespace lemon + +#endif //LEMON_SUURBALLE_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/time_measure.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/time_measure.h new file mode 100644 index 00000000000..3f7f0778999 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/time_measure.h @@ -0,0 +1,610 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_TIME_MEASURE_H +#define LEMON_TIME_MEASURE_H + +///\ingroup timecount +///\file +///\brief Tools for measuring cpu usage + +#ifdef WIN32 +#include +#else +#include +#include +#include +#endif + +#include +#include +#include +#include + +namespace lemon { + + /// \addtogroup timecount + /// @{ + + /// A class to store (cpu)time instances. + + /// This class stores five time values. + /// - a real time + /// - a user cpu time + /// - a system cpu time + /// - a user cpu time of children + /// - a system cpu time of children + /// + /// TimeStamp's can be added to or substracted from each other and + /// they can be pushed to a stream. + /// + /// In most cases, perhaps the \ref Timer or the \ref TimeReport + /// class is what you want to use instead. + + class TimeStamp + { + double utime; + double stime; + double cutime; + double cstime; + double rtime; + + public: + ///Display format specifier + + ///\e + /// + enum Format { + /// Reports all measured values + NORMAL = 0, + /// Only real time and an error indicator is displayed + SHORT = 1 + }; + + private: + static Format _format; + + void _reset() { + utime = stime = cutime = cstime = rtime = 0; + } + + public: + + ///Set output format + + ///Set output format. + /// + ///The output format is global for all timestamp instances. + static void format(Format f) { _format = f; } + ///Retrieve the current output format + + ///Retrieve the current output format + /// + ///The output format is global for all timestamp instances. + static Format format() { return _format; } + + + ///Read the current time values of the process + void stamp() + { +#ifndef WIN32 + timeval tv; + gettimeofday(&tv, 0); + rtime=tv.tv_sec+double(tv.tv_usec)/1e6; + + tms ts; + double tck=sysconf(_SC_CLK_TCK); + times(&ts); + utime=ts.tms_utime/tck; + stime=ts.tms_stime/tck; + cutime=ts.tms_cutime/tck; + cstime=ts.tms_cstime/tck; +#else + bits::getWinProcTimes(rtime, utime, stime, cutime, cstime); +#endif + } + + /// Constructor initializing with zero + TimeStamp() + { _reset(); } + ///Constructor initializing with the current time values of the process + TimeStamp(void *) { stamp();} + + ///Set every time value to zero + TimeStamp &reset() {_reset();return *this;} + + ///\e + TimeStamp &operator+=(const TimeStamp &b) + { + utime+=b.utime; + stime+=b.stime; + cutime+=b.cutime; + cstime+=b.cstime; + rtime+=b.rtime; + return *this; + } + ///\e + TimeStamp operator+(const TimeStamp &b) const + { + TimeStamp t(*this); + return t+=b; + } + ///\e + TimeStamp &operator-=(const TimeStamp &b) + { + utime-=b.utime; + stime-=b.stime; + cutime-=b.cutime; + cstime-=b.cstime; + rtime-=b.rtime; + return *this; + } + ///\e + TimeStamp operator-(const TimeStamp &b) const + { + TimeStamp t(*this); + return t-=b; + } + ///\e + TimeStamp &operator*=(double b) + { + utime*=b; + stime*=b; + cutime*=b; + cstime*=b; + rtime*=b; + return *this; + } + ///\e + TimeStamp operator*(double b) const + { + TimeStamp t(*this); + return t*=b; + } + friend TimeStamp operator*(double b,const TimeStamp &t); + ///\e + TimeStamp &operator/=(double b) + { + utime/=b; + stime/=b; + cutime/=b; + cstime/=b; + rtime/=b; + return *this; + } + ///\e + TimeStamp operator/(double b) const + { + TimeStamp t(*this); + return t/=b; + } + ///The time ellapsed since the last call of stamp() + TimeStamp ellapsed() const + { + TimeStamp t(NULL); + return t-*this; + } + + friend std::ostream& operator<<(std::ostream& os,const TimeStamp &t); + + ///Gives back the user time of the process + double userTime() const + { + return utime; + } + ///Gives back the system time of the process + double systemTime() const + { + return stime; + } + ///Gives back the user time of the process' children + + ///\note On WIN32 platform this value is not calculated. + /// + double cUserTime() const + { + return cutime; + } + ///Gives back the user time of the process' children + + ///\note On WIN32 platform this value is not calculated. + /// + double cSystemTime() const + { + return cstime; + } + ///Gives back the real time + double realTime() const {return rtime;} + }; + + inline TimeStamp operator*(double b,const TimeStamp &t) + { + return t*b; + } + + ///Prints the time counters + + ///Prints the time counters in the following form: + /// + /// u: XX.XXs s: XX.XXs cu: XX.XXs cs: XX.XXs real: XX.XXs + /// + /// where the values are the + /// \li \c u: user cpu time, + /// \li \c s: system cpu time, + /// \li \c cu: user cpu time of children, + /// \li \c cs: system cpu time of children, + /// \li \c real: real time. + /// \relates TimeStamp + /// \note On WIN32 platform the cummulative values are not + /// calculated. + inline std::ostream& operator<<(std::ostream& os,const TimeStamp &t) + { + switch(t._format) + { + case TimeStamp::NORMAL: + os << "u: " << t.userTime() << + "s, s: " << t.systemTime() << + "s, cu: " << t.cUserTime() << + "s, cs: " << t.cSystemTime() << + "s, real: " << t.realTime() << "s"; + break; + case TimeStamp::SHORT: + double total = t.userTime()+t.systemTime()+ + t.cUserTime()+t.cSystemTime(); + os << t.realTime() + << "s (err: " << round((t.realTime()-total)/ + t.realTime()*10000)/100 + << "%)"; + break; + } + return os; + } + + ///Class for measuring the cpu time and real time usage of the process + + ///Class for measuring the cpu time and real time usage of the process. + ///It is quite easy-to-use, here is a short example. + ///\code + /// #include + /// #include + /// + /// int main() + /// { + /// + /// ... + /// + /// Timer t; + /// doSomething(); + /// std::cout << t << '\n'; + /// t.restart(); + /// doSomethingElse(); + /// std::cout << t << '\n'; + /// + /// ... + /// + /// } + ///\endcode + /// + ///The \ref Timer can also be \ref stop() "stopped" and + ///\ref start() "started" again, so it is possible to compute collected + ///running times. + /// + ///\warning Depending on the operation system and its actual configuration + ///the time counters have a certain (10ms on a typical Linux system) + ///granularity. + ///Therefore this tool is not appropriate to measure very short times. + ///Also, if you start and stop the timer very frequently, it could lead to + ///distorted results. + /// + ///\note If you want to measure the running time of the execution of a certain + ///function, consider the usage of \ref TimeReport instead. + /// + ///\sa TimeReport + class Timer + { + int _running; //Timer is running iff _running>0; (_running>=0 always holds) + TimeStamp start_time; //This is the relativ start-time if the timer + //is _running, the collected _running time otherwise. + + void _reset() {if(_running) start_time.stamp(); else start_time.reset();} + + public: + ///Constructor. + + ///\param run indicates whether or not the timer starts immediately. + /// + Timer(bool run=true) :_running(run) {_reset();} + + ///\name Control the State of the Timer + ///Basically a Timer can be either running or stopped, + ///but it provides a bit finer control on the execution. + ///The \ref lemon::Timer "Timer" also counts the number of + ///\ref lemon::Timer::start() "start()" executions, and it stops + ///only after the same amount (or more) \ref lemon::Timer::stop() + ///"stop()"s. This can be useful e.g. to compute the running time + ///of recursive functions. + + ///@{ + + ///Reset and stop the time counters + + ///This function resets and stops the time counters + ///\sa restart() + void reset() + { + _running=0; + _reset(); + } + + ///Start the time counters + + ///This function starts the time counters. + /// + ///If the timer is started more than ones, it will remain running + ///until the same amount of \ref stop() is called. + ///\sa stop() + void start() + { + if(_running) _running++; + else { + _running=1; + TimeStamp t; + t.stamp(); + start_time=t-start_time; + } + } + + + ///Stop the time counters + + ///This function stops the time counters. If start() was executed more than + ///once, then the same number of stop() execution is necessary the really + ///stop the timer. + /// + ///\sa halt() + ///\sa start() + ///\sa restart() + ///\sa reset() + + void stop() + { + if(_running && !--_running) { + TimeStamp t; + t.stamp(); + start_time=t-start_time; + } + } + + ///Halt (i.e stop immediately) the time counters + + ///This function stops immediately the time counters, i.e. t.halt() + ///is a faster + ///equivalent of the following. + ///\code + /// while(t.running()) t.stop() + ///\endcode + /// + /// + ///\sa stop() + ///\sa restart() + ///\sa reset() + + void halt() + { + if(_running) { + _running=0; + TimeStamp t; + t.stamp(); + start_time=t-start_time; + } + } + + ///Returns the running state of the timer + + ///This function returns the number of stop() exections that is + ///necessary to really stop the timer. + ///For example, the timer + ///is running if and only if the return value is \c true + ///(i.e. greater than + ///zero). + int running() { return _running; } + + + ///Restart the time counters + + ///This function is a shorthand for + ///a reset() and a start() calls. + /// + void restart() + { + reset(); + start(); + } + + ///@} + + ///\name Query Functions for the Ellapsed Time + + ///@{ + + ///Gives back the ellapsed user time of the process + double userTime() const + { + return operator TimeStamp().userTime(); + } + ///Gives back the ellapsed system time of the process + double systemTime() const + { + return operator TimeStamp().systemTime(); + } + ///Gives back the ellapsed user time of the process' children + + ///\note On WIN32 platform this value is not calculated. + /// + double cUserTime() const + { + return operator TimeStamp().cUserTime(); + } + ///Gives back the ellapsed user time of the process' children + + ///\note On WIN32 platform this value is not calculated. + /// + double cSystemTime() const + { + return operator TimeStamp().cSystemTime(); + } + ///Gives back the ellapsed real time + double realTime() const + { + return operator TimeStamp().realTime(); + } + ///Computes the ellapsed time + + ///This conversion computes the ellapsed time, therefore you can print + ///the ellapsed time like this. + ///\code + /// Timer t; + /// doSomething(); + /// std::cout << t << '\n'; + ///\endcode + operator TimeStamp () const + { + TimeStamp t; + t.stamp(); + return _running?t-start_time:start_time; + } + + + ///@} + }; + + ///Same as Timer but prints a report on destruction. + + ///Same as \ref Timer but prints a report on destruction. + ///This example shows its usage. + ///\code + /// void myAlg(ListGraph &g,int n) + /// { + /// TimeReport tr("Running time of myAlg: "); + /// ... //Here comes the algorithm + /// } + ///\endcode + /// + ///\sa Timer + ///\sa NoTimeReport + class TimeReport : public Timer + { + std::string _title; + std::ostream &_os; + bool _active; + public: + ///Constructor + + ///Constructor. + ///\param title This text will be printed before the ellapsed time. + ///\param os The stream to print the report to. + ///\param run Sets whether the timer should start immediately. + ///\param active Sets whether the report should actually be printed + /// on destruction. + TimeReport(std::string title,std::ostream &os=std::cerr,bool run=true, + bool active=true) + : Timer(run), _title(title), _os(os), _active(active) {} + ///Destructor that prints the ellapsed time + ~TimeReport() + { + if(_active) _os << _title << *this << std::endl; + } + + ///Retrieve the activity status + + ///\e + /// + bool active() const { return _active; } + ///Set the activity status + + /// This function set whether the time report should actually be printed + /// on destruction. + void active(bool a) { _active=a; } + }; + + ///'Do nothing' version of TimeReport + + ///\sa TimeReport + /// + class NoTimeReport + { + public: + ///\e + NoTimeReport(std::string,std::ostream &,bool) {} + ///\e + NoTimeReport(std::string,std::ostream &) {} + ///\e + NoTimeReport(std::string) {} + ///\e Do nothing. + ~NoTimeReport() {} + + operator TimeStamp () const { return TimeStamp(); } + void reset() {} + void start() {} + void stop() {} + void halt() {} + int running() { return 0; } + void restart() {} + double userTime() const { return 0; } + double systemTime() const { return 0; } + double cUserTime() const { return 0; } + double cSystemTime() const { return 0; } + double realTime() const { return 0; } + }; + + ///Tool to measure the running time more exactly. + + ///This function calls \c f several times and returns the average + ///running time. The number of the executions will be choosen in such a way + ///that the full real running time will be roughly between \c min_time + ///and 2*min_time. + ///\param f the function object to be measured. + ///\param min_time the minimum total running time. + ///\retval num if it is not \c NULL, then the actual + /// number of execution of \c f will be written into *num. + ///\retval full_time if it is not \c NULL, then the actual + /// total running time will be written into *full_time. + ///\return The average running time of \c f. + + template + TimeStamp runningTimeTest(F f,double min_time=10,unsigned int *num = NULL, + TimeStamp *full_time=NULL) + { + TimeStamp full; + unsigned int total=0; + Timer t; + for(unsigned int tn=1;tn <= 1U<<31 && full.realTime()<=min_time; tn*=2) { + for(;total may offer additional tuning parameters. + /// + ///\sa Tolerance + ///\sa Tolerance + ///\sa Tolerance + + template + class Tolerance + { + public: + typedef T Value; + + ///\name Comparisons + ///The concept is that these bool functions return \c true only if + ///the related comparisons hold even if some numerical error appeared + ///during the computations. + + ///@{ + + ///Returns \c true if \c a is \e surely strictly less than \c b + static bool less(Value a,Value b) {return a(0) < a;} + ///Returns \c true if \c a is \e surely negative + static bool negative(Value a) {return a < static_cast(0);} + ///Returns \c true if \c a is \e surely non-zero + static bool nonZero(Value a) {return a != static_cast(0);} + + ///@} + + ///Returns the zero value. + static Value zero() {return static_cast(0);} + + // static bool finite(Value a) {} + // static Value big() {} + // static Value negativeBig() {} + }; + + + ///Float specialization of Tolerance. + + ///Float specialization of Tolerance. + ///\sa Tolerance + ///\relates Tolerance + template<> + class Tolerance + { + static float def_epsilon; + float _epsilon; + public: + ///\e + typedef float Value; + + ///Constructor setting the epsilon tolerance to the default value. + Tolerance() : _epsilon(def_epsilon) {} + ///Constructor setting the epsilon tolerance to the given value. + Tolerance(float e) : _epsilon(e) {} + + ///Returns the epsilon value. + Value epsilon() const {return _epsilon;} + ///Sets the epsilon value. + void epsilon(Value e) {_epsilon=e;} + + ///Returns the default epsilon value. + static Value defaultEpsilon() {return def_epsilon;} + ///Sets the default epsilon value. + static void defaultEpsilon(Value e) {def_epsilon=e;} + + ///\name Comparisons + ///See \ref lemon::Tolerance "Tolerance" for more details. + + ///@{ + + ///Returns \c true if \c a is \e surely strictly less than \c b + bool less(Value a,Value b) const {return a+_epsilona; } + ///Returns \c true if \c a is \e surely non-zero + bool nonZero(Value a) const { return positive(a)||negative(a); } + + ///@} + + ///Returns zero + static Value zero() {return 0;} + }; + + ///Double specialization of Tolerance. + + ///Double specialization of Tolerance. + ///\sa Tolerance + ///\relates Tolerance + template<> + class Tolerance + { + static double def_epsilon; + double _epsilon; + public: + ///\e + typedef double Value; + + ///Constructor setting the epsilon tolerance to the default value. + Tolerance() : _epsilon(def_epsilon) {} + ///Constructor setting the epsilon tolerance to the given value. + Tolerance(double e) : _epsilon(e) {} + + ///Returns the epsilon value. + Value epsilon() const {return _epsilon;} + ///Sets the epsilon value. + void epsilon(Value e) {_epsilon=e;} + + ///Returns the default epsilon value. + static Value defaultEpsilon() {return def_epsilon;} + ///Sets the default epsilon value. + static void defaultEpsilon(Value e) {def_epsilon=e;} + + ///\name Comparisons + ///See \ref lemon::Tolerance "Tolerance" for more details. + + ///@{ + + ///Returns \c true if \c a is \e surely strictly less than \c b + bool less(Value a,Value b) const {return a+_epsilona; } + ///Returns \c true if \c a is \e surely non-zero + bool nonZero(Value a) const { return positive(a)||negative(a); } + + ///@} + + ///Returns zero + static Value zero() {return 0;} + }; + + ///Long double specialization of Tolerance. + + ///Long double specialization of Tolerance. + ///\sa Tolerance + ///\relates Tolerance + template<> + class Tolerance + { + static long double def_epsilon; + long double _epsilon; + public: + ///\e + typedef long double Value; + + ///Constructor setting the epsilon tolerance to the default value. + Tolerance() : _epsilon(def_epsilon) {} + ///Constructor setting the epsilon tolerance to the given value. + Tolerance(long double e) : _epsilon(e) {} + + ///Returns the epsilon value. + Value epsilon() const {return _epsilon;} + ///Sets the epsilon value. + void epsilon(Value e) {_epsilon=e;} + + ///Returns the default epsilon value. + static Value defaultEpsilon() {return def_epsilon;} + ///Sets the default epsilon value. + static void defaultEpsilon(Value e) {def_epsilon=e;} + + ///\name Comparisons + ///See \ref lemon::Tolerance "Tolerance" for more details. + + ///@{ + + ///Returns \c true if \c a is \e surely strictly less than \c b + bool less(Value a,Value b) const {return a+_epsilona; } + ///Returns \c true if \c a is \e surely non-zero + bool nonZero(Value a) const { return positive(a)||negative(a); } + + ///@} + + ///Returns zero + static Value zero() {return 0;} + }; + + /// @} + +} //namespace lemon + +#endif //LEMON_TOLERANCE_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/unionfind.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/unionfind.h new file mode 100644 index 00000000000..3d96b372b2d --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/unionfind.h @@ -0,0 +1,1824 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_UNION_FIND_H +#define LEMON_UNION_FIND_H + +//!\ingroup auxdat +//!\file +//!\brief Union-Find data structures. +//! + +#include +#include +#include +#include +#include + +#include + +namespace lemon { + + /// \ingroup auxdat + /// + /// \brief A \e Union-Find data structure implementation + /// + /// The class implements the \e Union-Find data structure. + /// The union operation uses rank heuristic, while + /// the find operation uses path compression. + /// This is a very simple but efficient implementation, providing + /// only four methods: join (union), find, insert and size. + /// For more features, see the \ref UnionFindEnum class. + /// + /// It is primarily used in Kruskal algorithm for finding minimal + /// cost spanning tree in a graph. + /// \sa kruskal() + /// + /// \pre You need to add all the elements by the \ref insert() + /// method. + template + class UnionFind { + public: + + ///\e + typedef IM ItemIntMap; + ///\e + typedef typename ItemIntMap::Key Item; + + private: + // If the items vector stores negative value for an item then + // that item is root item and it has -items[it] component size. + // Else the items[it] contains the index of the parent. + std::vector items; + ItemIntMap& index; + + bool rep(int idx) const { + return items[idx] < 0; + } + + int repIndex(int idx) const { + int k = idx; + while (!rep(k)) { + k = items[k] ; + } + while (idx != k) { + int next = items[idx]; + const_cast(items[idx]) = k; + idx = next; + } + return k; + } + + public: + + /// \brief Constructor + /// + /// Constructor of the UnionFind class. You should give an item to + /// integer map which will be used from the data structure. If you + /// modify directly this map that may cause segmentation fault, + /// invalid data structure, or infinite loop when you use again + /// the union-find. + UnionFind(ItemIntMap& m) : index(m) {} + + /// \brief Returns the index of the element's component. + /// + /// The method returns the index of the element's component. + /// This is an integer between zero and the number of inserted elements. + /// + int find(const Item& a) { + return repIndex(index[a]); + } + + /// \brief Clears the union-find data structure + /// + /// Erase each item from the data structure. + void clear() { + items.clear(); + } + + /// \brief Inserts a new element into the structure. + /// + /// This method inserts a new element into the data structure. + /// + /// The method returns the index of the new component. + int insert(const Item& a) { + int n = items.size(); + items.push_back(-1); + index.set(a,n); + return n; + } + + /// \brief Joining the components of element \e a and element \e b. + /// + /// This is the \e union operation of the Union-Find structure. + /// Joins the component of element \e a and component of + /// element \e b. If \e a and \e b are in the same component then + /// it returns false otherwise it returns true. + bool join(const Item& a, const Item& b) { + int ka = repIndex(index[a]); + int kb = repIndex(index[b]); + + if ( ka == kb ) + return false; + + if (items[ka] < items[kb]) { + items[ka] += items[kb]; + items[kb] = ka; + } else { + items[kb] += items[ka]; + items[ka] = kb; + } + return true; + } + + /// \brief Returns the size of the component of element \e a. + /// + /// Returns the size of the component of element \e a. + int size(const Item& a) { + int k = repIndex(index[a]); + return - items[k]; + } + + }; + + /// \ingroup auxdat + /// + /// \brief A \e Union-Find data structure implementation which + /// is able to enumerate the components. + /// + /// The class implements a \e Union-Find data structure + /// which is able to enumerate the components and the items in + /// a component. If you don't need this feature then perhaps it's + /// better to use the \ref UnionFind class which is more efficient. + /// + /// The union operation uses rank heuristic, while + /// the find operation uses path compression. + /// + /// \pre You need to add all the elements by the \ref insert() + /// method. + /// + template + class UnionFindEnum { + public: + + ///\e + typedef IM ItemIntMap; + ///\e + typedef typename ItemIntMap::Key Item; + + private: + + ItemIntMap& index; + + // If the parent stores negative value for an item then that item + // is root item and it has ~(items[it].parent) component id. Else + // the items[it].parent contains the index of the parent. + // + // The \c next and \c prev provides the double-linked + // cyclic list of one component's items. + struct ItemT { + int parent; + Item item; + + int next, prev; + }; + + std::vector items; + int firstFreeItem; + + struct ClassT { + int size; + int firstItem; + int next, prev; + }; + + std::vector classes; + int firstClass, firstFreeClass; + + int newClass() { + if (firstFreeClass == -1) { + int cdx = classes.size(); + classes.push_back(ClassT()); + return cdx; + } else { + int cdx = firstFreeClass; + firstFreeClass = classes[firstFreeClass].next; + return cdx; + } + } + + int newItem() { + if (firstFreeItem == -1) { + int idx = items.size(); + items.push_back(ItemT()); + return idx; + } else { + int idx = firstFreeItem; + firstFreeItem = items[firstFreeItem].next; + return idx; + } + } + + + bool rep(int idx) const { + return items[idx].parent < 0; + } + + int repIndex(int idx) const { + int k = idx; + while (!rep(k)) { + k = items[k].parent; + } + while (idx != k) { + int next = items[idx].parent; + const_cast(items[idx].parent) = k; + idx = next; + } + return k; + } + + int classIndex(int idx) const { + return ~(items[repIndex(idx)].parent); + } + + void singletonItem(int idx) { + items[idx].next = idx; + items[idx].prev = idx; + } + + void laceItem(int idx, int rdx) { + items[idx].prev = rdx; + items[idx].next = items[rdx].next; + items[items[rdx].next].prev = idx; + items[rdx].next = idx; + } + + void unlaceItem(int idx) { + items[items[idx].prev].next = items[idx].next; + items[items[idx].next].prev = items[idx].prev; + + items[idx].next = firstFreeItem; + firstFreeItem = idx; + } + + void spliceItems(int ak, int bk) { + items[items[ak].prev].next = bk; + items[items[bk].prev].next = ak; + int tmp = items[ak].prev; + items[ak].prev = items[bk].prev; + items[bk].prev = tmp; + + } + + void laceClass(int cls) { + if (firstClass != -1) { + classes[firstClass].prev = cls; + } + classes[cls].next = firstClass; + classes[cls].prev = -1; + firstClass = cls; + } + + void unlaceClass(int cls) { + if (classes[cls].prev != -1) { + classes[classes[cls].prev].next = classes[cls].next; + } else { + firstClass = classes[cls].next; + } + if (classes[cls].next != -1) { + classes[classes[cls].next].prev = classes[cls].prev; + } + + classes[cls].next = firstFreeClass; + firstFreeClass = cls; + } + + public: + + UnionFindEnum(ItemIntMap& _index) + : index(_index), items(), firstFreeItem(-1), + firstClass(-1), firstFreeClass(-1) {} + + /// \brief Inserts the given element into a new component. + /// + /// This method creates a new component consisting only of the + /// given element. + /// + int insert(const Item& item) { + int idx = newItem(); + + index.set(item, idx); + + singletonItem(idx); + items[idx].item = item; + + int cdx = newClass(); + + items[idx].parent = ~cdx; + + laceClass(cdx); + classes[cdx].size = 1; + classes[cdx].firstItem = idx; + + firstClass = cdx; + + return cdx; + } + + /// \brief Inserts the given element into the component of the others. + /// + /// This methods inserts the element \e a into the component of the + /// element \e comp. + void insert(const Item& item, int cls) { + int rdx = classes[cls].firstItem; + int idx = newItem(); + + index.set(item, idx); + + laceItem(idx, rdx); + + items[idx].item = item; + items[idx].parent = rdx; + + ++classes[~(items[rdx].parent)].size; + } + + /// \brief Clears the union-find data structure + /// + /// Erase each item from the data structure. + void clear() { + items.clear(); + firstClass = -1; + firstFreeItem = -1; + } + + /// \brief Finds the component of the given element. + /// + /// The method returns the component id of the given element. + int find(const Item &item) const { + return ~(items[repIndex(index[item])].parent); + } + + /// \brief Joining the component of element \e a and element \e b. + /// + /// This is the \e union operation of the Union-Find structure. + /// Joins the component of element \e a and component of + /// element \e b. If \e a and \e b are in the same component then + /// returns -1 else returns the remaining class. + int join(const Item& a, const Item& b) { + + int ak = repIndex(index[a]); + int bk = repIndex(index[b]); + + if (ak == bk) { + return -1; + } + + int acx = ~(items[ak].parent); + int bcx = ~(items[bk].parent); + + int rcx; + + if (classes[acx].size > classes[bcx].size) { + classes[acx].size += classes[bcx].size; + items[bk].parent = ak; + unlaceClass(bcx); + rcx = acx; + } else { + classes[bcx].size += classes[acx].size; + items[ak].parent = bk; + unlaceClass(acx); + rcx = bcx; + } + spliceItems(ak, bk); + + return rcx; + } + + /// \brief Returns the size of the class. + /// + /// Returns the size of the class. + int size(int cls) const { + return classes[cls].size; + } + + /// \brief Splits up the component. + /// + /// Splitting the component into singleton components (component + /// of size one). + void split(int cls) { + int fdx = classes[cls].firstItem; + int idx = items[fdx].next; + while (idx != fdx) { + int next = items[idx].next; + + singletonItem(idx); + + int cdx = newClass(); + items[idx].parent = ~cdx; + + laceClass(cdx); + classes[cdx].size = 1; + classes[cdx].firstItem = idx; + + idx = next; + } + + items[idx].prev = idx; + items[idx].next = idx; + + classes[~(items[idx].parent)].size = 1; + + } + + /// \brief Removes the given element from the structure. + /// + /// Removes the element from its component and if the component becomes + /// empty then removes that component from the component list. + /// + /// \warning It is an error to remove an element which is not in + /// the structure. + /// \warning This running time of this operation is proportional to the + /// number of the items in this class. + void erase(const Item& item) { + int idx = index[item]; + int fdx = items[idx].next; + + int cdx = classIndex(idx); + if (idx == fdx) { + unlaceClass(cdx); + items[idx].next = firstFreeItem; + firstFreeItem = idx; + return; + } else { + classes[cdx].firstItem = fdx; + --classes[cdx].size; + items[fdx].parent = ~cdx; + + unlaceItem(idx); + idx = items[fdx].next; + while (idx != fdx) { + items[idx].parent = fdx; + idx = items[idx].next; + } + + } + + } + + /// \brief Gives back a representant item of the component. + /// + /// Gives back a representant item of the component. + Item item(int cls) const { + return items[classes[cls].firstItem].item; + } + + /// \brief Removes the component of the given element from the structure. + /// + /// Removes the component of the given element from the structure. + /// + /// \warning It is an error to give an element which is not in the + /// structure. + void eraseClass(int cls) { + int fdx = classes[cls].firstItem; + unlaceClass(cls); + items[items[fdx].prev].next = firstFreeItem; + firstFreeItem = fdx; + } + + /// \brief LEMON style iterator for the representant items. + /// + /// ClassIt is a lemon style iterator for the components. It iterates + /// on the ids of the classes. + class ClassIt { + public: + /// \brief Constructor of the iterator + /// + /// Constructor of the iterator + ClassIt(const UnionFindEnum& ufe) : unionFind(&ufe) { + cdx = unionFind->firstClass; + } + + /// \brief Constructor to get invalid iterator + /// + /// Constructor to get invalid iterator + ClassIt(Invalid) : unionFind(0), cdx(-1) {} + + /// \brief Increment operator + /// + /// It steps to the next representant item. + ClassIt& operator++() { + cdx = unionFind->classes[cdx].next; + return *this; + } + + /// \brief Conversion operator + /// + /// It converts the iterator to the current representant item. + operator int() const { + return cdx; + } + + /// \brief Equality operator + /// + /// Equality operator + bool operator==(const ClassIt& i) { + return i.cdx == cdx; + } + + /// \brief Inequality operator + /// + /// Inequality operator + bool operator!=(const ClassIt& i) { + return i.cdx != cdx; + } + + private: + const UnionFindEnum* unionFind; + int cdx; + }; + + /// \brief LEMON style iterator for the items of a component. + /// + /// ClassIt is a lemon style iterator for the components. It iterates + /// on the items of a class. By example if you want to iterate on + /// each items of each classes then you may write the next code. + ///\code + /// for (ClassIt cit(ufe); cit != INVALID; ++cit) { + /// std::cout << "Class: "; + /// for (ItemIt iit(ufe, cit); iit != INVALID; ++iit) { + /// std::cout << toString(iit) << ' ' << std::endl; + /// } + /// std::cout << std::endl; + /// } + ///\endcode + class ItemIt { + public: + /// \brief Constructor of the iterator + /// + /// Constructor of the iterator. The iterator iterates + /// on the class of the \c item. + ItemIt(const UnionFindEnum& ufe, int cls) : unionFind(&ufe) { + fdx = idx = unionFind->classes[cls].firstItem; + } + + /// \brief Constructor to get invalid iterator + /// + /// Constructor to get invalid iterator + ItemIt(Invalid) : unionFind(0), idx(-1) {} + + /// \brief Increment operator + /// + /// It steps to the next item in the class. + ItemIt& operator++() { + idx = unionFind->items[idx].next; + if (idx == fdx) idx = -1; + return *this; + } + + /// \brief Conversion operator + /// + /// It converts the iterator to the current item. + operator const Item&() const { + return unionFind->items[idx].item; + } + + /// \brief Equality operator + /// + /// Equality operator + bool operator==(const ItemIt& i) { + return i.idx == idx; + } + + /// \brief Inequality operator + /// + /// Inequality operator + bool operator!=(const ItemIt& i) { + return i.idx != idx; + } + + private: + const UnionFindEnum* unionFind; + int idx, fdx; + }; + + }; + + /// \ingroup auxdat + /// + /// \brief A \e Extend-Find data structure implementation which + /// is able to enumerate the components. + /// + /// The class implements an \e Extend-Find data structure which is + /// able to enumerate the components and the items in a + /// component. The data structure is a simplification of the + /// Union-Find structure, and it does not allow to merge two components. + /// + /// \pre You need to add all the elements by the \ref insert() + /// method. + template + class ExtendFindEnum { + public: + + ///\e + typedef IM ItemIntMap; + ///\e + typedef typename ItemIntMap::Key Item; + + private: + + ItemIntMap& index; + + struct ItemT { + int cls; + Item item; + int next, prev; + }; + + std::vector items; + int firstFreeItem; + + struct ClassT { + int firstItem; + int next, prev; + }; + + std::vector classes; + + int firstClass, firstFreeClass; + + int newClass() { + if (firstFreeClass != -1) { + int cdx = firstFreeClass; + firstFreeClass = classes[cdx].next; + return cdx; + } else { + classes.push_back(ClassT()); + return classes.size() - 1; + } + } + + int newItem() { + if (firstFreeItem != -1) { + int idx = firstFreeItem; + firstFreeItem = items[idx].next; + return idx; + } else { + items.push_back(ItemT()); + return items.size() - 1; + } + } + + public: + + /// \brief Constructor + ExtendFindEnum(ItemIntMap& _index) + : index(_index), items(), firstFreeItem(-1), + classes(), firstClass(-1), firstFreeClass(-1) {} + + /// \brief Inserts the given element into a new component. + /// + /// This method creates a new component consisting only of the + /// given element. + int insert(const Item& item) { + int cdx = newClass(); + classes[cdx].prev = -1; + classes[cdx].next = firstClass; + if (firstClass != -1) { + classes[firstClass].prev = cdx; + } + firstClass = cdx; + + int idx = newItem(); + items[idx].item = item; + items[idx].cls = cdx; + items[idx].prev = idx; + items[idx].next = idx; + + classes[cdx].firstItem = idx; + + index.set(item, idx); + + return cdx; + } + + /// \brief Inserts the given element into the given component. + /// + /// This methods inserts the element \e item a into the \e cls class. + void insert(const Item& item, int cls) { + int idx = newItem(); + int rdx = classes[cls].firstItem; + items[idx].item = item; + items[idx].cls = cls; + + items[idx].prev = rdx; + items[idx].next = items[rdx].next; + items[items[rdx].next].prev = idx; + items[rdx].next = idx; + + index.set(item, idx); + } + + /// \brief Clears the union-find data structure + /// + /// Erase each item from the data structure. + void clear() { + items.clear(); + classes.clear(); + firstClass = firstFreeClass = firstFreeItem = -1; + } + + /// \brief Gives back the class of the \e item. + /// + /// Gives back the class of the \e item. + int find(const Item &item) const { + return items[index[item]].cls; + } + + /// \brief Gives back a representant item of the component. + /// + /// Gives back a representant item of the component. + Item item(int cls) const { + return items[classes[cls].firstItem].item; + } + + /// \brief Removes the given element from the structure. + /// + /// Removes the element from its component and if the component becomes + /// empty then removes that component from the component list. + /// + /// \warning It is an error to remove an element which is not in + /// the structure. + void erase(const Item &item) { + int idx = index[item]; + int cdx = items[idx].cls; + + if (idx == items[idx].next) { + if (classes[cdx].prev != -1) { + classes[classes[cdx].prev].next = classes[cdx].next; + } else { + firstClass = classes[cdx].next; + } + if (classes[cdx].next != -1) { + classes[classes[cdx].next].prev = classes[cdx].prev; + } + classes[cdx].next = firstFreeClass; + firstFreeClass = cdx; + } else { + classes[cdx].firstItem = items[idx].next; + items[items[idx].next].prev = items[idx].prev; + items[items[idx].prev].next = items[idx].next; + } + items[idx].next = firstFreeItem; + firstFreeItem = idx; + + } + + + /// \brief Removes the component of the given element from the structure. + /// + /// Removes the component of the given element from the structure. + /// + /// \warning It is an error to give an element which is not in the + /// structure. + void eraseClass(int cdx) { + int idx = classes[cdx].firstItem; + items[items[idx].prev].next = firstFreeItem; + firstFreeItem = idx; + + if (classes[cdx].prev != -1) { + classes[classes[cdx].prev].next = classes[cdx].next; + } else { + firstClass = classes[cdx].next; + } + if (classes[cdx].next != -1) { + classes[classes[cdx].next].prev = classes[cdx].prev; + } + classes[cdx].next = firstFreeClass; + firstFreeClass = cdx; + } + + /// \brief LEMON style iterator for the classes. + /// + /// ClassIt is a lemon style iterator for the components. It iterates + /// on the ids of classes. + class ClassIt { + public: + /// \brief Constructor of the iterator + /// + /// Constructor of the iterator + ClassIt(const ExtendFindEnum& ufe) : extendFind(&ufe) { + cdx = extendFind->firstClass; + } + + /// \brief Constructor to get invalid iterator + /// + /// Constructor to get invalid iterator + ClassIt(Invalid) : extendFind(0), cdx(-1) {} + + /// \brief Increment operator + /// + /// It steps to the next representant item. + ClassIt& operator++() { + cdx = extendFind->classes[cdx].next; + return *this; + } + + /// \brief Conversion operator + /// + /// It converts the iterator to the current class id. + operator int() const { + return cdx; + } + + /// \brief Equality operator + /// + /// Equality operator + bool operator==(const ClassIt& i) { + return i.cdx == cdx; + } + + /// \brief Inequality operator + /// + /// Inequality operator + bool operator!=(const ClassIt& i) { + return i.cdx != cdx; + } + + private: + const ExtendFindEnum* extendFind; + int cdx; + }; + + /// \brief LEMON style iterator for the items of a component. + /// + /// ClassIt is a lemon style iterator for the components. It iterates + /// on the items of a class. By example if you want to iterate on + /// each items of each classes then you may write the next code. + ///\code + /// for (ClassIt cit(ufe); cit != INVALID; ++cit) { + /// std::cout << "Class: "; + /// for (ItemIt iit(ufe, cit); iit != INVALID; ++iit) { + /// std::cout << toString(iit) << ' ' << std::endl; + /// } + /// std::cout << std::endl; + /// } + ///\endcode + class ItemIt { + public: + /// \brief Constructor of the iterator + /// + /// Constructor of the iterator. The iterator iterates + /// on the class of the \c item. + ItemIt(const ExtendFindEnum& ufe, int cls) : extendFind(&ufe) { + fdx = idx = extendFind->classes[cls].firstItem; + } + + /// \brief Constructor to get invalid iterator + /// + /// Constructor to get invalid iterator + ItemIt(Invalid) : extendFind(0), idx(-1) {} + + /// \brief Increment operator + /// + /// It steps to the next item in the class. + ItemIt& operator++() { + idx = extendFind->items[idx].next; + if (fdx == idx) idx = -1; + return *this; + } + + /// \brief Conversion operator + /// + /// It converts the iterator to the current item. + operator const Item&() const { + return extendFind->items[idx].item; + } + + /// \brief Equality operator + /// + /// Equality operator + bool operator==(const ItemIt& i) { + return i.idx == idx; + } + + /// \brief Inequality operator + /// + /// Inequality operator + bool operator!=(const ItemIt& i) { + return i.idx != idx; + } + + private: + const ExtendFindEnum* extendFind; + int idx, fdx; + }; + + }; + + /// \ingroup auxdat + /// + /// \brief A \e Union-Find data structure implementation which + /// is able to store a priority for each item and retrieve the minimum of + /// each class. + /// + /// A \e Union-Find data structure implementation which is able to + /// store a priority for each item and retrieve the minimum of each + /// class. In addition, it supports the joining and splitting the + /// components. If you don't need this feature then you makes + /// better to use the \ref UnionFind class which is more efficient. + /// + /// The union-find data strcuture based on a (2, 16)-tree with a + /// tournament minimum selection on the internal nodes. The insert + /// operation takes O(1), the find, set, decrease and increase takes + /// O(log(n)), where n is the number of nodes in the current + /// component. The complexity of join and split is O(log(n)*k), + /// where n is the sum of the number of the nodes and k is the + /// number of joined components or the number of the components + /// after the split. + /// + /// \pre You need to add all the elements by the \ref insert() + /// method. + template > + class HeapUnionFind { + public: + + ///\e + typedef V Value; + ///\e + typedef typename IM::Key Item; + ///\e + typedef IM ItemIntMap; + ///\e + typedef Comp Compare; + + private: + + static const int cmax = 16; + + ItemIntMap& index; + + struct ClassNode { + int parent; + int depth; + + int left, right; + int next, prev; + }; + + int first_class; + int first_free_class; + std::vector classes; + + int newClass() { + if (first_free_class < 0) { + int id = classes.size(); + classes.push_back(ClassNode()); + return id; + } else { + int id = first_free_class; + first_free_class = classes[id].next; + return id; + } + } + + void deleteClass(int id) { + classes[id].next = first_free_class; + first_free_class = id; + } + + struct ItemNode { + int parent; + Item item; + Value prio; + int next, prev; + int left, right; + int size; + }; + + int first_free_node; + std::vector nodes; + + int newNode() { + if (first_free_node < 0) { + int id = nodes.size(); + nodes.push_back(ItemNode()); + return id; + } else { + int id = first_free_node; + first_free_node = nodes[id].next; + return id; + } + } + + void deleteNode(int id) { + nodes[id].next = first_free_node; + first_free_node = id; + } + + Comp comp; + + int findClass(int id) const { + int kd = id; + while (kd >= 0) { + kd = nodes[kd].parent; + } + return ~kd; + } + + int leftNode(int id) const { + int kd = ~(classes[id].parent); + for (int i = 0; i < classes[id].depth; ++i) { + kd = nodes[kd].left; + } + return kd; + } + + int nextNode(int id) const { + int depth = 0; + while (id >= 0 && nodes[id].next == -1) { + id = nodes[id].parent; + ++depth; + } + if (id < 0) { + return -1; + } + id = nodes[id].next; + while (depth--) { + id = nodes[id].left; + } + return id; + } + + + void setPrio(int id) { + int jd = nodes[id].left; + nodes[id].prio = nodes[jd].prio; + nodes[id].item = nodes[jd].item; + jd = nodes[jd].next; + while (jd != -1) { + if (comp(nodes[jd].prio, nodes[id].prio)) { + nodes[id].prio = nodes[jd].prio; + nodes[id].item = nodes[jd].item; + } + jd = nodes[jd].next; + } + } + + void push(int id, int jd) { + nodes[id].size = 1; + nodes[id].left = nodes[id].right = jd; + nodes[jd].next = nodes[jd].prev = -1; + nodes[jd].parent = id; + } + + void pushAfter(int id, int jd) { + int kd = nodes[id].parent; + if (nodes[id].next != -1) { + nodes[nodes[id].next].prev = jd; + if (kd >= 0) { + nodes[kd].size += 1; + } + } else { + if (kd >= 0) { + nodes[kd].right = jd; + nodes[kd].size += 1; + } + } + nodes[jd].next = nodes[id].next; + nodes[jd].prev = id; + nodes[id].next = jd; + nodes[jd].parent = kd; + } + + void pushRight(int id, int jd) { + nodes[id].size += 1; + nodes[jd].prev = nodes[id].right; + nodes[jd].next = -1; + nodes[nodes[id].right].next = jd; + nodes[id].right = jd; + nodes[jd].parent = id; + } + + void popRight(int id) { + nodes[id].size -= 1; + int jd = nodes[id].right; + nodes[nodes[jd].prev].next = -1; + nodes[id].right = nodes[jd].prev; + } + + void splice(int id, int jd) { + nodes[id].size += nodes[jd].size; + nodes[nodes[id].right].next = nodes[jd].left; + nodes[nodes[jd].left].prev = nodes[id].right; + int kd = nodes[jd].left; + while (kd != -1) { + nodes[kd].parent = id; + kd = nodes[kd].next; + } + nodes[id].right = nodes[jd].right; + } + + void split(int id, int jd) { + int kd = nodes[id].parent; + nodes[kd].right = nodes[id].prev; + nodes[nodes[id].prev].next = -1; + + nodes[jd].left = id; + nodes[id].prev = -1; + int num = 0; + while (id != -1) { + nodes[id].parent = jd; + nodes[jd].right = id; + id = nodes[id].next; + ++num; + } + nodes[kd].size -= num; + nodes[jd].size = num; + } + + void pushLeft(int id, int jd) { + nodes[id].size += 1; + nodes[jd].next = nodes[id].left; + nodes[jd].prev = -1; + nodes[nodes[id].left].prev = jd; + nodes[id].left = jd; + nodes[jd].parent = id; + } + + void popLeft(int id) { + nodes[id].size -= 1; + int jd = nodes[id].left; + nodes[nodes[jd].next].prev = -1; + nodes[id].left = nodes[jd].next; + } + + void repairLeft(int id) { + int jd = ~(classes[id].parent); + while (nodes[jd].left != -1) { + int kd = nodes[jd].left; + if (nodes[jd].size == 1) { + if (nodes[jd].parent < 0) { + classes[id].parent = ~kd; + classes[id].depth -= 1; + nodes[kd].parent = ~id; + deleteNode(jd); + jd = kd; + } else { + int pd = nodes[jd].parent; + if (nodes[nodes[jd].next].size < cmax) { + pushLeft(nodes[jd].next, nodes[jd].left); + if (less(jd, nodes[jd].next) || + nodes[jd].item == nodes[pd].item) { + nodes[nodes[jd].next].prio = nodes[jd].prio; + nodes[nodes[jd].next].item = nodes[jd].item; + } + popLeft(pd); + deleteNode(jd); + jd = pd; + } else { + int ld = nodes[nodes[jd].next].left; + popLeft(nodes[jd].next); + pushRight(jd, ld); + if (less(ld, nodes[jd].left) || + nodes[ld].item == nodes[pd].item) { + nodes[jd].item = nodes[ld].item; + nodes[jd].prio = nodes[ld].prio; + } + if (nodes[nodes[jd].next].item == nodes[ld].item) { + setPrio(nodes[jd].next); + } + jd = nodes[jd].left; + } + } + } else { + jd = nodes[jd].left; + } + } + } + + void repairRight(int id) { + int jd = ~(classes[id].parent); + while (nodes[jd].right != -1) { + int kd = nodes[jd].right; + if (nodes[jd].size == 1) { + if (nodes[jd].parent < 0) { + classes[id].parent = ~kd; + classes[id].depth -= 1; + nodes[kd].parent = ~id; + deleteNode(jd); + jd = kd; + } else { + int pd = nodes[jd].parent; + if (nodes[nodes[jd].prev].size < cmax) { + pushRight(nodes[jd].prev, nodes[jd].right); + if (less(jd, nodes[jd].prev) || + nodes[jd].item == nodes[pd].item) { + nodes[nodes[jd].prev].prio = nodes[jd].prio; + nodes[nodes[jd].prev].item = nodes[jd].item; + } + popRight(pd); + deleteNode(jd); + jd = pd; + } else { + int ld = nodes[nodes[jd].prev].right; + popRight(nodes[jd].prev); + pushLeft(jd, ld); + if (less(ld, nodes[jd].right) || + nodes[ld].item == nodes[pd].item) { + nodes[jd].item = nodes[ld].item; + nodes[jd].prio = nodes[ld].prio; + } + if (nodes[nodes[jd].prev].item == nodes[ld].item) { + setPrio(nodes[jd].prev); + } + jd = nodes[jd].right; + } + } + } else { + jd = nodes[jd].right; + } + } + } + + + bool less(int id, int jd) const { + return comp(nodes[id].prio, nodes[jd].prio); + } + + public: + + /// \brief Returns true when the given class is alive. + /// + /// Returns true when the given class is alive, ie. the class is + /// not nested into other class. + bool alive(int cls) const { + return classes[cls].parent < 0; + } + + /// \brief Returns true when the given class is trivial. + /// + /// Returns true when the given class is trivial, ie. the class + /// contains just one item directly. + bool trivial(int cls) const { + return classes[cls].left == -1; + } + + /// \brief Constructs the union-find. + /// + /// Constructs the union-find. + /// \brief _index The index map of the union-find. The data + /// structure uses internally for store references. + HeapUnionFind(ItemIntMap& _index) + : index(_index), first_class(-1), + first_free_class(-1), first_free_node(-1) {} + + /// \brief Clears the union-find data structure + /// + /// Erase each item from the data structure. + void clear() { + nodes.clear(); + classes.clear(); + first_free_node = first_free_class = first_class = -1; + } + + /// \brief Insert a new node into a new component. + /// + /// Insert a new node into a new component. + /// \param item The item of the new node. + /// \param prio The priority of the new node. + /// \return The class id of the one-item-heap. + int insert(const Item& item, const Value& prio) { + int id = newNode(); + nodes[id].item = item; + nodes[id].prio = prio; + nodes[id].size = 0; + + nodes[id].prev = -1; + nodes[id].next = -1; + + nodes[id].left = -1; + nodes[id].right = -1; + + nodes[id].item = item; + index[item] = id; + + int class_id = newClass(); + classes[class_id].parent = ~id; + classes[class_id].depth = 0; + + classes[class_id].left = -1; + classes[class_id].right = -1; + + if (first_class != -1) { + classes[first_class].prev = class_id; + } + classes[class_id].next = first_class; + classes[class_id].prev = -1; + first_class = class_id; + + nodes[id].parent = ~class_id; + + return class_id; + } + + /// \brief The class of the item. + /// + /// \return The alive class id of the item, which is not nested into + /// other classes. + /// + /// The time complexity is O(log(n)). + int find(const Item& item) const { + return findClass(index[item]); + } + + /// \brief Joins the classes. + /// + /// The current function joins the given classes. The parameter is + /// an STL range which should be contains valid class ids. The + /// time complexity is O(log(n)*k) where n is the overall number + /// of the joined nodes and k is the number of classes. + /// \return The class of the joined classes. + /// \pre The range should contain at least two class ids. + template + int join(Iterator begin, Iterator end) { + std::vector cs; + for (Iterator it = begin; it != end; ++it) { + cs.push_back(*it); + } + + int class_id = newClass(); + { // creation union-find + + if (first_class != -1) { + classes[first_class].prev = class_id; + } + classes[class_id].next = first_class; + classes[class_id].prev = -1; + first_class = class_id; + + classes[class_id].depth = classes[cs[0]].depth; + classes[class_id].parent = classes[cs[0]].parent; + nodes[~(classes[class_id].parent)].parent = ~class_id; + + int l = cs[0]; + + classes[class_id].left = l; + classes[class_id].right = l; + + if (classes[l].next != -1) { + classes[classes[l].next].prev = classes[l].prev; + } + classes[classes[l].prev].next = classes[l].next; + + classes[l].prev = -1; + classes[l].next = -1; + + classes[l].depth = leftNode(l); + classes[l].parent = class_id; + + } + + { // merging of heap + int l = class_id; + for (int ci = 1; ci < int(cs.size()); ++ci) { + int r = cs[ci]; + int rln = leftNode(r); + if (classes[l].depth > classes[r].depth) { + int id = ~(classes[l].parent); + for (int i = classes[r].depth + 1; i < classes[l].depth; ++i) { + id = nodes[id].right; + } + while (id >= 0 && nodes[id].size == cmax) { + int new_id = newNode(); + int right_id = nodes[id].right; + + popRight(id); + if (nodes[id].item == nodes[right_id].item) { + setPrio(id); + } + push(new_id, right_id); + pushRight(new_id, ~(classes[r].parent)); + + if (less(~classes[r].parent, right_id)) { + nodes[new_id].item = nodes[~classes[r].parent].item; + nodes[new_id].prio = nodes[~classes[r].parent].prio; + } else { + nodes[new_id].item = nodes[right_id].item; + nodes[new_id].prio = nodes[right_id].prio; + } + + id = nodes[id].parent; + classes[r].parent = ~new_id; + } + if (id < 0) { + int new_parent = newNode(); + nodes[new_parent].next = -1; + nodes[new_parent].prev = -1; + nodes[new_parent].parent = ~l; + + push(new_parent, ~(classes[l].parent)); + pushRight(new_parent, ~(classes[r].parent)); + setPrio(new_parent); + + classes[l].parent = ~new_parent; + classes[l].depth += 1; + } else { + pushRight(id, ~(classes[r].parent)); + while (id >= 0 && less(~(classes[r].parent), id)) { + nodes[id].prio = nodes[~(classes[r].parent)].prio; + nodes[id].item = nodes[~(classes[r].parent)].item; + id = nodes[id].parent; + } + } + } else if (classes[r].depth > classes[l].depth) { + int id = ~(classes[r].parent); + for (int i = classes[l].depth + 1; i < classes[r].depth; ++i) { + id = nodes[id].left; + } + while (id >= 0 && nodes[id].size == cmax) { + int new_id = newNode(); + int left_id = nodes[id].left; + + popLeft(id); + if (nodes[id].prio == nodes[left_id].prio) { + setPrio(id); + } + push(new_id, left_id); + pushLeft(new_id, ~(classes[l].parent)); + + if (less(~classes[l].parent, left_id)) { + nodes[new_id].item = nodes[~classes[l].parent].item; + nodes[new_id].prio = nodes[~classes[l].parent].prio; + } else { + nodes[new_id].item = nodes[left_id].item; + nodes[new_id].prio = nodes[left_id].prio; + } + + id = nodes[id].parent; + classes[l].parent = ~new_id; + + } + if (id < 0) { + int new_parent = newNode(); + nodes[new_parent].next = -1; + nodes[new_parent].prev = -1; + nodes[new_parent].parent = ~l; + + push(new_parent, ~(classes[r].parent)); + pushLeft(new_parent, ~(classes[l].parent)); + setPrio(new_parent); + + classes[r].parent = ~new_parent; + classes[r].depth += 1; + } else { + pushLeft(id, ~(classes[l].parent)); + while (id >= 0 && less(~(classes[l].parent), id)) { + nodes[id].prio = nodes[~(classes[l].parent)].prio; + nodes[id].item = nodes[~(classes[l].parent)].item; + id = nodes[id].parent; + } + } + nodes[~(classes[r].parent)].parent = ~l; + classes[l].parent = classes[r].parent; + classes[l].depth = classes[r].depth; + } else { + if (classes[l].depth != 0 && + nodes[~(classes[l].parent)].size + + nodes[~(classes[r].parent)].size <= cmax) { + splice(~(classes[l].parent), ~(classes[r].parent)); + deleteNode(~(classes[r].parent)); + if (less(~(classes[r].parent), ~(classes[l].parent))) { + nodes[~(classes[l].parent)].prio = + nodes[~(classes[r].parent)].prio; + nodes[~(classes[l].parent)].item = + nodes[~(classes[r].parent)].item; + } + } else { + int new_parent = newNode(); + nodes[new_parent].next = nodes[new_parent].prev = -1; + push(new_parent, ~(classes[l].parent)); + pushRight(new_parent, ~(classes[r].parent)); + setPrio(new_parent); + + classes[l].parent = ~new_parent; + classes[l].depth += 1; + nodes[new_parent].parent = ~l; + } + } + if (classes[r].next != -1) { + classes[classes[r].next].prev = classes[r].prev; + } + classes[classes[r].prev].next = classes[r].next; + + classes[r].prev = classes[l].right; + classes[classes[l].right].next = r; + classes[l].right = r; + classes[r].parent = l; + + classes[r].next = -1; + classes[r].depth = rln; + } + } + return class_id; + } + + /// \brief Split the class to subclasses. + /// + /// The current function splits the given class. The join, which + /// made the current class, stored a reference to the + /// subclasses. The \c splitClass() member restores the classes + /// and creates the heaps. The parameter is an STL output iterator + /// which will be filled with the subclass ids. The time + /// complexity is O(log(n)*k) where n is the overall number of + /// nodes in the splitted classes and k is the number of the + /// classes. + template + void split(int cls, Iterator out) { + std::vector cs; + { // splitting union-find + int id = cls; + int l = classes[id].left; + + classes[l].parent = classes[id].parent; + classes[l].depth = classes[id].depth; + + nodes[~(classes[l].parent)].parent = ~l; + + *out++ = l; + + while (l != -1) { + cs.push_back(l); + l = classes[l].next; + } + + classes[classes[id].right].next = first_class; + classes[first_class].prev = classes[id].right; + first_class = classes[id].left; + + if (classes[id].next != -1) { + classes[classes[id].next].prev = classes[id].prev; + } + classes[classes[id].prev].next = classes[id].next; + + deleteClass(id); + } + + { + for (int i = 1; i < int(cs.size()); ++i) { + int l = classes[cs[i]].depth; + while (nodes[nodes[l].parent].left == l) { + l = nodes[l].parent; + } + int r = l; + while (nodes[l].parent >= 0) { + l = nodes[l].parent; + int new_node = newNode(); + + nodes[new_node].prev = -1; + nodes[new_node].next = -1; + + split(r, new_node); + pushAfter(l, new_node); + setPrio(l); + setPrio(new_node); + r = new_node; + } + classes[cs[i]].parent = ~r; + classes[cs[i]].depth = classes[~(nodes[l].parent)].depth; + nodes[r].parent = ~cs[i]; + + nodes[l].next = -1; + nodes[r].prev = -1; + + repairRight(~(nodes[l].parent)); + repairLeft(cs[i]); + + *out++ = cs[i]; + } + } + } + + /// \brief Gives back the priority of the current item. + /// + /// Gives back the priority of the current item. + const Value& operator[](const Item& item) const { + return nodes[index[item]].prio; + } + + /// \brief Sets the priority of the current item. + /// + /// Sets the priority of the current item. + void set(const Item& item, const Value& prio) { + if (comp(prio, nodes[index[item]].prio)) { + decrease(item, prio); + } else if (!comp(prio, nodes[index[item]].prio)) { + increase(item, prio); + } + } + + /// \brief Increase the priority of the current item. + /// + /// Increase the priority of the current item. + void increase(const Item& item, const Value& prio) { + int id = index[item]; + int kd = nodes[id].parent; + nodes[id].prio = prio; + while (kd >= 0 && nodes[kd].item == item) { + setPrio(kd); + kd = nodes[kd].parent; + } + } + + /// \brief Increase the priority of the current item. + /// + /// Increase the priority of the current item. + void decrease(const Item& item, const Value& prio) { + int id = index[item]; + int kd = nodes[id].parent; + nodes[id].prio = prio; + while (kd >= 0 && less(id, kd)) { + nodes[kd].prio = prio; + nodes[kd].item = item; + kd = nodes[kd].parent; + } + } + + /// \brief Gives back the minimum priority of the class. + /// + /// Gives back the minimum priority of the class. + const Value& classPrio(int cls) const { + return nodes[~(classes[cls].parent)].prio; + } + + /// \brief Gives back the minimum priority item of the class. + /// + /// \return Gives back the minimum priority item of the class. + const Item& classTop(int cls) const { + return nodes[~(classes[cls].parent)].item; + } + + /// \brief Gives back a representant item of the class. + /// + /// Gives back a representant item of the class. + /// The representant is indpendent from the priorities of the + /// items. + const Item& classRep(int id) const { + int parent = classes[id].parent; + return nodes[parent >= 0 ? classes[id].depth : leftNode(id)].item; + } + + /// \brief LEMON style iterator for the items of a class. + /// + /// ClassIt is a lemon style iterator for the components. It iterates + /// on the items of a class. By example if you want to iterate on + /// each items of each classes then you may write the next code. + ///\code + /// for (ClassIt cit(huf); cit != INVALID; ++cit) { + /// std::cout << "Class: "; + /// for (ItemIt iit(huf, cit); iit != INVALID; ++iit) { + /// std::cout << toString(iit) << ' ' << std::endl; + /// } + /// std::cout << std::endl; + /// } + ///\endcode + class ItemIt { + private: + + const HeapUnionFind* _huf; + int _id, _lid; + + public: + + /// \brief Default constructor + /// + /// Default constructor + ItemIt() {} + + ItemIt(const HeapUnionFind& huf, int cls) : _huf(&huf) { + int id = cls; + int parent = _huf->classes[id].parent; + if (parent >= 0) { + _id = _huf->classes[id].depth; + if (_huf->classes[id].next != -1) { + _lid = _huf->classes[_huf->classes[id].next].depth; + } else { + _lid = -1; + } + } else { + _id = _huf->leftNode(id); + _lid = -1; + } + } + + /// \brief Increment operator + /// + /// It steps to the next item in the class. + ItemIt& operator++() { + _id = _huf->nextNode(_id); + return *this; + } + + /// \brief Conversion operator + /// + /// It converts the iterator to the current item. + operator const Item&() const { + return _huf->nodes[_id].item; + } + + /// \brief Equality operator + /// + /// Equality operator + bool operator==(const ItemIt& i) { + return i._id == _id; + } + + /// \brief Inequality operator + /// + /// Inequality operator + bool operator!=(const ItemIt& i) { + return i._id != _id; + } + + /// \brief Equality operator + /// + /// Equality operator + bool operator==(Invalid) { + return _id == _lid; + } + + /// \brief Inequality operator + /// + /// Inequality operator + bool operator!=(Invalid) { + return _id != _lid; + } + + }; + + /// \brief Class iterator + /// + /// The iterator stores + class ClassIt { + private: + + const HeapUnionFind* _huf; + int _id; + + public: + + ClassIt(const HeapUnionFind& huf) + : _huf(&huf), _id(huf.first_class) {} + + ClassIt(const HeapUnionFind& huf, int cls) + : _huf(&huf), _id(huf.classes[cls].left) {} + + ClassIt(Invalid) : _huf(0), _id(-1) {} + + const ClassIt& operator++() { + _id = _huf->classes[_id].next; + return *this; + } + + /// \brief Equality operator + /// + /// Equality operator + bool operator==(const ClassIt& i) { + return i._id == _id; + } + + /// \brief Inequality operator + /// + /// Inequality operator + bool operator!=(const ClassIt& i) { + return i._id != _id; + } + + operator int() const { + return _id; + } + + }; + + }; + + //! @} + +} //namespace lemon + +#endif //LEMON_UNION_FIND_H diff --git a/extern/quadriflow/3rd/lemon-1.3.1/scripts/unify-sources.sh b/extern/quadriflow/3rd/lemon-1.3.1/scripts/unify-sources.sh new file mode 100755 index 00000000000..6aae63ab641 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/scripts/unify-sources.sh @@ -0,0 +1,390 @@ +#!/bin/bash +# +# 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. + +YEAR=`date +%Y` +HGROOT=`hg root` + +function hg_year() { + if [ -n "$(hg st $1)" ]; then + echo $YEAR + else + hg log -l 1 --template='{date|isodate}\n' $1 | + cut -d '-' -f 1 + fi +} + +# file enumaration modes + +function all_files() { + hg status -a -m -c | + cut -d ' ' -f 2 | grep -E '(\.(cc|h|dox)$|Makefile\.am$)' | + while read file; do echo $HGROOT/$file; done +} + +function modified_files() { + hg status -a -m | + cut -d ' ' -f 2 | grep -E '(\.(cc|h|dox)$|Makefile\.am$)' | + while read file; do echo $HGROOT/$file; done +} + +function changed_files() { + { + if [ -n "$HG_PARENT1" ] + then + hg status --rev $HG_PARENT1:$HG_NODE -a -m + fi + if [ -n "$HG_PARENT2" ] + then + hg status --rev $HG_PARENT2:$HG_NODE -a -m + fi + } | cut -d ' ' -f 2 | grep -E '(\.(cc|h|dox)$|Makefile\.am$)' | + sort | uniq | + while read file; do echo $HGROOT/$file; done +} + +function given_files() { + for file in $GIVEN_FILES + do + echo $file + done +} + +# actions + +function update_action() { + if ! diff -q $1 $2 >/dev/null + then + echo -n " [$3 updated]" + rm $2 + mv $1 $2 + CHANGED=YES + fi +} + +function update_warning() { + echo -n " [$2 warning]" + WARNED=YES +} + +function update_init() { + echo Update source files... + TOTAL_FILES=0 + CHANGED_FILES=0 + WARNED_FILES=0 +} + +function update_done() { + echo $CHANGED_FILES out of $TOTAL_FILES files has been changed. + echo $WARNED_FILES out of $TOTAL_FILES files triggered warnings. +} + +function update_begin() { + ((TOTAL_FILES++)) + CHANGED=NO + WARNED=NO +} + +function update_end() { + if [ $CHANGED == YES ] + then + ((++CHANGED_FILES)) + fi + if [ $WARNED == YES ] + then + ((++WARNED_FILES)) + fi +} + +function check_action() { + if [ "$3" == 'tabs' ] + then + if echo $2 | grep -q -v -E 'Makefile\.am$' + then + PATTERN=$(echo -e '\t') + else + PATTERN=' ' + fi + elif [ "$3" == 'trailing spaces' ] + then + PATTERN='\ +$' + else + PATTERN='*' + fi + + if ! diff -q $1 $2 >/dev/null + then + if [ "$PATTERN" == '*' ] + then + diff $1 $2 | grep '^[0-9]' | sed "s|^\(.*\)c.*$|$2:\1: check failed: $3|g" | + sed "s/:\([0-9]*\),\([0-9]*\):\(.*\)$/:\1:\3 (until line \2)/g" + else + grep -n -E "$PATTERN" $2 | sed "s|^\([0-9]*\):.*$|$2:\1: check failed: $3|g" + fi + FAILED=YES + fi +} + +function check_warning() { + if [ "$2" == 'long lines' ] + then + grep -n -E '.{81,}' $1 | sed "s|^\([0-9]*\):.*$|$1:\1: warning: $2|g" + else + echo "$1: warning: $2" + fi + WARNED=YES +} + +function check_init() { + echo Check source files... + FAILED_FILES=0 + WARNED_FILES=0 + TOTAL_FILES=0 +} + +function check_done() { + echo $FAILED_FILES out of $TOTAL_FILES files has been failed. + echo $WARNED_FILES out of $TOTAL_FILES files triggered warnings. + + if [ $WARNED_FILES -gt 0 -o $FAILED_FILES -gt 0 ] + then + if [ "$WARNING" == 'INTERACTIVE' ] + then + echo -n "Are the files with errors/warnings acceptable? (yes/no) " + while read answer + do + if [ "$answer" == 'yes' ] + then + return 0 + elif [ "$answer" == 'no' ] + then + return 1 + fi + echo -n "Are the files with errors/warnings acceptable? (yes/no) " + done + elif [ "$WARNING" == 'WERROR' ] + then + return 1 + fi + fi +} + +function check_begin() { + ((TOTAL_FILES++)) + FAILED=NO + WARNED=NO +} + +function check_end() { + if [ $FAILED == YES ] + then + ((++FAILED_FILES)) + fi + if [ $WARNED == YES ] + then + ((++WARNED_FILES)) + fi +} + + + +# checks + +function header_check() { + if echo $1 | grep -q -E 'Makefile\.am$' + then + return + fi + + TMP_FILE=`mktemp` + + (echo "/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-"$(hg_year $1)" + * 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. + * + */ +" + awk 'BEGIN { pm=0; } + pm==3 { print } + /\/\* / && pm==0 { pm=1;} + /[^:blank:]/ && (pm==0 || pm==2) { pm=3; print;} + /\*\// && pm==1 { pm=2;} + ' $1 + ) >$TMP_FILE + + "$ACTION"_action "$TMP_FILE" "$1" header +} + +function tabs_check() { + if echo $1 | grep -q -v -E 'Makefile\.am$' + then + OLD_PATTERN=$(echo -e '\t') + NEW_PATTERN=' ' + else + OLD_PATTERN=' ' + NEW_PATTERN=$(echo -e '\t') + fi + TMP_FILE=`mktemp` + cat $1 | sed -e "s/$OLD_PATTERN/$NEW_PATTERN/g" >$TMP_FILE + + "$ACTION"_action "$TMP_FILE" "$1" 'tabs' +} + +function spaces_check() { + TMP_FILE=`mktemp` + cat $1 | sed -e 's/ \+$//g' >$TMP_FILE + + "$ACTION"_action "$TMP_FILE" "$1" 'trailing spaces' +} + +function long_lines_check() { + if cat $1 | grep -q -E '.{81,}' + then + "$ACTION"_warning $1 'long lines' + fi +} + +# process the file + +function process_file() { + if [ "$ACTION" == 'update' ] + then + echo -n " $ACTION $1..." + else + echo " $ACTION $1..." + fi + + CHECKING="header tabs spaces long_lines" + + "$ACTION"_begin $1 + for check in $CHECKING + do + "$check"_check $1 + done + "$ACTION"_end $1 + if [ "$ACTION" == 'update' ] + then + echo + fi +} + +function process_all { + "$ACTION"_init + while read file + do + process_file $file + done < <($FILES) + "$ACTION"_done +} + +while [ $# -gt 0 ] +do + + if [ "$1" == '--help' ] || [ "$1" == '-h' ] + then + echo -n \ +"Usage: + $0 [OPTIONS] [files] +Options: + --dry-run|-n + Check the files, but do not modify them. + --interactive|-i + If --dry-run is specified and the checker emits warnings, + then the user is asked if the warnings should be considered + errors. + --werror|-w + Make all warnings into errors. + --all|-a + Check all source files in the repository. + --modified|-m + Check only the modified (and new) source files. This option is + useful to check the modification before making a commit. + --changed|-c + Check only the changed source files compared to the parent(s) of + the current hg node. This option is useful as hg hook script. + To automatically check all your changes before making a commit, + add the following section to the appropriate .hg/hgrc file. + + [hooks] + pretxncommit.checksources = scripts/unify-sources.sh -c -n -i + + --help|-h + Print this help message. + files + The files to check/unify. If no file names are given, the modified + source files will be checked/unified (just like using the + --modified|-m option). +" + exit 0 + elif [ "$1" == '--dry-run' ] || [ "$1" == '-n' ] + then + [ -n "$ACTION" ] && echo "Conflicting action options" >&2 && exit 1 + ACTION=check + elif [ "$1" == "--all" ] || [ "$1" == '-a' ] + then + [ -n "$FILES" ] && echo "Conflicting target options" >&2 && exit 1 + FILES=all_files + elif [ "$1" == "--changed" ] || [ "$1" == '-c' ] + then + [ -n "$FILES" ] && echo "Conflicting target options" >&2 && exit 1 + FILES=changed_files + elif [ "$1" == "--modified" ] || [ "$1" == '-m' ] + then + [ -n "$FILES" ] && echo "Conflicting target options" >&2 && exit 1 + FILES=modified_files + elif [ "$1" == "--interactive" ] || [ "$1" == "-i" ] + then + [ -n "$WARNING" ] && echo "Conflicting warning options" >&2 && exit 1 + WARNING='INTERACTIVE' + elif [ "$1" == "--werror" ] || [ "$1" == "-w" ] + then + [ -n "$WARNING" ] && echo "Conflicting warning options" >&2 && exit 1 + WARNING='WERROR' + elif [ $(echo x$1 | cut -c 2) == '-' ] + then + echo "Invalid option $1" >&2 && exit 1 + else + [ -n "$FILES" ] && echo "Invalid option $1" >&2 && exit 1 + GIVEN_FILES=$@ + FILES=given_files + break + fi + + shift +done + +if [ -z $FILES ] +then + FILES=modified_files +fi + +if [ -z $ACTION ] +then + ACTION=update +fi + +process_all diff --git a/extern/quadriflow/3rd/lemon-1.3.1/scripts/valgrind-wrapper.sh b/extern/quadriflow/3rd/lemon-1.3.1/scripts/valgrind-wrapper.sh new file mode 100755 index 00000000000..bbb12229066 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/scripts/valgrind-wrapper.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +# Run in valgrind, with leak checking enabled + +valgrind -q --leak-check=full "$@" 2> .valgrind-log + +# Save the test result + +result="$?" + +# Valgrind should generate no error messages + +log_contents="`cat .valgrind-log`" + +if [ "$log_contents" != "" ]; then + cat .valgrind-log >&2 + result=1 +fi + +rm -f .valgrind-log + +exit $result diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/CMakeLists.txt b/extern/quadriflow/3rd/lemon-1.3.1/test/CMakeLists.txt new file mode 100644 index 00000000000..96fc5dd486c --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/CMakeLists.txt @@ -0,0 +1,161 @@ +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 + arc_look_up_test + bellman_ford_test + bfs_test + bpgraph_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_reader_writer_test + lgf_test + maps_test + matching_test + max_cardinality_search_test + max_clique_test + max_flow_test + min_cost_arborescence_test + min_cost_flow_test + min_mean_cycle_test + nagamochi_ibaraki_test + path_test + planarity_test + radix_sort_test + random_test + suurballe_test + time_measure_test + tsp_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} ${ILOG_LIBRARIES}) + ENDIF() + IF(LEMON_HAVE_CLP) + SET(LP_TEST_LIBS ${LP_TEST_LIBS} ${COIN_CLP_LIBRARIES}) + ENDIF() + IF(LEMON_HAVE_SOPLEX) + SET(LP_TEST_LIBS ${LP_TEST_LIBS} ${SOPLEX_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 ${ILOG_CPLEX_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} ${ILOG_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 ${ILOG_CPLEX_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/extern/quadriflow/3rd/lemon-1.3.1/test/adaptors_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/adaptors_test.cc new file mode 100644 index 00000000000..9077db96eff --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/adaptors_test.cc @@ -0,0 +1,1468 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "test/test_tools.h" +#include "test/graph_test.h" + +using namespace lemon; + +void checkReverseDigraph() { + // Check concepts + checkConcept >(); + checkConcept >(); + checkConcept, + ReverseDigraph >(); + checkConcept, + ReverseDigraph >(); + checkConcept, + ReverseDigraph >(); + checkConcept, + ReverseDigraph >(); + + // Create a digraph and an adaptor + typedef ListDigraph Digraph; + typedef ReverseDigraph 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); + ::lemon::ignore_unused_variable_warning(a3); + + // 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); + ::lemon::ignore_unused_variable_warning(a6,a7,a8); + + 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 >(); + checkConcept >(); + checkConcept, + SubDigraph >(); + checkConcept, + SubDigraph >(); + checkConcept, + SubDigraph >(); + checkConcept, + SubDigraph >(); + + // Create a digraph and an adaptor + typedef ListDigraph Digraph; + typedef Digraph::NodeMap NodeFilter; + typedef Digraph::ArcMap ArcFilter; + typedef SubDigraph 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 >(); + checkConcept >(); + checkConcept, + FilterNodes >(); + checkConcept, + FilterNodes >(); + checkConcept, + FilterNodes >(); + checkConcept, + FilterNodes >(); + + // Create a digraph and an adaptor + typedef ListDigraph Digraph; + typedef Digraph::NodeMap NodeFilter; + typedef FilterNodes 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 >(); + checkConcept >(); + checkConcept, + FilterArcs >(); + checkConcept, + FilterArcs >(); + checkConcept, + FilterArcs >(); + checkConcept, + FilterArcs >(); + + // Create a digraph and an adaptor + typedef ListDigraph Digraph; + typedef Digraph::ArcMap ArcFilter; + typedef FilterArcs 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 >(); + checkConcept >(); + checkConcept, + Undirector >(); + checkConcept, + Undirector >(); + checkConcept, + Undirector >(); + checkConcept, + Undirector >(); + + + // Create a digraph and an adaptor + typedef ListDigraph Digraph; + typedef Undirector 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 > IntCombinedMap; + typedef Adaptor::CombinedArcMap + , Digraph::ArcMap > BoolCombinedMap; + checkConcept, + IntCombinedMap>(); + checkConcept, + BoolCombinedMap>(); + + Digraph::ArcMap 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 > + 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 >(); + checkConcept >(); + + // Create a digraph and an adaptor + typedef ListDigraph Digraph; + typedef Digraph::ArcMap IntArcMap; + typedef ResidualDigraph 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 bfs(adaptor); + bfs.run(n1, n4); + + if (!bfs.reached(n4)) break; + + Path p = bfs.path(n4); + + int min = std::numeric_limits::max(); + for (Path::ArcIt a(p); a != INVALID; ++a) { + if (res_cap[a] < min) min = res_cap[a]; + } + + for (Path::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 >(); + checkConcept >(); + + // Create a digraph and an adaptor + typedef ListDigraph Digraph; + typedef SplitNodes 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); + ::lemon::ignore_unused_variable_warning(a1,a2,a3); + + 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 > IntCombinedNodeMap; + typedef Adaptor::CombinedNodeMap + , Digraph::NodeMap > BoolCombinedNodeMap; + checkConcept, + IntCombinedNodeMap>(); +//checkConcept, +// BoolCombinedNodeMap>(); + checkConcept, + BoolCombinedNodeMap>(); + + Digraph::NodeMap 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 > + 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::NodeMap > IntCombinedArcMap; + typedef Adaptor::CombinedArcMap + , Digraph::NodeMap > BoolCombinedArcMap; + checkConcept, + IntCombinedArcMap>(); +//checkConcept, +// BoolCombinedArcMap>(); + checkConcept, + BoolCombinedArcMap>(); + + Digraph::ArcMap a_map(digraph); + for (Digraph::ArcIt a(digraph); a != INVALID; ++a) { + a_map[a] = digraph.id(a); + } + + Adaptor::CombinedArcMap, Digraph::NodeMap > + 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 >(); + checkConcept >(); + checkConcept, + SubGraph >(); + checkConcept, + SubGraph >(); + checkConcept, + SubGraph >(); + checkConcept, + SubGraph >(); + + // Create a graph and an adaptor + typedef ListGraph Graph; + typedef Graph::NodeMap NodeFilter; + typedef Graph::EdgeMap EdgeFilter; + typedef SubGraph 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 >(); + checkConcept >(); + checkConcept, + FilterNodes >(); + checkConcept, + FilterNodes >(); + checkConcept, + FilterNodes >(); + checkConcept, + FilterNodes >(); + + // Create a graph and an adaptor + typedef ListGraph Graph; + typedef Graph::NodeMap NodeFilter; + typedef FilterNodes 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 >(); + checkConcept >(); + checkConcept, + FilterEdges >(); + checkConcept, + FilterEdges >(); + checkConcept, + FilterEdges >(); + checkConcept, + FilterEdges >(); + + // Create a graph and an adaptor + typedef ListGraph Graph; + typedef Graph::EdgeMap EdgeFilter; + typedef FilterEdges 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 >(); + checkConcept >(); + checkConcept, + Orienter >(); + checkConcept, + Orienter >(); + checkConcept, + Orienter >(); + checkConcept, + Orienter >(); + + // Create a graph and an adaptor + typedef ListGraph Graph; + typedef ListGraph::EdgeMap DirMap; + typedef Orienter 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 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 Orienter< const GridGraph, GridGraph::EdgeMap > + OrientedGridGraph; + typedef SplitNodes SplitGridGraph; + typedef Undirector USplitGridGraph; + checkConcept(); + checkConcept(); + + OrientedGridGraph oadaptor = orienter(graph, dir_map); + SplitGridGraph adaptor = splitNodes(oadaptor); + 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/extern/quadriflow/3rd/lemon-1.3.1/test/arc_look_up_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/arc_look_up_test.cc new file mode 100644 index 00000000000..2f4edf52d66 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/arc_look_up_test.cc @@ -0,0 +1,84 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 +#include "lemon/list_graph.h" +#include "lemon/lgf_reader.h" + +#include "test_tools.h" + +using namespace lemon; + +const std::string lgf = + "@nodes\n" +"label\n" +"0\n" +"1\n" +"2\n" +"3\n" +"4\n" +"5\n" +"6\n" +"@arcs\n" +"label\n" +"5 6 0\n" +"5 4 1\n" +"4 6 2\n" +"3 4 3\n" +"3 4 4\n" +"3 2 5\n" +"3 5 6\n" +"3 5 7\n" +"3 5 8\n" +"3 5 9\n" +"2 4 10\n" +"2 4 11\n" +"2 4 12\n" +"2 4 13\n" +"1 2 14\n" +"1 2 15\n" +"1 0 16\n" +"1 3 17\n" +"1 3 18\n" +"1 3 19\n" +"1 3 20\n" +"0 2 21\n" +"0 2 22\n" +"0 2 23\n" +"0 2 24\n"; + + +int main() { + ListDigraph graph; + std::istringstream lgfs(lgf); + DigraphReader(graph, lgfs).run(); + + AllArcLookUp lookup(graph); + + int numArcs = countArcs(graph); + + int arcCnt = 0; + for(ListDigraph::NodeIt n1(graph); n1 != INVALID; ++n1) + for(ListDigraph::NodeIt n2(graph); n2 != INVALID; ++n2) + for(ListDigraph::Arc a = lookup(n1, n2); a != INVALID; + a = lookup(n1, n2, a)) + ++arcCnt; + check(arcCnt==numArcs, "Wrong total number of arcs"); + + return 0; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/bellman_ford_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/bellman_ford_test.cc new file mode 100644 index 00000000000..14faa07c961 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/bellman_ford_test.cc @@ -0,0 +1,289 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 +#include +#include +#include +#include +#include + +#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 LengthMap; + typedef BellmanFord BF; + typedef Digraph::Node Node; + typedef Digraph::Arc Arc; + + Digraph gr; + Node s, t, n; + Arc e; + Value l; + ::lemon::ignore_unused_variable_warning(l); + int k=3; + bool b; + ::lemon::ignore_unused_variable_warning(b); + BF::DistMap d(gr); + BF::PredMap p(gr); + LengthMap length; + concepts::Path 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 > + ::SetDistMap > + ::SetOperationTraits > + ::Create bf_test(gr,length); + + LengthMap length_map; + concepts::ReadWriteMap pred_map; + concepts::ReadWriteMap 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 LengthMap; + + Digraph g; + bool b; + ::lemon::ignore_unused_variable_warning(b); + + bellmanFord(g,LengthMap()).run(Node()); + b = bellmanFord(g,LengthMap()).run(Node(),Node()); + bellmanFord(g,LengthMap()) + .predMap(concepts::ReadWriteMap()) + .distMap(concepts::ReadWriteMap()) + .run(Node()); + b=bellmanFord(g,LengthMap()) + .predMap(concepts::ReadWriteMap()) + .distMap(concepts::ReadWriteMap()) + .path(concepts::Path()) + .dist(Value()) + .run(Node(),Node()); +} + + +template +void checkBellmanFord() { + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + typedef typename Digraph::template ArcMap 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 + bf(gr, length); + bf.run(s); + Path 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 path; + Value dist = 0; + 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 bf(gr, length); + bf.run(n1); + StaticPath p = bf.negativeCycle(); + check(p.length() == 1 && p.front() == p.back() && p.front() == a2, + "Wrong negative cycle."); + } + + length[a2] = 0; + + { + BellmanFord 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 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 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(); + checkBellmanFord(); + checkBellmanFordNegativeCycle(); + return 0; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/bfs_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/bfs_test.cc new file mode 100644 index 00000000000..976fa88b637 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/bfs_test.cc @@ -0,0 +1,239 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 +#include +#include +#include +#include +#include + +#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 BType; + typedef Digraph::Node Node; + typedef Digraph::Arc Arc; + + Digraph G; + Node s, t, n; + Arc e; + int l, i; + ::lemon::ignore_unused_variable_warning(l,i); + bool b; + BType::DistMap d(G); + BType::PredMap p(G); + Path pp; + concepts::ReadMap 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 > + ::SetDistMap > + ::SetReachedMap > + ::SetStandardProcessedMap + ::SetProcessedMap > + ::Create bfs_test(G); + + concepts::ReadWriteMap pred_map; + concepts::ReadWriteMap dist_map; + concepts::ReadWriteMap reached_map; + concepts::WriteMap 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; + ::lemon::ignore_unused_variable_warning(b); + + bfs(g).run(Node()); + b=bfs(g).run(Node(),Node()); + bfs(g).run(); + bfs(g) + .predMap(concepts::ReadWriteMap()) + .distMap(concepts::ReadWriteMap()) + .reachedMap(concepts::ReadWriteMap()) + .processedMap(concepts::WriteMap()) + .run(Node()); + b=bfs(g) + .predMap(concepts::ReadWriteMap()) + .distMap(concepts::ReadWriteMap()) + .reachedMap(concepts::ReadWriteMap()) + .processedMap(concepts::WriteMap()) + .path(concepts::Path()) + .dist(VType()) + .run(Node(),Node()); + bfs(g) + .predMap(concepts::ReadWriteMap()) + .distMap(concepts::ReadWriteMap()) + .reachedMap(concepts::ReadWriteMap()) + .processedMap(concepts::WriteMap()) + .run(); +} + +template +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 bfs_test(G); + bfs_test.run(s); + + check(bfs_test.dist(t)==2,"Bfs found a wrong path."); + + Path 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 myPredMap; + bfs(G).predMap(myPredMap).run(s); + } +} + +int main() +{ + checkBfs(); + checkBfs(); + return 0; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/bpgraph_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/bpgraph_test.cc new file mode 100644 index 00000000000..45fc5b855d4 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/bpgraph_test.cc @@ -0,0 +1,456 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 +#include +#include +#include + +#include "test_tools.h" +#include "graph_test.h" + +using namespace lemon; +using namespace lemon::concepts; + +template +void checkBpGraphBuild() { + TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph); + + BpGraph G; + checkGraphNodeList(G, 0); + checkGraphRedNodeList(G, 0); + checkGraphBlueNodeList(G, 0); + checkGraphEdgeList(G, 0); + checkGraphArcList(G, 0); + + G.reserveNode(3); + G.reserveEdge(3); + + RedNode + rn1 = G.addRedNode(); + checkGraphNodeList(G, 1); + checkGraphRedNodeList(G, 1); + checkGraphBlueNodeList(G, 0); + checkGraphEdgeList(G, 0); + checkGraphArcList(G, 0); + + BlueNode + bn1 = G.addBlueNode(), + bn2 = G.addBlueNode(); + checkGraphNodeList(G, 3); + checkGraphRedNodeList(G, 1); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 0); + checkGraphArcList(G, 0); + + Edge e1 = G.addEdge(rn1, bn2); + check(G.redNode(e1) == rn1 && G.blueNode(e1) == bn2, "Wrong edge"); + check(G.u(e1) == rn1 && G.v(e1) == bn2, "Wrong edge"); + + checkGraphNodeList(G, 3); + checkGraphRedNodeList(G, 1); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 1); + checkGraphArcList(G, 2); + + checkGraphIncEdgeArcLists(G, rn1, 1); + checkGraphIncEdgeArcLists(G, bn1, 0); + checkGraphIncEdgeArcLists(G, bn2, 1); + + checkGraphConEdgeList(G, 1); + checkGraphConArcList(G, 2); + + Edge + e2 = G.addEdge(bn1, rn1), + e3 = G.addEdge(rn1, bn2); + ::lemon::ignore_unused_variable_warning(e2,e3); + + checkGraphNodeList(G, 3); + checkGraphRedNodeList(G, 1); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 3); + checkGraphArcList(G, 6); + + checkGraphIncEdgeArcLists(G, rn1, 3); + checkGraphIncEdgeArcLists(G, bn1, 1); + checkGraphIncEdgeArcLists(G, bn2, 2); + + checkGraphConEdgeList(G, 3); + checkGraphConArcList(G, 6); + + checkArcDirections(G); + + checkNodeIds(G); + checkRedNodeIds(G); + checkBlueNodeIds(G); + checkArcIds(G); + checkEdgeIds(G); + + checkGraphNodeMap(G); + checkGraphRedNodeMap(G); + checkGraphBlueNodeMap(G); + checkGraphArcMap(G); + checkGraphEdgeMap(G); +} + +template +void checkBpGraphErase() { + TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph); + + BpGraph G; + RedNode + n1 = G.addRedNode(), n4 = G.addRedNode(); + BlueNode + n2 = G.addBlueNode(), n3 = G.addBlueNode(); + Edge + e1 = G.addEdge(n1, n2), e2 = G.addEdge(n1, n3), + e3 = G.addEdge(n4, n2), e4 = G.addEdge(n4, n3); + ::lemon::ignore_unused_variable_warning(e1,e3,e4); + + // Check edge deletion + G.erase(e2); + + checkGraphNodeList(G, 4); + checkGraphRedNodeList(G, 2); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 3); + checkGraphArcList(G, 6); + + checkGraphIncEdgeArcLists(G, n1, 1); + checkGraphIncEdgeArcLists(G, n2, 2); + checkGraphIncEdgeArcLists(G, n3, 1); + checkGraphIncEdgeArcLists(G, n4, 2); + + checkGraphConEdgeList(G, 3); + checkGraphConArcList(G, 6); + + // Check node deletion + G.erase(n3); + + checkGraphNodeList(G, 3); + checkGraphRedNodeList(G, 2); + checkGraphBlueNodeList(G, 1); + checkGraphEdgeList(G, 2); + checkGraphArcList(G, 4); + + checkGraphIncEdgeArcLists(G, n1, 1); + checkGraphIncEdgeArcLists(G, n2, 2); + checkGraphIncEdgeArcLists(G, n4, 1); + + checkGraphConEdgeList(G, 2); + checkGraphConArcList(G, 4); + +} + +template +void checkBpGraphAlter() { + TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph); + + BpGraph G; + RedNode + n1 = G.addRedNode(), n4 = G.addRedNode(); + BlueNode + n2 = G.addBlueNode(), n3 = G.addBlueNode(); + Edge + e1 = G.addEdge(n1, n2), e2 = G.addEdge(n1, n3), + e3 = G.addEdge(n4, n2), e4 = G.addEdge(n4, n3); + ::lemon::ignore_unused_variable_warning(e1,e3,e4); + + G.changeRed(e2, n4); + check(G.redNode(e2) == n4, "Wrong red node"); + check(G.blueNode(e2) == n3, "Wrong blue node"); + + checkGraphNodeList(G, 4); + checkGraphRedNodeList(G, 2); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 4); + checkGraphArcList(G, 8); + + checkGraphIncEdgeArcLists(G, n1, 1); + checkGraphIncEdgeArcLists(G, n2, 2); + checkGraphIncEdgeArcLists(G, n3, 2); + checkGraphIncEdgeArcLists(G, n4, 3); + + checkGraphConEdgeList(G, 4); + checkGraphConArcList(G, 8); + + G.changeBlue(e2, n2); + check(G.redNode(e2) == n4, "Wrong red node"); + check(G.blueNode(e2) == n2, "Wrong blue node"); + + checkGraphNodeList(G, 4); + checkGraphRedNodeList(G, 2); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 4); + checkGraphArcList(G, 8); + + checkGraphIncEdgeArcLists(G, n1, 1); + checkGraphIncEdgeArcLists(G, n2, 3); + checkGraphIncEdgeArcLists(G, n3, 1); + checkGraphIncEdgeArcLists(G, n4, 3); + + checkGraphConEdgeList(G, 4); + checkGraphConArcList(G, 8); +} + + +template +void checkBpGraphSnapshot() { + TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph); + + BpGraph G; + RedNode + n1 = G.addRedNode(); + BlueNode + n2 = G.addBlueNode(), + n3 = G.addBlueNode(); + Edge + e1 = G.addEdge(n1, n2), + e2 = G.addEdge(n1, n3); + ::lemon::ignore_unused_variable_warning(e1,e2); + + checkGraphNodeList(G, 3); + checkGraphRedNodeList(G, 1); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 2); + checkGraphArcList(G, 4); + + typename BpGraph::Snapshot snapshot(G); + + RedNode n4 = G.addRedNode(); + G.addEdge(n4, n2); + G.addEdge(n4, n3); + + checkGraphNodeList(G, 4); + checkGraphRedNodeList(G, 2); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 4); + checkGraphArcList(G, 8); + + snapshot.restore(); + + checkGraphNodeList(G, 3); + checkGraphRedNodeList(G, 1); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 2); + checkGraphArcList(G, 4); + + checkGraphIncEdgeArcLists(G, n1, 2); + checkGraphIncEdgeArcLists(G, n2, 1); + checkGraphIncEdgeArcLists(G, n3, 1); + + checkGraphConEdgeList(G, 2); + checkGraphConArcList(G, 4); + + checkNodeIds(G); + checkRedNodeIds(G); + checkBlueNodeIds(G); + checkArcIds(G); + checkEdgeIds(G); + + checkGraphNodeMap(G); + checkGraphRedNodeMap(G); + checkGraphBlueNodeMap(G); + checkGraphArcMap(G); + checkGraphEdgeMap(G); + + G.addRedNode(); + snapshot.save(G); + + G.addEdge(G.addRedNode(), G.addBlueNode()); + + snapshot.restore(); + snapshot.save(G); + + checkGraphNodeList(G, 4); + checkGraphRedNodeList(G, 2); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 2); + checkGraphArcList(G, 4); + + G.addEdge(G.addRedNode(), G.addBlueNode()); + + snapshot.restore(); + + checkGraphNodeList(G, 4); + checkGraphRedNodeList(G, 2); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 2); + checkGraphArcList(G, 4); +} + +template +void checkBpGraphValidity() { + TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph); + BpGraph g; + + RedNode + n1 = g.addRedNode(); + BlueNode + n2 = g.addBlueNode(), + n3 = g.addBlueNode(); + + Edge + e1 = g.addEdge(n1, n2), + e2 = g.addEdge(n1, n3); + ::lemon::ignore_unused_variable_warning(e2); + + 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"); +} + +void checkConcepts() { + { // Checking graph components + checkConcept(); + + checkConcept, + IDableBpGraphComponent<> >(); + + checkConcept, + IterableBpGraphComponent<> >(); + + checkConcept, + AlterableBpGraphComponent<> >(); + + checkConcept, + MappableBpGraphComponent<> >(); + + checkConcept, + ExtendableBpGraphComponent<> >(); + + checkConcept, + ErasableBpGraphComponent<> >(); + + checkConcept, + ClearableBpGraphComponent<> >(); + + } + { // Checking skeleton graph + checkConcept(); + } + { // Checking SmartBpGraph + checkConcept(); + checkConcept, SmartBpGraph>(); + checkConcept, SmartBpGraph>(); + checkConcept, SmartBpGraph>(); + } +} + +void checkFullBpGraph(int redNum, int blueNum) { + typedef FullBpGraph BpGraph; + BPGRAPH_TYPEDEFS(BpGraph); + + BpGraph G(redNum, blueNum); + checkGraphNodeList(G, redNum + blueNum); + checkGraphRedNodeList(G, redNum); + checkGraphBlueNodeList(G, blueNum); + checkGraphEdgeList(G, redNum * blueNum); + checkGraphArcList(G, 2 * redNum * blueNum); + + G.resize(redNum, blueNum); + checkGraphNodeList(G, redNum + blueNum); + checkGraphRedNodeList(G, redNum); + checkGraphBlueNodeList(G, blueNum); + checkGraphEdgeList(G, redNum * blueNum); + checkGraphArcList(G, 2 * redNum * blueNum); + + for (RedNodeIt n(G); n != INVALID; ++n) { + checkGraphOutArcList(G, n, blueNum); + checkGraphInArcList(G, n, blueNum); + checkGraphIncEdgeList(G, n, blueNum); + } + + for (BlueNodeIt n(G); n != INVALID; ++n) { + checkGraphOutArcList(G, n, redNum); + checkGraphInArcList(G, n, redNum); + checkGraphIncEdgeList(G, n, redNum); + } + + checkGraphConArcList(G, 2 * redNum * blueNum); + checkGraphConEdgeList(G, redNum * blueNum); + + checkArcDirections(G); + + checkNodeIds(G); + checkRedNodeIds(G); + checkBlueNodeIds(G); + checkArcIds(G); + checkEdgeIds(G); + + checkGraphNodeMap(G); + checkGraphRedNodeMap(G); + checkGraphBlueNodeMap(G); + checkGraphArcMap(G); + checkGraphEdgeMap(G); + + for (int i = 0; i < G.redNum(); ++i) { + check(G.red(G.redNode(i)), "Wrong node"); + check(G.index(G.redNode(i)) == i, "Wrong index"); + } + + for (int i = 0; i < G.blueNum(); ++i) { + check(G.blue(G.blueNode(i)), "Wrong node"); + check(G.index(G.blueNode(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 (G.red(u) == G.red(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 checkGraphs() { + { // Checking ListGraph + checkBpGraphBuild(); + checkBpGraphErase(); + checkBpGraphAlter(); + checkBpGraphSnapshot(); + checkBpGraphValidity(); + } + { // Checking SmartGraph + checkBpGraphBuild(); + checkBpGraphSnapshot(); + checkBpGraphValidity(); + } + { // Checking FullBpGraph + checkFullBpGraph(6, 8); + checkFullBpGraph(7, 4); + } +} + +int main() { + checkConcepts(); + checkGraphs(); + return 0; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/circulation_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/circulation_test.cc new file mode 100644 index 00000000000..3b3a4a97216 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/circulation_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-2013 + * 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 + +#include "test_tools.h" +#include +#include +#include +#include +#include + +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 CapMap; + typedef concepts::ReadMap SupplyMap; + typedef concepts::ReadWriteMap FlowMap; + typedef concepts::WriteMap BarrierMap; + + typedef Elevator Elev; + typedef LinkedElevator LinkedElev; + + Digraph g; + Node n; + Arc a; + CapMap lcap, ucap; + SupplyMap supply; + FlowMap flow; + BarrierMap bar; + VType v; + bool b; + ::lemon::ignore_unused_variable_warning(v,b); + + typedef Circulation + ::SetFlowMap + ::SetElevator + ::SetStandardElevator + ::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(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); + + ::lemon::ignore_unused_variable_warning(fm); +} + +template +void checkCirculation(const G& g, const LM& lm, const UM& um, + const DM& dm, bool find) +{ + Circulation 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(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/extern/quadriflow/3rd/lemon-1.3.1/test/connectivity_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/connectivity_test.cc new file mode 100644 index 00000000000..4ab343ee0fd --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/connectivity_test.cc @@ -0,0 +1,316 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 +#include +#include + +#include "test_tools.h" + +using namespace lemon; + + +int main() +{ + typedef ListDigraph Digraph; + typedef Undirector Graph; + + { + Digraph d; + Digraph::NodeMap 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 order(d); + Graph g(d); + Digraph::Node n = d.addNode(); + ::lemon::ignore_unused_variable_warning(n); + + 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."); + } + + { + ListGraph g; + ListGraph::NodeMap map(g); + + ListGraph::Node n1 = g.addNode(); + ListGraph::Node n2 = g.addNode(); + + ListGraph::Edge e1 = g.addEdge(n1, n2); + ::lemon::ignore_unused_variable_warning(e1); + check(biNodeConnected(g), "Graph is bi-node-connected"); + + ListGraph::Node n3 = g.addNode(); + ::lemon::ignore_unused_variable_warning(n3); + check(!biNodeConnected(g), "Graph is not bi-node-connected"); + } + + + { + Digraph d; + Digraph::NodeMap 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 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 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 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 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 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 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 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(); + ::lemon::ignore_unused_variable_warning(watch); + + 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 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/extern/quadriflow/3rd/lemon-1.3.1/test/counter_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/counter_test.cc new file mode 100644 index 00000000000..df31dd4d39e --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/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 +#include +#include + +#include "test/test_tools.h" + +using namespace lemon; + +template +void bubbleSort(std::vector& 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 +void insertionSort(std::vector& 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 +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& 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(true); + counterTest(false); + + std::vector x(10); + init(x); bubbleSort(x); + init(x); insertionSort(x); + + return 0; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/dfs_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/dfs_test.cc new file mode 100644 index 00000000000..ef5049a000a --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/dfs_test.cc @@ -0,0 +1,238 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 +#include +#include +#include +#include +#include + +#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 DType; + typedef Digraph::Node Node; + typedef Digraph::Arc Arc; + + Digraph G; + Node s, t; + Arc e; + int l, i; + bool b; + ::lemon::ignore_unused_variable_warning(l,i,b); + + DType::DistMap d(G); + DType::PredMap p(G); + Path pp; + concepts::ReadMap 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 > + ::SetDistMap > + ::SetReachedMap > + ::SetStandardProcessedMap + ::SetProcessedMap > + ::Create dfs_test(G); + + concepts::ReadWriteMap pred_map; + concepts::ReadWriteMap dist_map; + concepts::ReadWriteMap reached_map; + concepts::WriteMap 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; + ::lemon::ignore_unused_variable_warning(b); + + dfs(g).run(Node()); + b=dfs(g).run(Node(),Node()); + dfs(g).run(); + dfs(g) + .predMap(concepts::ReadWriteMap()) + .distMap(concepts::ReadWriteMap()) + .reachedMap(concepts::ReadWriteMap()) + .processedMap(concepts::WriteMap()) + .run(Node()); + b=dfs(g) + .predMap(concepts::ReadWriteMap()) + .distMap(concepts::ReadWriteMap()) + .reachedMap(concepts::ReadWriteMap()) + .processedMap(concepts::WriteMap()) + .path(concepts::Path()) + .dist(VType()) + .run(Node(),Node()); + dfs(g) + .predMap(concepts::ReadWriteMap()) + .distMap(concepts::ReadWriteMap()) + .reachedMap(concepts::ReadWriteMap()) + .processedMap(concepts::WriteMap()) + .run(); +} + +template +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 dfs_test(G); + dfs_test.run(s); + + Path 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 dfs(G); + check(dfs.run(s1,t1) && dfs.reached(t1),"Node 3 is reachable from Node 6."); + } + + { + NullMap myPredMap; + dfs(G).predMap(myPredMap).run(s); + } +} + +int main() +{ + checkDfs(); + checkDfs(); + return 0; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/digraph_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/digraph_test.cc new file mode 100644 index 00000000000..e3ff54577ea --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/digraph_test.cc @@ -0,0 +1,569 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 +#include +#include +#include +#include + +#include "test_tools.h" +#include "graph_test.h" + +using namespace lemon; +using namespace lemon::concepts; + +template +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); + ::lemon::ignore_unused_variable_warning(a2,a3,a4); + + 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 +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); + ::lemon::ignore_unused_variable_warning(a1,a2,a3,a4); + + 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 +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); + ::lemon::ignore_unused_variable_warning(a1,a2,a3,a5); + + 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 +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); + ::lemon::ignore_unused_variable_warning(a2,a3,a4,a5); + + // 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 +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); + ::lemon::ignore_unused_variable_warning(a1,a2,a3,a4); + + 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(); + + checkConcept, + IDableDigraphComponent<> >(); + + checkConcept, + IterableDigraphComponent<> >(); + + checkConcept, + MappableDigraphComponent<> >(); + } + { // Checking skeleton digraph + checkConcept(); + } + { // Checking ListDigraph + checkConcept(); + checkConcept, ListDigraph>(); + checkConcept, ListDigraph>(); + checkConcept, ListDigraph>(); + checkConcept, ListDigraph>(); + } + { // Checking SmartDigraph + checkConcept(); + checkConcept, SmartDigraph>(); + checkConcept, SmartDigraph>(); + checkConcept, SmartDigraph>(); + } + { // Checking StaticDigraph + checkConcept(); + checkConcept, StaticDigraph>(); + } + { // Checking FullDigraph + checkConcept(); + } +} + +template +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); + ::lemon::ignore_unused_variable_warning(e2); + + 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 +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 nref(g); + SmartDigraph::ArcMap 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); + ::lemon::ignore_unused_variable_warning(a2,a3,a4); + + 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 > 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(); + checkDigraphSplit(); + checkDigraphAlter(); + checkDigraphErase(); + checkDigraphSnapshot(); + checkDigraphValidityErase(); + } + { // Checking SmartDigraph + checkDigraphBuild(); + checkDigraphSplit(); + checkDigraphSnapshot(); + checkDigraphValidity(); + } + { // Checking StaticDigraph + checkStaticDigraph(); + } + { // Checking FullDigraph + checkFullDigraph(8); + } +} + +int main() { + checkDigraphs(); + checkConcepts(); + return 0; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/dijkstra_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/dijkstra_test.cc new file mode 100644 index 00000000000..20cc76b36a8 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/dijkstra_test.cc @@ -0,0 +1,246 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 +#include +#include +#include +#include +#include +#include + +#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 LengthMap; + typedef Dijkstra DType; + typedef Digraph::Node Node; + typedef Digraph::Arc Arc; + + Digraph G; + Node s, t, n; + Arc e; + VType l; + int i; + bool b; + ::lemon::ignore_unused_variable_warning(l,i,b); + + DType::DistMap d(G); + DType::PredMap p(G); + LengthMap length; + Path pp; + concepts::ReadMap 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 > + ::SetDistMap > + ::SetStandardProcessedMap + ::SetProcessedMap > + ::SetOperationTraits > + ::SetHeap > > + ::SetStandardHeap > > + ::SetHeap >, + concepts::ReadWriteMap > + ::Create dijkstra_test(G,length); + + LengthMap length_map; + concepts::ReadWriteMap pred_map; + concepts::ReadWriteMap dist_map; + concepts::WriteMap processed_map; + concepts::ReadWriteMap heap_cross_ref; + BinHeap > 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 LengthMap; + + Digraph g; + bool b; + ::lemon::ignore_unused_variable_warning(b); + + dijkstra(g,LengthMap()).run(Node()); + b=dijkstra(g,LengthMap()).run(Node(),Node()); + dijkstra(g,LengthMap()) + .predMap(concepts::ReadWriteMap()) + .distMap(concepts::ReadWriteMap()) + .processedMap(concepts::WriteMap()) + .run(Node()); + b=dijkstra(g,LengthMap()) + .predMap(concepts::ReadWriteMap()) + .distMap(concepts::ReadWriteMap()) + .processedMap(concepts::WriteMap()) + .path(concepts::Path()) + .dist(VType()) + .run(Node(),Node()); +} + +template +void checkDijkstra() { + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + typedef typename Digraph::template ArcMap 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 + dijkstra_test(G, length); + dijkstra_test.run(s); + + check(dijkstra_test.dist(t)==3,"Dijkstra found a wrong path."); + + Path 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 myPredMap; + dijkstra(G,length).predMap(myPredMap).run(s); + } +} + +int main() { + checkDijkstra(); + checkDijkstra(); + return 0; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/dim_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/dim_test.cc new file mode 100644 index 00000000000..0b2b9250feb --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/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 +#include +#include "test_tools.h" + +using namespace std; +using namespace lemon; + +int main() +{ + typedef dim2::Point 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 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/extern/quadriflow/3rd/lemon-1.3.1/test/edge_set_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/edge_set_test.cc new file mode 100644 index 00000000000..dbe74a9fcb5 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/edge_set_test.cc @@ -0,0 +1,396 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 +#include + +#include +#include +#include + +#include + +#include + +#include "graph_test.h" +#include "test_tools.h" + +using namespace lemon; + +void checkSmartArcSet() { + checkConcept >(); + + typedef ListDigraph Digraph; + typedef SmartArcSet ArcSet; + + Digraph digraph; + Digraph::Node + n1 = digraph.addNode(), + n2 = digraph.addNode(); + + Digraph::Arc ga1 = digraph.addArc(n1, n2); + ::lemon::ignore_unused_variable_warning(ga1); + + ArcSet arc_set(digraph); + + Digraph::Arc ga2 = digraph.addArc(n2, n1); + ::lemon::ignore_unused_variable_warning(ga2); + + 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); + ::lemon::ignore_unused_variable_warning(a2,a3,a4); + + 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 >(); + + typedef ListDigraph Digraph; + typedef ListArcSet ArcSet; + + Digraph digraph; + Digraph::Node + n1 = digraph.addNode(), + n2 = digraph.addNode(); + + Digraph::Arc ga1 = digraph.addArc(n1, n2); + ::lemon::ignore_unused_variable_warning(ga1); + + ArcSet arc_set(digraph); + + Digraph::Arc ga2 = digraph.addArc(n2, n1); + ::lemon::ignore_unused_variable_warning(ga2); + + 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); + ::lemon::ignore_unused_variable_warning(a2,a3,a4); + + 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 >(); + + typedef ListDigraph Digraph; + typedef SmartEdgeSet EdgeSet; + + Digraph digraph; + Digraph::Node + n1 = digraph.addNode(), + n2 = digraph.addNode(); + + Digraph::Arc ga1 = digraph.addArc(n1, n2); + ::lemon::ignore_unused_variable_warning(ga1); + + EdgeSet edge_set(digraph); + + Digraph::Arc ga2 = digraph.addArc(n2, n1); + ::lemon::ignore_unused_variable_warning(ga2); + + 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); + ::lemon::ignore_unused_variable_warning(e2,e3,e4); + + 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 >(); + + typedef ListDigraph Digraph; + typedef ListEdgeSet EdgeSet; + + Digraph digraph; + Digraph::Node + n1 = digraph.addNode(), + n2 = digraph.addNode(); + + Digraph::Arc ga1 = digraph.addArc(n1, n2); + ::lemon::ignore_unused_variable_warning(ga1); + + EdgeSet edge_set(digraph); + + Digraph::Arc ga2 = digraph.addArc(n2, n1); + ::lemon::ignore_unused_variable_warning(ga2); + + 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); + ::lemon::ignore_unused_variable_warning(e2,e3,e4); + + 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/extern/quadriflow/3rd/lemon-1.3.1/test/error_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/error_test.cc new file mode 100644 index 00000000000..1527519812b --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/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 + +#include +#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 + +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 + +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/extern/quadriflow/3rd/lemon-1.3.1/test/euler_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/euler_test.cc new file mode 100644 index 00000000000..11a39e47081 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/euler_test.cc @@ -0,0 +1,225 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 +#include +#include +#include "test_tools.h" + +using namespace lemon; + +template +void checkDiEulerIt(const Digraph& g, + const typename Digraph::Node& start = INVALID) +{ + typename Digraph::template ArcMap visitationNumber(g, 0); + + DiEulerIt 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 +void checkEulerIt(const Graph& g, + const typename Graph::Node& start = INVALID) +{ + typename Graph::template EdgeMap visitationNumber(g, 0); + + EulerIt 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 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(); + ::lemon::ignore_unused_variable_warning(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 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(); + ::lemon::ignore_unused_variable_warning(n0,n4,n5); + + 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/extern/quadriflow/3rd/lemon-1.3.1/test/fractional_matching_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/fractional_matching_test.cc new file mode 100644 index 00000000000..bee866c0149 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/fractional_matching_test.cc @@ -0,0 +1,527 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#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 mat_test(g); + const MaxFractionalMatching& + 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::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 WeightMap; + + Graph g; + Node n; + Edge e; + WeightMap w(g); + + MaxWeightedFractionalMatching mat_test(g, w); + const MaxWeightedFractionalMatching& + 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::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 WeightMap; + + Graph g; + Node n; + Edge e; + WeightMap w(g); + + MaxWeightedPerfectFractionalMatching mat_test(g, w); + const MaxWeightedPerfectFractionalMatching& + 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::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& 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 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 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& 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 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& weight, + const MaxWeightedFractionalMatching& 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)); + ::lemon::ignore_unused_variable_warning(o); + } 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 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& weight, + const MaxWeightedPerfectFractionalMatching& 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)); + ::lemon::ignore_unused_variable_warning(o); + } + + 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 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 weight(graph); + + istringstream lgfs(lgf[i]); + graphReader(graph, lgfs). + edgeMap("weight", weight).run(); + + bool perfect_with_loops; + { + MaxFractionalMatching mfm(graph, true); + mfm.run(); + checkFractionalMatching(graph, mfm, true); + perfect_with_loops = mfm.matchingSize() == countNodes(graph); + } + + bool perfect_without_loops; + { + MaxFractionalMatching mfm(graph, false); + mfm.run(); + checkFractionalMatching(graph, mfm, false); + perfect_without_loops = mfm.matchingSize() == countNodes(graph); + } + + { + MaxFractionalMatching mfm(graph, true); + bool result = mfm.runPerfect(); + checkPerfectFractionalMatching(graph, mfm, result, true); + check(result == perfect_with_loops, "Wrong perfect matching"); + } + + { + MaxFractionalMatching mfm(graph, false); + bool result = mfm.runPerfect(); + checkPerfectFractionalMatching(graph, mfm, result, false); + check(result == perfect_without_loops, "Wrong perfect matching"); + } + + { + MaxWeightedFractionalMatching mwfm(graph, weight, true); + mwfm.run(); + checkWeightedFractionalMatching(graph, weight, mwfm, true); + } + + { + MaxWeightedFractionalMatching mwfm(graph, weight, false); + mwfm.run(); + checkWeightedFractionalMatching(graph, weight, mwfm, false); + } + + { + MaxWeightedPerfectFractionalMatching 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 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/extern/quadriflow/3rd/lemon-1.3.1/test/gomory_hu_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/gomory_hu_test.cc new file mode 100644 index 00000000000..178f21fec6f --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/gomory_hu_test.cc @@ -0,0 +1,142 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 + +#include "test_tools.h" +#include +#include +#include +#include +#include +#include + +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 CapMap; + typedef concepts::ReadWriteMap CutMap; + + Graph g; + Node n; + CapMap cap; + CutMap cut; + Value v; + int d; + ::lemon::ignore_unused_variable_warning(v,d); + + GomoryHu gh_test(g, cap); + const GomoryHu& + 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 IntEdgeMap; +typedef Graph::NodeMap 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, input). + edgeMap("capacity", capacity).run(); + + GomoryHu ght(graph, capacity); + ght.run(); + + for (NodeIt u(graph); u != INVALID; ++u) { + for (NodeIt v(graph); v != u; ++v) { + Preflow 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::MinCutEdgeIt a(ght, u, v);a!=INVALID;++a) + sum+=capacity[a]; + check(sum == ght.minCutValue(u, v), "Problem with MinCutEdgeIt"); + + sum=0; + for(GomoryHu::MinCutNodeIt n(ght, u, v,true);n!=INVALID;++n) + sum++; + for(GomoryHu::MinCutNodeIt n(ght, u, v,false);n!=INVALID;++n) + sum++; + check(sum == countNodes(graph), "Problem with MinCutNodeIt"); + } + } + + return 0; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/graph_copy_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/graph_copy_test.cc new file mode 100644 index 00000000000..9a7d8155e0f --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/graph_copy_test.cc @@ -0,0 +1,388 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 +#include +#include +#include +#include + +#include "test_tools.h" + +using namespace std; +using namespace lemon; + +template +void digraph_copy_test() { + const int nn = 10; + + // Build a digraph + SmartDigraph from; + SmartDigraph::NodeMap fnm(from); + SmartDigraph::ArcMap fam(from); + SmartDigraph::Node fn = INVALID; + SmartDigraph::Arc fa = INVALID; + + std::vector 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 + GR to; + typename GR::template NodeMap tnm(to); + typename GR::template ArcMap tam(to); + typename GR::Node tn; + typename GR::Arc ta; + + SmartDigraph::NodeMap nr(from); + SmartDigraph::ArcMap er(from); + + typename GR::template NodeMap ncr(to); + typename GR::template ArcMap 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 (typename GR::NodeIt it(to); it != INVALID; ++it) { + check(nr[ncr[it]] == it, "Wrong copy."); + } + + for (typename GR::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."); +} + +template +void graph_copy_test() { + const int nn = 10; + + // Build a graph + SmartGraph from; + SmartGraph::NodeMap fnm(from); + SmartGraph::ArcMap fam(from); + SmartGraph::EdgeMap fem(from); + SmartGraph::Node fn = INVALID; + SmartGraph::Arc fa = INVALID; + SmartGraph::Edge fe = INVALID; + + std::vector 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 + GR to; + typename GR::template NodeMap tnm(to); + typename GR::template ArcMap tam(to); + typename GR::template EdgeMap tem(to); + typename GR::Node tn; + typename GR::Arc ta; + typename GR::Edge te; + + SmartGraph::NodeMap nr(from); + SmartGraph::ArcMap ar(from); + SmartGraph::EdgeMap er(from); + + typename GR::template NodeMap ncr(to); + typename GR::template ArcMap acr(to); + typename GR::template EdgeMap 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 (typename GR::NodeIt it(to); it != INVALID; ++it) { + check(nr[ncr[it]] == it, "Wrong copy."); + } + + for (typename GR::ArcIt it(to); it != INVALID; ++it) { + check(ar[acr[it]] == it, "Wrong copy."); + } + for (typename GR::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."); +} + +template +void bpgraph_copy_test() { + const int nn = 10; + + // Build a graph + SmartBpGraph from; + SmartBpGraph::NodeMap fnm(from); + SmartBpGraph::RedNodeMap frnm(from); + SmartBpGraph::BlueNodeMap fbnm(from); + SmartBpGraph::ArcMap fam(from); + SmartBpGraph::EdgeMap fem(from); + SmartBpGraph::Node fn = INVALID; + SmartBpGraph::RedNode frn = INVALID; + SmartBpGraph::BlueNode fbn = INVALID; + SmartBpGraph::Arc fa = INVALID; + SmartBpGraph::Edge fe = INVALID; + + std::vector frnv; + for (int i = 0; i < nn; ++i) { + SmartBpGraph::RedNode node = from.addRedNode(); + frnv.push_back(node); + fnm[node] = i * i; + frnm[node] = i + i; + if (i == 0) { + fn = node; + frn = node; + } + } + + std::vector fbnv; + for (int i = 0; i < nn; ++i) { + SmartBpGraph::BlueNode node = from.addBlueNode(); + fbnv.push_back(node); + fnm[node] = i * i; + fbnm[node] = i + i; + if (i == 0) fbn = node; + } + + for (int i = 0; i < nn; ++i) { + for (int j = 0; j < nn; ++j) { + SmartBpGraph::Edge edge = from.addEdge(frnv[i], fbnv[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 + GR to; + typename GR::template NodeMap tnm(to); + typename GR::template RedNodeMap trnm(to); + typename GR::template BlueNodeMap tbnm(to); + typename GR::template ArcMap tam(to); + typename GR::template EdgeMap tem(to); + typename GR::Node tn; + typename GR::RedNode trn; + typename GR::BlueNode tbn; + typename GR::Arc ta; + typename GR::Edge te; + + SmartBpGraph::NodeMap nr(from); + SmartBpGraph::RedNodeMap rnr(from); + SmartBpGraph::BlueNodeMap bnr(from); + SmartBpGraph::ArcMap ar(from); + SmartBpGraph::EdgeMap er(from); + + typename GR::template NodeMap ncr(to); + typename GR::template RedNodeMap rncr(to); + typename GR::template BlueNodeMap bncr(to); + typename GR::template ArcMap acr(to); + typename GR::template EdgeMap ecr(to); + + bpGraphCopy(from, to). + nodeMap(fnm, tnm). + redNodeMap(frnm, trnm).blueNodeMap(fbnm, tbnm). + arcMap(fam, tam).edgeMap(fem, tem). + nodeRef(nr).redRef(rnr).blueRef(bnr). + arcRef(ar).edgeRef(er). + nodeCrossRef(ncr).redCrossRef(rncr).blueCrossRef(bncr). + arcCrossRef(acr).edgeCrossRef(ecr). + node(fn, tn).redNode(frn, trn).blueNode(fbn, tbn). + arc(fa, ta).edge(fe, te).run(); + + check(countNodes(from) == countNodes(to), "Wrong copy."); + check(countRedNodes(from) == countRedNodes(to), "Wrong copy."); + check(countBlueNodes(from) == countBlueNodes(to), "Wrong copy."); + check(countEdges(from) == countEdges(to), "Wrong copy."); + check(countArcs(from) == countArcs(to), "Wrong copy."); + + for (SmartBpGraph::NodeIt it(from); it != INVALID; ++it) { + check(ncr[nr[it]] == it, "Wrong copy."); + check(fnm[it] == tnm[nr[it]], "Wrong copy."); + } + + for (SmartBpGraph::RedNodeIt it(from); it != INVALID; ++it) { + check(ncr[nr[it]] == it, "Wrong copy."); + check(fnm[it] == tnm[nr[it]], "Wrong copy."); + check(rnr[it] == nr[it], "Wrong copy."); + check(rncr[rnr[it]] == it, "Wrong copy."); + check(frnm[it] == trnm[rnr[it]], "Wrong copy."); + check(to.red(rnr[it]), "Wrong copy."); + } + + for (SmartBpGraph::BlueNodeIt it(from); it != INVALID; ++it) { + check(ncr[nr[it]] == it, "Wrong copy."); + check(fnm[it] == tnm[nr[it]], "Wrong copy."); + check(bnr[it] == nr[it], "Wrong copy."); + check(bncr[bnr[it]] == it, "Wrong copy."); + check(fbnm[it] == tbnm[bnr[it]], "Wrong copy."); + check(to.blue(bnr[it]), "Wrong copy."); + } + + for (SmartBpGraph::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 (SmartBpGraph::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 (typename GR::NodeIt it(to); it != INVALID; ++it) { + check(nr[ncr[it]] == it, "Wrong copy."); + } + for (typename GR::RedNodeIt it(to); it != INVALID; ++it) { + check(rncr[it] == ncr[it], "Wrong copy."); + check(rnr[rncr[it]] == it, "Wrong copy."); + } + for (typename GR::BlueNodeIt it(to); it != INVALID; ++it) { + check(bncr[it] == ncr[it], "Wrong copy."); + check(bnr[bncr[it]] == it, "Wrong copy."); + } + for (typename GR::ArcIt it(to); it != INVALID; ++it) { + check(ar[acr[it]] == it, "Wrong copy."); + } + for (typename GR::EdgeIt it(to); it != INVALID; ++it) { + check(er[ecr[it]] == it, "Wrong copy."); + } + check(tn == nr[fn], "Wrong copy."); + check(trn == rnr[frn], "Wrong copy."); + check(tbn == bnr[fbn], "Wrong copy."); + check(ta == ar[fa], "Wrong copy."); + check(te == er[fe], "Wrong copy."); + + // Test repeated copy + bpGraphCopy(from, to).run(); + + check(countNodes(from) == countNodes(to), "Wrong copy."); + check(countRedNodes(from) == countRedNodes(to), "Wrong copy."); + check(countBlueNodes(from) == countBlueNodes(to), "Wrong copy."); + check(countEdges(from) == countEdges(to), "Wrong copy."); + check(countArcs(from) == countArcs(to), "Wrong copy."); +} + + +int main() { + digraph_copy_test(); + digraph_copy_test(); + digraph_copy_test(); + graph_copy_test(); + graph_copy_test(); + bpgraph_copy_test(); + bpgraph_copy_test(); + + return 0; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/graph_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/graph_test.cc new file mode 100644 index 00000000000..283b02ef58a --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/graph_test.cc @@ -0,0 +1,603 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 +#include +#include +#include +#include +#include + +#include "test_tools.h" +#include "graph_test.h" + +using namespace lemon; +using namespace lemon::concepts; + +template +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); + ::lemon::ignore_unused_variable_warning(e2,e3); + + 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 +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); + ::lemon::ignore_unused_variable_warning(e1,e3,e4,e5); + + 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 +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); + ::lemon::ignore_unused_variable_warning(e1,e3,e4,e5); + + // 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 +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); + ::lemon::ignore_unused_variable_warning(e1,e2,e3); + + 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(); + + checkConcept, + IDableGraphComponent<> >(); + + checkConcept, + IterableGraphComponent<> >(); + + checkConcept, + MappableGraphComponent<> >(); + } + { // Checking skeleton graph + checkConcept(); + } + { // Checking ListGraph + checkConcept(); + checkConcept, ListGraph>(); + checkConcept, ListGraph>(); + checkConcept, ListGraph>(); + checkConcept, ListGraph>(); + } + { // Checking SmartGraph + checkConcept(); + checkConcept, SmartGraph>(); + checkConcept, SmartGraph>(); + checkConcept, SmartGraph>(); + } + { // Checking FullGraph + checkConcept(); + } + { // Checking GridGraph + checkConcept(); + } + { // Checking HypercubeGraph + checkConcept(); + } +} + +template +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); + ::lemon::ignore_unused_variable_warning(e2); + + 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 +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); + ::lemon::ignore_unused_variable_warning(n); + + 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(); + checkGraphAlter(); + checkGraphErase(); + checkGraphSnapshot(); + checkGraphValidityErase(); + } + { // Checking SmartGraph + checkGraphBuild(); + checkGraphSnapshot(); + checkGraphValidity(); + } + { // 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/extern/quadriflow/3rd/lemon-1.3.1/test/graph_test.h b/extern/quadriflow/3rd/lemon-1.3.1/test/graph_test.h new file mode 100644 index 00000000000..70558b768e8 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/graph_test.h @@ -0,0 +1,421 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 + +#include +#include + +#include "test_tools.h" + +namespace lemon { + + template + void checkGraphNodeList(const Graph &G, int cnt) + { + typename Graph::NodeIt n(G); + for(int i=0;i + void checkGraphRedNodeList(const Graph &G, int cnt) + { + typename Graph::RedNodeIt n(G); + for(int i=0;i + void checkGraphBlueNodeList(const Graph &G, int cnt) + { + typename Graph::BlueNodeIt n(G); + for(int i=0;i + void checkGraphArcList(const Graph &G, int cnt) + { + typename Graph::ArcIt e(G); + for(int i=0;i + void checkGraphOutArcList(const Graph &G, typename Graph::Node n, int cnt) + { + typename Graph::OutArcIt e(G,n); + for(int i=0;i + void checkGraphInArcList(const Graph &G, typename Graph::Node n, int cnt) + { + typename Graph::InArcIt e(G,n); + for(int i=0;i + void checkGraphEdgeList(const Graph &G, int cnt) + { + typename Graph::EdgeIt e(G); + for(int i=0;i + void checkGraphIncEdgeList(const Graph &G, typename Graph::Node n, int cnt) + { + typename Graph::IncEdgeIt e(G,n); + for(int i=0;i + void checkGraphIncEdgeArcLists(const Graph &G, typename Graph::Node n, + int cnt) + { + checkGraphIncEdgeList(G, n, cnt); + checkGraphOutArcList(G, n, cnt); + checkGraphInArcList(G, n, cnt); + } + + template + 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 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 + 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 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 + 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 + void checkNodeIds(const Graph& G) { + typedef typename Graph::Node Node; + std::set 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)); + } + check(G.maxId(Node()) <= G.maxNodeId(), "Wrong maximum id"); + } + + template + void checkRedNodeIds(const Graph& G) { + typedef typename Graph::RedNode RedNode; + std::set values; + for (typename Graph::RedNodeIt n(G); n != INVALID; ++n) { + check(G.red(n), "Wrong partition"); + check(values.find(G.id(n)) == values.end(), "Wrong id"); + check(G.id(n) <= G.maxRedId(), "Wrong maximum id"); + values.insert(G.id(n)); + } + check(G.maxId(RedNode()) == G.maxRedId(), "Wrong maximum id"); + } + + template + void checkBlueNodeIds(const Graph& G) { + typedef typename Graph::BlueNode BlueNode; + std::set values; + for (typename Graph::BlueNodeIt n(G); n != INVALID; ++n) { + check(G.blue(n), "Wrong partition"); + check(values.find(G.id(n)) == values.end(), "Wrong id"); + check(G.id(n) <= G.maxBlueId(), "Wrong maximum id"); + values.insert(G.id(n)); + } + check(G.maxId(BlueNode()) == G.maxBlueId(), "Wrong maximum id"); + } + + template + void checkArcIds(const Graph& G) { + typedef typename Graph::Arc Arc; + std::set 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)); + } + check(G.maxId(Arc()) <= G.maxArcId(), "Wrong maximum id"); + } + + template + void checkEdgeIds(const Graph& G) { + typedef typename Graph::Edge Edge; + std::set 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)); + } + check(G.maxId(Edge()) <= G.maxEdgeId(), "Wrong maximum id"); + } + + template + void checkGraphNodeMap(const Graph& G) { + typedef typename Graph::Node Node; + typedef typename Graph::NodeIt NodeIt; + + typedef typename Graph::template NodeMap 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(12); + // for (NodeIt it(G); it != INVALID; ++it) { + // check(map[it] == 12, "Wrong operator[]."); + // } + } + + template + void checkGraphRedNodeMap(const Graph& G) { + typedef typename Graph::Node Node; + typedef typename Graph::RedNodeIt RedNodeIt; + + typedef typename Graph::template RedNodeMap IntRedNodeMap; + IntRedNodeMap map(G, 42); + for (RedNodeIt it(G); it != INVALID; ++it) { + check(map[it] == 42, "Wrong map constructor."); + } + int s = 0; + for (RedNodeIt 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 (RedNodeIt it(G); it != INVALID; ++it) { + s -= map[it]; + } + check(s == 0, "Wrong sum."); + + // map = constMap(12); + // for (NodeIt it(G); it != INVALID; ++it) { + // check(map[it] == 12, "Wrong operator[]."); + // } + } + + template + void checkGraphBlueNodeMap(const Graph& G) { + typedef typename Graph::Node Node; + typedef typename Graph::BlueNodeIt BlueNodeIt; + + typedef typename Graph::template BlueNodeMap IntBlueNodeMap; + IntBlueNodeMap map(G, 42); + for (BlueNodeIt it(G); it != INVALID; ++it) { + check(map[it] == 42, "Wrong map constructor."); + } + int s = 0; + for (BlueNodeIt 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 (BlueNodeIt it(G); it != INVALID; ++it) { + s -= map[it]; + } + check(s == 0, "Wrong sum."); + + // map = constMap(12); + // for (NodeIt it(G); it != INVALID; ++it) { + // check(map[it] == 12, "Wrong operator[]."); + // } + } + + template + void checkGraphArcMap(const Graph& G) { + typedef typename Graph::Arc Arc; + typedef typename Graph::ArcIt ArcIt; + + typedef typename Graph::template ArcMap 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(12); + // for (ArcIt it(G); it != INVALID; ++it) { + // check(map[it] == 12, "Wrong operator[]."); + // } + } + + template + void checkGraphEdgeMap(const Graph& G) { + typedef typename Graph::Edge Edge; + typedef typename Graph::EdgeIt EdgeIt; + + typedef typename Graph::template EdgeMap 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(12); + // for (EdgeIt it(G); it != INVALID; ++it) { + // check(map[it] == 12, "Wrong operator[]."); + // } + } + + +} //namespace lemon + +#endif diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/graph_utils_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/graph_utils_test.cc new file mode 100644 index 00000000000..19a934a235a --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/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 +#include + +#include +#include +#include +#include + +#include "graph_test.h" +#include "test_tools.h" + +using namespace lemon; + +template +void checkFindArcs() { + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + + { + Digraph digraph; + for (int i = 0; i < 10; ++i) { + digraph.addNode(); + } + RangeIdMap nodes(digraph); + typename RangeIdMap::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 found(digraph, false); + RangeIdMap arcs(digraph); + for (NodeIt src(digraph); src != INVALID; ++src) { + for (NodeIt trg(digraph); trg != INVALID; ++trg) { + for (ConArcIt 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 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 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 al1(fg); + DynArcLookUp al2(fg); + AllArcLookUp 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 +void checkFindEdges() { + TEMPLATE_GRAPH_TYPEDEFS(Graph); + Graph graph; + for (int i = 0; i < 10; ++i) { + graph.addNode(); + } + RangeIdMap nodes(graph); + typename RangeIdMap::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 found(graph, 0); + RangeIdMap edges(graph); + for (NodeIt src(graph); src != INVALID; ++src) { + for (NodeIt trg(graph); trg != INVALID; ++trg) { + for (ConEdgeIt 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 +void checkDeg() +{ + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + + const int nodeNum = 10; + const int arcNum = 100; + Digraph digraph; + InDegMap inDeg(digraph); + OutDegMap outDeg(digraph); + std::vector nodes(nodeNum); + for (int i = 0; i < nodeNum; ++i) { + nodes[i] = digraph.addNode(); + } + std::vector 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 +void checkSnapDeg() +{ + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + + Digraph g; + Node n1=g.addNode(); + Node n2=g.addNode(); + + InDegMap ind(g); + + g.addArc(n1,n2); + + typename Digraph::Snapshot snap(g); + + OutDegMap 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(); + checkFindArcs(); + checkFindEdges(); + checkFindEdges(); + + // Checking In/OutDegMap (and Snapshot feature) + checkDeg(); + checkDeg(); + checkSnapDeg(); + checkSnapDeg(); + + return 0; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/hao_orlin_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/hao_orlin_test.cc new file mode 100644 index 00000000000..c245cb7a727 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/hao_orlin_test.cc @@ -0,0 +1,164 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 + +#include +#include +#include +#include +#include +#include + +#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 CapMap; + typedef concepts::WriteMap CutMap; + + Digraph g; + Node n; + CapMap cap; + CutMap cut; + Value v; + ::lemon::ignore_unused_variable_warning(v); + + HaoOrlin ho_test(g, cap); + const HaoOrlin& + 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 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 cap1(graph), cap2(graph), cap3(graph); + SmartDigraph::NodeMap cut(graph); + + istringstream input(lgf); + digraphReader(graph, input) + .arcMap("cap1", cap1) + .arcMap("cap2", cap2) + .arcMap("cap3", cap3) + .run(); + + { + HaoOrlin 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 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 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 UGraph; + UGraph ugraph(graph); + + { + HaoOrlin > 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 > 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 > 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/extern/quadriflow/3rd/lemon-1.3.1/test/heap_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/heap_test.cc new file mode 100644 index 00000000000..38e15771a8a --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/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-2013 + * 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 +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +void heapSortTest() { + RangeMap map(test_len, -1); + Heap heap(map); + + std::vector 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 +void heapIncreaseTest() { + RangeMap map(test_len, -1); + + Heap heap(map); + + std::vector 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 +void dijkstraHeapTest(const Digraph& digraph, const IntArcMap& length, + Node source) { + + typename Dijkstra::template SetStandardHeap:: + 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 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 IntHeap; + checkConcept, IntHeap>(); + heapSortTest(); + heapIncreaseTest(); + + typedef BinHeap NodeHeap; + checkConcept, NodeHeap>(); + dijkstraHeapTest(digraph, length, source); + } + + // QuadHeap + { + typedef QuadHeap IntHeap; + checkConcept, IntHeap>(); + heapSortTest(); + heapIncreaseTest(); + + typedef QuadHeap NodeHeap; + checkConcept, NodeHeap>(); + dijkstraHeapTest(digraph, length, source); + } + + // DHeap + { + typedef DHeap IntHeap; + checkConcept, IntHeap>(); + heapSortTest(); + heapIncreaseTest(); + + typedef DHeap NodeHeap; + checkConcept, NodeHeap>(); + dijkstraHeapTest(digraph, length, source); + } + + // FibHeap + { + typedef FibHeap IntHeap; + checkConcept, IntHeap>(); + heapSortTest(); + heapIncreaseTest(); + + typedef FibHeap NodeHeap; + checkConcept, NodeHeap>(); + dijkstraHeapTest(digraph, length, source); + } + + // PairingHeap + { + typedef PairingHeap IntHeap; + checkConcept, IntHeap>(); + heapSortTest(); + heapIncreaseTest(); + + typedef PairingHeap NodeHeap; + checkConcept, NodeHeap>(); + dijkstraHeapTest(digraph, length, source); + } + + // RadixHeap + { + typedef RadixHeap IntHeap; + checkConcept, IntHeap>(); + heapSortTest(); + heapIncreaseTest(); + + typedef RadixHeap NodeHeap; + checkConcept, NodeHeap>(); + dijkstraHeapTest(digraph, length, source); + } + + // BinomialHeap + { + typedef BinomialHeap IntHeap; + checkConcept, IntHeap>(); + heapSortTest(); + heapIncreaseTest(); + + typedef BinomialHeap NodeHeap; + checkConcept, NodeHeap>(); + dijkstraHeapTest(digraph, length, source); + } + + // BucketHeap, SimpleBucketHeap + { + typedef BucketHeap IntHeap; + checkConcept, IntHeap>(); + heapSortTest(); + heapIncreaseTest(); + + typedef BucketHeap NodeHeap; + checkConcept, NodeHeap>(); + dijkstraHeapTest(digraph, length, source); + + typedef SimpleBucketHeap SimpleIntHeap; + heapSortTest(); + } + + { + typedef FibHeap IntHeap; + checkConcept, IntHeap>(); + heapSortTest(); + heapIncreaseTest(); + + typedef FibHeap NodeHeap; + checkConcept, NodeHeap>(); + dijkstraHeapTest(digraph, length, source); + } + + { + typedef RadixHeap IntHeap; + checkConcept, IntHeap>(); + heapSortTest(); + heapIncreaseTest(); + + typedef RadixHeap NodeHeap; + checkConcept, NodeHeap>(); + dijkstraHeapTest(digraph, length, source); + } + + { + typedef BucketHeap IntHeap; + checkConcept, IntHeap>(); + heapSortTest(); + heapIncreaseTest(); + + typedef BucketHeap NodeHeap; + checkConcept, NodeHeap>(); + dijkstraHeapTest(digraph, length, source); + } + + + return 0; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/kruskal_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/kruskal_test.cc new file mode 100644 index 00000000000..af36c72fd7c --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/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 +#include + +#include "test_tools.h" +#include +#include +#include + +#include +#include +#include + +using namespace std; +using namespace lemon; + +void checkCompileKruskal() +{ + concepts::WriteMap w; + concepts::WriteMap uw; + + concepts::ReadMap r; + concepts::ReadMap ur; + + concepts::Digraph g; + concepts::Graph ug; + + kruskal(g, r, w); + kruskal(ug, ur, uw); + + std::vector > rs; + std::vector > urs; + + kruskal(g, rs, w); + kruskal(ug, urs, uw); + + std::vector ws; + std::vector 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 ECostMap; + typedef ListGraph::EdgeMap EBoolMap; + + ECostMap edge_cost_map(G, 2); + EBoolMap tree_map(G); + + + //Test with const map. + check(kruskal(G, ConstMap(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 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/extern/quadriflow/3rd/lemon-1.3.1/test/lgf_reader_writer_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/lgf_reader_writer_test.cc new file mode 100644 index 00000000000..25d9423ac0c --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/lgf_reader_writer_test.cc @@ -0,0 +1,578 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 + +#include +#include +#include + +#include +#include +#include + +#include "test_tools.h" + +struct ReaderConverter { + int operator()(const std::string& str) const { + return str.length(); + } +}; + +struct WriterConverter { + std::string operator()(int value) const { + return std::string(value, '*'); + } +}; + +void checkDigraphReaderCompile() { + typedef lemon::concepts::ExtendableDigraphComponent< + lemon::concepts::Digraph> Digraph; + Digraph digraph; + Digraph::NodeMap node_map(digraph); + Digraph::ArcMap arc_map(digraph); + Digraph::Node node; + Digraph::Arc arc; + int attr; + + lemon::DigraphReader reader(digraph, "filename"); + reader.nodeMap("node_map", node_map); + reader.nodeMap("node_map", node_map, ReaderConverter()); + reader.arcMap("arc_map", arc_map); + reader.arcMap("arc_map", arc_map, ReaderConverter()); + reader.attribute("attr", attr); + reader.attribute("attr", attr, ReaderConverter()); + reader.node("node", node); + reader.arc("arc", arc); + + reader.nodes("alt_nodes_caption"); + reader.arcs("alt_arcs_caption"); + reader.attributes("alt_attrs_caption"); + + reader.useNodes(node_map); + reader.useNodes(node_map, WriterConverter()); + reader.useArcs(arc_map); + reader.useArcs(arc_map, WriterConverter()); + + reader.skipNodes(); + reader.skipArcs(); + + reader.run(); + + lemon::DigraphReader reader2(digraph, std::cin); +} + +void checkDigraphWriterCompile() { + typedef lemon::concepts::Digraph Digraph; + Digraph digraph; + Digraph::NodeMap node_map(digraph); + Digraph::ArcMap arc_map(digraph); + Digraph::Node node; + Digraph::Arc arc; + int attr; + + lemon::DigraphWriter writer(digraph, "filename"); + writer.nodeMap("node_map", node_map); + writer.nodeMap("node_map", node_map, WriterConverter()); + writer.arcMap("arc_map", arc_map); + writer.arcMap("arc_map", arc_map, WriterConverter()); + writer.attribute("attr", attr); + writer.attribute("attr", attr, WriterConverter()); + writer.node("node", node); + writer.arc("arc", arc); + + writer.nodes("alt_nodes_caption"); + writer.arcs("alt_arcs_caption"); + writer.attributes("alt_attrs_caption"); + + writer.skipNodes(); + writer.skipArcs(); + + writer.run(); +} + +void checkGraphReaderCompile() { + typedef lemon::concepts::ExtendableGraphComponent< + lemon::concepts::Graph> Graph; + Graph graph; + Graph::NodeMap node_map(graph); + Graph::ArcMap arc_map(graph); + Graph::EdgeMap edge_map(graph); + Graph::Node node; + Graph::Arc arc; + Graph::Edge edge; + int attr; + + lemon::GraphReader reader(graph, "filename"); + reader.nodeMap("node_map", node_map); + reader.nodeMap("node_map", node_map, ReaderConverter()); + reader.arcMap("arc_map", arc_map); + reader.arcMap("arc_map", arc_map, ReaderConverter()); + reader.edgeMap("edge_map", edge_map); + reader.edgeMap("edge_map", edge_map, ReaderConverter()); + reader.attribute("attr", attr); + reader.attribute("attr", attr, ReaderConverter()); + reader.node("node", node); + reader.arc("arc", arc); + + reader.nodes("alt_nodes_caption"); + reader.edges("alt_edges_caption"); + reader.attributes("alt_attrs_caption"); + + reader.useNodes(node_map); + reader.useNodes(node_map, WriterConverter()); + reader.useEdges(edge_map); + reader.useEdges(edge_map, WriterConverter()); + + reader.skipNodes(); + reader.skipEdges(); + + reader.run(); + + lemon::GraphReader reader2(graph, std::cin); +} + +void checkGraphWriterCompile() { + typedef lemon::concepts::Graph Graph; + Graph graph; + Graph::NodeMap node_map(graph); + Graph::ArcMap arc_map(graph); + Graph::EdgeMap edge_map(graph); + Graph::Node node; + Graph::Arc arc; + Graph::Edge edge; + int attr; + + lemon::GraphWriter writer(graph, "filename"); + writer.nodeMap("node_map", node_map); + writer.nodeMap("node_map", node_map, WriterConverter()); + writer.arcMap("arc_map", arc_map); + writer.arcMap("arc_map", arc_map, WriterConverter()); + writer.edgeMap("edge_map", edge_map); + writer.edgeMap("edge_map", edge_map, WriterConverter()); + writer.attribute("attr", attr); + writer.attribute("attr", attr, WriterConverter()); + writer.node("node", node); + writer.arc("arc", arc); + writer.edge("edge", edge); + + writer.nodes("alt_nodes_caption"); + writer.edges("alt_edges_caption"); + writer.attributes("alt_attrs_caption"); + + writer.skipNodes(); + writer.skipEdges(); + + writer.run(); + + lemon::GraphWriter writer2(graph, std::cout); +} + +void checkBpGraphReaderCompile() { + typedef lemon::concepts::ExtendableBpGraphComponent< + lemon::concepts::BpGraph> BpGraph; + BpGraph graph; + BpGraph::NodeMap node_map(graph); + BpGraph::RedNodeMap red_node_map(graph); + BpGraph::BlueNodeMap blue_node_map(graph); + BpGraph::ArcMap arc_map(graph); + BpGraph::EdgeMap edge_map(graph); + BpGraph::Node node; + BpGraph::RedNode red_node; + BpGraph::BlueNode blue_node; + BpGraph::Arc arc; + BpGraph::Edge edge; + int attr; + + lemon::BpGraphReader reader(graph, "filename"); + reader.nodeMap("node_map", node_map); + reader.nodeMap("node_map", node_map, ReaderConverter()); + reader.redNodeMap("red_node_map", red_node_map); + reader.redNodeMap("red_node_map", red_node_map, ReaderConverter()); + reader.blueNodeMap("blue_node_map", blue_node_map); + reader.blueNodeMap("blue_node_map", blue_node_map, ReaderConverter()); + reader.arcMap("arc_map", arc_map); + reader.arcMap("arc_map", arc_map, ReaderConverter()); + reader.edgeMap("edge_map", edge_map); + reader.edgeMap("edge_map", edge_map, ReaderConverter()); + reader.attribute("attr", attr); + reader.attribute("attr", attr, ReaderConverter()); + reader.node("node", node); + reader.redNode("red_node", red_node); + reader.blueNode("blue_node", blue_node); + reader.arc("arc", arc); + + reader.nodes("alt_nodes_caption"); + reader.edges("alt_edges_caption"); + reader.attributes("alt_attrs_caption"); + + reader.useNodes(node_map); + reader.useNodes(node_map, WriterConverter()); + reader.useEdges(edge_map); + reader.useEdges(edge_map, WriterConverter()); + + reader.skipNodes(); + reader.skipEdges(); + + reader.run(); + + lemon::BpGraphReader reader2(graph, std::cin); +} + +void checkBpGraphWriterCompile() { + typedef lemon::concepts::BpGraph BpGraph; + BpGraph graph; + BpGraph::NodeMap node_map(graph); + BpGraph::RedNodeMap red_node_map(graph); + BpGraph::BlueNodeMap blue_node_map(graph); + BpGraph::ArcMap arc_map(graph); + BpGraph::EdgeMap edge_map(graph); + BpGraph::Node node; + BpGraph::RedNode red_node; + BpGraph::BlueNode blue_node; + BpGraph::Arc arc; + BpGraph::Edge edge; + int attr; + + lemon::BpGraphWriter writer(graph, "filename"); + writer.nodeMap("node_map", node_map); + writer.nodeMap("node_map", node_map, WriterConverter()); + writer.redNodeMap("red_node_map", red_node_map); + writer.redNodeMap("red_node_map", red_node_map, WriterConverter()); + writer.blueNodeMap("blue_node_map", blue_node_map); + writer.blueNodeMap("blue_node_map", blue_node_map, WriterConverter()); + writer.arcMap("arc_map", arc_map); + writer.arcMap("arc_map", arc_map, WriterConverter()); + writer.edgeMap("edge_map", edge_map); + writer.edgeMap("edge_map", edge_map, WriterConverter()); + writer.attribute("attr", attr); + writer.attribute("attr", attr, WriterConverter()); + writer.node("node", node); + writer.redNode("red_node", red_node); + writer.blueNode("blue_node", blue_node); + writer.arc("arc", arc); + + writer.nodes("alt_nodes_caption"); + writer.edges("alt_edges_caption"); + writer.attributes("alt_attrs_caption"); + + writer.skipNodes(); + writer.skipEdges(); + + writer.run(); + + lemon::BpGraphWriter writer2(graph, std::cout); +} + +void checkDigraphReaderWriter() { + typedef lemon::SmartDigraph Digraph; + Digraph 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(n2, n3); + + Digraph::NodeMap node_map(digraph); + node_map[n1] = 11; + node_map[n2] = 12; + node_map[n3] = 13; + + Digraph::ArcMap arc_map(digraph); + arc_map[a1] = 21; + arc_map[a2] = 22; + + int attr = 100; + + std::ostringstream os; + lemon::DigraphWriter writer(digraph, os); + + writer.nodeMap("node_map1", node_map); + writer.nodeMap("node_map2", node_map, WriterConverter()); + writer.arcMap("arc_map1", arc_map); + writer.arcMap("arc_map2", arc_map, WriterConverter()); + writer.node("node", n2); + writer.arc("arc", a1); + writer.attribute("attr1", attr); + writer.attribute("attr2", attr, WriterConverter()); + + writer.run(); + + typedef lemon::ListDigraph ExpDigraph; + ExpDigraph exp_digraph; + ExpDigraph::NodeMap exp_node_map1(exp_digraph); + ExpDigraph::NodeMap exp_node_map2(exp_digraph); + ExpDigraph::ArcMap exp_arc_map1(exp_digraph); + ExpDigraph::ArcMap exp_arc_map2(exp_digraph); + ExpDigraph::Node exp_n2; + ExpDigraph::Arc exp_a1; + int exp_attr1; + int exp_attr2; + + std::istringstream is(os.str()); + lemon::DigraphReader reader(exp_digraph, is); + + reader.nodeMap("node_map1", exp_node_map1); + reader.nodeMap("node_map2", exp_node_map2, ReaderConverter()); + reader.arcMap("arc_map1", exp_arc_map1); + reader.arcMap("arc_map2", exp_arc_map2, ReaderConverter()); + reader.node("node", exp_n2); + reader.arc("arc", exp_a1); + reader.attribute("attr1", exp_attr1); + reader.attribute("attr2", exp_attr2, ReaderConverter()); + + reader.run(); + + check(lemon::countNodes(exp_digraph) == 3, "Wrong number of nodes"); + check(lemon::countArcs(exp_digraph) == 2, "Wrong number of arcs"); + check(exp_node_map1[exp_n2] == 12, "Wrong map value"); + check(exp_node_map2[exp_n2] == 12, "Wrong map value"); + check(exp_arc_map1[exp_a1] == 21, "Wrong map value"); + check(exp_arc_map2[exp_a1] == 21, "Wrong map value"); + check(exp_attr1 == 100, "Wrong attr value"); + check(exp_attr2 == 100, "Wrong attr value"); +} + +void checkGraphReaderWriter() { + typedef lemon::SmartGraph Graph; + Graph graph; + Graph::Node n1 = graph.addNode(); + Graph::Node n2 = graph.addNode(); + Graph::Node n3 = graph.addNode(); + + Graph::Edge e1 = graph.addEdge(n1, n2); + Graph::Edge e2 = graph.addEdge(n2, n3); + + Graph::NodeMap node_map(graph); + node_map[n1] = 11; + node_map[n2] = 12; + node_map[n3] = 13; + + Graph::EdgeMap edge_map(graph); + edge_map[e1] = 21; + edge_map[e2] = 22; + + Graph::ArcMap arc_map(graph); + arc_map[graph.direct(e1, true)] = 211; + arc_map[graph.direct(e1, false)] = 212; + arc_map[graph.direct(e2, true)] = 221; + arc_map[graph.direct(e2, false)] = 222; + + int attr = 100; + + std::ostringstream os; + lemon::GraphWriter writer(graph, os); + + writer.nodeMap("node_map1", node_map); + writer.nodeMap("node_map2", node_map, WriterConverter()); + writer.edgeMap("edge_map1", edge_map); + writer.edgeMap("edge_map2", edge_map, WriterConverter()); + writer.arcMap("arc_map1", arc_map); + writer.arcMap("arc_map2", arc_map, WriterConverter()); + writer.node("node", n2); + writer.edge("edge", e1); + writer.arc("arc", graph.direct(e1, false)); + writer.attribute("attr1", attr); + writer.attribute("attr2", attr, WriterConverter()); + + writer.run(); + + typedef lemon::ListGraph ExpGraph; + ExpGraph exp_graph; + ExpGraph::NodeMap exp_node_map1(exp_graph); + ExpGraph::NodeMap exp_node_map2(exp_graph); + ExpGraph::EdgeMap exp_edge_map1(exp_graph); + ExpGraph::EdgeMap exp_edge_map2(exp_graph); + ExpGraph::ArcMap exp_arc_map1(exp_graph); + ExpGraph::ArcMap exp_arc_map2(exp_graph); + ExpGraph::Node exp_n2; + ExpGraph::Edge exp_e1; + ExpGraph::Arc exp_a1; + int exp_attr1; + int exp_attr2; + + std::istringstream is(os.str()); + lemon::GraphReader reader(exp_graph, is); + + reader.nodeMap("node_map1", exp_node_map1); + reader.nodeMap("node_map2", exp_node_map2, ReaderConverter()); + reader.edgeMap("edge_map1", exp_edge_map1); + reader.edgeMap("edge_map2", exp_edge_map2, ReaderConverter()); + reader.arcMap("arc_map1", exp_arc_map1); + reader.arcMap("arc_map2", exp_arc_map2, ReaderConverter()); + reader.node("node", exp_n2); + reader.edge("edge", exp_e1); + reader.arc("arc", exp_a1); + reader.attribute("attr1", exp_attr1); + reader.attribute("attr2", exp_attr2, ReaderConverter()); + + reader.run(); + + check(lemon::countNodes(exp_graph) == 3, "Wrong number of nodes"); + check(lemon::countEdges(exp_graph) == 2, "Wrong number of edges"); + check(lemon::countArcs(exp_graph) == 4, "Wrong number of arcs"); + check(exp_node_map1[exp_n2] == 12, "Wrong map value"); + check(exp_node_map2[exp_n2] == 12, "Wrong map value"); + check(exp_edge_map1[exp_e1] == 21, "Wrong map value"); + check(exp_edge_map2[exp_e1] == 21, "Wrong map value"); + check(exp_arc_map1[exp_a1] == 212, "Wrong map value"); + check(exp_arc_map2[exp_a1] == 212, "Wrong map value"); + check(exp_attr1 == 100, "Wrong attr value"); + check(exp_attr2 == 100, "Wrong attr value"); +} + +void checkBpGraphReaderWriter() { + typedef lemon::SmartBpGraph Graph; + Graph graph; + Graph::RedNode rn1 = graph.addRedNode(); + Graph::RedNode rn2 = graph.addRedNode(); + Graph::RedNode rn3 = graph.addRedNode(); + Graph::BlueNode bn1 = graph.addBlueNode(); + Graph::BlueNode bn2 = graph.addBlueNode(); + Graph::Node n = bn1; + + Graph::Edge e1 = graph.addEdge(rn1, bn1); + Graph::Edge e2 = graph.addEdge(rn2, bn1); + + Graph::NodeMap node_map(graph); + node_map[rn1] = 11; + node_map[rn2] = 12; + node_map[rn3] = 13; + node_map[bn1] = 14; + node_map[bn2] = 15; + + Graph::NodeMap red_node_map(graph); + red_node_map[rn1] = 411; + red_node_map[rn2] = 412; + red_node_map[rn3] = 413; + + Graph::NodeMap blue_node_map(graph); + blue_node_map[bn1] = 414; + blue_node_map[bn2] = 415; + + Graph::EdgeMap edge_map(graph); + edge_map[e1] = 21; + edge_map[e2] = 22; + + Graph::ArcMap arc_map(graph); + arc_map[graph.direct(e1, true)] = 211; + arc_map[graph.direct(e1, false)] = 212; + arc_map[graph.direct(e2, true)] = 221; + arc_map[graph.direct(e2, false)] = 222; + + int attr = 100; + + std::ostringstream os; + lemon::BpGraphWriter writer(graph, os); + + writer.nodeMap("node_map1", node_map); + writer.nodeMap("node_map2", node_map, WriterConverter()); + writer.nodeMap("red_node_map1", red_node_map); + writer.nodeMap("red_node_map2", red_node_map, WriterConverter()); + writer.nodeMap("blue_node_map1", blue_node_map); + writer.nodeMap("blue_node_map2", blue_node_map, WriterConverter()); + writer.edgeMap("edge_map1", edge_map); + writer.edgeMap("edge_map2", edge_map, WriterConverter()); + writer.arcMap("arc_map1", arc_map); + writer.arcMap("arc_map2", arc_map, WriterConverter()); + writer.node("node", n); + writer.redNode("red_node", rn1); + writer.blueNode("blue_node", bn2); + writer.edge("edge", e1); + writer.arc("arc", graph.direct(e1, false)); + writer.attribute("attr1", attr); + writer.attribute("attr2", attr, WriterConverter()); + + writer.run(); + + typedef lemon::ListBpGraph ExpGraph; + ExpGraph exp_graph; + ExpGraph::NodeMap exp_node_map1(exp_graph); + ExpGraph::NodeMap exp_node_map2(exp_graph); + ExpGraph::RedNodeMap exp_red_node_map1(exp_graph); + ExpGraph::RedNodeMap exp_red_node_map2(exp_graph); + ExpGraph::BlueNodeMap exp_blue_node_map1(exp_graph); + ExpGraph::BlueNodeMap exp_blue_node_map2(exp_graph); + ExpGraph::EdgeMap exp_edge_map1(exp_graph); + ExpGraph::EdgeMap exp_edge_map2(exp_graph); + ExpGraph::ArcMap exp_arc_map1(exp_graph); + ExpGraph::ArcMap exp_arc_map2(exp_graph); + ExpGraph::Node exp_n; + ExpGraph::RedNode exp_rn1; + ExpGraph::BlueNode exp_bn2; + ExpGraph::Edge exp_e1; + ExpGraph::Arc exp_a1; + int exp_attr1; + int exp_attr2; + + std::istringstream is(os.str()); + lemon::BpGraphReader reader(exp_graph, is); + + reader.nodeMap("node_map1", exp_node_map1); + reader.nodeMap("node_map2", exp_node_map2, ReaderConverter()); + reader.redNodeMap("red_node_map1", exp_red_node_map1); + reader.redNodeMap("red_node_map2", exp_red_node_map2, ReaderConverter()); + reader.blueNodeMap("blue_node_map1", exp_blue_node_map1); + reader.blueNodeMap("blue_node_map2", exp_blue_node_map2, ReaderConverter()); + reader.edgeMap("edge_map1", exp_edge_map1); + reader.edgeMap("edge_map2", exp_edge_map2, ReaderConverter()); + reader.arcMap("arc_map1", exp_arc_map1); + reader.arcMap("arc_map2", exp_arc_map2, ReaderConverter()); + reader.node("node", exp_n); + reader.redNode("red_node", exp_rn1); + reader.blueNode("blue_node", exp_bn2); + reader.edge("edge", exp_e1); + reader.arc("arc", exp_a1); + reader.attribute("attr1", exp_attr1); + reader.attribute("attr2", exp_attr2, ReaderConverter()); + + reader.run(); + + check(lemon::countNodes(exp_graph) == 5, "Wrong number of nodes"); + check(lemon::countRedNodes(exp_graph) == 3, "Wrong number of red nodes"); + check(lemon::countBlueNodes(exp_graph) == 2, "Wrong number of blue nodes"); + check(lemon::countEdges(exp_graph) == 2, "Wrong number of edges"); + check(lemon::countArcs(exp_graph) == 4, "Wrong number of arcs"); + check(exp_node_map1[exp_n] == 14, "Wrong map value"); + check(exp_node_map2[exp_n] == 14, "Wrong map value"); + check(exp_red_node_map1[exp_rn1] == 411, "Wrong map value"); + check(exp_red_node_map2[exp_rn1] == 411, "Wrong map value"); + check(exp_blue_node_map1[exp_bn2] == 415, "Wrong map value"); + check(exp_blue_node_map2[exp_bn2] == 415, "Wrong map value"); + check(exp_edge_map1[exp_e1] == 21, "Wrong map value"); + check(exp_edge_map2[exp_e1] == 21, "Wrong map value"); + check(exp_arc_map1[exp_a1] == 212, "Wrong map value"); + check(exp_arc_map2[exp_a1] == 212, "Wrong map value"); + check(exp_attr1 == 100, "Wrong attr value"); + check(exp_attr2 == 100, "Wrong attr value"); +} + + +int main() { + { // Check digrpah + checkDigraphReaderWriter(); + } + { // Check graph + checkGraphReaderWriter(); + } + { // Check bipartite graph + checkBpGraphReaderWriter(); + } + return 0; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/lgf_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/lgf_test.cc new file mode 100644 index 00000000000..839afb15242 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/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-2013 + * 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 +#include +#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 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 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/extern/quadriflow/3rd/lemon-1.3.1/test/lp_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/lp_test.cc new file mode 100644 index 00000000000..914a37643df --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/lp_test.cc @@ -0,0 +1,470 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 +#include +#include "test_tools.h" +#include + +#include + +#ifdef LEMON_HAVE_GLPK +#include +#endif + +#ifdef LEMON_HAVE_CPLEX +#include +#endif + +#ifdef LEMON_HAVE_SOPLEX +#include +#endif + +#ifdef LEMON_HAVE_CLP +#include +#endif + +#ifdef LEMON_HAVE_LP +#include +#endif +using namespace lemon; + +int countCols(LpBase & lp) { + int count=0; + for (LpBase::ColIt c(lp); c!=INVALID; ++c) ++count; + return count; +} + +int countRows(LpBase & lp) { + int count=0; + for (LpBase::RowIt r(lp); r!=INVALID; ++r) ++count; + return count; +} + + +void lpTest(LpSolver& lp) +{ + + typedef LpSolver LP; + + // Test LpBase::clear() + check(countRows(lp)==0, "Wrong number of rows"); + check(countCols(lp)==0, "Wrong number of cols"); + lp.addCol(); lp.addRow(); lp.addRow(); + check(countRows(lp)==2, "Wrong number of rows"); + check(countCols(lp)==1, "Wrong number of cols"); + lp.clear(); + check(countRows(lp)==0, "Wrong number of rows"); + check(countCols(lp)==0, "Wrong number of cols"); + lp.addCol(); lp.addCol(); lp.addCol(); lp.addRow(); + check(countRows(lp)==1, "Wrong number of rows"); + check(countCols(lp)==3, "Wrong number of cols"); + lp.clear(); + + std::vector 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 y(10); + lp.addColSet(y); + + lp.colLowerBound(y,1); + lp.colUpperBound(y,1); + lp.colBounds(y,1,2); + + std::map 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; +#if ( __GNUC__ == 4 ) && ( __GNUC_MINOR__ == 3 ) + c2 = ( -3 <= v ) <= 4; +#else + c2 = -3 <= v <= 4; +#endif + + } + + 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(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; + + 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<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 +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_LP + { + Lp lp,lp2; + lpTest(lp); + aTest(lp2); + cloneTest(); + } +#endif + +#ifdef LEMON_HAVE_GLPK + { + GlpkLp lp_glpk1,lp_glpk2; + lpTest(lp_glpk1); + aTest(lp_glpk2); + cloneTest(); + } +#endif + +#ifdef LEMON_HAVE_CPLEX + try { + CplexLp lp_cplex1,lp_cplex2; + lpTest(lp_cplex1); + aTest(lp_cplex2); + cloneTest(); + } 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(); + } +#endif + +#ifdef LEMON_HAVE_CLP + { + ClpLp lp_clp1,lp_clp2; + lpTest(lp_clp1); + aTest(lp_clp2); + cloneTest(); + } +#endif + + return 0; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/maps_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/maps_test.cc new file mode 100644 index 00000000000..5502e046fde --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/maps_test.cc @@ -0,0 +1,1022 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +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 +class Sum { + T& _sum; +public: + Sum(T& sum) : _sum(sum) {} + void operator()(const T& t) { _sum += t; } +}; + +typedef ReadMap DoubleMap; +typedef ReadWriteMap DoubleWriteMap; +typedef ReferenceMap DoubleRefMap; + +typedef ReadMap BoolMap; +typedef ReadWriteMap BoolWriteMap; +typedef ReferenceMap BoolRefMap; + +int main() +{ + // Map concepts + checkConcept, ReadMap >(); + checkConcept, ReadMap >(); + checkConcept, WriteMap >(); + checkConcept, WriteMap >(); + checkConcept, ReadWriteMap >(); + checkConcept, ReadWriteMap >(); + checkConcept, ReferenceMap >(); + checkConcept, ReferenceMap >(); + + // NullMap + { + checkConcept, NullMap >(); + NullMap map1; + NullMap map2 = map1; + ::lemon::ignore_unused_variable_warning(map2); + map1 = nullMap(); + } + + // ConstMap + { + checkConcept, ConstMap >(); + checkConcept, ConstMap >(); + ConstMap map1; + ConstMap map2 = B(); + ConstMap map3 = map1; + ::lemon::ignore_unused_variable_warning(map2,map3); + + map1 = constMap(B()); + map1 = constMap(); + map1.setAll(B()); + ConstMap map4(C(1)); + ConstMap map5 = map4; + ::lemon::ignore_unused_variable_warning(map5); + + map4 = constMap(C(2)); + map4.setAll(C(3)); + + checkConcept, ConstMap >(); + check(constMap(10)[A()] == 10, "Something is wrong with ConstMap"); + + checkConcept, ConstMap > >(); + ConstMap > map6; + ConstMap > map7 = map6; + map6 = constMap(); + map7 = constMap >(); + check(map6[A()] == 10 && map7[A()] == 10, + "Something is wrong with ConstMap"); + } + + // IdentityMap + { + checkConcept, IdentityMap >(); + IdentityMap map1; + IdentityMap map2 = map1; + ::lemon::ignore_unused_variable_warning(map2); + + map1 = identityMap(); + + checkConcept, IdentityMap >(); + check(identityMap()[1.0] == 1.0 && + identityMap()[3.14] == 3.14, + "Something is wrong with IdentityMap"); + } + + // RangeMap + { + checkConcept, RangeMap >(); + RangeMap map1; + RangeMap map2(10); + RangeMap map3(10,B()); + RangeMap map4 = map1; + RangeMap map5 = rangeMap(); + RangeMap map6 = rangeMap(10); + RangeMap map7 = rangeMap(10,B()); + + checkConcept< ReferenceMap, + RangeMap >(); + std::vector v(10, 0); + v[5] = 100; + RangeMap map8(v); + RangeMap map9 = rangeMap(v); + check(map9.size() == 10 && map9[2] == 0 && map9[5] == 100, + "Something is wrong with RangeMap"); + } + + // SparseMap + { + checkConcept, SparseMap >(); + SparseMap map1; + SparseMap map2 = B(); + SparseMap map3 = sparseMap(); + SparseMap map4 = sparseMap(B()); + + checkConcept< ReferenceMap, + SparseMap >(); + std::map m; + SparseMap map5(m); + SparseMap map6(m,10); + SparseMap map7 = sparseMap(m); + SparseMap 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 > CompMap; + checkConcept, CompMap>(); + CompMap map1 = CompMap(DoubleMap(),ReadMap()); + ::lemon::ignore_unused_variable_warning(map1); + CompMap map2 = composeMap(DoubleMap(), ReadMap()); + ::lemon::ignore_unused_variable_warning(map2); + + SparseMap m1(false); m1[3.14] = true; + RangeMap 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 > CombMap; + checkConcept, CombMap>(); + CombMap map1 = CombMap(DoubleMap(), DoubleMap()); + ::lemon::ignore_unused_variable_warning(map1); + CombMap map2 = combineMap(DoubleMap(), DoubleMap(), std::plus()); + ::lemon::ignore_unused_variable_warning(map2); + + check(combineMap(constMap(), identityMap(), &binc)[B()] == 3, + "Something is wrong with CombineMap"); + } + + // FunctorToMap, MapToFunctor + { + checkConcept, FunctorToMap >(); + checkConcept, FunctorToMap >(); + FunctorToMap map1; + FunctorToMap map2 = FunctorToMap(F()); + ::lemon::ignore_unused_variable_warning(map2); + + B b = functorToMap(F())[A()]; + ::lemon::ignore_unused_variable_warning(b); + + checkConcept, MapToFunctor > >(); + MapToFunctor > map = + MapToFunctor >(ReadMap()); + ::lemon::ignore_unused_variable_warning(map); + + check(functorToMap(&func)[A()] == 3, + "Something is wrong with FunctorToMap"); + check(mapToFunctor(constMap(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(2)))[A()] == 2, + "Something is wrong with FunctorToMap or MapToFunctor"); + } + + // ConvertMap + { + checkConcept, + ConvertMap, double> >(); + ConvertMap, int> map1(rangeMap(1, true)); + ::lemon::ignore_unused_variable_warning(map1); + ConvertMap, int> map2 = convertMap(rangeMap(2, false)); + ::lemon::ignore_unused_variable_warning(map2); + + } + + // ForkMap + { + checkConcept >(); + + typedef RangeMap RM; + typedef SparseMap SM; + RM m1(10, -1); + SM m2(-1); + checkConcept, ForkMap >(); + checkConcept, ForkMap >(); + ForkMap map1(m1,m2); + ForkMap 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 >(); + checkConcept >(); + checkConcept >(); + checkConcept >(); + + ConstMap c1(1.0), c2(3.14); + IdentityMap im; + ConvertMap, 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 >(); + checkConcept >(); + checkConcept >(); + checkConcept >(); + checkConcept >(); + checkConcept >(); + checkConcept >(); + + 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 >(); + checkConcept >(); + checkConcept >(); + checkConcept >(); + checkConcept >(); + checkConcept >(); + checkConcept >(); + checkConcept >(); + + TrueMap tm; + FalseMap fm; + RangeMap 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 cm(2.0); + IdentityMap im; + ConvertMap, 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 vec; + checkConcept, LoggerBoolMap >(); + checkConcept, + LoggerBoolMap > >(); + + vec v1; + vec v2(10); + LoggerBoolMap > + map1(std::back_inserter(v1)); + LoggerBoolMap 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::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 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 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, IdMap >(); + checkConcept, IdMap >(); + checkConcept, RangeIdMap >(); + checkConcept, RangeIdMap >(); + + Graph gr; + IdMap nmap(gr); + IdMap amap(gr); + RangeIdMap nrmap(gr); + RangeIdMap 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, SourceMap >(); + checkConcept, TargetMap >(); + checkConcept, ForwardMap >(); + checkConcept, BackwardMap >(); + checkConcept, InDegMap >(); + checkConcept, OutDegMap >(); + + 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(true))), + targetMap(orienter(gr, constMap(false)))), + "Wrong SourceMap or TargetMap"); + + typedef Orienter > Digraph; + ConstMap true_edge_map(true); + Digraph dgr(gr, true_edge_map); + OutDegMap odm(dgr); + InDegMap 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, + CrossRefMap >(); + checkConcept, + CrossRefMap >(); + checkConcept, + CrossRefMap >(); + + Graph gr; + typedef CrossRefMap 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, + CrossRefMap >(); + + Graph gr; + typedef CrossRefMap 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 Ibm; + checkConcept, Ibm>(); + + const int num = 10; + Graph g; + Ibm map0(g, true); + std::vector 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(it)], "Wrong TrueIt"); + ++n; + } + check(n == num, "Wrong number"); + + n = 0; + for (Ibm::ItemIt it(map1, true); it != INVALID; ++it) { + check(map1[static_cast(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(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(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(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(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(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 Iim; + + checkConcept, Iim>(); + + const int num = 10; + Graph g; + Iim map0(g, 0); + std::vector 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(it) == items[i], "Wrong value"); + ++it; + check(static_cast(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(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(it)] == 1, "Wrong value"); + ++n; + } + check(n == num, "Wrong number"); + + } + + // Iterable value map + { + typedef SmartGraph Graph; + typedef SmartGraph::Node Item; + typedef IterableValueMap Ivm; + + checkConcept, Ivm>(); + + const int num = 10; + Graph g; + Ivm map0(g, 0.0); + std::vector 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(i)); + } + check(distance(map1.beginValue(), map1.endValue()) == num, "Wrong size"); + + for (int i = 0; i < num; ++i) { + Ivm::ItemIt it(map1, static_cast(i)); + check(static_cast(it) == items[i], "Wrong value"); + ++it; + check(static_cast(it) == INVALID, "Wrong value"); + } + + for (Ivm::ValueIt vit = map1.beginValue(); + vit != map1.endValue(); ++vit) { + check(map1[static_cast(Ivm::ItemIt(map1, *vit))] == *vit, + "Wrong ValueIt"); + } + + for (int i = 0; i < num; ++i) { + map1.set(items[i], static_cast(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(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(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 map1(g); + SmartDigraph::ArcMap map2(g); + ConstMap cmap1 = A(); + ConstMap 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()) == n3, "Wrong mapMin()"); + check(mapMax(g, map1, std::greater()) == 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()) == a4, "Wrong mapMin()"); + check(mapMax(g, map2, std::greater()) == a2, "Wrong mapMax()"); + check(mapMinValue(g, map2, std::greater()) == 'c', + "Wrong mapMinValue()"); + check(mapMaxValue(g, map2, std::greater()) == '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(7)) == n2, + "Wrong mapFindIf()"); + check(mapFindIf(g, map1, Less(5)) == INVALID, + "Wrong mapFindIf()"); + check(mapFindIf(g, map2, Less('d')) == ArcIt(g), + "Wrong mapFindIf()"); + check(mapFindIf(g, map2, Less('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(11)) == 2, + "Wrong mapCountIf()"); + check(mapCountIf(g, map1, Less(13)) == 3, + "Wrong mapCountIf()"); + check(mapCountIf(g, map1, Less(5)) == 0, + "Wrong mapCountIf()"); + check(mapCountIf(g, map2, Less('d')) == 4, + "Wrong mapCountIf()"); + check(mapCountIf(g, map2, Less('c')) == 3, + "Wrong mapCountIf()"); + check(mapCountIf(g, map2, Less('a')) == 0, + "Wrong mapCountIf()"); + + // MapIt, ConstMapIt +/* +These tests can be used after applying bugfix #330 + typedef SmartDigraph::NodeMap::MapIt MapIt; + typedef SmartDigraph::NodeMap::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(sum)); + check(sum == 27, "Wrong NodeMap<>::MapIt"); + std::for_each(ConstMapIt(map1), ConstMapIt(INVALID), Sum(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 map3(g, 0); + SmartDigraph::ArcMap 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 ug(g); + Undirector::EdgeMap umap1(ug, 'x'); + Undirector::ArcMap 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(2)), "Wrong mapCompare()"); + mapFill(g, map1, 2); + check(mapCompare(g, constMap(2), map1), "Wrong mapFill()"); + + check(!mapCompare(g, map2, constMap('z')), "Wrong mapCompare()"); + mapCopy(g, constMap('z'), map2); + check(mapCompare(g, constMap('z'), map2), "Wrong mapCopy()"); + } + + return 0; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/matching_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/matching_test.cc new file mode 100644 index 00000000000..dcb1d3b5752 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/matching_test.cc @@ -0,0 +1,449 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#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 MatMap; + + Graph g; + Node n; + Edge e; + MatMap mat(g); + + MaxMatching mat_test(g); + const MaxMatching& + 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::MatchingMap& mmap = + const_mat_test.matchingMap(); + e = mmap[n]; + const_mat_test.mate(n); + + MaxMatching::Status stat = + const_mat_test.status(n); + ::lemon::ignore_unused_variable_warning(stat); + const MaxMatching::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 WeightMap; + + Graph g; + Node n; + Edge e; + WeightMap w(g); + + MaxWeightedMatching mat_test(g, w); + const MaxWeightedMatching& + 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::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 WeightMap; + + Graph g; + Node n; + Edge e; + WeightMap w(g); + + MaxWeightedPerfectMatching mat_test(g, w); + const MaxWeightedPerfectMatching& + 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::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& mm) { + int num = 0; + + IntNodeMap comp_index(graph); + UnionFind comp(comp_index); + + int barrier_num = 0; + + for (NodeIt n(graph); n != INVALID; ++n) { + check(mm.status(n) == MaxMatching::EVEN || + mm.matching(n) != INVALID, "Wrong Gallai-Edmonds decomposition"); + if (mm.status(n) == MaxMatching::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::EVEN || + mm.status(graph.v(e)) != MaxMatching::MATCHED, + "Wrong Gallai-Edmonds decomposition"); + + check(mm.status(graph.v(e)) != MaxMatching::EVEN || + mm.status(graph.u(e)) != MaxMatching::MATCHED, + "Wrong Gallai-Edmonds decomposition"); + + if (mm.status(graph.u(e)) != MaxMatching::ODD && + mm.status(graph.v(e)) != MaxMatching::ODD) { + comp.join(graph.u(e), graph.v(e)); + } + } + + std::set comp_root; + int odd_comp_num = 0; + for (NodeIt n(graph); n != INVALID; ++n) { + if (mm.status(n) != MaxMatching::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& weight, + const MaxWeightedMatching& 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::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& weight, + const MaxWeightedPerfectMatching& 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::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 weight(graph); + + istringstream lgfs(lgf[i]); + graphReader(graph, lgfs). + edgeMap("weight", weight).run(); + + bool perfect; + { + MaxMatching mm(graph); + mm.run(); + checkMatching(graph, mm); + perfect = 2 * mm.matchingSize() == countNodes(graph); + } + + { + MaxWeightedMatching mwm(graph, weight); + mwm.run(); + checkWeightedMatching(graph, weight, mwm); + } + + { + MaxWeightedMatching mwm(graph, weight); + mwm.init(); + mwm.start(); + checkWeightedMatching(graph, weight, mwm); + } + + { + MaxWeightedPerfectMatching mwpm(graph, weight); + bool result = mwpm.run(); + + check(result == perfect, "Perfect matching found"); + if (perfect) { + checkWeightedPerfectMatching(graph, weight, mwpm); + } + } + + { + MaxWeightedPerfectMatching 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/extern/quadriflow/3rd/lemon-1.3.1/test/max_cardinality_search_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/max_cardinality_search_test.cc new file mode 100644 index 00000000000..c01066f36e7 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/max_cardinality_search_test.cc @@ -0,0 +1,162 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 + +#include "test_tools.h" +#include +#include +#include +#include +#include +#include + +using namespace lemon; +using namespace std; + +char test_lgf[] = + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "@arcs\n" + " label capacity\n" + "0 1 0 2\n" + "1 0 1 2\n" + "2 1 2 1\n" + "2 3 3 3\n" + "3 2 4 3\n" + "3 1 5 5\n" + "@attributes\n" + "s 0\n" + "x 1\n" + "y 2\n" + "z 3\n"; + +void checkMaxCardSearchCompile() { + + typedef concepts::Digraph Digraph; + typedef int Value; + typedef Digraph::Node Node; + typedef Digraph::Arc Arc; + typedef concepts::ReadMap CapMap; + typedef concepts::ReadWriteMap CardMap; + typedef concepts::ReadWriteMap ProcMap; + typedef Digraph::NodeMap HeapCrossRef; + + Digraph g; + Node n,s; + CapMap cap; + CardMap card; + ProcMap proc; + HeapCrossRef crossref(g); + + typedef MaxCardinalitySearch + ::SetCapacityMap + ::SetCardinalityMap + ::SetProcessedMap + ::SetStandardHeap > + ::Create MaxCardType; + + MaxCardType maxcard(g,cap); + const MaxCardType& const_maxcard = maxcard; + + const MaxCardType::Heap& heap_const = const_maxcard.heap(); + MaxCardType::Heap& heap = const_cast(heap_const); + maxcard.heap(heap,crossref); + + maxcard.capacityMap(cap).cardinalityMap(card).processedMap(proc); + + maxcard.init(); + maxcard.addSource(s); + n = maxcard.nextNode(); + maxcard.processNextNode(); + maxcard.start(); + maxcard.run(s); + maxcard.run(); + } + + void checkWithIntMap( std::istringstream& input) + { + typedef SmartDigraph Digraph; + typedef Digraph::Node Node; + typedef Digraph::ArcMap CapMap; + + Digraph g; + Node s,x,y,z,a; + CapMap cap(g); + + DigraphReader(g,input). + arcMap("capacity", cap). + node("s",s). + node("x",x). + node("y",y). + node("z",z). + run(); + + MaxCardinalitySearch maxcard(g,cap); + + maxcard.init(); + maxcard.addSource(s); + maxcard.start(x); + + check(maxcard.processed(s) && !maxcard.processed(x) && + !maxcard.processed(y), "Wrong processed()!"); + + a=maxcard.nextNode(); + check(maxcard.processNextNode()==a, + "Wrong nextNode() or processNextNode() return value!"); + + check(maxcard.processed(a), "Wrong processNextNode()!"); + + maxcard.start(); + check(maxcard.cardinality(x)==2 && maxcard.cardinality(y)>=4, + "Wrong cardinalities!"); + } + + void checkWithConst1Map(std::istringstream &input) { + typedef SmartDigraph Digraph; + typedef Digraph::Node Node; + + Digraph g; + Node s,x,y,z; + + DigraphReader(g,input). + node("s",s). + node("x",x). + node("y",y). + node("z",z). + run(); + + MaxCardinalitySearch maxcard(g); + maxcard.run(s); + check(maxcard.cardinality(x)==1 && + maxcard.cardinality(y)+maxcard.cardinality(z)==3, + "Wrong cardinalities!"); +} + +int main() { + + std::istringstream input1(test_lgf); + checkWithIntMap(input1); + + std::istringstream input2(test_lgf); + checkWithConst1Map(input2); +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/max_clique_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/max_clique_test.cc new file mode 100644 index 00000000000..d16f0f99072 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/max_clique_test.cc @@ -0,0 +1,188 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 +#include +#include +#include +#include +#include + +#include "test_tools.h" + +using namespace lemon; + +char test_lgf[] = + "@nodes\n" + "label max_clique\n" + "1 0\n" + "2 0\n" + "3 0\n" + "4 1\n" + "5 1\n" + "6 1\n" + "7 1\n" + "@edges\n" + " label\n" + "1 2 1\n" + "1 3 2\n" + "1 4 3\n" + "1 6 4\n" + "2 3 5\n" + "2 5 6\n" + "2 7 7\n" + "3 4 8\n" + "3 5 9\n" + "4 5 10\n" + "4 6 11\n" + "4 7 12\n" + "5 6 13\n" + "5 7 14\n" + "6 7 15\n"; + + +// Check with general graphs +template +void checkMaxCliqueGeneral(Param rule) { + typedef ListGraph GR; + typedef GrossoLocatelliPullanMc McAlg; + typedef McAlg::CliqueNodeIt CliqueIt; + + // Basic tests + { + GR g; + GR::NodeMap map(g); + McAlg mc(g); + mc.iterationLimit(50); + check(mc.run(rule) == McAlg::SIZE_LIMIT, "Wrong termination cause"); + check(mc.cliqueSize() == 0, "Wrong clique size"); + check(CliqueIt(mc) == INVALID, "Wrong CliqueNodeIt"); + + GR::Node u = g.addNode(); + check(mc.run(rule) == McAlg::SIZE_LIMIT, "Wrong termination cause"); + check(mc.cliqueSize() == 1, "Wrong clique size"); + mc.cliqueMap(map); + check(map[u], "Wrong clique map"); + CliqueIt it1(mc); + check(static_cast(it1) == u && ++it1 == INVALID, + "Wrong CliqueNodeIt"); + + GR::Node v = g.addNode(); + check(mc.run(rule) == McAlg::ITERATION_LIMIT, "Wrong termination cause"); + check(mc.cliqueSize() == 1, "Wrong clique size"); + mc.cliqueMap(map); + check((map[u] && !map[v]) || (map[v] && !map[u]), "Wrong clique map"); + CliqueIt it2(mc); + check(it2 != INVALID && ++it2 == INVALID, "Wrong CliqueNodeIt"); + + g.addEdge(u, v); + check(mc.run(rule) == McAlg::SIZE_LIMIT, "Wrong termination cause"); + check(mc.cliqueSize() == 2, "Wrong clique size"); + mc.cliqueMap(map); + check(map[u] && map[v], "Wrong clique map"); + CliqueIt it3(mc); + check(it3 != INVALID && ++it3 != INVALID && ++it3 == INVALID, + "Wrong CliqueNodeIt"); + } + + // Test graph + { + GR g; + GR::NodeMap max_clique(g); + GR::NodeMap map(g); + std::istringstream input(test_lgf); + graphReader(g, input) + .nodeMap("max_clique", max_clique) + .run(); + + McAlg mc(g); + mc.iterationLimit(50); + check(mc.run(rule) == McAlg::ITERATION_LIMIT, "Wrong termination cause"); + check(mc.cliqueSize() == 4, "Wrong clique size"); + mc.cliqueMap(map); + for (GR::NodeIt n(g); n != INVALID; ++n) { + check(map[n] == max_clique[n], "Wrong clique map"); + } + int cnt = 0; + for (CliqueIt n(mc); n != INVALID; ++n) { + cnt++; + check(map[n] && max_clique[n], "Wrong CliqueNodeIt"); + } + check(cnt == 4, "Wrong CliqueNodeIt"); + } +} + +// Check with full graphs +template +void checkMaxCliqueFullGraph(Param rule) { + typedef FullGraph GR; + typedef GrossoLocatelliPullanMc McAlg; + typedef McAlg::CliqueNodeIt CliqueIt; + + for (int size = 0; size <= 40; size = size * 3 + 1) { + GR g(size); + GR::NodeMap map(g); + McAlg mc(g); + check(mc.run(rule) == McAlg::SIZE_LIMIT, "Wrong termination cause"); + check(mc.cliqueSize() == size, "Wrong clique size"); + mc.cliqueMap(map); + for (GR::NodeIt n(g); n != INVALID; ++n) { + check(map[n], "Wrong clique map"); + } + int cnt = 0; + for (CliqueIt n(mc); n != INVALID; ++n) cnt++; + check(cnt == size, "Wrong CliqueNodeIt"); + } +} + +// Check with grid graphs +template +void checkMaxCliqueGridGraph(Param rule) { + GridGraph g(5, 7); + GridGraph::NodeMap map(g); + GrossoLocatelliPullanMc mc(g); + + mc.iterationLimit(100); + check(mc.run(rule) == mc.ITERATION_LIMIT, "Wrong termination cause"); + check(mc.cliqueSize() == 2, "Wrong clique size"); + + mc.stepLimit(100); + check(mc.run(rule) == mc.STEP_LIMIT, "Wrong termination cause"); + check(mc.cliqueSize() == 2, "Wrong clique size"); + + mc.sizeLimit(2); + check(mc.run(rule) == mc.SIZE_LIMIT, "Wrong termination cause"); + check(mc.cliqueSize() == 2, "Wrong clique size"); +} + + +int main() { + checkMaxCliqueGeneral(GrossoLocatelliPullanMc::RANDOM); + checkMaxCliqueGeneral(GrossoLocatelliPullanMc::DEGREE_BASED); + checkMaxCliqueGeneral(GrossoLocatelliPullanMc::PENALTY_BASED); + + checkMaxCliqueFullGraph(GrossoLocatelliPullanMc::RANDOM); + checkMaxCliqueFullGraph(GrossoLocatelliPullanMc::DEGREE_BASED); + checkMaxCliqueFullGraph(GrossoLocatelliPullanMc::PENALTY_BASED); + + checkMaxCliqueGridGraph(GrossoLocatelliPullanMc::RANDOM); + checkMaxCliqueGridGraph(GrossoLocatelliPullanMc::DEGREE_BASED); + checkMaxCliqueGridGraph(GrossoLocatelliPullanMc::PENALTY_BASED); + + return 0; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/max_flow_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/max_flow_test.cc new file mode 100644 index 00000000000..f63874a615a --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/max_flow_test.cc @@ -0,0 +1,395 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 + +#include "test_tools.h" +#include +#include +#include +#include +#include +#include +#include + +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"; + + +// Checks the general interface of a max flow algorithm +template +struct MaxFlowClassConcept +{ + + template + struct Constraints { + + typedef typename GR::Node Node; + typedef typename GR::Arc Arc; + typedef typename CAP::Value Value; + typedef concepts::ReadWriteMap FlowMap; + typedef concepts::WriteMap CutMap; + + GR g; + Node n; + Arc e; + CAP cap; + FlowMap flow; + CutMap cut; + Value v; + bool b; + + void constraints() { + checkConcept(); + + const Constraints& me = *this; + + typedef typename MF + ::template SetFlowMap + ::Create MaxFlowType; + typedef typename MF::Create MaxFlowType2; + MaxFlowType max_flow(me.g, me.cap, me.n, me.n); + const MaxFlowType& const_max_flow = max_flow; + + max_flow + .capacityMap(cap) + .flowMap(flow) + .source(n) + .target(n); + + typename MaxFlowType::Tolerance tol = const_max_flow.tolerance(); + max_flow.tolerance(tol); + + max_flow.init(); + max_flow.init(cap); + max_flow.run(); + + v = const_max_flow.flowValue(); + v = const_max_flow.flow(e); + const FlowMap& fm = const_max_flow.flowMap(); + + b = const_max_flow.minCut(n); + const_max_flow.minCutMap(cut); + + ::lemon::ignore_unused_variable_warning(fm); + } + + }; + +}; + +// Checks the specific parts of Preflow's interface +void checkPreflowCompile() +{ + typedef int Value; + typedef concepts::Digraph Digraph; + typedef concepts::ReadMap CapMap; + typedef Elevator Elev; + typedef LinkedElevator LinkedElev; + + Digraph g; + Digraph::Node n; + CapMap cap; + + typedef Preflow + ::SetElevator + ::SetStandardElevator + ::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(elev)); + + bool b = preflow_test.init(cap); + preflow_test.startFirstPhase(); + preflow_test.startSecondPhase(); + preflow_test.runMinCut(); + + ::lemon::ignore_unused_variable_warning(b); +} + +// Checks the specific parts of EdmondsKarp's interface +void checkEdmondsKarpCompile() +{ + typedef int Value; + typedef concepts::Digraph Digraph; + typedef concepts::ReadMap CapMap; + typedef Elevator Elev; + typedef LinkedElevator LinkedElev; + + Digraph g; + Digraph::Node n; + CapMap cap; + + EdmondsKarp ek_test(g, cap, n, n); + + ek_test.init(cap); + bool b = ek_test.checkedInit(cap); + b = ek_test.augment(); + ek_test.start(); + + ::lemon::ignore_unused_variable_warning(b); +} + + +template +T cutValue (const SmartDigraph& g, + const SmartDigraph::NodeMap& cut, + const SmartDigraph::ArcMap& cap) { + + T c=0; + for(SmartDigraph::ArcIt e(g); e!=INVALID; ++e) { + if (cut[g.source(e)] && !cut[g.target(e)]) c+=cap[e]; + } + return c; +} + +template +bool checkFlow(const SmartDigraph& g, + const SmartDigraph::ArcMap& flow, + const SmartDigraph::ArcMap& 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; + T 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 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 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)."); +} + +template +void checkMaxFlowAlg() { + typedef SmartDigraph Digraph; + DIGRAPH_TYPEDEFS(Digraph); + + typedef typename MF::Value Value; + typedef Digraph::ArcMap CapMap; + typedef CapMap FlowMap; + typedef BoolNodeMap CutMap; + + Digraph g; + Node s, t; + CapMap cap(g); + std::istringstream input(test_lgf); + DigraphReader(g,input) + .arcMap("capacity", cap) + .node("source",s) + .node("target",t) + .run(); + + MF max_flow(g, cap, s, t); + max_flow.run(); + + check(checkFlow(g, max_flow.flowMap(), cap, s, t), + "The flow is not feasible."); + + CutMap min_cut(g); + max_flow.minCutMap(min_cut); + Value min_cut_value = cutValue(g, min_cut, cap); + + check(max_flow.flowValue() == min_cut_value, + "The max flow value is not equal to the min cut value."); + + FlowMap flow(g); + for (ArcIt e(g); e != INVALID; ++e) flow[e] = max_flow.flowMap()[e]; + + Value flow_value = max_flow.flowValue(); + + for (ArcIt e(g); e != INVALID; ++e) cap[e] = 2 * cap[e]; + max_flow.init(flow); + + SF::startFirstPhase(max_flow); // start first phase of the algorithm + + CutMap min_cut1(g); + max_flow.minCutMap(min_cut1); + min_cut_value = cutValue(g, min_cut1, cap); + + check(max_flow.flowValue() == min_cut_value && + min_cut_value == 2 * flow_value, + "The max flow value or the min cut value is wrong."); + + SF::startSecondPhase(max_flow); // start second phase of the algorithm + + check(checkFlow(g, max_flow.flowMap(), cap, s, t), + "The flow is not feasible."); + + CutMap min_cut2(g); + max_flow.minCutMap(min_cut2); + min_cut_value = cutValue(g, min_cut2, cap); + + check(max_flow.flowValue() == min_cut_value && + min_cut_value == 2 * flow_value, + "The max flow value or the min cut value was not doubled"); + + + max_flow.flowMap(flow); + + NodeIt tmp1(g, s); + ++tmp1; + if (tmp1 != INVALID) s = tmp1; + + NodeIt tmp2(g, t); + ++tmp2; + if (tmp2 != INVALID) t = tmp2; + + max_flow.source(s); + max_flow.target(t); + + max_flow.run(); + + CutMap min_cut3(g); + max_flow.minCutMap(min_cut3); + min_cut_value=cutValue(g, min_cut3, cap); + + check(max_flow.flowValue() == min_cut_value, + "The max flow value or the min cut value is wrong."); +} + +// Struct for calling start functions of a general max flow algorithm +template +struct GeneralStartFunctions { + + static void startFirstPhase(MF& mf) { + mf.start(); + } + + static void startSecondPhase(MF& mf) { + ::lemon::ignore_unused_variable_warning(mf); + } + +}; + +// Struct for calling start functions of Preflow +template +struct PreflowStartFunctions { + + static void startFirstPhase(MF& mf) { + mf.startFirstPhase(); + } + + static void startSecondPhase(MF& mf) { + mf.startSecondPhase(); + } + +}; + +int main() { + + typedef concepts::Digraph GR; + typedef concepts::ReadMap CM1; + typedef concepts::ReadMap CM2; + + // Check the interface of Preflow + checkConcept< MaxFlowClassConcept, + Preflow >(); + checkConcept< MaxFlowClassConcept, + Preflow >(); + + // Check the interface of EdmondsKarp + checkConcept< MaxFlowClassConcept, + EdmondsKarp >(); + checkConcept< MaxFlowClassConcept, + EdmondsKarp >(); + + // Check Preflow + typedef Preflow > PType1; + typedef Preflow > PType2; + checkMaxFlowAlg >(); + checkMaxFlowAlg >(); + initFlowTest(); + + // Check EdmondsKarp + typedef EdmondsKarp > EKType1; + typedef EdmondsKarp > EKType2; + checkMaxFlowAlg >(); + checkMaxFlowAlg >(); + + initFlowTest(); + + return 0; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/min_cost_arborescence_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/min_cost_arborescence_test.cc new file mode 100644 index 00000000000..3a5ea36f1ea --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/min_cost_arborescence_test.cc @@ -0,0 +1,207 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 +#include +#include +#include + +#include +#include +#include +#include + +#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 CostMap; + typedef Digraph::Node Node; + typedef Digraph::Arc Arc; + typedef concepts::WriteMap ArbMap; + typedef concepts::ReadWriteMap PredMap; + + typedef MinCostArborescence:: + SetArborescenceMap:: + SetPredMap::Create MinCostArbType; + + Digraph g; + Node s, n; + Arc e; + VType c; + bool b; + ::lemon::ignore_unused_variable_warning(c,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); + + ::lemon::ignore_unused_variable_warning(am); + ::lemon::ignore_unused_variable_warning(pm); +} + +int main() { + typedef SmartDigraph Digraph; + DIGRAPH_TYPEDEFS(Digraph); + + typedef Digraph::ArcMap CostMap; + + Digraph digraph; + CostMap cost(digraph); + Node source; + + std::istringstream is(test_lgf); + digraphReader(digraph, is). + arcMap("cost", cost). + node("source", source).run(); + + MinCostArborescence mca(digraph, cost); + mca.run(source); + + vector > > dualSolution(mca.dualNum()); + + for (int i = 0; i < mca.dualNum(); ++i) { + dualSolution[i].first = mca.dualValue(i); + for (MinCostArborescence::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 arborescence(digraph); + check(mca.arborescenceCost() == + minCostArborescence(digraph, cost, source, arborescence), + "Wrong result of the function interface"); + + return 0; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/min_cost_flow_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/min_cost_flow_test.cc new file mode 100644 index 00000000000..15dcf542d36 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/min_cost_flow_test.cc @@ -0,0 +1,548 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#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 c(gr), l1(gr), l2(gr), l3(gr), u(gr); +Digraph::NodeMap s1(gr), s2(gr), s3(gr), s4(gr), s5(gr), s6(gr); +ConstMap cc(1), cu(std::numeric_limits::max()); +Node v, w; + +Digraph neg1_gr; +Digraph::ArcMap neg1_c(neg1_gr), neg1_l1(neg1_gr), neg1_l2(neg1_gr); +ConstMap neg1_u1(std::numeric_limits::max()), neg1_u2(5000); +Digraph::NodeMap neg1_s(neg1_gr); + +Digraph neg2_gr; +Digraph::ArcMap neg2_c(neg2_gr); +ConstMap neg2_l(0), neg2_u(1000); +Digraph::NodeMap neg2_s(neg2_gr); + + +enum SupplyType { + EQ, + GEQ, + LEQ +}; + + +// Check the interface of an MCF algorithm +template +class McfClassConcept +{ +public: + + template + struct Constraints { + void constraints() { + checkConcept(); + + 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(); + 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 NM; + typedef concepts::ReadMap VAM; + typedef concepts::ReadMap CAM; + typedef concepts::WriteMap FlowMap; + typedef concepts::WriteMap 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 flow(gr); + typename GR::template NodeMap 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); + + // Tests for empty graph + Digraph gr0; + MCF mcf0(gr0); + mcf0.run(param); + check(mcf0.totalCost() == 0, "Wrong total cost"); +} + +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(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(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(neg2_gr, neg_inp2) + .arcMap("cost", neg2_c) + .nodeMap("sup", neg2_s) + .run(); + + // Check the interface of NetworkSimplex + { + typedef concepts::Digraph GR; + checkConcept< McfClassConcept, + NetworkSimplex >(); + checkConcept< McfClassConcept, + NetworkSimplex >(); + checkConcept< McfClassConcept, + NetworkSimplex >(); + } + + // Check the interface of CapacityScaling + { + typedef concepts::Digraph GR; + checkConcept< McfClassConcept, + CapacityScaling >(); + checkConcept< McfClassConcept, + CapacityScaling >(); + checkConcept< McfClassConcept, + CapacityScaling >(); + typedef CapacityScaling:: + SetHeap > >::Create CAS; + checkConcept< McfClassConcept, CAS >(); + } + + // Check the interface of CostScaling + { + typedef concepts::Digraph GR; + checkConcept< McfClassConcept, + CostScaling >(); + checkConcept< McfClassConcept, + CostScaling >(); + checkConcept< McfClassConcept, + CostScaling >(); + typedef CostScaling:: + SetLargeCost::Create COS; + checkConcept< McfClassConcept, COS >(); + } + + // Check the interface of CycleCanceling + { + typedef concepts::Digraph GR; + checkConcept< McfClassConcept, + CycleCanceling >(); + checkConcept< McfClassConcept, + CycleCanceling >(); + checkConcept< McfClassConcept, + CycleCanceling >(); + } + + // Test NetworkSimplex + { + typedef NetworkSimplex MCF; + runMcfGeqTests(MCF::FIRST_ELIGIBLE, "NS-FE", true); + runMcfLeqTests(MCF::FIRST_ELIGIBLE, "NS-FE"); + runMcfGeqTests(MCF::BEST_ELIGIBLE, "NS-BE", true); + runMcfLeqTests(MCF::BEST_ELIGIBLE, "NS-BE"); + runMcfGeqTests(MCF::BLOCK_SEARCH, "NS-BS", true); + runMcfLeqTests(MCF::BLOCK_SEARCH, "NS-BS"); + runMcfGeqTests(MCF::CANDIDATE_LIST, "NS-CL", true); + runMcfLeqTests(MCF::CANDIDATE_LIST, "NS-CL"); + runMcfGeqTests(MCF::ALTERING_LIST, "NS-AL", true); + runMcfLeqTests(MCF::ALTERING_LIST, "NS-AL"); + } + + // Test CapacityScaling + { + typedef CapacityScaling MCF; + runMcfGeqTests(0, "SSP"); + runMcfGeqTests(2, "CAS"); + } + + // Test CostScaling + { + typedef CostScaling MCF; + runMcfGeqTests(MCF::PUSH, "COS-PR"); + runMcfGeqTests(MCF::AUGMENT, "COS-AR"); + runMcfGeqTests(MCF::PARTIAL_AUGMENT, "COS-PAR"); + } + + // Test CycleCanceling + { + typedef CycleCanceling MCF; + runMcfGeqTests(MCF::SIMPLE_CYCLE_CANCELING, "SCC"); + runMcfGeqTests(MCF::MINIMUM_MEAN_CYCLE_CANCELING, "MMCC"); + runMcfGeqTests(MCF::CANCEL_AND_TIGHTEN, "CAT"); + } + + return 0; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/min_mean_cycle_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/min_mean_cycle_test.cc new file mode 100644 index 00000000000..e7524546e54 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/min_mean_cycle_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-2013 + * 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 +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 +struct MmcClassConcept +{ + template + struct Constraints { + void constraints() { + const Constraints& me = *this; + + typedef typename MMC + ::template SetPath > + ::template SetLargeCost + ::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 CM; + + GR g; + CM cost; + ListPath p; + Cost v; + int i; + double d; + bool b; + }; +}; + +// Perform a test with the given parameters +template +void checkMmcAlg(const SmartDigraph& gr, + const SmartDigraph::ArcMap& lm, + const SmartDigraph::ArcMap& cm, + int cost, int size) { + MMC alg(gr, lm); + check(alg.findCycleMean(), "Wrong result"); + check(alg.cycleMean() == static_cast(cost) / size, + "Wrong cycle mean"); + alg.findCycle(); + check(alg.cycleCost() == cost && alg.cycleSize() == size, + "Wrong path"); + SmartDigraph::ArcMap 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 +struct IsSameType { + static const int result = 0; +}; + +template +struct IsSameType { + 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, + KarpMmc > >(); + checkConcept< MmcClassConcept, + KarpMmc > >(); + + // HartmannOrlinMmc + checkConcept< MmcClassConcept, + HartmannOrlinMmc > >(); + checkConcept< MmcClassConcept, + HartmannOrlinMmc > >(); + + // HowardMmc + checkConcept< MmcClassConcept, + HowardMmc > >(); + checkConcept< MmcClassConcept, + HowardMmc > >(); + + check((IsSameType > + ::LargeCost, long_int>::result == 1), "Wrong LargeCost type"); + check((IsSameType > + ::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 >(gr, l1, c1, 6, 3); + checkMmcAlg >(gr, l2, c2, 5, 2); + checkMmcAlg >(gr, l3, c3, 0, 1); + checkMmcAlg >(gr, l4, c4, -1, 1); + + // HartmannOrlin + checkMmcAlg >(gr, l1, c1, 6, 3); + checkMmcAlg >(gr, l2, c2, 5, 2); + checkMmcAlg >(gr, l3, c3, 0, 1); + checkMmcAlg >(gr, l4, c4, -1, 1); + + // Howard + checkMmcAlg >(gr, l1, c1, 6, 3); + checkMmcAlg >(gr, l2, c2, 5, 2); + checkMmcAlg >(gr, l3, c3, 0, 1); + checkMmcAlg >(gr, l4, c4, -1, 1); + + // Howard with iteration limit + HowardMmc mmc(gr, l1); + check((mmc.findCycleMean(2) == HowardMmc::ITERATION_LIMIT), + "Wrong termination cause"); + check((mmc.findCycleMean(4) == HowardMmc::OPTIMAL), + "Wrong termination cause"); + } + + return 0; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/mip_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/mip_test.cc new file mode 100644 index 00000000000..641ceb5fe77 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/mip_test.cc @@ -0,0 +1,171 @@ +/* -*- 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 + +#ifdef LEMON_HAVE_CPLEX +#include +#endif + +#ifdef LEMON_HAVE_GLPK +#include +#endif + +#ifdef LEMON_HAVE_CBC +#include +#endif + +#ifdef LEMON_HAVE_MIP +#include +#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 "< +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_MIP + { + Mip mip1; + aTest(mip1); + cloneTest(); + } +#endif + +#ifdef LEMON_HAVE_GLPK + { + GlpkMip mip1; + aTest(mip1); + cloneTest(); + } +#endif + +#ifdef LEMON_HAVE_CPLEX + try { + CplexMip mip2; + aTest(mip2); + cloneTest(); + } catch (CplexEnv::LicenseError& error) { + check(false, error.what()); + } +#endif + +#ifdef LEMON_HAVE_CBC + { + CbcMip mip1; + aTest(mip1); + cloneTest(); + } +#endif + + return 0; + +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/nagamochi_ibaraki_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/nagamochi_ibaraki_test.cc new file mode 100644 index 00000000000..94ec29d933b --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/nagamochi_ibaraki_test.cc @@ -0,0 +1,142 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 + +#include +#include +#include +#include +#include +#include + +#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" + "2 3 1 6 6 \n"; + +void checkNagamochiIbarakiCompile() +{ + typedef int Value; + typedef concepts::Graph Graph; + + typedef Graph::Node Node; + typedef Graph::Edge Edge; + typedef concepts::ReadMap CapMap; + typedef concepts::WriteMap CutMap; + + Graph g; + Node n; + CapMap cap; + CutMap cut; + Value v; + bool b; + ::lemon::ignore_unused_variable_warning(v,b); + + NagamochiIbaraki ni_test(g, cap); + const NagamochiIbaraki& const_ni_test = ni_test; + + ni_test.init(); + ni_test.start(); + b = ni_test.processNextPhase(); + ni_test.run(); + + v = const_ni_test.minCutValue(); + v = const_ni_test.minCutMap(cut); +} + +template +typename CapMap::Value + cutValue(const Graph& graph, const CapMap& cap, const CutMap& cut) +{ + typename CapMap::Value sum = 0; + for (typename Graph::EdgeIt e(graph); e != INVALID; ++e) { + if (cut[graph.u(e)] != cut[graph.v(e)]) { + sum += cap[e]; + } + } + return sum; +} + +int main() { + SmartGraph graph; + SmartGraph::EdgeMap cap1(graph), cap2(graph), cap3(graph); + SmartGraph::NodeMap cut(graph); + + istringstream input(lgf); + graphReader(graph, input) + .edgeMap("cap1", cap1) + .edgeMap("cap2", cap2) + .edgeMap("cap3", cap3) + .run(); + + { + NagamochiIbaraki ni(graph, cap1); + ni.run(); + ni.minCutMap(cut); + + check(ni.minCutValue() == 1, "Wrong cut value"); + check(ni.minCutValue() == cutValue(graph, cap1, cut), "Wrong cut value"); + } + { + NagamochiIbaraki ni(graph, cap2); + ni.run(); + ni.minCutMap(cut); + + check(ni.minCutValue() == 3, "Wrong cut value"); + check(ni.minCutValue() == cutValue(graph, cap2, cut), "Wrong cut value"); + } + { + NagamochiIbaraki ni(graph, cap3); + ni.run(); + ni.minCutMap(cut); + + check(ni.minCutValue() == 5, "Wrong cut value"); + check(ni.minCutValue() == cutValue(graph, cap3, cut), "Wrong cut value"); + } + { + NagamochiIbaraki::SetUnitCapacity::Create ni(graph); + ni.run(); + ni.minCutMap(cut); + + ConstMap cap4(1); + check(ni.minCutValue() == 1, "Wrong cut value"); + check(ni.minCutValue() == cutValue(graph, cap4, cut), "Wrong cut value"); + } + + return 0; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/path_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/path_test.cc new file mode 100644 index 00000000000..f2d96038135 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/path_test.cc @@ -0,0 +1,339 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 +#include + +#include +#include +#include + +#include +#include + +#include "test_tools.h" + +using namespace std; +using namespace lemon; + +template +void checkConcepts() { + checkConcept, concepts::Path >(); + checkConcept, Path >(); + checkConcept, SimplePath >(); + checkConcept, StaticPath >(); + checkConcept, ListPath >(); +} + +// Conecpt checking for path structures +void checkPathConcepts() { + checkConcepts(); + checkConcepts(); +} + +// Check if proper copy consructor is called (use valgrind for testing) +template +void checkCopy(typename GR::Arc a) { + P1 p; + p.addBack(a); + P1 q; + q = p; + P1 r(p); + P2 q2; + q2 = p; + P2 r2(p); +} + +// Tests for copy constructors and assignment operators of paths +void checkPathCopy() { + ListDigraph g; + ListDigraph::Arc a = g.addArc(g.addNode(), g.addNode()); + + typedef Path Path1; + typedef SimplePath Path2; + typedef ListPath Path3; + typedef StaticPath Path4; + checkCopy(a); + checkCopy(a); + checkCopy(a); + checkCopy(a); + checkCopy(a); + checkCopy(a); + checkCopy(a); + checkCopy(a); + checkCopy(a); +} + +// Class for testing path functions +class CheckPathFunctions { + typedef ListDigraph GR; + DIGRAPH_TYPEDEFS(GR); + GR gr; + const GR& cgr; + Node n1, n2, n3, n4; + Node tmp_n; + Arc a1, a2, a3, a4; + Arc tmp_a; + +public: + + CheckPathFunctions() : cgr(gr) { + n1 = gr.addNode(); + n2 = gr.addNode(); + n3 = gr.addNode(); + n4 = gr.addNode(); + a1 = gr.addArc(n1, n2); + a2 = gr.addArc(n2, n3); + a3 = gr.addArc(n3, n4); + a4 = gr.addArc(n4, n1); + } + + void run() { + checkBackAndFrontInsertablePath >(); + checkBackAndFrontInsertablePath >(); + checkBackInsertablePath >(); + + checkListPathSplitAndSplice(); + } + +private: + + template + void checkBackInsertablePath() { + + // Create and check empty path + P p; + const P& cp = p; + check(cp.empty(), "The path is not empty"); + check(cp.length() == 0, "The path is not empty"); +// check(cp.front() == INVALID, "Wrong front()"); +// check(cp.back() == INVALID, "Wrong back()"); + typename P::ArcIt ai(cp); + check(ai == INVALID, "Wrong ArcIt"); + check(pathSource(cgr, cp) == INVALID, "Wrong pathSource()"); + check(pathTarget(cgr, cp) == INVALID, "Wrong pathTarget()"); + check(checkPath(cgr, cp), "Wrong checkPath()"); + PathNodeIt

ni(cgr, cp); + check(ni == INVALID, "Wrong PathNodeIt"); + + // Check single-arc path + p.addBack(a1); + check(!cp.empty(), "Wrong empty()"); + check(cp.length() == 1, "Wrong length"); + check(cp.front() == a1, "Wrong front()"); + check(cp.back() == a1, "Wrong back()"); + check(cp.nth(0) == a1, "Wrong nth()"); + ai = cp.nthIt(0); + check((tmp_a = ai) == a1, "Wrong nthIt()"); + check(++ai == INVALID, "Wrong nthIt()"); + typename P::ArcIt ai2(cp); + check((tmp_a = ai2) == a1, "Wrong ArcIt"); + check(++ai2 == INVALID, "Wrong ArcIt"); + check(pathSource(cgr, cp) == n1, "Wrong pathSource()"); + check(pathTarget(cgr, cp) == n2, "Wrong pathTarget()"); + check(checkPath(cgr, cp), "Wrong checkPath()"); + PathNodeIt

ni2(cgr, cp); + check((tmp_n = ni2) == n1, "Wrong PathNodeIt"); + check((tmp_n = ++ni2) == n2, "Wrong PathNodeIt"); + check(++ni2 == INVALID, "Wrong PathNodeIt"); + + // Check adding more arcs + p.addBack(a2); + p.addBack(a3); + check(!cp.empty(), "Wrong empty()"); + check(cp.length() == 3, "Wrong length"); + check(cp.front() == a1, "Wrong front()"); + check(cp.back() == a3, "Wrong back()"); + check(cp.nth(0) == a1, "Wrong nth()"); + check(cp.nth(1) == a2, "Wrong nth()"); + check(cp.nth(2) == a3, "Wrong nth()"); + typename P::ArcIt ai3(cp); + check((tmp_a = ai3) == a1, "Wrong ArcIt"); + check((tmp_a = ++ai3) == a2, "Wrong nthIt()"); + check((tmp_a = ++ai3) == a3, "Wrong nthIt()"); + check(++ai3 == INVALID, "Wrong nthIt()"); + ai = cp.nthIt(0); + check((tmp_a = ai) == a1, "Wrong nthIt()"); + check((tmp_a = ++ai) == a2, "Wrong nthIt()"); + ai = cp.nthIt(2); + check((tmp_a = ai) == a3, "Wrong nthIt()"); + check(++ai == INVALID, "Wrong nthIt()"); + check(pathSource(cgr, cp) == n1, "Wrong pathSource()"); + check(pathTarget(cgr, cp) == n4, "Wrong pathTarget()"); + check(checkPath(cgr, cp), "Wrong checkPath()"); + PathNodeIt

ni3(cgr, cp); + check((tmp_n = ni3) == n1, "Wrong PathNodeIt"); + check((tmp_n = ++ni3) == n2, "Wrong PathNodeIt"); + check((tmp_n = ++ni3) == n3, "Wrong PathNodeIt"); + check((tmp_n = ++ni3) == n4, "Wrong PathNodeIt"); + check(++ni3 == INVALID, "Wrong PathNodeIt"); + + // Check arc removal and addition + p.eraseBack(); + p.eraseBack(); + p.addBack(a2); + check(!cp.empty(), "Wrong empty()"); + check(cp.length() == 2, "Wrong length"); + check(cp.front() == a1, "Wrong front()"); + check(cp.back() == a2, "Wrong back()"); + check(pathSource(cgr, cp) == n1, "Wrong pathSource()"); + check(pathTarget(cgr, cp) == n3, "Wrong pathTarget()"); + check(checkPath(cgr, cp), "Wrong checkPath()"); + + // Check clear() + p.clear(); + check(cp.empty(), "The path is not empty"); + check(cp.length() == 0, "The path is not empty"); + + // Check inconsistent path + p.addBack(a4); + p.addBack(a2); + p.addBack(a1); + check(!cp.empty(), "Wrong empty()"); + check(cp.length() == 3, "Wrong length"); + check(cp.front() == a4, "Wrong front()"); + check(cp.back() == a1, "Wrong back()"); + check(pathSource(cgr, cp) == n4, "Wrong pathSource()"); + check(pathTarget(cgr, cp) == n2, "Wrong pathTarget()"); + check(!checkPath(cgr, cp), "Wrong checkPath()"); + } + + template + void checkBackAndFrontInsertablePath() { + + // Include back insertable test cases + checkBackInsertablePath

(); + + // Check front and back insertion + P p; + const P& cp = p; + p.addFront(a4); + p.addBack(a1); + p.addFront(a3); + check(!cp.empty(), "Wrong empty()"); + check(cp.length() == 3, "Wrong length"); + check(cp.front() == a3, "Wrong front()"); + check(cp.back() == a1, "Wrong back()"); + check(cp.nth(0) == a3, "Wrong nth()"); + check(cp.nth(1) == a4, "Wrong nth()"); + check(cp.nth(2) == a1, "Wrong nth()"); + typename P::ArcIt ai(cp); + check((tmp_a = ai) == a3, "Wrong ArcIt"); + check((tmp_a = ++ai) == a4, "Wrong nthIt()"); + check((tmp_a = ++ai) == a1, "Wrong nthIt()"); + check(++ai == INVALID, "Wrong nthIt()"); + ai = cp.nthIt(0); + check((tmp_a = ai) == a3, "Wrong nthIt()"); + check((tmp_a = ++ai) == a4, "Wrong nthIt()"); + ai = cp.nthIt(2); + check((tmp_a = ai) == a1, "Wrong nthIt()"); + check(++ai == INVALID, "Wrong nthIt()"); + check(pathSource(cgr, cp) == n3, "Wrong pathSource()"); + check(pathTarget(cgr, cp) == n2, "Wrong pathTarget()"); + check(checkPath(cgr, cp), "Wrong checkPath()"); + + // Check eraseFront() + p.eraseFront(); + p.addBack(a2); + check(!cp.empty(), "Wrong empty()"); + check(cp.length() == 3, "Wrong length"); + check(cp.front() == a4, "Wrong front()"); + check(cp.back() == a2, "Wrong back()"); + check(cp.nth(0) == a4, "Wrong nth()"); + check(cp.nth(1) == a1, "Wrong nth()"); + check(cp.nth(2) == a2, "Wrong nth()"); + typename P::ArcIt ai2(cp); + check((tmp_a = ai2) == a4, "Wrong ArcIt"); + check((tmp_a = ++ai2) == a1, "Wrong nthIt()"); + check((tmp_a = ++ai2) == a2, "Wrong nthIt()"); + check(++ai2 == INVALID, "Wrong nthIt()"); + ai = cp.nthIt(0); + check((tmp_a = ai) == a4, "Wrong nthIt()"); + check((tmp_a = ++ai) == a1, "Wrong nthIt()"); + ai = cp.nthIt(2); + check((tmp_a = ai) == a2, "Wrong nthIt()"); + check(++ai == INVALID, "Wrong nthIt()"); + check(pathSource(cgr, cp) == n4, "Wrong pathSource()"); + check(pathTarget(cgr, cp) == n3, "Wrong pathTarget()"); + check(checkPath(cgr, cp), "Wrong checkPath()"); + } + + void checkListPathSplitAndSplice() { + + // Build a path with spliceFront() and spliceBack() + ListPath p1, p2, p3, p4; + p1.addBack(a3); + p1.addFront(a2); + p2.addBack(a1); + p1.spliceFront(p2); + p3.addFront(a4); + p1.spliceBack(p3); + check(p1.length() == 4, "Wrong length"); + check(p1.front() == a1, "Wrong front()"); + check(p1.back() == a4, "Wrong back()"); + ListPath::ArcIt ai(p1); + check((tmp_a = ai) == a1, "Wrong ArcIt"); + check((tmp_a = ++ai) == a2, "Wrong nthIt()"); + check((tmp_a = ++ai) == a3, "Wrong nthIt()"); + check((tmp_a = ++ai) == a4, "Wrong nthIt()"); + check(++ai == INVALID, "Wrong nthIt()"); + check(checkPath(cgr, p1), "Wrong checkPath()"); + + // Check split() + p1.split(p1.nthIt(2), p2); + check(p1.length() == 2, "Wrong length"); + ai = p1.nthIt(0); + check((tmp_a = ai) == a1, "Wrong ArcIt"); + check((tmp_a = ++ai) == a2, "Wrong nthIt()"); + check(++ai == INVALID, "Wrong nthIt()"); + check(checkPath(cgr, p1), "Wrong checkPath()"); + check(p2.length() == 2, "Wrong length"); + ai = p2.nthIt(0); + check((tmp_a = ai) == a3, "Wrong ArcIt"); + check((tmp_a = ++ai) == a4, "Wrong nthIt()"); + check(++ai == INVALID, "Wrong nthIt()"); + check(checkPath(cgr, p2), "Wrong checkPath()"); + + // Check split() and splice() + p1.spliceFront(p2); + p1.split(p1.nthIt(2), p2); + p2.split(p2.nthIt(1), p3); + p2.spliceBack(p1); + p2.splice(p2.nthIt(1), p3); + check(p2.length() == 4, "Wrong length"); + check(p2.front() == a1, "Wrong front()"); + check(p2.back() == a4, "Wrong back()"); + ai = p2.nthIt(0); + check((tmp_a = ai) == a1, "Wrong ArcIt"); + check((tmp_a = ++ai) == a2, "Wrong nthIt()"); + check((tmp_a = ++ai) == a3, "Wrong nthIt()"); + check((tmp_a = ++ai) == a4, "Wrong nthIt()"); + check(++ai == INVALID, "Wrong nthIt()"); + check(checkPath(cgr, p2), "Wrong checkPath()"); + } + +}; + +int main() { + checkPathConcepts(); + checkPathCopy(); + CheckPathFunctions cpf; + cpf.run(); + + return 0; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/planarity_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/planarity_test.cc new file mode 100644 index 00000000000..0ac11eebba1 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/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 + +#include + +#include +#include +#include +#include + +#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 PE; +typedef PlanarDrawing PD; +typedef PlanarColoring PC; + +void checkEmbedding(const Graph& graph, PE& pe) { + int face_num = 0; + + Graph::ArcMap 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 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::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 e1, Point e2, Point f1, Point 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 p, Point q, Point 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 e1 = pd[graph.u(e)]; + Point e2 = pd[graph.v(e)]; + Point f1 = pd[graph.u(f)]; + Point 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 pd(graph); + pd.run(pe.embeddingMap()); + checkDrawing(graph, pd); + + PlanarColoring pc(graph); + pc.runFiveColoring(pe.embeddingMap()); + checkColoring(graph, pc, 5); + + } else { + checkKuratowski(graph, pe); + } + } + + return 0; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/radix_sort_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/radix_sort_test.cc new file mode 100644 index 00000000000..6ae2debfa84 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/radix_sort_test.cc @@ -0,0 +1,266 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 +#include +#include +#include +#include + +#include "test_tools.h" + +#include +#include +#include + +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; } + +template +bool isTheSame(T &a, T&b) +{ + typename T::iterator ai=a.begin(); + typename T::iterator bi=b.begin(); + for(;ai!=a.end()||bi!=b.end();++ai,++bi) + if(*ai!=*bi) return false; + return ai==a.end()&&bi==b.end(); +} + +template +T listsort(typename T::iterator b, typename T::iterator e) +{ + if(b==e) return T(); + typename T::iterator bn=b; + if(++bn==e) { + T l; + l.push_back(*b); + return l; + } + typename T::iterator m=b; + bool x=false; + for(typename T::iterator i=b;i!=e;++i,x=!x) + if(x) ++m; + T l1(listsort(b,m)); + T l2(listsort(m,e)); + T l; + while((!l1.empty())&&(!l2.empty())) + if(l1.front()<=l2.front()) + { + l.push_back(l1.front()); + l1.pop_front(); + } + else { + l.push_back(l2.front()); + l2.pop_front(); + } + while(!l1.empty()) + { + l.push_back(l1.front()); + l1.pop_front(); + } + while(!l2.empty()) + { + l.push_back(l2.front()); + l2.pop_front(); + } + return l; +} + +template +void generateIntSequence(int n, T & 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; + } +} + +template +void generateCharSequence(int n, T & data) { + int prime = 251; + int root = 3, value = root; + for (int i = 0; i < n; ++i) { + data.push_back(static_cast(value)); + value = (value * root) % prime; + } +} + +void checkRadixSort() { + { + std::vector data1; + generateIntSequence(n, data1); + + std::vector 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 data1(n); + generateCharSequence(n, data1); + + std::vector 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"); + } + + } + { + std::list data1; + generateIntSequence(n, data1); + + std::list data2(listsort >(data1.begin(), data1.end())); + + radixSort(data1.begin(), data1.end()); + + check(isTheSame(data1,data2), "Test failed"); + + + // radixSort(data2.begin(), data2.end(), Negate()); + // check(isTheSame(data1,data2), "Test failed"); + // 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::list data1(n); + generateCharSequence(n, data1); + + std::list data2(listsort > + (data1.begin(), + data1.end())); + + radixSort(data1.begin(), data1.end()); + check(isTheSame(data1,data2), "Test failed"); + + } +} + + +void checkStableRadixSort() { + { + std::vector data1; + generateIntSequence(n, data1); + + std::vector 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 data1(n); + generateCharSequence(n, data1); + + std::vector 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"); + } + + } + { + std::list data1; + generateIntSequence(n, data1); + + std::list data2(listsort >(data1.begin(), + data1.end())); + stableRadixSort(data1.begin(), data1.end()); + check(isTheSame(data1,data2), "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::list data1(n); + generateCharSequence(n, data1); + + std::list data2(listsort > + (data1.begin(), + data1.end())); + radixSort(data1.begin(), data1.end()); + check(isTheSame(data1,data2), "Test failed"); + + } +} + +int main() { + + checkRadixSort(); + checkStableRadixSort(); + + return 0; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/random_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/random_test.cc new file mode 100644 index 00000000000..49dd8b60398 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/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 +#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/extern/quadriflow/3rd/lemon-1.3.1/test/suurballe_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/suurballe_test.cc new file mode 100644 index 00000000000..7c00f212ac0 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/suurballe_test.cc @@ -0,0 +1,267 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 + +#include +#include +#include +#include +#include +#include + +#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 LengthMap; + + typedef Suurballe ST; + typedef Suurballe + ::SetFlowMap + ::SetPotentialMap + ::SetPath > + ::SetHeap > > + ::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; + ::lemon::ignore_unused_variable_warning(f,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 p = const_suurb_test.path(k); + + ::lemon::ignore_unused_variable_warning(fm); + ::lemon::ignore_unused_variable_warning(pm); +} + +// Check the feasibility of the flow +template +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 +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 length(digraph); + Node s, t; + + std::istringstream input(test_lgf); + DigraphReader(digraph, input). + arcMap("length", length). + node("source", s). + node("target", t). + run(); + + // Check run() + { + Suurballe 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 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/extern/quadriflow/3rd/lemon-1.3.1/test/test_tools.h b/extern/quadriflow/3rd/lemon-1.3.1/test/test_tools.h new file mode 100644 index 00000000000..33003566791 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/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 +#include + +///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/extern/quadriflow/3rd/lemon-1.3.1/test/test_tools_fail.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/test_tools_fail.cc new file mode 100644 index 00000000000..6407cd15b04 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/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/extern/quadriflow/3rd/lemon-1.3.1/test/test_tools_pass.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/test_tools_pass.cc new file mode 100644 index 00000000000..b590c15a614 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/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/extern/quadriflow/3rd/lemon-1.3.1/test/time_measure_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/time_measure_test.cc new file mode 100644 index 00000000000..4e7155a91ba --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/time_measure_test.cc @@ -0,0 +1,60 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 +#include + +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); + ::lemon::ignore_unused_variable_warning(x); + } +} + +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/extern/quadriflow/3rd/lemon-1.3.1/test/tsp_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/tsp_test.cc new file mode 100644 index 00000000000..398a812e090 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/test/tsp_test.cc @@ -0,0 +1,287 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "test_tools.h" + +using namespace lemon; + +// // Tests checkMetricCost() function +// void metricCostTest() { +// GRAPH_TYPEDEFS(FullGraph); +// FullGraph g(10); +// check(checkMetricCost(g, constMap(0)), "Wrong checkMetricCost()"); +// check(checkMetricCost(g, constMap(1)), "Wrong checkMetricCost()"); +// check(!checkMetricCost(g, constMap(-1)), "Wrong checkMetricCost()"); +// +// FullGraph::EdgeMap cost(g); +// for (NodeIt u(g); u != INVALID; ++u) { +// for (NodeIt v(g); v != INVALID; ++v) { +// if (u == v) continue; +// float x1 = g.id(u), x2 = g.id(v); +// float y1 = x1 * x1, y2 = x2 * x2; +// cost[g.edge(u, v)] = std::sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)); +// } +// } +// check(checkMetricCost(g, cost), "Wrong checkMetricCost()"); +// float eps = Tolerance::defaultEpsilon(); +// cost[g.edge(g(0), g(9))] = +// cost[g.edge(g(0), g(8))] + cost[g.edge(g(8), g(9))] + eps * 2; +// check(!checkMetricCost(g, cost), "Wrong checkMetricCost()"); +// check(checkMetricCost(g, cost, Tolerance(eps * 4)), +// "Wrong checkMetricCost()"); +// } + +// Checks tour validity +template +bool checkTour(const FullGraph &gr, const Container &p) { + FullGraph::NodeMap used(gr, false); + + int node_cnt = 0; + for (typename Container::const_iterator it = p.begin(); it != p.end(); ++it) + { + FullGraph::Node node = *it; + if (used[node]) return false; + used[node] = true; + ++node_cnt; + } + + return (node_cnt == gr.nodeNum()); +} + +// Checks tour validity +bool checkTourPath(const FullGraph &gr, const Path &p) { + FullGraph::NodeMap used(gr, false); + + if (!checkPath(gr, p)) return false; + if (gr.nodeNum() <= 1 && p.length() != 0) return false; + if (gr.nodeNum() > 1 && p.length() != gr.nodeNum()) return false; + + for (int i = 0; i < p.length(); ++i) { + if (used[gr.target(p.nth(i))]) return false; + used[gr.target(p.nth(i))] = true; + } + return true; +} + +// Checks tour cost +template +bool checkCost(const FullGraph &gr, const std::vector &p, + const CostMap &cost, typename CostMap::Value total) +{ + typedef typename CostMap::Value Cost; + + Cost s = 0; + for (int i = 0; i < int(p.size()) - 1; ++i) + s += cost[gr.edge(p[i], p[i+1])]; + if (int(p.size()) >= 2) + s += cost[gr.edge(p.back(), p.front())]; + + return !Tolerance().different(s, total); +} + +// Checks tour cost +template +bool checkCost(const FullGraph &, const Path &p, + const CostMap &cost, typename CostMap::Value total) +{ + typedef typename CostMap::Value Cost; + + Cost s = 0; + for (int i = 0; i < p.length(); ++i) + s += cost[p.nth(i)]; + + return !Tolerance().different(s, total); +} + +// Tests a TSP algorithm on small graphs +template +void tspTestSmall(const std::string &alg_name) { + GRAPH_TYPEDEFS(FullGraph); + + for (int n = 0; n <= 5; ++n) { + FullGraph g(n); + unsigned nsize = n; + int esize = n <= 1 ? 0 : n; + + ConstMap cost_map(1); + TSP alg(g, cost_map); + + check(alg.run() == esize, alg_name + ": Wrong total cost"); + check(alg.tourCost() == esize, alg_name + ": Wrong total cost"); + + std::list list1(nsize), list2; + std::vector vec1(nsize), vec2; + alg.tourNodes(list1.begin()); + alg.tourNodes(vec1.begin()); + alg.tourNodes(std::front_inserter(list2)); + alg.tourNodes(std::back_inserter(vec2)); + check(checkTour(g, alg.tourNodes()), alg_name + ": Wrong node sequence"); + check(checkTour(g, list1), alg_name + ": Wrong node sequence"); + check(checkTour(g, vec1), alg_name + ": Wrong node sequence"); + check(checkTour(g, list2), alg_name + ": Wrong node sequence"); + check(checkTour(g, vec2), alg_name + ": Wrong node sequence"); + check(checkCost(g, vec1, constMap(1), esize), + alg_name + ": Wrong tour cost"); + + SimplePath path; + alg.tour(path); + check(path.length() == esize, alg_name + ": Wrong tour"); + check(checkTourPath(g, path), alg_name + ": Wrong tour"); + check(checkCost(g, path, constMap(1), esize), + alg_name + ": Wrong tour cost"); + } +} + +// Tests a TSP algorithm on random graphs +template +void tspTestRandom(const std::string &alg_name) { + GRAPH_TYPEDEFS(FullGraph); + + FullGraph g(20); + FullGraph::NodeMap > pos(g); + DoubleEdgeMap cost(g); + + TSP alg(g, cost); + Opt2Tsp opt2(g, cost); + + for (int i = 1; i <= 3; i++) { + for (NodeIt u(g); u != INVALID; ++u) { + pos[u] = dim2::Point(rnd(), rnd()); + } + for (NodeIt u(g); u != INVALID; ++u) { + for (NodeIt v(g); v != INVALID; ++v) { + if (u == v) continue; + cost[g.edge(u, v)] = (pos[u] - pos[v]).normSquare(); + } + } + + check(alg.run() > 0, alg_name + ": Wrong total cost"); + + std::vector vec; + alg.tourNodes(std::back_inserter(vec)); + check(checkTour(g, vec), alg_name + ": Wrong node sequence"); + check(checkCost(g, vec, cost, alg.tourCost()), + alg_name + ": Wrong tour cost"); + + SimplePath path; + alg.tour(path); + check(checkTourPath(g, path), alg_name + ": Wrong tour"); + check(checkCost(g, path, cost, alg.tourCost()), + alg_name + ": Wrong tour cost"); + + check(!Tolerance().less(alg.tourCost(), opt2.run(alg.tourNodes())), + "2-opt improvement: Wrong total cost"); + check(checkTour(g, opt2.tourNodes()), + "2-opt improvement: Wrong node sequence"); + check(checkCost(g, opt2.tourNodes(), cost, opt2.tourCost()), + "2-opt improvement: Wrong tour cost"); + + check(!Tolerance().less(alg.tourCost(), opt2.run(path)), + "2-opt improvement: Wrong total cost"); + check(checkTour(g, opt2.tourNodes()), + "2-opt improvement: Wrong node sequence"); + check(checkCost(g, opt2.tourNodes(), cost, opt2.tourCost()), + "2-opt improvement: Wrong tour cost"); + } +} + +// Algorithm class for Nearest Insertion +template +class NearestInsertionTsp : public InsertionTsp { +public: + NearestInsertionTsp(const FullGraph &gr, const CM &cost) + : InsertionTsp(gr, cost) {} + typename CM::Value run() { + return InsertionTsp::run(InsertionTsp::NEAREST); + } +}; + +// Algorithm class for Farthest Insertion +template +class FarthestInsertionTsp : public InsertionTsp { +public: + FarthestInsertionTsp(const FullGraph &gr, const CM &cost) + : InsertionTsp(gr, cost) {} + typename CM::Value run() { + return InsertionTsp::run(InsertionTsp::FARTHEST); + } +}; + +// Algorithm class for Cheapest Insertion +template +class CheapestInsertionTsp : public InsertionTsp { +public: + CheapestInsertionTsp(const FullGraph &gr, const CM &cost) + : InsertionTsp(gr, cost) {} + typename CM::Value run() { + return InsertionTsp::run(InsertionTsp::CHEAPEST); + } +}; + +// Algorithm class for Random Insertion +template +class RandomInsertionTsp : public InsertionTsp { +public: + RandomInsertionTsp(const FullGraph &gr, const CM &cost) + : InsertionTsp(gr, cost) {} + typename CM::Value run() { + return InsertionTsp::run(InsertionTsp::RANDOM); + } +}; + +int main() { + GRAPH_TYPEDEFS(FullGraph); + + // metricCostTest(); + + tspTestSmall > >("Nearest Neighbor"); + tspTestSmall > >("Greedy"); + tspTestSmall > >("Nearest Insertion"); + tspTestSmall > > + ("Farthest Insertion"); + tspTestSmall > > + ("Cheapest Insertion"); + tspTestSmall > >("Random Insertion"); + tspTestSmall > >("Christofides"); + tspTestSmall > >("2-opt"); + + tspTestRandom >("Nearest Neighbor"); + tspTestRandom >("Greedy"); + tspTestRandom >("Nearest Insertion"); + tspTestRandom >("Farthest Insertion"); + tspTestRandom >("Cheapest Insertion"); + tspTestRandom >("Random Insertion"); + tspTestRandom >("Christofides"); + tspTestRandom >("2-opt"); + + return 0; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/test/unionfind_test.cc b/extern/quadriflow/3rd/lemon-1.3.1/test/unionfind_test.cc new file mode 100644 index 00000000000..e82d8e64ae7 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/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 +#include +#include +#include "test_tools.h" + +using namespace lemon; +using namespace std; + +typedef UnionFindEnum > UFE; + +int main() { + ListGraph g; + ListGraph::NodeMap base(g); + UFE U(base); + vector 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; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/tools/CMakeLists.txt b/extern/quadriflow/3rd/lemon-1.3.1/tools/CMakeLists.txt new file mode 100644 index 00000000000..64b7df77f65 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/tools/CMakeLists.txt @@ -0,0 +1,31 @@ +INCLUDE_DIRECTORIES( + ${PROJECT_SOURCE_DIR} + ${PROJECT_BINARY_DIR} +) + +LINK_DIRECTORIES( + ${PROJECT_BINARY_DIR}/lemon +) + +ADD_EXECUTABLE(lgf-gen lgf-gen.cc) +TARGET_LINK_LIBRARIES(lgf-gen lemon) + +ADD_EXECUTABLE(dimacs-to-lgf dimacs-to-lgf.cc) +TARGET_LINK_LIBRARIES(dimacs-to-lgf lemon) + +ADD_EXECUTABLE(dimacs-solver dimacs-solver.cc) +TARGET_LINK_LIBRARIES(dimacs-solver lemon) + +INSTALL( + TARGETS lgf-gen dimacs-to-lgf dimacs-solver + RUNTIME DESTINATION bin + COMPONENT bin +) + +IF(NOT WIN32) + INSTALL( + PROGRAMS ${CMAKE_CURRENT_SOURCE_DIR}/lemon-0.x-to-1.x.sh + DESTINATION bin + COMPONENT bin + ) +ENDIF() diff --git a/extern/quadriflow/3rd/lemon-1.3.1/tools/dimacs-solver.cc b/extern/quadriflow/3rd/lemon-1.3.1/tools/dimacs-solver.cc new file mode 100644 index 00000000000..60da2330e50 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/tools/dimacs-solver.cc @@ -0,0 +1,279 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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. + * + */ + +///\ingroup tools +///\file +///\brief DIMACS problem solver. +/// +/// This program solves various problems given in DIMACS format. +/// +/// See +/// \code +/// dimacs-solver --help +/// \endcode +/// for more info on usage. + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +using namespace lemon; +typedef SmartDigraph Digraph; +DIGRAPH_TYPEDEFS(Digraph); +typedef SmartGraph Graph; + +template +void solve_sp(ArgParser &ap, std::istream &is, std::ostream &, + DimacsDescriptor &desc) +{ + bool report = !ap.given("q"); + Digraph g; + Node s; + Digraph::ArcMap len(g); + Timer t; + t.restart(); + readDimacsSp(is, g, len, s, desc); + if(report) std::cerr << "Read the file: " << t << '\n'; + t.restart(); + Dijkstra > dij(g,len); + if(report) std::cerr << "Setup Dijkstra class: " << t << '\n'; + t.restart(); + dij.run(s); + if(report) std::cerr << "Run Dijkstra: " << t << '\n'; +} + +template +void solve_max(ArgParser &ap, std::istream &is, std::ostream &, + Value infty, DimacsDescriptor &desc) +{ + bool report = !ap.given("q"); + Digraph g; + Node s,t; + Digraph::ArcMap cap(g); + Timer ti; + ti.restart(); + readDimacsMax(is, g, cap, s, t, infty, desc); + if(report) std::cerr << "Read the file: " << ti << '\n'; + ti.restart(); + Preflow > pre(g,cap,s,t); + if(report) std::cerr << "Setup Preflow class: " << ti << '\n'; + ti.restart(); + pre.run(); + if(report) std::cerr << "Run Preflow: " << ti << '\n'; + if(report) std::cerr << "\nMax flow value: " << pre.flowValue() << '\n'; +} + +template +void solve_min(ArgParser &ap, std::istream &is, std::ostream &, + Value infty, DimacsDescriptor &desc) +{ + bool report = !ap.given("q"); + Digraph g; + Digraph::ArcMap lower(g), cap(g), cost(g); + Digraph::NodeMap sup(g); + Timer ti; + + ti.restart(); + readDimacsMin(is, g, lower, cap, cost, sup, infty, desc); + ti.stop(); + Value sum_sup = 0; + for (Digraph::NodeIt n(g); n != INVALID; ++n) { + sum_sup += sup[n]; + } + if (report) { + std::cerr << "Sum of supply values: " << sum_sup << "\n"; + if (sum_sup <= 0) + std::cerr << "GEQ supply contraints are used for NetworkSimplex\n\n"; + else + std::cerr << "LEQ supply contraints are used for NetworkSimplex\n\n"; + } + if (report) std::cerr << "Read the file: " << ti << '\n'; + + typedef NetworkSimplex MCF; + ti.restart(); + MCF ns(g); + ns.lowerMap(lower).upperMap(cap).costMap(cost).supplyMap(sup); + if (sum_sup > 0) ns.supplyType(ns.LEQ); + if (report) std::cerr << "Setup NetworkSimplex class: " << ti << '\n'; + ti.restart(); + typename MCF::ProblemType res = ns.run(); + if (report) { + std::cerr << "Run NetworkSimplex: " << ti << "\n\n"; + std::cerr << "Feasible flow: " << (res == MCF::OPTIMAL ? "found" : + "not found") << '\n'; + if (res) std::cerr << "Min flow cost: " + << ns.template totalCost() << '\n'; + } +} + +void solve_mat(ArgParser &ap, std::istream &is, std::ostream &, + DimacsDescriptor &desc) +{ + bool report = !ap.given("q"); + Graph g; + Timer ti; + ti.restart(); + readDimacsMat(is, g, desc); + if(report) std::cerr << "Read the file: " << ti << '\n'; + ti.restart(); + MaxMatching mat(g); + if(report) std::cerr << "Setup MaxMatching class: " << ti << '\n'; + ti.restart(); + mat.run(); + if(report) std::cerr << "Run MaxMatching: " << ti << '\n'; + if(report) std::cerr << "\nCardinality of max matching: " + << mat.matchingSize() << '\n'; +} + + +template +void solve(ArgParser &ap, std::istream &is, std::ostream &os, + DimacsDescriptor &desc) +{ + std::stringstream iss(static_cast(ap["infcap"])); + Value infty; + iss >> infty; + if(iss.fail()) + { + std::cerr << "Cannot interpret '" + << static_cast(ap["infcap"]) << "' as infinite" + << std::endl; + exit(1); + } + + switch(desc.type) + { + case DimacsDescriptor::MIN: + solve_min(ap,is,os,infty,desc); + break; + case DimacsDescriptor::MAX: + solve_max(ap,is,os,infty,desc); + break; + case DimacsDescriptor::SP: + solve_sp(ap,is,os,desc); + break; + case DimacsDescriptor::MAT: + solve_mat(ap,is,os,desc); + break; + default: + break; + } +} + +int main(int argc, const char *argv[]) { + + std::string inputName; + std::string outputName; + + ArgParser ap(argc, argv); + ap.other("[INFILE [OUTFILE]]", + "If either the INFILE or OUTFILE file is missing the standard\n" + " input/output will be used instead.") + .boolOption("q", "Do not print any report") + .boolOption("int","Use 'int' for capacities, costs etc. (default)") + .optionGroup("datatype","int") +#ifdef LEMON_HAVE_LONG_LONG + .boolOption("long","Use 'long long' for capacities, costs etc.") + .optionGroup("datatype","long") +#endif + .boolOption("double","Use 'double' for capacities, costs etc.") + .optionGroup("datatype","double") + .boolOption("ldouble","Use 'long double' for capacities, costs etc.") + .optionGroup("datatype","ldouble") + .onlyOneGroup("datatype") + .stringOption("infcap","Value used for 'very high' capacities","0") + .run(); + + std::ifstream input; + std::ofstream output; + + switch(ap.files().size()) + { + case 2: + output.open(ap.files()[1].c_str()); + if (!output) { + throw IoError("Cannot open the file for writing", ap.files()[1]); + } + case 1: + input.open(ap.files()[0].c_str()); + if (!input) { + throw IoError("File cannot be found", ap.files()[0]); + } + case 0: + break; + default: + std::cerr << ap.commandName() << ": too many arguments\n"; + return 1; + } + std::istream& is = (ap.files().size()<1 ? std::cin : input); + std::ostream& os = (ap.files().size()<2 ? std::cout : output); + + DimacsDescriptor desc = dimacsType(is); + + if(!ap.given("q")) + { + std::cout << "Problem type: "; + switch(desc.type) + { + case DimacsDescriptor::MIN: + std::cout << "min"; + break; + case DimacsDescriptor::MAX: + std::cout << "max"; + break; + case DimacsDescriptor::SP: + std::cout << "sp"; + case DimacsDescriptor::MAT: + std::cout << "mat"; + break; + default: + exit(1); + break; + } + std::cout << "\nNum of nodes: " << desc.nodeNum; + std::cout << "\nNum of arcs: " << desc.edgeNum; + std::cout << "\n\n"; + } + + if(ap.given("double")) + solve(ap,is,os,desc); + else if(ap.given("ldouble")) + solve(ap,is,os,desc); +#ifdef LEMON_HAVE_LONG_LONG + else if(ap.given("long")) + solve(ap,is,os,desc); + else solve(ap,is,os,desc); +#else + else solve(ap,is,os,desc); +#endif + + return 0; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/tools/dimacs-to-lgf.cc b/extern/quadriflow/3rd/lemon-1.3.1/tools/dimacs-to-lgf.cc new file mode 100644 index 00000000000..3968645dd90 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/tools/dimacs-to-lgf.cc @@ -0,0 +1,148 @@ +/* -*- 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. + * + */ + +///\ingroup tools +///\file +///\brief DIMACS to LGF converter. +/// +/// This program converts various DIMACS formats to the LEMON Digraph Format +/// (LGF). +/// +/// See +/// \code +/// dimacs-to-lgf --help +/// \endcode +/// for more info on the usage. + +#include +#include +#include + +#include +#include +#include + +#include +#include + +using namespace std; +using namespace lemon; + + +int main(int argc, const char *argv[]) { + typedef SmartDigraph Digraph; + + typedef Digraph::Arc Arc; + typedef Digraph::Node Node; + typedef Digraph::ArcIt ArcIt; + typedef Digraph::NodeIt NodeIt; + typedef Digraph::ArcMap DoubleArcMap; + typedef Digraph::NodeMap DoubleNodeMap; + + std::string inputName; + std::string outputName; + + ArgParser ap(argc, argv); + ap.other("[INFILE [OUTFILE]]", + "If either the INFILE or OUTFILE file is missing the standard\n" + " input/output will be used instead.") + .run(); + + ifstream input; + ofstream output; + + switch(ap.files().size()) + { + case 2: + output.open(ap.files()[1].c_str()); + if (!output) { + throw IoError("Cannot open the file for writing", ap.files()[1]); + } + case 1: + input.open(ap.files()[0].c_str()); + if (!input) { + throw IoError("File cannot be found", ap.files()[0]); + } + case 0: + break; + default: + cerr << ap.commandName() << ": too many arguments\n"; + return 1; + } + istream& is = (ap.files().size()<1 ? cin : input); + ostream& os = (ap.files().size()<2 ? cout : output); + + DimacsDescriptor desc = dimacsType(is); + switch(desc.type) + { + case DimacsDescriptor::MIN: + { + Digraph digraph; + DoubleArcMap lower(digraph), capacity(digraph), cost(digraph); + DoubleNodeMap supply(digraph); + readDimacsMin(is, digraph, lower, capacity, cost, supply, 0, desc); + DigraphWriter(digraph, os). + nodeMap("supply", supply). + arcMap("lower", lower). + arcMap("capacity", capacity). + arcMap("cost", cost). + attribute("problem","min"). + run(); + } + break; + case DimacsDescriptor::MAX: + { + Digraph digraph; + Node s, t; + DoubleArcMap capacity(digraph); + readDimacsMax(is, digraph, capacity, s, t, 0, desc); + DigraphWriter(digraph, os). + arcMap("capacity", capacity). + node("source", s). + node("target", t). + attribute("problem","max"). + run(); + } + break; + case DimacsDescriptor::SP: + { + Digraph digraph; + Node s; + DoubleArcMap capacity(digraph); + readDimacsSp(is, digraph, capacity, s, desc); + DigraphWriter(digraph, os). + arcMap("capacity", capacity). + node("source", s). + attribute("problem","sp"). + run(); + } + break; + case DimacsDescriptor::MAT: + { + Digraph digraph; + readDimacsMat(is, digraph,desc); + DigraphWriter(digraph, os). + attribute("problem","mat"). + run(); + } + break; + default: + break; + } + return 0; +} diff --git a/extern/quadriflow/3rd/lemon-1.3.1/tools/lemon-0.x-to-1.x.sh b/extern/quadriflow/3rd/lemon-1.3.1/tools/lemon-0.x-to-1.x.sh new file mode 100755 index 00000000000..1dac1be653a --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/tools/lemon-0.x-to-1.x.sh @@ -0,0 +1,134 @@ +#!/bin/bash + +set -e + +if [ $# -eq 0 -o x$1 = "x-h" -o x$1 = "x-help" -o x$1 = "x--help" ]; then + echo "Usage:" + echo " $0 source-file(s)" + exit +fi + +for i in $@ +do + echo Update $i... + TMP=`mktemp` + sed -e "s/\/_gr_aph_label_/g"\ + -e "s/\/_gr_aph_label_s/g"\ + -e "s/\/_ed_ge_label_/g"\ + -e "s/\/_ed_ge_label_s/g"\ + -e "s/\/_digr_aph_label_/g"\ + -e "s/\/_digr_aph_label_s/g"\ + -e "s/\/_ar_c_label_/g"\ + -e "s/\/_ar_c_label_s/g"\ + -e "s/UGraph/_Gr_aph_label_/g"\ + -e "s/u[Gg]raph/_gr_aph_label_/g"\ + -e "s/Graph\>/_Digr_aph_label_/g"\ + -e "s/\/_digr_aph_label_/g"\ + -e "s/Graphs\>/_Digr_aph_label_s/g"\ + -e "s/\/_digr_aph_label_s/g"\ + -e "s/\([Gg]\)raph\([a-z]\)/_\1r_aph_label_\2/g"\ + -e "s/\([a-z_]\)graph/\1_gr_aph_label_/g"\ + -e "s/Graph/_Digr_aph_label_/g"\ + -e "s/graph/_digr_aph_label_/g"\ + -e "s/UEdge/_Ed_ge_label_/g"\ + -e "s/u[Ee]dge/_ed_ge_label_/g"\ + -e "s/IncEdgeIt/_In_cEd_geIt_label_/g"\ + -e "s/Edge\>/_Ar_c_label_/g"\ + -e "s/\/_ar_c_label_/g"\ + -e "s/_edge\>/__ar_c_label_/g"\ + -e "s/Edges\>/_Ar_c_label_s/g"\ + -e "s/\/_ar_c_label_s/g"\ + -e "s/_edges\>/__ar_c_label_s/g"\ + -e "s/\([Ee]\)dge\([a-z]\)/_\1d_ge_label_\2/g"\ + -e "s/\([a-z]\)edge/\1_ed_ge_label_/g"\ + -e "s/Edge/_Ar_c_label_/g"\ + -e "s/edge/_ar_c_label_/g"\ + -e "s/A[Nn]ode/_Re_d_label_/g"\ + -e "s/B[Nn]ode/_Blu_e_label_/g"\ + -e "s/A-[Nn]ode/_Re_d_label_/g"\ + -e "s/B-[Nn]ode/_Blu_e_label_/g"\ + -e "s/a[Nn]ode/_re_d_label_/g"\ + -e "s/b[Nn]ode/_blu_e_label_/g"\ + -e "s/\/_GR_APH_TY_PEDE_FS_label_/g"\ + -e "s/\/_DIGR_APH_TY_PEDE_FS_label_/g"\ + -e "s/_Digr_aph_label_/Digraph/g"\ + -e "s/_digr_aph_label_/digraph/g"\ + -e "s/_Gr_aph_label_/Graph/g"\ + -e "s/_gr_aph_label_/graph/g"\ + -e "s/_Ar_c_label_/Arc/g"\ + -e "s/_ar_c_label_/arc/g"\ + -e "s/_Ed_ge_label_/Edge/g"\ + -e "s/_ed_ge_label_/edge/g"\ + -e "s/_In_cEd_geIt_label_/IncEdgeIt/g"\ + -e "s/_Re_d_label_/Red/g"\ + -e "s/_Blu_e_label_/Blue/g"\ + -e "s/_re_d_label_/red/g"\ + -e "s/_blu_e_label_/blue/g"\ + -e "s/_GR_APH_TY_PEDE_FS_label_/GRAPH_TYPEDEFS/g"\ + -e "s/_DIGR_APH_TY_PEDE_FS_label_/DIGRAPH_TYPEDEFS/g"\ + -e "s/\/adaptors.h/g"\ + -e "s/\/core.h/g"\ + -e "s/\/lgf_reader.h/g"\ + -e "s/\/lgf_writer.h/g"\ + -e "s/\/connectivity.h/g"\ + -e "s/DigraphToEps/GraphToEps/g"\ + -e "s/digraphToEps/graphToEps/g"\ + -e "s/\/SetPredMap/g"\ + -e "s/\/SetDistMap/g"\ + -e "s/\/SetReachedMap/g"\ + -e "s/\/SetProcessedMap/g"\ + -e "s/\/SetHeap/g"\ + -e "s/\/SetStandradHeap/g"\ + -e "s/\/SetOperationTraits/g"\ + -e "s/\/SetStandardProcessedMap/g"\ + -e "s/\/graphCopy/g"\ + -e "s/\/digraphCopy/g"\ + -e "s/\/HypercubeGraph/g"\ + -e "s/\/RangeMap/g"\ + -e "s/\/rangeMap/g"\ + -e "s/\<\([sS]\)tdMap\>/\1parseMap/g"\ + -e "s/\<\([Ff]\)unctorMap\>/\1unctorToMap/g"\ + -e "s/\<\([Mm]\)apFunctor\>/\1apToFunctor/g"\ + -e "s/\<\([Ff]\)orkWriteMap\>/\1orkMap/g"\ + -e "s/\/LoggerBoolMap/g"\ + -e "s/\/loggerBoolMap/g"\ + -e "s/\/CrossRefMap/g"\ + -e "s/\/crossRefMap/g"\ + -e "s/\/RangeIdMap/g"\ + -e "s/\/rangeIdMap/g"\ + -e "s/\/Box/g"\ + -e "s/\/readNautyGraph/g"\ + -e "s/\/ReverseDigraph/g"\ + -e "s/\/reverseDigraph/g"\ + -e "s/\/SubDigraph/g"\ + -e "s/\/subDigraph/g"\ + -e "s/\/SubGraph/g"\ + -e "s/\/subGraph/g"\ + -e "s/\/FilterNodes/g"\ + -e "s/\/filterNodes/g"\ + -e "s/\/FilterArcs/g"\ + -e "s/\/filterArcs/g"\ + -e "s/\/Undirector/g"\ + -e "s/\/undirector/g"\ + -e "s/\/ResidualDigraph/g"\ + -e "s/\/residualDigraph/g"\ + -e "s/\/SplitNodes/g"\ + -e "s/\/splitNodes/g"\ + -e "s/\/SubGraph/g"\ + -e "s/\/subGraph/g"\ + -e "s/\/FilterNodes/g"\ + -e "s/\/filterNodes/g"\ + -e "s/\/FilterEdges/g"\ + -e "s/\/filterEdges/g"\ + -e "s/\/Orienter/g"\ + -e "s/\/orienter/g"\ + -e "s/\/CplexLp/g"\ + -e "s/\/CplexMip/g"\ + -e "s/\/GlpkLp/g"\ + -e "s/\/GlpkMip/g"\ + -e "s/\/SoplexLp/g"\ + <$i > $TMP + mv $TMP $i +done diff --git a/extern/quadriflow/3rd/lemon-1.3.1/tools/lgf-gen.cc b/extern/quadriflow/3rd/lemon-1.3.1/tools/lgf-gen.cc new file mode 100644 index 00000000000..390c8ae5972 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/tools/lgf-gen.cc @@ -0,0 +1,847 @@ +/* -*- 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. + * + */ + +/// \ingroup tools +/// \file +/// \brief Special plane graph generator. +/// +/// Graph generator application for various types of plane graphs. +/// +/// See +/// \code +/// lgf-gen --help +/// \endcode +/// for more information on the usage. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace lemon; + +typedef dim2::Point Point; + +GRAPH_TYPEDEFS(ListGraph); + +bool progress=true; + +int N; +// int girth; + +ListGraph g; + +std::vector nodes; +ListGraph::NodeMap coords(g); + + +double totalLen(){ + double tlen=0; + for(EdgeIt e(g);e!=INVALID;++e) + tlen+=std::sqrt((coords[g.v(e)]-coords[g.u(e)]).normSquare()); + return tlen; +} + +int tsp_impr_num=0; + +const double EPSILON=1e-8; +bool tsp_improve(Node u, Node v) +{ + double luv=std::sqrt((coords[v]-coords[u]).normSquare()); + Node u2=u; + Node v2=v; + do { + Node n; + for(IncEdgeIt e(g,v2);(n=g.runningNode(e))==u2;++e) { } + u2=v2; + v2=n; + if(luv+std::sqrt((coords[v2]-coords[u2]).normSquare())-EPSILON> + std::sqrt((coords[u]-coords[u2]).normSquare())+ + std::sqrt((coords[v]-coords[v2]).normSquare())) + { + g.erase(findEdge(g,u,v)); + g.erase(findEdge(g,u2,v2)); + g.addEdge(u2,u); + g.addEdge(v,v2); + tsp_impr_num++; + return true; + } + } while(v2!=u); + return false; +} + +bool tsp_improve(Node u) +{ + for(IncEdgeIt e(g,u);e!=INVALID;++e) + if(tsp_improve(u,g.runningNode(e))) return true; + return false; +} + +void tsp_improve() +{ + bool b; + do { + b=false; + for(NodeIt n(g);n!=INVALID;++n) + if(tsp_improve(n)) b=true; + } while(b); +} + +void tsp() +{ + for(int i=0;i" << l.b; + return os; +} + +bool cross(Line a, Line b) +{ + Point ao=rot90(a.b-a.a); + Point bo=rot90(b.b-b.a); + return (ao*(b.a-a.a))*(ao*(b.b-a.a))<0 && + (bo*(a.a-b.a))*(bo*(a.b-b.a))<0; +} + +struct Parc +{ + Node a; + Node b; + double len; +}; + +bool pedgeLess(Parc a,Parc b) +{ + return a.len arcs; + +namespace _delaunay_bits { + + struct Part { + int prev, curr, next; + + Part(int p, int c, int n) : prev(p), curr(c), next(n) {} + }; + + inline std::ostream& operator<<(std::ostream& os, const Part& part) { + os << '(' << part.prev << ',' << part.curr << ',' << part.next << ')'; + return os; + } + + inline double circle_point(const Point& p, const Point& q, const Point& r) { + double a = p.x * (q.y - r.y) + q.x * (r.y - p.y) + r.x * (p.y - q.y); + if (a == 0) return std::numeric_limits::quiet_NaN(); + + double d = (p.x * p.x + p.y * p.y) * (q.y - r.y) + + (q.x * q.x + q.y * q.y) * (r.y - p.y) + + (r.x * r.x + r.y * r.y) * (p.y - q.y); + + double e = (p.x * p.x + p.y * p.y) * (q.x - r.x) + + (q.x * q.x + q.y * q.y) * (r.x - p.x) + + (r.x * r.x + r.y * r.y) * (p.x - q.x); + + double f = (p.x * p.x + p.y * p.y) * (q.x * r.y - r.x * q.y) + + (q.x * q.x + q.y * q.y) * (r.x * p.y - p.x * r.y) + + (r.x * r.x + r.y * r.y) * (p.x * q.y - q.x * p.y); + + return d / (2 * a) + std::sqrt((d * d + e * e) / (4 * a * a) + f / a); + } + + inline bool circle_form(const Point& p, const Point& q, const Point& r) { + return rot90(q - p) * (r - q) < 0.0; + } + + inline double intersection(const Point& p, const Point& q, double sx) { + const double epsilon = 1e-8; + + if (p.x == q.x) return (p.y + q.y) / 2.0; + + if (sx < p.x + epsilon) return p.y; + if (sx < q.x + epsilon) return q.y; + + double a = q.x - p.x; + double b = (q.x - sx) * p.y - (p.x - sx) * q.y; + double d = (q.x - sx) * (p.x - sx) * (p - q).normSquare(); + return (b - std::sqrt(d)) / a; + } + + struct YLess { + + + YLess(const std::vector& points, double& sweep) + : _points(points), _sweep(sweep) {} + + bool operator()(const Part& l, const Part& r) const { + const double epsilon = 1e-8; + + // std::cerr << l << " vs " << r << std::endl; + double lbx = l.prev != -1 ? + intersection(_points[l.prev], _points[l.curr], _sweep) : + - std::numeric_limits::infinity(); + double rbx = r.prev != -1 ? + intersection(_points[r.prev], _points[r.curr], _sweep) : + - std::numeric_limits::infinity(); + double lex = l.next != -1 ? + intersection(_points[l.curr], _points[l.next], _sweep) : + std::numeric_limits::infinity(); + double rex = r.next != -1 ? + intersection(_points[r.curr], _points[r.next], _sweep) : + std::numeric_limits::infinity(); + + if (lbx > lex) std::swap(lbx, lex); + if (rbx > rex) std::swap(rbx, rex); + + if (lex < epsilon + rex && lbx + epsilon < rex) return true; + if (rex < epsilon + lex && rbx + epsilon < lex) return false; + return lex < rex; + } + + const std::vector& _points; + double& _sweep; + }; + + struct BeachIt; + + typedef std::multimap SpikeHeap; + + typedef std::multimap Beach; + + struct BeachIt { + Beach::iterator it; + + BeachIt(Beach::iterator iter) : it(iter) {} + }; + +} + +inline void delaunay() { + Counter cnt("Number of arcs added: "); + + using namespace _delaunay_bits; + + typedef _delaunay_bits::Part Part; + typedef std::vector > SiteHeap; + + + std::vector points; + std::vector nodes; + + for (NodeIt it(g); it != INVALID; ++it) { + nodes.push_back(it); + points.push_back(coords[it]); + } + + SiteHeap siteheap(points.size()); + + double sweep; + + + for (int i = 0; i < int(siteheap.size()); ++i) { + siteheap[i] = std::make_pair(points[i].x, i); + } + + std::sort(siteheap.begin(), siteheap.end()); + sweep = siteheap.front().first; + + YLess yless(points, sweep); + Beach beach(yless); + + SpikeHeap spikeheap; + + std::set > arcs; + + int siteindex = 0; + { + SiteHeap front; + + while (siteindex < int(siteheap.size()) && + siteheap[0].first == siteheap[siteindex].first) { + front.push_back(std::make_pair(points[siteheap[siteindex].second].y, + siteheap[siteindex].second)); + ++siteindex; + } + + std::sort(front.begin(), front.end()); + + for (int i = 0; i < int(front.size()); ++i) { + int prev = (i == 0 ? -1 : front[i - 1].second); + int curr = front[i].second; + int next = (i + 1 == int(front.size()) ? -1 : front[i + 1].second); + + beach.insert(std::make_pair(Part(prev, curr, next), + spikeheap.end())); + } + } + + while (siteindex < int(points.size()) || !spikeheap.empty()) { + + SpikeHeap::iterator spit = spikeheap.begin(); + + if (siteindex < int(points.size()) && + (spit == spikeheap.end() || siteheap[siteindex].first < spit->first)) { + int site = siteheap[siteindex].second; + sweep = siteheap[siteindex].first; + + Beach::iterator bit = beach.upper_bound(Part(site, site, site)); + + if (bit->second != spikeheap.end()) { + delete bit->second->second; + spikeheap.erase(bit->second); + } + + int prev = bit->first.prev; + int curr = bit->first.curr; + int next = bit->first.next; + + beach.erase(bit); + + SpikeHeap::iterator pit = spikeheap.end(); + if (prev != -1 && + circle_form(points[prev], points[curr], points[site])) { + double x = circle_point(points[prev], points[curr], points[site]); + pit = spikeheap.insert(std::make_pair(x, new BeachIt(beach.end()))); + pit->second->it = + beach.insert(std::make_pair(Part(prev, curr, site), pit)); + } else { + beach.insert(std::make_pair(Part(prev, curr, site), pit)); + } + + beach.insert(std::make_pair(Part(curr, site, curr), spikeheap.end())); + + SpikeHeap::iterator nit = spikeheap.end(); + if (next != -1 && + circle_form(points[site], points[curr],points[next])) { + double x = circle_point(points[site], points[curr], points[next]); + nit = spikeheap.insert(std::make_pair(x, new BeachIt(beach.end()))); + nit->second->it = + beach.insert(std::make_pair(Part(site, curr, next), nit)); + } else { + beach.insert(std::make_pair(Part(site, curr, next), nit)); + } + + ++siteindex; + } else { + sweep = spit->first; + + Beach::iterator bit = spit->second->it; + + int prev = bit->first.prev; + int curr = bit->first.curr; + int next = bit->first.next; + + { + std::pair arc; + + arc = prev < curr ? + std::make_pair(prev, curr) : std::make_pair(curr, prev); + + if (arcs.find(arc) == arcs.end()) { + arcs.insert(arc); + g.addEdge(nodes[prev], nodes[curr]); + ++cnt; + } + + arc = curr < next ? + std::make_pair(curr, next) : std::make_pair(next, curr); + + if (arcs.find(arc) == arcs.end()) { + arcs.insert(arc); + g.addEdge(nodes[curr], nodes[next]); + ++cnt; + } + } + + Beach::iterator pbit = bit; --pbit; + int ppv = pbit->first.prev; + Beach::iterator nbit = bit; ++nbit; + int nnt = nbit->first.next; + + if (bit->second != spikeheap.end()) + { + delete bit->second->second; + spikeheap.erase(bit->second); + } + if (pbit->second != spikeheap.end()) + { + delete pbit->second->second; + spikeheap.erase(pbit->second); + } + if (nbit->second != spikeheap.end()) + { + delete nbit->second->second; + spikeheap.erase(nbit->second); + } + + beach.erase(nbit); + beach.erase(bit); + beach.erase(pbit); + + SpikeHeap::iterator pit = spikeheap.end(); + if (ppv != -1 && ppv != next && + circle_form(points[ppv], points[prev], points[next])) { + double x = circle_point(points[ppv], points[prev], points[next]); + if (x < sweep) x = sweep; + pit = spikeheap.insert(std::make_pair(x, new BeachIt(beach.end()))); + pit->second->it = + beach.insert(std::make_pair(Part(ppv, prev, next), pit)); + } else { + beach.insert(std::make_pair(Part(ppv, prev, next), pit)); + } + + SpikeHeap::iterator nit = spikeheap.end(); + if (nnt != -1 && prev != nnt && + circle_form(points[prev], points[next], points[nnt])) { + double x = circle_point(points[prev], points[next], points[nnt]); + if (x < sweep) x = sweep; + nit = spikeheap.insert(std::make_pair(x, new BeachIt(beach.end()))); + nit->second->it = + beach.insert(std::make_pair(Part(prev, next, nnt), nit)); + } else { + beach.insert(std::make_pair(Part(prev, next, nnt), nit)); + } + + } + } + + for (Beach::iterator it = beach.begin(); it != beach.end(); ++it) { + int curr = it->first.curr; + int next = it->first.next; + + if (next == -1) continue; + + std::pair arc; + + arc = curr < next ? + std::make_pair(curr, next) : std::make_pair(next, curr); + + if (arcs.find(arc) == arcs.end()) { + arcs.insert(arc); + g.addEdge(nodes[curr], nodes[next]); + ++cnt; + } + } +} + +void sparse(int d) +{ + Counter cnt("Number of arcs removed: "); + Bfs bfs(g); + for(std::vector::reverse_iterator ei=arcs.rbegin(); + ei!=arcs.rend();++ei) + { + Node a=g.u(*ei); + Node b=g.v(*ei); + g.erase(*ei); + bfs.run(a,b); + if(bfs.predArc(b)==INVALID || bfs.dist(b)>d) + g.addEdge(a,b); + else cnt++; + } +} + +void sparse2(int d) +{ + Counter cnt("Number of arcs removed: "); + for(std::vector::reverse_iterator ei=arcs.rbegin(); + ei!=arcs.rend();++ei) + { + Node a=g.u(*ei); + Node b=g.v(*ei); + g.erase(*ei); + ConstMap cegy(1); + Suurballe > sur(g,cegy); + int k=sur.run(a,b,2); + if(k<2 || sur.totalLength()>d) + g.addEdge(a,b); + else cnt++; +// else std::cout << "Remove arc " << g.id(a) << "-" << g.id(b) << '\n'; + } +} + +void sparseTriangle(int d) +{ + Counter cnt("Number of arcs added: "); + std::vector pedges; + for(NodeIt n(g);n!=INVALID;++n) + for(NodeIt m=++(NodeIt(n));m!=INVALID;++m) + { + Parc p; + p.a=n; + p.b=m; + p.len=(coords[m]-coords[n]).normSquare(); + pedges.push_back(p); + } + std::sort(pedges.begin(),pedges.end(),pedgeLess); + for(std::vector::iterator pi=pedges.begin();pi!=pedges.end();++pi) + { + Line li(pi->a,pi->b); + EdgeIt e(g); + for(;e!=INVALID && !cross(e,li);++e) ; + Edge ne; + if(e==INVALID) { + ConstMap cegy(1); + Suurballe > sur(g,cegy); + int k=sur.run(pi->a,pi->b,2); + if(k<2 || sur.totalLength()>d) + { + ne=g.addEdge(pi->a,pi->b); + arcs.push_back(ne); + cnt++; + } + } + } +} + +template +class LengthSquareMap { +public: + typedef typename Graph::Edge Key; + typedef typename CoordMap::Value::Value Value; + + LengthSquareMap(const Graph& graph, const CoordMap& coords) + : _graph(graph), _coords(coords) {} + + Value operator[](const Key& key) const { + return (_coords[_graph.v(key)] - + _coords[_graph.u(key)]).normSquare(); + } + +private: + + const Graph& _graph; + const CoordMap& _coords; +}; + +void minTree() { + std::vector pedges; + Timer T; + std::cout << T.realTime() << "s: Creating delaunay triangulation...\n"; + delaunay(); + std::cout << T.realTime() << "s: Calculating spanning tree...\n"; + LengthSquareMap > ls(g, coords); + ListGraph::EdgeMap tree(g); + kruskal(g, ls, tree); + std::cout << T.realTime() << "s: Removing non tree arcs...\n"; + std::vector remove; + for (EdgeIt e(g); e != INVALID; ++e) { + if (!tree[e]) remove.push_back(e); + } + for(int i = 0; i < int(remove.size()); ++i) { + g.erase(remove[i]); + } + std::cout << T.realTime() << "s: Done\n"; +} + +void tsp2() +{ + std::cout << "Find a tree..." << std::endl; + + minTree(); + + std::cout << "Total arc length (tree) : " << totalLen() << std::endl; + + std::cout << "Make it Euler..." << std::endl; + + { + std::vector leafs; + for(NodeIt n(g);n!=INVALID;++n) + if(countIncEdges(g,n)%2==1) leafs.push_back(n); + +// for(unsigned int i=0;i pedges; + for(unsigned int i=0;i enext(g); + { + EulerIt e(g); + Arc eo=e; + Arc ef=e; +// std::cout << "Tour arc: " << g.id(Edge(e)) << std::endl; + for(++e;e!=INVALID;++e) + { +// std::cout << "Tour arc: " << g.id(Edge(e)) << std::endl; + enext[eo]=e; + eo=e; + } + enext[eo]=ef; + } + + std::cout << "Creating a tour from that..." << std::endl; + + int nnum = countNodes(g); + int ednum = countEdges(g); + + for(Arc p=enext[EdgeIt(g)];ednum>nnum;p=enext[p]) + { +// std::cout << "Checking arc " << g.id(p) << std::endl; + Arc e=enext[p]; + Arc f=enext[e]; + Node n2=g.source(f); + Node n1=g.oppositeNode(n2,e); + Node n3=g.oppositeNode(n2,f); + if(countIncEdges(g,n2)>2) + { +// std::cout << "Remove an Arc" << std::endl; + Arc ff=enext[f]; + g.erase(e); + g.erase(f); + if(n1!=n3) + { + Arc ne=g.direct(g.addEdge(n1,n3),n1); + enext[p]=ne; + enext[ne]=ff; + ednum--; + } + else { + enext[p]=ff; + ednum-=2; + } + } + } + + std::cout << "Total arc length (tour) : " << totalLen() << std::endl; + + std::cout << "2-opt the tour..." << std::endl; + + tsp_improve(); + + std::cout << "Total arc length (2-opt tour) : " << totalLen() << std::endl; +} + + +int main(int argc,const char **argv) +{ + ArgParser ap(argc,argv); + +// bool eps; + bool disc_d, square_d, gauss_d; +// bool tsp_a,two_a,tree_a; + int num_of_cities=1; + double area=1; + N=100; +// girth=10; + std::string ndist("disc"); + ap.refOption("n", "Number of nodes (default is 100)", N) + .intOption("g", "Girth parameter (default is 10)", 10) + .refOption("cities", "Number of cities (default is 1)", num_of_cities) + .refOption("area", "Full relative area of the cities (default is 1)", area) + .refOption("disc", "Nodes are evenly distributed on a unit disc (default)", + disc_d) + .optionGroup("dist", "disc") + .refOption("square", "Nodes are evenly distributed on a unit square", + square_d) + .optionGroup("dist", "square") + .refOption("gauss", "Nodes are located according to a two-dim Gauss " + "distribution", gauss_d) + .optionGroup("dist", "gauss") + .onlyOneGroup("dist") + .boolOption("eps", "Also generate .eps output (.eps)") + .boolOption("nonodes", "Draw only the edges in the generated .eps output") + .boolOption("dir", "Directed graph is generated (each edge is replaced by " + "two directed arcs)") + .boolOption("2con", "Create a two connected planar graph") + .optionGroup("alg","2con") + .boolOption("tree", "Create a min. cost spanning tree") + .optionGroup("alg","tree") + .boolOption("tsp", "Create a TSP tour") + .optionGroup("alg","tsp") + .boolOption("tsp2", "Create a TSP tour (tree based)") + .optionGroup("alg","tsp2") + .boolOption("dela", "Delaunay triangulation graph") + .optionGroup("alg","dela") + .onlyOneGroup("alg") + .boolOption("rand", "Use time seed for random number generator") + .optionGroup("rand", "rand") + .intOption("seed", "Random seed", -1) + .optionGroup("rand", "seed") + .onlyOneGroup("rand") + .other("[prefix]","Prefix of the output files. Default is 'lgf-gen-out'") + .run(); + + if (ap["rand"]) { + int seed = int(time(0)); + std::cout << "Random number seed: " << seed << std::endl; + rnd = Random(seed); + } + if (ap.given("seed")) { + int seed = ap["seed"]; + std::cout << "Random number seed: " << seed << std::endl; + rnd = Random(seed); + } + + std::string prefix; + switch(ap.files().size()) + { + case 0: + prefix="lgf-gen-out"; + break; + case 1: + prefix=ap.files()[0]; + break; + default: + std::cerr << "\nAt most one prefix can be given\n\n"; + exit(1); + } + + double sum_sizes=0; + std::vector sizes; + std::vector cum_sizes; + for(int s=0;s(g,prefix+".lgf"). + nodeMap("coordinates_x",scaleMap(xMap(coords),600)). + nodeMap("coordinates_y",scaleMap(yMap(coords),600)). + run(); + else GraphWriter(g,prefix+".lgf"). + nodeMap("coordinates_x",scaleMap(xMap(coords),600)). + nodeMap("coordinates_y",scaleMap(yMap(coords),600)). + run(); +} + diff --git a/extern/quadriflow/3rd/pcg32/pcg32/pcg32.h b/extern/quadriflow/3rd/pcg32/pcg32/pcg32.h new file mode 100644 index 00000000000..aa06f28a845 --- /dev/null +++ b/extern/quadriflow/3rd/pcg32/pcg32/pcg32.h @@ -0,0 +1,209 @@ +/* + * Tiny self-contained version of the PCG Random Number Generation for C++ + * put together from pieces of the much larger C/C++ codebase. + * Wenzel Jakob, February 2015 + * + * The PCG random number generator was developed by Melissa O'Neill + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For additional information about the PCG random number generation scheme, + * including its license and other licensing options, visit + * + * http://www.pcg-random.org + */ + +#ifndef __PCG32_H +#define __PCG32_H 1 + +#define PCG32_DEFAULT_STATE 0x853c49e6748fea9bULL +#define PCG32_DEFAULT_STREAM 0xda3e39cb94b95bdbULL +#define PCG32_MULT 0x5851f42d4c957f2dULL + +#include +#include +#include +#include + +/// PCG32 Pseudorandom number generator +struct pcg32 { + /// Initialize the pseudorandom number generator with default seed + pcg32() : state(PCG32_DEFAULT_STATE), inc(PCG32_DEFAULT_STREAM) {} + + /// Initialize the pseudorandom number generator with the \ref seed() function + pcg32(uint64_t initstate, uint64_t initseq = 1u) { seed(initstate, initseq); } + + /** + * \brief Seed the pseudorandom number generator + * + * Specified in two parts: a state initializer and a sequence selection + * constant (a.k.a. stream id) + */ + void seed(uint64_t initstate, uint64_t initseq = 1) { + state = 0U; + inc = (initseq << 1u) | 1u; + nextUInt(); + state += initstate; + nextUInt(); + } + + /// Generate a uniformly distributed unsigned 32-bit random number + uint32_t nextUInt() { + uint64_t oldstate = state; + state = oldstate * PCG32_MULT + inc; + uint32_t xorshifted = (uint32_t) (((oldstate >> 18u) ^ oldstate) >> 27u); + uint32_t rot = (uint32_t) (oldstate >> 59u); + return (xorshifted >> rot) | (xorshifted << ((~rot + 1u) & 31)); + } + + /// Generate a uniformly distributed number, r, where 0 <= r < bound + uint32_t nextUInt(uint32_t bound) { + // To avoid bias, we need to make the range of the RNG a multiple of + // bound, which we do by dropping output less than a threshold. + // A naive scheme to calculate the threshold would be to do + // + // uint32_t threshold = 0x100000000ull % bound; + // + // but 64-bit div/mod is slower than 32-bit div/mod (especially on + // 32-bit platforms). In essence, we do + // + // uint32_t threshold = (0x100000000ull-bound) % bound; + // + // because this version will calculate the same modulus, but the LHS + // value is less than 2^32. + + uint32_t threshold = (~bound+1u) % bound; + + // Uniformity guarantees that this loop will terminate. In practice, it + // should usually terminate quickly; on average (assuming all bounds are + // equally likely), 82.25% of the time, we can expect it to require just + // one iteration. In the worst case, someone passes a bound of 2^31 + 1 + // (i.e., 2147483649), which invalidates almost 50% of the range. In + // practice, bounds are typically small and only a tiny amount of the range + // is eliminated. + for (;;) { + uint32_t r = nextUInt(); + if (r >= threshold) + return r % bound; + } + } + + /// Generate a single precision floating point value on the interval [0, 1) + float nextFloat() { + /* Trick from MTGP: generate an uniformly distributed + single precision number in [1,2) and subtract 1. */ + union { + uint32_t u; + float f; + } x; + x.u = (nextUInt() >> 9) | 0x3f800000UL; + return x.f - 1.0f; + } + + /** + * \brief Generate a double precision floating point value on the interval [0, 1) + * + * \remark Since the underlying random number generator produces 32 bit output, + * only the first 32 mantissa bits will be filled (however, the resolution is still + * finer than in \ref nextFloat(), which only uses 23 mantissa bits) + */ + double nextDouble() { + /* Trick from MTGP: generate an uniformly distributed + double precision number in [1,2) and subtract 1. */ + union { + uint64_t u; + double d; + } x; + x.u = ((uint64_t) nextUInt() << 20) | 0x3ff0000000000000ULL; + return x.d - 1.0; + } + + /** + * \brief Multi-step advance function (jump-ahead, jump-back) + * + * The method used here is based on Brown, "Random Number Generation + * with Arbitrary Stride", Transactions of the American Nuclear + * Society (Nov. 1994). The algorithm is very similar to fast + * exponentiation. + */ + void advance(int64_t delta_) { + uint64_t + cur_mult = PCG32_MULT, + cur_plus = inc, + acc_mult = 1u, + acc_plus = 0u; + + /* Even though delta is an unsigned integer, we can pass a signed + integer to go backwards, it just goes "the long way round". */ + uint64_t delta = (uint64_t) delta_; + + while (delta > 0) { + if (delta & 1) { + acc_mult *= cur_mult; + acc_plus = acc_plus * cur_mult + cur_plus; + } + cur_plus = (cur_mult + 1) * cur_plus; + cur_mult *= cur_mult; + delta /= 2; + } + state = acc_mult * state + acc_plus; + } + + /** + * \brief Draw uniformly distributed permutation and permute the + * given STL container + * + * From: Knuth, TAoCP Vol. 2 (3rd 3d), Section 3.4.2 + */ + template void shuffle(Iterator begin, Iterator end) { + if (begin <= end) return; + for (Iterator it = end - 1; it > begin; --it) + std::iter_swap(it, begin + nextUInt((uint32_t) (it - begin + 1))); + } + + /// Compute the distance between two PCG32 pseudorandom number generators + int64_t operator-(const pcg32 &other) const { + assert(inc == other.inc); + + uint64_t + cur_mult = PCG32_MULT, + cur_plus = inc, + cur_state = other.state, + the_bit = 1u, + distance = 0u; + + while (state != cur_state) { + if ((state & the_bit) != (cur_state & the_bit)) { + cur_state = cur_state * cur_mult + cur_plus; + distance |= the_bit; + } + assert((state & the_bit) == (cur_state & the_bit)); + the_bit <<= 1; + cur_plus = (cur_mult + 1ULL) * cur_plus; + cur_mult *= cur_mult; + } + + return (int64_t) distance; + } + + /// Equality operator + bool operator==(const pcg32 &other) const { return state == other.state && inc == other.inc; } + + /// Inequality operator + bool operator!=(const pcg32 &other) const { return state != other.state || inc != other.inc; } + + uint64_t state; // RNG state. All values are possible. + uint64_t inc; // Controls which RNG sequence (stream) is selected. Must *always* be odd. +}; + +#endif // __PCG32_H diff --git a/extern/quadriflow/3rd/pss/pss/parallel_stable_sort.h b/extern/quadriflow/3rd/pss/pss/parallel_stable_sort.h new file mode 100644 index 00000000000..3d8854f92ca --- /dev/null +++ b/extern/quadriflow/3rd/pss/pss/parallel_stable_sort.h @@ -0,0 +1,140 @@ +/* + Copyright (C) 2014 Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ +#include +#include +#include + +#include "pss_common.h" + +namespace pss { + +namespace internal { + +template +class merge_task: public tbb::task { + tbb::task* execute(); + RandomAccessIterator1 xs, xe; + RandomAccessIterator2 ys, ye; + RandomAccessIterator3 zs; + Compare comp; + bool destroy; +public: + merge_task( RandomAccessIterator1 xs_, RandomAccessIterator1 xe_, RandomAccessIterator2 ys_, RandomAccessIterator2 ye_, RandomAccessIterator3 zs_, bool destroy_, Compare comp_ ) : + xs(xs_), xe(xe_), ys(ys_), ye(ye_), zs(zs_), comp(comp_), destroy(destroy_) + {} +}; + +template +tbb::task* merge_task::execute() { + const size_t MERGE_CUT_OFF = 2000; + auto n = (xe-xs) + (ye-ys); + if( (size_t) n <= MERGE_CUT_OFF ) { + serial_move_merge( xs, xe, ys, ye, zs, comp ); + if( destroy ) { + serial_destroy(xs,xe); + serial_destroy(ys,ye); + } + return NULL; + } else { + RandomAccessIterator1 xm; + RandomAccessIterator2 ym; + if( xe-xs < ye-ys ) { + ym = ys+(ye-ys)/2; + xm = std::upper_bound(xs,xe,*ym,comp); + } else { + xm = xs+(xe-xs)/2; + ym = std::lower_bound(ys,ye,*xm,comp); + } + RandomAccessIterator3 zm = zs + ((xm-xs) + (ym-ys)); + tbb::task* right = new( allocate_additional_child_of(*parent()) ) merge_task( xm, xe, ym, ye, zm, destroy, comp ); + spawn(*right); + recycle_as_continuation(); + xe = xm; + ye = ym; + return this; + } +} + +template +class stable_sort_task: public tbb::task { + tbb::task* execute(); + RandomAccessIterator1 xs, xe; + RandomAccessIterator2 zs; + Compare comp; + signed char inplace; +public: + stable_sort_task(RandomAccessIterator1 xs_, RandomAccessIterator1 xe_, RandomAccessIterator2 zs_, int inplace_, Compare comp_ ) : + xs(xs_), xe(xe_), zs(zs_), comp(comp_), inplace(inplace_) + {} +}; + +template +tbb::task* stable_sort_task::execute() { + const size_t SORT_CUT_OFF = 500; + if ((size_t) (xe - xs) <= SORT_CUT_OFF) { + stable_sort_base_case(xs, xe, zs, inplace, comp); + return NULL; + } else { + RandomAccessIterator1 xm = xs + (xe - xs) / 2; + RandomAccessIterator2 zm = zs + (xm - xs); + RandomAccessIterator2 ze = zs + (xe - xs); + task* m; + if (inplace) + m = new (allocate_continuation()) merge_task(zs, zm, zm, ze, xs, inplace==2, comp); + else + m = new (allocate_continuation()) merge_task(xs, xm, xm, xe, zs, false, comp); + m->set_ref_count(2); + task* right = new(m->allocate_child()) stable_sort_task(xm,xe,zm,!inplace, comp); + spawn(*right); + recycle_as_child_of(*m); + xe=xm; + inplace=!inplace; + return this; + } +} + +} // namespace internal + +template +void parallel_stable_sort( RandomAccessIterator xs, RandomAccessIterator xe, Compare comp ) { + typedef typename std::iterator_traits::value_type T; + if( internal::raw_buffer z = internal::raw_buffer( sizeof(T)*(xe-xs) ) ) { + using tbb::task; + typedef typename std::iterator_traits::value_type T; + internal::raw_buffer buf( sizeof(T)*(xe-xs) ); + task::spawn_root_and_wait(*new( task::allocate_root() ) internal::stable_sort_task( xs, xe, (T*)buf.get(), 2, comp )); + } else + // Not enough memory available - fall back on serial sort + std::stable_sort( xs, xe, comp ); +} + +} // namespace pss diff --git a/extern/quadriflow/3rd/pss/pss/pss_common.h b/extern/quadriflow/3rd/pss/pss/pss_common.h new file mode 100644 index 00000000000..628c0f9830a --- /dev/null +++ b/extern/quadriflow/3rd/pss/pss/pss_common.h @@ -0,0 +1,106 @@ +/* + Copyright (C) 2014 Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ +#include +#include + +namespace pss { + +namespace internal { + +//! Destroy sequence [xs,xe) +template +void serial_destroy( RandomAccessIterator zs, RandomAccessIterator ze ) { + typedef typename std::iterator_traits::value_type T; + while( zs!=ze ) { + --ze; + (*ze).~T(); + } +} + +//! Merge sequences [xs,xe) and [ys,ye) to output sequence [zs,(xe-xs)+(ye-ys)), using std::move +template +void serial_move_merge( RandomAccessIterator1 xs, RandomAccessIterator1 xe, RandomAccessIterator2 ys, RandomAccessIterator2 ye, RandomAccessIterator3 zs, Compare comp ) { + if( xs!=xe ) { + if( ys!=ye ) { + for(;;) { + if( comp(*ys,*xs) ) { + *zs = std::move(*ys); + ++zs; + if( ++ys==ye ) { break; } + } else { + *zs = std::move(*xs); + ++zs; + if( ++xs==xe ) { goto movey; } + } + } + } + ys = xs; + ye = xe; + } +movey: + std::move( ys, ye, zs ); +} + +template +void stable_sort_base_case( RandomAccessIterator1 xs, RandomAccessIterator1 xe, RandomAccessIterator2 zs, int inplace, Compare comp) { + std::stable_sort( xs, xe, comp ); + if( inplace!=2 ) { + RandomAccessIterator2 ze = zs + (xe-xs); + typedef typename std::iterator_traits::value_type T; + if( inplace ) + // Initialize the temporary buffer + for( ; zs +![QuadriFlow Results](https://github.com/hjwdzh/quadriflow/raw/master/img/result.jpg) + +## WebGL Application +Our 3D WebGL Apps for QuadriFlow are online! Without any installation, you are able to +* [**Compare**](https://yichaozhou.com/publication/1805quadriflow/#demo) QuadriFlow with previous methods; +* [**Quadrangulate**](https://yichaozhou.com/publication/1805quadriflow/#tool) your own meshes and + download the result! + +## Desktop Software +The software supports cmake build for Linux/Mac/Windows systems. For linux and mac users, run **`sh demo.sh`** to build and try the QuadriFlow example, which converts `examples/Gargoyle_input.obj` to `examples/Gargoyle_quadriflow.obj`. + +### Install + +``` +git clone git://github.com/hjwdzh/quadriflow +cd quadriflow +mkdir build +cd build +cmake .. -DCMAKE_BUILD_TYPE=release +make -j +``` + +### QuadriFlow Software + +We take a manifold triangle mesh `input.obj` and generate a manifold quad mesh `output.obj`. The face number increases linearly with the resolution controled by the user. + +``` +./quadriflow -i input.obj -o output.obj -f [resolution] +``` + +Here, the resolution is the desired number of faces in the quad mesh. + +## Advanced Functions + +### Min-cost Flow +By default, `quadriflow` uses the Boykov maximum flow solver from boost becuase it is faster. To +enable the adaptive network simplex minimum-cost flow solver, you can enable the `-mcf` option: + +``` +./quadriflow -mcf -i input.obj -o output.obj -f [resolution] +``` + +### Sharp Preserving +By default, `quadriflow` does not explicitly detect and perserve the sharp edges in the model. To +enable this feature, uses + +``` +./quadriflow -sharp -i input.obj -o output.obj -f [resolution] +``` + +### SAT Flip Removal (Unix Only) +By default, `quadriflow` does not use the SAT solver to remove the flips in the integer offsets +map. To remove the flips and guarantee a watertight result mesh, you can enable the SAT solver. +First, make sure that `minisat` and `timeout` is properly installed under your `${PATH}`. The +former can be done by building `3rd/MapleCOMSPS_LRB/CMakeLists.txt` and copying `minisat` to `/usr/bin`. +In addition, `timeout` is included in coreutils. If you are using Mac, you can install it using +homebrew: +``` +brew install coreutils +export PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH" +``` + +You can verify if those binaries are properly installed by executing +``` +which minisat +which timeout +``` + +After that, you can enable SAT flip removal procedure by executing +``` +./quadriflow -sat -i input.obj -o output.obj -f [resolution] +``` + +When using the SAT flip removal, we also suggest you enabling the verbose logging to understand +what is going on. You can build quadriflow with the following options: +``` +cmake .. -DCMAKE_BUILD_TYPE=release -DBUILD_LOG=ON +``` + +### GUROBI Support (For Benchmark Purpose) + +To use the Gurobi integer programming to solve the integer offset problem, you can build QuadriFlow with +``` +cmake .. -DCMAKE_BUILD_TYPE=release -DBUILD_GUROBI=ON -DBUILD_LOG=ON +``` +This override other solvers and should only be used for benchmark purpose. + +## External Dependencies +* Boost +* Eigen +* OpenMP (optional in CMake) +* TBB (optional in CMake) +* GUROBI (for benchmark purpose only) + +## Licenses + +QuadriFlow is released under [MIT License](LICENSE.txt). +For 3rd dependencies, +* Boost and Lemon are released under [Boost Software License](https://lemon.cs.elte.hu/trac/lemon/wiki/License) +* Most part of Eigen is released under [MPL2](https://www.mozilla.org/en-US/MPL/2.0/FAQ/) + * Sparse Cholesky Decomposition algorithms are released under LGPL + * To replace it using Sparse LU decomposition with a more permissive MPL2 license (a little slower), enable `BUILD_FREE_LICENSE` in CMake (e.g., `-DBUILD_FREE_LICENSE=ON`). +* `pcg32.h` is released under the Apache License, Version 2.0 +* `parallel_stable_sort.h` is released under the MIT License + +## Authors +- [Jingwei Huang](mailto:jingweih@stanford.edu) +- [Yichao Zhou](mailto:zyc@berkeley.edu) + +© 2018 Jingwei Huang and Yichao Zhou All Rights Reserved + +**IMPORTANT**: If you use this software please cite the following in any resulting publication: +``` +@article {10.1111:cgf.13498, + journal = {Computer Graphics Forum}, + title = {{QuadriFlow: A Scalable and Robust Method for Quadrangulation}}, + author = {Huang, Jingwei and Zhou, Yichao and Niessner, Matthias and Shewchuk, Jonathan Richard and Guibas, Leonidas J.}, + year = {2018}, + publisher = {The Eurographics Association and John Wiley & Sons Ltd.}, + ISSN = {1467-8659}, + DOI = {10.1111/cgf.13498} +} +``` + +## Triangle Manifold + +In case you are dealing with a triangle mesh that is not a manifold, we implemented the software that converts any triangle mesh to watertight manifold. Please visit https://github.com/hjwdzh/Manifold for details. diff --git a/extern/quadriflow/src/Optimizer.cu b/extern/quadriflow/src/Optimizer.cu new file mode 100644 index 00000000000..8520c3f90a8 --- /dev/null +++ b/extern/quadriflow/src/Optimizer.cu @@ -0,0 +1,281 @@ +#include +#include +#include "AdjacentMatrix.h" + +__device__ __host__ glm::dvec3 +middle_point(const glm::dvec3 &p0, const glm::dvec3 &n0, const glm::dvec3 &p1, const glm::dvec3 &n1) { + /* How was this derived? + * + * Minimize \|x-p0\|^2 + \|x-p1\|^2, where + * dot(n0, x) == dot(n0, p0) + * dot(n1, x) == dot(n1, p1) + * + * -> Lagrange multipliers, set derivative = 0 + * Use first 3 equalities to write x in terms of + * lambda_1 and lambda_2. Substitute that into the last + * two equations and solve for the lambdas. Finally, + * add a small epsilon term to avoid issues when n1=n2. + */ + double n0p0 = glm::dot(n0, p0), n0p1 = glm::dot(n0, p1), + n1p0 = glm::dot(n1, p0), n1p1 = glm::dot(n1, p1), + n0n1 = glm::dot(n0, n1), + denom = 1.0f / (1.0f - n0n1*n0n1 + 1e-4f), + lambda_0 = 2.0f*(n0p1 - n0p0 - n0n1*(n1p0 - n1p1))*denom, + lambda_1 = 2.0f*(n1p0 - n1p1 - n0n1*(n0p1 - n0p0))*denom; + + return 0.5 * (p0 + p1) - 0.25 * (n0 * lambda_0 + n1 * lambda_1); +} + +__device__ __host__ glm::dvec3 +position_round_4(const glm::dvec3 &o, const glm::dvec3 &q, +const glm::dvec3 &n, const glm::dvec3 &p, +double scale) { + double inv_scale = 1.0 / scale; + glm::dvec3 t = glm::cross(n, q); + glm::dvec3 d = p - o; + return o + + q * std::round(glm::dot(q, d) * inv_scale) * scale + + t * std::round(glm::dot(t, d) * inv_scale) * scale; +} + +__device__ __host__ glm::dvec3 +position_floor_4(const glm::dvec3 &o, const glm::dvec3 &q, +const glm::dvec3 &n, const glm::dvec3 &p, +double scale) { + double inv_scale = 1.0 / scale; + glm::dvec3 t = glm::cross(n,q); + glm::dvec3 d = p - o; + return o + + q * std::floor(glm::dot(q, d) * inv_scale) * scale + + t * std::floor(glm::dot(t, d) * inv_scale) * scale; +} + + +__device__ __host__ double cudaSignum(double value) { + return std::copysign((double)1, value); +} + +__device__ __host__ void +compat_orientation_extrinsic_4(const glm::dvec3 &q0, const glm::dvec3 &n0, +const glm::dvec3 &q1, const glm::dvec3 &n1, glm::dvec3& value1, glm::dvec3& value2) { + const glm::dvec3 A[2] = { q0, glm::cross(n0, q0) }; + const glm::dvec3 B[2] = { q1, glm::cross(n1, q1) }; + + double best_score = -1e10; + int best_a = 0, best_b = 0; + + for (int i = 0; i < 2; ++i) { + for (int j = 0; j < 2; ++j) { + double score = std::abs(glm::dot(A[i], B[j])); + if (score > best_score + 1e-6) { + best_a = i; + best_b = j; + best_score = score; + } + } + } + const double dp = glm::dot(A[best_a], B[best_b]); + value1 = A[best_a]; + value2 = B[best_b] * cudaSignum(dp); +} + +__device__ __host__ void +compat_position_extrinsic_4( +const glm::dvec3 &p0, const glm::dvec3 &n0, const glm::dvec3 &q0, const glm::dvec3 &o0, +const glm::dvec3 &p1, const glm::dvec3 &n1, const glm::dvec3 &q1, const glm::dvec3 &o1, +double scale, glm::dvec3& v1, glm::dvec3& v2) { + + glm::dvec3 t0 = glm::cross(n0, q0), t1 = glm::cross(n1, q1); + glm::dvec3 middle = middle_point(p0, n0, p1, n1); + glm::dvec3 o0p = position_floor_4(o0, q0, n0, middle, scale); + glm::dvec3 o1p = position_floor_4(o1, q1, n1, middle, scale); + + double best_cost = 1e10; + int best_i = -1, best_j = -1; + + for (int i = 0; i<4; ++i) { + glm::dvec3 o0t = o0p + (q0 * ((i & 1) * scale) + t0 * (((i & 2) >> 1) * scale)); + for (int j = 0; j<4; ++j) { + glm::dvec3 o1t = o1p + (q1 * ((j & 1) * scale) + t1 * (((j & 2) >> 1) * scale)); + glm::dvec3 t = o0t - o1t; + double cost = glm::dot(t, t); + + if (cost < best_cost) { + best_i = i; + best_j = j; + best_cost = cost; + } + } + } + + v1 = o0p + (q0 * ((best_i & 1) * scale) + t0 * (((best_i & 2) >> 1) * scale)), + v2 = o1p + (q1 * ((best_j & 1) * scale) + t1 * (((best_j & 2) >> 1) * scale)); +} + +__global__ +void cudaUpdateOrientation(int* phase, int num_phases, glm::dvec3* N, glm::dvec3* Q, Link* adj, int* adjOffset, int num_adj) { + int pi = blockIdx.x * blockDim.x + threadIdx.x; + +// for (int pi = 0; pi < num_phases; ++pi) { + if (pi >= num_phases) + return; + int i = phase[pi]; + glm::dvec3 n_i = N[i]; + double weight_sum = 0.0f; + glm::dvec3 sum = Q[i]; + + for (int l = adjOffset[i]; l < adjOffset[i + 1]; ++l) { + Link link = adj[l]; + const int j = link.id; + const double weight = link.weight; + if (weight == 0) + continue; + glm::dvec3 n_j = N[j]; + glm::dvec3 q_j = Q[j]; + glm::dvec3 value1, value2; + compat_orientation_extrinsic_4(sum, n_i, q_j, n_j, value1, value2); + sum = value1 * weight_sum + value2 * weight; + sum -= n_i*glm::dot(n_i, sum); + weight_sum += weight; + + double norm = glm::length(sum); + if (norm > 2.93873587705571876e-39f) + sum /= norm; + } + + if (weight_sum > 0) { + Q[i] = sum; + } +// } +} + +__global__ +void cudaPropagateOrientationUpper(glm::dvec3* srcField, glm::ivec2* toUpper, glm::dvec3* N, glm::dvec3* destField, int num_orientation) { + int i = blockIdx.x * blockDim.x + threadIdx.x; +// for (int i = 0; i < num_orientation; ++i) { + if (i >= num_orientation) + return; + for (int k = 0; k < 2; ++k) { + int dest = toUpper[i][k]; + if (dest == -1) + continue; + glm::dvec3 q = srcField[i]; + glm::dvec3 n = N[dest]; + destField[dest] = q - n * glm::dot(n, q); + } +// } +} + +__global__ +void cudaPropagateOrientationLower(glm::ivec2* toUpper, glm::dvec3* Q, glm::dvec3* N, glm::dvec3* Q_next, glm::dvec3* N_next, int num_toUpper) { + int i = blockIdx.x * blockDim.x + threadIdx.x; +// for (int i = 0; i < num_toUpper; ++i) { + if (i >= num_toUpper) + return; + glm::ivec2 upper = toUpper[i]; + glm::dvec3 q0 = Q[upper[0]]; + glm::dvec3 n0 = N[upper[0]]; + + glm::dvec3 q, q1, n1, value1, value2; + if (upper[1] != -1) { + q1 = Q[upper[1]]; + n1 = N[upper[1]]; + compat_orientation_extrinsic_4(q0, n0, q1, n1, value1, value2); + q = value1 + value2; + } + else { + q = q0; + } + glm::dvec3 n = N_next[i]; + q -= glm::dot(n, q) * n; + + double len = q.x * q.x + q.y * q.y + q.z * q.z; + if (len > 2.93873587705571876e-39f) + q /= sqrt(len); + Q_next[i] = q; +// } +} + + +__global__ +void cudaUpdatePosition(int* phase, int num_phases, glm::dvec3* N, glm::dvec3* Q, Link* adj, int* adjOffset, int num_adj, glm::dvec3* V, glm::dvec3* O, double scale) { + int pi = blockIdx.x * blockDim.x + threadIdx.x; + +// for (int pi = 0; pi < num_phases; ++pi) { + if (pi >= num_phases) + return; + int i = phase[pi]; + glm::dvec3 n_i = N[i], v_i = V[i]; + glm::dvec3 q_i = Q[i]; + glm::dvec3 sum = O[i]; + double weight_sum = 0.0f; + + for (int l = adjOffset[i]; l < adjOffset[i + 1]; ++l) { + Link link = adj[l]; + int j = link.id; + const double weight = link.weight; + if (weight == 0) + continue; + + glm::dvec3 n_j = N[j], v_j = V[j]; + glm::dvec3 q_j = Q[j], o_j = O[j]; + glm::dvec3 v1, v2; + compat_position_extrinsic_4( + v_i, n_i, q_i, sum, v_j, n_j, q_j, o_j, scale, v1, v2); + + sum = v1*weight_sum +v2*weight; + weight_sum += weight; + if (weight_sum > 2.93873587705571876e-39f) + sum /= weight_sum; + sum -= glm::dot(n_i, sum - v_i)*n_i; + } + + if (weight_sum > 0) { + O[i] = position_round_4(sum, q_i, n_i, v_i, scale); + } +// } +} + +__global__ +void cudaPropagatePositionUpper(glm::dvec3* srcField, glm::ivec2* toUpper, glm::dvec3* N, glm::dvec3* V, glm::dvec3* destField, int num_position) { + int i = blockIdx.x * blockDim.x + threadIdx.x; +// for (int i = 0; i < num_position; ++i) { + if (i >= num_position) + return; + for (int k = 0; k < 2; ++k) { + int dest = toUpper[i][k]; + if (dest == -1) + continue; + glm::dvec3 o = srcField[i], n = N[dest], v = V[dest]; + o -= n * glm::dot(n, o - v); + destField[dest] = o; + } +// } +} + + +void UpdateOrientation(int* phase, int num_phases, glm::dvec3* N, glm::dvec3* Q, Link* adj, int* adjOffset, int num_adj) { + cudaUpdateOrientation << <(num_phases + 255) / 256, 256 >> >(phase, num_phases, N, Q, adj, adjOffset, num_adj); +// cudaUpdateOrientation(phase, num_phases, N, Q, adj, adjOffset, num_adj); +} + +void PropagateOrientationUpper(glm::dvec3* srcField, int num_orientation, glm::ivec2* toUpper, glm::dvec3* N, glm::dvec3* destField) { + cudaPropagateOrientationUpper << <(num_orientation + 255) / 256, 256 >> >(srcField, toUpper, N, destField, num_orientation); +// cudaPropagateOrientationUpper(srcField, toUpper, N, destField, num_orientation); +} + +void PropagateOrientationLower(glm::ivec2* toUpper, glm::dvec3* Q, glm::dvec3* N, glm::dvec3* Q_next, glm::dvec3* N_next, int num_toUpper) { + cudaPropagateOrientationLower << <(num_toUpper + 255) / 256, 256 >> >(toUpper, Q, N, Q_next, N_next, num_toUpper); +// cudaPropagateOrientationLower(toUpper, Q, N, Q_next, N_next, num_toUpper); +} + + +void UpdatePosition(int* phase, int num_phases, glm::dvec3* N, glm::dvec3* Q, Link* adj, int* adjOffset, int num_adj, glm::dvec3* V, glm::dvec3* O, double scale) { + cudaUpdatePosition << <(num_phases + 255) / 256, 256 >> >(phase, num_phases, N, Q, adj, adjOffset, num_adj, V, O, scale); +// cudaUpdatePosition(phase, num_phases, N, Q, adj, adjOffset, num_adj, V, O, scale); +} + +void PropagatePositionUpper(glm::dvec3* srcField, int num_position, glm::ivec2* toUpper, glm::dvec3* N, glm::dvec3* V, glm::dvec3* destField) { + cudaPropagatePositionUpper << <(num_position + 255) / 256, 256 >> >(srcField, toUpper, N, V, destField, num_position); +// cudaPropagatePositionUpper(srcField, toUpper, N, V, destField, num_position); +} diff --git a/extern/quadriflow/src/adjacent-matrix.cpp b/extern/quadriflow/src/adjacent-matrix.cpp new file mode 100644 index 00000000000..e20ffb05f6d --- /dev/null +++ b/extern/quadriflow/src/adjacent-matrix.cpp @@ -0,0 +1,35 @@ +#include "config.hpp" +#include "adjacent-matrix.hpp" +#include "dedge.hpp" +#include + +namespace qflow { + +void generate_adjacency_matrix_uniform( + const MatrixXi &F, const VectorXi &V2E, const VectorXi &E2E, + const VectorXi &nonManifold, AdjacentMatrix& adj) { + adj.resize(V2E.size()); +#ifdef WITH_OMP +#pragma omp parallel for +#endif + for (int i = 0; i < adj.size(); ++i) { + int start = V2E[i]; + int edge = start; + if (start == -1) + continue; + do { + int base = edge % 3, f = edge / 3; + int opp = E2E[edge], next = dedge_next_3(opp); + if (adj[i].empty()) + adj[i].push_back(Link(F((base + 2) % 3, f))); + if (opp == -1 || next != start) { + adj[i].push_back(Link(F((base + 1) % 3, f))); + if (opp == -1) + break; + } + edge = next; + } while (edge != start); + } +} + +} // namespace qflow diff --git a/extern/quadriflow/src/adjacent-matrix.hpp b/extern/quadriflow/src/adjacent-matrix.hpp new file mode 100644 index 00000000000..e3eb2e12a47 --- /dev/null +++ b/extern/quadriflow/src/adjacent-matrix.hpp @@ -0,0 +1,37 @@ +#ifndef ADJACENT_MATRIX_H_ +#define ADJACENT_MATRIX_H_ + +#include + +namespace qflow { + +struct Link +{ + Link(){} + Link(int _id, double _w = 1) + : id(_id), weight(_w) + {} + inline bool operator<(const Link &link) const { return id < link.id; } + int id; + double weight; +}; + +struct TaggedLink { + int id; + unsigned char flag; + TaggedLink(){} + TaggedLink(int id) : id(id), flag(0) { } + bool used() const { return flag & 1; } + void markUsed() { flag |= 1; } + TaggedLink& operator=(const Link& l) { + flag = 0; + id = l.id; + return *this; + } +}; + +typedef std::vector > AdjacentMatrix; + +} // namespace qflow + +#endif \ No newline at end of file diff --git a/extern/quadriflow/src/compare-key.hpp b/extern/quadriflow/src/compare-key.hpp new file mode 100644 index 00000000000..df9109d62e0 --- /dev/null +++ b/extern/quadriflow/src/compare-key.hpp @@ -0,0 +1,102 @@ +#ifndef COMPARE_KEY_H_ +#define COMPARE_KEY_H_ + +#include +#include + +namespace qflow { + +struct Key2i +{ + Key2i(int x, int y) + : key(std::make_pair(x, y)) + {} + bool operator==(const Key2i& other) const + { + return key == other.key; + } + bool operator<(const Key2i& other) const + { + return key < other.key; + } + std::pair key; +}; + +struct Key3i +{ + Key3i(int x, int y, int z) + : key(std::make_pair(x, std::make_pair(y, z))) + {} + bool operator==(const Key3i& other) const + { + return key == other.key; + } + bool operator<(const Key3i& other) const + { + return key < other.key; + } + std::pair > key; +}; + +struct Key3f +{ + Key3f(double x, double y, double z, double threshold) + : key(std::make_pair(x / threshold, std::make_pair(y / threshold, z / threshold))) + {} + bool operator==(const Key3f& other) const + { + return key == other.key; + } + bool operator<(const Key3f& other) const + { + return key < other.key; + } + std::pair > key; +}; + +struct KeySorted2i +{ + KeySorted2i(int x, int y) + : key(std::make_pair(x, y)) + { + if (x > y) + std::swap(key.first, key.second); + } + bool operator==(const KeySorted2i& other) const + { + return key == other.key; + } + bool operator<(const KeySorted2i& other) const + { + return key < other.key; + } + std::pair key; +}; + +struct KeySorted3i +{ + KeySorted3i(int x, int y, int z) + : key(std::make_pair(x, std::make_pair(y, z))) + { + if (key.first > key.second.first) + std::swap(key.first, key.second.first); + if (key.first > key.second.second) + std::swap(key.first, key.second.second); + if (key.second.first > key.second.second) + std::swap(key.second.first, key.second.second); + } + bool operator==(const Key3i& other) const + { + return key == other.key; + } + bool operator<(const Key3i& other) const + { + return key < other.key; + } + std::pair > key; +}; + + +} // namespace qflow + +#endif diff --git a/extern/quadriflow/src/config.hpp b/extern/quadriflow/src/config.hpp new file mode 100644 index 00000000000..842b885a209 --- /dev/null +++ b/extern/quadriflow/src/config.hpp @@ -0,0 +1,34 @@ +#ifndef CONFIG_H_ +#define CONFIG_H_ + +// Move settings to cmake to make CMake happy :) + +// #define WITH_SCALE +// #define WITH_CUDA + +const int GRAIN_SIZE = 1024; + +#ifdef LOG_OUTPUT + +#define lprintf(...) printf(__VA_ARGS__) +#define lputs(...) puts(__VA_ARGS__) + +#else + +#define lprintf(...) void(0) +#define lputs(...) void(0) + +#endif + +#include + +namespace qflow { + +// simulation of Windows GetTickCount() +unsigned long long inline GetCurrentTime64() { + using namespace std::chrono; + return duration_cast(steady_clock::now().time_since_epoch()).count(); +} +} // namespace qflow + +#endif diff --git a/extern/quadriflow/src/dedge.cpp b/extern/quadriflow/src/dedge.cpp new file mode 100644 index 00000000000..b030e20d6a1 --- /dev/null +++ b/extern/quadriflow/src/dedge.cpp @@ -0,0 +1,487 @@ +#include "dedge.hpp" +#include "config.hpp" + +#include +#include +#include +#include +#include +#include "compare-key.hpp" +#ifdef WITH_TBB +#include "tbb/tbb.h" +#endif +namespace qflow { + +inline int dedge_prev(int e, int deg) { return (e % deg == 0u) ? e + (deg - 1) : e - 1; } + +inline bool atomicCompareAndExchange(volatile int* v, uint32_t newValue, int oldValue) { +#if defined(_WIN32) + return _InterlockedCompareExchange(reinterpret_cast(v), (long)newValue, + (long)oldValue) == (long)oldValue; +#else + return __sync_bool_compare_and_swap(v, oldValue, newValue); +#endif +} + +const int INVALID = -1; + +#undef max +#undef min +bool compute_direct_graph(MatrixXd& V, MatrixXi& F, VectorXi& V2E, VectorXi& E2E, + VectorXi& boundary, VectorXi& nonManifold) { + V2E.resize(V.cols()); + V2E.setConstant(INVALID); + + uint32_t deg = F.rows(); + std::vector> tmp(F.size()); + +#ifdef WITH_TBB + tbb::parallel_for( + tbb::blocked_range(0u, (uint32_t)F.cols(), GRAIN_SIZE), + [&](const tbb::blocked_range& range) { + for (uint32_t f = range.begin(); f != range.end(); ++f) { + for (uint32_t i = 0; i < deg; ++i) { + uint32_t idx_cur = F(i, f), idx_next = F((i + 1) % deg, f), + edge_id = deg * f + i; + if (idx_cur >= V.cols() || idx_next >= V.cols()) + throw std::runtime_error( + "Mesh data contains an out-of-bounds vertex reference!"); + if (idx_cur == idx_next) continue; + + tmp[edge_id] = std::make_pair(idx_next, INVALID); + if (!atomicCompareAndExchange(&V2E[idx_cur], edge_id, INVALID)) { + uint32_t idx = V2E[idx_cur]; + while (!atomicCompareAndExchange((int*)&tmp[idx].second, edge_id, INVALID)) + idx = tmp[idx].second; + } + } + } + }); +#else + for (int f = 0; f < F.cols(); ++f) { + for (unsigned int i = 0; i < deg; ++i) { + unsigned int idx_cur = F(i, f), idx_next = F((i + 1) % deg, f), edge_id = deg * f + i; + if (idx_cur >= V.cols() || idx_next >= V.cols()) + throw std::runtime_error("Mesh data contains an out-of-bounds vertex reference!"); + if (idx_cur == idx_next) continue; + + tmp[edge_id] = std::make_pair(idx_next, -1); + if (V2E[idx_cur] == -1) + V2E[idx_cur] = edge_id; + else { + unsigned int idx = V2E[idx_cur]; + while (tmp[idx].second != -1) { + idx = tmp[idx].second; + } + tmp[idx].second = edge_id; + } + } + } +#endif + + nonManifold.resize(V.cols()); + nonManifold.setConstant(false); + + E2E.resize(F.cols() * deg); + E2E.setConstant(INVALID); + +#ifdef WITH_OMP +#pragma omp parallel for +#endif + for (int f = 0; f < F.cols(); ++f) { + for (uint32_t i = 0; i < deg; ++i) { + uint32_t idx_cur = F(i, f), idx_next = F((i + 1) % deg, f), edge_id_cur = deg * f + i; + + if (idx_cur == idx_next) continue; + + uint32_t it = V2E[idx_next], edge_id_opp = INVALID; + while (it != INVALID) { + if (tmp[it].first == idx_cur) { + if (edge_id_opp == INVALID) { + edge_id_opp = it; + } else { + nonManifold[idx_cur] = true; + nonManifold[idx_next] = true; + edge_id_opp = INVALID; + break; + } + } + it = tmp[it].second; + } + + if (edge_id_opp != INVALID && edge_id_cur < edge_id_opp) { + E2E[edge_id_cur] = edge_id_opp; + E2E[edge_id_opp] = edge_id_cur; + } + } + } + std::atomic nonManifoldCounter(0), boundaryCounter(0), isolatedCounter(0); + + boundary.resize(V.cols()); + boundary.setConstant(false); + + /* Detect boundary regions of the mesh and adjust vertex->edge pointers*/ +#ifdef WITH_OMP +#pragma omp parallel for +#endif + for (int i = 0; i < V.cols(); ++i) { + uint32_t edge = V2E[i]; + if (edge == INVALID) { + isolatedCounter++; + continue; + } + if (nonManifold[i]) { + nonManifoldCounter++; + V2E[i] = INVALID; + continue; + } + + /* Walk backwards to the first boundary edge (if any) */ + uint32_t start = edge, v2e = INVALID; + do { + v2e = std::min(v2e, edge); + uint32_t prevEdge = E2E[dedge_prev(edge, deg)]; + if (prevEdge == INVALID) { + /* Reached boundary -- update the vertex->edge link */ + v2e = edge; + boundary[i] = true; + boundaryCounter++; + break; + } + edge = prevEdge; + } while (edge != start); + V2E[i] = v2e; + } +#ifdef LOG_OUTPUT + printf("counter triangle %d %d\n", (int)boundaryCounter, (int)nonManifoldCounter); +#endif + return true; + std::vector> vert_to_edges(V2E.size()); + for (int i = 0; i < F.cols(); ++i) { + for (int j = 0; j < 3; ++j) { + int v = F(j, i); + vert_to_edges[v].push_back(i * 3 + j); + } + } + std::vector colors(F.cols() * 3, -1); + bool update = false; + int num_v = V.cols(); + std::map new_vertices; + for (int i = 0; i < vert_to_edges.size(); ++i) { + int num_color = 0; + for (int j = 0; j < vert_to_edges[i].size(); ++j) { + int deid0 = vert_to_edges[i][j]; + if (colors[deid0] == -1) { + int deid = deid0; + do { + colors[deid] = num_color; + if (num_color != 0) F(deid % 3, deid / 3) = num_v; + deid = deid / 3 * 3 + (deid + 2) % 3; + deid = E2E[deid]; + } while (deid != deid0); + num_color += 1; + if (num_color > 1) { + update = true; + new_vertices[num_v] = i; + num_v += 1; + } + } + } + } + if (update) { + V.conservativeResize(3, num_v); + for (auto& p : new_vertices) { + V.col(p.first) = V.col(p.second); + } + return false; + } + return true; +} + +void compute_direct_graph_quad(std::vector& V, std::vector& F, std::vector& V2E, std::vector& E2E, VectorXi& boundary, VectorXi& nonManifold) { + V2E.clear(); + E2E.clear(); + boundary = VectorXi(); + nonManifold = VectorXi(); + V2E.resize(V.size(), INVALID); + + uint32_t deg = 4; + std::vector> tmp(F.size() * deg); + +#ifdef WITH_TBB + tbb::parallel_for( + tbb::blocked_range(0u, (uint32_t)F.size(), GRAIN_SIZE), + [&](const tbb::blocked_range& range) { + for (uint32_t f = range.begin(); f != range.end(); ++f) { + for (uint32_t i = 0; i < deg; ++i) { + uint32_t idx_cur = F[f][i], idx_next = F[f][(i + 1) % deg], + edge_id = deg * f + i; + if (idx_cur >= V.size() || idx_next >= V.size()) + throw std::runtime_error( + "Mesh data contains an out-of-bounds vertex reference!"); + if (idx_cur == idx_next) continue; + + tmp[edge_id] = std::make_pair(idx_next, INVALID); + if (!atomicCompareAndExchange(&V2E[idx_cur], edge_id, INVALID)) { + uint32_t idx = V2E[idx_cur]; + while (!atomicCompareAndExchange((int*)&tmp[idx].second, edge_id, INVALID)) + idx = tmp[idx].second; + } + } + } + }); +#else + for (int f = 0; f < F.size(); ++f) { + for (unsigned int i = 0; i < deg; ++i) { + unsigned int idx_cur = F[f][i], idx_next = F[f][(i + 1) % deg], edge_id = deg * f + i; + if (idx_cur >= V.size() || idx_next >= V.size()) + throw std::runtime_error("Mesh data contains an out-of-bounds vertex reference!"); + if (idx_cur == idx_next) continue; + tmp[edge_id] = std::make_pair(idx_next, -1); + if (V2E[idx_cur] == -1) { + V2E[idx_cur] = edge_id; + } + else { + unsigned int idx = V2E[idx_cur]; + while (tmp[idx].second != -1) { + idx = tmp[idx].second; + } + tmp[idx].second = edge_id; + } + } + } +#endif + nonManifold.resize(V.size()); + nonManifold.setConstant(false); + + E2E.resize(F.size() * deg, INVALID); + +#ifdef WITH_OMP +#pragma omp parallel for +#endif + for (int f = 0; f < F.size(); ++f) { + for (uint32_t i = 0; i < deg; ++i) { + uint32_t idx_cur = F[f][i], idx_next = F[f][(i + 1) % deg], edge_id_cur = deg * f + i; + + if (idx_cur == idx_next) continue; + + uint32_t it = V2E[idx_next], edge_id_opp = INVALID; + while (it != INVALID) { + if (tmp[it].first == idx_cur) { + if (edge_id_opp == INVALID) { + edge_id_opp = it; + } else { + nonManifold[idx_cur] = true; + nonManifold[idx_next] = true; + edge_id_opp = INVALID; + break; + } + } + it = tmp[it].second; + } + + if (edge_id_opp != INVALID && edge_id_cur < edge_id_opp) { + E2E[edge_id_cur] = edge_id_opp; + E2E[edge_id_opp] = edge_id_cur; + } + } + } + std::atomic nonManifoldCounter(0), boundaryCounter(0), isolatedCounter(0); + + boundary.resize(V.size()); + boundary.setConstant(false); + + /* Detect boundary regions of the mesh and adjust vertex->edge pointers*/ +#ifdef WITH_OMP +#pragma omp parallel for +#endif + for (int i = 0; i < V.size(); ++i) { + uint32_t edge = V2E[i]; + if (edge == INVALID) { + isolatedCounter++; + continue; + } + if (nonManifold[i]) { + nonManifoldCounter++; + V2E[i] = INVALID; + continue; + } + + /* Walk backwards to the first boundary edge (if any) */ + uint32_t start = edge, v2e = INVALID; + do { + v2e = std::min(v2e, edge); + uint32_t prevEdge = E2E[dedge_prev(edge, deg)]; + if (prevEdge == INVALID) { + /* Reached boundary -- update the vertex->edge link */ + v2e = edge; + boundary[i] = true; + boundaryCounter++; + break; + } + edge = prevEdge; + } while (edge != start); + V2E[i] = v2e; + } +#ifdef LOG_OUTPUT + printf("counter %d %d\n", (int)boundaryCounter, (int)nonManifoldCounter); +#endif +} + +void remove_nonmanifold(std::vector& F, std::vector& V) { + typedef std::pair Edge; + + int degree = 4; + std::map>> irregular; + std::vector> E(V.size()); + std::vector> VF(V.size()); + + auto kill_face_single = [&](uint32_t f) { + if (F[f][0] == INVALID) return; + for (int i = 0; i < degree; ++i) E[F[f][i]].erase(F[f][(i + 1) % degree]); + F[f].setConstant(INVALID); + }; + + auto kill_face = [&](uint32_t f) { + if (degree == 4 && F[f][2] == F[f][3]) { + auto it = irregular.find(F[f][2]); + if (it != irregular.end()) { + for (auto& item : it->second) { + kill_face_single(item.second.second); + } + } + } + kill_face_single(f); + }; + + uint32_t nm_edge = 0, nm_vert = 0; + + for (uint32_t f = 0; f < (uint32_t)F.size(); ++f) { + if (F[f][0] == INVALID) continue; + if (degree == 4 && F[f][2] == F[f][3]) { + /* Special handling of irregular faces */ + irregular[F[f][2]][F[f][0]] = std::make_pair(F[f][1], f); + continue; + } + + bool nonmanifold = false; + for (uint32_t e = 0; e < degree; ++e) { + uint32_t v0 = F[f][e], v1 = F[f][(e + 1) % degree], v2 = F[f][(e + 2) % degree]; + if (E[v0].find(v1) != E[v0].end() || (degree == 4 && E[v0].find(v2) != E[v0].end())) + nonmanifold = true; + } + + if (nonmanifold) { + nm_edge++; + F[f].setConstant(INVALID); + continue; + } + + for (uint32_t e = 0; e < degree; ++e) { + uint32_t v0 = F[f][e], v1 = F[f][(e + 1) % degree], v2 = F[f][(e + 2) % degree]; + + E[v0].insert(v1); + if (degree == 4) E[v0].insert(v2); + VF[v0].insert(f); + } + } + + std::vector edges; + for (auto item : irregular) { + bool nonmanifold = false; + auto face = item.second; + edges.clear(); + + uint32_t cur = face.begin()->first, stop = cur; + while (true) { + uint32_t pred = cur; + cur = face[cur].first; + uint32_t next = face[cur].first, it = 0; + while (true) { + ++it; + if (next == pred) break; + if (E[cur].find(next) != E[cur].end() && it == 1) nonmanifold = true; + edges.push_back(Edge(cur, next)); + next = face[next].first; + } + if (cur == stop) break; + } + + if (nonmanifold) { + nm_edge++; + for (auto& i : item.second) F[i.second.second].setConstant(INVALID); + continue; + } else { + for (auto e : edges) { + E[e.first].insert(e.second); + + for (auto e2 : face) VF[e.first].insert(e2.second.second); + } + } + } + + /* Check vertices */ + std::set v_marked, v_unmarked, f_adjacent; + + std::function dfs = [&](uint32_t i) { + v_marked.insert(i); + v_unmarked.erase(i); + + for (uint32_t f : VF[i]) { + if (f_adjacent.find(f) == f_adjacent.end()) /* if not part of adjacent face */ + continue; + for (uint32_t j = 0; j < degree; ++j) { + uint32_t k = F[f][j]; + if (v_unmarked.find(k) == v_unmarked.end() || /* if not unmarked OR */ + v_marked.find(k) != v_marked.end()) /* if already marked */ + continue; + dfs(k); + } + } + }; + + for (uint32_t i = 0; i < (uint32_t)V.size(); ++i) { + v_marked.clear(); + v_unmarked.clear(); + f_adjacent.clear(); + + for (uint32_t f : VF[i]) { + if (F[f][0] == INVALID) continue; + + for (uint32_t k = 0; k < degree; ++k) v_unmarked.insert(F[f][k]); + + f_adjacent.insert(f); + } + + if (v_unmarked.empty()) continue; + v_marked.insert(i); + v_unmarked.erase(i); + + dfs(*v_unmarked.begin()); + + if (v_unmarked.size() > 0) { + nm_vert++; + for (uint32_t f : f_adjacent) kill_face(f); + } + } + + if (nm_vert > 0 || nm_edge > 0) { + std::cout << "Non-manifold elements: vertices=" << nm_vert << ", edges=" << nm_edge + << std::endl; + } + uint32_t nFaces = 0, nFacesOrig = F.size(); + for (uint32_t f = 0; f < (uint32_t)F.size(); ++f) { + if (F[f][0] == INVALID) continue; + if (nFaces != f) { + F[nFaces] = F[f]; + } + ++nFaces; + } + + if (nFacesOrig != nFaces) { + F.resize(nFaces); + std::cout << "Faces reduced from " << nFacesOrig << " -> " << nFaces << std::endl; + } +} + +} // namespace qflow diff --git a/extern/quadriflow/src/dedge.hpp b/extern/quadriflow/src/dedge.hpp new file mode 100644 index 00000000000..e8ee372f012 --- /dev/null +++ b/extern/quadriflow/src/dedge.hpp @@ -0,0 +1,25 @@ +#ifndef DEDGE_H_ +#define DEDGE_H_ + +#include +#include +#include + +namespace qflow { + +using namespace Eigen; + +inline int dedge_prev_3(int e) { return (e % 3 == 0) ? e + 2 : e - 1; } +inline int dedge_next_3(int e) { return (e % 3 == 2) ? e - 2 : e + 1; } + +bool compute_direct_graph(MatrixXd& V, MatrixXi& F, VectorXi& V2E, + VectorXi& E2E, VectorXi& boundary, VectorXi& nonManifold); + +void compute_direct_graph_quad(std::vector& V, std::vector& F, std::vector& V2E, + std::vector& E2E, VectorXi& boundary, VectorXi& nonManifold); + +void remove_nonmanifold(std::vector &F, std::vector &V); + +} // namespace qflow + +#endif diff --git a/extern/quadriflow/src/disajoint-tree.hpp b/extern/quadriflow/src/disajoint-tree.hpp new file mode 100644 index 00000000000..1822b83a208 --- /dev/null +++ b/extern/quadriflow/src/disajoint-tree.hpp @@ -0,0 +1,151 @@ +#ifndef DISAJOINT_TREE_H_ +#define DISAJOINT_TREE_H_ + +#include + +namespace qflow { + +class DisajointTree { + public: + DisajointTree() {} + DisajointTree(int n) { + parent.resize(n); + rank.resize(n, 1); + for (int i = 0; i < n; ++i) parent[i] = i; + } + int Parent(int x) { + if (x == parent[x]) return x; + int y = Parent(parent[x]); + parent[x] = y; + return y; + } + int Index(int x) { return indices[x]; } + int IndexToParent(int x) {return indices_to_parent[x]; }; + void MergeFromTo(int x, int y) { + int px = Parent(x); + int py = Parent(y); + if (px == py) return; + rank[py] += rank[px]; + parent[px] = py; + } + void Merge(int x, int y) { + int px = Parent(x); + int py = Parent(y); + if (px == py) return; + if (rank[px] < rank[py]) { + rank[py] += rank[px]; + parent[px] = py; + } else { + rank[px] += rank[py]; + parent[py] = px; + } + } + + // renumber the root so that it is consecutive. + void BuildCompactParent() { + std::vector compact_parent; + compact_parent.resize(parent.size()); + compact_num = 0; + for (int i = 0; i < parent.size(); ++i) { + if (parent[i] == i) { + compact_parent[i] = compact_num++; + indices_to_parent.push_back(i); + } + } + indices.resize(parent.size()); + for (int i = 0; i < parent.size(); ++i) { + indices[i] = compact_parent[Parent(i)]; + } + } + + int CompactNum() { return compact_num; } + + int compact_num; + std::vector parent; + std::vector indices, indices_to_parent; + std::vector rank; +}; + +class DisajointOrientTree { + public: + DisajointOrientTree() {} + DisajointOrientTree(int n) { + parent.resize(n); + rank.resize(n, 1); + for (int i = 0; i < n; ++i) parent[i] = std::make_pair(i, 0); + } + int Parent(int j) { + if (j == parent[j].first) return j; + int k = Parent(parent[j].first); + parent[j].second = (parent[j].second + parent[parent[j].first].second) % 4; + parent[j].first = k; + return k; + } + int Orient(int j) { + if (j == parent[j].first) return parent[j].second; + return (parent[j].second + Orient(parent[j].first)) % 4; + } + int Index(int x) { return indices[x]; } + void MergeFromTo(int v0, int v1, int orient0, int orient1) { + int p0 = Parent(v0); + int p1 = Parent(v1); + if (p0 == p1) return; + int orientp0 = Orient(v0); + int orientp1 = Orient(v1); + + if (p0 == p1) { + return; + } + rank[p1] += rank[p0]; + parent[p0].first = p1; + parent[p0].second = (orient0 - orient1 + orientp1 - orientp0 + 8) % 4; + } + + void Merge(int v0, int v1, int orient0, int orient1) { + int p0 = Parent(v0); + int p1 = Parent(v1); + if (p0 == p1) { + return; + } + int orientp0 = Orient(v0); + int orientp1 = Orient(v1); + + if (p0 == p1) { + return; + } + if (rank[p1] < rank[p0]) { + rank[p0] += rank[p1]; + parent[p1].first = p0; + parent[p1].second = (orient1 - orient0 + orientp0 - orientp1 + 8) % 4; + } else { + rank[p1] += rank[p0]; + parent[p0].first = p1; + parent[p0].second = (orient0 - orient1 + orientp1 - orientp0 + 8) % 4; + } + } + void BuildCompactParent() { + std::vector compact_parent; + compact_parent.resize(parent.size()); + compact_num = 0; + for (int i = 0; i < parent.size(); ++i) { + if (parent[i].first == i) { + compact_parent[i] = compact_num++; + } + } + indices.resize(parent.size()); + for (int i = 0; i < parent.size(); ++i) { + indices[i] = compact_parent[Parent(i)]; + } + } + + int CompactNum() { return compact_num; } + + int compact_num; + std::vector> parent; + std::vector indices; + std::vector rank; +}; + +} // namespace qflow + +#endif diff --git a/extern/quadriflow/src/dset.hpp b/extern/quadriflow/src/dset.hpp new file mode 100644 index 00000000000..f8e6f6da6b6 --- /dev/null +++ b/extern/quadriflow/src/dset.hpp @@ -0,0 +1,163 @@ +#if !defined(__UNIONFIND_H) +#define __UNIONFIND_H + +#include +#include +#include + +namespace qflow { + +/** +* Lock-free parallel disjoint set data structure (aka UNION-FIND) +* with path compression and union by rank +* +* Supports concurrent find(), same() and unite() calls as described +* in the paper +* +* "Wait-free Parallel Algorithms for the Union-Find Problem" +* by Richard J. Anderson and Heather Woll +* +* In addition, this class supports optimistic locking (try_lock/unlock) +* of disjoint sets and a combined unite+unlock operation. +* +* \author Wenzel Jakob +*/ +class DisjointSets { +public: + DisjointSets(uint32_t size) : mData(size) { + for (uint32_t i = 0; i r2 || (r1 == r2 && id1 < id2)) { + std::swap(r1, r2); + std::swap(id1, id2); + } + + uint64_t oldEntry = ((uint64_t)r1 << 32) | id1; + uint64_t newEntry = ((uint64_t)r1 << 32) | id2; + + if (!mData[id1].compare_exchange_strong(oldEntry, newEntry)) + continue; + + if (r1 == r2) { + oldEntry = ((uint64_t)r2 << 32) | id2; + newEntry = ((uint64_t)(r2 + 1) << 32) | id2; + /* Try to update the rank (may fail, that's ok) */ + mData[id2].compare_exchange_weak(oldEntry, newEntry); + } + + break; + } + return id2; + } + + /** + * Try to lock the a disjoint union identified by one + * of its elements (this can occasionally fail when there + * are concurrent operations). The parameter 'id' will be + * updated to store the current representative ID of the + * union + */ + bool try_lock(uint32_t &id) { + const uint64_t lock_flag = 1ULL << 63; + id = find(id); + uint64_t value = mData[id]; + if ((value & lock_flag) || (uint32_t)value != id) + return false; + // On IA32/x64, a PAUSE instruction is recommended for CAS busy loops +#if defined(__i386__) || defined(__amd64__) + __asm__ __volatile__("pause\n"); +#endif + return mData[id].compare_exchange_strong(value, value | lock_flag); + } + + void unlock(uint32_t id) { + const uint64_t lock_flag = 1ULL << 63; + mData[id] &= ~lock_flag; + } + + /** + * Return the representative index of the set that results from merging + * locked disjoint sets 'id1' and 'id2' + */ + uint32_t unite_index_locked(uint32_t id1, uint32_t id2) const { + uint32_t r1 = rank(id1), r2 = rank(id2); + return (r1 > r2 || (r1 == r2 && id1 < id2)) ? id1 : id2; + } + + /** + * Atomically unite two locked disjoint sets and unlock them. Assumes + * that here are no other concurrent unite() involving the same sets + */ + uint32_t unite_unlock(uint32_t id1, uint32_t id2) { + uint32_t r1 = rank(id1), r2 = rank(id2); + + if (r1 > r2 || (r1 == r2 && id1 < id2)) { + std::swap(r1, r2); + std::swap(id1, id2); + } + + mData[id1] = ((uint64_t)r1 << 32) | id2; + mData[id2] = ((uint64_t)(r2 + ((r1 == r2) ? 1 : 0)) << 32) | id2; + + return id2; + } + + uint32_t size() const { return (uint32_t)mData.size(); } + + uint32_t rank(uint32_t id) const { + return ((uint32_t)(mData[id] >> 32)) & 0x7FFFFFFFu; + } + + uint32_t parent(uint32_t id) const { + return (uint32_t)mData[id]; + } + + friend std::ostream &operator<<(std::ostream &os, const DisjointSets &f) { + for (size_t i = 0; i= 0 && lens[fid] < max_len) { + max_len = lens[fid]; + next_id = E2E[edge_id + fid]; + next_f = next_id; + if (next_f != -1) next_f /= 3; + found = true; + } + } + if (!found) { + printf("error...\n"); + exit(0); + } + // printf("status: %f %f %d\n", len, max_len, f); + if (max_len >= len) { + if (tx && ty) { + *tx = coord.x() + dirs.x() * len; + *ty = coord.y() + dirs.y() * len; + } + p = p + len * pt; + len = 0; + return p; + } + p = V.col(F(0, f)) + t1 * (coord.x() + dirs.x() * max_len) + + t2 * (coord.y() + dirs.y() * max_len); + len -= max_len; + if (next_f == -1) { + if (tx && ty) { + *tx = coord.x() + dirs.x() * max_len; + *ty = coord.y() + dirs.y() * max_len; + } + return p; + } + pt = rotate_vector_into_plane(pt, NF.col(f), NF.col(next_f)); + f = next_f; + prev_id = next_id; + } + return p; +} +inline Vector3d TravelField(Vector3d p, Vector3d &pt, double &len, int &f, VectorXi &E2E, + MatrixXd &V, MatrixXi &F, MatrixXd &NF, MatrixXd &QF, MatrixXd &QV, + MatrixXd &NV, std::vector &triangle_space, double *tx = 0, + double *ty = 0, Vector3d *dir_unfold = 0) { + Vector3d N = NF.col(f); + pt = (pt - pt.dot(N) * N).normalized(); + int prev_id = -1; + int count = 0; + std::vector Ns; + + auto FaceQFromVertices = [&](int f, double tx, double ty) { + const Vector3d &n = NF.col(f); + const Vector3d &q_1 = QV.col(F(0, f)), &q_2 = QV.col(F(1, f)), &q_3 = QV.col(F(2, f)); + const Vector3d &n_1 = NV.col(F(0, f)), &n_2 = NV.col(F(1, f)), &n_3 = NV.col(F(2, f)); + Vector3d q_1n = rotate_vector_into_plane(q_1, n_1, n); + Vector3d q_2n = rotate_vector_into_plane(q_2, n_2, n); + Vector3d q_3n = rotate_vector_into_plane(q_3, n_3, n); + auto orient = compat_orientation_extrinsic_4(q_1n, n, q_2n, n); + Vector3d q = (orient.first * tx + orient.second * ty).normalized(); + orient = compat_orientation_extrinsic_4(q, n, q_3n, n); + q = (orient.first * (tx + ty) + orient.second * (1 - tx - ty)).normalized(); + return q; + }; + + auto BestQFromGivenQ = [&](const Vector3d &n, const Vector3d &q, const Vector3d &given_q) { + Vector3d q_1 = n.cross(q); + double t1 = q.dot(given_q); + double t2 = q_1.dot(given_q); + if (fabs(t1) > fabs(t2)) { + if (t1 > 0.0) + return Vector3d(q); + else + return Vector3d(-q); + } else { + if (t2 > 0.0) + return Vector3d(q_1); + else + return Vector3d(-q_1); + } + }; + + while (len > 0) { + count += 1; + Vector3d t1 = V.col(F(1, f)) - V.col(F(0, f)); + Vector3d t2 = V.col(F(2, f)) - V.col(F(0, f)); + Vector3d N = NF.col(f); + Ns.push_back(N); + // printf("point dis: %f\n", (p - V.col(F(1, f))).dot(N)); + int edge_id = f * 3; + double max_len = 1e30; + bool found = false; + int next_id = -1, next_f = -1; + Vector3d next_q; + Matrix3d m, n; + m.col(0) = t1; + m.col(1) = t2; + m.col(2) = N; + n = m.inverse(); + MatrixXd &T = triangle_space[f]; + VectorXd coord = T * Vector3d(p - V.col(F(0, f))); + VectorXd dirs = (T * pt); + double lens[3]; + lens[0] = -coord.y() / dirs.y(); + lens[1] = (1 - coord.x() - coord.y()) / (dirs.x() + dirs.y()); + lens[2] = -coord.x() / dirs.x(); + for (int fid = 0; fid < 3; ++fid) { + if (fid + edge_id == prev_id) continue; + + if (lens[fid] >= 0 && lens[fid] < max_len) { + max_len = lens[fid]; + next_id = E2E[edge_id + fid]; + next_f = next_id; + if (next_f != -1) next_f /= 3; + found = true; + } + } + double w1 = (coord.x() + dirs.x() * max_len); + double w2 = (coord.y() + dirs.y() * max_len); + if (w1 < 0) w1 = 0.0f; + if (w2 < 0) w2 = 0.0f; + if (w1 + w2 > 1) { + double w = w1 + w2; + w1 /= w; + w2 /= w; + } + + if (!found) { + printf("error...\n"); + exit(0); + } + // printf("status: %f %f %d\n", len, max_len, f); + if (max_len >= len) { + if (tx && ty) { + *tx = w1; + *ty = w2; + } + Vector3d ideal_q = FaceQFromVertices(f, *tx, *ty); + *dir_unfold = BestQFromGivenQ(NF.col(f), ideal_q, *dir_unfold); + for (int i = Ns.size() - 1; i > 0; --i) { + *dir_unfold = rotate_vector_into_plane(*dir_unfold, Ns[i], Ns[i - 1]); + } + p = p + len * pt; + len = 0; + return p; + } + p = V.col(F(0, f)) + t1 * w1 + t2 * w2; + len -= max_len; + if (next_f == -1) { + if (tx && ty) { + *tx = w1; + *ty = w2; + } + Vector3d ideal_q = FaceQFromVertices(f, *tx, *ty); + *dir_unfold = BestQFromGivenQ(NF.col(f), ideal_q, *dir_unfold); + for (int i = Ns.size() - 1; i > 0; --i) { + *dir_unfold = rotate_vector_into_plane(*dir_unfold, Ns[i], Ns[i - 1]); + } + return p; + } + pt = rotate_vector_into_plane(pt, NF.col(f), NF.col(next_f)); + // pt = BestQFromGivenQ(NF.col(next_f), QF.col(next_f), pt); + if (dir_unfold) { + *dir_unfold = BestQFromGivenQ(NF.col(next_f), QF.col(next_f), *dir_unfold); + } + f = next_f; + prev_id = next_id; + } + + return p; +} + +} // namespace qflow + +#endif diff --git a/extern/quadriflow/src/flow.hpp b/extern/quadriflow/src/flow.hpp new file mode 100644 index 00000000000..ab4a01cb4ed --- /dev/null +++ b/extern/quadriflow/src/flow.hpp @@ -0,0 +1,375 @@ +#ifndef FLOW_H_ +#define FLOW_H_ + +#include +#include +#include +#include + +#include "config.hpp" + +#include +#include +#include +#include + +#include +#include +#include + +using namespace boost; +using namespace Eigen; + +namespace qflow { + +class MaxFlowHelper { + public: + MaxFlowHelper() {} + virtual ~MaxFlowHelper(){}; + virtual void resize(int n, int m) = 0; + virtual void addEdge(int x, int y, int c, int rc, int v, int cost = 1) = 0; + virtual int compute() = 0; + virtual void applyTo(std::vector& edge_diff) = 0; +}; + +class BoykovMaxFlowHelper : public MaxFlowHelper { + public: + typedef int EdgeWeightType; + typedef adjacency_list_traits Traits; + // clang-format off + typedef adjacency_list < vecS, vecS, directedS, + property < vertex_name_t, std::string, + property < vertex_index_t, long, + property < vertex_color_t, boost::default_color_type, + property < vertex_distance_t, long, + property < vertex_predecessor_t, Traits::edge_descriptor > > > > >, + + property < edge_capacity_t, EdgeWeightType, + property < edge_residual_capacity_t, EdgeWeightType, + property < edge_reverse_t, Traits::edge_descriptor > > > > Graph; + // clang-format on + + public: + BoykovMaxFlowHelper() { rev = get(edge_reverse, g); } + void resize(int n, int m) { + vertex_descriptors.resize(n); + for (int i = 0; i < n; ++i) vertex_descriptors[i] = add_vertex(g); + } + int compute() { + EdgeWeightType flow = + boykov_kolmogorov_max_flow(g, vertex_descriptors.front(), vertex_descriptors.back()); + return flow; + } + void addDirectEdge(Traits::vertex_descriptor& v1, Traits::vertex_descriptor& v2, + property_map::type& rev, const int capacity, + const int inv_capacity, Graph& g, Traits::edge_descriptor& e1, + Traits::edge_descriptor& e2) { + e1 = add_edge(v1, v2, g).first; + e2 = add_edge(v2, v1, g).first; + put(edge_capacity, g, e1, capacity); + put(edge_capacity, g, e2, inv_capacity); + + rev[e1] = e2; + rev[e2] = e1; + } + void addEdge(int x, int y, int c, int rc, int v, int cost = 1) { + Traits::edge_descriptor e1, e2; + addDirectEdge(vertex_descriptors[x], vertex_descriptors[y], rev, c, rc, g, e1, e2); + if (v != -1) { + edge_to_variables[e1] = std::make_pair(v, -1); + edge_to_variables[e2] = std::make_pair(v, 1); + } + } + void applyTo(std::vector& edge_diff) { + property_map::type capacity = get(edge_capacity, g); + property_map::type residual_capacity = + get(edge_residual_capacity, g); + + graph_traits::vertex_iterator u_iter, u_end; + graph_traits::out_edge_iterator ei, e_end; + for (tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) + for (tie(ei, e_end) = out_edges(*u_iter, g); ei != e_end; ++ei) + if (capacity[*ei] > 0) { + int flow = (capacity[*ei] - residual_capacity[*ei]); + if (flow > 0) { + auto it = edge_to_variables.find(*ei); + if (it != edge_to_variables.end()) { + edge_diff[it->second.first / 2][it->second.first % 2] += + it->second.second * flow; + } + } + } + } + + private: + Graph g; + property_map::type rev; + std::vector vertex_descriptors; + std::map> edge_to_variables; +}; + +class NetworkSimplexFlowHelper : public MaxFlowHelper { + public: + using Weight = int; + using Capacity = int; + using Graph = lemon::SmartDigraph; + using Node = Graph::Node; + using Arc = Graph::Arc; + template + using ArcMap = lemon::SmartDigraph::ArcMap; + using Preflow = lemon::Preflow>; + using NetworkSimplex = lemon::NetworkSimplex; + + public: + NetworkSimplexFlowHelper() : cost(graph), capacity(graph), flow(graph), variable(graph) {} + ~NetworkSimplexFlowHelper(){}; + void resize(int n, int m) { + nodes.reserve(n); + for (int i = 0; i < n; ++i) nodes.push_back(graph.addNode()); + } + void addEdge(int x, int y, int c, int rc, int v, int cst = 1) { + assert(x >= 0); + assert(v >= -1); + if (c) { + auto e1 = graph.addArc(nodes[x], nodes[y]); + cost[e1] = cst; + capacity[e1] = c; + variable[e1] = std::make_pair(v, 1); + } + + if (rc) { + auto e2 = graph.addArc(nodes[y], nodes[x]); + cost[e2] = cst; + capacity[e2] = rc; + variable[e2] = std::make_pair(v, -1); + } + } + int compute() { + Preflow pf(graph, capacity, nodes.front(), nodes.back()); + NetworkSimplex ns(graph); + + // Run preflow to find maximum flow + lprintf("push-relabel flow... "); + pf.runMinCut(); + int maxflow = pf.flowValue(); + + // Run network simplex to find minimum cost maximum flow + ns.costMap(cost).upperMap(capacity).stSupply(nodes.front(), nodes.back(), maxflow); + auto status = ns.run(); + switch (status) { + case NetworkSimplex::OPTIMAL: + ns.flowMap(flow); + break; + case NetworkSimplex::INFEASIBLE: + lputs("NetworkSimplex::INFEASIBLE"); + assert(0); + break; + default: + lputs("Unknown: NetworkSimplex::Default"); + assert(0); + break; + } + + return maxflow; + } + void applyTo(std::vector& edge_diff) { + for (Graph::ArcIt e(graph); e != lemon::INVALID; ++e) { + int var = variable[e].first; + if (var == -1) continue; + int sgn = variable[e].second; + edge_diff[var / 2][var % 2] -= sgn * flow[e]; + } + } + + private: + Graph graph; + ArcMap cost; + ArcMap capacity; + ArcMap flow; + ArcMap> variable; + std::vector nodes; + std::vector edges; +}; + +#ifdef WITH_GUROBI + +#include + +class GurobiFlowHelper : public MaxFlowHelper { + public: + GurobiFlowHelper() {} + virtual ~GurobiFlowHelper(){}; + virtual void resize(int n, int m) { + nodes.resize(n * 2); + edges.resize(m); + } + virtual void addEdge(int x, int y, int c, int rc, int v, int cost = 1) { + nodes[x * 2 + 0].push_back(vars.size()); + nodes[y * 2 + 1].push_back(vars.size()); + vars.push_back(model.addVar(0, c, 0, GRB_INTEGER)); + edges.push_back(std::make_pair(v, 1)); + + nodes[y * 2 + 0].push_back(vars.size()); + nodes[x * 2 + 1].push_back(vars.size()); + vars.push_back(model.addVar(0, rc, 0, GRB_INTEGER)); + edges.push_back(std::make_pair(v, -1)); + } + virtual int compute() { + std::cerr << "compute" << std::endl; + int ns = nodes.size() / 2; + + int flow; + for (int i = 1; i < ns - 1; ++i) { + GRBLinExpr cons = 0; + for (auto n : nodes[2 * i + 0]) cons += vars[n]; + for (auto n : nodes[2 * i + 1]) cons -= vars[n]; + model.addConstr(cons == 0); + } + + // first pass, maximum flow + GRBLinExpr outbound = 0; + { + lprintf("first pass\n"); + for (auto& n : nodes[0]) outbound += vars[n]; + for (auto& n : nodes[1]) outbound -= vars[n]; + model.setObjective(outbound, GRB_MAXIMIZE); + model.optimize(); + + flow = (int)model.get(GRB_DoubleAttr_ObjVal); + lprintf("Gurobi result: %d\n", flow); + } + + // second pass, minimum cost flow + { + lprintf("second pass\n"); + model.addConstr(outbound == flow); + GRBLinExpr cost = 0; + for (auto& v : vars) cost += v; + model.setObjective(cost, GRB_MINIMIZE); + model.optimize(); + + double optimal_cost = (int)model.get(GRB_DoubleAttr_ObjVal); + lprintf("Gurobi result: %.3f\n", optimal_cost); + } + return flow; + } + virtual void applyTo(std::vector& edge_diff) { assert(0); }; + + private: + GRBEnv env = GRBEnv(); + GRBModel model = GRBModel(env); + std::vector vars; + std::vector> edges; + std::vector> nodes; +}; + +#endif + +class ECMaxFlowHelper : public MaxFlowHelper { + public: + struct FlowInfo { + int id; + int capacity, flow; + int v, d; + FlowInfo* rev; + }; + struct SearchInfo { + SearchInfo(int _id, int _prev_id, FlowInfo* _info) + : id(_id), prev_id(_prev_id), info(_info) {} + int id; + int prev_id; + FlowInfo* info; + }; + ECMaxFlowHelper() { num = 0; } + int num; + std::vector variable_to_edge; + void resize(int n, int m) { + graph.resize(n); + variable_to_edge.resize(m, 0); + num = n; + } + void addEdge(int x, int y, int c, int rc, int v, int cost = 0) { + FlowInfo flow; + flow.id = y; + flow.capacity = c; + flow.flow = 0; + flow.v = v; + flow.d = -1; + graph[x].push_back(flow); + auto& f1 = graph[x].back(); + flow.id = x; + flow.capacity = rc; + flow.flow = 0; + flow.v = v; + flow.d = 1; + graph[y].push_back(flow); + auto& f2 = graph[y].back(); + f2.rev = &f1; + f1.rev = &f2; + } + int compute() { + int total_flow = 0; + int count = 0; + while (true) { + count += 1; + std::vector vhash(num, 0); + std::vector q; + q.push_back(SearchInfo(0, -1, 0)); + vhash[0] = 1; + int q_front = 0; + bool found = false; + while (q_front < q.size()) { + int vert = q[q_front].id; + for (auto& l : graph[vert]) { + if (vhash[l.id] || l.capacity <= l.flow) continue; + q.push_back(SearchInfo(l.id, q_front, &l)); + vhash[l.id] = 1; + if (l.id == num - 1) { + found = true; + break; + } + } + if (found) break; + q_front += 1; + } + if (q_front == q.size()) break; + int loc = q.size() - 1; + while (q[loc].prev_id != -1) { + q[loc].info->flow += 1; + q[loc].info->rev->flow -= 1; + loc = q[loc].prev_id; + // int prev_v = q[loc].id; + // applyFlow(prev_v, current_v, 1); + // applyFlow(current_v, prev_v, -1); + } + total_flow += 1; + } + return total_flow; + } + void applyTo(std::vector& edge_diff) { + for (int i = 0; i < graph.size(); ++i) { + for (auto& flow : graph[i]) { + if (flow.flow > 0 && flow.v != -1) { + if (flow.flow > 0) { + edge_diff[flow.v / 2][flow.v % 2] += flow.d * flow.flow; + if (abs(edge_diff[flow.v / 2][flow.v % 2]) > 2) { + } + } + } + } + } + } + void applyFlow(int v1, int v2, int flow) { + for (auto& it : graph[v1]) { + if (it.id == v2) { + it.flow += flow; + break; + } + } + } + std::vector> graph; +}; + +} // namespace qflow + +#endif diff --git a/extern/quadriflow/src/hierarchy.cpp b/extern/quadriflow/src/hierarchy.cpp new file mode 100644 index 00000000000..c333256a139 --- /dev/null +++ b/extern/quadriflow/src/hierarchy.cpp @@ -0,0 +1,1343 @@ +#include "hierarchy.hpp" +#include +#include +#include +#include "config.hpp" +#include "field-math.hpp" +#include +#include "localsat.hpp" +#include "pcg32/pcg32.h" +#ifdef WITH_TBB +# include "tbb/tbb.h" +# include "pss/parallel_stable_sort.h" +#endif + +namespace qflow { + +Hierarchy::Hierarchy() { + mAdj.resize(MAX_DEPTH + 1); + mV.resize(MAX_DEPTH + 1); + mN.resize(MAX_DEPTH + 1); + mA.resize(MAX_DEPTH + 1); + mPhases.resize(MAX_DEPTH + 1); + mToLower.resize(MAX_DEPTH); + mToUpper.resize(MAX_DEPTH); + rng_seed = 0; + + mCQ.reserve(MAX_DEPTH + 1); + mCQw.reserve(MAX_DEPTH + 1); + mCO.reserve(MAX_DEPTH + 1); + mCOw.reserve(MAX_DEPTH + 1); +} + +#undef max + +void Hierarchy::Initialize(double scale, int with_scale) { + this->with_scale = with_scale; + generate_graph_coloring_deterministic(mAdj[0], mV[0].cols(), mPhases[0]); + + for (int i = 0; i < MAX_DEPTH; ++i) { + DownsampleGraph(mAdj[i], mV[i], mN[i], mA[i], mV[i + 1], mN[i + 1], mA[i + 1], mToUpper[i], + mToLower[i], mAdj[i + 1]); + generate_graph_coloring_deterministic(mAdj[i + 1], mV[i + 1].cols(), mPhases[i + 1]); + if (mV[i + 1].cols() == 1) { + mAdj.resize(i + 2); + mV.resize(i + 2); + mN.resize(i + 2); + mA.resize(i + 2); + mToUpper.resize(i + 1); + mToLower.resize(i + 1); + break; + } + } + mQ.resize(mV.size()); + mO.resize(mV.size()); + mS.resize(mV.size()); + mK.resize(mV.size()); + + mCO.resize(mV.size()); + mCOw.resize(mV.size()); + mCQ.resize(mV.size()); + mCQw.resize(mV.size()); + + //Set random seed + srand(rng_seed); + + mScale = scale; + for (int i = 0; i < mV.size(); ++i) { + mQ[i].resize(mN[i].rows(), mN[i].cols()); + mO[i].resize(mN[i].rows(), mN[i].cols()); + mS[i].resize(2, mN[i].cols()); + mK[i].resize(2, mN[i].cols()); + for (int j = 0; j < mN[i].cols(); ++j) { + Vector3d s, t; + coordinate_system(mN[i].col(j), s, t); + //rand() is not thread safe! + double angle = ((double)rand()) / RAND_MAX * 2 * M_PI; + double x = ((double)rand()) / RAND_MAX * 2 - 1.f; + double y = ((double)rand()) / RAND_MAX * 2 - 1.f; + mQ[i].col(j) = s * std::cos(angle) + t * std::sin(angle); + mO[i].col(j) = mV[i].col(j) + (s * x + t * y) * scale; + if (with_scale) { + mS[i].col(j) = Vector2d(1.0f, 1.0f); + mK[i].col(j) = Vector2d(0.0, 0.0); + } + } + } +#ifdef WITH_CUDA + printf("copy to device...\n"); + CopyToDevice(); + printf("copy to device finish...\n"); +#endif +} + +#ifdef WITH_TBB +void Hierarchy::generate_graph_coloring_deterministic(const AdjacentMatrix& adj, int size, + std::vector>& phases) { + struct ColorData { + uint8_t nColors; + uint32_t nNodes[256]; + ColorData() : nColors(0) {} + }; + + const uint8_t INVALID_COLOR = 0xFF; + phases.clear(); + + /* Generate a permutation */ + std::vector perm(size); + std::vector mutex(size); + for (uint32_t i = 0; i < size; ++i) perm[i] = i; + + tbb::parallel_for(tbb::blocked_range(0u, size, GRAIN_SIZE), + [&](const tbb::blocked_range& range) { + pcg32 rng; + rng.advance(range.begin()); + for (uint32_t i = range.begin(); i != range.end(); ++i) { + uint32_t j = i, k = rng.nextUInt(size - i) + i; + if (j == k) continue; + if (j > k) std::swap(j, k); + tbb::spin_mutex::scoped_lock l0(mutex[j]); + tbb::spin_mutex::scoped_lock l1(mutex[k]); + std::swap(perm[j], perm[k]); + } + }); + + std::vector color(size, INVALID_COLOR); + ColorData colorData = tbb::parallel_reduce( + tbb::blocked_range(0u, size, GRAIN_SIZE), ColorData(), + [&](const tbb::blocked_range& range, ColorData colorData) -> ColorData { + std::vector neighborhood; + bool possible_colors[256]; + + for (uint32_t pidx = range.begin(); pidx != range.end(); ++pidx) { + uint32_t i = perm[pidx]; + + neighborhood.clear(); + neighborhood.push_back(i); + // for (const Link *link = adj[i]; link != adj[i + 1]; ++link) + for (auto& link : adj[i]) neighborhood.push_back(link.id); + std::sort(neighborhood.begin(), neighborhood.end()); + for (uint32_t j : neighborhood) mutex[j].lock(); + + std::fill(possible_colors, possible_colors + colorData.nColors, true); + + // for (const Link *link = adj[i]; link != adj[i + 1]; ++link) { + for (auto& link : adj[i]) { + uint8_t c = color[link.id]; + if (c != INVALID_COLOR) { + while (c >= colorData.nColors) { + possible_colors[colorData.nColors] = true; + colorData.nNodes[colorData.nColors] = 0; + colorData.nColors++; + } + possible_colors[c] = false; + } + } + + uint8_t chosen_color = INVALID_COLOR; + for (uint8_t j = 0; j < colorData.nColors; ++j) { + if (possible_colors[j]) { + chosen_color = j; + break; + } + } + if (chosen_color == INVALID_COLOR) { + if (colorData.nColors == INVALID_COLOR - 1) + throw std::runtime_error( + "Ran out of colors during graph coloring! " + "The input mesh is very likely corrupt."); + colorData.nNodes[colorData.nColors] = 1; + color[i] = colorData.nColors++; + } else { + colorData.nNodes[chosen_color]++; + color[i] = chosen_color; + } + + for (uint32_t j : neighborhood) mutex[j].unlock(); + } + return colorData; + }, + [](ColorData c1, ColorData c2) -> ColorData { + ColorData result; + result.nColors = std::max(c1.nColors, c2.nColors); + memset(result.nNodes, 0, sizeof(uint32_t) * result.nColors); + for (uint8_t i = 0; i < c1.nColors; ++i) result.nNodes[i] += c1.nNodes[i]; + for (uint8_t i = 0; i < c2.nColors; ++i) result.nNodes[i] += c2.nNodes[i]; + return result; + }); + + phases.resize(colorData.nColors); + for (int i = 0; i < colorData.nColors; ++i) phases[i].reserve(colorData.nNodes[i]); + + for (uint32_t i = 0; i < size; ++i) phases[color[i]].push_back(i); +} +#else +void Hierarchy::generate_graph_coloring_deterministic(const AdjacentMatrix& adj, int size, + std::vector>& phases) { + phases.clear(); + + std::vector perm(size); + for (uint32_t i = 0; i < size; ++i) perm[i] = i; + pcg32 rng; + rng.shuffle(perm.begin(), perm.end()); + + std::vector color(size, -1); + std::vector possible_colors; + std::vector size_per_color; + int ncolors = 0; + + for (uint32_t i = 0; i < size; ++i) { + uint32_t ip = perm[i]; + + std::fill(possible_colors.begin(), possible_colors.end(), 1); + + for (auto& link : adj[ip]) { + int c = color[link.id]; + if (c >= 0) possible_colors[c] = 0; + } + + int chosen_color = -1; + for (uint32_t j = 0; j < possible_colors.size(); ++j) { + if (possible_colors[j]) { + chosen_color = j; + break; + } + } + + if (chosen_color < 0) { + chosen_color = ncolors++; + possible_colors.resize(ncolors); + size_per_color.push_back(0); + } + + color[ip] = chosen_color; + size_per_color[chosen_color]++; + } + phases.resize(ncolors); + for (int i = 0; i < ncolors; ++i) phases[i].reserve(size_per_color[i]); + for (uint32_t i = 0; i < size; ++i) phases[color[i]].push_back(i); +} +#endif + +void Hierarchy::DownsampleGraph(const AdjacentMatrix adj, const MatrixXd& V, const MatrixXd& N, + const VectorXd& A, MatrixXd& V_p, MatrixXd& N_p, VectorXd& A_p, + MatrixXi& to_upper, VectorXi& to_lower, AdjacentMatrix& adj_p) { + struct Entry { + int i, j; + double order; + inline Entry() { i = j = -1; }; + inline Entry(int i, int j, double order) : i(i), j(j), order(order) {} + inline bool operator<(const Entry& e) const { return order > e.order; } + inline bool operator==(const Entry& e) const { return order == e.order; } + }; + + int nLinks = 0; + for (auto& adj_i : adj) nLinks += adj_i.size(); + std::vector entries(nLinks); + std::vector bases(adj.size()); + for (int i = 1; i < bases.size(); ++i) { + bases[i] = bases[i - 1] + adj[i - 1].size(); + } + +#ifdef WITH_OMP +#pragma omp parallel for +#endif + for (int i = 0; i < V.cols(); ++i) { + int base = bases[i]; + auto& ad = adj[i]; + auto entry_it = entries.begin() + base; + for (auto it = ad.begin(); it != ad.end(); ++it, ++entry_it) { + int k = it->id; + double dp = N.col(i).dot(N.col(k)); + double ratio = A[i] > A[k] ? (A[i] / A[k]) : (A[k] / A[i]); + *entry_it = Entry(i, k, dp * ratio); + } + } + +#ifdef WITH_TBB + pss::parallel_stable_sort(entries.begin(), entries.end(), std::less()); +#else + std::stable_sort(entries.begin(), entries.end(), std::less()); +#endif + + std::vector mergeFlag(V.cols(), false); + + int nCollapsed = 0; + for (int i = 0; i < nLinks; ++i) { + const Entry& e = entries[i]; + if (mergeFlag[e.i] || mergeFlag[e.j]) continue; + mergeFlag[e.i] = mergeFlag[e.j] = true; + entries[nCollapsed++] = entries[i]; + } + int vertexCount = V.cols() - nCollapsed; + + // Allocate memory for coarsened graph + V_p.resize(3, vertexCount); + N_p.resize(3, vertexCount); + A_p.resize(vertexCount); + to_upper.resize(2, vertexCount); + to_lower.resize(V.cols()); + +#ifdef WITH_OMP +#pragma omp parallel for +#endif + for (int i = 0; i < nCollapsed; ++i) { + const Entry& e = entries[i]; + const double area1 = A[e.i], area2 = A[e.j], surfaceArea = area1 + area2; + if (surfaceArea > RCPOVERFLOW) + V_p.col(i) = (V.col(e.i) * area1 + V.col(e.j) * area2) / surfaceArea; + else + V_p.col(i) = (V.col(e.i) + V.col(e.j)) * 0.5f; + Vector3d normal = N.col(e.i) * area1 + N.col(e.j) * area2; + double norm = normal.norm(); + N_p.col(i) = norm > RCPOVERFLOW ? Vector3d(normal / norm) : Vector3d::UnitX(); + A_p[i] = surfaceArea; + to_upper.col(i) << e.i, e.j; + to_lower[e.i] = i; + to_lower[e.j] = i; + } + + int offset = nCollapsed; + + for (int i = 0; i < V.cols(); ++i) { + if (!mergeFlag[i]) { + int idx = offset++; + V_p.col(idx) = V.col(i); + N_p.col(idx) = N.col(i); + A_p[idx] = A[i]; + to_upper.col(idx) << i, -1; + to_lower[i] = idx; + } + } + + adj_p.resize(V_p.cols()); + std::vector capacity(V_p.cols()); + std::vector> scratches(V_p.cols()); +#ifdef WITH_OMP +#pragma omp parallel for +#endif + for (int i = 0; i < V_p.cols(); ++i) { + int t = 0; + for (int j = 0; j < 2; ++j) { + int upper = to_upper(j, i); + if (upper == -1) continue; + t += adj[upper].size(); + } + scratches[i].reserve(t); + adj_p[i].reserve(t); + } +#ifdef WITH_OMP +#pragma omp parallel for +#endif + for (int i = 0; i < V_p.cols(); ++i) { + auto& scratch = scratches[i]; + for (int j = 0; j < 2; ++j) { + int upper = to_upper(j, i); + if (upper == -1) continue; + auto& ad = adj[upper]; + for (auto& link : ad) scratch.push_back(Link(to_lower[link.id], link.weight)); + } + std::sort(scratch.begin(), scratch.end()); + int id = -1; + auto& ad = adj_p[i]; + for (auto& link : scratch) { + if (link.id != i) { + if (id != link.id) { + ad.push_back(link); + id = link.id; + } else { + ad.back().weight += link.weight; + } + } + } + } +} + +void Hierarchy::SaveToFile(FILE* fp) { + Save(fp, mScale); + Save(fp, mF); + Save(fp, mE2E); + Save(fp, mAdj); + Save(fp, mV); + Save(fp, mN); + Save(fp, mA); + Save(fp, mToLower); + Save(fp, mToUpper); + Save(fp, mQ); + Save(fp, mO); + Save(fp, mS); + Save(fp, mK); + Save(fp, this->mPhases); +} + +void Hierarchy::LoadFromFile(FILE* fp) { + Read(fp, mScale); + Read(fp, mF); + Read(fp, mE2E); + Read(fp, mAdj); + Read(fp, mV); + Read(fp, mN); + Read(fp, mA); + Read(fp, mToLower); + Read(fp, mToUpper); + Read(fp, mQ); + Read(fp, mO); + Read(fp, mS); + Read(fp, mK); + Read(fp, this->mPhases); +} + +void Hierarchy::UpdateGraphValue(std::vector& FQ, std::vector& F2E, + std::vector& edge_diff) { + FQ = std::move(mFQ[0]); + F2E = std::move(mF2E[0]); + edge_diff = std::move(mEdgeDiff[0]); +} + +void Hierarchy::DownsampleEdgeGraph(std::vector& FQ, std::vector& F2E, + std::vector& edge_diff, + std::vector& allow_changes, int level) { + std::vector E2F(edge_diff.size(), Vector2i(-1, -1)); + for (int i = 0; i < F2E.size(); ++i) { + for (int j = 0; j < 3; ++j) { + int e = F2E[i][j]; + if (E2F[e][0] == -1) + E2F[e][0] = i; + else + E2F[e][1] = i; + } + } + int levels = (level == -1) ? 100 : level; + mFQ.resize(levels); + mF2E.resize(levels); + mE2F.resize(levels); + mEdgeDiff.resize(levels); + mAllowChanges.resize(levels); + mSing.resize(levels); + mToUpperEdges.resize(levels - 1); + mToUpperOrients.resize(levels - 1); + for (int i = 0; i < FQ.size(); ++i) { + Vector2i diff(0, 0); + for (int j = 0; j < 3; ++j) { + diff += rshift90(edge_diff[F2E[i][j]], FQ[i][j]); + } + if (diff != Vector2i::Zero()) { + mSing[0].push_back(i); + } + } + mAllowChanges[0] = allow_changes; + mFQ[0] = std::move(FQ); + mF2E[0] = std::move(F2E); + mE2F[0] = std::move(E2F); + mEdgeDiff[0] = std::move(edge_diff); + for (int l = 0; l < levels - 1; ++l) { + auto& FQ = mFQ[l]; + auto& E2F = mE2F[l]; + auto& F2E = mF2E[l]; + auto& Allow = mAllowChanges[l]; + auto& EdgeDiff = mEdgeDiff[l]; + auto& Sing = mSing[l]; + std::vector fixed_faces(F2E.size(), 0); + for (auto& s : Sing) { + fixed_faces[s] = 1; + } + + auto& toUpper = mToUpperEdges[l]; + auto& toUpperOrients = mToUpperOrients[l]; + toUpper.resize(E2F.size(), -1); + toUpperOrients.resize(E2F.size(), 0); + + auto& nFQ = mFQ[l + 1]; + auto& nE2F = mE2F[l + 1]; + auto& nF2E = mF2E[l + 1]; + auto& nAllow = mAllowChanges[l + 1]; + auto& nEdgeDiff = mEdgeDiff[l + 1]; + auto& nSing = mSing[l + 1]; + + for (int i = 0; i < E2F.size(); ++i) { + if (EdgeDiff[i] != Vector2i::Zero()) continue; + if ((E2F[i][0] >= 0 && fixed_faces[E2F[i][0]]) || + (E2F[i][1] >= 0 && fixed_faces[E2F[i][1]])) { + continue; + } + for (int j = 0; j < 2; ++j) { + int f = E2F[i][j]; + if (f < 0) + continue; + for (int k = 0; k < 3; ++k) { + int neighbor_e = F2E[f][k]; + for (int m = 0; m < 2; ++m) { + int neighbor_f = E2F[neighbor_e][m]; + if (neighbor_f < 0) + continue; + if (fixed_faces[neighbor_f] == 0) fixed_faces[neighbor_f] = 1; + } + } + } + if (E2F[i][0] >= 0) + fixed_faces[E2F[i][0]] = 2; + if (E2F[i][1] >= 0) + fixed_faces[E2F[i][1]] = 2; + toUpper[i] = -2; + } + for (int i = 0; i < E2F.size(); ++i) { + if (toUpper[i] == -2) continue; + if ((E2F[i][0] < 0 || fixed_faces[E2F[i][0]] == 2) && (E2F[i][1] < 0 || fixed_faces[E2F[i][1]] == 2)) { + toUpper[i] = -3; + continue; + } + } + int numE = 0; + for (int i = 0; i < toUpper.size(); ++i) { + if (toUpper[i] == -1) { + if ((E2F[i][0] < 0 || fixed_faces[E2F[i][0]] < 2) && (E2F[i][1] < 0 || fixed_faces[E2F[i][1]] < 2)) { + nE2F.push_back(E2F[i]); + toUpperOrients[i] = 0; + toUpper[i] = numE++; + continue; + } + int f0 = (E2F[i][1] < 0 || fixed_faces[E2F[i][0]] < 2) ? E2F[i][0] : E2F[i][1]; + int e = i; + int f = f0; + std::vector> paths; + paths.push_back(std::make_pair(i, 0)); + while (true) { + if (E2F[e][0] == f) + f = E2F[e][1]; + else if (E2F[e][1] == f) + f = E2F[e][0]; + if (f < 0 || fixed_faces[f] < 2) { + for (int j = 0; j < paths.size(); ++j) { + auto& p = paths[j]; + toUpper[p.first] = numE; + int orient = p.second; + if (j > 0) orient = (orient + toUpperOrients[paths[j - 1].first]) % 4; + toUpperOrients[p.first] = orient; + } + nE2F.push_back(Vector2i(f0, f)); + numE += 1; + break; + } + int ind0 = -1, ind1 = -1; + int e0 = e; + for (int j = 0; j < 3; ++j) { + if (F2E[f][j] == e) { + ind0 = j; + break; + } + } + for (int j = 0; j < 3; ++j) { + int e1 = F2E[f][j]; + if (e1 != e && toUpper[e1] != -2) { + e = e1; + ind1 = j; + break; + } + } + + if (ind1 != -1) { + paths.push_back(std::make_pair(e, (FQ[f][ind1] - FQ[f][ind0] + 6) % 4)); + } else { + if (EdgeDiff[e] != Vector2i::Zero()) { + printf("Unsatisfied !!!...\n"); + printf("%d %d %d: %d %d\n", F2E[f][0], F2E[f][1], F2E[f][2], e0, e); + exit(0); + } + for (auto& p : paths) { + toUpper[p.first] = numE; + toUpperOrients[p.first] = 0; + } + numE += 1; + nE2F.push_back(Vector2i(f0, f0)); + break; + } + } + } + } + nEdgeDiff.resize(numE); + nAllow.resize(numE * 2, 1); + for (int i = 0; i < toUpper.size(); ++i) { + if (toUpper[i] >= 0 && toUpperOrients[i] == 0) { + nEdgeDiff[toUpper[i]] = EdgeDiff[i]; + } + if (toUpper[i] >= 0) { + int dimension = toUpperOrients[i] % 2; + if (Allow[i * 2 + dimension] == 0) + nAllow[toUpper[i] * 2] = 0; + else if (Allow[i * 2 + dimension] == 2) + nAllow[toUpper[i] * 2] = 2; + if (Allow[i * 2 + 1 - dimension] == 0) + nAllow[toUpper[i] * 2 + 1] = 0; + else if (Allow[i * 2 + 1 - dimension] == 2) + nAllow[toUpper[i] * 2 + 1] = 2; + } + } + std::vector upperface(F2E.size(), -1); + + for (int i = 0; i < F2E.size(); ++i) { + Vector3i eid; + for (int j = 0; j < 3; ++j) { + eid[j] = toUpper[F2E[i][j]]; + } + if (eid[0] >= 0 && eid[1] >= 0 && eid[2] >= 0) { + Vector3i eid_orient; + for (int j = 0; j < 3; ++j) { + eid_orient[j] = (FQ[i][j] + 4 - toUpperOrients[F2E[i][j]]) % 4; + } + upperface[i] = nF2E.size(); + nF2E.push_back(eid); + nFQ.push_back(eid_orient); + } + } + for (int i = 0; i < nE2F.size(); ++i) { + for (int j = 0; j < 2; ++j) { + if (nE2F[i][j] >= 0) + nE2F[i][j] = upperface[nE2F[i][j]]; + } + } + + for (auto& s : Sing) { + if (upperface[s] >= 0) nSing.push_back(upperface[s]); + } + mToUpperFaces.push_back(std::move(upperface)); + + if (nEdgeDiff.size() == EdgeDiff.size()) { + levels = l + 1; + break; + } + } + + mFQ.resize(levels); + mF2E.resize(levels); + mAllowChanges.resize(levels); + mE2F.resize(levels); + mEdgeDiff.resize(levels); + mSing.resize(levels); + mToUpperEdges.resize(levels - 1); + mToUpperOrients.resize(levels - 1); +} + +int Hierarchy::FixFlipSat(int depth, int threshold) { + if (system("which minisat > /dev/null 2>&1")) { + printf("minisat not found, \"-sat\" will not be used!\n"); + return 0; + } + if (system("which timeout > /dev/null 2>&1")) { + printf("timeout not found, \"-sat\" will not be used!\n"); + return 0; + } + + auto& F2E = mF2E[depth]; + auto& E2F = mE2F[depth]; + auto& FQ = mFQ[depth]; + auto& EdgeDiff = mEdgeDiff[depth]; + auto& AllowChanges = mAllowChanges[depth]; + + // build E2E + std::vector E2E(F2E.size() * 3, -1); + for (int i = 0; i < E2F.size(); ++i) { + int f1 = E2F[i][0]; + int f2 = E2F[i][1]; + int t1 = 0; + int t2 = 2; + if (f1 != -1) while (F2E[f1][t1] != i) t1 += 1; + if (f2 != -1) while (F2E[f2][t2] != i) t2 -= 1; + t1 += f1 * 3; + t2 += f2 * 3; + if (f1 != -1) E2E[t1] = (f2 == -1) ? -1 : t2; + if (f2 != -1) E2E[t2] = (f1 == -1) ? -1 : t1; + } + + auto IntegerArea = [&](int f) { + Vector2i diff1 = rshift90(EdgeDiff[F2E[f][0]], FQ[f][0]); + Vector2i diff2 = rshift90(EdgeDiff[F2E[f][1]], FQ[f][1]); + return diff1[0] * diff2[1] - diff1[1] * diff2[0]; + }; + + std::deque> Q; + std::vector mark_dedges(F2E.size() * 3, false); + for (int f = 0; f < F2E.size(); ++f) { + if (IntegerArea(f) < 0) { + for (int j = 0; j < 3; ++j) { + if (mark_dedges[f * 3 + j]) continue; + Q.push_back(std::make_pair(f * 3 + j, 0)); + mark_dedges[f * 3 + j] = true; + } + } + } + + int mark_count = 0; + while (!Q.empty()) { + int e0 = Q.front().first; + int depth = Q.front().second; + Q.pop_front(); + mark_count++; + + int e = e0, e1; + do { + e1 = E2E[e]; + if (e1 == -1) break; + int length = EdgeDiff[F2E[e1 / 3][e1 % 3]].array().abs().sum(); + if (length == 0 && !mark_dedges[e1]) { + mark_dedges[e1] = true; + Q.push_front(std::make_pair(e1, depth)); + } + e = (e1 / 3) * 3 + (e1 + 1) % 3; + mark_dedges[e] = true; + } while (e != e0); + if (e1 == -1) { + do { + e1 = E2E[e]; + if (e1 == -1) break; + int length = EdgeDiff[F2E[e1 / 3][e1 % 3]].array().abs().sum(); + if (length == 0 && !mark_dedges[e1]) { + mark_dedges[e1] = true; + Q.push_front(std::make_pair(e1, depth)); + } + e = (e1 / 3) * 3 + (e1 + 2) % 3; + mark_dedges[e] = true; + } while (e != e0); + } + + do { + e1 = E2E[e]; + if (e1 == -1) break; + int length = EdgeDiff[F2E[e1 / 3][e1 % 3]].array().abs().sum(); + if (length > 0 && depth + length <= threshold && !mark_dedges[e1]) { + mark_dedges[e1] = true; + Q.push_back(std::make_pair(e1, depth + length)); + } + e = e1 / 3 * 3 + (e1 + 1) % 3; + mark_dedges[e] = true; + } while (e != e0); + if (e1 == -1) { + do { + e1 = E2E[e]; + if (e1 == -1) break; + int length = EdgeDiff[F2E[e1 / 3][e1 % 3]].array().abs().sum(); + if (length > 0 && depth + length <= threshold && !mark_dedges[e1]) { + mark_dedges[e1] = true; + Q.push_back(std::make_pair(e1, depth + length)); + } + e = e1 / 3 * 3 + (e1 + 2) % 3; + mark_dedges[e] = true; + } while (e != e0); + } + } + lprintf("[FlipH] Depth %2d: marked = %d\n", depth, mark_count); + + std::vector flexible(EdgeDiff.size(), false); + for (int i = 0; i < F2E.size(); ++i) { + for (int j = 0; j < 3; ++j) { + int dedge = i * 3 + j; + int edgeid = F2E[i][j]; + if (mark_dedges[dedge]) { + flexible[edgeid] = true; + } + } + } + for (int i = 0; i < flexible.size(); ++i) { + if (E2F[i][0] == E2F[i][1]) flexible[i] = false; + if (AllowChanges[i] == 0) flexible[i] = false; + } + + // Reindexing and solve + int num_group = 0; + std::vector groups(EdgeDiff.size(), -1); + std::vector indices(EdgeDiff.size(), -1); + for (int i = 0; i < EdgeDiff.size(); ++i) { + if (groups[i] == -1 && flexible[i]) { + // group it + std::queue q; + q.push(i); + groups[i] = num_group; + while (!q.empty()) { + int e = q.front(); + q.pop(); + int f[] = {E2F[e][0], E2F[e][1]}; + for (int j = 0; j < 2; ++j) { + if (f[j] == -1) continue; + for (int k = 0; k < 3; ++k) { + int e1 = F2E[f[j]][k]; + if (flexible[e1] && groups[e1] == -1) { + groups[e1] = num_group; + q.push(e1); + } + } + } + } + num_group += 1; + } + } + + std::vector num_edges(num_group); + std::vector num_flips(num_group); + std::vector> values(num_group); + std::vector> variable_eq(num_group); + std::vector> constant_eq(num_group); + std::vector> variable_ge(num_group); + std::vector> constant_ge(num_group); + for (int i = 0; i < groups.size(); ++i) { + if (groups[i] != -1) { + indices[i] = num_edges[groups[i]]++; + values[groups[i]].push_back(EdgeDiff[i][0]); + values[groups[i]].push_back(EdgeDiff[i][1]); + } + } + std::vector num_edges_flexible = num_edges; + std::map, int> fixed_variables; + for (int i = 0; i < F2E.size(); ++i) { + Vector2i var[3]; + Vector2i cst[3]; + int gind = 0; + while (gind < 3 && groups[F2E[i][gind]] == -1) gind += 1; + if (gind == 3) continue; + int group = groups[F2E[i][gind]]; + int ind[3] = {-1, -1, -1}; + for (int j = 0; j < 3; ++j) { + int g = groups[F2E[i][j]]; + if (g != group) { + if (g == -1) { + auto key = std::make_pair(F2E[i][j], group); + auto it = fixed_variables.find(key); + if (it == fixed_variables.end()) { + ind[j] = num_edges[group]; + values[group].push_back(EdgeDiff[F2E[i][j]][0]); + values[group].push_back(EdgeDiff[F2E[i][j]][1]); + fixed_variables[key] = num_edges[group]++; + } else { + ind[j] = it->second; + } + } + } else { + ind[j] = indices[F2E[i][j]]; + } + } + for (int j = 0; j < 3; ++j) assert(ind[j] != -1); + for (int j = 0; j < 3; ++j) { + var[j] = rshift90(Vector2i(ind[j] * 2 + 1, ind[j] * 2 + 2), FQ[i][j]); + cst[j] = var[j].array().sign(); + var[j] = var[j].array().abs() - 1; + } + + num_flips[group] += IntegerArea(i) < 0; + variable_eq[group].push_back(Vector3i(var[0][0], var[1][0], var[2][0])); + constant_eq[group].push_back(Vector3i(cst[0][0], cst[1][0], cst[2][0])); + variable_eq[group].push_back(Vector3i(var[0][1], var[1][1], var[2][1])); + constant_eq[group].push_back(Vector3i(cst[0][1], cst[1][1], cst[2][1])); + + variable_ge[group].push_back(Vector4i(var[0][0], var[1][1], var[0][1], var[1][0])); + constant_ge[group].push_back(Vector2i(cst[0][0] * cst[1][1], cst[0][1] * cst[1][0])); + } + int flip_before = 0, flip_after = 0; + for (int i = 0; i < F2E.size(); ++i) { + int area = IntegerArea(i); + if (area < 0) flip_before++; + } + + for (int i = 0; i < num_group; ++i) { + std::vector flexible(values[i].size(), true); + for (int j = num_edges_flexible[i] * 2; j < flexible.size(); ++j) { + flexible[j] = false; + } + SolveSatProblem(values[i].size(), values[i], flexible, variable_eq[i], constant_eq[i], + variable_ge[i], constant_ge[i]); + } + + for (int i = 0; i < EdgeDiff.size(); ++i) { + int group = groups[i]; + if (group == -1) continue; + EdgeDiff[i][0] = values[group][2 * indices[i] + 0]; + EdgeDiff[i][1] = values[group][2 * indices[i] + 1]; + } + for (int i = 0; i < F2E.size(); ++i) { + Vector2i diff(0, 0); + for (int j = 0; j < 3; ++j) { + diff += rshift90(EdgeDiff[F2E[i][j]], FQ[i][j]); + } + assert(diff == Vector2i::Zero()); + + int area = IntegerArea(i); + if (area < 0) flip_after++; + } + + lprintf("[FlipH] FlipArea, Before: %d After %d\n", flip_before, flip_after); + return flip_after; +} + +void Hierarchy::PushDownwardFlip(int depth) { + auto& EdgeDiff = mEdgeDiff[depth]; + auto& nEdgeDiff = mEdgeDiff[depth - 1]; + auto& toUpper = mToUpperEdges[depth - 1]; + auto& toUpperOrients = mToUpperOrients[depth - 1]; + auto& toUpperFaces = mToUpperFaces[depth - 1]; + for (int i = 0; i < toUpper.size(); ++i) { + if (toUpper[i] >= 0) { + int orient = (4 - toUpperOrients[i]) % 4; + nEdgeDiff[i] = rshift90(EdgeDiff[toUpper[i]], orient); + } else { + nEdgeDiff[i] = Vector2i(0, 0); + } + } + auto& nF2E = mF2E[depth - 1]; + auto& nFQ = mFQ[depth - 1]; + for (int i = 0; i < nF2E.size(); ++i) { + Vector2i diff(0, 0); + for (int j = 0; j < 3; ++j) { + diff += rshift90(nEdgeDiff[nF2E[i][j]], nFQ[i][j]); + } + if (diff != Vector2i::Zero()) { + printf("Fail!!!!!!! %d\n", i); + for (int j = 0; j < 3; ++j) { + Vector2i d = rshift90(nEdgeDiff[nF2E[i][j]], nFQ[i][j]); + printf("<%d %d %d>\n", nF2E[i][j], nFQ[i][j], toUpperOrients[nF2E[i][j]]); + printf("%d %d\n", d[0], d[1]); + printf("%d -> %d\n", nF2E[i][j], toUpper[nF2E[i][j]]); + } + printf("%d -> %d\n", i, toUpperFaces[i]); + exit(1); + } + } +} + +void Hierarchy::FixFlip() { + int l = mF2E.size() - 1; + auto& F2E = mF2E[l]; + auto& E2F = mE2F[l]; + auto& FQ = mFQ[l]; + auto& EdgeDiff = mEdgeDiff[l]; + auto& AllowChange = mAllowChanges[l]; + + // build E2E + std::vector E2E(F2E.size() * 3, -1); + for (int i = 0; i < E2F.size(); ++i) { + int v1 = E2F[i][0]; + int v2 = E2F[i][1]; + int t1 = 0; + int t2 = 2; + if (v1 != -1) + while (F2E[v1][t1] != i) t1 += 1; + if (v2 != -1) + while (F2E[v2][t2] != i) t2 -= 1; + t1 += v1 * 3; + t2 += v2 * 3; + if (v1 != -1) + E2E[t1] = (v2 == -1) ? -1 : t2; + if (v2 != -1) + E2E[t2] = (v1 == -1) ? -1 : t1; + } + + auto Area = [&](int f) { + Vector2i diff1 = rshift90(EdgeDiff[F2E[f][0]], FQ[f][0]); + Vector2i diff2 = rshift90(EdgeDiff[F2E[f][1]], FQ[f][1]); + return diff1[0] * diff2[1] - diff1[1] * diff2[0]; + }; + std::vector valences(F2E.size() * 3, -10000); // comment this line + auto CheckShrink = [&](int deid, int allowed_edge_length) { + // Check if we want shrink direct edge deid so that all edge length is smaller than + // allowed_edge_length + if (deid == -1) { + return false; + } + std::vector corresponding_faces; + std::vector corresponding_edges; + std::vector corresponding_diff; + int deid0 = deid; + while (deid != -1) { + deid = deid / 3 * 3 + (deid + 2) % 3; + if (E2E[deid] == -1) + break; + deid = E2E[deid]; + if (deid == deid0) + break; + } + Vector2i diff = EdgeDiff[F2E[deid / 3][deid % 3]]; + do { + corresponding_diff.push_back(diff); + corresponding_edges.push_back(deid); + corresponding_faces.push_back(deid / 3); + + // transform to the next face + deid = E2E[deid]; + if (deid == -1) { + return false; + } + // transform for the target incremental diff + diff = -rshift90(diff, FQ[deid / 3][deid % 3]); + deid = deid / 3 * 3 + (deid + 1) % 3; + // transform to local + diff = rshift90(diff, (4 - FQ[deid / 3][deid % 3]) % 4); + } while (deid != corresponding_edges.front()); + // check diff + if (deid != -1 && diff != corresponding_diff.front()) { + return false; + } + std::unordered_map new_values; + for (int i = 0; i < corresponding_diff.size(); ++i) { + int deid = corresponding_edges[i]; + int eid = F2E[deid / 3][deid % 3]; + new_values[eid] = EdgeDiff[eid]; + } + for (int i = 0; i < corresponding_diff.size(); ++i) { + int deid = corresponding_edges[i]; + int eid = F2E[deid / 3][deid % 3]; + for (int j = 0; j < 2; ++j) { + if (corresponding_diff[i][j] != 0 && AllowChange[eid * 2 + j] == 0) return false; + } + auto& res = new_values[eid]; + res -= corresponding_diff[i]; + int edge_thres = allowed_edge_length; + if (abs(res[0]) > edge_thres || abs(res[1]) > edge_thres) { + return false; + } + if ((abs(res[0]) > 1 && abs(res[1]) != 0) || (abs(res[1]) > 1 && abs(res[0]) != 0)) + return false; + } + int prev_area = 0, current_area = 0; + for (int f = 0; f < corresponding_faces.size(); ++f) { + int area = Area(corresponding_faces[f]); + if (area < 0) prev_area += 1; + } + for (auto& p : new_values) { + std::swap(EdgeDiff[p.first], p.second); + } + for (int f = 0; f < corresponding_faces.size(); ++f) { + int area = Area(corresponding_faces[f]); + if (area < 0) { + current_area += 1; + } + } + if (current_area < prev_area) { + return true; + } + for (auto& p : new_values) { + std::swap(EdgeDiff[p.first], p.second); + } + return false; + }; + + std::queue flipped; + for (int i = 0; i < F2E.size(); ++i) { + int area = Area(i); + if (area < 0) { + flipped.push(i); + } + } + + bool update = false; + int max_len = 1; + while (!update && max_len <= 2) { + while (!flipped.empty()) { + int f = flipped.front(); + if (Area(f) >= 0) { + flipped.pop(); + continue; + } + for (int i = 0; i < 3; ++i) { + if (CheckShrink(f * 3 + i, max_len) || CheckShrink(E2E[f * 3 + i], max_len)) { + update = true; + break; + } + } + flipped.pop(); + } + max_len += 1; + } + if (update) { + Hierarchy flip_hierarchy; + flip_hierarchy.DownsampleEdgeGraph(mFQ.back(), mF2E.back(), mEdgeDiff.back(), + mAllowChanges.back(), -1); + flip_hierarchy.FixFlip(); + flip_hierarchy.UpdateGraphValue(mFQ.back(), mF2E.back(), mEdgeDiff.back()); + } + PropagateEdge(); +} + +void Hierarchy::PropagateEdge() { + for (int level = mToUpperEdges.size(); level > 0; --level) { + auto& EdgeDiff = mEdgeDiff[level]; + auto& nEdgeDiff = mEdgeDiff[level - 1]; + auto& FQ = mFQ[level]; + auto& nFQ = mFQ[level - 1]; + auto& F2E = mF2E[level - 1]; + auto& toUpper = mToUpperEdges[level - 1]; + auto& toUpperFace = mToUpperFaces[level - 1]; + auto& toUpperOrients = mToUpperOrients[level - 1]; + for (int i = 0; i < toUpper.size(); ++i) { + if (toUpper[i] >= 0) { + int orient = (4 - toUpperOrients[i]) % 4; + nEdgeDiff[i] = rshift90(EdgeDiff[toUpper[i]], orient); + } else { + nEdgeDiff[i] = Vector2i(0, 0); + } + } + for (int i = 0; i < toUpperFace.size(); ++i) { + if (toUpperFace[i] == -1) continue; + Vector3i eid_orient = FQ[toUpperFace[i]]; + for (int j = 0; j < 3; ++j) { + nFQ[i][j] = (eid_orient[j] + toUpperOrients[F2E[i][j]]) % 4; + } + } + } +} + +void Hierarchy::clearConstraints() { + int levels = mV.size(); + if (levels == 0) return; + for (int i = 0; i < levels; ++i) { + int size = mV[i].cols(); + mCQ[i].resize(3, size); + mCO[i].resize(3, size); + mCQw[i].resize(size); + mCOw[i].resize(size); + mCQw[i].setZero(); + mCOw[i].setZero(); + } +} + +void Hierarchy::propagateConstraints() { + int levels = mV.size(); + if (levels == 0) return; + + for (int l = 0; l < levels - 1; ++l) { + auto& N = mN[l]; + auto& N_next = mN[l + 1]; + auto& V = mV[l]; + auto& V_next = mV[l + 1]; + auto& CQ = mCQ[l]; + auto& CQ_next = mCQ[l + 1]; + auto& CQw = mCQw[l]; + auto& CQw_next = mCQw[l + 1]; + auto& CO = mCO[l]; + auto& CO_next = mCO[l + 1]; + auto& COw = mCOw[l]; + auto& COw_next = mCOw[l + 1]; + auto& toUpper = mToUpper[l]; + MatrixXd& S = mS[l]; + + for (uint32_t i = 0; i != mV[l + 1].cols(); ++i) { + Vector2i upper = toUpper.col(i); + Vector3d cq = Vector3d::Zero(), co = Vector3d::Zero(); + float cqw = 0.0f, cow = 0.0f; + + bool has_cq0 = CQw[upper[0]] != 0; + bool has_cq1 = upper[1] != -1 && CQw[upper[1]] != 0; + bool has_co0 = COw[upper[0]] != 0; + bool has_co1 = upper[1] != -1 && COw[upper[1]] != 0; + + if (has_cq0 && !has_cq1) { + cq = CQ.col(upper[0]); + cqw = CQw[upper[0]]; + } else if (has_cq1 && !has_cq0) { + cq = CQ.col(upper[1]); + cqw = CQw[upper[1]]; + } else if (has_cq1 && has_cq0) { + Vector3d q_i = CQ.col(upper[0]); + Vector3d n_i = CQ.col(upper[0]); + Vector3d q_j = CQ.col(upper[1]); + Vector3d n_j = CQ.col(upper[1]); + auto result = compat_orientation_extrinsic_4(q_i, n_i, q_j, n_j); + cq = result.first * CQw[upper[0]] + result.second * CQw[upper[1]]; + cqw = (CQw[upper[0]] + CQw[upper[1]]); + } + if (cq != Vector3d::Zero()) { + Vector3d n = N_next.col(i); + cq -= n.dot(cq) * n; + if (cq.squaredNorm() > RCPOVERFLOW) cq.normalize(); + } + + if (has_co0 && !has_co1) { + co = CO.col(upper[0]); + cow = COw[upper[0]]; + } else if (has_co1 && !has_co0) { + co = CO.col(upper[1]); + cow = COw[upper[1]]; + } else if (has_co1 && has_co0) { + double scale_x = mScale; + double scale_y = mScale; + if (with_scale) { + // FIXME + // scale_x *= S(0, i); + // scale_y *= S(1, i); + } + double inv_scale_x = 1.0f / scale_x; + double inv_scale_y = 1.0f / scale_y; + + double scale_x_1 = mScale; + double scale_y_1 = mScale; + if (with_scale) { + // FIXME + // scale_x_1 *= S(0, j); + // scale_y_1 *= S(1, j); + } + double inv_scale_x_1 = 1.0f / scale_x_1; + double inv_scale_y_1 = 1.0f / scale_y_1; + auto result = compat_position_extrinsic_4( + V.col(upper[0]), N.col(upper[0]), CQ.col(upper[0]), CO.col(upper[0]), + V.col(upper[1]), N.col(upper[1]), CQ.col(upper[1]), CO.col(upper[1]), scale_x, + scale_y, inv_scale_x, inv_scale_y, scale_x_1, scale_y_1, inv_scale_x_1, + inv_scale_y_1); + cow = COw[upper[0]] + COw[upper[1]]; + co = (result.first * COw[upper[0]] + result.second * COw[upper[1]]) / cow; + } + if (co != Vector3d::Zero()) { + Vector3d n = N_next.col(i), v = V_next.col(i); + co -= n.dot(cq - v) * n; + } +#if 0 + cqw *= 0.5f; + cow *= 0.5f; +#else + if (cqw > 0) cqw = 1; + if (cow > 0) cow = 1; +#endif + + CQw_next[i] = cqw; + COw_next[i] = cow; + CQ_next.col(i) = cq; + CO_next.col(i) = co; + } + } +} +#ifdef WITH_CUDA +#include + +void Hierarchy::CopyToDevice() { + if (cudaAdj.empty()) { + cudaAdj.resize(mAdj.size()); + cudaAdjOffset.resize(mAdj.size()); + for (int i = 0; i < mAdj.size(); ++i) { + std::vector offset(mAdj[i].size() + 1, 0); + for (int j = 0; j < mAdj[i].size(); ++j) { + offset[j + 1] = offset[j] + mAdj[i][j].size(); + } + cudaMalloc(&cudaAdjOffset[i], sizeof(int) * (mAdj[i].size() + 1)); + cudaMemcpy(cudaAdjOffset[i], offset.data(), sizeof(int) * (mAdj[i].size() + 1), + cudaMemcpyHostToDevice); + // cudaAdjOffset[i] = (int*)malloc(sizeof(int) * (mAdj[i].size() + 1)); + // memcpy(cudaAdjOffset[i], offset.data(), sizeof(int) * (mAdj[i].size() + + // 1)); + + cudaMalloc(&cudaAdj[i], sizeof(Link) * offset.back()); + // cudaAdj[i] = (Link*)malloc(sizeof(Link) * offset.back()); + std::vector plainlink(offset.back()); + for (int j = 0; j < mAdj[i].size(); ++j) { + memcpy(plainlink.data() + offset[j], mAdj[i][j].data(), + mAdj[i][j].size() * sizeof(Link)); + } + cudaMemcpy(cudaAdj[i], plainlink.data(), plainlink.size() * sizeof(Link), + cudaMemcpyHostToDevice); + } + } + + if (cudaN.empty()) { + cudaN.resize(mN.size()); + for (int i = 0; i < mN.size(); ++i) { + cudaMalloc(&cudaN[i], sizeof(glm::dvec3) * mN[i].cols()); + // cudaN[i] = (glm::dvec3*)malloc(sizeof(glm::dvec3) * mN[i].cols()); + } + } + for (int i = 0; i < mN.size(); ++i) { + cudaMemcpy(cudaN[i], mN[i].data(), sizeof(glm::dvec3) * mN[i].cols(), + cudaMemcpyHostToDevice); + // memcpy(cudaN[i], mN[i].data(), sizeof(glm::dvec3) * mN[i].cols()); + } + + if (cudaV.empty()) { + cudaV.resize(mV.size()); + for (int i = 0; i < mV.size(); ++i) { + cudaMalloc(&cudaV[i], sizeof(glm::dvec3) * mV[i].cols()); + // cudaV[i] = (glm::dvec3*)malloc(sizeof(glm::dvec3) * mV[i].cols()); + } + } + for (int i = 0; i < mV.size(); ++i) { + cudaMemcpy(cudaV[i], mV[i].data(), sizeof(glm::dvec3) * mV[i].cols(), + cudaMemcpyHostToDevice); + // memcpy(cudaV[i], mV[i].data(), sizeof(glm::dvec3) * mV[i].cols()); + } + + if (cudaQ.empty()) { + cudaQ.resize(mQ.size()); + for (int i = 0; i < mQ.size(); ++i) { + cudaMalloc(&cudaQ[i], sizeof(glm::dvec3) * mQ[i].cols()); + // cudaQ[i] = (glm::dvec3*)malloc(sizeof(glm::dvec3) * mQ[i].cols()); + } + } + for (int i = 0; i < mQ.size(); ++i) { + cudaMemcpy(cudaQ[i], mQ[i].data(), sizeof(glm::dvec3) * mQ[i].cols(), + cudaMemcpyHostToDevice); + // memcpy(cudaQ[i], mQ[i].data(), sizeof(glm::dvec3) * mQ[i].cols()); + } + if (cudaO.empty()) { + cudaO.resize(mO.size()); + for (int i = 0; i < mO.size(); ++i) { + cudaMalloc(&cudaO[i], sizeof(glm::dvec3) * mO[i].cols()); + // cudaO[i] = (glm::dvec3*)malloc(sizeof(glm::dvec3) * mO[i].cols()); + } + } + for (int i = 0; i < mO.size(); ++i) { + cudaMemcpy(cudaO[i], mO[i].data(), sizeof(glm::dvec3) * mO[i].cols(), + cudaMemcpyHostToDevice); + // memcpy(cudaO[i], mO[i].data(), sizeof(glm::dvec3) * mO[i].cols()); + } + if (cudaPhases.empty()) { + cudaPhases.resize(mPhases.size()); + for (int i = 0; i < mPhases.size(); ++i) { + cudaPhases[i].resize(mPhases[i].size()); + for (int j = 0; j < mPhases[i].size(); ++j) { + cudaMalloc(&cudaPhases[i][j], sizeof(int) * mPhases[i][j].size()); + // cudaPhases[i][j] = (int*)malloc(sizeof(int) * + // mPhases[i][j].size()); + } + } + } + for (int i = 0; i < mPhases.size(); ++i) { + for (int j = 0; j < mPhases[i].size(); ++j) { + cudaMemcpy(cudaPhases[i][j], mPhases[i][j].data(), sizeof(int) * mPhases[i][j].size(), + cudaMemcpyHostToDevice); + // memcpy(cudaPhases[i][j], mPhases[i][j].data(), sizeof(int) * + // mPhases[i][j].size()); + } + } + if (cudaToUpper.empty()) { + cudaToUpper.resize(mToUpper.size()); + for (int i = 0; i < mToUpper.size(); ++i) { + cudaMalloc(&cudaToUpper[i], mToUpper[i].cols() * sizeof(glm::ivec2)); + // cudaToUpper[i] = (glm::ivec2*)malloc(mToUpper[i].cols() * + // sizeof(glm::ivec2)); + } + } + for (int i = 0; i < mToUpper.size(); ++i) { + cudaMemcpy(cudaToUpper[i], mToUpper[i].data(), sizeof(glm::ivec2) * mToUpper[i].cols(), + cudaMemcpyHostToDevice); + // memcpy(cudaToUpper[i], mToUpper[i].data(), sizeof(glm::ivec2) * + // mToUpper[i].cols()); + } + cudaDeviceSynchronize(); +} + +void Hierarchy::CopyToHost() {} + +#endif + +} // namespace qflow diff --git a/extern/quadriflow/src/hierarchy.hpp b/extern/quadriflow/src/hierarchy.hpp new file mode 100644 index 00000000000..8403038de4f --- /dev/null +++ b/extern/quadriflow/src/hierarchy.hpp @@ -0,0 +1,99 @@ +#ifndef HIERARCHY_H_ +#define HIERARCHY_H_ + +#ifdef WITH_CUDA +# include +#endif + +#include +#include +#include "adjacent-matrix.hpp" +#include "config.hpp" +#include "serialize.hpp" +#define RCPOVERFLOW 2.93873587705571876e-39f + +using namespace Eigen; + +namespace qflow { + +class Hierarchy { + public: + Hierarchy(); + void Initialize(double scale, int with_scale = 0); + void DownsampleGraph(const AdjacentMatrix adj, const MatrixXd& V, const MatrixXd& N, + const VectorXd& A, MatrixXd& V_p, MatrixXd& N_p, VectorXd& A_p, + MatrixXi& to_upper, VectorXi& to_lower, AdjacentMatrix& adj_p); + void generate_graph_coloring_deterministic(const AdjacentMatrix& adj, int size, + std::vector>& phases); + void FixFlip(); + int FixFlipSat(int depth, int threshold = 0); + void PushDownwardFlip(int depth); + void PropagateEdge(); + void DownsampleEdgeGraph(std::vector& FQ, std::vector& F2E, + std::vector& edge_diff, + std::vector& allow_changes, int level); + void UpdateGraphValue(std::vector& FQ, std::vector& F2E, + std::vector& edge_diff); + + enum { MAX_DEPTH = 25 }; + + void SaveToFile(FILE* fp); + void LoadFromFile(FILE* fp); + + void clearConstraints(); + void propagateConstraints(); + + double mScale; + int rng_seed; + + MatrixXi mF; // mF(i, j) i \in [0, 3) ith index in face j + VectorXi mE2E; // inverse edge + std::vector mAdj; + std::vector mV; + std::vector mN; + std::vector mA; + std::vector>> mPhases; + // parameters + std::vector mQ; + std::vector mO; + std::vector mToLower; + std::vector mToUpper; // mToUpper[h](i, j) \in V; i \in [0, 2); j \in V + std::vector mS; + std::vector mK; + + // constraints + std::vector mCQ; + std::vector mCO; + std::vector mCQw; + std::vector mCOw; + + int with_scale; + + // upper: fine to coarse + std::vector> mToUpperFaces; // face correspondance + std::vector> mSing; + std::vector> mToUpperEdges; // edge correspondance + std::vector> mToUpperOrients; // rotation of edges from fine to coarse + std::vector> mFQ; // face_edgeOrients + std::vector> mF2E; // face_edgeIds + std::vector> mE2F; // undirect edges to face ID + std::vector > mAllowChanges; + std::vector> mEdgeDiff; // face_edgeDiff + +#ifdef WITH_CUDA + std::vector cudaAdj; + std::vector cudaAdjOffset; + std::vector cudaN; + std::vector cudaV; + std::vector cudaQ; + std::vector cudaO; + std::vector> cudaPhases; + std::vector cudaToUpper; + void CopyToDevice(); + void CopyToHost(); +#endif +}; + +} // namespace qflow + +#endif diff --git a/extern/quadriflow/src/loader.cpp b/extern/quadriflow/src/loader.cpp new file mode 100644 index 00000000000..aa27066e6e4 --- /dev/null +++ b/extern/quadriflow/src/loader.cpp @@ -0,0 +1,159 @@ +// +// loader.cpp +// Loop +// +// Created by Jingwei on 10/22/17. +// Copyright © 2017 Jingwei. All rights reserved. +// + +#include "loader.hpp" + +#include +#include + +namespace qflow { + +inline std::vector &str_tokenize(const std::string &s, char delim, std::vector &elems, bool include_empty = false) { + std::stringstream ss(s); + std::string item; + while (std::getline(ss, item, delim)) + if (!item.empty() || include_empty) + elems.push_back(item); + return elems; +} + +inline std::vector str_tokenize(const std::string &s, char delim, bool include_empty) { + std::vector elems; + str_tokenize(s, delim, elems, include_empty); + return elems; +} + +inline uint32_t str_to_uint32_t(const std::string &str) { + char *end_ptr = nullptr; + uint32_t result = (uint32_t)strtoul(str.c_str(), &end_ptr, 10); + if (*end_ptr != '\0') + throw std::runtime_error("Could not parse unsigned integer \"" + str + "\""); + return result; +} + +void load(const char* filename, MatrixXd& V, MatrixXi& F) +{ + /// Vertex indices used by the OBJ format + struct obj_vertex { + uint32_t p = (uint32_t)-1; + uint32_t n = (uint32_t)-1; + uint32_t uv = (uint32_t)-1; + + inline obj_vertex() { } + + inline obj_vertex(const std::string &string) { + std::vector tokens = str_tokenize(string, '/', true); + + if (tokens.size() < 1 || tokens.size() > 3) + throw std::runtime_error("Invalid vertex data: \"" + string + "\""); + + p = str_to_uint32_t(tokens[0]); + +#if 0 + if (tokens.size() >= 2 && !tokens[1].empty()) + uv = str_to_uint32_t(tokens[1]); + + if (tokens.size() >= 3 && !tokens[2].empty()) + n = str_to_uint32_t(tokens[2]); +#endif + } + + inline bool operator==(const obj_vertex &v) const { + return v.p == p && v.n == n && v.uv == uv; + } + }; + + /// Hash function for obj_vertex + struct obj_vertexHash : std::unary_function { + std::size_t operator()(const obj_vertex &v) const { + size_t hash = std::hash()(v.p); + hash = hash * 37 + std::hash()(v.uv); + hash = hash * 37 + std::hash()(v.n); + return hash; + } + }; + + typedef std::unordered_map VertexMap; + + std::ifstream is(filename); + + std::vector positions; + //std::vector texcoords; + //std::vector normals; + std::vector indices; + std::vector vertices; + VertexMap vertexMap; + + std::string line_str; + while (std::getline(is, line_str)) { + std::istringstream line(line_str); + + std::string prefix; + line >> prefix; + + if (prefix == "v") { + Vector3d p; + line >> p.x() >> p.y() >> p.z(); + positions.push_back(p); + } + else if (prefix == "vt") { + /* + Vector2d tc; + line >> tc.x() >> tc.y(); + texcoords.push_back(tc); + */ + } + else if (prefix == "vn") { + /* + Vector3d n; + line >> n.x() >> n.y() >> n.z(); + normals.push_back(n); + */ + } + else if (prefix == "f") { + std::string v1, v2, v3, v4; + line >> v1 >> v2 >> v3 >> v4; + obj_vertex tri[6]; + int nVertices = 3; + + tri[0] = obj_vertex(v1); + tri[1] = obj_vertex(v2); + tri[2] = obj_vertex(v3); + + if (!v4.empty()) { + /* This is a quad, split into two triangles */ + tri[3] = obj_vertex(v4); + tri[4] = tri[0]; + tri[5] = tri[2]; + nVertices = 6; + } + /* Convert to an indexed vertex list */ + for (int i = 0; isecond); + } + } + } + } + + F.resize(3, indices.size() / 3); + memcpy(F.data(), indices.data(), sizeof(uint32_t)*indices.size()); + + V.resize(3, vertices.size()); + for (uint32_t i = 0; i +#include + +namespace qflow { + +using namespace Eigen; + +void load(const char* filename, MatrixXd& V, MatrixXi& F); + +} // namespace qflow + +#endif diff --git a/extern/quadriflow/src/localsat.cpp b/extern/quadriflow/src/localsat.cpp new file mode 100644 index 00000000000..1ab665175da --- /dev/null +++ b/extern/quadriflow/src/localsat.cpp @@ -0,0 +1,295 @@ +#ifdef NDEBUG +#undef NDEBUG +#endif + +#include "localsat.hpp" +#include "config.hpp" +#include "dedge.hpp" +#include "field-math.hpp" + +#include + +#include +#include +#include +#include + +namespace qflow { + +const int max_depth = 0; + +using namespace Eigen; + +SolverStatus RunCNF(const std::string &fin_name, int n_variable, int timeout, + const std::vector> &sat_clause, std::vector &value) { + int n_sat_variable = 3 * n_variable; + auto fout_name = fin_name + ".result.txt"; + + FILE *fout = fopen(fin_name.c_str(), "w"); + fprintf(fout, "p cnf %d %d\n", n_sat_variable, (int)sat_clause.size()); + for (auto &c : sat_clause) { + for (auto e : c) fprintf(fout, "%d ", e); + fputs("0\n", fout); + } + fclose(fout); + + char cmd[100]; + snprintf(cmd, 99, "rm %s > /dev/null 2>&1", fout_name.c_str()); + system(cmd); + snprintf(cmd, 99, "timeout %d minisat %s %s > /dev/null 2>&1", timeout, fin_name.c_str(), + fout_name.c_str()); + int exit_code = system(cmd); + + FILE *fin = fopen(fout_name.c_str(), "r"); + char buf[16] = {0}; + fscanf(fin, "%15s", buf); + lprintf(" MiniSAT:"); + if (strcmp(buf, "SAT") != 0) { + fclose(fin); + + if (exit_code == 124) { + lprintf(" Timeout! "); + return SolverStatus::Timeout; + } + lprintf(" Unsatisfiable! "); + return SolverStatus::Unsat; + }; + + lprintf(" Satisfiable! "); + for (int i = 0; i < n_variable; ++i) { + int sign[3]; + fscanf(fin, "%d %d %d", sign + 0, sign + 1, sign + 2); + + int nvalue = -2; + for (int j = 0; j < 3; ++j) { + assert(abs(sign[j]) == 3 * i + j + 1); + if ((sign[j] > 0) == (value[i] != j - 1)) { + assert(nvalue == -2); + nvalue = j - 1; + } + } + value[i] = nvalue; + } + fclose(fin); + + return SolverStatus::Sat; +} + +SolverStatus SolveSatProblem(int n_variable, std::vector &value, + const std::vector flexible, // NOQA + const std::vector &variable_eq, + const std::vector &constant_eq, + const std::vector &variable_ge, + const std::vector &constant_ge, + int timeout) { + for (int v : value) assert(-1 <= v && v <= +1); + + auto VAR = [&](int i, int v) { + int index = 1 + 3 * i + v + 1; + // We initialize the SAT problem by setting all the variable to false. + // This is because minisat by default will try false first. + if (v == value[i]) index = -index; + return index; + }; + + int n_flexible = 0; + std::vector> sat_clause; + std::vector sat_ishard; + + auto add_clause = [&](const std::vector &clause, bool hard) { + sat_clause.push_back(clause); + sat_ishard.push_back(hard); + }; + + for (int i = 0; i < n_variable; ++i) { + add_clause({-VAR(i, -1), -VAR(i, 0)}, true); + add_clause({-VAR(i, +1), -VAR(i, 0)}, true); + add_clause({-VAR(i, -1), -VAR(i, +1)}, true); + add_clause({VAR(i, -1), VAR(i, 0), VAR(i, +1)}, true); + if (!flexible[i]) { + add_clause({VAR(i, value[i])}, true); + } else { + ++n_flexible; + } + } + + for (int i = 0; i < (int)variable_eq.size(); ++i) { + auto &var = variable_eq[i]; + auto &cst = constant_eq[i]; + for (int v0 = -1; v0 <= 1; ++v0) + for (int v1 = -1; v1 <= 1; ++v1) + for (int v2 = -1; v2 <= 1; ++v2) + if (cst[0] * v0 + cst[1] * v1 + cst[2] * v2 != 0) { + add_clause({-VAR(var[0], v0), -VAR(var[1], v1), -VAR(var[2], v2)}, true); + } + } + + for (int i = 0; i < (int)variable_ge.size(); ++i) { + auto &var = variable_ge[i]; + auto &cst = constant_ge[i]; + for (int v0 = -1; v0 <= 1; ++v0) + for (int v1 = -1; v1 <= 1; ++v1) + for (int v2 = -1; v2 <= 1; ++v2) + for (int v3 = -1; v3 <= 1; ++v3) + if (cst[0] * v0 * v1 - cst[1] * v2 * v3 < 0) { + add_clause({-VAR(var[0], v0), -VAR(var[1], v1), -VAR(var[2], v2), + -VAR(var[3], v3)}, + false); + } + } + + int nflip_before = 0, nflip_after = 0; + for (int i = 0; i < (int)variable_ge.size(); ++i) { + auto &var = variable_ge[i]; + auto &cst = constant_ge[i]; + if (value[var[0]] * value[var[1]] * cst[0] - value[var[2]] * value[var[3]] * cst[1] < 0) + nflip_before++; + } + + lprintf(" [SAT] nvar: %6d nflip: %3d ", n_flexible * 2, nflip_before); + auto rcnf = RunCNF("test.out", n_variable, timeout, sat_clause, value); + + for (int i = 0; i < (int)variable_eq.size(); ++i) { + auto &var = variable_eq[i]; + auto &cst = constant_eq[i]; + assert(cst[0] * value[var[0]] + cst[1] * value[var[1]] + cst[2] * value[var[2]] == 0); + } + for (int i = 0; i < (int)variable_ge.size(); ++i) { + auto &var = variable_ge[i]; + auto &cst = constant_ge[i]; + int area = value[var[0]] * value[var[1]] * cst[0] - value[var[2]] * value[var[3]] * cst[1]; + if (area < 0) ++nflip_after; + } + lprintf("nflip: %3d\n", nflip_after); + return rcnf; +} + +void ExportLocalSat(std::vector &edge_diff, const std::vector &face_edgeIds, + const std::vector &face_edgeOrients, const MatrixXi &F, + const VectorXi &V2E, const VectorXi &E2E) { + int flip_count = 0; + int flip_count1 = 0; + + std::vector value(2 * edge_diff.size()); + for (int i = 0; i < (int)edge_diff.size(); ++i) { + value[2 * i + 0] = edge_diff[i][0]; + value[2 * i + 1] = edge_diff[i][1]; + } + + std::deque> Q; + std::vector mark_vertex(V2E.size(), false); + + assert(F.cols() == (int)face_edgeIds.size()); + std::vector variable_eq(face_edgeIds.size() * 2); + std::vector constant_eq(face_edgeIds.size() * 2); + std::vector variable_ge(face_edgeIds.size()); + std::vector constant_ge(face_edgeIds.size()); + + VectorXd face_area(F.cols()); + + for (int i = 0; i < (int)face_edgeIds.size(); ++i) { + Vector2i diff[3]; + Vector2i var[3]; + Vector2i cst[3]; + for (int j = 0; j < 3; ++j) { + int edgeid = face_edgeIds[i][j]; + diff[j] = rshift90(edge_diff[edgeid], face_edgeOrients[i][j]); + var[j] = rshift90(Vector2i(edgeid * 2 + 1, edgeid * 2 + 2), face_edgeOrients[i][j]); + cst[j] = var[j].array().sign(); + var[j] = var[j].array().abs() - 1; + } + + assert(diff[0] + diff[1] + diff[2] == Vector2i::Zero()); + variable_eq[2 * i + 0] = Vector3i(var[0][0], var[1][0], var[2][0]); + constant_eq[2 * i + 0] = Vector3i(cst[0][0], cst[1][0], cst[2][0]); + variable_eq[2 * i + 1] = Vector3i(var[0][1], var[1][1], var[2][1]); + constant_eq[2 * i + 1] = Vector3i(cst[0][1], cst[1][1], cst[2][1]); + + face_area[i] = diff[0][0] * diff[1][1] - diff[0][1] * diff[1][0]; + if (face_area[i] < 0) { + printf("[SAT] Face %d's area < 0\n", i); + for (int j = 0; j < 3; ++j) { + int v = F(j, i); + if (mark_vertex[v]) continue; + Q.push_back(std::make_pair(v, 0)); + mark_vertex[v] = true; + } + flip_count += 1; + } + variable_ge[i] = Vector4i(var[0][0], var[1][1], var[0][1], var[1][0]); + constant_ge[i] = Vector2i(cst[0][0] * cst[1][1], cst[0][1] * cst[1][0]); + } + for (int i = 0; i < (int)variable_eq.size(); ++i) { + auto &var = variable_eq[i]; + auto &cst = constant_eq[i]; + assert((0 <= var.array()).all()); + assert((var.array() < value.size()).all()); + assert(cst[0] * value[var[0]] + cst[1] * value[var[1]] + cst[2] * value[var[2]] == 0); + } + + for (int i = 0; i < (int)variable_ge.size(); ++i) { + auto &var = variable_ge[i]; + auto &cst = constant_ge[i]; + assert((0 <= variable_ge[i].array()).all()); + assert((variable_ge[i].array() < value.size()).all()); + if (value[var[0]] * value[var[1]] * cst[0] - value[var[2]] * value[var[3]] * cst[1] < 0) { + assert(face_area[i] < 0); + flip_count1++; + } + } + assert(flip_count == flip_count1); + + // BFS + printf("[SAT] Start BFS: Q.size() = %d\n", (int)Q.size()); + + int mark_count = Q.size(); + while (!Q.empty()) { + int vertex = Q.front().first; + int depth = Q.front().second; + Q.pop_front(); + mark_count++; + int e0 = V2E(vertex); + + for (int e = e0;;) { + int v = F((e + 1) % 3, e / 3); + if (!mark_vertex[v]) { + int undirected_edge_id = face_edgeIds[e / 3][e % 3]; + int undirected_edge_length = edge_diff[undirected_edge_id].array().abs().sum() > 0; + int ndepth = depth + undirected_edge_length; + if (ndepth <= max_depth) { + if (undirected_edge_length == 0) + Q.push_front(std::make_pair(v, ndepth)); + else + Q.push_back(std::make_pair(v, ndepth)); + mark_vertex[v] = true; + } + } + e = dedge_next_3(E2E(e)); + if (e == e0) break; + } + } + printf("[SAT] Mark %d vertices out of %d\n", mark_count, (int)V2E.size()); + + std::vector flexible(value.size(), false); + for (int i = 0; i < (int)face_edgeIds.size(); ++i) { + for (int j = 0; j < 3; ++j) { + int edgeid = face_edgeIds[i][j]; + if (mark_vertex[F(j, i)] || mark_vertex[F((j + 1) % 3, i)]) { + flexible[edgeid * 2 + 0] = true; + flexible[edgeid * 2 + 1] = true; + } else { + assert(face_area[i] >= 0); + } + } + } + + SolveSatProblem(value.size(), value, flexible, variable_eq, constant_eq, variable_ge, + constant_ge); + + for (int i = 0; i < edge_diff.size(); ++i) { + edge_diff[i][0] = value[2 * i + 0]; + edge_diff[i][1] = value[2 * i + 1]; + } +} + +} // namespace qflow diff --git a/extern/quadriflow/src/localsat.hpp b/extern/quadriflow/src/localsat.hpp new file mode 100644 index 00000000000..af952320ebb --- /dev/null +++ b/extern/quadriflow/src/localsat.hpp @@ -0,0 +1,31 @@ +#ifndef __LOCAL_SAT_H +#define __LOCAL_SAT_H + +#include +#include + +namespace qflow { + +using namespace Eigen; + +enum class SolverStatus { + Sat, + Unsat, + Timeout, +}; + +SolverStatus SolveSatProblem(int n_variable, std::vector &value, + const std::vector flexible, // NOQA + const std::vector &variable_eq, + const std::vector &constant_eq, + const std::vector &variable_ge, + const std::vector &constant_ge, + int timeout = 8); + +void ExportLocalSat(std::vector &edge_diff, const std::vector &face_edgeIds, + const std::vector &face_edgeOrients, const MatrixXi &F, + const VectorXi &V2E, const VectorXi &E2E); + +} // namespace qflow + +#endif diff --git a/extern/quadriflow/src/main.cpp b/extern/quadriflow/src/main.cpp new file mode 100644 index 00000000000..18bc4063c42 --- /dev/null +++ b/extern/quadriflow/src/main.cpp @@ -0,0 +1,127 @@ +#include "config.hpp" +#include "field-math.hpp" +#include "optimizer.hpp" +#include "parametrizer.hpp" +#include + +#ifdef WITH_CUDA +#include +#endif + +using namespace qflow; + +Parametrizer field; + +int main(int argc, char** argv) { + setbuf(stdout, NULL); + +#ifdef WITH_CUDA + cudaFree(0); +#endif + int t1, t2; + std::string input_obj, output_obj; + int faces = -1; + for (int i = 0; i < argc; ++i) { + if (strcmp(argv[i], "-f") == 0) { + sscanf(argv[i + 1], "%d", &faces); + } else if (strcmp(argv[i], "-i") == 0) { + input_obj = argv[i + 1]; + } else if (strcmp(argv[i], "-o") == 0) { + output_obj = argv[i + 1]; + } else if (strcmp(argv[i], "-sharp") == 0) { + field.flag_preserve_sharp = 1; + } else if (strcmp(argv[i], "-boundary") == 0) { + field.flag_preserve_boundary = 1; + } else if (strcmp(argv[i], "-adaptive") == 0) { + field.flag_adaptive_scale = 1; + } else if (strcmp(argv[i], "-mcf") == 0) { + field.flag_minimum_cost_flow = 1; + } else if (strcmp(argv[i], "-sat") == 0) { + field.flag_aggresive_sat = 1; + } else if (strcmp(argv[i], "-seed") == 0) { + field.hierarchy.rng_seed = atoi(argv[i + 1]); + } + } + printf("%d %s %s\n", faces, input_obj.c_str(), output_obj.c_str()); + if (input_obj.size() >= 1) { + field.Load(input_obj.c_str()); + } else { + assert(0); + // field.Load((std::string(DATA_PATH) + "/fertility.obj").c_str()); + } + + printf("Initialize...\n"); + t1 = GetCurrentTime64(); + field.Initialize(faces); + t2 = GetCurrentTime64(); + printf("Use %lf seconds\n", (t2 - t1) * 1e-3); + + if (field.flag_preserve_boundary) { + printf("Add boundary constrains...\n"); + Hierarchy& mRes = field.hierarchy; + mRes.clearConstraints(); + for (uint32_t i = 0; i < 3 * mRes.mF.cols(); ++i) { + if (mRes.mE2E[i] == -1) { + uint32_t i0 = mRes.mF(i % 3, i / 3); + uint32_t i1 = mRes.mF((i + 1) % 3, i / 3); + Vector3d p0 = mRes.mV[0].col(i0), p1 = mRes.mV[0].col(i1); + Vector3d edge = p1 - p0; + if (edge.squaredNorm() > 0) { + edge.normalize(); + mRes.mCO[0].col(i0) = p0; + mRes.mCO[0].col(i1) = p1; + mRes.mCQ[0].col(i0) = mRes.mCQ[0].col(i1) = edge; + mRes.mCQw[0][i0] = mRes.mCQw[0][i1] = mRes.mCOw[0][i0] = mRes.mCOw[0][i1] = + 1.0; + } + } + } + mRes.propagateConstraints(); + } + + printf("Solve Orientation Field...\n"); + t1 = GetCurrentTime64(); + + Optimizer::optimize_orientations(field.hierarchy); + field.ComputeOrientationSingularities(); + t2 = GetCurrentTime64(); + printf("Use %lf seconds\n", (t2 - t1) * 1e-3); + + if (field.flag_adaptive_scale == 1) { + printf("Estimate Slop...\n"); + t1 = GetCurrentTime64(); + field.EstimateSlope(); + t2 = GetCurrentTime64(); + printf("Use %lf seconds\n", (t2 - t1) * 1e-3); + } + printf("Solve for scale...\n"); + t1 = GetCurrentTime64(); + Optimizer::optimize_scale(field.hierarchy, field.rho, field.flag_adaptive_scale); + field.flag_adaptive_scale = 1; + t2 = GetCurrentTime64(); + printf("Use %lf seconds\n", (t2 - t1) * 1e-3); + + printf("Solve for position field...\n"); + t1 = GetCurrentTime64(); + Optimizer::optimize_positions(field.hierarchy, field.flag_adaptive_scale); + + field.ComputePositionSingularities(); + t2 = GetCurrentTime64(); + printf("Use %lf seconds\n", (t2 - t1) * 1e-3); + t1 = GetCurrentTime64(); + printf("Solve index map...\n"); + field.ComputeIndexMap(); + t2 = GetCurrentTime64(); + printf("Indexmap Use %lf seconds\n", (t2 - t1) * 1e-3); + printf("Writing the file...\n"); + + if (output_obj.size() < 1) { + assert(0); + // field.OutputMesh((std::string(DATA_PATH) + "/result.obj").c_str()); + } else { + field.OutputMesh(output_obj.c_str()); + } + printf("finish...\n"); + // field.LoopFace(2); + return 0; +} diff --git a/extern/quadriflow/src/merge-vertex.cpp b/extern/quadriflow/src/merge-vertex.cpp new file mode 100644 index 00000000000..4c7b0a2bb9b --- /dev/null +++ b/extern/quadriflow/src/merge-vertex.cpp @@ -0,0 +1,44 @@ +#include "merge-vertex.hpp" + +#include "compare-key.hpp" + +#include +#include + +namespace qflow { + +void merge_close(MatrixXd& V, MatrixXi& F, double threshold) +{ + std::map vid_maps; + std::vector vid_compress(V.cols()); + for (int i = 0; i < V.cols(); ++i) { + Key3f key(V(0, i), V(1, i), V(2, i), threshold); + if (vid_maps.count(key)) { + vid_compress[i] = vid_maps[key]; + } + else { + V.col(vid_maps.size()) = V.col(i); + vid_compress[i] = vid_maps.size(); + vid_maps[key] = vid_compress[i]; + } + } + printf("Compress Vertex from %d to %d...\n", (int)V.cols(), (int)vid_maps.size()); + MatrixXd newV(3, vid_maps.size()); + memcpy(newV.data(), V.data(), sizeof(double) * 3 * vid_maps.size()); + V = std::move(newV); + int f_num = 0; + for (int i = 0; i < F.cols(); ++i) { + for (int j = 0; j < 3; ++j) { + F(j, f_num) = vid_compress[F(j, i)]; + } + if (F(0, f_num) != F(1, f_num) && F(0, f_num) != F(2, f_num) && F(1, f_num) != F(2, f_num)) { + f_num++; + } + } + printf("Compress Face from %d to %d...\n", (int)F.cols(), f_num); + MatrixXi newF(3, f_num); + memcpy(newF.data(), F.data(), sizeof(int) * 3 * f_num); + F = std::move(newF); +} + +} // namespace qflow diff --git a/extern/quadriflow/src/merge-vertex.hpp b/extern/quadriflow/src/merge-vertex.hpp new file mode 100644 index 00000000000..8bcea3d8e4d --- /dev/null +++ b/extern/quadriflow/src/merge-vertex.hpp @@ -0,0 +1,14 @@ +#ifndef MERGE_VERTEX_H_ +#define MERGE_VERTEX_H_ + +#include + +namespace qflow { + +using namespace Eigen; + +void merge_close(MatrixXd& V, MatrixXi& F, double threshold); + +} // namespace qflow + +#endif \ No newline at end of file diff --git a/extern/quadriflow/src/optimizer.cpp b/extern/quadriflow/src/optimizer.cpp new file mode 100644 index 00000000000..1c59ad0f70c --- /dev/null +++ b/extern/quadriflow/src/optimizer.cpp @@ -0,0 +1,1419 @@ +#include "optimizer.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include "config.hpp" +#include "field-math.hpp" +#include "flow.hpp" +#include "parametrizer.hpp" + +namespace qflow { + +#ifdef WITH_CUDA +# include +#endif + +#ifndef EIGEN_MPL2_ONLY +template +using LinearSolver = Eigen::SimplicialLLT; +#else +template +using LinearSolver = Eigen::SparseLU; +#endif + +Optimizer::Optimizer() {} + +void Optimizer::optimize_orientations(Hierarchy& mRes) { +#ifdef WITH_CUDA + optimize_orientations_cuda(mRes); + printf("%s\n", cudaGetErrorString(cudaDeviceSynchronize())); + cudaMemcpy(mRes.mQ[0].data(), mRes.cudaQ[0], sizeof(glm::dvec3) * mRes.mQ[0].cols(), + cudaMemcpyDeviceToHost); + +#else + + int levelIterations = 6; + for (int level = mRes.mN.size() - 1; level >= 0; --level) { + AdjacentMatrix& adj = mRes.mAdj[level]; + const MatrixXd& N = mRes.mN[level]; + const MatrixXd& CQ = mRes.mCQ[level]; + const VectorXd& CQw = mRes.mCQw[level]; + MatrixXd& Q = mRes.mQ[level]; + auto& phases = mRes.mPhases[level]; + for (int iter = 0; iter < levelIterations; ++iter) { + for (int phase = 0; phase < phases.size(); ++phase) { + auto& p = phases[phase]; +#ifdef WITH_OMP +#pragma omp parallel for +#endif + for (int pi = 0; pi < p.size(); ++pi) { + int i = p[pi]; + const Vector3d n_i = N.col(i); + double weight_sum = 0.0f; + Vector3d sum = Q.col(i); + for (auto& link : adj[i]) { + const int j = link.id; + const double weight = link.weight; + if (weight == 0) continue; + const Vector3d n_j = N.col(j); + Vector3d q_j = Q.col(j); + std::pair value = + compat_orientation_extrinsic_4(sum, n_i, q_j, n_j); + sum = value.first * weight_sum + value.second * weight; + sum -= n_i * n_i.dot(sum); + weight_sum += weight; + double norm = sum.norm(); + if (norm > RCPOVERFLOW) sum /= norm; + } + + if (CQw.size() > 0) { + float cw = CQw[i]; + if (cw != 0) { + std::pair value = + compat_orientation_extrinsic_4(sum, n_i, CQ.col(i), n_i); + sum = value.first * (1 - cw) + value.second * cw; + sum -= n_i * n_i.dot(sum); + + float norm = sum.norm(); + if (norm > RCPOVERFLOW) sum /= norm; + } + } + + if (weight_sum > 0) { + Q.col(i) = sum; + } + } + } + } + if (level > 0) { + const MatrixXd& srcField = mRes.mQ[level]; + const MatrixXi& toUpper = mRes.mToUpper[level - 1]; + MatrixXd& destField = mRes.mQ[level - 1]; + const MatrixXd& N = mRes.mN[level - 1]; +#ifdef WITH_OMP +#pragma omp parallel for +#endif + for (int i = 0; i < srcField.cols(); ++i) { + for (int k = 0; k < 2; ++k) { + int dest = toUpper(k, i); + if (dest == -1) continue; + Vector3d q = srcField.col(i), n = N.col(dest); + destField.col(dest) = q - n * n.dot(q); + } + } + } + } + + for (int l = 0; l < mRes.mN.size() - 1; ++l) { + const MatrixXd& N = mRes.mN[l]; + const MatrixXd& N_next = mRes.mN[l + 1]; + const MatrixXd& Q = mRes.mQ[l]; + MatrixXd& Q_next = mRes.mQ[l + 1]; + auto& toUpper = mRes.mToUpper[l]; +#ifdef WITH_OMP +#pragma omp parallel for +#endif + for (int i = 0; i < toUpper.cols(); ++i) { + Vector2i upper = toUpper.col(i); + Vector3d q0 = Q.col(upper[0]); + Vector3d n0 = N.col(upper[0]); + Vector3d q; + + if (upper[1] != -1) { + Vector3d q1 = Q.col(upper[1]); + Vector3d n1 = N.col(upper[1]); + auto result = compat_orientation_extrinsic_4(q0, n0, q1, n1); + q = result.first + result.second; + } else { + q = q0; + } + Vector3d n = N_next.col(i); + q -= n.dot(q) * n; + if (q.squaredNorm() > RCPOVERFLOW) q.normalize(); + + Q_next.col(i) = q; + } + } + +#endif +} + +void Optimizer::optimize_scale(Hierarchy& mRes, VectorXd& rho, int adaptive) { + const MatrixXd& N = mRes.mN[0]; + MatrixXd& Q = mRes.mQ[0]; + MatrixXd& V = mRes.mV[0]; + MatrixXd& S = mRes.mS[0]; + MatrixXd& K = mRes.mK[0]; + MatrixXi& F = mRes.mF; + + if (adaptive) { + std::vector> lhsTriplets; + + lhsTriplets.reserve(F.cols() * 6); + for (int i = 0; i < V.cols(); ++i) { + for (int j = 0; j < 2; ++j) { + S(j, i) = 1.0; + double sc1 = std::max(0.75 * S(j, i), rho[i] * 1.0 / mRes.mScale); + S(j, i) = std::min(S(j, i), sc1); + } + } + + std::vector> entries(V.cols() * 2); + double lambda = 1; + for (int i = 0; i < entries.size(); ++i) { + entries[i][i] = lambda; + } + for (int i = 0; i < F.cols(); ++i) { + for (int j = 0; j < 3; ++j) { + int v1 = F(j, i); + int v2 = F((j + 1) % 3, i); + Vector3d diff = V.col(v2) - V.col(v1); + Vector3d q_1 = Q.col(v1); + Vector3d q_2 = Q.col(v2); + Vector3d n_1 = N.col(v1); + Vector3d n_2 = N.col(v2); + Vector3d q_1_y = n_1.cross(q_1); + auto index = compat_orientation_extrinsic_index_4(q_1, n_1, q_2, n_2); + int v1_x = v1 * 2, v1_y = v1 * 2 + 1, v2_x = v2 * 2, v2_y = v2 * 2 + 1; + + double dx = diff.dot(q_1); + double dy = diff.dot(q_1_y); + + double kx_g = K(0, v1); + double ky_g = K(1, v1); + + if (index.first % 2 != index.second % 2) { + std::swap(v2_x, v2_y); + } + double scale_x = (fmin(fmax(1 + kx_g * dy, 0.3), 3)); + double scale_y = (fmin(fmax(1 + ky_g * dx, 0.3), 3)); + // (v2_x - scale_x * v1_x)^2 = 0 + // x^2 - 2s xy + s^2 y^2 + entries[v2_x][v2_x] += 1; + entries[v1_x][v1_x] += scale_x * scale_x; + entries[v2_y][v2_y] += 1; + entries[v1_y][v1_y] += scale_y * scale_y; + auto it = entries[v1_x].find(v2_x); + if (it == entries[v1_x].end()) { + entries[v1_x][v2_x] = -scale_x; + entries[v2_x][v1_x] = -scale_x; + entries[v1_y][v2_y] = -scale_y; + entries[v2_y][v1_y] = -scale_y; + } else { + it->second -= scale_x; + entries[v2_x][v1_x] -= scale_x; + entries[v1_y][v2_y] -= scale_y; + entries[v2_y][v1_y] -= scale_y; + } + } + } + + Eigen::SparseMatrix A(V.cols() * 2, V.cols() * 2); + VectorXd rhs(V.cols() * 2); + rhs.setZero(); + for (int i = 0; i < entries.size(); ++i) { + rhs(i) = lambda * S(i % 2, i / 2); + for (auto& rec : entries[i]) { + lhsTriplets.push_back(Eigen::Triplet(i, rec.first, rec.second)); + } + } + A.setFromTriplets(lhsTriplets.begin(), lhsTriplets.end()); + LinearSolver> solver; + solver.analyzePattern(A); + + solver.factorize(A); + + VectorXd result = solver.solve(rhs); + + double total_area = 0; + for (int i = 0; i < V.cols(); ++i) { + S(0, i) = (result(i * 2)); + S(1, i) = (result(i * 2 + 1)); + total_area += S(0, i) * S(1, i); + } + total_area = sqrt(V.cols() / total_area); + for (int i = 0; i < V.cols(); ++i) { + // S(0, i) *= total_area; + // S(1, i) *= total_area; + } + } else { + for (int i = 0; i < V.cols(); ++i) { + S(0, i) = 1; + S(1, i) = 1; + } + } + + for (int l = 0; l < mRes.mS.size() - 1; ++l) { + const MatrixXd& S = mRes.mS[l]; + MatrixXd& S_next = mRes.mS[l + 1]; + auto& toUpper = mRes.mToUpper[l]; + for (int i = 0; i < toUpper.cols(); ++i) { + Vector2i upper = toUpper.col(i); + Vector2d q0 = S.col(upper[0]); + + if (upper[1] != -1) { + q0 = (q0 + S.col(upper[1])) * 0.5; + } + S_next.col(i) = q0; + } + } +} + +void Optimizer::optimize_positions(Hierarchy& mRes, int with_scale) { + int levelIterations = 6; +#ifdef WITH_CUDA + optimize_positions_cuda(mRes); + cudaMemcpy(mRes.mO[0].data(), mRes.cudaO[0], sizeof(glm::dvec3) * mRes.mO[0].cols(), + cudaMemcpyDeviceToHost); +#else + for (int level = mRes.mAdj.size() - 1; level >= 0; --level) { + for (int iter = 0; iter < levelIterations; ++iter) { + AdjacentMatrix& adj = mRes.mAdj[level]; + const MatrixXd &N = mRes.mN[level], &Q = mRes.mQ[level], &V = mRes.mV[level]; + const MatrixXd& CQ = mRes.mCQ[level]; + const MatrixXd& CO = mRes.mCO[level]; + const VectorXd& COw = mRes.mCOw[level]; + MatrixXd& O = mRes.mO[level]; + MatrixXd& S = mRes.mS[level]; + auto& phases = mRes.mPhases[level]; + for (int phase = 0; phase < phases.size(); ++phase) { + auto& p = phases[phase]; +#ifdef WITH_OMP +#pragma omp parallel for +#endif + for (int pi = 0; pi < p.size(); ++pi) { + int i = p[pi]; + double scale_x = mRes.mScale; + double scale_y = mRes.mScale; + if (with_scale) { + scale_x *= S(0, i); + scale_y *= S(1, i); + } + double inv_scale_x = 1.0f / scale_x; + double inv_scale_y = 1.0f / scale_y; + const Vector3d n_i = N.col(i), v_i = V.col(i); + Vector3d q_i = Q.col(i); + + Vector3d sum = O.col(i); + double weight_sum = 0.0f; + + q_i.normalize(); + for (auto& link : adj[i]) { + const int j = link.id; + const double weight = link.weight; + if (weight == 0) continue; + double scale_x_1 = mRes.mScale; + double scale_y_1 = mRes.mScale; + if (with_scale) { + scale_x_1 *= S(0, j); + scale_y_1 *= S(1, j); + } + double inv_scale_x_1 = 1.0f / scale_x_1; + double inv_scale_y_1 = 1.0f / scale_y_1; + + const Vector3d n_j = N.col(j), v_j = V.col(j); + Vector3d q_j = Q.col(j), o_j = O.col(j); + + q_j.normalize(); + + std::pair value = compat_position_extrinsic_4( + v_i, n_i, q_i, sum, v_j, n_j, q_j, o_j, scale_x, scale_y, inv_scale_x, + inv_scale_y, scale_x_1, scale_y_1, inv_scale_x_1, inv_scale_y_1); + + sum = value.first * weight_sum + value.second * weight; + weight_sum += weight; + if (weight_sum > RCPOVERFLOW) sum /= weight_sum; + sum -= n_i.dot(sum - v_i) * n_i; + } + + if (COw.size() > 0) { + float cw = COw[i]; + if (cw != 0) { + Vector3d co = CO.col(i), cq = CQ.col(i); + Vector3d d = co - sum; + d -= cq.dot(d) * cq; + sum += cw * d; + sum -= n_i.dot(sum - v_i) * n_i; + } + } + + if (weight_sum > 0) { + O.col(i) = position_round_4(sum, q_i, n_i, v_i, scale_x, scale_y, + inv_scale_x, inv_scale_y); + } + } + } + } + if (level > 0) { + const MatrixXd& srcField = mRes.mO[level]; + const MatrixXi& toUpper = mRes.mToUpper[level - 1]; + MatrixXd& destField = mRes.mO[level - 1]; + const MatrixXd& N = mRes.mN[level - 1]; + const MatrixXd& V = mRes.mV[level - 1]; +#ifdef WITH_OMP +#pragma omp parallel for +#endif + for (int i = 0; i < srcField.cols(); ++i) { + for (int k = 0; k < 2; ++k) { + int dest = toUpper(k, i); + if (dest == -1) continue; + Vector3d o = srcField.col(i), n = N.col(dest), v = V.col(dest); + o -= n * n.dot(o - v); + destField.col(dest) = o; + } + } + } + } +#endif +} + +void Optimizer::optimize_positions_dynamic( + MatrixXi& F, MatrixXd& V, MatrixXd& N, MatrixXd& Q, std::vector>& Vset, + std::vector& O_compact, std::vector& F_compact, + std::vector& V2E_compact, std::vector& E2E_compact, double mScale, + std::vector& diffs, std::vector& diff_count, + std::map, int>& o2e, std::vector& sharp_o, + std::map>& compact_sharp_constraints, int with_scale) { + std::set uncertain; + for (auto& info : o2e) { + if (diff_count[info.second] == 0) { + uncertain.insert(info.first.first); + uncertain.insert(info.first.second); + } + } + std::vector Vind(O_compact.size(), -1); + std::vector> links(O_compact.size()); + std::vector> dedges(O_compact.size()); + std::vector> adj(V.cols()); + for (int i = 0; i < F.cols(); ++i) { + for (int j = 0; j < 3; ++j) { + int v1 = F(j, i); + int v2 = F((j + 1) % 3, i); + adj[v1].push_back(v2); + } + } + auto FindNearest = [&]() { + for (int i = 0; i < O_compact.size(); ++i) { + if (Vind[i] == -1) { + double min_dis = 1e30; + int min_ind = -1; + for (auto v : Vset[i]) { + double dis = (V.col(v) - O_compact[i]).squaredNorm(); + if (dis < min_dis) { + min_dis = dis; + min_ind = v; + } + } + if (min_ind > -1) { + Vind[i] = min_ind; + double x = (O_compact[i] - V.col(min_ind)).dot(N.col(min_ind)); + O_compact[i] -= x * N.col(min_ind); + } + } else { + int current_v = Vind[i]; + Vector3d n = N.col(current_v); + double current_dis = (O_compact[i] - V.col(current_v)).squaredNorm(); + while (true) { + int next_v = -1; + for (auto& v : adj[current_v]) { + if (N.col(v).dot(n) < cos(10.0 / 180.0 * 3.141592654)) continue; + double dis = (O_compact[i] - V.col(v)).squaredNorm(); + if (dis < current_dis) { + current_dis = dis; + next_v = v; + } + } + if (next_v == -1) break; + // rotate ideal distance + Vector3d n1 = N.col(current_v); + Vector3d n2 = N.col(next_v); + Vector3d axis = n1.cross(n2); + double len = axis.norm(); + double angle = atan2(len, n1.dot(n2)); + axis.normalized(); + Matrix3d m = AngleAxisd(angle, axis).toRotationMatrix(); + for (auto e : dedges[i]) { + Vector3d& d = diffs[e]; + d = m * d; + } + current_v = next_v; + } + Vind[i] = current_v; + } + } + }; + + auto BuildConnection = [&]() { + for (int i = 0; i < links.size(); ++i) { + int deid0 = V2E_compact[i]; + if (deid0 != -1) { + std::list& connection = links[i]; + std::list& dedge = dedges[i]; + int deid = deid0; + do { + connection.push_back(F_compact[deid / 4][(deid + 1) % 4]); + dedge.push_back(deid); + deid = E2E_compact[deid / 4 * 4 + (deid + 3) % 4]; + } while (deid != -1 && deid != deid0); + if (deid == -1) { + deid = deid0; + do { + deid = E2E_compact[deid]; + if (deid == -1) break; + deid = deid / 4 * 4 + (deid + 1) % 4; + connection.push_front(F_compact[deid / 4][(deid + 1) % 4]); + dedge.push_front(deid); + } while (true); + } + } + } + }; + + std::vector lines; + auto ComputeDistance = [&]() { + std::set unobserved; + for (auto& info : o2e) { + if (diff_count[info.second] == 0) { + unobserved.insert(info.first.first); + } + } + while (true) { + bool update = false; + std::set observed; + for (auto& p : unobserved) { + std::vector observations, edges; + int count = 0; + for (auto& e : dedges[p]) { + edges.push_back(e); + if (diff_count[e]) { + count += 1; + observations.push_back(1); + } else { + observations.push_back(0); + } + } + if (count <= 1) continue; + update = true; + observed.insert(p); + for (int i = 0; i < observations.size(); ++i) { + if (observations[i] == 1) continue; + int j = i; + std::list interp; + while (observations[j] == 0) { + interp.push_front(j); + j -= 1; + if (j < 0) j = edges.size() - 1; + } + j = (i + 1) % edges.size(); + while (observations[j] == 0) { + interp.push_back(j); + j += 1; + if (j == edges.size()) j = 0; + } + Vector3d dl = diffs[edges[(interp.front() + edges.size() - 1) % edges.size()]]; + double lenl = dl.norm(); + Vector3d dr = diffs[edges[(interp.back() + 1) % edges.size()]]; + double lenr = dr.norm(); + dl /= lenl; + dr /= lenr; + Vector3d n = dl.cross(dr).normalized(); + double angle = atan2(dl.cross(dr).norm(), dl.dot(dr)); + if (angle < 0) angle += 2 * 3.141592654; + Vector3d nc = N.col(Vind[p]); + if (n.dot(nc) < 0) { + n = -n; + angle = 2 * 3.141592654 - angle; + } + double step = (lenr - lenl) / (interp.size() + 1); + angle /= interp.size() + 1; + Vector3d dlp = nc.cross(dl).normalized(); + int t = 0; + for (auto q : interp) { + t += 1; + observations[q] = 1; + double ad = angle * t; + int e = edges[q]; + int re = E2E_compact[e]; + diff_count[e] = 2; + diffs[e] = (cos(ad) * dl + sin(ad) * dlp) * (lenl + step * t); + if (re != -1) { + diff_count[re] = 2; + diffs[re] = -diffs[e]; + } + } + for (int i = 0; i < edges.size(); ++i) { + lines.push_back(O_compact[p]); + lines.push_back(O_compact[p] + diffs[edges[i]]); + } + } + } + if (!update) break; + for (auto& p : observed) unobserved.erase(p); + } + }; + + BuildConnection(); + int max_iter = 10; + for (int iter = 0; iter < max_iter; ++iter) { + FindNearest(); + ComputeDistance(); + + std::vector> entries(O_compact.size() * 2); + std::vector fixed_dim(O_compact.size() * 2, 0); + for (auto& info : compact_sharp_constraints) { + fixed_dim[info.first * 2 + 1] = 1; + if (info.second.second.norm() < 0.5) fixed_dim[info.first * 2] = 1; + } + std::vector b(O_compact.size() * 2); + std::vector x(O_compact.size() * 2); + std::vector Q_compact(O_compact.size()); + std::vector N_compact(O_compact.size()); + std::vector V_compact(O_compact.size()); +#ifdef WITH_OMP +#pragma omp parallel for +#endif + for (int i = 0; i < O_compact.size(); ++i) { + Q_compact[i] = Q.col(Vind[i]); + N_compact[i] = N.col(Vind[i]); + V_compact[i] = V.col(Vind[i]); + if (fixed_dim[i * 2 + 1] && !fixed_dim[i * 2]) { + Q_compact[i] = compact_sharp_constraints[i].second; + V_compact[i] = compact_sharp_constraints[i].first; + } + } + for (int i = 0; i < O_compact.size(); ++i) { + Vector3d q = Q_compact[i]; + Vector3d n = N_compact[i]; + Vector3d q_y = n.cross(q); + auto Vi = V_compact[i]; + x[i * 2] = (O_compact[i] - Vi).dot(q); + x[i * 2 + 1] = (O_compact[i] - Vi).dot(q_y); + } + for (int i = 0; i < O_compact.size(); ++i) { + Vector3d qx = Q_compact[i]; + Vector3d qy = N_compact[i]; + qy = qy.cross(qx); + auto dedge_it = dedges[i].begin(); + for (auto it = links[i].begin(); it != links[i].end(); ++it, ++dedge_it) { + int j = *it; + Vector3d qx2 = Q_compact[j]; + Vector3d qy2 = N_compact[j]; + qy2 = qy2.cross(qx2); + + int de = o2e[std::make_pair(i, j)]; + double lambda = (diff_count[de] == 1) ? 1 : 1; + Vector3d target_offset = diffs[de]; + + auto Vi = V_compact[i]; + auto Vj = V_compact[j]; + + Vector3d offset = Vj - Vi; + + // target_offset.normalize(); + // target_offset *= mScale; + Vector3d C = target_offset - offset; + int vid[] = {j * 2, j * 2 + 1, i * 2, i * 2 + 1}; + Vector3d weights[] = {qx2, qy2, -qx, -qy}; + for (int ii = 0; ii < 4; ++ii) { + for (int jj = 0; jj < 4; ++jj) { + auto it = entries[vid[ii]].find(vid[jj]); + if (it == entries[vid[ii]].end()) { + entries[vid[ii]][vid[jj]] = lambda * weights[ii].dot(weights[jj]); + } else { + entries[vid[ii]][vid[jj]] += lambda * weights[ii].dot(weights[jj]); + } + } + b[vid[ii]] += lambda * weights[ii].dot(C); + } + } + } + + // fix sharp edges + for (int i = 0; i < entries.size(); ++i) { + if (entries[i].size() == 0) { + entries[i][i] = 1; + b[i] = x[i]; + } + if (fixed_dim[i]) { + b[i] = x[i]; + entries[i].clear(); + entries[i][i] = 1; + } else { + std::unordered_map newmap; + for (auto& rec : entries[i]) { + if (fixed_dim[rec.first]) { + b[i] -= rec.second * x[rec.first]; + } else { + newmap[rec.first] = rec.second; + } + } + std::swap(entries[i], newmap); + } + } + std::vector> lhsTriplets; + lhsTriplets.reserve(F_compact.size() * 8); + Eigen::SparseMatrix A(O_compact.size() * 2, O_compact.size() * 2); + VectorXd rhs(O_compact.size() * 2); + rhs.setZero(); + for (int i = 0; i < entries.size(); ++i) { + rhs(i) = b[i]; + for (auto& rec : entries[i]) { + lhsTriplets.push_back(Eigen::Triplet(i, rec.first, rec.second)); + } + } + + A.setFromTriplets(lhsTriplets.begin(), lhsTriplets.end()); + +#ifdef LOG_OUTPUT + int t1 = GetCurrentTime64(); +#endif + + // FIXME: IncompleteCholesky Preconditioner will fail here so I fallback to Diagonal one. + // I suspected either there is a implementation bug in IncompleteCholesky Preconditioner + // or there is a memory corruption somewhere. However, g++'s address sanitizer does not + // report anything useful. + LinearSolver> solver; + solver.analyzePattern(A); + solver.factorize(A); + // Eigen::setNbThreads(1); + // ConjugateGradient, Lower | Upper> solver; + // VectorXd x0 = VectorXd::Map(x.data(), x.size()); + // solver.setMaxIterations(40); + + // solver.compute(A); + VectorXd x_new = solver.solve(rhs); // solver.solveWithGuess(rhs, x0); + +#ifdef LOG_OUTPUT + // std::cout << "[LSQ] n_iteration:" << solver.iterations() << std::endl; + // std::cout << "[LSQ] estimated error:" << solver.error() << std::endl; + int t2 = GetCurrentTime64(); + printf("[LSQ] Linear solver uses %lf seconds.\n", (t2 - t1) * 1e-3); +#endif + for (int i = 0; i < O_compact.size(); ++i) { + // Vector3d q = Q.col(Vind[i]); + Vector3d q = Q_compact[i]; + // Vector3d n = N.col(Vind[i]); + Vector3d n = N_compact[i]; + Vector3d q_y = n.cross(q); + auto Vi = V_compact[i]; + O_compact[i] = Vi + q * x_new[i * 2] + q_y * x_new[i * 2 + 1]; + } + + // forgive my hack... + if (iter + 1 == max_iter) { + for (int iter = 0; iter < 5; ++iter) { + for (int i = 0; i < O_compact.size(); ++i) { + if (sharp_o[i]) continue; + if (dedges[i].size() != 4 || uncertain.count(i)) { + Vector3d n(0, 0, 0), v(0, 0, 0); + Vector3d v0 = O_compact[i]; + for (auto e : dedges[i]) { + Vector3d v1 = O_compact[F_compact[e / 4][(e + 1) % 4]]; + Vector3d v2 = O_compact[F_compact[e / 4][(e + 3) % 4]]; + n += (v1 - v0).cross(v2 - v0); + v += v1; + } + n.normalize(); + Vector3d offset = v / dedges[i].size() - v0; + offset -= offset.dot(n) * n; + O_compact[i] += offset; + } + } + } + } + } +} + +void Optimizer::optimize_positions_sharp( + Hierarchy& mRes, std::vector& edge_values, std::vector& edge_diff, + std::vector& sharp_edges, std::set& sharp_vertices, + std::map>& sharp_constraints, int with_scale) { + auto& V = mRes.mV[0]; + auto& F = mRes.mF; + auto& Q = mRes.mQ[0]; + auto& N = mRes.mN[0]; + auto& O = mRes.mO[0]; + auto& S = mRes.mS[0]; + + DisajointTree tree(V.cols()); + for (int i = 0; i < edge_diff.size(); ++i) { + if (edge_diff[i].array().abs().sum() == 0) { + tree.Merge(edge_values[i].x, edge_values[i].y); + } + } + tree.BuildCompactParent(); + std::map compact_sharp_indices; + std::set compact_sharp_edges; + for (int i = 0; i < sharp_edges.size(); ++i) { + if (sharp_edges[i] == 1) { + int v1 = tree.Index(F(i % 3, i / 3)); + int v2 = tree.Index(F((i + 1) % 3, i / 3)); + compact_sharp_edges.insert(DEdge(v1, v2)); + } + } + for (auto& v : sharp_vertices) { + int p = tree.Index(v); + if (compact_sharp_indices.count(p) == 0) { + int s = compact_sharp_indices.size(); + compact_sharp_indices[p] = s; + } + } + std::map> sharp_vertices_links; + std::set sharp_dedges; + for (int i = 0; i < sharp_edges.size(); ++i) { + if (sharp_edges[i]) { + int v1 = F(i % 3, i / 3); + int v2 = F((i + 1) % 3, i / 3); + if (sharp_vertices_links.count(v1) == 0) sharp_vertices_links[v1] = std::set(); + sharp_vertices_links[v1].insert(v2); + sharp_dedges.insert(DEdge(v1, v2)); + } + } + std::vector> sharp_to_original_indices(compact_sharp_indices.size()); + for (auto& v : sharp_vertices_links) { + if (v.second.size() == 2) continue; + int p = tree.Index(v.first); + sharp_to_original_indices[compact_sharp_indices[p]].push_back(v.first); + } + for (auto& v : sharp_vertices_links) { + if (v.second.size() != 2) continue; + int p = tree.Index(v.first); + sharp_to_original_indices[compact_sharp_indices[p]].push_back(v.first); + } + + for (int i = 0; i < V.cols(); ++i) { + if (sharp_vertices.count(i)) continue; + int p = tree.Index(i); + if (compact_sharp_indices.count(p)) + sharp_to_original_indices[compact_sharp_indices[p]].push_back(i); + } + + int num = sharp_to_original_indices.size(); + std::vector> links(sharp_to_original_indices.size()); + for (int e = 0; e < edge_diff.size(); ++e) { + int v1 = edge_values[e].x; + int v2 = edge_values[e].y; + int p1 = tree.Index(v1); + int p2 = tree.Index(v2); + if (p1 == p2 || compact_sharp_edges.count(DEdge(p1, p2)) == 0) continue; + p1 = compact_sharp_indices[p1]; + p2 = compact_sharp_indices[p2]; + + links[p1].insert(p2); + links[p2].insert(p1); + } + + std::vector hash(links.size(), 0); + std::vector> loops; + for (int i = 0; i < num; ++i) { + if (hash[i] == 1) continue; + if (links[i].size() == 2) { + std::vector q; + q.push_back(i); + hash[i] = 1; + int v = i; + int prev_v = -1; + bool is_loop = false; + while (links[v].size() == 2) { + int next_v = -1; + for (auto nv : links[v]) + if (nv != prev_v) next_v = nv; + if (hash[next_v]) { + is_loop = true; + break; + } + if (links[next_v].size() == 2) hash[next_v] = true; + q.push_back(next_v); + prev_v = v; + v = next_v; + } + if (!is_loop && q.size() >= 2) { + std::vector q1; + int v = i; + int prev_v = q[1]; + while (links[v].size() == 2) { + int next_v = -1; + for (auto nv : links[v]) + if (nv != prev_v) next_v = nv; + if (hash[next_v]) { + is_loop = true; + break; + } + if (links[next_v].size() == 2) hash[next_v] = true; + q1.push_back(next_v); + prev_v = v; + v = next_v; + } + std::reverse(q1.begin(), q1.end()); + q1.insert(q1.end(), q.begin(), q.end()); + std::swap(q1, q); + } + if (q.size() < 3) continue; + if (is_loop) q.push_back(q.front()); + double len = 0, scale = 0; + std::vector o(q.size()), new_o(q.size()); + std::vector sc(q.size()); + + for (int i = 0; i < q.size() - 1; ++i) { + int v1 = q[i]; + int v2 = q[i + 1]; + auto it = links[v1].find(v2); + if (it == links[v1].end()) { + printf("Non exist!\n"); + exit(0); + } + } + + for (int i = 0; i < q.size(); ++i) { + if (sharp_to_original_indices[q[i]].size() == 0) { + continue; + } + o[i] = O.col(sharp_to_original_indices[q[i]][0]); + Vector3d qx = Q.col(sharp_to_original_indices[q[i]][0]); + Vector3d qy = Vector3d(N.col(sharp_to_original_indices[q[i]][0])).cross(qx); + int fst = sharp_to_original_indices[q[1]][0]; + Vector3d dis = (i == 0) ? (Vector3d(O.col(fst)) - o[i]) : o[i] - o[i - 1]; + if (with_scale) + sc[i] = (abs(qx.dot(dis)) > abs(qy.dot(dis))) + ? S(0, sharp_to_original_indices[q[i]][0]) + : S(1, sharp_to_original_indices[q[i]][0]); + else + sc[i] = 1; + new_o[i] = o[i]; + } + + if (is_loop) { + for (int i = 0; i < q.size(); ++i) { + Vector3d dir = + (o[(i + 1) % q.size()] - o[(i + q.size() - 1) % q.size()]).normalized(); + for (auto& ind : sharp_to_original_indices[q[i]]) { + sharp_constraints[ind] = std::make_pair(o[i], dir); + } + } + } else { + for (int i = 0; i < q.size(); ++i) { + Vector3d dir(0, 0, 0); + if (i != 0 && i + 1 != q.size()) + dir = (o[i + 1] - o[i - 1]).normalized(); + else if (links[q[i]].size() == 1) { + if (i == 0) + dir = (o[i + 1] - o[i]).normalized(); + else + dir = (o[i] - o[i - 1]).normalized(); + } + for (auto& ind : sharp_to_original_indices[q[i]]) { + sharp_constraints[ind] = std::make_pair(o[i], dir); + } + } + } + + for (int i = 0; i < q.size() - 1; ++i) { + len += (o[i + 1] - o[i]).norm(); + scale += sc[i]; + } + + int next_m = q.size() - 1; + + double left_norm = len * sc[0] / scale; + int current_v = 0; + double current_norm = (o[1] - o[0]).norm(); + for (int i = 1; i < next_m; ++i) { + while (left_norm >= current_norm) { + left_norm -= current_norm; + current_v += 1; + current_norm = (o[current_v + 1] - o[current_v]).norm(); + } + new_o[i] = + (o[current_v + 1] * left_norm + o[current_v] * (current_norm - left_norm)) / + current_norm; + o[current_v] = new_o[i]; + current_norm -= left_norm; + left_norm = len * sc[current_v] / scale; + } + + for (int i = 0; i < q.size(); ++i) { + for (auto v : sharp_to_original_indices[q[i]]) { + O.col(v) = new_o[i]; + } + } + + loops.push_back(new_o); + } + } + return; + std::ofstream os("/Users/jingwei/Desktop/sharp.obj"); + for (int i = 0; i < loops.size(); ++i) { + for (auto& v : loops[i]) { + os << "v " << v[0] << " " << v[1] << " " << v[2] << "\n"; + } + } + int offset = 1; + for (int i = 0; i < loops.size(); ++i) { + for (int j = 0; j < loops[i].size() - 1; ++j) { + os << "l " << offset + j << " " << offset + j + 1 << "\n"; + } + offset += loops[i].size(); + } + os.close(); + exit(0); +} + +void Optimizer::optimize_positions_fixed( + Hierarchy& mRes, std::vector& edge_values, std::vector& edge_diff, + std::set& sharp_vertices, std::map>& sharp_constraints, + int with_scale) { + auto& V = mRes.mV[0]; + auto& F = mRes.mF; + auto& Q = mRes.mQ[0]; + auto& N = mRes.mN[0]; + auto& O = mRes.mO[0]; + auto& S = mRes.mS[0]; + + DisajointTree tree(V.cols()); + for (int i = 0; i < edge_diff.size(); ++i) { + if (edge_diff[i].array().abs().sum() == 0) { + tree.Merge(edge_values[i].x, edge_values[i].y); + } + } + tree.BuildCompactParent(); + int num = tree.CompactNum(); + + // Find the most descriptive vertex + std::vector v_positions(num, Vector3d(0, 0, 0)); + std::vector v_count(num); + std::vector v_distance(num, 1e30); + std::vector v_index(num, -1); + + for (int i = 0; i < V.cols(); ++i) { + v_positions[tree.Index(i)] += O.col(i); + v_count[tree.Index(i)] += 1; + } + for (int i = 0; i < num; ++i) { + if (v_count[i] > 0) v_positions[i] /= v_count[i]; + } + for (int i = 0; i < V.cols(); ++i) { + int p = tree.Index(i); + double dis = (v_positions[p] - V.col(i)).squaredNorm(); + if (dis < v_distance[p]) { + v_distance[p] = dis; + v_index[p] = i; + } + } + + std::set compact_sharp_vertices; + for (auto& v : sharp_vertices) { + v_positions[tree.Index(v)] = O.col(v); + v_index[tree.Index(v)] = v; + V.col(v) = O.col(v); + compact_sharp_vertices.insert(tree.Index(v)); + } + std::vector>> ideal_distances(tree.CompactNum()); + for (int e = 0; e < edge_diff.size(); ++e) { + int v1 = edge_values[e].x; + int v2 = edge_values[e].y; + + int p1 = tree.Index(v1); + int p2 = tree.Index(v2); + int q1 = v_index[p1]; + int q2 = v_index[p2]; + + Vector3d q_1 = Q.col(v1); + Vector3d q_2 = Q.col(v2); + + Vector3d n_1 = N.col(v1); + Vector3d n_2 = N.col(v2); + Vector3d q_1_y = n_1.cross(q_1); + Vector3d q_2_y = n_2.cross(q_2); + auto index = compat_orientation_extrinsic_index_4(q_1, n_1, q_2, n_2); + double s_x1 = S(0, v1), s_y1 = S(1, v1); + double s_x2 = S(0, v2), s_y2 = S(1, v2); + int rank_diff = (index.second + 4 - index.first) % 4; + if (rank_diff % 2 == 1) std::swap(s_x2, s_y2); + Vector3d qd_x = 0.5 * (rotate90_by(q_2, n_2, rank_diff) + q_1); + Vector3d qd_y = 0.5 * (rotate90_by(q_2_y, n_2, rank_diff) + q_1_y); + double scale_x = (with_scale ? 0.5 * (s_x1 + s_x2) : 1) * mRes.mScale; + double scale_y = (with_scale ? 0.5 * (s_y1 + s_y2) : 1) * mRes.mScale; + Vector2i diff = edge_diff[e]; + + Vector3d origin1 = + /*(sharp_constraints.count(q1)) ? sharp_constraints[q1].first : */ V.col(q1); + Vector3d origin2 = + /*(sharp_constraints.count(q2)) ? sharp_constraints[q2].first : */ V.col(q2); + Vector3d C = diff[0] * scale_x * qd_x + diff[1] * scale_y * qd_y + origin1 - origin2; + auto it = ideal_distances[p1].find(p2); + if (it == ideal_distances[p1].end()) { + ideal_distances[p1][p2] = std::make_pair(1, C); + } else { + it->second.first += 1; + it->second.second += C; + } + } + + std::vector> entries(num * 2); + std::vector b(num * 2); + + for (int m = 0; m < num; ++m) { + int v1 = v_index[m]; + for (auto& info : ideal_distances[m]) { + int v2 = v_index[info.first]; + Vector3d q_1 = Q.col(v1); + Vector3d q_2 = Q.col(v2); + if (sharp_constraints.count(v1)) { + Vector3d d = sharp_constraints[v1].second; + if (d != Vector3d::Zero()) q_1 = d; + } + if (sharp_constraints.count(v2)) { + Vector3d d = sharp_constraints[v2].second; + if (d != Vector3d::Zero()) q_2 = d; + } + + Vector3d n_1 = N.col(v1); + Vector3d n_2 = N.col(v2); + Vector3d q_1_y = n_1.cross(q_1); + Vector3d q_2_y = n_2.cross(q_2); + Vector3d weights[] = {q_2, q_2_y, -q_1, -q_1_y}; + int vid[] = {info.first * 2, info.first * 2 + 1, m * 2, m * 2 + 1}; + Vector3d dis = info.second.second / info.second.first; + double lambda = 1; + if (sharp_vertices.count(v1) && sharp_vertices.count(v2)) lambda = 1; + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + auto it = entries[vid[i]].find(vid[j]); + if (it == entries[vid[i]].end()) { + entries[vid[i]][vid[j]] = weights[i].dot(weights[j]) * lambda; + } else { + entries[vid[i]][vid[j]] += weights[i].dot(weights[j]) * lambda; + } + } + b[vid[i]] += weights[i].dot(dis) * lambda; + } + } + } + + std::vector fixed_dim(num * 2, 0); + std::vector x(num * 2); +#ifdef WITH_OMP +#pragma omp parallel for +#endif + for (int i = 0; i < num; ++i) { + int p = v_index[i]; + Vector3d q = Q.col(p); + + if (sharp_constraints.count(p)) { + Vector3d dir = sharp_constraints[p].second; + fixed_dim[i * 2 + 1] = 1; + if (dir != Vector3d::Zero()) { + q = dir; + } else + fixed_dim[i * 2] = 1; + } + Vector3d n = N.col(p); + Vector3d q_y = n.cross(q); + x[i * 2] = (v_positions[i] - V.col(p)).dot(q); + x[i * 2 + 1] = (v_positions[i] - V.col(p)).dot(q_y); + } + + // fix sharp edges + for (int i = 0; i < entries.size(); ++i) { + if (fixed_dim[i]) { + b[i] = x[i]; + entries[i].clear(); + entries[i][i] = 1; + } else { + std::unordered_map newmap; + for (auto& rec : entries[i]) { + if (fixed_dim[rec.first]) { + b[i] -= rec.second * x[rec.first]; + } else { + newmap[rec.first] = rec.second; + } + } + std::swap(entries[i], newmap); + } + } + for (int i = 0; i < entries.size(); ++i) { + if (entries[i].size() == 0) { + entries[i][i] = 1; + } + } + + std::vector> lhsTriplets; + lhsTriplets.reserve(F.cols() * 6); + Eigen::SparseMatrix A(num * 2, num * 2); + VectorXd rhs(num * 2); + rhs.setZero(); + for (int i = 0; i < entries.size(); ++i) { + rhs(i) = b[i]; + if (std::isnan(b[i])) { + printf("Equation has nan!\n"); + exit(0); + } + for (auto& rec : entries[i]) { + lhsTriplets.push_back(Eigen::Triplet(i, rec.first, rec.second)); + if (std::isnan(rec.second)) { + printf("Equation has nan!\n"); + exit(0); + } + } + } + A.setFromTriplets(lhsTriplets.begin(), lhsTriplets.end()); + +#ifdef LOG_OUTPUT + int t1 = GetCurrentTime64(); +#endif + /* + Eigen::setNbThreads(1); + ConjugateGradient, Lower | Upper> solver; + VectorXd x0 = VectorXd::Map(x.data(), x.size()); + solver.setMaxIterations(40); + + solver.compute(A); + */ + LinearSolver> solver; + solver.analyzePattern(A); + solver.factorize(A); + + VectorXd x_new = solver.solve(rhs); +#ifdef LOG_OUTPUT + // std::cout << "[LSQ] n_iteration:" << solver.iterations() << std::endl; + // std::cout << "[LSQ] estimated error:" << solver.error() << std::endl; + int t2 = GetCurrentTime64(); + printf("[LSQ] Linear solver uses %lf seconds.\n", (t2 - t1) * 1e-3); +#endif + + for (int i = 0; i < x.size(); ++i) { + if (!std::isnan(x_new[i])) { + if (!fixed_dim[i / 2 * 2 + 1]) { + double total = 0; + for (auto& res : entries[i]) { + double t = x_new[res.first]; + if (std::isnan(t)) t = 0; + total += t * res.second; + } + } + x[i] = x_new[i]; + } + } + + for (int i = 0; i < O.cols(); ++i) { + int p = tree.Index(i); + int c = v_index[p]; + Vector3d q = Q.col(c); + if (fixed_dim[p * 2 + 1]) { + Vector3d dir = sharp_constraints[c].second; + if (dir != Vector3d::Zero()) q = dir; + } + Vector3d n = N.col(c); + Vector3d q_y = n.cross(q); + O.col(i) = V.col(c) + q * x[p * 2] + q_y * x[p * 2 + 1]; + } +} + +void Optimizer::optimize_integer_constraints(Hierarchy& mRes, std::map& singularities, + bool use_minimum_cost_flow) { + int edge_capacity = 2; + bool fullFlow = false; + std::vector>& AllowChange = mRes.mAllowChanges; + for (int level = mRes.mToUpperEdges.size(); level >= 0; --level) { + auto& EdgeDiff = mRes.mEdgeDiff[level]; + auto& FQ = mRes.mFQ[level]; + auto& F2E = mRes.mF2E[level]; + auto& E2F = mRes.mE2F[level]; + + int iter = 0; + while (!fullFlow) { + std::vector edge_to_constraints(E2F.size() * 2, Vector4i(-1, 0, -1, 0)); + std::vector initial(F2E.size() * 2, 0); + for (int i = 0; i < F2E.size(); ++i) { + for (int j = 0; j < 3; ++j) { + int e = F2E[i][j]; + Vector2i index = rshift90(Vector2i(e * 2 + 1, e * 2 + 2), FQ[i][j]); + for (int k = 0; k < 2; ++k) { + int l = abs(index[k]); + int s = index[k] / l; + int ind = l - 1; + int equationID = i * 2 + k; + if (edge_to_constraints[ind][0] == -1) { + edge_to_constraints[ind][0] = equationID; + edge_to_constraints[ind][1] = s; + } else { + edge_to_constraints[ind][2] = equationID; + edge_to_constraints[ind][3] = s; + } + initial[equationID] += s * EdgeDiff[ind / 2][ind % 2]; + } + } + } + std::vector> arcs; + std::vector arc_ids; + for (int i = 0; i < edge_to_constraints.size(); ++i) { + if (AllowChange[level][i] == 0) continue; + if (edge_to_constraints[i][0] == -1 || edge_to_constraints[i][2] == -1) continue; + if (edge_to_constraints[i][1] == -edge_to_constraints[i][3]) { + int v1 = edge_to_constraints[i][0]; + int v2 = edge_to_constraints[i][2]; + if (edge_to_constraints[i][1] < 0) std::swap(v1, v2); + int current_v = EdgeDiff[i / 2][i % 2]; + arcs.push_back(std::make_pair(Vector2i(v1, v2), current_v)); + if (AllowChange[level][i] == 1) + arc_ids.push_back(i + 1); + else { + arc_ids.push_back(-(i + 1)); + } + } + } + int supply = 0; + int demand = 0; + for (int i = 0; i < initial.size(); ++i) { + int init_val = initial[i]; + if (init_val > 0) { + arcs.push_back(std::make_pair(Vector2i(-1, i), initial[i])); + supply += init_val; + } else if (init_val < 0) { + demand -= init_val; + arcs.push_back(std::make_pair(Vector2i(i, initial.size()), -init_val)); + } + } + + std::unique_ptr solver = nullptr; + if (use_minimum_cost_flow && level == mRes.mToUpperEdges.size()) { + lprintf("network simplex MCF is used\n"); + solver = std::make_unique(); + } else if (supply < 20) { + solver = std::make_unique(); + } else { + solver = std::make_unique(); + } + +#ifdef WITH_GUROBI + if (use_minimum_cost_flow && level == mRes.mToUpperEdges.size()) { + solver = std::make_unique(); + } +#endif + solver->resize(initial.size() + 2, arc_ids.size()); + + std::set ids; + for (int i = 0; i < arcs.size(); ++i) { + int v1 = arcs[i].first[0] + 1; + int v2 = arcs[i].first[1] + 1; + int c = arcs[i].second; + if (v1 == 0 || v2 == initial.size() + 1) { + solver->addEdge(v1, v2, c, 0, -1); + } else { + if (arc_ids[i] > 0) + solver->addEdge(v1, v2, std::max(0, c + edge_capacity), + std::max(0, -c + edge_capacity), arc_ids[i] - 1); + else { + if (c > 0) + solver->addEdge(v1, v2, std::max(0, c - 1), + std::max(0, -c + edge_capacity), -1 - arc_ids[i]); + else + solver->addEdge(v1, v2, std::max(0, c + edge_capacity), + std::max(0, -c - 1), -1 - arc_ids[i]); + } + } + } + int flow_count = solver->compute(); + + solver->applyTo(EdgeDiff); + + lprintf("flow_count = %d, supply = %d\n", flow_count, supply); + if (flow_count == supply) fullFlow = true; + if (level != 0 || fullFlow) break; + edge_capacity += 1; + iter++; + if (iter == 10) { + /* Probably won't converge. */ + break; + } + lprintf("Not full flow, edge_capacity += 1\n"); + } + + if (level != 0) { + auto& nEdgeDiff = mRes.mEdgeDiff[level - 1]; + auto& toUpper = mRes.mToUpperEdges[level - 1]; + auto& toUpperOrients = mRes.mToUpperOrients[level - 1]; + for (int i = 0; i < toUpper.size(); ++i) { + if (toUpper[i] >= 0) { + int orient = (4 - toUpperOrients[i]) % 4; + nEdgeDiff[i] = rshift90(EdgeDiff[toUpper[i]], orient); + } + } + } + } +} + +#ifdef WITH_CUDA + +void Optimizer::optimize_orientations_cuda(Hierarchy& mRes) { + int levelIterations = 6; + for (int level = mRes.mN.size() - 1; level >= 0; --level) { + Link* adj = mRes.cudaAdj[level]; + int* adjOffset = mRes.cudaAdjOffset[level]; + glm::dvec3* N = mRes.cudaN[level]; + glm::dvec3* Q = mRes.cudaQ[level]; + auto& phases = mRes.cudaPhases[level]; + for (int iter = 0; iter < levelIterations; ++iter) { + for (int phase = 0; phase < phases.size(); ++phase) { + int* p = phases[phase]; + UpdateOrientation(p, mRes.mPhases[level][phase].size(), N, Q, adj, adjOffset, + mRes.mAdj[level][phase].size()); + } + } + if (level > 0) { + glm::dvec3* srcField = mRes.cudaQ[level]; + glm::ivec2* toUpper = mRes.cudaToUpper[level - 1]; + glm::dvec3* destField = mRes.cudaQ[level - 1]; + glm::dvec3* N = mRes.cudaN[level - 1]; + PropagateOrientationUpper(srcField, mRes.mQ[level].cols(), toUpper, N, destField); + } + } + + for (int l = 0; l < mRes.mN.size() - 1; ++l) { + glm::dvec3* N = mRes.cudaN[l]; + glm::dvec3* N_next = mRes.cudaN[l + 1]; + glm::dvec3* Q = mRes.cudaQ[l]; + glm::dvec3* Q_next = mRes.cudaQ[l + 1]; + glm::ivec2* toUpper = mRes.cudaToUpper[l]; + + PropagateOrientationLower(toUpper, Q, N, Q_next, N_next, mRes.mToUpper[l].cols()); + } +} + +void Optimizer::optimize_positions_cuda(Hierarchy& mRes) { + int levelIterations = 6; + for (int level = mRes.mAdj.size() - 1; level >= 0; --level) { + Link* adj = mRes.cudaAdj[level]; + int* adjOffset = mRes.cudaAdjOffset[level]; + glm::dvec3* N = mRes.cudaN[level]; + glm::dvec3* Q = mRes.cudaQ[level]; + glm::dvec3* V = mRes.cudaV[level]; + glm::dvec3* O = mRes.cudaO[level]; + std::vector phases = mRes.cudaPhases[level]; + for (int iter = 0; iter < levelIterations; ++iter) { + for (int phase = 0; phase < phases.size(); ++phase) { + int* p = phases[phase]; + UpdatePosition(p, mRes.mPhases[level][phase].size(), N, Q, adj, adjOffset, + mRes.mAdj[level][phase].size(), V, O, mRes.mScale); + } + } + if (level > 0) { + glm::dvec3* srcField = mRes.cudaO[level]; + glm::ivec2* toUpper = mRes.cudaToUpper[level - 1]; + glm::dvec3* destField = mRes.cudaO[level - 1]; + glm::dvec3* N = mRes.cudaN[level - 1]; + glm::dvec3* V = mRes.cudaV[level - 1]; + PropagatePositionUpper(srcField, mRes.mO[level].cols(), toUpper, N, V, destField); + } + } +} + +#endif + +} // namespace qflow diff --git a/extern/quadriflow/src/optimizer.hpp b/extern/quadriflow/src/optimizer.hpp new file mode 100644 index 00000000000..ad6fa720a6e --- /dev/null +++ b/extern/quadriflow/src/optimizer.hpp @@ -0,0 +1,56 @@ +#ifndef OPTIMIZER_H_ +#define OPTIMIZER_H_ +#include "config.hpp" +#include "field-math.hpp" +#include "hierarchy.hpp" + +namespace qflow { + +class Optimizer { + public: + Optimizer(); + static void optimize_orientations(Hierarchy& mRes); + static void optimize_scale(Hierarchy& mRes, VectorXd& rho, int adaptive); + static void optimize_positions(Hierarchy& mRes, int with_scale = 0); + static void optimize_integer_constraints(Hierarchy& mRes, std::map& singularities, + bool use_minimum_cost_flow); + static void optimize_positions_fixed( + Hierarchy& mRes, std::vector& edge_values, std::vector& edge_diff, + std::set& sharp_vertices, + std::map>& sharp_constraints, int with_scale = 0); + static void optimize_positions_sharp( + Hierarchy& mRes, std::vector& edge_values, std::vector& edge_diff, + std::vector& sharp_edges, std::set& sharp_vertices, + std::map>& sharp_constraints, int with_scale = 0); + static void optimize_positions_dynamic( + MatrixXi& F, MatrixXd& V, MatrixXd& N, MatrixXd& Q, std::vector>& Vset, + std::vector& O_compact, std::vector& F_compact, + std::vector& V2E_compact, std::vector& E2E_compact, double mScale, + std::vector& diffs, std::vector& diff_count, + std::map, int>& o2e, std::vector& sharp_o, + std::map>& compact_sharp_constraints, int with_scale); +#ifdef WITH_CUDA + static void optimize_orientations_cuda(Hierarchy& mRes); + static void optimize_positions_cuda(Hierarchy& mRes); +#endif +}; + +#ifdef WITH_CUDA +extern void UpdateOrientation(int* phase, int num_phases, glm::dvec3* N, glm::dvec3* Q, Link* adj, + int* adjOffset, int num_adj); +extern void PropagateOrientationUpper(glm::dvec3* srcField, int num_orientation, + glm::ivec2* toUpper, glm::dvec3* N, glm::dvec3* destField); +extern void PropagateOrientationLower(glm::ivec2* toUpper, glm::dvec3* Q, glm::dvec3* N, + glm::dvec3* Q_next, glm::dvec3* N_next, int num_toUpper); + +extern void UpdatePosition(int* phase, int num_phases, glm::dvec3* N, glm::dvec3* Q, Link* adj, + int* adjOffset, int num_adj, glm::dvec3* V, glm::dvec3* O, + double scale); +extern void PropagatePositionUpper(glm::dvec3* srcField, int num_position, glm::ivec2* toUpper, + glm::dvec3* N, glm::dvec3* V, glm::dvec3* destField); + +#endif + +} // namespace qflow + +#endif diff --git a/extern/quadriflow/src/parametrizer-flip.cpp b/extern/quadriflow/src/parametrizer-flip.cpp new file mode 100644 index 00000000000..67b6ebbb8e2 --- /dev/null +++ b/extern/quadriflow/src/parametrizer-flip.cpp @@ -0,0 +1,583 @@ +#include "dedge.hpp" +#include "parametrizer.hpp" + +#include +#include +#include +#include + +namespace qflow { + +double Parametrizer::QuadEnergy(std::vector& loop_vertices, std::vector& res_quads, + int level) { + if (loop_vertices.size() < 4) return 0; + if (loop_vertices.size() == 4) { + double energy = 0; + for (int j = 0; j < 4; ++j) { + int v0 = loop_vertices[j]; + int v2 = loop_vertices[(j + 1) % 4]; + int v1 = loop_vertices[(j + 3) % 4]; + Vector3d pt1 = (O_compact[v1] - O_compact[v0]).normalized(); + Vector3d pt2 = (O_compact[v2] - O_compact[v0]).normalized(); + Vector3d n = pt1.cross(pt2); + double sina = n.norm(); + if (n.dot(N_compact[v0]) < 0) sina = -sina; + double cosa = pt1.dot(pt2); + double angle = atan2(sina, cosa) / 3.141592654 * 180.0; + if (angle < 0) angle = 360 + angle; + energy += angle * angle; + } + res_quads.push_back( + Vector4i(loop_vertices[0], loop_vertices[3], loop_vertices[2], loop_vertices[1])); + return energy; + } + double max_energy = 1e30; + for (int seg1 = 2; seg1 < loop_vertices.size(); seg1 += 2) { + for (int seg2 = seg1 + 1; seg2 < loop_vertices.size(); seg2 += 2) { + std::vector quads[4]; + std::vector vertices = {loop_vertices[0], loop_vertices[1], loop_vertices[seg1], + loop_vertices[seg2]}; + double energy = 0; + energy += QuadEnergy(vertices, quads[0], level + 1); + if (seg1 > 2) { + std::vector vertices(loop_vertices.begin() + 1, loop_vertices.begin() + seg1); + vertices.push_back(loop_vertices[seg1]); + energy += QuadEnergy(vertices, quads[1], level + 1); + } + if (seg2 != seg1 + 1) { + std::vector vertices(loop_vertices.begin() + seg1, + loop_vertices.begin() + seg2); + vertices.push_back(loop_vertices[seg2]); + energy += QuadEnergy(vertices, quads[2], level + 2); + } + if (seg2 + 1 != loop_vertices.size()) { + std::vector vertices(loop_vertices.begin() + seg2, loop_vertices.end()); + vertices.push_back(loop_vertices[0]); + energy += QuadEnergy(vertices, quads[3], level + 1); + } + if (max_energy > energy) { + max_energy = energy; + res_quads.clear(); + for (int i = 0; i < 4; ++i) { + for (auto& v : quads[i]) { + res_quads.push_back(v); + } + } + } + } + } + return max_energy; +} + +void Parametrizer::FixHoles(std::vector& loop_vertices) { + std::vector> loop_vertices_array; + std::unordered_map map_loops; + for (int i = 0; i < loop_vertices.size(); ++i) { + if (map_loops.count(loop_vertices[i])) { + int j = map_loops[loop_vertices[i]]; + loop_vertices_array.push_back(std::vector()); + if (i - j > 3 && (i - j) % 2 == 0) { + for (int k = j; k < i; ++k) { + if (map_loops.count(loop_vertices[k])) { + loop_vertices_array.back().push_back(loop_vertices[k]); + map_loops.erase(loop_vertices[k]); + } + } + } + } + map_loops[loop_vertices[i]] = i; + } + if (map_loops.size() >= 3) { + loop_vertices_array.push_back(std::vector()); + for (int k = 0; k < loop_vertices.size(); ++k) { + if (map_loops.count(loop_vertices[k])) { + if (map_loops.count(loop_vertices[k])) { + loop_vertices_array.back().push_back(loop_vertices[k]); + map_loops.erase(loop_vertices[k]); + } + } + } + } + for (int i = 0; i < loop_vertices_array.size(); ++i) { + auto& loop_vertices = loop_vertices_array[i]; + if (loop_vertices.size() == 0) return; + std::vector quads; +#ifdef LOG_OUTPUT +// printf("Compute energy for loop: %d\n", (int)loop_vertices.size()); +#endif + QuadEnergy(loop_vertices, quads, 0); +#ifdef LOG_OUTPUT +// printf("quads: %d\n", quads.size()); +#endif + for (auto& p : quads) { + bool flag = false; + for (int j = 0; j < 4; ++j) { + int v1 = p[j]; + int v2 = p[(j + 1) % 4]; + auto key = std::make_pair(v1, v2); + if (Quad_edges.count(key)) { + flag = true; + break; + } + } + if (!flag) { + for (int j = 0; j < 4; ++j) { + int v1 = p[j]; + int v2 = p[(j + 1) % 4]; + auto key = std::make_pair(v1, v2); + Quad_edges.insert(key); + } + F_compact.push_back(p); + } + } + } +} + +void Parametrizer::FixHoles() { + for (int i = 0; i < F_compact.size(); ++i) { + for (int j = 0; j < 4; ++j) { + int v1 = F_compact[i][j]; + int v2 = F_compact[i][(j + 1) % 4]; + auto key = std::make_pair(v1, v2); + Quad_edges.insert(key); + } + } + std::vector detected_boundary(E2E_compact.size(), 0); + for (int i = 0; i < E2E_compact.size(); ++i) { + if (detected_boundary[i] != 0 || E2E_compact[i] != -1) continue; + std::vector loop_edges; + int current_e = i; + + while (detected_boundary[current_e] == 0) { + detected_boundary[current_e] = 1; + loop_edges.push_back(current_e); + current_e = current_e / 4 * 4 + (current_e + 1) % 4; + while (E2E_compact[current_e] != -1) { + current_e = E2E_compact[current_e]; + current_e = current_e / 4 * 4 + (current_e + 1) % 4; + } + } + std::vector loop_vertices(loop_edges.size()); + for (int j = 0; j < loop_edges.size(); ++j) { + loop_vertices[j] = F_compact[loop_edges[j] / 4][loop_edges[j] % 4]; + } + if (loop_vertices.size() < 25) FixHoles(loop_vertices); + } +} + +void Parametrizer::FixFlipHierarchy() { + Hierarchy fh; + fh.DownsampleEdgeGraph(face_edgeOrients, face_edgeIds, edge_diff, allow_changes, -1); + fh.FixFlip(); + fh.UpdateGraphValue(face_edgeOrients, face_edgeIds, edge_diff); +} + +void Parametrizer::FixFlipSat() { +#ifdef LOG_OUTPUT + printf("Solving SAT!\n"); +#endif + + if (!this->flag_aggresive_sat) return; + + for (int threshold = 1; threshold <= 4; ++threshold) { + lprintf("[FixFlipSat] threshold = %d\n", threshold); + + Hierarchy fh; + fh.DownsampleEdgeGraph(face_edgeOrients, face_edgeIds, edge_diff, allow_changes, -1); + int nflip = 0; + for (int depth = std::min(5, (int)fh.mFQ.size() - 1); depth >= 0; --depth) { + nflip = fh.FixFlipSat(depth, threshold); + if (depth > 0) fh.PushDownwardFlip(depth); + if (nflip == 0) break; + } + fh.UpdateGraphValue(face_edgeOrients, face_edgeIds, edge_diff); + if (nflip == 0) break; + } +} + +void Parametrizer::AdvancedExtractQuad() { + Hierarchy fh; + fh.DownsampleEdgeGraph(face_edgeOrients, face_edgeIds, edge_diff, allow_changes, -1); + auto& V = hierarchy.mV[0]; + auto& F = hierarchy.mF; + disajoint_tree = DisajointTree(V.cols()); + auto& diffs = fh.mEdgeDiff.front(); + for (int i = 0; i < diffs.size(); ++i) { + if (diffs[i] == Vector2i::Zero()) { + disajoint_tree.Merge(edge_values[i].x, edge_values[i].y); + } + } + disajoint_tree.BuildCompactParent(); + auto& F2E = fh.mF2E.back(); + auto& E2F = fh.mE2F.back(); + auto& EdgeDiff = fh.mEdgeDiff.back(); + auto& FQ = fh.mFQ.back(); + + std::vector edge(E2F.size()); + std::vector face(F2E.size()); + for (int i = 0; i < diffs.size(); ++i) { + int t = i; + for (int j = 0; j < fh.mToUpperEdges.size(); ++j) { + t = fh.mToUpperEdges[j][t]; + if (t < 0) break; + } + if (t >= 0) edge[t] = i; + } + for (int i = 0; i < F.cols(); ++i) { + int t = i; + for (int j = 0; j < fh.mToUpperFaces.size(); ++j) { + t = fh.mToUpperFaces[j][t]; + if (t < 0) break; + } + if (t >= 0) face[t] = i; + } + fh.UpdateGraphValue(face_edgeOrients, face_edgeIds, edge_diff); + + auto& O = hierarchy.mO[0]; + auto& Q = hierarchy.mQ[0]; + auto& N = hierarchy.mN[0]; + int num_v = disajoint_tree.CompactNum(); + Vset.resize(num_v); + O_compact.resize(num_v, Vector3d::Zero()); + Q_compact.resize(num_v, Vector3d::Zero()); + N_compact.resize(num_v, Vector3d::Zero()); + counter.resize(num_v, 0); + for (int i = 0; i < O.cols(); ++i) { + int compact_v = disajoint_tree.Index(i); + Vset[compact_v].push_back(i); + O_compact[compact_v] += O.col(i); + N_compact[compact_v] = N_compact[compact_v] * counter[compact_v] + N.col(i); + N_compact[compact_v].normalize(); + if (counter[compact_v] == 0) + Q_compact[compact_v] = Q.col(i); + else { + auto pairs = compat_orientation_extrinsic_4(Q_compact[compact_v], N_compact[compact_v], + Q.col(i), N.col(i)); + Q_compact[compact_v] = (pairs.first * counter[compact_v] + pairs.second).normalized(); + } + counter[compact_v] += 1; + } + for (int i = 0; i < O_compact.size(); ++i) { + O_compact[i] /= counter[i]; + } + + BuildTriangleManifold(disajoint_tree, edge, face, edge_values, F2E, E2F, EdgeDiff, FQ); +} + +void Parametrizer::BuildTriangleManifold(DisajointTree& disajoint_tree, std::vector& edge, + std::vector& face, std::vector& edge_values, + std::vector& F2E, std::vector& E2F, + std::vector& EdgeDiff, + std::vector& FQ) { + auto& F = hierarchy.mF; + std::vector E2E(F2E.size() * 3, -1); + for (int i = 0; i < E2F.size(); ++i) { + int v1 = E2F[i][0]; + int v2 = E2F[i][1]; + int t1 = 0; + int t2 = 2; + if (v1 != -1) + while (F2E[v1][t1] != i) t1 += 1; + if (v2 != -1) + while (F2E[v2][t2] != i) t2 -= 1; + t1 += v1 * 3; + t2 += v2 * 3; + if (v1 != -1) + E2E[t1] = (v2 == -1) ? -1 : t2; + if (v2 != -1) + E2E[t2] = (v1 == -1) ? -1 : t1; + } + + std::vector triangle_vertices(F2E.size(), Vector3i(-1, -1, -1)); + int num_v = 0; + std::vector N, Q, O; + std::vector> Vs; + for (int i = 0; i < F2E.size(); ++i) { + for (int j = 0; j < 3; ++j) { + if (triangle_vertices[i][j] != -1) continue; + int f = face[i]; + int v = disajoint_tree.Index(F(j, f)); + Vs.push_back(Vset[v]); + Q.push_back(Q_compact[v]); + N.push_back(N_compact[v]); + O.push_back(O_compact[v]); + int deid0 = i * 3 + j; + int deid = deid0; + do { + triangle_vertices[deid / 3][deid % 3] = num_v; + deid = E2E[deid / 3 * 3 + (deid + 2) % 3]; + } while (deid != deid0 && deid != -1); + if (deid == -1) { + deid = deid0; + do { + deid = E2E[deid]; + if (deid == -1) + break; + deid = deid / 3 * 3 + (deid + 1) % 3; + triangle_vertices[deid/3][deid%3] = num_v; + } while (deid != -1); + } + num_v += 1; + } + } + + int num_v0 = num_v; + do { + num_v0 = num_v; + std::vector> vert_to_dedge(num_v); + for (int i = 0; i < triangle_vertices.size(); ++i) { + Vector3i pt = triangle_vertices[i]; + if (pt[0] == pt[1] || pt[1] == pt[2] || pt[2] == pt[0]) { + for (int j = 0; j < 3; ++j) { + int t = E2E[i * 3 + j]; + if (t != -1) E2E[t] = -1; + } + for (int j = 0; j < 3; ++j) { + E2E[i * 3 + j] = -1; + } + } else { + for (int j = 0; j < 3; ++j) + vert_to_dedge[triangle_vertices[i][j]].push_back(i * 3 + j); + } + } + std::vector colors(triangle_vertices.size() * 3, -1), + reverse_colors(triangle_vertices.size() * 3, -1); + for (int i = 0; i < vert_to_dedge.size(); ++i) { + int num_color = 0; + for (int j = 0; j < vert_to_dedge[i].size(); ++j) { + int deid = vert_to_dedge[i][j]; + if (colors[deid] != -1) continue; + std::list l; + int deid0 = deid; + do { + l.push_back(deid); + deid = deid / 3 * 3 + (deid + 2) % 3; + deid = E2E[deid]; + } while (deid != -1 && deid != deid0); + if (deid == -1) { + deid = deid0; + do { + deid = E2E[deid]; + if (deid == -1) break; + deid = deid / 3 * 3 + (deid + 1) % 3; + if (deid == deid0) break; + l.push_front(deid); + } while (true); + } + std::vector dedges; + for (auto& e : l) dedges.push_back(e); + std::map, int> loc; + std::vector deid_colors(dedges.size(), num_color); + num_color += 1; + for (int jj = 0; jj < dedges.size(); ++jj) { + int deid = dedges[jj]; + colors[deid] = 0; + int v1 = triangle_vertices[deid / 3][deid % 3]; + int v2 = triangle_vertices[deid / 3][(deid + 1) % 3]; + std::pair pt(v1, v2); + if (loc.count(pt)) { + int s = loc[pt]; + for (int k = s; k < jj; ++k) { + int deid1 = dedges[k]; + int v11 = triangle_vertices[deid1 / 3][deid1 % 3]; + int v12 = triangle_vertices[deid1 / 3][(deid1 + 1) % 3]; + std::pair pt1(v11, v12); + loc.erase(pt1); + deid_colors[k] = num_color; + } + num_color += 1; + } + loc[pt] = jj; + } + for (int j = 0; j < dedges.size(); ++j) { + int deid = dedges[j]; + int color = deid_colors[j]; + if (color > 0) { + triangle_vertices[deid / 3][deid % 3] = num_v + color - 1; + } + } + } + if (num_color > 1) { + for (int j = 0; j < num_color - 1; ++j) { + Vs.push_back(Vs[i]); + O.push_back(O[i]); + N.push_back(N[i]); + Q.push_back(Q[i]); + } + num_v += num_color - 1; + } + } + } while (num_v != num_v0); + int offset = 0; + std::vector triangle_edges, triangle_orients; + for (int i = 0; i < triangle_vertices.size(); ++i) { + Vector3i pt = triangle_vertices[i]; + if (pt[0] == pt[1] || pt[1] == pt[2] || pt[2] == pt[0]) continue; + triangle_vertices[offset++] = triangle_vertices[i]; + triangle_edges.push_back(F2E[i]); + triangle_orients.push_back(FQ[i]); + } + triangle_vertices.resize(offset); + std::set flip_vertices; + for (int i = 0; i < triangle_vertices.size(); ++i) { + Vector2i d1 = rshift90(EdgeDiff[triangle_edges[i][0]], triangle_orients[i][0]); + Vector2i d2 = rshift90(EdgeDiff[triangle_edges[i][1]], triangle_orients[i][1]); + int area = d1[0] * d2[1] - d1[1] * d2[0]; + if (area < 0) { + for (int j = 0; j < 3; ++j) { + flip_vertices.insert(triangle_vertices[i][j]); + } + } + } + MatrixXd NV(3, num_v); + MatrixXi NF(3, triangle_vertices.size()); + memcpy(NF.data(), triangle_vertices.data(), sizeof(int) * 3 * triangle_vertices.size()); + VectorXi NV2E, NE2E, NB, NN; + compute_direct_graph(NV, NF, NV2E, NE2E, NB, NN); + + std::map> quads; + for (int i = 0; i < triangle_vertices.size(); ++i) { + for (int j = 0; j < 3; ++j) { + int e = triangle_edges[i][j]; + int v1 = triangle_vertices[i][j]; + int v2 = triangle_vertices[i][(j + 1) % 3]; + int v3 = triangle_vertices[i][(j + 2) % 3]; + if (abs(EdgeDiff[e][0]) == 1 && abs(EdgeDiff[e][1]) == 1) { + DEdge edge(v1, v2); + if (quads.count(edge)) + quads[edge].second = Vector3i(v1, v2, v3); + else + quads[edge] = std::make_pair(Vector3i(v1, v2, v3), Vector3i(-1, -1, -1)); + } + } + } + + for (auto& p : quads) { + if (p.second.second[0] != -1 && p.second.first[2] != p.second.second[2]) { + F_compact.push_back(Vector4i(p.second.first[1], p.second.first[2], p.second.first[0], + p.second.second[2])); + } + } + std::swap(Vs, Vset); + std::swap(O_compact, O); + std::swap(N_compact, N); + std::swap(Q_compact, Q); + compute_direct_graph_quad(O_compact, F_compact, V2E_compact, E2E_compact, boundary_compact, + nonManifold_compact); + + while (true) { + std::vector erasedF(F_compact.size(), 0); + for (int i = 0; i < F_compact.size(); ++i) { + for (int j = 0; j < 3; ++j) { + for (int k = j + 1; k < 4; ++k) { + if (F_compact[i][j] == F_compact[i][k]) { + erasedF[i] = 1; + } + } + } + } + for (int i = 0; i < O_compact.size(); ++i) { + int v = 0; + int e0 = V2E_compact[i]; + if (e0 == -1) continue; + std::vector dedges; + int e = e0; + do { + dedges.push_back(e); + v += 1; + e = e / 4 * 4 + (e + 3) % 4; + e = E2E_compact[e]; + } while (e != e0 && e != -1); + if (e == -1) { + int e = e0; + while (true) { + e = E2E_compact[e]; + if (e == -1) break; + e = e / 4 * 4 + (e + 1) % 4; + v += 1; + dedges.push_back(e); + } + } + if (v == 2) { + // erasedF[dedges[1] / 4] = 1; + // F_compact[dedges[0]/4][dedges[0]%4] = + // F_compact[dedges[1]/4][(dedges[1]+2)%4]; + } + } + offset = 0; + for (int i = 0; i < F_compact.size(); ++i) { + if (erasedF[i] == 0) F_compact[offset++] = F_compact[i]; + } + if (offset == F_compact.size()) break; + F_compact.resize(offset); + compute_direct_graph_quad(O_compact, F_compact, V2E_compact, E2E_compact, boundary_compact, + nonManifold_compact); + } + FixHoles(); + compute_direct_graph_quad(O_compact, F_compact, V2E_compact, E2E_compact, boundary_compact, + nonManifold_compact); + + /* + for (auto& p : flip_vertices) { + int deid0 = V2E_compact[p]; + int deid = deid0; + std::list dedges; + if (deid0 != -1) { + do { + dedges.push_back(deid); + deid = E2E_compact[deid/4*4 + (deid+3) % 4]; + } while (deid != -1 && deid != deid0); + if (deid == -1) { + deid = deid0; + do { + deid = E2E_compact[deid]; + if (deid == -1) + break; + deid = deid/4*4 + (deid +1) % 4; + dedges.push_front(deid); + } while (deid != -1 && deid != deid0); + } + std::set eraseF; + std::set valid_dedges; + std::set boundaries; + std::vector loop_vertices; + for (auto& dedge : dedges) { + int f = dedge / 4; + eraseF.insert(f); + valid_dedges.insert(E2E_compact[f * 4 + (dedge+1)%4]); + valid_dedges.insert(E2E_compact[f * 4 + (dedge+2)%4]); + loop_vertices.push_back(F_compact[f][(dedge+1)%4]); + loop_vertices.push_back(F_compact[f][(dedge+2)%4]); + boundaries.insert(F_compact[f][(dedge+1)%4]); + boundaries.insert(F_compact[f][(dedge+2)%4]); + } + int offset = 0; + auto it = eraseF.begin(); + for (int i = 0; i < F_compact.size(); ++i) { + if (it == eraseF.end() || i != *it) { + bool need_erase = false; + for (int j = 0; j < 4; ++j) { + if (valid_dedges.count(i * 4 + j) == 0 && boundaries.count(F_compact[i][j]) + && boundaries.count(F_compact[i][(j + 1) % 4])) { need_erase = true; + } + } + if (!need_erase) + F_compact[offset++] = F_compact[i]; + } else { + it++; + } + } + F_compact.resize(offset); + compute_direct_graph_quad(O_compact, F_compact, V2E_compact, E2E_compact, + boundary_compact, nonManifold_compact); std::reverse(loop_vertices.begin(), + loop_vertices.end()); FixHoles(loop_vertices); compute_direct_graph_quad(O_compact, F_compact, + V2E_compact, E2E_compact, boundary_compact, nonManifold_compact); + } + } + FixHoles(); + compute_direct_graph_quad(O_compact, F_compact, V2E_compact, E2E_compact, boundary_compact, + nonManifold_compact); + */ +} + +} // namespace qflow diff --git a/extern/quadriflow/src/parametrizer-int.cpp b/extern/quadriflow/src/parametrizer-int.cpp new file mode 100644 index 00000000000..08fa36c1baa --- /dev/null +++ b/extern/quadriflow/src/parametrizer-int.cpp @@ -0,0 +1,425 @@ +#include "parametrizer.hpp" + +#include +#include +#include +#include +#include "optimizer.hpp" + +namespace qflow { + + +void Parametrizer::BuildEdgeInfo() { + auto& F = hierarchy.mF; + auto& E2E = hierarchy.mE2E; + + edge_diff.clear(); + edge_values.clear(); + face_edgeIds.resize(F.cols(), Vector3i(-1, -1, -1)); + for (int i = 0; i < F.cols(); ++i) { + for (int j = 0; j < 3; ++j) { + int k1 = j, k2 = (j + 1) % 3; + int v1 = F(k1, i); + int v2 = F(k2, i); + DEdge e2(v1, v2); + Vector2i diff2; + int rank2; + if (v1 > v2) { + rank2 = pos_rank(k2, i); + diff2 = + rshift90(Vector2i(-pos_index(k1 * 2, i), -pos_index(k1 * 2 + 1, i)), rank2); + } else { + rank2 = pos_rank(k1, i); + diff2 = rshift90(Vector2i(pos_index(k1 * 2, i), pos_index(k1 * 2 + 1, i)), rank2); + } + int current_eid = i * 3 + k1; + int eid = E2E[current_eid]; + int eID1 = face_edgeIds[current_eid / 3][current_eid % 3]; + int eID2 = -1; + if (eID1 == -1) { + eID2 = edge_values.size(); + edge_values.push_back(e2); + edge_diff.push_back(diff2); + face_edgeIds[i][k1] = eID2; + if (eid != -1) face_edgeIds[eid / 3][eid % 3] = eID2; + } else if (!singularities.count(i)) { + eID2 = face_edgeIds[eid / 3][eid % 3]; + edge_diff[eID2] = diff2; + } + } + } +} + +void Parametrizer::BuildIntegerConstraints() { + auto& F = hierarchy.mF; + auto& Q = hierarchy.mQ[0]; + auto& N = hierarchy.mN[0]; + face_edgeOrients.resize(F.cols()); + + //Random number generator (for shuffling) + std::random_device rd; + std::mt19937 g(rd()); + g.seed(hierarchy.rng_seed); + + // undirected edge to direct edge + std::vector> E2D(edge_diff.size(), std::make_pair(-1, -1)); + for (int i = 0; i < F.cols(); ++i) { + int v0 = F(0, i); + int v1 = F(1, i); + int v2 = F(2, i); + DEdge e0(v0, v1), e1(v1, v2), e2(v2, v0); + const Vector3i& eid = face_edgeIds[i]; + Vector2i variable_id[3]; + for (int i = 0; i < 3; ++i) { + variable_id[i] = Vector2i(eid[i] * 2 + 1, eid[i] * 2 + 2); + } + auto index1 = + compat_orientation_extrinsic_index_4(Q.col(v0), N.col(v0), Q.col(v1), N.col(v1)); + auto index2 = + compat_orientation_extrinsic_index_4(Q.col(v0), N.col(v0), Q.col(v2), N.col(v2)); + + int rank1 = (index1.first - index1.second + 4) % 4; // v1 -> v0 + int rank2 = (index2.first - index2.second + 4) % 4; // v2 -> v0 + int orients[3] = {0}; // == {0, 0, 0} + if (v1 < v0) { + variable_id[0] = -rshift90(variable_id[0], rank1); + orients[0] = (rank1 + 2) % 4; + } else { + orients[0] = 0; + } + if (v2 < v1) { + variable_id[1] = -rshift90(variable_id[1], rank2); + orients[1] = (rank2 + 2) % 4; + } else { + variable_id[1] = rshift90(variable_id[1], rank1); + orients[1] = rank1; + } + if (v2 < v0) { + variable_id[2] = rshift90(variable_id[2], rank2); + orients[2] = rank2; + } else { + variable_id[2] = -variable_id[2]; + orients[2] = 2; + } + face_edgeOrients[i] = Vector3i(orients[0], orients[1], orients[2]); + for (int j = 0; j < 3; ++j) { + int eid = face_edgeIds[i][j]; + if (E2D[eid].first == -1) + E2D[eid].first = i * 3 + j; + else + E2D[eid].second = i * 3 + j; + } + } + + // a face disajoint tree + DisajointOrientTree disajoint_orient_tree = DisajointOrientTree(F.cols()); + // merge the whole face graph except for the singularity in which there exists a spanning tree + // which contains consistent orientation + std::vector sharpUE(E2D.size()); + for (int i = 0; i < sharp_edges.size(); ++i) { + if (sharp_edges[i]) { + sharpUE[face_edgeIds[i / 3][i % 3]] = 1; + } + } + + for (int i = 0; i < E2D.size(); ++i) { + auto& edge_c = E2D[i]; + int f0 = edge_c.first / 3; + int f1 = edge_c.second / 3; + if (edge_c.first == -1 || edge_c.second == -1) continue; + if (singularities.count(f0) || singularities.count(f1) || sharpUE[i]) continue; + int orient1 = face_edgeOrients[f0][edge_c.first % 3]; + int orient0 = (face_edgeOrients[f1][edge_c.second % 3] + 2) % 4; + disajoint_orient_tree.Merge(f0, f1, orient0, orient1); + } + + // merge singularity later + for (auto& f : singularities) { + for (int i = 0; i < 3; ++i) { + if (sharpUE[face_edgeIds[f.first][i]]) continue; + auto& edge_c = E2D[face_edgeIds[f.first][i]]; + if (edge_c.first == -1 || edge_c.second == -1) continue; + int v0 = edge_c.first / 3; + int v1 = edge_c.second / 3; + int orient1 = face_edgeOrients[v0][edge_c.first % 3]; + int orient0 = (face_edgeOrients[v1][edge_c.second % 3] + 2) % 4; + disajoint_orient_tree.Merge(v0, v1, orient0, orient1); + } + } + + for (int i = 0; i < sharpUE.size(); ++i) { + if (sharpUE[i] == 0) continue; + auto& edge_c = E2D[i]; + if (edge_c.first == -1 || edge_c.second == -1) continue; + int f0 = edge_c.first / 3; + int f1 = edge_c.second / 3; + int orient1 = face_edgeOrients[f0][edge_c.first % 3]; + int orient0 = (face_edgeOrients[f1][edge_c.second % 3] + 2) % 4; + disajoint_orient_tree.Merge(f0, f1, orient0, orient1); + } + + // all the face has the same parent. we rotate every face to the space of that parent. + for (int i = 0; i < face_edgeOrients.size(); ++i) { + for (int j = 0; j < 3; ++j) { + face_edgeOrients[i][j] = + (face_edgeOrients[i][j] + disajoint_orient_tree.Orient(i)) % 4; + } + } + + std::vector sharp_colors(face_edgeIds.size(), -1); + int num_sharp_component = 0; + // label the connected component connected by non-fixed edges + // we need this because we need sink flow (demand) == source flow (supply) for each component + // rather than global + for (int i = 0; i < sharp_colors.size(); ++i) { + if (sharp_colors[i] != -1) continue; + sharp_colors[i] = num_sharp_component; + std::queue q; + q.push(i); + int counter = 0; + while (!q.empty()) { + int v = q.front(); + q.pop(); + for (int i = 0; i < 3; ++i) { + int e = face_edgeIds[v][i]; + int deid1 = E2D[e].first; + int deid2 = E2D[e].second; + if (deid1 == -1 || deid2 == -1) continue; + if (abs(face_edgeOrients[deid1 / 3][deid1 % 3] - + face_edgeOrients[deid2 / 3][deid2 % 3] + 4) % + 4 != + 2 || + sharpUE[e]) { + continue; + } + for (int k = 0; k < 2; ++k) { + int f = (k == 0) ? E2D[e].first / 3 : E2D[e].second / 3; + if (sharp_colors[f] == -1) { + sharp_colors[f] = num_sharp_component; + q.push(f); + } + } + } + counter += 1; + } + num_sharp_component += 1; + } + { + std::vector total_flows(num_sharp_component); + // check if each component is full-flow + for (int i = 0; i < face_edgeIds.size(); ++i) { + Vector2i diff(0, 0); + for (int j = 0; j < 3; ++j) { + int orient = face_edgeOrients[i][j]; + diff += rshift90(edge_diff[face_edgeIds[i][j]], orient); + } + total_flows[sharp_colors[i]] += diff[0] + diff[1]; + } + + // build "variable" + variables.resize(edge_diff.size() * 2, std::make_pair(Vector2i(-1, -1), 0)); + for (int i = 0; i < face_edgeIds.size(); ++i) { + for (int j = 0; j < 3; ++j) { + Vector2i sign = rshift90(Vector2i(1, 1), face_edgeOrients[i][j]); + int eid = face_edgeIds[i][j]; + Vector2i index = rshift90(Vector2i(eid * 2, eid * 2 + 1), face_edgeOrients[i][j]); + for (int k = 0; k < 2; ++k) { + auto& p = variables[abs(index[k])]; + if (p.first[0] == -1) + p.first[0] = i * 2 + k; + else + p.first[1] = i * 2 + k; + p.second += sign[k]; + } + } + } + + // fixed variable that might be manually modified. + // modified_variables[component_od][].first = fixed_variable_id + // modified_variables[component_od][].second = 1 if two positive signs -1 if two negative + // signs + std::vector>> modified_variables[2]; + for (int i = 0; i < 2; ++i) modified_variables[i].resize(total_flows.size()); + for (int i = 0; i < variables.size(); ++i) { + if ((variables[i].first[1] == -1 || variables[i].second != 0) && + allow_changes[i] == 1) { + int find = sharp_colors[variables[i].first[0] / 2]; + int step = std::abs(variables[i].second) % 2; + if (total_flows[find] > 0) { + if (variables[i].second > 0 && edge_diff[i / 2][i % 2] > -1) { + modified_variables[step][find].push_back(std::make_pair(i, -1)); + } + if (variables[i].second < 0 && edge_diff[i / 2][i % 2] < 1) { + modified_variables[step][find].push_back(std::make_pair(i, 1)); + } + } else if (total_flows[find] < 0) { + if (variables[i].second < 0 && edge_diff[i / 2][i % 2] > -1) { + modified_variables[step][find].push_back(std::make_pair(i, -1)); + } + if (variables[i].second > 0 && edge_diff[i / 2][i % 2] < 1) { + modified_variables[step][find].push_back(std::make_pair(i, 1)); + } + } + } + } + + // uniformly random manually modify variables so that the network has full flow. + for (int i = 0; i < 2; ++i) + for (auto& modified_var : modified_variables[i]) + std::shuffle(modified_var.begin(), modified_var.end(), g); + + for (int j = 0; j < total_flows.size(); ++j) { + for (int ii = 0; ii < 2; ++ii) { + if (total_flows[j] == 0) continue; + int max_num; + if (ii == 0) + max_num = + std::min(abs(total_flows[j]) / 2, (int)modified_variables[ii][j].size()); + else + max_num = std::min(abs(total_flows[j]), (int)modified_variables[ii][j].size()); + int dir = (total_flows[j] > 0) ? -1 : 1; + for (int i = 0; i < max_num; ++i) { + auto& info = modified_variables[ii][j][i]; + edge_diff[info.first / 2][info.first % 2] += info.second; + if (ii == 0) + total_flows[j] += 2 * dir; + else + total_flows[j] += dir; + } + } + } + } + + std::vector edge_to_constraints(E2D.size() * 2, Vector4i(-1, 0, -1, 0)); + for (int i = 0; i < face_edgeIds.size(); ++i) { + for (int j = 0; j < 3; ++j) { + int e = face_edgeIds[i][j]; + Vector2i index = rshift90(Vector2i(e * 2 + 1, e * 2 + 2), face_edgeOrients[i][j]); + for (int k = 0; k < 2; ++k) { + int l = abs(index[k]); + int s = index[k] / l; + int ind = l - 1; + int equationID = i * 2 + k; + if (edge_to_constraints[ind][0] == -1) { + edge_to_constraints[ind][0] = equationID; + edge_to_constraints[ind][1] = s; + } else { + edge_to_constraints[ind][2] = equationID; + edge_to_constraints[ind][3] = s; + } + } + } + } + std::vector> arcs; + std::vector arc_ids; + DisajointTree tree(face_edgeIds.size() * 2); + for (int i = 0; i < edge_to_constraints.size(); ++i) { + if (allow_changes[i] == 0) continue; + if (edge_to_constraints[i][0] == -1 || edge_to_constraints[i][2] == -1) continue; + if (edge_to_constraints[i][1] == -edge_to_constraints[i][3]) { + int v1 = edge_to_constraints[i][0]; + int v2 = edge_to_constraints[i][2]; + tree.Merge(v1, v2); + if (edge_to_constraints[i][1] < 0) std::swap(v1, v2); + int current_v = edge_diff[i / 2][i % 2]; + arcs.push_back(std::make_pair(Vector2i(v1, v2), current_v)); + } + } + tree.BuildCompactParent(); + std::vector total_flows(tree.CompactNum()); + // check if each component is full-flow + for (int i = 0; i < face_edgeIds.size(); ++i) { + Vector2i diff(0, 0); + for (int j = 0; j < 3; ++j) { + int orient = face_edgeOrients[i][j]; + diff += rshift90(edge_diff[face_edgeIds[i][j]], orient); + } + for (int j = 0; j < 2; ++j) { + total_flows[tree.Index(i * 2 + j)] += diff[j]; + } + } + + // build "variable" + variables.resize(edge_diff.size() * 2); + for (int i = 0; i < variables.size(); ++i) { + variables[i].first = Vector2i(-1, -1); + variables[i].second = 0; + } + for (int i = 0; i < face_edgeIds.size(); ++i) { + for (int j = 0; j < 3; ++j) { + Vector2i sign = rshift90(Vector2i(1, 1), face_edgeOrients[i][j]); + int eid = face_edgeIds[i][j]; + Vector2i index = rshift90(Vector2i(eid * 2, eid * 2 + 1), face_edgeOrients[i][j]); + for (int k = 0; k < 2; ++k) { + auto& p = variables[abs(index[k])]; + if (p.first[0] == -1) + p.first[0] = i * 2 + k; + else + p.first[1] = i * 2 + k; + p.second += sign[k]; + } + } + } + + // fixed variable that might be manually modified. + // modified_variables[component_od][].first = fixed_variable_id + // modified_variables[component_od][].second = 1 if two positive signs -1 if two negative signs + std::vector>> modified_variables[2]; + for (int i = 0; i < 2; ++i) { + modified_variables[i].resize(total_flows.size()); + } + for (int i = 0; i < variables.size(); ++i) { + if ((variables[i].first[1] == -1 || variables[i].second != 0) && allow_changes[i] == 1) { + int find = tree.Index(variables[i].first[0]); + int step = abs(variables[i].second) % 2; + if (total_flows[find] > 0) { + if (variables[i].second > 0 && edge_diff[i / 2][i % 2] > -1) { + modified_variables[step][find].push_back(std::make_pair(i, -1)); + } + if (variables[i].second < 0 && edge_diff[i / 2][i % 2] < 1) { + modified_variables[step][find].push_back(std::make_pair(i, 1)); + } + } else if (total_flows[find] < 0) { + if (variables[i].second < 0 && edge_diff[i / 2][i % 2] > -1) { + modified_variables[step][find].push_back(std::make_pair(i, -1)); + } + if (variables[i].second > 0 && edge_diff[i / 2][i % 2] < 1) { + modified_variables[step][find].push_back(std::make_pair(i, 1)); + } + } + } + } + + // uniformly random manually modify variables so that the network has full flow. + for (int j = 0; j < 2; ++j) { + for (auto& modified_var : modified_variables[j]) + std::shuffle(modified_var.begin(), modified_var.end(), g); + } + for (int j = 0; j < total_flows.size(); ++j) { + for (int ii = 0; ii < 2; ++ii) { + if (total_flows[j] == 0) continue; + int max_num; + if (ii == 0) + max_num = std::min(abs(total_flows[j]) / 2, (int)modified_variables[ii][j].size()); + else + max_num = std::min(abs(total_flows[j]), (int)modified_variables[ii][j].size()); + int dir = (total_flows[j] > 0) ? -1 : 1; + for (int i = 0; i < max_num; ++i) { + auto& info = modified_variables[ii][j][i]; + edge_diff[info.first / 2][info.first % 2] += info.second; + if (ii == 0) + total_flows[j] += 2 * dir; + else + total_flows[j] += dir; + } + } + } +} + +void Parametrizer::ComputeMaxFlow() { + hierarchy.DownsampleEdgeGraph(face_edgeOrients, face_edgeIds, edge_diff, allow_changes, 1); + Optimizer::optimize_integer_constraints(hierarchy, singularities, flag_minimum_cost_flow); + hierarchy.UpdateGraphValue(face_edgeOrients, face_edgeIds, edge_diff); +} + +} // namespace qflow diff --git a/extern/quadriflow/src/parametrizer-mesh.cpp b/extern/quadriflow/src/parametrizer-mesh.cpp new file mode 100644 index 00000000000..19effe92390 --- /dev/null +++ b/extern/quadriflow/src/parametrizer-mesh.cpp @@ -0,0 +1,615 @@ +#include "config.hpp" +#include "dedge.hpp" +#include "field-math.hpp" +#include "loader.hpp" +#include "merge-vertex.hpp" +#include "parametrizer.hpp" +#include "subdivide.hpp" +#include "dedge.hpp" +#include + +namespace qflow { + +void Parametrizer::NormalizeMesh() { + double maxV[3] = {-1e30, -1e30, -1e30}; + double minV[3] = {1e30, 1e30, 1e30}; + + for (int i = 0; i < V.cols(); ++i) { + for (int j = 0; j < 3; ++j) { + maxV[j] = std::max(maxV[j], V(j, i)); + minV[j] = std::min(minV[j], V(j, i)); + } + } + double scale = + std::max(std::max(maxV[0] - minV[0], maxV[1] - minV[1]), maxV[2] - minV[2]) * 0.5; +#ifdef WITH_OMP +#pragma omp parallel for +#endif + for (int i = 0; i < V.cols(); ++i) { + for (int j = 0; j < 3; ++j) { + V(j, i) = (V(j, i) - (maxV[j] + minV[j]) * 0.5) / scale; + } + } +#ifdef LOG_OUTPUT + printf("vertices size: %d\n", (int)V.cols()); + printf("faces size: %d\n", (int)F.cols()); +#endif + this->normalize_scale = scale; + this->normalize_offset = Vector3d(0.5 * (maxV[0] + minV[0]), 0.5 * (maxV[1] + minV[1]), 0.5 * (maxV[2] + minV[2])); + // merge_close(V, F, 1e-6); +} + +void Parametrizer::Load(const char* filename) { + load(filename, V, F); + NormalizeMesh(); +} + +void Parametrizer::Initialize(int faces) { + ComputeMeshStatus(); + //ComputeCurvature(V, F, rho); + rho.resize(V.cols(), 1); + for (int i = 0; i < V.cols(); ++i) { + rho[i] = 1; + } +#ifdef PERFORMANCE_TEST + scale = sqrt(surface_area / (V.cols() * 10)); +#else + if (faces <= 0) { + scale = sqrt(surface_area / V.cols()); + } else { + scale = std::sqrt(surface_area / faces); + } +#endif + double target_len = std::min(scale / 2, average_edge_length * 2); +#ifdef PERFORMANCE_TEST + scale = sqrt(surface_area / V.cols()); +#endif + + if (target_len < max_edge_length) { + while (!compute_direct_graph(V, F, V2E, E2E, boundary, nonManifold)) + ; + subdivide(F, V, rho, V2E, E2E, boundary, nonManifold, target_len); + } + + while (!compute_direct_graph(V, F, V2E, E2E, boundary, nonManifold)) + ; + generate_adjacency_matrix_uniform(F, V2E, E2E, nonManifold, adj); + + for (int iter = 0; iter < 5; ++iter) { + VectorXd r(rho.size()); + for (int i = 0; i < rho.size(); ++i) { + r[i] = rho[i]; + for (auto& id : adj[i]) { + r[i] = std::min(r[i], rho[id.id]); + } + } + rho = r; + } + ComputeSharpEdges(); + ComputeSmoothNormal(); + ComputeVertexArea(); + + if (flag_adaptive_scale) + ComputeInverseAffine(); + +#ifdef LOG_OUTPUT + printf("V: %d F: %d\n", (int)V.cols(), (int)F.cols()); +#endif + hierarchy.mA[0] = std::move(A); + hierarchy.mAdj[0] = std::move(adj); + hierarchy.mN[0] = std::move(N); + hierarchy.mV[0] = std::move(V); + hierarchy.mE2E = std::move(E2E); + hierarchy.mF = std::move(F); + hierarchy.Initialize(scale, flag_adaptive_scale); +} + +void Parametrizer::ComputeMeshStatus() { + surface_area = 0; + average_edge_length = 0; + max_edge_length = 0; + for (int f = 0; f < F.cols(); ++f) { + Vector3d v[3] = {V.col(F(0, f)), V.col(F(1, f)), V.col(F(2, f))}; + double area = 0.5f * (v[1] - v[0]).cross(v[2] - v[0]).norm(); + surface_area += area; + for (int i = 0; i < 3; ++i) { + double len = (v[(i + 1) % 3] - v[i]).norm(); + average_edge_length += len; + if (len > max_edge_length) max_edge_length = len; + } + } + average_edge_length /= (F.cols() * 3); +} + +void Parametrizer::ComputeSharpEdges() { + sharp_edges.resize(F.cols() * 3, 0); + + if (flag_preserve_boundary) { + for (int i = 0; i < sharp_edges.size(); ++i) { + int re = E2E[i]; + if (re == -1) { + sharp_edges[i] = 1; + } + } + } + + if (flag_preserve_sharp == 0) + return; + + std::vector face_normals(F.cols()); + for (int i = 0; i < F.cols(); ++i) { + Vector3d p1 = V.col(F(0, i)); + Vector3d p2 = V.col(F(1, i)); + Vector3d p3 = V.col(F(2, i)); + face_normals[i] = (p2 - p1).cross(p3 - p1).normalized(); + } + + double cos_thres = cos(60.0/180.0*3.141592654); + for (int i = 0; i < sharp_edges.size(); ++i) { + int e = i; + int re = E2E[e]; + Vector3d& n1 = face_normals[e/3]; + Vector3d& n2 = face_normals[re/3]; + if (n1.dot(n2) < cos_thres) { + sharp_edges[i] = 1; + } + } +} + +void Parametrizer::ComputeSharpO() { + auto& F = hierarchy.mF; + auto& V = hierarchy.mV[0]; + auto& O = hierarchy.mO[0]; + auto& E2E = hierarchy.mE2E; + DisajointTree tree(V.cols()); + for (int i = 0; i < edge_diff.size(); ++i) { + if (edge_diff[i][0] == 0 && edge_diff[i][1] == 0) { + tree.Merge(edge_values[i].x, edge_values[i].y); + } + } + std::map > edge_normals; + for (int i = 0; i < F.cols(); ++i) { + int pv[] = {tree.Parent(F(0, i)), tree.Parent(F(1, i)), tree.Parent(F(2, i))}; + if (pv[0] == pv[1] || pv[1] == pv[2] || pv[2] == pv[0]) + continue; + DEdge e[] = {DEdge(pv[0], pv[1]), DEdge(pv[1], pv[2]), DEdge(pv[2], pv[0])}; + Vector3d d1 = O.col(F(1, i)) - O.col(F(0, i)); + Vector3d d2 = O.col(F(2, i)) - O.col(F(0, i)); + Vector3d n = d1.cross(d2).normalized(); + for (int j = 0; j < 3; ++j) { + if (edge_normals.count(e[j]) == 0) + edge_normals[e[j]] = std::vector(); + edge_normals[e[j]].push_back(n); + } + } + std::map sharps; + for (auto& info : edge_normals) { + auto& normals = info.second; + bool sharp = false; + for (int i = 0; i < normals.size(); ++i) { + for (int j = i + 1; j < normals.size(); ++j) { + if (normals[i].dot(normals[j]) < cos(60.0 / 180.0 * 3.141592654)) { + sharp = true; + break; + } + } + if (sharp) + break; + } + if (sharp) { + int s = sharps.size(); + sharps[info.first] = s; + } + } + for (auto& s : sharp_edges) + s = 0; + std::vector sharp_hash(sharps.size(), 0); + for (int i = 0; i < F.cols(); ++i) { + for (int j = 0; j < 3; ++j) { + int v1 = tree.Parent(F(j, i)); + int v2 = tree.Parent(F((j + 1) % 3, i)); + DEdge e(v1, v2); + if (sharps.count(e) == 0) + continue; + int id = sharps[e]; + if (sharp_hash[id]) + continue; + sharp_hash[id] = 1; + sharp_edges[i * 3 + j] = 1; + sharp_edges[E2E[i * 3 + j]] = 1; + } + } + +} + +void Parametrizer::ComputeSmoothNormal() { + /* Compute face normals */ + Nf.resize(3, F.cols()); +#ifdef WITH_OMP +#pragma omp parallel for +#endif + for (int f = 0; f < F.cols(); ++f) { + Vector3d v0 = V.col(F(0, f)), v1 = V.col(F(1, f)), v2 = V.col(F(2, f)), + n = (v1 - v0).cross(v2 - v0); + double norm = n.norm(); + if (norm < RCPOVERFLOW) { + n = Vector3d::UnitX(); + } else { + n /= norm; + } + Nf.col(f) = n; + } + + N.resize(3, V.cols()); +#ifdef WITH_OMP +#pragma omp parallel for +#endif + for (int i = 0; i < V2E.rows(); ++i) { + int edge = V2E[i]; + if (nonManifold[i] || edge == -1) { + N.col(i) = Vector3d::UnitX(); + continue; + } + + + int stop = edge; + do { + if (sharp_edges[edge]) + break; + edge = E2E[edge]; + if (edge != -1) + edge = dedge_next_3(edge); + } while (edge != stop && edge != -1); + if (edge == -1) + edge = stop; + else + stop = edge; + Vector3d normal = Vector3d::Zero(); + do { + int idx = edge % 3; + + Vector3d d0 = V.col(F((idx + 1) % 3, edge / 3)) - V.col(i); + Vector3d d1 = V.col(F((idx + 2) % 3, edge / 3)) - V.col(i); + double angle = fast_acos(d0.dot(d1) / std::sqrt(d0.squaredNorm() * d1.squaredNorm())); + + /* "Computing Vertex Normals from Polygonal Facets" + by Grit Thuermer and Charles A. Wuethrich, JGT 1998, Vol 3 */ + if (std::isfinite(angle)) normal += Nf.col(edge / 3) * angle; + + int opp = E2E[edge]; + if (opp == -1) break; + + edge = dedge_next_3(opp); + if (sharp_edges[edge]) + break; + } while (edge != stop); + double norm = normal.norm(); + N.col(i) = norm > RCPOVERFLOW ? Vector3d(normal / norm) : Vector3d::UnitX(); + } +} + +void Parametrizer::ComputeVertexArea() { + A.resize(V.cols()); + A.setZero(); + +#ifdef WITH_OMP +#pragma omp parallel for +#endif + for (int i = 0; i < V2E.size(); ++i) { + int edge = V2E[i], stop = edge; + if (nonManifold[i] || edge == -1) continue; + double vertex_area = 0; + do { + int ep = dedge_prev_3(edge), en = dedge_next_3(edge); + + Vector3d v = V.col(F(edge % 3, edge / 3)); + Vector3d vn = V.col(F(en % 3, en / 3)); + Vector3d vp = V.col(F(ep % 3, ep / 3)); + + Vector3d face_center = (v + vp + vn) * (1.0f / 3.0f); + Vector3d prev = (v + vp) * 0.5f; + Vector3d next = (v + vn) * 0.5f; + + vertex_area += 0.5f * ((v - prev).cross(v - face_center).norm() + + (v - next).cross(v - face_center).norm()); + + int opp = E2E[edge]; + if (opp == -1) break; + edge = dedge_next_3(opp); + } while (edge != stop); + + A[i] = vertex_area; + } +} + +void Parametrizer::FixValence() +{ + // Remove Valence 2 + while (true) { + bool update = false; + std::vector marks(V2E_compact.size(), 0); + std::vector erasedF(F_compact.size(), 0); + for (int i = 0; i < V2E_compact.size(); ++i) { + int deid0 = V2E_compact[i]; + if (marks[i] || deid0 == -1) + continue; + int deid = deid0; + std::vector dedges; + do { + dedges.push_back(deid); + int deid1 = deid / 4 * 4 + (deid + 3) % 4; + deid = E2E_compact[deid1]; + } while (deid != deid0 && deid != -1); + if (dedges.size() == 2) { + int v1 = F_compact[dedges[0]/4][(dedges[0] + 1)%4]; + int v2 = F_compact[dedges[0]/4][(dedges[0] + 2)%4]; + int v3 = F_compact[dedges[1]/4][(dedges[1] + 1)%4]; + int v4 = F_compact[dedges[1]/4][(dedges[1] + 2)%4]; + if (marks[v1] || marks[v2] || marks[v3] || marks[v4]) + continue; + marks[v1] = true; + marks[v2] = true; + marks[v3] = true; + marks[v4] = true; + if (v1 == v2 || v1 == v3 || v1 == v4 || v2 == v3 || v2 == v4 || v3 == v4) { + erasedF[dedges[0]/4] = 1; + } else { + F_compact[dedges[0]/4] = Vector4i(v1, v2, v3, v4); + } + erasedF[dedges[1]/4] = 1; + update = true; + } + } + if (update) { + int top = 0; + for (int i = 0; i < erasedF.size(); ++i) { + if (erasedF[i] == 0) { + F_compact[top++] = F_compact[i]; + } + } + F_compact.resize(top); + compute_direct_graph_quad(O_compact, F_compact, V2E_compact, E2E_compact, boundary_compact, + nonManifold_compact); + } else { + break; + } + } + std::vector > v_dedges(V2E_compact.size()); + for (int i = 0; i < F_compact.size(); ++i) { + for (int j = 0; j < 4; ++j) { + v_dedges[F_compact[i][j]].push_back(i * 4 + j); + } + } + int top = V2E_compact.size(); + for (int i = 0; i < v_dedges.size(); ++i) { + std::map groups; + int group_id = 0; + for (int j = 0; j < v_dedges[i].size(); ++j) { + int deid = v_dedges[i][j]; + if (groups.count(deid)) + continue; + int deid0 = deid; + do { + groups[deid] = group_id; + deid = deid / 4 * 4 + (deid + 3) % 4; + deid = E2E_compact[deid]; + } while (deid != deid0 && deid != -1); + if (deid == -1) { + deid = deid0; + while (E2E_compact[deid] != -1) { + deid = E2E_compact[deid]; + deid = deid / 4 * 4 + (deid + 1) % 4; + groups[deid] = group_id; + } + } + group_id += 1; + } + if (group_id > 1) { + for (auto& g : groups) { + if (g.second >= 1) + F_compact[g.first/4][g.first%4] = top - 1 + g.second; + } + for (int j = 1; j < group_id; ++j) { + Vset.push_back(Vset[i]); + N_compact.push_back(N_compact[i]); + Q_compact.push_back(Q_compact[i]); + O_compact.push_back(O_compact[i]); + } + top = O_compact.size(); + } + } + compute_direct_graph_quad(O_compact, F_compact, V2E_compact, E2E_compact, boundary_compact, + nonManifold_compact); + + // Decrease Valence + while (true) { + bool update = false; + std::vector marks(V2E_compact.size(), 0); + std::vector valences(V2E_compact.size(), 0); + for (int i = 0; i < V2E_compact.size(); ++i) { + int deid0 = V2E_compact[i]; + if (deid0 == -1) + continue; + int deid = deid0; + int count = 0; + do { + count += 1; + int deid1 = E2E_compact[deid]; + if (deid1 == -1) { + count += 1; + break; + } + deid = deid1 / 4 * 4 + (deid1 + 1) % 4; + } while (deid != deid0 && deid != -1); + if (deid == -1) + count += 1; + valences[i] = count; + } + std::priority_queue > prior_queue; + for (int i = 0; i < valences.size(); ++i) { + if (valences[i] > 5) + prior_queue.push(std::make_pair(valences[i], i)); + } + while (!prior_queue.empty()) { + auto info = prior_queue.top(); + prior_queue.pop(); + if (marks[info.second]) + continue; + int deid0 = V2E_compact[info.second]; + if (deid0 == -1) + continue; + int deid = deid0; + std::vector loop_vertices, loop_dedges;; + bool marked = false; + do { + int v = F_compact[deid/4][(deid+1)%4]; + loop_dedges.push_back(deid); + loop_vertices.push_back(v); + if (marks[v]) + marked = true; + int deid1 = E2E_compact[deid]; + if (deid1 == -1) + break; + deid = deid1 / 4 * 4 + (deid1 + 1) % 4; + } while (deid != deid0 && deid != -1); + if (marked) + continue; + + if (deid != -1) { + int step = (info.first + 1) / 2; + std::pair min_val(0x7fffffff, 0x7fffffff); + int split_idx = -1; + for (int i = 0; i < loop_vertices.size(); ++i) { + if (i + step >= loop_vertices.size()) + continue; + int v1 = valences[loop_vertices[i]]; + int v2 = valences[loop_vertices[i + step]]; + if (v1 < v2) + std::swap(v1, v2); + auto key = std::make_pair(v1, v2); + if (key < min_val) { + min_val = key; + split_idx = i + 1; + } + } + if (min_val.first >= info.first) + continue; + update = true; + for (int id = split_idx; id < split_idx + step; ++id) { + F_compact[loop_dedges[id]/4][loop_dedges[id]%4] = O_compact.size(); + } + F_compact.push_back(Vector4i(O_compact.size(), loop_vertices[(split_idx+loop_vertices.size()-1)%loop_vertices.size()],info.second, loop_vertices[(split_idx + step - 1 + loop_vertices.size()) % loop_vertices.size()])); + } else { + for (int id = loop_vertices.size() / 2; id < loop_vertices.size(); ++id) { + F_compact[loop_dedges[id]/4][loop_dedges[id]%4] = O_compact.size(); + } + update = true; + } + marks[info.second] = 1; + for (int i = 0; i < loop_vertices.size(); ++i) { + marks[loop_vertices[i]] = 1; + } + Vset.push_back(Vset[info.second]); + O_compact.push_back(O_compact[info.second]); + N_compact.push_back(N_compact[info.second]); + Q_compact.push_back(Q_compact[info.second]); + } + if (!update) { + break; + } else { + compute_direct_graph_quad(O_compact, F_compact, V2E_compact, E2E_compact, boundary_compact, + nonManifold_compact); + } + } + // Remove Zero Valence + std::vector valences(V2E_compact.size(), 0); + for (int i = 0; i < F_compact.size(); ++i) { + for (int j = 0; j < 4; ++j) { + valences[F_compact[i][j]] = 1; + } + } + top = 0; + std::vector compact_indices(valences.size()); + for (int i = 0; i < valences.size(); ++i) { + if (valences[i] == 0) + continue; + N_compact[top] = N_compact[i]; + O_compact[top] = O_compact[i]; + Q_compact[top] = Q_compact[i]; + Vset[top] = Vset[i]; + compact_indices[i] = top; + top += 1; + } + for (int i = 0; i < F_compact.size(); ++i) { + for (int j = 0; j < 4; ++j) { + F_compact[i][j] = compact_indices[F_compact[i][j]]; + } + } + N_compact.resize(top); + O_compact.resize(top); + Q_compact.resize(top); + Vset.resize(top); + compute_direct_graph_quad(O_compact, F_compact, V2E_compact, E2E_compact, boundary_compact, + nonManifold_compact); + { + compute_direct_graph_quad(O_compact, F_compact, V2E_compact, E2E_compact, boundary_compact, + nonManifold_compact); + std::vector masks(F_compact.size() * 4, 0); + for (int i = 0; i < V2E_compact.size(); ++i) { + int deid0 = V2E_compact[i]; + if (deid0 == -1) + continue; + int deid = deid0; + do { + masks[deid] = 1; + deid = E2E_compact[deid]; + if (deid == -1) { + break; + } + deid = deid / 4 * 4 + (deid + 1) % 4; + } while (deid != deid0 && deid != -1); + } + std::vector > v_dedges(V2E_compact.size()); + for (int i = 0; i < F_compact.size(); ++i) { + for (int j = 0; j < 4; ++j) { + v_dedges[F_compact[i][j]].push_back(i * 4 + j); + } + } + } + std::map pts; + for (int i = 0; i < V2E_compact.size(); ++i) { + int deid0 = V2E_compact[i]; + if (deid0 == -1) + continue; + int deid = deid0; + int count = 0; + do { + count += 1; + int deid1 = E2E_compact[deid]; + if (deid1 == -1) + break; + deid = deid1 / 4 * 4 + (deid1 + 1) % 4; + } while (deid != deid0 && deid != -1); + if (pts.count(count) == 0) + pts[count] = 1; + else + pts[count] += 1; + } + return; +} + +void Parametrizer::OutputMesh(const char* obj_name) { + std::ofstream os(obj_name); + for (int i = 0; i < O_compact.size(); ++i) { + auto t = O_compact[i] * this->normalize_scale + this->normalize_offset; + os << "v " << t[0] << " " << t[1] << " " << t[2] << "\n"; + } + for (int i = 0; i < F_compact.size(); ++i) { + os << "f " << F_compact[i][0]+1 << " " << F_compact[i][1]+1 + << " " << F_compact[i][2]+1 << " " << F_compact[i][3]+1 + << "\n"; + } + os.close(); +} + +} // namespace qflow diff --git a/extern/quadriflow/src/parametrizer-scale.cpp b/extern/quadriflow/src/parametrizer-scale.cpp new file mode 100644 index 00000000000..bbd901d08c9 --- /dev/null +++ b/extern/quadriflow/src/parametrizer-scale.cpp @@ -0,0 +1,119 @@ +#include "parametrizer.hpp" + +namespace qflow { + +void Parametrizer::ComputeInverseAffine() +{ + if (flag_adaptive_scale == 0) + return; + triangle_space.resize(F.cols()); +#ifdef WITH_OMP +#pragma omp parallel for +#endif + for (int i = 0; i < F.cols(); ++i) { + Matrix3d p, q; + p.col(0) = V.col(F(1, i)) - V.col(F(0, i)); + p.col(1) = V.col(F(2, i)) - V.col(F(0, i)); + p.col(2) = Nf.col(i); + q = p.inverse(); + triangle_space[i].resize(2, 3); + for (int j = 0; j < 2; ++j) { + for (int k = 0; k < 3; ++k) { + triangle_space[i](j, k) = q(j, k); + } + } + } +} + +void Parametrizer::EstimateSlope() { + auto& mF = hierarchy.mF; + auto& mQ = hierarchy.mQ[0]; + auto& mN = hierarchy.mN[0]; + auto& mV = hierarchy.mV[0]; + FS.resize(2, mF.cols()); + FQ.resize(3, mF.cols()); + for (int i = 0; i < mF.cols(); ++i) { + const Vector3d& n = Nf.col(i); + const Vector3d &q_1 = mQ.col(mF(0, i)), &q_2 = mQ.col(mF(1, i)), &q_3 = mQ.col(mF(2, i)); + const Vector3d &n_1 = mN.col(mF(0, i)), &n_2 = mN.col(mF(1, i)), &n_3 = mN.col(mF(2, i)); + Vector3d q_1n = rotate_vector_into_plane(q_1, n_1, n); + Vector3d q_2n = rotate_vector_into_plane(q_2, n_2, n); + Vector3d q_3n = rotate_vector_into_plane(q_3, n_3, n); + + auto p = compat_orientation_extrinsic_4(q_1n, n, q_2n, n); + Vector3d q = (p.first + p.second).normalized(); + p = compat_orientation_extrinsic_4(q, n, q_3n, n); + q = (p.first * 2 + p.second); + q = q - n * q.dot(n); + FQ.col(i) = q.normalized(); + } + for (int i = 0; i < mF.cols(); ++i) { + double step = hierarchy.mScale * 1.f; + + const Vector3d &n = Nf.col(i); + Vector3d p = (mV.col(mF(0, i)) + mV.col(mF(1, i)) + mV.col(mF(2, i))) * (1.0 / 3.0); + Vector3d q_x = FQ.col(i), q_y = n.cross(q_x); + Vector3d q_xl = -q_x, q_xr = q_x; + Vector3d q_yl = -q_y, q_yr = q_y; + Vector3d q_yl_unfold = q_y, q_yr_unfold = q_y, q_xl_unfold = q_x, q_xr_unfold = q_x; + int f; + double tx, ty, len; + + f = i; len = step; + TravelField(p, q_xl, len, f, hierarchy.mE2E, mV, mF, Nf, FQ, mQ, mN, triangle_space, &tx, &ty, &q_yl_unfold); + + f = i; len = step; + TravelField(p, q_xr, len, f, hierarchy.mE2E, mV, mF, Nf, FQ, mQ, mN, triangle_space, &tx, &ty, &q_yr_unfold); + + f = i; len = step; + TravelField(p, q_yl, len, f, hierarchy.mE2E, mV, mF, Nf, FQ, mQ, mN, triangle_space, &tx, &ty, &q_xl_unfold); + + f = i; len = step; + TravelField(p, q_yr, len, f, hierarchy.mE2E, mV, mF, Nf, FQ, mQ, mN, triangle_space, &tx, &ty, &q_xr_unfold); + double dSx = (q_yr_unfold - q_yl_unfold).dot(q_x) / (2.0f * step); + double dSy = (q_xr_unfold - q_xl_unfold).dot(q_y) / (2.0f * step); + FS.col(i) = Vector2d(dSx, dSy); + } + + std::vector areas(mV.cols(), 0.0); + for (int i = 0; i < mF.cols(); ++i) { + Vector3d p1 = mV.col(mF(1, i)) - mV.col(mF(0, i)); + Vector3d p2 = mV.col(mF(2, i)) - mV.col(mF(0, i)); + double area = p1.cross(p2).norm(); + for (int j = 0; j < 3; ++j) { + auto index = compat_orientation_extrinsic_index_4(FQ.col(i), Nf.col(i), mQ.col(mF(j, i)), mN.col(mF(j, i))); + double scaleX = FS.col(i).x(), scaleY = FS.col(i).y(); + if (index.first != index.second % 2) { + std::swap(scaleX, scaleY); + } + if (index.second >= 2) { + scaleX = -scaleX; + scaleY = -scaleY; + } + hierarchy.mK[0].col(mF(j, i)) += area * Vector2d(scaleX, scaleY); + areas[mF(j, i)] += area; + } + } + for (int i = 0; i < mV.cols(); ++i) { + if (areas[i] != 0) + hierarchy.mK[0].col(i) /= areas[i]; + } + for (int l = 0; l< hierarchy.mK.size() - 1; ++l) { + const MatrixXd &K = hierarchy.mK[l]; + MatrixXd &K_next = hierarchy.mK[l + 1]; + auto& toUpper = hierarchy.mToUpper[l]; + for (int i = 0; i < toUpper.cols(); ++i) { + Vector2i upper = toUpper.col(i); + Vector2d k0 = K.col(upper[0]); + + if (upper[1] != -1) { + Vector2d k1 = K.col(upper[1]); + k0 = 0.5 * (k0 + k1); + } + + K_next.col(i) = k0; + } + } +} + +} // namespace qflow diff --git a/extern/quadriflow/src/parametrizer-sing.cpp b/extern/quadriflow/src/parametrizer-sing.cpp new file mode 100644 index 00000000000..2d600e3cda4 --- /dev/null +++ b/extern/quadriflow/src/parametrizer-sing.cpp @@ -0,0 +1,142 @@ +#include "config.hpp" +#include "field-math.hpp" +#include "parametrizer.hpp" + +namespace qflow { + +void Parametrizer::ComputeOrientationSingularities() { + MatrixXd &N = hierarchy.mN[0], &Q = hierarchy.mQ[0]; + const MatrixXi& F = hierarchy.mF; + singularities.clear(); + for (int f = 0; f < F.cols(); ++f) { + int index = 0; + int abs_index = 0; + for (int k = 0; k < 3; ++k) { + int i = F(k, f), j = F(k == 2 ? 0 : (k + 1), f); + auto value = + compat_orientation_extrinsic_index_4(Q.col(i), N.col(i), Q.col(j), N.col(j)); + index += value.second - value.first; + abs_index += std::abs(value.second - value.first); + } + int index_mod = modulo(index, 4); + if (index_mod == 1 || index_mod == 3) { + if (index >= 4 || index < 0) { + Q.col(F(0, f)) = -Q.col(F(0, f)); + } + singularities[f] = index_mod; + } + } +} + +void Parametrizer::ComputePositionSingularities() { + const MatrixXd &V = hierarchy.mV[0], &N = hierarchy.mN[0], &Q = hierarchy.mQ[0], + &O = hierarchy.mO[0]; + const MatrixXi& F = hierarchy.mF; + + pos_sing.clear(); + pos_rank.resize(F.rows(), F.cols()); + pos_index.resize(6, F.cols()); + for (int f = 0; f < F.cols(); ++f) { + Vector2i index = Vector2i::Zero(); + uint32_t i0 = F(0, f), i1 = F(1, f), i2 = F(2, f); + + Vector3d q[3] = {Q.col(i0).normalized(), Q.col(i1).normalized(), Q.col(i2).normalized()}; + Vector3d n[3] = {N.col(i0), N.col(i1), N.col(i2)}; + Vector3d o[3] = {O.col(i0), O.col(i1), O.col(i2)}; + Vector3d v[3] = {V.col(i0), V.col(i1), V.col(i2)}; + + int best[3]; + double best_dp = -std::numeric_limits::infinity(); + for (int i = 0; i < 4; ++i) { + Vector3d v0 = rotate90_by(q[0], n[0], i); + for (int j = 0; j < 4; ++j) { + Vector3d v1 = rotate90_by(q[1], n[1], j); + for (int k = 0; k < 4; ++k) { + Vector3d v2 = rotate90_by(q[2], n[2], k); + double dp = std::min(std::min(v0.dot(v1), v1.dot(v2)), v2.dot(v0)); + if (dp > best_dp) { + best_dp = dp; + best[0] = i; + best[1] = j; + best[2] = k; + } + } + } + } + pos_rank(0, f) = best[0]; + pos_rank(1, f) = best[1]; + pos_rank(2, f) = best[2]; + for (int k = 0; k < 3; ++k) q[k] = rotate90_by(q[k], n[k], best[k]); + + for (int k = 0; k < 3; ++k) { + int kn = k == 2 ? 0 : (k + 1); + double scale_x = hierarchy.mScale, scale_y = hierarchy.mScale, + scale_x_1 = hierarchy.mScale, scale_y_1 = hierarchy.mScale; + if (flag_adaptive_scale) { + scale_x *= hierarchy.mS[0](0, F(k, f)); + scale_y *= hierarchy.mS[0](1, F(k, f)); + scale_x_1 *= hierarchy.mS[0](0, F(kn, f)); + scale_y_1 *= hierarchy.mS[0](1, F(kn, f)); + if (best[k] % 2 != 0) std::swap(scale_x, scale_y); + if (best[kn] % 2 != 0) std::swap(scale_x_1, scale_y_1); + } + double inv_scale_x = 1.0 / scale_x, inv_scale_y = 1.0 / scale_y, + inv_scale_x_1 = 1.0 / scale_x_1, inv_scale_y_1 = 1.0 / scale_y_1; + std::pair value = compat_position_extrinsic_index_4( + v[k], n[k], q[k], o[k], v[kn], n[kn], q[kn], o[kn], scale_x, scale_y, inv_scale_x, + inv_scale_y, scale_x_1, scale_y_1, inv_scale_x_1, inv_scale_y_1, nullptr); + auto diff = value.first - value.second; + index += diff; + pos_index(k * 2, f) = diff[0]; + pos_index(k * 2 + 1, f) = diff[1]; + } + + if (index != Vector2i::Zero()) { + pos_sing[f] = rshift90(index, best[0]); + } + } +} + +void Parametrizer::AnalyzeValence() { + auto& F = hierarchy.mF; + std::map sing; + for (auto& f : singularities) { + for (int i = 0; i < 3; ++i) { + sing[F(i, f.first)] = f.second; + } + } + auto& F2E = face_edgeIds; + auto& E2E = hierarchy.mE2E; + auto& FQ = face_edgeOrients; + std::set sing1, sing2; + for (int i = 0; i < F2E.size(); ++i) { + for (int j = 0; j < 3; ++j) { + int deid = i * 3 + j; + int sum_int = 0; + std::vector edges; + std::vector angles; + do { + int deid1 = deid / 3 * 3 + (deid + 2) % 3; + deid = E2E[deid1]; + sum_int += (FQ[deid / 3][deid % 3] + 6 - FQ[deid1 / 3][deid1 % 3]) % 4; + } while (deid != i * 3 + j); + if (sum_int % 4 == 2) { + printf("OMG! valence = 2\n"); + exit(0); + } + if (sum_int % 4 == 1) sing1.insert(F(j, i)); + if (sum_int % 4 == 3) sing2.insert(F(j, i)); + } + } + int count3 = 0, count4 = 0; + for (auto& s : singularities) { + if (s.second == 1) + count3 += 1; + else + count4 += 1; + } + printf("singularity: <%d %d> <%d %d>\n", (int)sing1.size(), (int)sing2.size(), count3, count4); +} + + +} // namespace qflow diff --git a/extern/quadriflow/src/parametrizer.cpp b/extern/quadriflow/src/parametrizer.cpp new file mode 100644 index 00000000000..b85383566c9 --- /dev/null +++ b/extern/quadriflow/src/parametrizer.cpp @@ -0,0 +1,247 @@ +#include "parametrizer.hpp" +#include "config.hpp" +#include "dedge.hpp" +#include "field-math.hpp" +#include "flow.hpp" +#include "localsat.hpp" +#include "optimizer.hpp" +#include "subdivide.hpp" + +#include "dset.hpp" + +#include +#include +#include +#include +#include +#include + +namespace qflow { + +void Parametrizer::ComputeIndexMap(int with_scale) { + // build edge info + auto& V = hierarchy.mV[0]; + auto& F = hierarchy.mF; + auto& Q = hierarchy.mQ[0]; + auto& N = hierarchy.mN[0]; + auto& O = hierarchy.mO[0]; + auto& S = hierarchy.mS[0]; + // ComputeOrientationSingularities(); + + BuildEdgeInfo(); + + if (flag_preserve_sharp) { + // ComputeSharpO(); + } + for (int i = 0; i < sharp_edges.size(); ++i) { + if (sharp_edges[i]) { + int e = face_edgeIds[i / 3][i % 3]; + if (edge_diff[e][0] * edge_diff[e][1] != 0) { + Vector3d d = O.col(edge_values[e].y) - O.col(edge_values[e].x); + Vector3d q = Q.col(edge_values[e].x); + Vector3d n = N.col(edge_values[e].x); + Vector3d qy = n.cross(q); + if (abs(q.dot(d)) > qy.dot(d)) + edge_diff[e][1] = 0; + else + edge_diff[e][0] = 0; + } + } + } + std::map> sharp_constraints; + std::set sharpvert; + for (int i = 0; i < sharp_edges.size(); ++i) { + if (sharp_edges[i]) { + sharpvert.insert(F(i % 3, i / 3)); + sharpvert.insert(F((i + 1) % 3, i / 3)); + } + } + + allow_changes.resize(edge_diff.size() * 2, 1); + for (int i = 0; i < sharp_edges.size(); ++i) { + int e = face_edgeIds[i / 3][i % 3]; + if (sharpvert.count(edge_values[e].x) && sharpvert.count(edge_values[e].y)) { + if (sharp_edges[i] != 0) { + for (int k = 0; k < 2; ++k) { + if (edge_diff[e][k] == 0) { + allow_changes[e * 2 + k] = 0; + } + } + } + } + } +#ifdef LOG_OUTPUT + printf("Build Integer Constraints...\n"); +#endif + BuildIntegerConstraints(); + + ComputeMaxFlow(); + // potential bug +#ifdef LOG_OUTPUT + printf("subdivide...\n"); +#endif + subdivide_edgeDiff(F, V, N, Q, O, &hierarchy.mS[0], V2E, hierarchy.mE2E, boundary, nonManifold, + edge_diff, edge_values, face_edgeOrients, face_edgeIds, sharp_edges, + singularities, 1); + + allow_changes.clear(); + allow_changes.resize(edge_diff.size() * 2, 1); + for (int i = 0; i < sharp_edges.size(); ++i) { + if (sharp_edges[i] == 0) continue; + int e = face_edgeIds[i / 3][i % 3]; + for (int k = 0; k < 2; ++k) { + if (edge_diff[e][k] == 0) allow_changes[e * 2 + k] = 0; + } + } + +#ifdef LOG_OUTPUT + printf("Fix flip advance...\n"); + int t1 = GetCurrentTime64(); +#endif + FixFlipHierarchy(); + subdivide_edgeDiff(F, V, N, Q, O, &hierarchy.mS[0], V2E, hierarchy.mE2E, boundary, nonManifold, + edge_diff, edge_values, face_edgeOrients, face_edgeIds, sharp_edges, + singularities, 1); + FixFlipSat(); + +#ifdef LOG_OUTPUT + int t2 = GetCurrentTime64(); + printf("Flip use %lf\n", (t2 - t1) * 1e-3); + printf("Post Linear Solver...\n"); +#endif + std::set sharp_vertices; + for (int i = 0; i < sharp_edges.size(); ++i) { + if (sharp_edges[i] == 1) { + sharp_vertices.insert(F(i % 3, i / 3)); + sharp_vertices.insert(F((i + 1) % 3, i / 3)); + } + } + + Optimizer::optimize_positions_sharp(hierarchy, edge_values, edge_diff, sharp_edges, + sharp_vertices, sharp_constraints, with_scale); + + Optimizer::optimize_positions_fixed(hierarchy, edge_values, edge_diff, sharp_vertices, + sharp_constraints, flag_adaptive_scale); + + AdvancedExtractQuad(); + + FixValence(); + + std::vector sharp_o(O_compact.size(), 0); + std::map> compact_sharp_constraints; + for (int i = 0; i < Vset.size(); ++i) { + int sharpv = -1; + for (auto& p : Vset[i]) { + if (sharp_constraints.count(p)) { + sharpv = p; + sharp_o[i] = 1; + if (compact_sharp_constraints.count(i) == 0 || + compact_sharp_constraints[i].second != Vector3d::Zero()) { + compact_sharp_constraints[i] = sharp_constraints[sharpv]; + O_compact[i] = O.col(sharpv); + compact_sharp_constraints[i].first = O_compact[i]; + } + } + } + } + + std::map, int> o2e; + for (int i = 0; i < F_compact.size(); ++i) { + for (int j = 0; j < 4; ++j) { + int v1 = F_compact[i][j]; + int v2 = F_compact[i][(j + 1) % 4]; + o2e[std::make_pair(v1, v2)] = i * 4 + j; + } + } + std::vector> v2o(V.cols()); + for (int i = 0; i < Vset.size(); ++i) { + for (auto v : Vset[i]) { + v2o[v].push_back(i); + } + } + std::vector diffs(F_compact.size() * 4, Vector3d(0, 0, 0)); + std::vector diff_count(F_compact.size() * 4, 0); + for (int i = 0; i < F.cols(); ++i) { + for (int j = 0; j < 3; ++j) { + int v1 = F(j, i); + int v2 = F((j + 1) % 3, i); + if (v1 != edge_values[face_edgeIds[i][j]].x) continue; + if (edge_diff[face_edgeIds[i][j]].array().abs().sum() != 1) continue; + if (v2o[v1].size() > 1 || v2o[v2].size() > 1) continue; + for (auto o1 : v2o[v1]) { + for (auto o2 : v2o[v2]) { + auto key = std::make_pair(o1, o2); + if (o2e.count(key)) { + int dedge = o2e[key]; + Vector3d q_1 = Q.col(v1); + Vector3d q_2 = Q.col(v2); + Vector3d n_1 = N.col(v1); + Vector3d n_2 = N.col(v2); + Vector3d q_1_y = n_1.cross(q_1); + Vector3d q_2_y = n_2.cross(q_2); + auto index = compat_orientation_extrinsic_index_4(q_1, n_1, q_2, n_2); + double s_x1 = S(0, v1), s_y1 = S(1, v1); + double s_x2 = S(0, v2), s_y2 = S(1, v2); + int rank_diff = (index.second + 4 - index.first) % 4; + if (rank_diff % 2 == 1) std::swap(s_x2, s_y2); + Vector3d qd_x = 0.5 * (rotate90_by(q_2, n_2, rank_diff) + q_1); + Vector3d qd_y = 0.5 * (rotate90_by(q_2_y, n_2, rank_diff) + q_1_y); + double scale_x = (with_scale ? 0.5 * (s_x1 + s_x2) : 1) * hierarchy.mScale; + double scale_y = (with_scale ? 0.5 * (s_y1 + s_y2) : 1) * hierarchy.mScale; + Vector2i diff = edge_diff[face_edgeIds[i][j]]; + Vector3d C = diff[0] * scale_x * qd_x + diff[1] * scale_y * qd_y; + + diff_count[dedge] += 1; + diffs[dedge] += C; + auto key = std::make_pair(o2, o1); + if (o2e.count(key)) { + int dedge = o2e[key]; + diff_count[dedge] += 1; + diffs[dedge] -= C; + } + } + } + } + } + } + + for (int i = 0; i < F.cols(); ++i) { + Vector2i d1 = rshift90(edge_diff[face_edgeIds[i][0]], face_edgeOrients[i][0]); + Vector2i d2 = rshift90(edge_diff[face_edgeIds[i][1]], face_edgeOrients[i][1]); + if (d1[0] * d2[1] - d1[1] * d2[0] < 0) { + for (int j = 0; j < 3; ++j) { + int v1 = F(j, i); + int v2 = F((j + 1) % 3, i); + for (auto o1 : v2o[v1]) { + for (auto o2 : v2o[v2]) { + auto key = std::make_pair(o1, o2); + if (o2e.count(key)) { + int dedge = o2e[key]; + diff_count[dedge] = 0; + diffs[dedge] = Vector3d(0, 0, 0); + } + } + } + } + } + } + + for (int i = 0; i < diff_count.size(); ++i) { + if (diff_count[i] != 0) { + diffs[i] /= diff_count[i]; + diff_count[i] = 1; + } + } + + Optimizer::optimize_positions_dynamic(F, V, N, Q, Vset, O_compact, F_compact, V2E_compact, + E2E_compact, sqrt(surface_area / F_compact.size()), + diffs, diff_count, o2e, sharp_o, + compact_sharp_constraints, flag_adaptive_scale); + + // optimize_quad_positions(O_compact, N_compact, Q_compact, F_compact, V2E_compact, + // E2E_compact, + // V, N, Q, O, F, V2E, hierarchy.mE2E, disajoint_tree, + // hierarchy.mScale, false); +} + +} // namespace qflow diff --git a/extern/quadriflow/src/parametrizer.hpp b/extern/quadriflow/src/parametrizer.hpp new file mode 100644 index 00000000000..1f4a02be6c2 --- /dev/null +++ b/extern/quadriflow/src/parametrizer.hpp @@ -0,0 +1,177 @@ +#ifndef PARAMETRIZER_H_ +#define PARAMETRIZER_H_ +#include +#include +#ifdef WITH_TBB +#include +#endif + +#include +#include +#include +#include +#include +#include +#include "adjacent-matrix.hpp" +#include "disajoint-tree.hpp" +#include "field-math.hpp" +#include "hierarchy.hpp" +#include "post-solver.hpp" +#include "serialize.hpp" + +namespace qflow { + +using namespace Eigen; + +typedef std::pair Edge; +typedef std::map> SingDictionary; + +struct ExpandInfo { + ExpandInfo() {} + int current_v; + int singularity; + int step; + int edge_id; + int prev; +}; + +class Parametrizer { + public: + Parametrizer() {} + // Mesh Initialization + void Load(const char* filename); + void NormalizeMesh(); + void ComputeMeshStatus(); + void ComputeSmoothNormal(); + void ComputeSharpEdges(); + void ComputeSharpO(); + void ComputeVertexArea(); + void Initialize(int faces); + + // Singularity and Mesh property + void AnalyzeValence(); + void ComputeOrientationSingularities(); + void ComputePositionSingularities(); + + // Integer Grid Map Pipeline + void ComputeIndexMap(int with_scale = 0); + void BuildEdgeInfo(); + void ComputeMaxFlow(); + void MarkInteger(); + void BuildIntegerConstraints(); + + // Fix Flip + void FixFlipHierarchy(); + void FixFlipSat(); + void FixHoles(); + void FixHoles(std::vector& loop_vertices); + void FixValence(); + double QuadEnergy(std::vector& loop_vertices, std::vector& res_quads, + int level); + + // Quadmesh and IO + void AdvancedExtractQuad(); + void BuildTriangleManifold(DisajointTree& disajoint_tree, std::vector& edge, + std::vector& face, std::vector& edge_values, + std::vector& F2E, std::vector& E2F, + std::vector& EdgeDiff, std::vector& FQ); + void OutputMesh(const char* obj_name); + + std::map singularities; // map faceid to valence (1 (valence=3) or 3(valence=5)) + std::map pos_sing; + MatrixXi pos_rank; // pos_rank(i, j) i \in [0, 3) jth face ith vertex rotate by its value so + // that all thress vertices are in the same orientation + MatrixXi pos_index; // pos_index(i x 2 + dim, j) i \in [0, 6) jth face ith vertex's + // (t_ij-t_ji)'s dim's dimenstion in the paper + // input mesh + MatrixXd V; + MatrixXd N; + MatrixXd Nf; + MatrixXd FS; + MatrixXd FQ; + MatrixXi F; + + double normalize_scale; + Vector3d normalize_offset; + + // data structures + VectorXd rho; + VectorXi V2E; + VectorXi E2E; + VectorXi boundary; + VectorXi nonManifold; // nonManifold vertices, in boolean + AdjacentMatrix adj; + Hierarchy hierarchy; + + // Mesh Status; + double surface_area; + double scale; + double average_edge_length; + double max_edge_length; + VectorXd A; + + // just for test + DisajointTree disajoint_tree; + + int compact_num_v; + std::vector> Vset; + std::vector O_compact; + std::vector Q_compact; + std::vector N_compact; + std::vector F_compact; + std::set> Quad_edges; + std::vector V2E_compact; + std::vector E2E_compact; + VectorXi boundary_compact; + VectorXi nonManifold_compact; + + std::vector bad_vertices; + std::vector counter; + std::vector + sharp_edges; // sharp_edges[deid]: whether deid is a sharp edge that should be preserved + std::vector allow_changes; // allow_changes[variable_id]: whether var can be changed + // based on sharp edges + std::vector edge_diff; // edge_diff[edgeIds[i](j)]: t_ij+t_ji under + // edge_values[edgeIds[i](j)].x's Q value + std::vector edge_values; // see above + std::vector + face_edgeIds; // face_edgeIds[i](j): ith face jth edge's "undirected edge ID" + + // face_edgeOrients[i](j): Rotate from edge_diff space + // (a) initially, to F(0, i)'s Q space + // (b) later on, to a global Q space where some edges are fixed + std::vector face_edgeOrients; + + // variable[i].first: indices of the two equations corresponding to variable i + // variable[i].second: number of positive minus negative of variables' occurances + std::vector> variables; + + struct QuadInfo { + QuadInfo() : patchId(-1), coordinate(0x10000000, 0x10000000), singular(0), edge(0) {} + int patchId; + Vector2i coordinate; + int singular; + int edge; + }; + std::vector quad_info; + + // scale + void ComputeInverseAffine(); + void EstimateSlope(); + std::vector triangle_space; + + // flag + int flag_preserve_sharp = 0; + int flag_preserve_boundary = 0; + int flag_adaptive_scale = 0; + int flag_aggresive_sat = 0; + int flag_minimum_cost_flow = 0; +}; + +extern void generate_adjacency_matrix_uniform(const MatrixXi& F, const VectorXi& V2E, + const VectorXi& E2E, const VectorXi& nonManifold, + AdjacentMatrix& adj); + +} // namespace qflow + +#endif diff --git a/extern/quadriflow/src/post-solver.cpp b/extern/quadriflow/src/post-solver.cpp new file mode 100644 index 00000000000..6027ddd2eb7 --- /dev/null +++ b/extern/quadriflow/src/post-solver.cpp @@ -0,0 +1,427 @@ +// +// post-solver.cpp +// parametrize +// +// Created by Jingwei on 2/5/18. +// +#include +#include +#include +#include +#include + +#include "ceres/ceres.h" +#include "ceres/rotation.h" + +#include "post-solver.hpp" +#include "serialize.hpp" + +namespace qflow { + +/// Coefficient of area constraint. The magnitude is 1 if area is equal to 0. +const double COEFF_AREA = 1; +/// Coefficient of tangent constraint. The magnitude is 0.03 if the bais is reference_length. +/// This is because current tangent constraint is not very accurate. +/// This optimization conflicts with COEFF_AREA. +const double COEFF_TANGENT = 0.02; +/// Coefficient of normal constraint. The magnitude is the arc angle. +const double COEFF_NORMAL = 1; +/// Coefficient of normal constraint. The magnitude is the arc angle. +const double COEFF_FLOW = 1; +/// Coefficient of orthogonal edge. The magnitude is the arc angle. +const double COEFF_ORTH = 1; +/// Coefficient of edge length. The magnitude is the arc angle. +const double COEFF_LENGTH = 1; +/// Number of iterations of the CGNR solver +const int N_ITER = 100; + +template +T DotProduct(const T a[3], const T2 b[3]) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; +} + +template +T Length2(const T a[3]) { + return DotProduct(a, a); +} + +namespace ceres { +inline double min(const double f, const double g) { return std::min(f, g); } + +template +inline Jet min(const Jet& f, const Jet& g) { + if (f.a < g.a) + return f; + else + return g; +} +} // namespace ceres + +bool DEBUG = 0; +struct FaceConstraint { + FaceConstraint(double coeff_area, double coeff_normal, double coeff_flow, double coeff_orth, + double length, Vector3d normal[4], Vector3d Q0[4], Vector3d Q1[4]) + : coeff_area(coeff_area), + coeff_normal(coeff_normal), + coeff_flow(coeff_flow), + coeff_orth(coeff_orth), + area0(length * length), + normal0{ + normal[0], + normal[1], + normal[2], + normal[3], + }, + Q0{Q0[0], Q0[1], Q0[2], Q0[3]}, + Q1{Q1[0], Q1[1], Q1[2], Q1[3]} {} + + template + bool operator()(const T* p0, const T* p1, const T* p2, const T* p3, T* r) const { + const T* p[] = {p0, p1, p2, p3}; + r[12] = T(); + for (int k = 0; k < 4; ++k) { + auto pc = p[k]; + auto pa = p[(k + 1) % 4]; + auto pb = p[(k + 3) % 4]; + + T a[3]{pa[0] - pc[0], pa[1] - pc[1], pa[2] - pc[2]}; + T b[3]{pb[0] - pc[0], pb[1] - pc[1], pb[2] - pc[2]}; + + T length_a = ceres::sqrt(Length2(a)); + T length_b = ceres::sqrt(Length2(b)); + T aa[3]{a[0] / length_a, a[1] / length_a, a[2] / length_a}; + T bb[3]{b[0] / length_b, b[1] / length_b, b[2] / length_b}; + r[3 * k + 0] = coeff_orth * DotProduct(aa, bb); + + T degree_edge0 = ceres::abs(DotProduct(aa, &Q0[k][0])); + T degree_edge1 = ceres::abs(DotProduct(aa, &Q1[k][0])); + T degree_edge = ceres::min(degree_edge0, degree_edge1); + r[3 * k + 1] = coeff_flow * degree_edge; + + T normal[3]; + ceres::CrossProduct(a, b, normal); + T area = ceres::sqrt(Length2(normal)); + r[12] += area; + + assert(area != T()); + for (int i = 0; i < 3; ++i) normal[i] /= area; + T degree_normal = DotProduct(normal, &normal0[k][0]) - T(1); + r[3 * k + 2] = coeff_normal * degree_normal * degree_normal; + } + r[12] = coeff_area * (r[12] / (4.0 * area0) - 1.0); + return true; + } + + static ceres::CostFunction* create(double coeff_area, double coeff_normal, double coeff_flow, + double coeff_orth, double length, Vector3d normal[4], + Vector3d Q0[4], Vector3d Q1[4]) { + return new ceres::AutoDiffCostFunction(new FaceConstraint( + coeff_area, coeff_normal, coeff_flow, coeff_orth, length, normal, Q0, Q1)); + } + + double coeff_area; + double coeff_normal; + double coeff_flow; + double coeff_orth; + + double area0; + Vector3d normal0[4]; + Vector3d Q0[4], Q1[4]; +}; + +struct VertexConstraint { + VertexConstraint(double coeff_tangent, Vector3d normal, double bias, double length) + : coeff{coeff_tangent / length * 10}, bias0{bias}, normal0{normal} {} + + template + bool operator()(const T* p, T* r) const { + r[0] = coeff * (DotProduct(p, &normal0[0]) - bias0); + return true; + } + + static ceres::CostFunction* create(double coeff_tangent, Vector3d normal, double bias, + double length) { + return new ceres::AutoDiffCostFunction( + new VertexConstraint(coeff_tangent, normal, bias, length)); + } + + double coeff; + double bias0; + Vector3d normal0; +}; + +void solve(std::vector& O_quad, std::vector& N_quad, + std::vector& Q_quad, std::vector& F_quad, + std::vector& B_quad, MatrixXd& V, MatrixXd& N, MatrixXd& Q, MatrixXd& O, + MatrixXi& F, double reference_length, double coeff_area, double coeff_tangent, + double coeff_normal, double coeff_flow, double coeff_orth) { + printf("Parameter: \n"); + printf(" coeff_area: %.4f\n", coeff_area); + printf(" coeff_tangent: %.4f\n", coeff_tangent); + printf(" coeff_normal: %.4f\n", coeff_normal); + printf(" coeff_flow: %.4f\n", coeff_flow); + printf(" coeff_orth: %.4f\n\n", coeff_orth); + int n_quad = Q_quad.size(); + + ceres::Problem problem; + std::vector solution(n_quad * 3); + for (int vquad = 0; vquad < n_quad; ++vquad) { + solution[3 * vquad + 0] = O_quad[vquad][0]; + solution[3 * vquad + 1] = O_quad[vquad][1]; + solution[3 * vquad + 2] = O_quad[vquad][2]; + } + + // Face constraint (area and normal direction) + for (int fquad = 0; fquad < F_quad.size(); ++fquad) { + auto v = F_quad[fquad]; + Vector3d normal[4], Q0[4], Q1[4]; + for (int k = 0; k < 4; ++k) { + normal[k] = N_quad[v[k]]; + Q0[k] = Q_quad[v[k]]; + Q1[k] = Q0[k].cross(normal[k]).normalized(); + } + ceres::CostFunction* cost_function = FaceConstraint::create( + coeff_area, coeff_normal, coeff_flow, coeff_orth, reference_length, normal, Q0, Q1); + problem.AddResidualBlock(cost_function, nullptr, &solution[3 * v[0]], &solution[3 * v[1]], + &solution[3 * v[2]], &solution[3 * v[3]]); + } + + // Tangent constraint + for (int vquad = 0; vquad < O_quad.size(); ++vquad) { + ceres::CostFunction* cost_function = VertexConstraint::create( + coeff_tangent, N_quad[vquad], B_quad[vquad], reference_length); + problem.AddResidualBlock(cost_function, nullptr, &solution[3 * vquad]); + } + + // Flow constraint + + ceres::Solver::Options options; + options.num_threads = 1; + options.max_num_iterations = N_ITER; + options.initial_trust_region_radius = 1; + options.linear_solver_type = ceres::CGNR; + options.minimizer_progress_to_stdout = true; + ceres::Solver::Summary summary; + ceres::Solve(options, &problem, &summary); + + std::cout << summary.BriefReport() << std::endl; + + for (int vquad = 0; vquad < n_quad; ++vquad) { + O_quad[vquad][0] = solution[3 * vquad + 0]; + O_quad[vquad][1] = solution[3 * vquad + 1]; + O_quad[vquad][2] = solution[3 * vquad + 2]; + } + + return; +} + +void optimize_quad_positions(std::vector& O_quad, std::vector& N_quad, + std::vector& Q_quad, std::vector& F_quad, + VectorXi& V2E_quad, std::vector& E2E_quad, MatrixXd& V, + MatrixXd& N, MatrixXd& Q, MatrixXd& O, MatrixXi& F, VectorXi& V2E, + VectorXi& E2E, DisajointTree& disajoint_tree, double reference_length, + bool just_serialize) { + printf("Quad mesh info:\n"); + printf("Number of vertices with normals and orientations: %d = %d = %d\n", (int)O_quad.size(), + (int)N_quad.size(), (int)Q_quad.size()); + printf("Number of faces: %d\n", (int)F_quad.size()); + printf("Number of directed edges: %d\n", (int)E2E_quad.size()); + // Information for the original mesh + printf("Triangle mesh info:\n"); + printf( + "Number of vertices with normals, " + "orientations and associated quad positions: " + "%d = %d = %d = %d\n", + (int)V.cols(), (int)N.cols(), (int)Q.cols(), (int)O.cols()); + printf("Number of faces: %d\n", (int)F.cols()); + printf("Number of directed edges: %d\n", (int)E2E.size()); + printf("Reference length: %.2f\n", reference_length); + + int flip_count = 0; + for (int i = 0; i < F_quad.size(); ++i) { + bool flipped = false; + for (int j = 0; j < 4; ++j) { + int v1 = F_quad[i][j]; + int v2 = F_quad[i][(j + 1) % 4]; + int v3 = F_quad[i][(j + 3) % 4]; + + Vector3d face_norm = (O_quad[v2] - O_quad[v1]).cross(O_quad[v3] - O_quad[v1]); + Vector3d vertex_norm = N_quad[v1]; + if (face_norm.dot(vertex_norm) < 0) { + flipped = true; + } + } + if (flipped) { + flip_count++; + } + } + printf("Flipped Quads: %d\n", flip_count); + + int n_quad = O_quad.size(); + int n_trig = O.cols(); + std::vector B_quad(n_quad); // Average bias for quad vertex + std::vector B_weight(n_quad); + + printf("ntrig: %d, disjoint_tree.size: %d\n", n_trig, (int)disajoint_tree.indices.size()); + for (int vtrig = 0; vtrig < n_trig; ++vtrig) { + int vquad = disajoint_tree.Index(vtrig); + double b = N_quad[vquad].dot(O.col(vtrig)); + B_quad[vquad] += b; + B_weight[vquad] += 1; + } + for (int vquad = 0; vquad < n_quad; ++vquad) { + assert(B_weight[vquad]); + B_quad[vquad] /= B_weight[vquad]; + } + + puts("Save parameters to post.bin for optimization"); + FILE* out = fopen("post.bin", "wb"); + assert(out); + Save(out, O_quad); + Save(out, N_quad); + Save(out, Q_quad); + Save(out, F_quad); + Save(out, B_quad); + Save(out, V); + Save(out, N); + Save(out, Q); + Save(out, O); + Save(out, F); + Save(out, reference_length); + fclose(out); + + if (!just_serialize) { + puts("Start post optimization"); + solve(O_quad, N_quad, Q_quad, F_quad, B_quad, V, N, Q, O, F, reference_length, COEFF_AREA, + COEFF_TANGENT, COEFF_NORMAL, COEFF_FLOW, COEFF_ORTH); + } +} + +#ifdef POST_SOLVER + +void SaveObj(const std::string& fname, std::vector O_quad, + std::vector F_quad) { + std::ofstream os(fname); + for (int i = 0; i < (int)O_quad.size(); ++i) { + os << "v " << O_quad[i][0] << " " << O_quad[i][1] << " " << O_quad[i][2] << "\n"; + } + for (int i = 0; i < (int)F_quad.size(); ++i) { + os << "f " << F_quad[i][0] + 1 << " " << F_quad[i][1] + 1 << " " << F_quad[i][2] + 1 << " " + << F_quad[i][3] + 1 << "\n"; + } + os.close(); +} + +int main(int argc, char* argv[]) { + double coeff_area; + double coeff_tangent; + double coeff_normal; + double coeff_flow; + double coeff_orth; + + namespace po = boost::program_options; + po::options_description desc("Allowed options"); + desc.add_options() // clang-format off + ("help,h", "produce help message") + ("area,a", po::value(&coeff_area)->default_value(COEFF_AREA), "Set the coefficient of area constraint") + ("tangent,t", po::value(&coeff_tangent)->default_value(COEFF_TANGENT), "Set the coefficient of tangent constraint") + ("normal,n", po::value(&coeff_normal)->default_value(COEFF_NORMAL), "Set the coefficient of normal constraint") + ("flow,f", po::value(&coeff_flow)->default_value(COEFF_FLOW), "Set the coefficient of flow (Q) constraint") + ("orth,o", po::value(&coeff_orth)->default_value(COEFF_ORTH), "Set the coefficient of orthogonal constraint"); + + // clang-format on + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + if (vm.count("help")) { + std::cout << desc << std::endl; + return 1; + } + + std::vector O_quad; + std::vector N_quad; + std::vector Q_quad; + std::vector F_quad; + std::vector B_quad; + MatrixXd V; + MatrixXd N; + MatrixXd Q; + MatrixXd O; + MatrixXi F; + double reference_length; + + puts("Read parameters from post.bin"); + FILE* in = fopen("post.bin", "rb"); + assert(in); + Read(in, O_quad); + Read(in, N_quad); + Read(in, Q_quad); + Read(in, F_quad); + Read(in, B_quad); + Read(in, V); + Read(in, N); + Read(in, Q); + Read(in, O); + Read(in, F); + Read(in, reference_length); + fclose(in); + printf("reference_length: %.2f\n", reference_length); + SaveObj("presolver.obj", O_quad, F_quad); + + int n_flip = 0; + double sum_degree = 0; + for (int i = 0; i < F_quad.size(); ++i) { + bool flipped = false; + for (int j = 0; j < 4; ++j) { + int v1 = F_quad[i][j]; + int v2 = F_quad[i][(j + 1) % 4]; + int v3 = F_quad[i][(j + 3) % 4]; + + Vector3d face_norm = + (O_quad[v2] - O_quad[v1]).cross(O_quad[v3] - O_quad[v1]).normalized(); + Vector3d vertex_norm = N_quad[v1]; + if (face_norm.dot(vertex_norm) < 0) { + flipped = true; + } + double degree = std::acos(face_norm.dot(vertex_norm)); + assert(degree >= 0); + // printf("cos theta = %.2f\n", degree); + sum_degree += degree * degree; + } + n_flip += flipped; + } + printf("n_flip: %d\nsum_degree: %.3f\n", n_flip, sum_degree); + + puts("Start post optimization"); + solve(O_quad, N_quad, Q_quad, F_quad, B_quad, V, N, Q, O, F, reference_length, coeff_area, + coeff_tangent, coeff_normal, coeff_flow, coeff_orth); + SaveObj("postsolver.obj", O_quad, F_quad); + + n_flip = 0; + sum_degree = 0; + for (int i = 0; i < F_quad.size(); ++i) { + bool flipped = false; + for (int j = 0; j < 4; ++j) { + int v1 = F_quad[i][j]; + int v2 = F_quad[i][(j + 1) % 4]; + int v3 = F_quad[i][(j + 3) % 4]; + + Vector3d face_norm = + (O_quad[v2] - O_quad[v1]).cross(O_quad[v3] - O_quad[v1]).normalized(); + Vector3d vertex_norm = N_quad[v1]; + if (face_norm.dot(vertex_norm) < 0) { + flipped = true; + } + double degree = std::acos(face_norm.dot(vertex_norm)); + assert(degree >= 0); + sum_degree += degree * degree; + } + n_flip += flipped; + } + printf("n_flip: %d\nsum_degree: %.3f\n", n_flip, sum_degree); + return 0; +} + +#endif + +} // namespace qflow diff --git a/extern/quadriflow/src/post-solver.hpp b/extern/quadriflow/src/post-solver.hpp new file mode 100644 index 00000000000..546245d801e --- /dev/null +++ b/extern/quadriflow/src/post-solver.hpp @@ -0,0 +1,64 @@ +// +// post-solver.hpp +// Parametrize +// +// Created by Jingwei on 2/5/18. +// + +#ifndef post_solver_h +#define post_solver_h + +#include +#include +#include "disajoint-tree.hpp" + +namespace qflow { + +using namespace Eigen; + +/* + * TODO: Optimize O_quad, and possibly N_quad + * Input: + * O_quad[i]: initialized i-th vertex position of the quad mesh + * N_quad[i]: initialized i-th vertex normal of the quad mesh + * Q_quad[i]: initialized i-th vertex orientation of the quad mesh, guaranteed to be orthogonal to + * N_quad[i] + * F_quad[i]: 4 vertex index of the i-th quad face + * + * Concept: i-th directed edge is the (i%4)-th edge of the (i/4)-th face of the quad mesh + * V2E_quad[i]: one directed edge from i-th vertex of the quad mesh + * E2E_quad[i]: the reverse directed edge's index of the i-th directed edge of the quad mesh + * + * V.col(i): i-th vertex position of the triangle mesh + * N.col(i): i-th vertex normal of the triangle mesh + * Q.col(i): i-th vertex orientation of the triangle mesh, guaranteed to be orthogonal to N.col(i) + * O.col(i): "quad position" associated with the i-th vertex in the triangle mesh (see InstantMesh + * position field) + * F.col(i): i-th triangle of the triangle mesh + * + * V2E[i]: one directed edge from the i-th vertex of the triangle mesh + * E2E[i]: the reverse directed edge's index of the i-th directed edge of the triangle mesh + * + * j = disajoint_tree.Index(i) + * the j-th vertex of the quad mesh is corresponding to the i-th vertex of the triangle mesh + * the relation is one-to-multiple + * O_quad can be viewed as an average of corresponding O + * N_quad can be viewed as an average of corresponding N + * Q_quad can be viewed as aggregation of corresponding Q + * Method that aggregates qi to qj with weights wi and wj: + * value = compat_orientation_extrinsic_4(qj, nj, qi, ni) + * result = (value.first * wj + value.second * wi).normalized() + * + * Output: + * Optimized O_quad, (possibly N_quad) + */ +void optimize_quad_positions(std::vector& O_quad, std::vector& N_quad, + std::vector& Q_quad, std::vector& F_quad, + VectorXi& V2E_quad, std::vector& E2E_quad, MatrixXd& V, MatrixXd& N, + MatrixXd& Q, MatrixXd& O, MatrixXi& F, VectorXi& V2E, VectorXi& E2E, + DisajointTree& disajoint_tree, double reference_length, + bool just_serialize = true); + +} // namespace qflow + +#endif /* post_solver_h */ diff --git a/extern/quadriflow/src/serialize.hpp b/extern/quadriflow/src/serialize.hpp new file mode 100644 index 00000000000..3e670e02fa5 --- /dev/null +++ b/extern/quadriflow/src/serialize.hpp @@ -0,0 +1,127 @@ +#ifndef SERIALIZE_H_ +#define SERIALIZE_H_ + +#include +#include +#include +#include +#include +#include "adjacent-matrix.hpp" + +namespace qflow { + +template +inline void Save(FILE* fp, const Eigen::Matrix& m) { + int r = m.rows(), c = m.cols(); + fwrite(&r, sizeof(int), 1, fp); + fwrite(&c, sizeof(int), 1, fp); + std::vector buffer(r * c); + for (int i = 0; i < r; ++i) { + for (int j = 0; j < c; ++j) { + buffer[i * c + j] = m(i, j); + } + } + fwrite(buffer.data(), sizeof(T), r * c, fp); +} + +template +inline void Read(FILE* fp, Eigen::Matrix& m) { + int r, c; + fread(&r, sizeof(int), 1, fp); + fread(&c, sizeof(int), 1, fp); + std::vector buffer(r * c); + fread(buffer.data(), sizeof(T), r * c, fp); + m.resize(r, c); + for (int i = 0; i < r; ++i) { + for (int j = 0; j < c; ++j) { + m(i, j) = buffer[i * c + j]; + } + } +} + +inline void Save(FILE* fp, const Link& p) { fwrite(&p, sizeof(Link), 1, fp); } + +inline void Read(FILE* fp, Link& p) { fread(&p, sizeof(Link), 1, fp); } + +inline void Save(FILE* fp, const TaggedLink& p) { fwrite(&p, sizeof(TaggedLink), 1, fp); } + +inline void Read(FILE* fp, TaggedLink& p) { fread(&p, sizeof(TaggedLink), 1, fp); } + +inline void Save(FILE* fp, double p) { fwrite(&p, sizeof(double), 1, fp); } + +inline void Read(FILE* fp, double& p) { fread(&p, sizeof(double), 1, fp); } + +inline void Save(FILE* fp, int p) { fwrite(&p, sizeof(int), 1, fp); } + +inline void Read(FILE* fp, int& p) { fread(&p, sizeof(int), 1, fp); } + +template +inline void Save(FILE* fp, const std::pair& p) { + fwrite(&p.first, sizeof(T), 1, fp); + fwrite(&p.second, sizeof(F), 1, fp); +} + +template +inline void Read(FILE* fp, std::pair& p) { + fread(&p.first, sizeof(T), 1, fp); + fread(&p.second, sizeof(F), 1, fp); +} + +template +inline void Save(FILE* fp, const std::map& p) { + int num = p.size(); + fwrite(&num, sizeof(int), 1, fp); + for (auto& s : p) { + fwrite(&s, sizeof(s), 1, fp); + } +} + +template +inline void Read(FILE* fp, std::map& p) { + int num; + p.clear(); + fread(&num, sizeof(int), 1, fp); + for (int i = 0; i < num; ++i) { + std::pair m; + fread(&m, sizeof(m), 1, fp); + p.insert(m); + } +} + +template +void Save(FILE* fp, const std::vector& p) { + int num = p.size(); + fwrite(&num, sizeof(int), 1, fp); + for (auto& q : p) { + Save(fp, q); + } +} + +template +void Read(FILE* fp, std::vector& p) { + int num; + fread(&num, sizeof(int), 1, fp); + p.resize(num); + for (auto& q : p) { + Read(fp, q); + } +} + +template +void Save(FILE* fp, const std::set& p) { + std::vector buffer; + buffer.insert(buffer.end(), p.begin(), p.end()); + Save(fp, buffer); +} + +template +void Read(FILE* fp, std::set& p) { + std::vector buffer; + Read(fp, buffer); + p.clear(); + for (auto& q : buffer) p.insert(q); +} + +} // namespace qflow + +#endif diff --git a/extern/quadriflow/src/subdivide.cpp b/extern/quadriflow/src/subdivide.cpp new file mode 100644 index 00000000000..c408bbc6394 --- /dev/null +++ b/extern/quadriflow/src/subdivide.cpp @@ -0,0 +1,516 @@ +#include "subdivide.hpp" + +#include +#include + +#include "dedge.hpp" +#include "disajoint-tree.hpp" +#include "field-math.hpp" +#include "parametrizer.hpp" + +namespace qflow { + +void subdivide(MatrixXi &F, MatrixXd &V, VectorXd& rho, VectorXi &V2E, VectorXi &E2E, VectorXi &boundary, + VectorXi &nonmanifold, double maxLength) { + typedef std::pair Edge; + + std::priority_queue queue; + + maxLength *= maxLength; + + for (int i = 0; i < E2E.size(); ++i) { + int v0 = F(i % 3, i / 3), v1 = F((i + 1) % 3, i / 3); + if (nonmanifold[v0] || nonmanifold[v1]) continue; + double length = (V.col(v0) - V.col(v1)).squaredNorm(); + if (length > maxLength || length > std::max(maxLength * 0.75, std::min(rho[v0], rho[v1]) * 1.0)) { + int other = E2E[i]; + if (other == -1 || other > i) queue.push(Edge(length, i)); + } + } + + int nV = V.cols(), nF = F.cols(), nSplit = 0; + /* + / v0 \ + v1p 1 | 0 v0p + \ v1 / + + / v0 \ + / 1 | 0 \ + v1p - vn - v0p + \ 2 | 3 / + \ v1 / + + f0: vn, v0p, v0 + f1: vn, v0, v1p + f2: vn, v1p, v1 + f3: vn, v1, v0p + */ + int counter = 0; + while (!queue.empty()) { + counter += 1; + Edge edge = queue.top(); + queue.pop(); + int e0 = edge.second, e1 = E2E[e0]; + bool is_boundary = e1 == -1; + int f0 = e0 / 3, f1 = is_boundary ? -1 : (e1 / 3); + int v0 = F(e0 % 3, f0), v0p = F((e0 + 2) % 3, f0), v1 = F((e0 + 1) % 3, f0); + if ((V.col(v0) - V.col(v1)).squaredNorm() != edge.first) { + continue; + } + int v1p = is_boundary ? -1 : F((e1 + 2) % 3, f1); + int vn = nV++; + nSplit++; + /* Update V */ + if (nV > V.cols()) { + V.conservativeResize(V.rows(), V.cols() * 2); + rho.conservativeResize(V.cols() * 2); + V2E.conservativeResize(V.cols()); + boundary.conservativeResize(V.cols()); + nonmanifold.conservativeResize(V.cols()); + } + + /* Update V */ + V.col(vn) = (V.col(v0) + V.col(v1)) * 0.5f; + rho[vn] = 0.5f * (rho[v0], rho[v1]); + nonmanifold[vn] = false; + boundary[vn] = is_boundary; + + /* Update F and E2E */ + int f2 = is_boundary ? -1 : (nF++); + int f3 = nF++; + if (nF > F.cols()) { + F.conservativeResize(F.rows(), std::max(nF, (int)F.cols() * 2)); + E2E.conservativeResize(F.cols() * 3); + } + + /* Update F */ + F.col(f0) << vn, v0p, v0; + if (!is_boundary) { + F.col(f1) << vn, v0, v1p; + F.col(f2) << vn, v1p, v1; + } + F.col(f3) << vn, v1, v0p; + + /* Update E2E */ + const int e0p = E2E[dedge_prev_3(e0)], e0n = E2E[dedge_next_3(e0)]; + +#define sE2E(a, b) \ + E2E[a] = b; \ + if (b != -1) E2E[b] = a; + sE2E(3 * f0 + 0, 3 * f3 + 2); + sE2E(3 * f0 + 1, e0p); + sE2E(3 * f3 + 1, e0n); + if (is_boundary) { + sE2E(3 * f0 + 2, -1); + sE2E(3 * f3 + 0, -1); + } else { + const int e1p = E2E[dedge_prev_3(e1)], e1n = E2E[dedge_next_3(e1)]; + sE2E(3 * f0 + 2, 3 * f1 + 0); + sE2E(3 * f1 + 1, e1n); + sE2E(3 * f1 + 2, 3 * f2 + 0); + sE2E(3 * f2 + 1, e1p); + sE2E(3 * f2 + 2, 3 * f3 + 0); + } +#undef sE2E + + /* Update V2E */ + V2E[v0] = 3 * f0 + 2; + V2E[vn] = 3 * f0 + 0; + V2E[v1] = 3 * f3 + 1; + V2E[v0p] = 3 * f0 + 1; + if (!is_boundary) V2E[v1p] = 3 * f1 + 2; + + auto schedule = [&](int f) { + for (int i = 0; i < 3; ++i) { + double length = (V.col(F(i, f)) - V.col(F((i + 1) % 3, f))).squaredNorm(); + if (length > maxLength + || length > std::max(maxLength * 0.75, std::min(rho[F(i, f)], rho[F((i + 1) % 3, f)]) * 1.0)) + queue.push(Edge(length, f * 3 + i)); + } + }; + + schedule(f0); + if (!is_boundary) { + schedule(f2); + schedule(f1); + }; + schedule(f3); + } + F.conservativeResize(F.rows(), nF); + V.conservativeResize(V.rows(), nV); + rho.conservativeResize(nV); + V2E.conservativeResize(nV); + boundary.conservativeResize(nV); + nonmanifold.conservativeResize(nV); + E2E.conservativeResize(nF * 3); +} + +void subdivide_edgeDiff(MatrixXi &F, MatrixXd &V, MatrixXd &N, MatrixXd &Q, MatrixXd &O, MatrixXd* S, + VectorXi &V2E, VectorXi &E2E, VectorXi &boundary, VectorXi &nonmanifold, + std::vector &edge_diff, std::vector &edge_values, + std::vector &face_edgeOrients, std::vector &face_edgeIds, + std::vector& sharp_edges, std::map &singularities, int max_len) { + struct EdgeLink { + int id; + double length; + Vector2i diff; + int maxlen() const { return std::max(abs(diff[0]), abs(diff[1])); } + bool operator<(const EdgeLink &link) const { return maxlen() < link.maxlen(); } + }; + + struct FaceOrient { + int orient; + Vector3i d; + Vector3d q; + Vector3d n; + }; + + std::vector face_spaces(F.cols()); + std::priority_queue queue; + std::vector diffs(E2E.size()); + for (int i = 0; i < F.cols(); ++i) { + for (int j = 0; j < 3; ++j) { + int eid = i * 3 + j; + diffs[eid] = rshift90(edge_diff[face_edgeIds[i][j]], face_edgeOrients[i][j]); + } + } + for (int i = 0; i < F.cols(); ++i) { + FaceOrient orient{}; + orient.q = Q.col(F(0, i)); + orient.n = N.col(F(0, i)); + int orient_diff[3]; + for (int j = 0; j < 3; ++j) { + int final_orient = face_edgeOrients[i][j]; + int eid = face_edgeIds[i][j]; + auto value = compat_orientation_extrinsic_index_4( + Q.col(edge_values[eid].x), N.col(edge_values[eid].x), orient.q, orient.n); + int target_orient = (value.second - value.first + 4) % 4; + if (F(j, i) == edge_values[eid].y) target_orient = (target_orient + 2) % 4; + orient_diff[j] = (final_orient - target_orient + 4) % 4; + } + if (orient_diff[0] == orient_diff[1]) + orient.orient = orient_diff[0]; + else if (orient_diff[0] == orient_diff[2]) + orient.orient = orient_diff[2]; + else if (orient_diff[1] == orient_diff[2]) + orient.orient = orient_diff[1]; + orient.d = Vector3i((orient_diff[0] - orient.orient + 4) % 4, + (orient_diff[1] - orient.orient + 4) % 4, + (orient_diff[2] - orient.orient + 4) % 4); + face_spaces[i] = (orient); + } + for (int i = 0; i < E2E.size(); ++i) { + int v0 = F(i % 3, i / 3), v1 = F((i + 1) % 3, i / 3); + if (nonmanifold[v0] || nonmanifold[v1]) continue; + double length = (V.col(v0) - V.col(v1)).squaredNorm(); + Vector2i diff = diffs[i]; + if (abs(diff[0]) > max_len || abs(diff[1]) > max_len) { + int other = E2E[i]; + if (other == -1 || other > i) { + EdgeLink e; + e.id = i; + e.length = length; + e.diff = diff; + queue.push(e); + } + } + } + auto AnalyzeOrient = [&](int f0, const Vector3i &d) { + for (int j = 0; j < 3; ++j) { + int orient = face_spaces[f0].orient + d[j]; + int v = std::min(F(j, f0), F((j + 1) % 3, f0)); + auto value = compat_orientation_extrinsic_index_4( + Q.col(v), N.col(v), face_spaces[f0].q, face_spaces[f0].n); + if (F(j, f0) != v) orient += 2; + face_edgeOrients[f0][j] = (orient + value.second - value.first + 4) % 4; + } + face_spaces[f0].d = d; + for (int j = 0; j < 3; ++j) { + int eid = face_edgeIds[f0][j]; + int orient = face_edgeOrients[f0][j]; + auto diff = rshift90(diffs[f0 * 3 + j], (4 - orient) % 4); + edge_diff[eid] = diff; + } + }; + auto FixOrient = [&](int f0) { + for (int j = 0; j < 3; ++j) { + auto diff = edge_diff[face_edgeIds[f0][j]]; + if (rshift90(diff, face_edgeOrients[f0][j]) != diffs[f0 * 3 + j]) { + int orient = 0; + while (orient < 4 && rshift90(diff, orient) != diffs[f0 * 3 + j]) orient += 1; + face_spaces[f0].d[j] = + (face_spaces[f0].d[j] + orient - face_edgeOrients[f0][j]) % 4; + face_edgeOrients[f0][j] = orient; + } + } + }; + /* + auto Length = [&](int f0) { + int l = 0; + for (int j = 0; j < 3; ++j) { + for (int k = 0; k < 2; ++k) { + l += abs(diffs[f0*3+j][k]); + } + printf("<%d %d> ", diffs[f0*3+j][0], diffs[f0*3+j][1]); + } + printf("\n"); + return l; + }; + */ + int nV = V.cols(), nF = F.cols(), nSplit = 0; + /* + / v0 \ + v1p 1 | 0 v0p + \ v1 / + + / v0 \ + / 1 | 0 \ + v1p - vn - v0p + \ 2 | 3 / + \ v1 / + + f0: vn, v0p, v0 + f1: vn, v0, v1p + f2: vn, v1p, v1 + f3: vn, v1, v0p + */ + int counter = 0; + while (!queue.empty()) { + counter += 1; + EdgeLink edge = queue.top(); + queue.pop(); + + int e0 = edge.id, e1 = E2E[e0]; + bool is_boundary = e1 == -1; + int f0 = e0 / 3, f1 = is_boundary ? -1 : (e1 / 3); + int v0 = F(e0 % 3, f0), v0p = F((e0 + 2) % 3, f0), v1 = F((e0 + 1) % 3, f0); + if ((V.col(v0) - V.col(v1)).squaredNorm() != edge.length) { + continue; + } + if (abs(diffs[e0][0]) < 2 && abs(diffs[e0][1]) < 2) continue; + if (f1 != -1) { + face_edgeOrients.push_back(Vector3i()); + sharp_edges.push_back(0); + sharp_edges.push_back(0); + sharp_edges.push_back(0); + face_edgeIds.push_back(Vector3i()); + } + int v1p = is_boundary ? -1 : F((e1 + 2) % 3, f1); + int vn = nV++; + nSplit++; + if (nV > V.cols()) { + V.conservativeResize(V.rows(), V.cols() * 2); + N.conservativeResize(N.rows(), N.cols() * 2); + Q.conservativeResize(Q.rows(), Q.cols() * 2); + O.conservativeResize(O.rows(), O.cols() * 2); + if (S) + S->conservativeResize(S->rows(), S->cols() * 2); + V2E.conservativeResize(V.cols()); + boundary.conservativeResize(V.cols()); + nonmanifold.conservativeResize(V.cols()); + } + + V.col(vn) = (V.col(v0) + V.col(v1)) * 0.5; + N.col(vn) = N.col(v0); + Q.col(vn) = Q.col(v0); + O.col(vn) = (O.col(v0) + O.col(v1)) * 0.5; + if (S) + S->col(vn) = S->col(v0); + + nonmanifold[vn] = false; + boundary[vn] = is_boundary; + + int eid = face_edgeIds[f0][e0 % 3]; + int sharp_eid = sharp_edges[e0]; + int eid01 = face_edgeIds[f0][(e0 + 1) % 3]; + int sharp_eid01 = sharp_edges[f0 * 3 + (e0 + 1) % 3]; + int eid02 = face_edgeIds[f0][(e0 + 2) % 3]; + int sharp_eid02 = sharp_edges[f0 * 3 + (e0 + 2) % 3]; + + int eid0, eid1, eid0p, eid1p; + int sharp_eid0, sharp_eid1, sharp_eid0p, sharp_eid1p; + + eid0 = eid; + sharp_eid0 = sharp_eid; + edge_values[eid0] = DEdge(v0, vn); + + eid1 = edge_values.size(); + sharp_eid1 = sharp_eid; + edge_values.push_back(DEdge(vn, v1)); + edge_diff.push_back(Vector2i()); + + eid0p = edge_values.size(); + sharp_eid0p = 0; + edge_values.push_back(DEdge(vn, v0p)); + edge_diff.push_back(Vector2i()); + + int f2 = is_boundary ? -1 : (nF++); + int f3 = nF++; + sharp_edges.push_back(0); + sharp_edges.push_back(0); + sharp_edges.push_back(0); + face_edgeIds.push_back(Vector3i()); + face_edgeOrients.push_back(Vector3i()); + + if (nF > F.cols()) { + F.conservativeResize(F.rows(), std::max(nF, (int)F.cols() * 2)); + face_spaces.resize(F.cols()); + E2E.conservativeResize(F.cols() * 3); + diffs.resize(F.cols() * 3); + } + + auto D01 = diffs[e0]; + auto D1p = diffs[e0 / 3 * 3 + (e0 + 1) % 3]; + auto Dp0 = diffs[e0 / 3 * 3 + (e0 + 2) % 3]; + + Vector2i D0n = D01 / 2; + + auto orients1 = face_spaces[f0]; + F.col(f0) << vn, v0p, v0; + face_edgeIds[f0] = Vector3i(eid0p, eid02, eid0); + sharp_edges[f0 * 3] = sharp_eid0p; + sharp_edges[f0 * 3 + 1] = sharp_eid02; + sharp_edges[f0 * 3 + 2] = sharp_eid0; + + diffs[f0 * 3] = D01 + D1p - D0n; + diffs[f0 * 3 + 1] = Dp0; + diffs[f0 * 3 + 2] = D0n; + int o1 = e0 % 3, o2 = e1 % 3; + AnalyzeOrient(f0, Vector3i(0, orients1.d[(o1 + 2) % 3], orients1.d[o1])); + if (!is_boundary) { + auto orients2 = face_spaces[f1]; + int eid11 = face_edgeIds[f1][(e1 + 1) % 3]; + int sharp_eid11 = sharp_edges[f1 * 3 + (e1 + 1) % 3]; + int eid12 = face_edgeIds[f1][(e1 + 2) % 3]; + int sharp_eid12 = sharp_edges[f1 * 3 + (e1 + 2) % 3]; + + auto Ds10 = diffs[e1]; + auto Ds0p = diffs[e1 / 3 * 3 + (e1 + 1) % 3]; + + auto Dsp1 = diffs[e1 / 3 * 3 + (e1 + 2) % 3]; + int orient = 0; + while (rshift90(D01, orient) != Ds10) orient += 1; + Vector2i Dsn0 = rshift90(D0n, orient); + + F.col(f1) << vn, v0, v1p; + eid1p = edge_values.size(); + sharp_eid1p = 0; + edge_values.push_back(DEdge(vn, v1p)); + edge_diff.push_back(Vector2i()); + + sharp_edges[f1 * 3] = sharp_eid0; + sharp_edges[f1 * 3 + 1] = sharp_eid11; + sharp_edges[f1 * 3 + 2] = sharp_eid1p; + face_edgeIds[f1] = (Vector3i(eid0, eid11, eid1p)); + diffs[f1 * 3] = Dsn0; + diffs[f1 * 3 + 1] = Ds0p; + diffs[f1 * 3 + 2] = Dsp1 + (Ds10 - Dsn0); + + AnalyzeOrient(f1, Vector3i(orients2.d[o2], orients2.d[(o2 + 1) % 3], 0)); + + face_spaces[f2] = face_spaces[f1]; + sharp_edges[f2 * 3] = sharp_eid1p; + sharp_edges[f2 * 3 + 1] = sharp_eid12; + sharp_edges[f2 * 3 + 2] = sharp_eid1; + face_edgeIds[f2] = (Vector3i(eid1p, eid12, eid1)); + F.col(f2) << vn, v1p, v1; + diffs[f2 * 3] = -Dsp1 - (Ds10 - Dsn0); + diffs[f2 * 3 + 1] = Dsp1; + diffs[f2 * 3 + 2] = Ds10 - Dsn0; + + AnalyzeOrient(f2, Vector3i(0, orients2.d[(o2 + 2) % 3], orients2.d[o2])); + } + face_spaces[f3] = face_spaces[f0]; + sharp_edges[f3 * 3] = sharp_eid1; + sharp_edges[f3 * 3 + 1] = sharp_eid01; + sharp_edges[f3 * 3 + 2] = sharp_eid0p; + face_edgeIds[f3] = (Vector3i(eid1, eid01, eid0p)); + F.col(f3) << vn, v1, v0p; + diffs[f3 * 3] = D01 - D0n; + diffs[f3 * 3 + 1] = D1p; + diffs[f3 * 3 + 2] = D0n - (D01 + D1p); + + AnalyzeOrient(f3, Vector3i(orients1.d[o1], orients1.d[(o1 + 1) % 3], 0)); + + FixOrient(f0); + if (!is_boundary) { + FixOrient(f1); + FixOrient(f2); + } + FixOrient(f3); + + const int e0p = E2E[dedge_prev_3(e0)], e0n = E2E[dedge_next_3(e0)]; + +#define sE2E(a, b) \ + E2E[a] = b; \ + if (b != -1) E2E[b] = a; + sE2E(3 * f0 + 0, 3 * f3 + 2); + sE2E(3 * f0 + 1, e0p); + sE2E(3 * f3 + 1, e0n); + if (is_boundary) { + sE2E(3 * f0 + 2, -1); + sE2E(3 * f3 + 0, -1); + } else { + const int e1p = E2E[dedge_prev_3(e1)], e1n = E2E[dedge_next_3(e1)]; + sE2E(3 * f0 + 2, 3 * f1 + 0); + sE2E(3 * f1 + 1, e1n); + sE2E(3 * f1 + 2, 3 * f2 + 0); + sE2E(3 * f2 + 1, e1p); + sE2E(3 * f2 + 2, 3 * f3 + 0); + } +#undef sE2E + + V2E[v0] = 3 * f0 + 2; + V2E[vn] = 3 * f0 + 0; + V2E[v1] = 3 * f3 + 1; + V2E[v0p] = 3 * f0 + 1; + if (!is_boundary) V2E[v1p] = 3 * f1 + 2; + + auto schedule = [&](int f) { + for (int i = 0; i < 3; ++i) { + if (abs(diffs[f * 3 + i][0]) > max_len || abs(diffs[f * 3 + i][1]) > max_len) { + EdgeLink e; + e.id = f * 3 + i; + e.length = (V.col(F((i + 1) % 3, f)) - V.col(F(i, f))).squaredNorm(); + e.diff = diffs[f * 3 + i]; + queue.push(e); + } + } + }; + + schedule(f0); + if (!is_boundary) { + schedule(f2); + schedule(f1); + }; + schedule(f3); + } + F.conservativeResize(F.rows(), nF); + V.conservativeResize(V.rows(), nV); + N.conservativeResize(V.rows(), nV); + Q.conservativeResize(V.rows(), nV); + O.conservativeResize(V.rows(), nV); + if (S) + S->conservativeResize(S->rows(), nV); + V2E.conservativeResize(nV); + boundary.conservativeResize(nV); + nonmanifold.conservativeResize(nV); + E2E.conservativeResize(nF * 3); + for (int i = 0; i < F.cols(); ++i) { + for (int j = 0; j < 3; ++j) { + auto diff = edge_diff[face_edgeIds[i][j]]; + if (abs(diff[0]) > 1 || abs(diff[1]) > 1) { + printf("wrong init %d %d!\n", face_edgeIds[i][j], i * 3 + j); + exit(0); + } + } + } + for (int i = 0; i < edge_diff.size(); ++i) { + if (abs(edge_diff[i][0]) > 1 || abs(edge_diff[i][1]) > 1) { + printf("wrong...\n"); + exit(0); + } + } +} + +} // namespace qflow diff --git a/extern/quadriflow/src/subdivide.hpp b/extern/quadriflow/src/subdivide.hpp new file mode 100644 index 00000000000..a93c58ac2a7 --- /dev/null +++ b/extern/quadriflow/src/subdivide.hpp @@ -0,0 +1,17 @@ +#include +#include + +#include "parametrizer.hpp" +using namespace Eigen; + +namespace qflow { + +void subdivide(MatrixXi &F, MatrixXd &V, VectorXd& rho, VectorXi &V2E, VectorXi &E2E, VectorXi &boundary, + VectorXi &nonmanifold, double maxLength); + +void subdivide_edgeDiff(MatrixXi &F, MatrixXd &V, MatrixXd &N, MatrixXd &Q, MatrixXd &O, MatrixXd* S, + VectorXi &V2E, VectorXi &E2E, VectorXi &boundary, VectorXi &nonmanifold, + std::vector &edge_diff, std::vector &edge_values, + std::vector &face_edgeOrients, std::vector &face_edgeIds, + std::vector& sharp_edges, std::map &singularities, int max_len); +} // namespace qflow -- cgit v1.2.3