From dd628b6af7f1b425c128fd0ef59a4bada17fa234 Mon Sep 17 00:00:00 2001 From: Jeremy Hu Date: Sat, 28 Dec 2019 14:51:59 +0930 Subject: [PATCH] Integrate QuadriFlow https://github.com/hjwdzh/QuadriFlow --- ACKNOWLEDGEMENTS.html | 6 + dust3d.pro | 54 + src/meshgenerator.cpp | 20 + src/remesher.cpp | 109 + src/remesher.h | 24 + thirdparty/QuadriFlow/.clang-format | 5 + thirdparty/QuadriFlow/.gitignore | 293 ++ .../3rd/MapleCOMSPS_LRB/CMakeLists.txt | 29 + .../QuadriFlow/3rd/MapleCOMSPS_LRB/LICENSE | 23 + .../QuadriFlow/3rd/MapleCOMSPS_LRB/README | 24 + .../3rd/MapleCOMSPS_LRB/core/Dimacs.h | 89 + .../3rd/MapleCOMSPS_LRB/core/Main.cc | 202 + .../3rd/MapleCOMSPS_LRB/core/Makefile | 4 + .../3rd/MapleCOMSPS_LRB/core/Solver.cc | 1547 +++++++ .../3rd/MapleCOMSPS_LRB/core/Solver.h | 524 +++ .../3rd/MapleCOMSPS_LRB/core/SolverTypes.h | 426 ++ .../doc/ReleaseNotes-2.2.0.txt | 79 + .../QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Alg.h | 84 + .../3rd/MapleCOMSPS_LRB/mtl/Alloc.h | 131 + .../QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Heap.h | 148 + .../3rd/MapleCOMSPS_LRB/mtl/IntTypes.h | 42 + .../QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Map.h | 193 + .../3rd/MapleCOMSPS_LRB/mtl/Queue.h | 69 + .../QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Sort.h | 98 + .../QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Vec.h | 130 + .../3rd/MapleCOMSPS_LRB/mtl/XAlloc.h | 45 + .../3rd/MapleCOMSPS_LRB/mtl/config.mk | 6 + .../3rd/MapleCOMSPS_LRB/mtl/template.mk | 107 + .../3rd/MapleCOMSPS_LRB/simp/Main.cc | 251 + .../3rd/MapleCOMSPS_LRB/simp/Makefile | 4 + .../3rd/MapleCOMSPS_LRB/simp/SimpSolver.cc | 825 ++++ .../3rd/MapleCOMSPS_LRB/simp/SimpSolver.h | 201 + .../3rd/MapleCOMSPS_LRB/utils/Makefile | 4 + .../3rd/MapleCOMSPS_LRB/utils/Options.cc | 91 + .../3rd/MapleCOMSPS_LRB/utils/Options.h | 386 ++ .../3rd/MapleCOMSPS_LRB/utils/ParseUtils.h | 122 + .../3rd/MapleCOMSPS_LRB/utils/System.cc | 92 + .../3rd/MapleCOMSPS_LRB/utils/System.h | 60 + .../3rd/lemon-1.3.1/.hg_archival.txt | 5 + .../QuadriFlow/3rd/lemon-1.3.1/.hgignore | 53 + thirdparty/QuadriFlow/3rd/lemon-1.3.1/.hgtags | 1 + thirdparty/QuadriFlow/3rd/lemon-1.3.1/AUTHORS | 26 + .../QuadriFlow/3rd/lemon-1.3.1/CMakeLists.txt | 373 ++ thirdparty/QuadriFlow/3rd/lemon-1.3.1/INSTALL | 167 + thirdparty/QuadriFlow/3rd/lemon-1.3.1/LICENSE | 32 + thirdparty/QuadriFlow/3rd/lemon-1.3.1/NEWS | 337 ++ thirdparty/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 + .../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 + .../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 .../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 + .../3rd/lemon-1.3.1/demo/CMakeLists.txt | 19 + .../3rd/lemon-1.3.1/demo/arg_parser_demo.cc | 112 + .../3rd/lemon-1.3.1/demo/digraph.lgf | 29 + .../3rd/lemon-1.3.1/demo/graph_to_eps_demo.cc | 206 + .../3rd/lemon-1.3.1/demo/lgf_demo.cc | 70 + .../3rd/lemon-1.3.1/lemon/CMakeLists.txt | 91 + .../3rd/lemon-1.3.1/lemon/adaptors.h | 3638 +++++++++++++++ .../3rd/lemon-1.3.1/lemon/arg_parser.cc | 474 ++ .../3rd/lemon-1.3.1/lemon/arg_parser.h | 440 ++ .../QuadriFlow/3rd/lemon-1.3.1/lemon/assert.h | 214 + .../QuadriFlow/3rd/lemon-1.3.1/lemon/base.cc | 37 + .../3rd/lemon-1.3.1/lemon/bellman_ford.h | 1116 +++++ .../QuadriFlow/3rd/lemon-1.3.1/lemon/bfs.h | 1754 +++++++ .../3rd/lemon-1.3.1/lemon/bin_heap.h | 347 ++ .../3rd/lemon-1.3.1/lemon/binomial_heap.h | 445 ++ .../lemon/bits/alteration_notifier.h | 472 ++ .../3rd/lemon-1.3.1/lemon/bits/array_map.h | 351 ++ .../3rd/lemon-1.3.1/lemon/bits/bezier.h | 174 + .../3rd/lemon-1.3.1/lemon/bits/default_map.h | 182 + .../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 ++ .../lemon-1.3.1/lemon/bits/graph_extender.h | 1332 ++++++ .../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 + .../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 + .../3rd/lemon-1.3.1/lemon/bucket_heap.h | 594 +++ .../3rd/lemon-1.3.1/lemon/capacity_scaling.h | 1014 ++++ .../QuadriFlow/3rd/lemon-1.3.1/lemon/cbc.cc | 460 ++ .../QuadriFlow/3rd/lemon-1.3.1/lemon/cbc.h | 129 + .../3rd/lemon-1.3.1/lemon/christofides_tsp.h | 254 ++ .../3rd/lemon-1.3.1/lemon/circulation.h | 807 ++++ .../QuadriFlow/3rd/lemon-1.3.1/lemon/clp.cc | 464 ++ .../QuadriFlow/3rd/lemon-1.3.1/lemon/clp.h | 164 + .../QuadriFlow/3rd/lemon-1.3.1/lemon/color.cc | 44 + .../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/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 ++ .../QuadriFlow/3rd/lemon-1.3.1/lemon/config.h | 22 + .../3rd/lemon-1.3.1/lemon/config.h.in | 22 + .../3rd/lemon-1.3.1/lemon/connectivity.h | 1688 +++++++ .../QuadriFlow/3rd/lemon-1.3.1/lemon/core.h | 2506 ++++++++++ .../3rd/lemon-1.3.1/lemon/cost_scaling.h | 1607 +++++++ .../3rd/lemon-1.3.1/lemon/counter.h | 249 + .../QuadriFlow/3rd/lemon-1.3.1/lemon/cplex.cc | 994 ++++ .../QuadriFlow/3rd/lemon-1.3.1/lemon/cplex.h | 292 ++ .../3rd/lemon-1.3.1/lemon/cycle_canceling.h | 1230 +++++ .../QuadriFlow/3rd/lemon-1.3.1/lemon/dfs.h | 1637 +++++++ .../QuadriFlow/3rd/lemon-1.3.1/lemon/dheap.h | 352 ++ .../3rd/lemon-1.3.1/lemon/dijkstra.h | 1303 ++++++ .../QuadriFlow/3rd/lemon-1.3.1/lemon/dim2.h | 726 +++ .../QuadriFlow/3rd/lemon-1.3.1/lemon/dimacs.h | 448 ++ .../3rd/lemon-1.3.1/lemon/edge_set.h | 1420 ++++++ .../3rd/lemon-1.3.1/lemon/edmonds_karp.h | 556 +++ .../3rd/lemon-1.3.1/lemon/elevator.h | 982 ++++ .../QuadriFlow/3rd/lemon-1.3.1/lemon/error.h | 276 ++ .../QuadriFlow/3rd/lemon-1.3.1/lemon/euler.h | 287 ++ .../3rd/lemon-1.3.1/lemon/fib_heap.h | 475 ++ .../lemon-1.3.1/lemon/fractional_matching.h | 2139 +++++++++ .../3rd/lemon-1.3.1/lemon/full_graph.h | 1082 +++++ .../QuadriFlow/3rd/lemon-1.3.1/lemon/glpk.cc | 1012 ++++ .../QuadriFlow/3rd/lemon-1.3.1/lemon/glpk.h | 263 ++ .../3rd/lemon-1.3.1/lemon/gomory_hu.h | 568 +++ .../3rd/lemon-1.3.1/lemon/graph_to_eps.h | 1186 +++++ .../3rd/lemon-1.3.1/lemon/greedy_tsp.h | 251 + .../3rd/lemon-1.3.1/lemon/grid_graph.h | 699 +++ .../lemon/grosso_locatelli_pullan_mc.h | 840 ++++ .../3rd/lemon-1.3.1/lemon/hao_orlin.h | 1015 +++++ .../lemon-1.3.1/lemon/hartmann_orlin_mmc.h | 654 +++ .../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 +++ .../3rd/lemon-1.3.1/lemon/karp_mmc.h | 590 +++ .../3rd/lemon-1.3.1/lemon/kruskal.h | 324 ++ .../3rd/lemon-1.3.1/lemon/lemon.pc.in | 10 + .../3rd/lemon-1.3.1/lemon/lgf_reader.h | 3854 ++++++++++++++++ .../3rd/lemon-1.3.1/lemon/lgf_writer.h | 2687 +++++++++++ .../3rd/lemon-1.3.1/lemon/list_graph.h | 2510 ++++++++++ .../QuadriFlow/3rd/lemon-1.3.1/lemon/lp.h | 95 + .../3rd/lemon-1.3.1/lemon/lp_base.cc | 30 + .../3rd/lemon-1.3.1/lemon/lp_base.h | 2147 +++++++++ .../3rd/lemon-1.3.1/lemon/lp_skeleton.cc | 143 + .../3rd/lemon-1.3.1/lemon/lp_skeleton.h | 234 + .../QuadriFlow/3rd/lemon-1.3.1/lemon/maps.h | 4057 +++++++++++++++++ .../3rd/lemon-1.3.1/lemon/matching.h | 3505 ++++++++++++++ .../QuadriFlow/3rd/lemon-1.3.1/lemon/math.h | 77 + .../lemon/max_cardinality_search.h | 794 ++++ .../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 + .../lemon-1.3.1/lemon/nearest_neighbor_tsp.h | 238 + .../3rd/lemon-1.3.1/lemon/network_simplex.h | 1659 +++++++ .../3rd/lemon-1.3.1/lemon/opt2_tsp.h | 367 ++ .../3rd/lemon-1.3.1/lemon/pairing_heap.h | 474 ++ .../QuadriFlow/3rd/lemon-1.3.1/lemon/path.h | 1164 +++++ .../3rd/lemon-1.3.1/lemon/planarity.h | 2754 +++++++++++ .../3rd/lemon-1.3.1/lemon/preflow.h | 985 ++++ .../3rd/lemon-1.3.1/lemon/quad_heap.h | 343 ++ .../3rd/lemon-1.3.1/lemon/radix_heap.h | 438 ++ .../3rd/lemon-1.3.1/lemon/radix_sort.h | 487 ++ .../3rd/lemon-1.3.1/lemon/random.cc | 29 + .../QuadriFlow/3rd/lemon-1.3.1/lemon/random.h | 1005 ++++ .../3rd/lemon-1.3.1/lemon/smart_graph.h | 1344 ++++++ .../3rd/lemon-1.3.1/lemon/soplex.cc | 465 ++ .../QuadriFlow/3rd/lemon-1.3.1/lemon/soplex.h | 158 + .../3rd/lemon-1.3.1/lemon/static_graph.h | 476 ++ .../3rd/lemon-1.3.1/lemon/suurballe.h | 776 ++++ .../3rd/lemon-1.3.1/lemon/time_measure.h | 610 +++ .../3rd/lemon-1.3.1/lemon/tolerance.h | 242 + .../3rd/lemon-1.3.1/lemon/unionfind.h | 1824 ++++++++ .../3rd/lemon-1.3.1/scripts/unify-sources.sh | 390 ++ .../lemon-1.3.1/scripts/valgrind-wrapper.sh | 22 + .../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 ++ .../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 + .../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 + .../3rd/lemon-1.3.1/test/dim_test.cc | 87 + .../3rd/lemon-1.3.1/test/edge_set_test.cc | 396 ++ .../3rd/lemon-1.3.1/test/error_test.cc | 90 + .../3rd/lemon-1.3.1/test/euler_test.cc | 225 + .../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 ++ .../3rd/lemon-1.3.1/test/graph_test.cc | 603 +++ .../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 + .../3rd/lemon-1.3.1/test/heap_test.cc | 310 ++ .../3rd/lemon-1.3.1/test/kruskal_test.cc | 147 + .../test/lgf_reader_writer_test.cc | 578 +++ .../3rd/lemon-1.3.1/test/lgf_test.cc | 169 + .../3rd/lemon-1.3.1/test/lp_test.cc | 470 ++ .../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 ++ .../test/min_cost_arborescence_test.cc | 207 + .../lemon-1.3.1/test/min_cost_flow_test.cc | 548 +++ .../lemon-1.3.1/test/min_mean_cycle_test.cc | 223 + .../3rd/lemon-1.3.1/test/mip_test.cc | 171 + .../test/nagamochi_ibaraki_test.cc | 142 + .../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 ++ .../3rd/lemon-1.3.1/test/random_test.cc | 40 + .../3rd/lemon-1.3.1/test/suurballe_test.cc | 267 ++ .../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 + .../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 + .../3rd/lemon-1.3.1/tools/lgf-gen.cc | 847 ++++ thirdparty/QuadriFlow/3rd/pcg32/pcg32/pcg32.h | 209 + .../3rd/pss/pss/parallel_stable_sort.h | 140 + .../QuadriFlow/3rd/pss/pss/pss_common.h | 106 + thirdparty/QuadriFlow/CMakeLists.txt | 152 + thirdparty/QuadriFlow/LICENSE.txt | 37 + thirdparty/QuadriFlow/README.md | 134 + thirdparty/QuadriFlow/cmake/FindEigen.cmake | 263 ++ thirdparty/QuadriFlow/cmake/FindGUROBI.cmake | 62 + thirdparty/QuadriFlow/cmake/FindTBB.cmake | 425 ++ thirdparty/QuadriFlow/demo.sh | 7 + thirdparty/QuadriFlow/img/result.jpg | Bin 0 -> 596950 bytes thirdparty/QuadriFlow/src/Optimizer.cu | 281 ++ thirdparty/QuadriFlow/src/adjacent-matrix.cpp | 35 + thirdparty/QuadriFlow/src/adjacent-matrix.hpp | 37 + thirdparty/QuadriFlow/src/compare-key.hpp | 102 + thirdparty/QuadriFlow/src/config.hpp | 44 + thirdparty/QuadriFlow/src/dedge.cpp | 487 ++ thirdparty/QuadriFlow/src/dedge.hpp | 25 + thirdparty/QuadriFlow/src/disajoint-tree.hpp | 151 + thirdparty/QuadriFlow/src/dset.hpp | 163 + thirdparty/QuadriFlow/src/field-math.hpp | 483 ++ thirdparty/QuadriFlow/src/flow.hpp | 375 ++ thirdparty/QuadriFlow/src/hierarchy.cpp | 1343 ++++++ thirdparty/QuadriFlow/src/hierarchy.hpp | 99 + thirdparty/QuadriFlow/src/loader.cpp | 159 + thirdparty/QuadriFlow/src/loader.hpp | 15 + thirdparty/QuadriFlow/src/localsat.cpp | 295 ++ thirdparty/QuadriFlow/src/localsat.hpp | 31 + thirdparty/QuadriFlow/src/main.cpp | 127 + thirdparty/QuadriFlow/src/merge-vertex.cpp | 44 + thirdparty/QuadriFlow/src/merge-vertex.hpp | 14 + thirdparty/QuadriFlow/src/optimizer.cpp | 1419 ++++++ thirdparty/QuadriFlow/src/optimizer.hpp | 56 + .../QuadriFlow/src/parametrizer-flip.cpp | 583 +++ .../QuadriFlow/src/parametrizer-int.cpp | 425 ++ .../QuadriFlow/src/parametrizer-mesh.cpp | 615 +++ .../QuadriFlow/src/parametrizer-scale.cpp | 119 + .../QuadriFlow/src/parametrizer-sing.cpp | 142 + thirdparty/QuadriFlow/src/parametrizer.cpp | 247 + thirdparty/QuadriFlow/src/parametrizer.hpp | 177 + thirdparty/QuadriFlow/src/post-solver.cpp | 427 ++ thirdparty/QuadriFlow/src/post-solver.hpp | 64 + thirdparty/QuadriFlow/src/serialize.hpp | 127 + thirdparty/QuadriFlow/src/subdivide.cpp | 516 +++ thirdparty/QuadriFlow/src/subdivide.hpp | 17 + .../eigen/Eigen/src/Core/Functors.h | 18 + .../Eigen/src/plugins/ArrayCwiseUnaryOps.h | 7 +- 283 files changed, 126316 insertions(+), 1 deletion(-) create mode 100644 src/remesher.cpp create mode 100644 src/remesher.h create mode 100755 thirdparty/QuadriFlow/.clang-format create mode 100755 thirdparty/QuadriFlow/.gitignore create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/CMakeLists.txt create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/LICENSE create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/README create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/core/Dimacs.h create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/core/Main.cc create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/core/Makefile create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/core/Solver.cc create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/core/Solver.h create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/core/SolverTypes.h create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/doc/ReleaseNotes-2.2.0.txt create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Alg.h create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Alloc.h create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Heap.h create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/IntTypes.h create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Map.h create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Queue.h create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Sort.h create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Vec.h create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/XAlloc.h create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/config.mk create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/template.mk create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/simp/Main.cc create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/simp/Makefile create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/simp/SimpSolver.cc create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/simp/SimpSolver.h create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/utils/Makefile create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/utils/Options.cc create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/utils/Options.h create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/utils/ParseUtils.h create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/utils/System.cc create mode 100755 thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/utils/System.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/.hg_archival.txt create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/.hgignore create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/.hgtags create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/AUTHORS create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/CMakeLists.txt create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/INSTALL create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/LICENSE create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/NEWS create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/README create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/FindCOIN.cmake create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/FindGLPK.cmake create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/FindGhostscript.cmake create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/FindILOG.cmake create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/FindSOPLEX.cmake create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/LEMONConfig.cmake.in create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/nsis/lemon.ico create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/nsis/uninstall.ico create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/version.cmake create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/version.cmake.in create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/contrib/CMakeLists.txt create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/demo/CMakeLists.txt create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/demo/arg_parser_demo.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/demo/digraph.lgf create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/demo/graph_to_eps_demo.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/demo/lgf_demo.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/CMakeLists.txt create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/adaptors.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/arg_parser.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/arg_parser.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/assert.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/base.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bellman_ford.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bfs.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bin_heap.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/binomial_heap.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/alteration_notifier.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/array_map.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/bezier.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/default_map.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/edge_set_extender.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/enable_if.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/graph_adaptor_extender.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/graph_extender.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/lock.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/map_extender.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/path_dump.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/solver_bits.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/traits.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/variant.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/vector_map.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/windows.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/windows.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bucket_heap.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/capacity_scaling.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/cbc.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/cbc.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/christofides_tsp.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/circulation.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/clp.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/clp.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/color.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/color.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/concept_check.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/concepts/bpgraph.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/concepts/digraph.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/concepts/graph.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/concepts/graph_components.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/concepts/heap.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/concepts/maps.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/concepts/path.h create mode 100644 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/config.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/config.h.in create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/connectivity.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/core.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/cost_scaling.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/counter.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/cplex.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/cplex.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/cycle_canceling.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/dfs.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/dheap.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/dijkstra.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/dim2.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/dimacs.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/edge_set.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/edmonds_karp.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/elevator.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/error.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/euler.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/fib_heap.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/fractional_matching.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/full_graph.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/glpk.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/glpk.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/gomory_hu.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/graph_to_eps.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/greedy_tsp.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/grid_graph.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/grosso_locatelli_pullan_mc.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/hao_orlin.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/hartmann_orlin_mmc.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/howard_mmc.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/hypercube_graph.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/insertion_tsp.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/karp_mmc.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/kruskal.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/lemon.pc.in create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/lgf_reader.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/lgf_writer.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/list_graph.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/lp.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/lp_base.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/lp_base.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/lp_skeleton.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/lp_skeleton.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/maps.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/matching.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/math.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/max_cardinality_search.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/min_cost_arborescence.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/nagamochi_ibaraki.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/nauty_reader.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/nearest_neighbor_tsp.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/network_simplex.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/opt2_tsp.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/pairing_heap.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/path.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/planarity.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/preflow.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/quad_heap.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/radix_heap.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/radix_sort.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/random.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/random.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/smart_graph.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/soplex.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/soplex.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/static_graph.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/suurballe.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/time_measure.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/tolerance.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/unionfind.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/scripts/unify-sources.sh create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/scripts/valgrind-wrapper.sh create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/CMakeLists.txt create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/adaptors_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/arc_look_up_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/bellman_ford_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/bfs_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/bpgraph_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/circulation_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/connectivity_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/counter_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/dfs_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/digraph_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/dijkstra_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/dim_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/edge_set_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/error_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/euler_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/fractional_matching_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/gomory_hu_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/graph_copy_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/graph_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/graph_test.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/graph_utils_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/hao_orlin_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/heap_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/kruskal_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/lgf_reader_writer_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/lgf_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/lp_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/maps_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/matching_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/max_cardinality_search_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/max_clique_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/max_flow_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/min_cost_arborescence_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/min_cost_flow_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/min_mean_cycle_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/mip_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/nagamochi_ibaraki_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/path_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/planarity_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/radix_sort_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/random_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/suurballe_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/test_tools.h create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/test_tools_fail.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/test_tools_pass.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/time_measure_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/tsp_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/unionfind_test.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/tools/CMakeLists.txt create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/tools/dimacs-solver.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/tools/dimacs-to-lgf.cc create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/tools/lemon-0.x-to-1.x.sh create mode 100755 thirdparty/QuadriFlow/3rd/lemon-1.3.1/tools/lgf-gen.cc create mode 100755 thirdparty/QuadriFlow/3rd/pcg32/pcg32/pcg32.h create mode 100755 thirdparty/QuadriFlow/3rd/pss/pss/parallel_stable_sort.h create mode 100755 thirdparty/QuadriFlow/3rd/pss/pss/pss_common.h create mode 100755 thirdparty/QuadriFlow/CMakeLists.txt create mode 100755 thirdparty/QuadriFlow/LICENSE.txt create mode 100755 thirdparty/QuadriFlow/README.md create mode 100755 thirdparty/QuadriFlow/cmake/FindEigen.cmake create mode 100755 thirdparty/QuadriFlow/cmake/FindGUROBI.cmake create mode 100755 thirdparty/QuadriFlow/cmake/FindTBB.cmake create mode 100755 thirdparty/QuadriFlow/demo.sh create mode 100755 thirdparty/QuadriFlow/img/result.jpg create mode 100755 thirdparty/QuadriFlow/src/Optimizer.cu create mode 100755 thirdparty/QuadriFlow/src/adjacent-matrix.cpp create mode 100755 thirdparty/QuadriFlow/src/adjacent-matrix.hpp create mode 100755 thirdparty/QuadriFlow/src/compare-key.hpp create mode 100755 thirdparty/QuadriFlow/src/config.hpp create mode 100755 thirdparty/QuadriFlow/src/dedge.cpp create mode 100755 thirdparty/QuadriFlow/src/dedge.hpp create mode 100755 thirdparty/QuadriFlow/src/disajoint-tree.hpp create mode 100755 thirdparty/QuadriFlow/src/dset.hpp create mode 100755 thirdparty/QuadriFlow/src/field-math.hpp create mode 100755 thirdparty/QuadriFlow/src/flow.hpp create mode 100755 thirdparty/QuadriFlow/src/hierarchy.cpp create mode 100755 thirdparty/QuadriFlow/src/hierarchy.hpp create mode 100755 thirdparty/QuadriFlow/src/loader.cpp create mode 100755 thirdparty/QuadriFlow/src/loader.hpp create mode 100755 thirdparty/QuadriFlow/src/localsat.cpp create mode 100755 thirdparty/QuadriFlow/src/localsat.hpp create mode 100755 thirdparty/QuadriFlow/src/main.cpp create mode 100755 thirdparty/QuadriFlow/src/merge-vertex.cpp create mode 100755 thirdparty/QuadriFlow/src/merge-vertex.hpp create mode 100755 thirdparty/QuadriFlow/src/optimizer.cpp create mode 100755 thirdparty/QuadriFlow/src/optimizer.hpp create mode 100755 thirdparty/QuadriFlow/src/parametrizer-flip.cpp create mode 100755 thirdparty/QuadriFlow/src/parametrizer-int.cpp create mode 100755 thirdparty/QuadriFlow/src/parametrizer-mesh.cpp create mode 100755 thirdparty/QuadriFlow/src/parametrizer-scale.cpp create mode 100755 thirdparty/QuadriFlow/src/parametrizer-sing.cpp create mode 100755 thirdparty/QuadriFlow/src/parametrizer.cpp create mode 100755 thirdparty/QuadriFlow/src/parametrizer.hpp create mode 100755 thirdparty/QuadriFlow/src/post-solver.cpp create mode 100755 thirdparty/QuadriFlow/src/post-solver.hpp create mode 100755 thirdparty/QuadriFlow/src/serialize.hpp create mode 100755 thirdparty/QuadriFlow/src/subdivide.cpp create mode 100755 thirdparty/QuadriFlow/src/subdivide.hpp diff --git a/ACKNOWLEDGEMENTS.html b/ACKNOWLEDGEMENTS.html index 354bd46d..51b3db25 100644 --- a/ACKNOWLEDGEMENTS.html +++ b/ACKNOWLEDGEMENTS.html @@ -1224,4 +1224,10 @@ https://www.reddit.com/r/gamedev/comments/5iuf3h/i_am_writting_a_3d_monster_mode
     A Fast Parallel Algorithm for Thinning Digital Patterns
     https://dl.acm.org/citation.cfm?id=358023
+
+ +

Huang, Jingwei and Zhou, Yichao and Niessner, Matthias and Shewchuk, Jonathan Richard and Guibas, Leonidas J.

+
+    QuadriFlow: A Scalable and Robust Method for Quadrangulation
+    http://stanford.edu/~jingweih/papers/quadriflow/
 
\ No newline at end of file diff --git a/dust3d.pro b/dust3d.pro index 47baa91a..3664a929 100644 --- a/dust3d.pro +++ b/dust3d.pro @@ -483,10 +483,64 @@ HEADERS += src/imageskeletonextractor.h SOURCES += src/contourtopartconverter.cpp HEADERS += src/contourtopartconverter.h +SOURCES += src/remesher.cpp +HEADERS += src/remesher.h + SOURCES += src/main.cpp HEADERS += src/version.h +INCLUDEPATH += thirdparty/QuadriFlow +INCLUDEPATH += thirdparty/QuadriFlow/3rd/pcg32 +INCLUDEPATH += thirdparty/QuadriFlow/3rd/pss +INCLUDEPATH += thirdparty/QuadriFlow/3rd/lemon-1.3.1 + +SOURCES += thirdparty/QuadriFlow/src/adjacent-matrix.cpp +HEADERS += thirdparty/QuadriFlow/src/adjacent-matrix.hpp + +HEADERS += thirdparty/QuadriFlow/src/compare-key.hpp + +HEADERS += thirdparty/QuadriFlow/src/config.hpp + +SOURCES += thirdparty/QuadriFlow/src/dedge.cpp +HEADERS += thirdparty/QuadriFlow/src/dedge.hpp + +HEADERS += thirdparty/QuadriFlow/src/disajoint-tree.hpp + +HEADERS += thirdparty/QuadriFlow/src/dset.hpp + +HEADERS += thirdparty/QuadriFlow/src/field-math.hpp + +HEADERS += thirdparty/QuadriFlow/src/flow.hpp + +SOURCES += thirdparty/QuadriFlow/src/hierarchy.cpp +HEADERS += thirdparty/QuadriFlow/src/hierarchy.hpp + +SOURCES += thirdparty/QuadriFlow/src/loader.cpp +HEADERS += thirdparty/QuadriFlow/src/loader.hpp + +SOURCES += thirdparty/QuadriFlow/src/localsat.cpp +HEADERS += thirdparty/QuadriFlow/src/localsat.hpp + +SOURCES += thirdparty/QuadriFlow/src/merge-vertex.cpp +HEADERS += thirdparty/QuadriFlow/src/merge-vertex.hpp + +SOURCES += thirdparty/QuadriFlow/src/optimizer.cpp +HEADERS += thirdparty/QuadriFlow/src/optimizer.hpp + +SOURCES += thirdparty/QuadriFlow/src/parametrizer.cpp +SOURCES += thirdparty/QuadriFlow/src/parametrizer-flip.cpp +SOURCES += thirdparty/QuadriFlow/src/parametrizer-int.cpp +SOURCES += thirdparty/QuadriFlow/src/parametrizer-mesh.cpp +SOURCES += thirdparty/QuadriFlow/src/parametrizer-scale.cpp +SOURCES += thirdparty/QuadriFlow/src/parametrizer-sing.cpp +HEADERS += thirdparty/QuadriFlow/src/parametrizer.hpp + +HEADERS += thirdparty/QuadriFlow/src/serialize.hpp + +SOURCES += thirdparty/QuadriFlow/src/subdivide.cpp +HEADERS += thirdparty/QuadriFlow/src/subdivide.hpp + INCLUDEPATH += thirdparty/bullet3/src SOURCES += thirdparty/bullet3/src/LinearMath/btAlignedAllocator.cpp diff --git a/src/meshgenerator.cpp b/src/meshgenerator.cpp index e5119289..a926d74c 100644 --- a/src/meshgenerator.cpp +++ b/src/meshgenerator.cpp @@ -16,6 +16,7 @@ #include "imageforever.h" #include "gridmeshbuilder.h" #include "triangulatefaces.h" +#include "remesher.h" MeshGenerator::MeshGenerator(Snapshot *snapshot) : m_snapshot(snapshot) @@ -1310,6 +1311,25 @@ void MeshGenerator::generate() m_outcome->vertices = combinedVertices; m_outcome->triangles = combinedFaces; m_outcome->paintMaps = componentCache.outcomePaintMaps; + + /* + Remesher remesher; + remesher.setMesh(combinedVertices, combinedFaces); + remesher.remesh(); + m_outcome->vertices = remesher.getRemeshedVertices(); + const auto &remeshedFaces = remesher.getRemeshedFaces(); + m_outcome->triangleAndQuads = remeshedFaces; + m_outcome->triangles.clear(); + m_outcome->triangles.reserve(remeshedFaces.size() * 2); + for (const auto &it: remeshedFaces) { + m_outcome->triangles.push_back(std::vector { + it[0], it[1], it[2] + }); + m_outcome->triangles.push_back(std::vector { + it[2], it[3], it[0] + }); + } + */ } // Recursively check uncombined components diff --git a/src/remesher.cpp b/src/remesher.cpp new file mode 100644 index 00000000..a71aba4a --- /dev/null +++ b/src/remesher.cpp @@ -0,0 +1,109 @@ +#include +#include +#include +#include +#ifdef WITH_CUDA +#include +#endif +#include "remesher.h" + +using namespace qflow; + +Remesher::~Remesher() +{ +} + +void Remesher::setMesh(const std::vector &vertices, + const std::vector> &triangles) +{ + m_vertices = vertices; + m_triangles = triangles; +} + +const std::vector &Remesher::getRemeshedVertices() +{ + return m_remeshedVertices; +} +const std::vector> &Remesher::getRemeshedFaces() +{ + return m_remeshedFaces; +} + +void Remesher::remesh() +{ + Parametrizer field; + +#ifdef WITH_CUDA + cudaFree(0); +#endif + + field.V.resize(3, m_vertices.size()); + field.F.resize(3, m_triangles.size()); + for (decltype(m_vertices.size()) i = 0; i < m_vertices.size(); i++) { + const auto &vertex = m_vertices[i]; + field.V.col(i) << (double)vertex.x(), (double)vertex.y(), (double)vertex.z(); + } + for (decltype(m_triangles.size()) i = 0; i < m_triangles.size(); i++) { + const auto &face = m_triangles[i]; + field.F.col(i) << (uint32_t)face[0], (uint32_t)face[1], (uint32_t)face[2]; + } + field.NormalizeMesh(); + + int faces = -1; + field.Initialize(faces); + + if (field.flag_preserve_boundary) { + Hierarchy& hierarchy = field.hierarchy; + hierarchy.clearConstraints(); + for (uint32_t i = 0; i < 3 * hierarchy.mF.cols(); ++i) { + if (hierarchy.mE2E[i] == -1) { + uint32_t i0 = hierarchy.mF(i % 3, i / 3); + uint32_t i1 = hierarchy.mF((i + 1) % 3, i / 3); + Vector3d p0 = hierarchy.mV[0].col(i0), p1 = hierarchy.mV[0].col(i1); + Vector3d edge = p1 - p0; + if (edge.squaredNorm() > 0) { + edge.normalize(); + hierarchy.mCO[0].col(i0) = p0; + hierarchy.mCO[0].col(i1) = p1; + hierarchy.mCQ[0].col(i0) = hierarchy.mCQ[0].col(i1) = edge; + hierarchy.mCQw[0][i0] = hierarchy.mCQw[0][i1] = hierarchy.mCOw[0][i0] = hierarchy.mCOw[0][i1] = + 1.0; + } + } + } + hierarchy.propagateConstraints(); + } + + Optimizer::optimize_orientations(field.hierarchy); + field.ComputeOrientationSingularities(); + + if (field.flag_adaptive_scale == 1) { + field.EstimateSlope(); + } + + Optimizer::optimize_scale(field.hierarchy, field.rho, field.flag_adaptive_scale); + field.flag_adaptive_scale = 1; + + Optimizer::optimize_positions(field.hierarchy, field.flag_adaptive_scale); + field.ComputePositionSingularities(); + + field.ComputeIndexMap(); + + m_remeshedVertices.reserve(field.O_compact.size()); + for (size_t i = 0; i < field.O_compact.size(); ++i) { + auto t = field.O_compact[i] * field.normalize_scale + field.normalize_offset; + m_remeshedVertices.push_back(QVector3D(t[0], t[1], t[2])); + } + m_remeshedFaces.reserve(field.F_compact.size()); + for (size_t i = 0; i < field.F_compact.size(); ++i) { + m_remeshedFaces.push_back(std::vector { + (size_t)field.F_compact[i][0], + (size_t)field.F_compact[i][1], + (size_t)field.F_compact[i][2], + (size_t)field.F_compact[i][3] + }); + } + + printf("m_remeshedVertices.size:%lu\r\n", m_remeshedVertices.size()); + printf("m_remeshedFaces.size:%lu\r\n", m_remeshedFaces.size()); +} diff --git a/src/remesher.h b/src/remesher.h new file mode 100644 index 00000000..1a35515f --- /dev/null +++ b/src/remesher.h @@ -0,0 +1,24 @@ +#ifndef DUST3D_REMESHER_H +#define DUST3D_REMESHER_H +#include +#include +#include + +class Remesher : public QObject +{ + Q_OBJECT +public: + ~Remesher(); + void setMesh(const std::vector &vertices, + const std::vector> &triangles); + void remesh(); + const std::vector &getRemeshedVertices(); + const std::vector> &getRemeshedFaces(); +private: + std::vector m_vertices; + std::vector> m_triangles; + std::vector m_remeshedVertices; + std::vector> m_remeshedFaces; +}; + +#endif diff --git a/thirdparty/QuadriFlow/.clang-format b/thirdparty/QuadriFlow/.clang-format new file mode 100755 index 00000000..3f406687 --- /dev/null +++ b/thirdparty/QuadriFlow/.clang-format @@ -0,0 +1,5 @@ +Language: Cpp +BasedOnStyle: Google +IndentWidth: 4 +Standard: Cpp11 +ColumnLimit: 99 diff --git a/thirdparty/QuadriFlow/.gitignore b/thirdparty/QuadriFlow/.gitignore new file mode 100755 index 00000000..c92aebc8 --- /dev/null +++ b/thirdparty/QuadriFlow/.gitignore @@ -0,0 +1,293 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates +*.o +*.or + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +data/ +[Bb]uild/ +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +open-wbo +open-wbo_* + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Typescript v1 declaration files +typings/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/CMakeLists.txt b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/CMakeLists.txt new file mode 100755 index 00000000..113701d1 --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.1) +project(MapleCOMSPS_LRB) + +find_package(ZLIB) + +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +include_directories(${ZLIB_INCLUDE_DIRS}) + +set( + minisat_SRC + core/Solver.cc + simp/Main.cc + simp/SimpSolver.cc + utils/Options.cc + utils/System.cc +) + +add_executable( + minisat + ${minisat_SRC} +) + +target_link_libraries( + minisat + ${ZLIB_LIBRARIES} +) diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/LICENSE b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/LICENSE new file mode 100755 index 00000000..9ecdbc93 --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/LICENSE @@ -0,0 +1,23 @@ +MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson + Copyright (c) 2007-2010 Niklas Sorensson + +Chanseok Oh's MiniSat Patch Series -- Copyright (c) 2015, Chanseok Oh + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +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 AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF 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/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/README b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/README new file mode 100755 index 00000000..e5e5617d --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/README @@ -0,0 +1,24 @@ +================================================================================ +DIRECTORY OVERVIEW: + +mtl/ Mini Template Library +utils/ Generic helper code (I/O, Parsing, CPU-time, etc) +core/ A core version of the solver +simp/ An extended solver with simplification capabilities +README +LICENSE + +================================================================================ +BUILDING: (release version: without assertions, statically linked, etc) + +export MROOT= (or setenv in cshell) +cd { core | simp } +gmake rs +cp minisat_static /minisat + +================================================================================ +EXAMPLES: + +Run minisat with same heuristics as version 2.0: + +> minisat -no-luby -rinc=1.5 -phase-saving=0 -rnd-freq=0.02 diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/core/Dimacs.h b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/core/Dimacs.h new file mode 100755 index 00000000..a05e900c --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/core/Dimacs.h @@ -0,0 +1,89 @@ +/****************************************************************************************[Dimacs.h] +Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +Copyright (c) 2007-2010, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +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 AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + +#ifndef Minisat_Dimacs_h +#define Minisat_Dimacs_h + +#include + +#include "utils/ParseUtils.h" +#include "core/SolverTypes.h" + +namespace Minisat { + +//================================================================================================= +// DIMACS Parser: + +template +static void readClause(B& in, Solver& S, vec& lits) { + int parsed_lit, var; + lits.clear(); + for (;;){ + parsed_lit = parseInt(in); + if (parsed_lit == 0) break; + var = abs(parsed_lit)-1; + while (var >= S.nVars()) S.newVar(); + lits.push( (parsed_lit > 0) ? mkLit(var) : ~mkLit(var) ); + } +} + +template +static void parse_DIMACS_main(B& in, Solver& S) { + vec lits; + int vars = 0; + int clauses = 0; + int cnt = 0; + for (;;){ + skipWhitespace(in); + if (*in == EOF) break; + else if (*in == 'p'){ + if (eagerMatch(in, "p cnf")){ + vars = parseInt(in); + clauses = parseInt(in); + // SATRACE'06 hack + // if (clauses > 4000000) + // S.eliminate(true); + }else{ + printf("PARSE ERROR! Unexpected char: %c\n", *in), exit(3); + } + } else if (*in == 'c' || *in == 'p') + skipLine(in); + else{ + cnt++; + readClause(in, S, lits); + S.addClause_(lits); } + } + if (vars != S.nVars()) + fprintf(stderr, "WARNING! DIMACS header mismatch: wrong number of variables.\n"); + if (cnt != clauses) + fprintf(stderr, "WARNING! DIMACS header mismatch: wrong number of clauses.\n"); +} + +// Inserts problem into solver. +// +template +static void parse_DIMACS(gzFile input_stream, Solver& S) { + StreamBuffer in(input_stream); + parse_DIMACS_main(in, S); } + +//================================================================================================= +} + +#endif diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/core/Main.cc b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/core/Main.cc new file mode 100755 index 00000000..7c93befc --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/core/Main.cc @@ -0,0 +1,202 @@ +/*****************************************************************************************[Main.cc] +Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +Copyright (c) 2007-2010, Niklas Sorensson + +Chanseok Oh's MiniSat Patch Series -- Copyright (c) 2015, Chanseok Oh + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +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 AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + +#include + +#include +#include + +#include "utils/System.h" +#include "utils/ParseUtils.h" +#include "utils/Options.h" +#include "core/Dimacs.h" +#include "core/Solver.h" + +using namespace Minisat; + +//================================================================================================= + + +void printStats(Solver& solver) +{ + double cpu_time = cpuTime(); +// double mem_used = memUsedPeak(); +// printf("c restarts : %"PRIu64"\n", solver.starts); +// printf("c conflicts : %-12"PRIu64" (%.0f /sec)\n", solver.conflicts , solver.conflicts /cpu_time); +// printf("c decisions : %-12"PRIu64" (%4.2f %% random) (%.0f /sec)\n", solver.decisions, (float)solver.rnd_decisions*100 / (float)solver.decisions, solver.decisions /cpu_time); +// printf("c propagations : %-12"PRIu64" (%.0f /sec)\n", solver.propagations, solver.propagations/cpu_time); +// printf("c conflict literals : %-12"PRIu64" (%4.2f %% deleted)\n", solver.tot_literals, (solver.max_literals - solver.tot_literals)*100 / (double)solver.max_literals); +// if (mem_used != 0) printf("c Memory used : %.2f MB\n", mem_used); + printf("c CPU time : %g s\n", cpu_time); +} + + +static Solver* solver; +// Terminate by notifying the solver and back out gracefully. This is mainly to have a test-case +// for this feature of the Solver as it may take longer than an immediate call to '_exit()'. +static void SIGINT_interrupt(int signum) { solver->interrupt(); } + +// Note that '_exit()' rather than 'exit()' has to be used. The reason is that 'exit()' calls +// destructors and may cause deadlocks if a malloc/free function happens to be running (these +// functions are guarded by locks for multithreaded use). +static void SIGINT_exit(int signum) { + printf("\n"); printf("c *** INTERRUPTED ***\n"); + if (solver->verbosity > 0){ + printStats(*solver); + printf("\n"); printf("c *** INTERRUPTED ***\n"); } + _exit(1); } + + +//================================================================================================= +// Main: + + +int main(int argc, char** argv) +{ + try { + setUsageHelp("USAGE: %s [options] \n\n where input may be either in plain or gzipped DIMACS.\n"); + printf("c This is COMiniSatPS.\n"); + +#if defined(__linux__) + fpu_control_t oldcw, newcw; + _FPU_GETCW(oldcw); newcw = (oldcw & ~_FPU_EXTENDED) | _FPU_DOUBLE; _FPU_SETCW(newcw); + printf("c WARNING: for repeatability, setting FPU to use double precision\n"); +#endif + // Extra options: + // + IntOption verb ("MAIN", "verb", "Verbosity level (0=silent, 1=some, 2=more).", 1, IntRange(0, 2)); + IntOption cpu_lim("MAIN", "cpu-lim","Limit on CPU time allowed in seconds.\n", INT32_MAX, IntRange(0, INT32_MAX)); + IntOption mem_lim("MAIN", "mem-lim","Limit on memory usage in megabytes.\n", INT32_MAX, IntRange(0, INT32_MAX)); + + parseOptions(argc, argv, true); + + Solver S; + double initial_time = cpuTime(); + + S.verbosity = verb; + + solver = &S; + // Use signal handlers that forcibly quit until the solver will be able to respond to + // interrupts: + signal(SIGINT, SIGINT_exit); + signal(SIGXCPU,SIGINT_exit); + + // Set limit on CPU-time: + if (cpu_lim != INT32_MAX){ + rlimit rl; + getrlimit(RLIMIT_CPU, &rl); + if (rl.rlim_max == RLIM_INFINITY || (rlim_t)cpu_lim < rl.rlim_max){ + rl.rlim_cur = cpu_lim; + if (setrlimit(RLIMIT_CPU, &rl) == -1) + printf("c WARNING! Could not set resource limit: CPU-time.\n"); + } } + + // Set limit on virtual memory: + if (mem_lim != INT32_MAX){ + rlim_t new_mem_lim = (rlim_t)mem_lim * 1024*1024; + rlimit rl; + getrlimit(RLIMIT_AS, &rl); + if (rl.rlim_max == RLIM_INFINITY || new_mem_lim < rl.rlim_max){ + rl.rlim_cur = new_mem_lim; + if (setrlimit(RLIMIT_AS, &rl) == -1) + printf("c WARNING! Could not set resource limit: Virtual memory.\n"); + } } + + if (argc == 1) + printf("c Reading from standard input... Use '--help' for help.\n"); + + gzFile in = (argc == 1) ? gzdopen(0, "rb") : gzopen(argv[1], "rb"); + if (in == NULL) + printf("c ERROR! Could not open file: %s\n", argc == 1 ? "" : argv[1]), exit(1); + + if (S.verbosity > 0){ + printf("c ============================[ Problem Statistics ]=============================\n"); + printf("c | |\n"); } + + parse_DIMACS(in, S); + gzclose(in); + FILE* res = (argc >= 3) ? fopen(argv[2], "wb") : NULL; + + if (S.verbosity > 0){ + printf("c | Number of variables: %12d |\n", S.nVars()); + printf("c | Number of clauses: %12d |\n", S.nClauses()); } + + double parsed_time = cpuTime(); + if (S.verbosity > 0){ + printf("c | Parse time: %12.2f s |\n", parsed_time - initial_time); + printf("c | |\n"); } + + // Change to signal-handlers that will only notify the solver and allow it to terminate + // voluntarily: + signal(SIGINT, SIGINT_interrupt); + signal(SIGXCPU,SIGINT_interrupt); + + if (!S.simplify()){ + if (res != NULL) fprintf(res, "UNSAT\n"), fclose(res); + if (S.verbosity > 0){ + printf("c ===============================================================================\n"); + printf("c Solved by unit propagation\n"); + printStats(S); + printf("\n"); } + printf("s UNSATISFIABLE\n"); + exit(20); + } + + vec dummy; + lbool ret = S.solveLimited(dummy); + if (S.verbosity > 0){ + printStats(S); + printf("\n"); } + printf(ret == l_True ? "s SATISFIABLE\n" : ret == l_False ? "s UNSATISFIABLE\n" : "s UNKNOWN\n"); + if (ret == l_True){ + printf("v "); + for (int i = 0; i < S.nVars(); i++) + if (S.model[i] != l_Undef) + printf("%s%s%d", (i==0)?"":" ", (S.model[i]==l_True)?"":"-", i+1); + printf(" 0\n"); + } + + if (res != NULL){ + if (ret == l_True){ + fprintf(res, "SAT\n"); + for (int i = 0; i < S.nVars(); i++) + if (S.model[i] != l_Undef) + fprintf(res, "%s%s%d", (i==0)?"":" ", (S.model[i]==l_True)?"":"-", i+1); + fprintf(res, " 0\n"); + }else if (ret == l_False) + fprintf(res, "UNSAT\n"); + else + fprintf(res, "INDET\n"); + fclose(res); + } + +#ifdef NDEBUG + exit(ret == l_True ? 10 : ret == l_False ? 20 : 0); // (faster than "return", which will invoke the destructor for 'Solver') +#else + return (ret == l_True ? 10 : ret == l_False ? 20 : 0); +#endif + } catch (OutOfMemoryException&){ + printf("c ===============================================================================\n"); + printf("s UNKNOWN\n"); + exit(0); + } +} diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/core/Makefile b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/core/Makefile new file mode 100755 index 00000000..5de1f729 --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/core/Makefile @@ -0,0 +1,4 @@ +EXEC = minisat +DEPDIR = mtl utils + +include $(MROOT)/mtl/template.mk diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/core/Solver.cc b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/core/Solver.cc new file mode 100755 index 00000000..39b1ddd8 --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/core/Solver.cc @@ -0,0 +1,1547 @@ +/***************************************************************************************[Solver.cc] +MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson + Copyright (c) 2007-2010, Niklas Sorensson + +Chanseok Oh's MiniSat Patch Series -- Copyright (c) 2015, Chanseok Oh + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +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 AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + +#include + +#include "mtl/Sort.h" +#include "core/Solver.h" + +using namespace Minisat; + +#ifdef BIN_DRUP +int Solver::buf_len = 0; +unsigned char Solver::drup_buf[2 * 1024 * 1024]; +unsigned char* Solver::buf_ptr = drup_buf; +#endif + +//================================================================================================= +// Options: + + +static const char* _cat = "CORE"; + +static DoubleOption opt_step_size (_cat, "step-size", "Initial step size", 0.40, DoubleRange(0, false, 1, false)); +static DoubleOption opt_step_size_dec (_cat, "step-size-dec","Step size decrement", 0.000001, DoubleRange(0, false, 1, false)); +static DoubleOption opt_min_step_size (_cat, "min-step-size","Minimal step size", 0.06, DoubleRange(0, false, 1, false)); +static DoubleOption opt_var_decay (_cat, "var-decay", "The variable activity decay factor", 0.80, DoubleRange(0, false, 1, false)); +static DoubleOption opt_clause_decay (_cat, "cla-decay", "The clause activity decay factor", 0.999, DoubleRange(0, false, 1, false)); +static DoubleOption opt_random_var_freq (_cat, "rnd-freq", "The frequency with which the decision heuristic tries to choose a random variable", 0, DoubleRange(0, true, 1, true)); +static DoubleOption opt_random_seed (_cat, "rnd-seed", "Used by the random variable selection", 91648253, DoubleRange(0, false, HUGE_VAL, false)); +static IntOption opt_ccmin_mode (_cat, "ccmin-mode", "Controls conflict clause minimization (0=none, 1=basic, 2=deep)", 2, IntRange(0, 2)); +static IntOption opt_phase_saving (_cat, "phase-saving", "Controls the level of phase saving (0=none, 1=limited, 2=full)", 2, IntRange(0, 2)); +static BoolOption opt_rnd_init_act (_cat, "rnd-init", "Randomize the initial activity", false); +static IntOption opt_restart_first (_cat, "rfirst", "The base restart interval", 100, IntRange(1, INT32_MAX)); +static DoubleOption opt_restart_inc (_cat, "rinc", "Restart interval increase factor", 2, DoubleRange(1, false, HUGE_VAL, false)); +static DoubleOption opt_garbage_frac (_cat, "gc-frac", "The fraction of wasted memory allowed before a garbage collection is triggered", 0.20, DoubleRange(0, false, HUGE_VAL, false)); + + +//================================================================================================= +// Constructor/Destructor: + + +Solver::Solver() : + + // Parameters (user settable): + // + drup_file (NULL) + , verbosity (0) + , step_size (opt_step_size) + , step_size_dec (opt_step_size_dec) + , min_step_size (opt_min_step_size) + , timer (5000) + , var_decay (opt_var_decay) + , clause_decay (opt_clause_decay) + , random_var_freq (opt_random_var_freq) + , random_seed (opt_random_seed) + , VSIDS (false) + , ccmin_mode (opt_ccmin_mode) + , phase_saving (opt_phase_saving) + , rnd_pol (false) + , rnd_init_act (opt_rnd_init_act) + , garbage_frac (opt_garbage_frac) + , restart_first (opt_restart_first) + , restart_inc (opt_restart_inc) + + // Parameters (the rest): + // + , learntsize_factor((double)1/(double)3), learntsize_inc(1.1) + + // Parameters (experimental): + // + , learntsize_adjust_start_confl (100) + , learntsize_adjust_inc (1.5) + + // Statistics: (formerly in 'SolverStats') + // + , solves(0), starts(0), decisions(0), rnd_decisions(0), propagations(0), conflicts(0), conflicts_VSIDS(0) + , dec_vars(0), clauses_literals(0), learnts_literals(0), max_literals(0), tot_literals(0) + + , ok (true) + , cla_inc (1) + , var_inc (1) + , watches_bin (WatcherDeleted(ca)) + , watches (WatcherDeleted(ca)) + , qhead (0) + , simpDB_assigns (-1) + , simpDB_props (0) + , order_heap_CHB (VarOrderLt(activity_CHB)) + , order_heap_VSIDS (VarOrderLt(activity_VSIDS)) + , progress_estimate (0) + , remove_satisfied (true) + + , core_lbd_cut (3) + , global_lbd_sum (0) + , lbd_queue (50) + , next_T2_reduce (10000) + , next_L_reduce (15000) + + , counter (0) + + // Resource constraints: + // + , conflict_budget (-1) + , propagation_budget (-1) + , asynch_interrupt (false) +{} + + +Solver::~Solver() +{ +} + + +//================================================================================================= +// Minor methods: + + +// Creates a new SAT variable in the solver. If 'decision' is cleared, variable will not be +// used as a decision variable (NOTE! This has effects on the meaning of a SATISFIABLE result). +// +Var Solver::newVar(bool sign, bool dvar) +{ + int v = nVars(); + watches_bin.init(mkLit(v, false)); + watches_bin.init(mkLit(v, true )); + watches .init(mkLit(v, false)); + watches .init(mkLit(v, true )); + assigns .push(l_Undef); + vardata .push(mkVarData(CRef_Undef, 0)); + activity_CHB .push(0); + activity_VSIDS.push(rnd_init_act ? drand(random_seed) * 0.00001 : 0); + + picked.push(0); + conflicted.push(0); + almost_conflicted.push(0); + + seen .push(0); + seen2 .push(0); + polarity .push(sign); + decision .push(); + trail .capacity(v+1); + setDecisionVar(v, dvar); + + // Additional space needed for stamping. + // TODO: allocate exact memory. + seen .push(0); + discovered.push(0); discovered.push(0); + finished .push(0); finished .push(0); + observed .push(0); observed .push(0); + flag .push(0); flag .push(0); + root .push(lit_Undef); root .push(lit_Undef); + parent .push(lit_Undef); parent .push(lit_Undef); + return v; +} + + +bool Solver::addClause_(vec& ps) +{ + assert(decisionLevel() == 0); + if (!ok) return false; + + // Check if clause is satisfied and remove false/duplicate literals: + sort(ps); + Lit p; int i, j; + + if (drup_file){ + add_oc.clear(); + for (int i = 0; i < ps.size(); i++) add_oc.push(ps[i]); } + + for (i = j = 0, p = lit_Undef; i < ps.size(); i++) + if (value(ps[i]) == l_True || ps[i] == ~p) + return true; + else if (value(ps[i]) != l_False && ps[i] != p) + ps[j++] = p = ps[i]; + ps.shrink(i - j); + + if (drup_file && i != j){ +#ifdef BIN_DRUP + binDRUP('a', ps, drup_file); + binDRUP('d', add_oc, drup_file); +#else + for (int i = 0; i < ps.size(); i++) + fprintf(drup_file, "%i ", (var(ps[i]) + 1) * (-2 * sign(ps[i]) + 1)); + fprintf(drup_file, "0\n"); + + fprintf(drup_file, "d "); + for (int i = 0; i < add_oc.size(); i++) + fprintf(drup_file, "%i ", (var(add_oc[i]) + 1) * (-2 * sign(add_oc[i]) + 1)); + fprintf(drup_file, "0\n"); +#endif + } + + if (ps.size() == 0) + return ok = false; + else if (ps.size() == 1){ + uncheckedEnqueue(ps[0]); + return ok = (propagate() == CRef_Undef); + }else{ + CRef cr = ca.alloc(ps, false); + clauses.push(cr); + attachClause(cr); + } + + return true; +} + + +void Solver::attachClause(CRef cr) { + const Clause& c = ca[cr]; + assert(c.size() > 1); + OccLists, WatcherDeleted>& ws = c.size() == 2 ? watches_bin : watches; + ws[~c[0]].push(Watcher(cr, c[1])); + ws[~c[1]].push(Watcher(cr, c[0])); + if (c.learnt()) learnts_literals += c.size(); + else clauses_literals += c.size(); } + + +void Solver::detachClause(CRef cr, bool strict) { + const Clause& c = ca[cr]; + assert(c.size() > 1); + OccLists, WatcherDeleted>& ws = c.size() == 2 ? watches_bin : watches; + + if (strict){ + remove(ws[~c[0]], Watcher(cr, c[1])); + remove(ws[~c[1]], Watcher(cr, c[0])); + }else{ + // Lazy detaching: (NOTE! Must clean all watcher lists before garbage collecting this clause) + ws.smudge(~c[0]); + ws.smudge(~c[1]); + } + + if (c.learnt()) learnts_literals -= c.size(); + else clauses_literals -= c.size(); } + + +void Solver::removeClause(CRef cr) { + Clause& c = ca[cr]; + + if (drup_file){ + if (c.mark() != 1){ +#ifdef BIN_DRUP + binDRUP('d', c, drup_file); +#else + fprintf(drup_file, "d "); + for (int i = 0; i < c.size(); i++) + fprintf(drup_file, "%i ", (var(c[i]) + 1) * (-2 * sign(c[i]) + 1)); + fprintf(drup_file, "0\n"); +#endif + }else + printf("c Bug: removeClause(). I don't expect this to happen.\n"); + } + + detachClause(cr); + // Don't leave pointers to free'd memory! + if (locked(c)){ + Lit implied = c.size() != 2 ? c[0] : (value(c[0]) == l_True ? c[0] : c[1]); + vardata[var(implied)].reason = CRef_Undef; } + c.mark(1); + ca.free(cr); +} + + +bool Solver::satisfied(const Clause& c) const { + for (int i = 0; i < c.size(); i++) + if (value(c[i]) == l_True) + return true; + return false; } + + +// Revert to the state at given level (keeping all assignment at 'level' but not beyond). +// +void Solver::cancelUntil(int level) { + if (decisionLevel() > level){ + for (int c = trail.size()-1; c >= trail_lim[level]; c--){ + Var x = var(trail[c]); + + if (!VSIDS){ + uint32_t age = conflicts - picked[x]; + if (age > 0){ + double adjusted_reward = ((double) (conflicted[x] + almost_conflicted[x])) / ((double) age); + double old_activity = activity_CHB[x]; + activity_CHB[x] = step_size * adjusted_reward + ((1 - step_size) * old_activity); + if (order_heap_CHB.inHeap(x)){ + if (activity_CHB[x] > old_activity) + order_heap_CHB.decrease(x); + else + order_heap_CHB.increase(x); + } + } + } + + assigns [x] = l_Undef; + if (phase_saving > 1 || (phase_saving == 1) && c > trail_lim.last()) + polarity[x] = sign(trail[c]); + insertVarOrder(x); } + qhead = trail_lim[level]; + trail.shrink(trail.size() - trail_lim[level]); + trail_lim.shrink(trail_lim.size() - level); + } } + + +//================================================================================================= +// Major methods: + + +Lit Solver::pickBranchLit() +{ + Var next = var_Undef; + Heap& order_heap = VSIDS ? order_heap_VSIDS : order_heap_CHB; + + // Random decision: + /*if (drand(random_seed) < random_var_freq && !order_heap.empty()){ + next = order_heap[irand(random_seed,order_heap.size())]; + if (value(next) == l_Undef && decision[next]) + rnd_decisions++; }*/ + + // Activity based decision: + while (next == var_Undef || value(next) != l_Undef || !decision[next]) + if (order_heap.empty()) + return lit_Undef; + else + next = order_heap.removeMin(); + + return mkLit(next, polarity[next]); +} + + +/*_________________________________________________________________________________________________ +| +| analyze : (confl : Clause*) (out_learnt : vec&) (out_btlevel : int&) -> [void] +| +| Description: +| Analyze conflict and produce a reason clause. +| +| Pre-conditions: +| * 'out_learnt' is assumed to be cleared. +| * Current decision level must be greater than root level. +| +| Post-conditions: +| * 'out_learnt[0]' is the asserting literal at level 'out_btlevel'. +| * If out_learnt.size() > 1 then 'out_learnt[1]' has the greatest decision level of the +| rest of literals. There may be others from the same level though. +| +|________________________________________________________________________________________________@*/ +void Solver::analyze(CRef confl, vec& out_learnt, int& out_btlevel, int& out_lbd) +{ + int pathC = 0; + Lit p = lit_Undef; + + // Generate conflict clause: + // + out_learnt.push(); // (leave room for the asserting literal) + int index = trail.size() - 1; + + do{ + assert(confl != CRef_Undef); // (otherwise should be UIP) + Clause& c = ca[confl]; + + // For binary clauses, we don't rearrange literals in propagate(), so check and make sure the first is an implied lit. + if (p != lit_Undef && c.size() == 2 && value(c[0]) == l_False){ + assert(value(c[1]) == l_True); + Lit tmp = c[0]; + c[0] = c[1], c[1] = tmp; } + + // Update LBD if improved. + if (c.learnt() && c.mark() != CORE){ + int lbd = computeLBD(c); + if (lbd < c.lbd()){ + if (c.lbd() <= 30) c.removable(false); // Protect once from reduction. + c.set_lbd(lbd); + if (lbd <= core_lbd_cut){ + learnts_core.push(confl); + c.mark(CORE); + }else if (lbd <= 6 && c.mark() == LOCAL){ + // Bug: 'cr' may already be in 'learnts_tier2', e.g., if 'cr' was demoted from TIER2 + // to LOCAL previously and if that 'cr' is not cleaned from 'learnts_tier2' yet. + learnts_tier2.push(confl); + c.mark(TIER2); } + } + + if (c.mark() == TIER2) + c.touched() = conflicts; + else if (c.mark() == LOCAL) + claBumpActivity(c); + } + + for (int j = (p == lit_Undef) ? 0 : 1; j < c.size(); j++){ + Lit q = c[j]; + + if (!seen[var(q)] && level(var(q)) > 0){ + if (VSIDS){ + varBumpActivity(var(q), .5); + add_tmp.push(q); + }else + conflicted[var(q)]++; + seen[var(q)] = 1; + if (level(var(q)) >= decisionLevel()){ + pathC++; + }else + out_learnt.push(q); + } + } + + // Select next clause to look at: + while (!seen[var(trail[index--])]); + p = trail[index+1]; + confl = reason(var(p)); + seen[var(p)] = 0; + pathC--; + + }while (pathC > 0); + out_learnt[0] = ~p; + + // Simplify conflict clause: + // + int i, j; + out_learnt.copyTo(analyze_toclear); + if (ccmin_mode == 2){ + uint32_t abstract_level = 0; + for (i = 1; i < out_learnt.size(); i++) + abstract_level |= abstractLevel(var(out_learnt[i])); // (maintain an abstraction of levels involved in conflict) + + for (i = j = 1; i < out_learnt.size(); i++) + if (reason(var(out_learnt[i])) == CRef_Undef || !litRedundant(out_learnt[i], abstract_level)) + out_learnt[j++] = out_learnt[i]; + + }else if (ccmin_mode == 1){ + for (i = j = 1; i < out_learnt.size(); i++){ + Var x = var(out_learnt[i]); + + if (reason(x) == CRef_Undef) + out_learnt[j++] = out_learnt[i]; + else{ + Clause& c = ca[reason(var(out_learnt[i]))]; + for (int k = c.size() == 2 ? 0 : 1; k < c.size(); k++) + if (!seen[var(c[k])] && level(var(c[k])) > 0){ + out_learnt[j++] = out_learnt[i]; + break; } + } + } + }else + i = j = out_learnt.size(); + + max_literals += out_learnt.size(); + out_learnt.shrink(i - j); + tot_literals += out_learnt.size(); + + out_lbd = computeLBD(out_learnt); + if (out_lbd <= 6 && out_learnt.size() <= 30) // Try further minimization? + if (binResMinimize(out_learnt)) + out_lbd = computeLBD(out_learnt); // Recompute LBD if minimized. + + // Find correct backtrack level: + // + if (out_learnt.size() == 1) + out_btlevel = 0; + else{ + int max_i = 1; + // Find the first literal assigned at the next-highest level: + for (int i = 2; i < out_learnt.size(); i++) + if (level(var(out_learnt[i])) > level(var(out_learnt[max_i]))) + max_i = i; + // Swap-in this literal at index 1: + Lit p = out_learnt[max_i]; + out_learnt[max_i] = out_learnt[1]; + out_learnt[1] = p; + out_btlevel = level(var(p)); + } + + if (VSIDS){ + for (int i = 0; i < add_tmp.size(); i++){ + Var v = var(add_tmp[i]); + if (level(v) >= out_btlevel - 1) + varBumpActivity(v, 1); + } + add_tmp.clear(); + }else{ + seen[var(p)] = true; + for(int i = out_learnt.size() - 1; i >= 0; i--){ + Var v = var(out_learnt[i]); + CRef rea = reason(v); + if (rea != CRef_Undef){ + const Clause& reaC = ca[rea]; + for (int i = 0; i < reaC.size(); i++){ + Lit l = reaC[i]; + if (!seen[var(l)]){ + seen[var(l)] = true; + almost_conflicted[var(l)]++; + analyze_toclear.push(l); } } } } } + + for (int j = 0; j < analyze_toclear.size(); j++) seen[var(analyze_toclear[j])] = 0; // ('seen[]' is now cleared) +} + + +// Try further learnt clause minimization by means of binary clause resolution. +bool Solver::binResMinimize(vec& out_learnt) +{ + // Preparation: remember which false variables we have in 'out_learnt'. + counter++; + for (int i = 1; i < out_learnt.size(); i++) + seen2[var(out_learnt[i])] = counter; + + // Get the list of binary clauses containing 'out_learnt[0]'. + const vec& ws = watches_bin[~out_learnt[0]]; + + int to_remove = 0; + for (int i = 0; i < ws.size(); i++){ + Lit the_other = ws[i].blocker; + // Does 'the_other' appear negatively in 'out_learnt'? + if (seen2[var(the_other)] == counter && value(the_other) == l_True){ + to_remove++; + seen2[var(the_other)] = counter - 1; // Remember to remove this variable. + } + } + + // Shrink. + if (to_remove > 0){ + int last = out_learnt.size() - 1; + for (int i = 1; i < out_learnt.size() - to_remove; i++) + if (seen2[var(out_learnt[i])] != counter) + out_learnt[i--] = out_learnt[last--]; + out_learnt.shrink(to_remove); + } + return to_remove != 0; +} + + +// Check if 'p' can be removed. 'abstract_levels' is used to abort early if the algorithm is +// visiting literals at levels that cannot be removed later. +bool Solver::litRedundant(Lit p, uint32_t abstract_levels) +{ + analyze_stack.clear(); analyze_stack.push(p); + int top = analyze_toclear.size(); + while (analyze_stack.size() > 0){ + assert(reason(var(analyze_stack.last())) != CRef_Undef); + Clause& c = ca[reason(var(analyze_stack.last()))]; analyze_stack.pop(); + + // Special handling for binary clauses like in 'analyze()'. + if (c.size() == 2 && value(c[0]) == l_False){ + assert(value(c[1]) == l_True); + Lit tmp = c[0]; + c[0] = c[1], c[1] = tmp; } + + for (int i = 1; i < c.size(); i++){ + Lit p = c[i]; + if (!seen[var(p)] && level(var(p)) > 0){ + if (reason(var(p)) != CRef_Undef && (abstractLevel(var(p)) & abstract_levels) != 0){ + seen[var(p)] = 1; + analyze_stack.push(p); + analyze_toclear.push(p); + }else{ + for (int j = top; j < analyze_toclear.size(); j++) + seen[var(analyze_toclear[j])] = 0; + analyze_toclear.shrink(analyze_toclear.size() - top); + return false; + } + } + } + } + + return true; +} + + +/*_________________________________________________________________________________________________ +| +| analyzeFinal : (p : Lit) -> [void] +| +| Description: +| Specialized analysis procedure to express the final conflict in terms of assumptions. +| Calculates the (possibly empty) set of assumptions that led to the assignment of 'p', and +| stores the result in 'out_conflict'. +|________________________________________________________________________________________________@*/ +void Solver::analyzeFinal(Lit p, vec& out_conflict) +{ + out_conflict.clear(); + out_conflict.push(p); + + if (decisionLevel() == 0) + return; + + seen[var(p)] = 1; + + for (int i = trail.size()-1; i >= trail_lim[0]; i--){ + Var x = var(trail[i]); + if (seen[x]){ + if (reason(x) == CRef_Undef){ + assert(level(x) > 0); + out_conflict.push(~trail[i]); + }else{ + Clause& c = ca[reason(x)]; + for (int j = c.size() == 2 ? 0 : 1; j < c.size(); j++) + if (level(var(c[j])) > 0) + seen[var(c[j])] = 1; + } + seen[x] = 0; + } + } + + seen[var(p)] = 0; +} + + +void Solver::uncheckedEnqueue(Lit p, CRef from) +{ + assert(value(p) == l_Undef); + Var x = var(p); + if (!VSIDS){ + picked[x] = conflicts; + conflicted[x] = 0; + almost_conflicted[x] = 0; + } + + assigns[x] = lbool(!sign(p)); + vardata[x] = mkVarData(from, decisionLevel()); + trail.push_(p); +} + + +/*_________________________________________________________________________________________________ +| +| propagate : [void] -> [Clause*] +| +| Description: +| Propagates all enqueued facts. If a conflict arises, the conflicting clause is returned, +| otherwise CRef_Undef. +| +| Post-conditions: +| * the propagation queue is empty, even if there was a conflict. +|________________________________________________________________________________________________@*/ +CRef Solver::propagate() +{ + CRef confl = CRef_Undef; + int num_props = 0; + watches.cleanAll(); + watches_bin.cleanAll(); + + while (qhead < trail.size()){ + Lit p = trail[qhead++]; // 'p' is enqueued fact to propagate. + vec& ws = watches[p]; + Watcher *i, *j, *end; + num_props++; + + vec& ws_bin = watches_bin[p]; // Propagate binary clauses first. + for (int k = 0; k < ws_bin.size(); k++){ + Lit the_other = ws_bin[k].blocker; + if (value(the_other) == l_False){ + confl = ws_bin[k].cref; +#ifdef LOOSE_PROP_STAT + return confl; +#else + goto ExitProp; +#endif + }else if(value(the_other) == l_Undef) + uncheckedEnqueue(the_other, ws_bin[k].cref); + } + + for (i = j = (Watcher*)ws, end = i + ws.size(); i != end;){ + // Try to avoid inspecting the clause: + Lit blocker = i->blocker; + if (value(blocker) == l_True){ + *j++ = *i++; continue; } + + // Make sure the false literal is data[1]: + CRef cr = i->cref; + Clause& c = ca[cr]; + Lit false_lit = ~p; + if (c[0] == false_lit) + c[0] = c[1], c[1] = false_lit; + assert(c[1] == false_lit); + i++; + + // If 0th watch is true, then clause is already satisfied. + Lit first = c[0]; + Watcher w = Watcher(cr, first); + if (first != blocker && value(first) == l_True){ + *j++ = w; continue; } + + // Look for new watch: + for (int k = 2; k < c.size(); k++) + if (value(c[k]) != l_False){ + c[1] = c[k]; c[k] = false_lit; + watches[~c[1]].push(w); + goto NextClause; } + + // Did not find watch -- clause is unit under assignment: + *j++ = w; + if (value(first) == l_False){ + confl = cr; + qhead = trail.size(); + // Copy the remaining watches: + while (i < end) + *j++ = *i++; + }else + uncheckedEnqueue(first, cr); + + NextClause:; + } + ws.shrink(i - j); + } + +ExitProp:; + propagations += num_props; + simpDB_props -= num_props; + + return confl; +} + + +/*_________________________________________________________________________________________________ +| +| reduceDB : () -> [void] +| +| Description: +| Remove half of the learnt clauses, minus the clauses locked by the current assignment. Locked +| clauses are clauses that are reason to some assignment. Binary clauses are never removed. +|________________________________________________________________________________________________@*/ +struct reduceDB_lt { + ClauseAllocator& ca; + reduceDB_lt(ClauseAllocator& ca_) : ca(ca_) {} + bool operator () (CRef x, CRef y) const { return ca[x].activity() < ca[y].activity(); } +}; +void Solver::reduceDB() +{ + int i, j; + //if (local_learnts_dirty) cleanLearnts(learnts_local, LOCAL); + //local_learnts_dirty = false; + + sort(learnts_local, reduceDB_lt(ca)); + + int limit = learnts_local.size() / 2; + for (i = j = 0; i < learnts_local.size(); i++){ + Clause& c = ca[learnts_local[i]]; + if (c.mark() == LOCAL) + if (c.removable() && !locked(c) && i < limit) + removeClause(learnts_local[i]); + else{ + if (!c.removable()) limit++; + c.removable(true); + learnts_local[j++] = learnts_local[i]; } + } + learnts_local.shrink(i - j); + + checkGarbage(); +} +void Solver::reduceDB_Tier2() +{ + int i, j; + for (i = j = 0; i < learnts_tier2.size(); i++){ + Clause& c = ca[learnts_tier2[i]]; + if (c.mark() == TIER2) + if (!locked(c) && c.touched() + 30000 < conflicts){ + learnts_local.push(learnts_tier2[i]); + c.mark(LOCAL); + //c.removable(true); + c.activity() = 0; + claBumpActivity(c); + }else + learnts_tier2[j++] = learnts_tier2[i]; + } + learnts_tier2.shrink(i - j); +} + + +void Solver::removeSatisfied(vec& cs) +{ + int i, j; + for (i = j = 0; i < cs.size(); i++){ + Clause& c = ca[cs[i]]; + if (satisfied(c)) + removeClause(cs[i]); + else + cs[j++] = cs[i]; + } + cs.shrink(i - j); +} + +void Solver::rebuildOrderHeap() +{ + vec vs; + for (Var v = 0; v < nVars(); v++) + if (decision[v] && value(v) == l_Undef) + vs.push(v); + + order_heap_CHB .build(vs); + order_heap_VSIDS.build(vs); +} + + +/*_________________________________________________________________________________________________ +| +| simplify : [void] -> [bool] +| +| Description: +| Simplify the clause database according to the current top-level assigment. Currently, the only +| thing done here is the removal of satisfied clauses, but more things can be put here. +|________________________________________________________________________________________________@*/ +bool Solver::simplify(bool do_stamping) +{ + assert(decisionLevel() == 0); + + if (!ok || propagate() != CRef_Undef) + return ok = false; + + if (nAssigns() == simpDB_assigns || (simpDB_props > 0)) + return true; + + // Remove satisfied clauses: + safeRemoveSatisfiedCompact(learnts_core, CORE); + safeRemoveSatisfiedCompact(learnts_tier2, TIER2); + safeRemoveSatisfiedCompact(learnts_local, LOCAL); + if (remove_satisfied) // Can be turned off. + removeSatisfied(clauses); + + if (do_stamping) + ok = stampAll(true); + + checkGarbage(); + rebuildOrderHeap(); + + simpDB_assigns = nAssigns(); + simpDB_props = clauses_literals + learnts_literals; // (shouldn't depend on stats really, but it will do for now) + + return ok; +} + + +// TODO: very dirty and hackish. +void Solver::removeClauseHack(CRef cr, Lit watched0, Lit watched1) +{ + assert(ca[cr].size() >= 2); + + Clause& c = ca[cr]; + if (drup_file) // Hackish. + if (c.mark() != 1){ +#ifdef BIN_DRUP + binDRUP('d', add_oc, drup_file); // 'add_oc' not 'c'. +#else + for (int i = 0; i < add_oc.size(); i++) + fprintf(drup_file, "%i ", (var(add_oc[i]) + 1) * (-2 * sign(add_oc[i]) + 1)); + fprintf(drup_file, "0\n"); +#endif + }else + printf("c Bug: removeClauseHack(). I don't expect this to happen.\n"); + + // TODO: dirty hack to exploit 'detachClause'. 'c' hasn't shrunk yet, so this will work fine. + c[0] = watched0, c[1] = watched1; + detachClause(cr); + // Don't leave pointers to free'd memory! + if (locked(c)){ + Lit implied = c.size() != 2 ? c[0] : (value(c[0]) == l_True ? c[0] : c[1]); + vardata[var(implied)].reason = CRef_Undef; } + c.mark(1); + ca.free(cr); +} + +// TODO: needs clean up. +void Solver::safeRemoveSatisfiedCompact(vec& cs, unsigned valid_mark) +{ + int i, j, k, l; + for (i = j = 0; i < cs.size(); i++){ + Clause& c = ca[cs[i]]; + if (c.mark() != valid_mark) continue; + + Lit c0 = c[0], c1 = c[1]; + if (drup_file){ // Remember the original clause before attempting to modify it. + add_oc.clear(); + for (int i = 0; i < c.size(); i++) add_oc.push(c[i]); } + + // Remove false literals at the same time. + for (k = l = 0; k < c.size(); k++) + if (value(c[k]) == l_True){ + removeClauseHack(cs[i], c0, c1); + goto NextClause; // Clause already satisfied; forget about it. + }else if (value(c[k]) == l_Undef) + c[l++] = c[k]; + assert(1 < l && l <= k); + + // If became binary, we also need to migrate watchers. The easiest way is to allocate a new binary. + if (l == 2 && k != 2){ + assert(add_tmp.size() == 0); + add_tmp.push(c[0]); add_tmp.push(c[1]); + bool learnt = c.learnt(); // Need a copy; see right below. + int lbd = c.lbd(); + int m = c.mark(); + CRef cr = ca.alloc(add_tmp, learnt); // Caution! 'alloc' may invalidate the 'c' reference. + if (learnt){ + if (m != CORE) learnts_core.push(cr); + ca[cr].mark(CORE); + ca[cr].set_lbd(lbd > 2 ? 2 : lbd); } + attachClause(cr); + + if (drup_file){ +#ifdef BIN_DRUP + binDRUP('a', add_tmp, drup_file); +#else + for (int i = 0; i < add_tmp.size(); i++) + fprintf(drup_file, "%i ", (var(add_tmp[i]) + 1) * (-2 * sign(add_tmp[i]) + 1)); + fprintf(drup_file, "0\n"); +#endif + } + add_tmp.clear(); + + removeClauseHack(cs[i], c0, c1); + cs[j++] = cr; // Should be after 'removeClauseHack' because 'i' may be equal to 'j'. + goto NextClause; + } + + c.shrink(k - l); // FIXME: fix (statistical) memory leak. + if (c.learnt()) learnts_literals -= (k - l); + else clauses_literals -= (k - l); + + if (drup_file && k != l){ +#ifdef BIN_DRUP + binDRUP('a', c, drup_file); + binDRUP('d', add_oc, drup_file); +#else + for (int i = 0; i < c.size(); i++) + fprintf(drup_file, "%i ", (var(c[i]) + 1) * (-2 * sign(c[i]) + 1)); + fprintf(drup_file, "0\n"); + + fprintf(drup_file, "d "); + for (int i = 0; i < add_oc.size(); i++) + fprintf(drup_file, "%i ", (var(add_oc[i]) + 1) * (-2 * sign(add_oc[i]) + 1)); + fprintf(drup_file, "0\n"); +#endif + } + + cs[j++] = cs[i]; +NextClause:; + } + cs.shrink(i - j); +} + +/*_________________________________________________________________________________________________ +| +| search : (nof_conflicts : int) (params : const SearchParams&) -> [lbool] +| +| Description: +| Search for a model the specified number of conflicts. +| +| Output: +| 'l_True' if a partial assigment that is consistent with respect to the clauseset is found. If +| all variables are decision variables, this means that the clause set is satisfiable. 'l_False' +| if the clause set is unsatisfiable. 'l_Undef' if the bound on number of conflicts is reached. +|________________________________________________________________________________________________@*/ +lbool Solver::search(int& nof_conflicts) +{ + assert(ok); + int backtrack_level; + int lbd; + vec learnt_clause; + bool cached = false; + starts++; + + for (;;){ + CRef confl = propagate(); + + if (confl != CRef_Undef){ + // CONFLICT + if (VSIDS){ + if (--timer == 0 && var_decay < 0.95) timer = 5000, var_decay += 0.01; + }else + if (step_size > min_step_size) step_size -= step_size_dec; + + conflicts++; nof_conflicts--; + if (conflicts == 100000 && learnts_core.size() < 100) core_lbd_cut = 5; + if (decisionLevel() == 0) return l_False; + + learnt_clause.clear(); + analyze(confl, learnt_clause, backtrack_level, lbd); + cancelUntil(backtrack_level); + + lbd--; + if (VSIDS){ + cached = false; + conflicts_VSIDS++; + lbd_queue.push(lbd); + global_lbd_sum += (lbd > 50 ? 50 : lbd); } + + if (learnt_clause.size() == 1){ + uncheckedEnqueue(learnt_clause[0]); + }else{ + CRef cr = ca.alloc(learnt_clause, true); + ca[cr].set_lbd(lbd); + if (lbd <= core_lbd_cut){ + learnts_core.push(cr); + ca[cr].mark(CORE); + }else if (lbd <= 6){ + learnts_tier2.push(cr); + ca[cr].mark(TIER2); + ca[cr].touched() = conflicts; + }else{ + learnts_local.push(cr); + claBumpActivity(ca[cr]); } + attachClause(cr); + uncheckedEnqueue(learnt_clause[0], cr); + } + if (drup_file){ +#ifdef BIN_DRUP + binDRUP('a', learnt_clause, drup_file); +#else + for (int i = 0; i < learnt_clause.size(); i++) + fprintf(drup_file, "%i ", (var(learnt_clause[i]) + 1) * (-2 * sign(learnt_clause[i]) + 1)); + fprintf(drup_file, "0\n"); +#endif + } + + if (VSIDS) varDecayActivity(); + claDecayActivity(); + + /*if (--learntsize_adjust_cnt == 0){ + learntsize_adjust_confl *= learntsize_adjust_inc; + learntsize_adjust_cnt = (int)learntsize_adjust_confl; + max_learnts *= learntsize_inc; + + if (verbosity >= 1) + printf("c | %9d | %7d %8d %8d | %8d %8d %6.0f | %6.3f %% |\n", + (int)conflicts, + (int)dec_vars - (trail_lim.size() == 0 ? trail.size() : trail_lim[0]), nClauses(), (int)clauses_literals, + (int)max_learnts, nLearnts(), (double)learnts_literals/nLearnts(), progressEstimate()*100); + }*/ + + }else{ + // NO CONFLICT + bool restart = false; + if (!VSIDS) + restart = nof_conflicts <= 0; + else if (!cached){ + restart = lbd_queue.full() && (lbd_queue.avg() * 0.8 > global_lbd_sum / conflicts_VSIDS); + cached = true; + } + if (restart /*|| !withinBudget()*/){ + lbd_queue.clear(); + cached = false; + // Reached bound on number of conflicts: + progress_estimate = progressEstimate(); + cancelUntil(0); + return l_Undef; } + + // Simplify the set of problem clauses: + if (decisionLevel() == 0 && !simplify(true)) + return l_False; + + if (conflicts >= next_T2_reduce){ + next_T2_reduce = conflicts + 10000; + reduceDB_Tier2(); } + if (conflicts >= next_L_reduce){ + next_L_reduce = conflicts + 15000; + reduceDB(); } + + Lit next = lit_Undef; + /*while (decisionLevel() < assumptions.size()){ + // Perform user provided assumption: + Lit p = assumptions[decisionLevel()]; + if (value(p) == l_True){ + // Dummy decision level: + newDecisionLevel(); + }else if (value(p) == l_False){ + analyzeFinal(~p, conflict); + return l_False; + }else{ + next = p; + break; + } + } + + if (next == lit_Undef)*/{ + // New variable decision: + decisions++; + next = pickBranchLit(); + + if (next == lit_Undef) + // Model found: + return l_True; + } + + // Increase decision level and enqueue 'next' + newDecisionLevel(); + uncheckedEnqueue(next); + } + } +} + + +double Solver::progressEstimate() const +{ + double progress = 0; + double F = 1.0 / nVars(); + + for (int i = 0; i <= decisionLevel(); i++){ + int beg = i == 0 ? 0 : trail_lim[i - 1]; + int end = i == decisionLevel() ? trail.size() : trail_lim[i]; + progress += pow(F, i) * (end - beg); + } + + return progress / nVars(); +} + +/* + Finite subsequences of the Luby-sequence: + + 0: 1 + 1: 1 1 2 + 2: 1 1 2 1 1 2 4 + 3: 1 1 2 1 1 2 4 1 1 2 1 1 2 4 8 + ... + + + */ + +static double luby(double y, int x){ + + // Find the finite subsequence that contains index 'x', and the + // size of that subsequence: + int size, seq; + for (size = 1, seq = 0; size < x+1; seq++, size = 2*size+1); + + while (size-1 != x){ + size = (size-1)>>1; + seq--; + x = x % size; + } + + return pow(y, seq); +} + +// NOTE: assumptions passed in member-variable 'assumptions'. +lbool Solver::solve_() +{ + model.clear(); + conflict.clear(); + if (!ok) return l_False; + + solves++; + + max_learnts = nClauses() * learntsize_factor; + learntsize_adjust_confl = learntsize_adjust_start_confl; + learntsize_adjust_cnt = (int)learntsize_adjust_confl; + lbool status = l_Undef; + + if (verbosity >= 1){ + printf("c ============================[ Search Statistics ]==============================\n"); + printf("c | Conflicts | ORIGINAL | LEARNT | Progress |\n"); + printf("c | | Vars Clauses Literals | Limit Clauses Lit/Cl | |\n"); + printf("c ===============================================================================\n"); + } + + add_tmp.clear(); + + VSIDS = true; + int init = 10000; + while (status == l_Undef && init > 0 /*&& withinBudget()*/) + status = search(init); + VSIDS = false; + + // Search: + int phase_allotment = 100; + int curr_restarts = 0; + for (;;){ + int weighted = phase_allotment; + fflush(stdout); + + while (status == l_Undef && weighted > 0 /*&& withinBudget()*/) + if (VSIDS) + status = search(weighted); + else{ + int nof_conflicts = luby(restart_inc, curr_restarts) * restart_first; + curr_restarts++; + weighted -= nof_conflicts; + status = search(nof_conflicts); + } + + if (status != l_Undef /*|| !withinBudget()*/) + break; // Should break here for correctness in incremental SAT solving. + + VSIDS = !VSIDS; + if (!VSIDS) + phase_allotment += phase_allotment / 10; + } + + if (verbosity >= 1) + printf("c ===============================================================================\n"); + +#ifdef BIN_DRUP + if (drup_file && status == l_False) binDRUP_flush(drup_file); +#endif + + if (status == l_True){ + // Extend & copy model: + model.growTo(nVars()); + for (int i = 0; i < nVars(); i++) model[i] = value(i); + }else if (status == l_False && conflict.size() == 0) + ok = false; + + cancelUntil(0); + return status; +} + +//================================================================================================= +// Writing CNF to DIMACS: +// +// FIXME: this needs to be rewritten completely. + +static Var mapVar(Var x, vec& map, Var& max) +{ + if (map.size() <= x || map[x] == -1){ + map.growTo(x+1, -1); + map[x] = max++; + } + return map[x]; +} + + +void Solver::toDimacs(FILE* f, Clause& c, vec& map, Var& max) +{ + if (satisfied(c)) return; + + for (int i = 0; i < c.size(); i++) + if (value(c[i]) != l_False) + fprintf(f, "%s%d ", sign(c[i]) ? "-" : "", mapVar(var(c[i]), map, max)+1); + fprintf(f, "0\n"); +} + + +void Solver::toDimacs(const char *file, const vec& assumps) +{ + FILE* f = fopen(file, "wr"); + if (f == NULL) + fprintf(stderr, "could not open file %s\n", file), exit(1); + toDimacs(f, assumps); + fclose(f); +} + + +void Solver::toDimacs(FILE* f, const vec& assumps) +{ + // Handle case when solver is in contradictory state: + if (!ok){ + fprintf(f, "p cnf 1 2\n1 0\n-1 0\n"); + return; } + + vec map; Var max = 0; + + // Cannot use removeClauses here because it is not safe + // to deallocate them at this point. Could be improved. + int cnt = 0; + for (int i = 0; i < clauses.size(); i++) + if (!satisfied(ca[clauses[i]])) + cnt++; + + for (int i = 0; i < clauses.size(); i++) + if (!satisfied(ca[clauses[i]])){ + Clause& c = ca[clauses[i]]; + for (int j = 0; j < c.size(); j++) + if (value(c[j]) != l_False) + mapVar(var(c[j]), map, max); + } + + // Assumptions are added as unit clauses: + cnt += assumptions.size(); + + fprintf(f, "p cnf %d %d\n", max, cnt); + + for (int i = 0; i < assumptions.size(); i++){ + assert(value(assumptions[i]) != l_False); + fprintf(f, "%s%d 0\n", sign(assumptions[i]) ? "-" : "", mapVar(var(assumptions[i]), map, max)+1); + } + + for (int i = 0; i < clauses.size(); i++) + toDimacs(f, ca[clauses[i]], map, max); + + if (verbosity > 0) + printf("c Wrote %d clauses with %d variables.\n", cnt, max); +} + + +//================================================================================================= +// Garbage Collection methods: + +void Solver::relocAll(ClauseAllocator& to) +{ + // All watchers: + // + // for (int i = 0; i < watches.size(); i++) + watches.cleanAll(); + watches_bin.cleanAll(); + for (int v = 0; v < nVars(); v++) + for (int s = 0; s < 2; s++){ + Lit p = mkLit(v, s); + // printf(" >>> RELOCING: %s%d\n", sign(p)?"-":"", var(p)+1); + vec& ws = watches[p]; + for (int j = 0; j < ws.size(); j++) + ca.reloc(ws[j].cref, to); + vec& ws_bin = watches_bin[p]; + for (int j = 0; j < ws_bin.size(); j++) + ca.reloc(ws_bin[j].cref, to); + } + + // All reasons: + // + for (int i = 0; i < trail.size(); i++){ + Var v = var(trail[i]); + + if (reason(v) != CRef_Undef && (ca[reason(v)].reloced() || locked(ca[reason(v)]))) + ca.reloc(vardata[v].reason, to); + } + + // All learnt: + // + for (int i = 0; i < learnts_core.size(); i++) + ca.reloc(learnts_core[i], to); + for (int i = 0; i < learnts_tier2.size(); i++) + ca.reloc(learnts_tier2[i], to); + for (int i = 0; i < learnts_local.size(); i++) + ca.reloc(learnts_local[i], to); + + // All original: + // + int i, j; + for (i = j = 0; i < clauses.size(); i++) + if (ca[clauses[i]].mark() != 1){ + ca.reloc(clauses[i], to); + clauses[j++] = clauses[i]; } + clauses.shrink(i - j); +} + + +void Solver::garbageCollect() +{ + // Initialize the next region to a size corresponding to the estimated utilization degree. This + // is not precise but should avoid some unnecessary reallocations for the new region: + ClauseAllocator to(ca.size() - ca.wasted()); + + relocAll(to); + if (verbosity >= 2) + printf("c | Garbage collection: %12d bytes => %12d bytes |\n", + ca.size()*ClauseAllocator::Unit_Size, to.size()*ClauseAllocator::Unit_Size); + to.moveTo(ca); +} + + +inline int gcd(int a, int b) { + int tmp; + if (a < b) tmp = a, a = b, b = tmp; + while (b) tmp = b, b = a % b, a = tmp; + return a; +} + +bool Solver::stampAll(bool use_bin_learnts) +{ + // Initialization. + int stamp_time = 0; + int nLits = 2*nVars(); + for (int i = 0; i < nVars(); i++){ + int m = i*2, n = i*2 + 1; + discovered[m] = discovered[n] = finished[m] = finished[n] = observed[m] = observed[n] = 0; + root[m] = root[n] = parent[m] = parent[n] = lit_Undef; + flag[m] = flag[n] = 0; } + + for (int roots_only = 1; roots_only >= 0; roots_only--){ + int l = irand(random_seed, nLits); + int l_inc = irand(random_seed, nLits-1) + 1; // Avoid 0 but ensure less than 'nLits'. + while (gcd(nLits, l_inc) > 1) + if (++l_inc == nLits) l_inc = 1; + + int first = l; + do{ + Lit p = toLit(l); + if (value(p) == l_Undef && !discovered[toInt(p)] && + (!roots_only || isRoot(p, use_bin_learnts)) && + implExistsByBin(p, use_bin_learnts)){ + stamp_time = stamp(p, stamp_time, use_bin_learnts); + + if (!ok || propagate() != CRef_Undef) + return ok = false; + } + + // Compute next literal to look at. + l += l_inc; + if (l >= nLits) l -= nLits; + + }while(l != first); + } + + return true; +} + +int Solver::stamp(Lit p, int stamp_time, bool use_bin_learnts) +{ + assert(value(p) == l_Undef && !discovered[toInt(p)] && !finished[toInt(p)]); + assert(rec_stack.size() == 0 && scc.size() == 0); + + int start_stamp = 0; + rec_stack.push(Frame(Frame::START, p, lit_Undef, 0)); + + while (rec_stack.size()){ + const Frame f = rec_stack.last(); rec_stack.pop(); + int i_curr = toInt(f.curr); + int i_next = toInt(f.next); + + if (f.type == Frame::START){ + if (discovered[i_curr]){ + observed[i_curr] = stamp_time; + continue; } + + assert(!finished[i_curr]); + discovered[i_curr] = observed[i_curr] = ++stamp_time; + + if (start_stamp == 0){ + start_stamp = stamp_time; + root[i_curr] = f.curr; + assert(parent[i_curr] == lit_Undef); } + rec_stack.push(Frame(Frame::CLOSE, f.curr, lit_Undef, 0)); + + assert(!flag[i_curr]); + flag[i_curr] = 1; + scc.push(f.curr); + + for (int undiscovered = 0; undiscovered <= 1; undiscovered++){ + int prev_top = rec_stack.size(); + analyze_toclear.clear(); + + const vec& ws = watches_bin[f.curr]; + for (int k = 0; k < ws.size(); k++){ + Lit the_other = ws[k].blocker; + + if (value(the_other) == l_Undef + && !seen[toInt(the_other)] + && undiscovered == !discovered[toInt(the_other)]) +// && (use_bin_learnts || !ca[ws[k].cref].learnt())) + { + seen[toInt(the_other)] = 1; + analyze_toclear.push(the_other); + + rec_stack.push(Frame(Frame::ENTER, f.curr, the_other, 0)); + //rec_stack.push(Frame(Frame::ENTER, f.curr, the_other, ca[ws[k].cref].learnt())); + } + } + for (int k = 0; k < analyze_toclear.size(); k++) seen[toInt(analyze_toclear[k])] = 0; + + // Now randomize child nodes to visit by shuffling pushed stack entries. + int stacked = rec_stack.size() - prev_top; + for (int i = 0; i < stacked - 1; i++){ + int j = i + irand(random_seed, stacked - i); // i <= j < stacked + if (i != j){ + Frame tmp = rec_stack[prev_top + i]; + rec_stack[prev_top + i] = rec_stack[prev_top + j]; + rec_stack[prev_top + j] = tmp; } + } + } + + }else if (f.type == Frame::ENTER){ + rec_stack.push(Frame(Frame::RETURN, f.curr, f.next, f.learnt)); + + int neg_observed = observed[toInt(~f.next)]; + if (start_stamp <= neg_observed){ // Failed literal? + Lit failed; + for (failed = f.curr; + discovered[toInt(failed)] > neg_observed; + failed = parent[toInt(failed)]) + assert(failed != lit_Undef); + + if (drup_file && value(~failed) != l_True){ +#ifdef BIN_DRUP + assert(add_tmp.size() == 0); + add_tmp.push(~failed); + binDRUP('a', add_tmp, drup_file); + add_tmp.clear(); +#else + fprintf(drup_file, "%i 0\n", (var(~failed) + 1) * (-2 * sign(~failed) + 1)); +#endif + } + + if (!(ok = enqueue(~failed))) + return -1; // Who cares what? + + if (discovered[toInt(~f.next)] && !finished[toInt(~f.next)]){ + rec_stack.pop(); // Skip this edge after a failed literal. + continue; } + } + + if (!discovered[i_next]){ + parent[i_next] = f.curr; + root[i_next] = p; + rec_stack.push(Frame(Frame::START, f.next, lit_Undef, 0)); } + + }else if (f.type == Frame::RETURN){ + if (!finished[i_next] && discovered[i_next] < discovered[i_curr]){ + discovered[i_curr] = discovered[i_next]; + flag[i_curr] = 0; + } + observed[i_next] = stamp_time; + + }else if (f.type == Frame::CLOSE){ + if (flag[i_curr]){ + stamp_time++; + int curr_discovered = discovered[i_curr]; + Lit q; + do{ + q = scc.last(); scc.pop(); + flag [toInt(q)] = 0; + discovered[toInt(q)] = curr_discovered; + finished [toInt(q)] = stamp_time; + }while (q != f.curr); + } + + }else assert(false); + } + + return stamp_time; +} + +bool Solver::implExistsByBin(Lit p, bool use_bin_learnts) const { + assert(value(p) == l_Undef); + + const vec& ws = watches_bin[p]; + for (int i = 0; i < ws.size(); i++){ + Lit the_other = ws[i].blocker; + assert(value(the_other) != l_False); // Propagate then. + + if (value(the_other) != l_True && !discovered[toInt(the_other)]) + if (use_bin_learnts || !ca[ws[i].cref].learnt()) + return true; + } + return false; +} + +bool Solver::isRoot(Lit p, bool use_bin_learnts) const { return !implExistsByBin(~p, use_bin_learnts); } diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/core/Solver.h b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/core/Solver.h new file mode 100755 index 00000000..9efca16a --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/core/Solver.h @@ -0,0 +1,524 @@ +/****************************************************************************************[Solver.h] +MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson + Copyright (c) 2007-2010, Niklas Sorensson + +Chanseok Oh's MiniSat Patch Series -- Copyright (c) 2015, Chanseok Oh + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +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 AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + +#ifndef Minisat_Solver_h +#define Minisat_Solver_h + +#define BIN_DRUP + +#define GLUCOSE23 +//#define INT_QUEUE_AVG +//#define LOOSE_PROP_STAT + +#ifdef GLUCOSE23 + #define INT_QUEUE_AVG + #define LOOSE_PROP_STAT +#endif + +#include "mtl/Vec.h" +#include "mtl/Heap.h" +#include "mtl/Alg.h" +#include "utils/Options.h" +#include "core/SolverTypes.h" + + +// Don't change the actual numbers. +#define LOCAL 0 +#define TIER2 2 +#define CORE 3 + +namespace Minisat { + +//================================================================================================= +// Solver -- the main class: + +class Solver { +private: + template + class MyQueue { + int max_sz, q_sz; + int ptr; + int64_t sum; + vec q; + public: + MyQueue(int sz) : max_sz(sz), q_sz(0), ptr(0), sum(0) { assert(sz > 0); q.growTo(sz); } + inline bool full () const { return q_sz == max_sz; } +#ifdef INT_QUEUE_AVG + inline T avg () const { assert(full()); return sum / max_sz; } +#else + inline double avg () const { assert(full()); return sum / (double) max_sz; } +#endif + inline void clear() { sum = 0; q_sz = 0; ptr = 0; } + void push(T e) { + if (q_sz < max_sz) q_sz++; + else sum -= q[ptr]; + sum += e; + q[ptr++] = e; + if (ptr == max_sz) ptr = 0; + } + }; + +public: + + // Constructor/Destructor: + // + Solver(); + virtual ~Solver(); + + // Problem specification: + // + Var newVar (bool polarity = true, bool dvar = true); // Add a new variable with parameters specifying variable mode. + + bool addClause (const vec& ps); // Add a clause to the solver. + bool addEmptyClause(); // Add the empty clause, making the solver contradictory. + bool addClause (Lit p); // Add a unit clause to the solver. + bool addClause (Lit p, Lit q); // Add a binary clause to the solver. + bool addClause (Lit p, Lit q, Lit r); // Add a ternary clause to the solver. + bool addClause_( vec& ps); // Add a clause to the solver without making superflous internal copy. Will + // change the passed vector 'ps'. + + // Solving: + // + bool simplify (bool do_stamping = false); // Removes already satisfied clauses. + bool solve (const vec& assumps); // Search for a model that respects a given set of assumptions. + lbool solveLimited (const vec& assumps); // Search for a model that respects a given set of assumptions (With resource constraints). + bool solve (); // Search without assumptions. + bool solve (Lit p); // Search for a model that respects a single assumption. + bool solve (Lit p, Lit q); // Search for a model that respects two assumptions. + bool solve (Lit p, Lit q, Lit r); // Search for a model that respects three assumptions. + bool okay () const; // FALSE means solver is in a conflicting state + + void toDimacs (FILE* f, const vec& assumps); // Write CNF to file in DIMACS-format. + void toDimacs (const char *file, const vec& assumps); + void toDimacs (FILE* f, Clause& c, vec& map, Var& max); + + // Convenience versions of 'toDimacs()': + void toDimacs (const char* file); + void toDimacs (const char* file, Lit p); + void toDimacs (const char* file, Lit p, Lit q); + void toDimacs (const char* file, Lit p, Lit q, Lit r); + + // Variable mode: + // + void setPolarity (Var v, bool b); // Declare which polarity the decision heuristic should use for a variable. Requires mode 'polarity_user'. + void setDecisionVar (Var v, bool b); // Declare if a variable should be eligible for selection in the decision heuristic. + + // Read state: + // + lbool value (Var x) const; // The current value of a variable. + lbool value (Lit p) const; // The current value of a literal. + lbool modelValue (Var x) const; // The value of a variable in the last model. The last call to solve must have been satisfiable. + lbool modelValue (Lit p) const; // The value of a literal in the last model. The last call to solve must have been satisfiable. + int nAssigns () const; // The current number of assigned literals. + int nClauses () const; // The current number of original clauses. + int nLearnts () const; // The current number of learnt clauses. + int nVars () const; // The current number of variables. + int nFreeVars () const; + + // Resource contraints: + // + void setConfBudget(int64_t x); + void setPropBudget(int64_t x); + void budgetOff(); + void interrupt(); // Trigger a (potentially asynchronous) interruption of the solver. + void clearInterrupt(); // Clear interrupt indicator flag. + + // Memory managment: + // + virtual void garbageCollect(); + void checkGarbage(double gf); + void checkGarbage(); + + // Extra results: (read-only member variable) + // + vec model; // If problem is satisfiable, this vector contains the model (if any). + vec conflict; // If problem is unsatisfiable (possibly under assumptions), + // this vector represent the final conflict clause expressed in the assumptions. + + // Mode of operation: + // + FILE* drup_file; + int verbosity; + double step_size; + double step_size_dec; + double min_step_size; + int timer; + double var_decay; + double clause_decay; + double random_var_freq; + double random_seed; + bool VSIDS; + int ccmin_mode; // Controls conflict clause minimization (0=none, 1=basic, 2=deep). + int phase_saving; // Controls the level of phase saving (0=none, 1=limited, 2=full). + bool rnd_pol; // Use random polarities for branching heuristics. + bool rnd_init_act; // Initialize variable activities with a small random value. + double garbage_frac; // The fraction of wasted memory allowed before a garbage collection is triggered. + + int restart_first; // The initial restart limit. (default 100) + double restart_inc; // The factor with which the restart limit is multiplied in each restart. (default 1.5) + double learntsize_factor; // The intitial limit for learnt clauses is a factor of the original clauses. (default 1 / 3) + double learntsize_inc; // The limit for learnt clauses is multiplied with this factor each restart. (default 1.1) + + int learntsize_adjust_start_confl; + double learntsize_adjust_inc; + + // Statistics: (read-only member variable) + // + uint64_t solves, starts, decisions, rnd_decisions, propagations, conflicts, conflicts_VSIDS; + uint64_t dec_vars, clauses_literals, learnts_literals, max_literals, tot_literals; + + vec picked; + vec conflicted; + vec almost_conflicted; + +protected: + + // Helper structures: + // + struct VarData { CRef reason; int level; }; + static inline VarData mkVarData(CRef cr, int l){ VarData d = {cr, l}; return d; } + + struct Watcher { + CRef cref; + Lit blocker; + Watcher(CRef cr, Lit p) : cref(cr), blocker(p) {} + bool operator==(const Watcher& w) const { return cref == w.cref; } + bool operator!=(const Watcher& w) const { return cref != w.cref; } + }; + + struct WatcherDeleted + { + const ClauseAllocator& ca; + WatcherDeleted(const ClauseAllocator& _ca) : ca(_ca) {} + bool operator()(const Watcher& w) const { return ca[w.cref].mark() == 1; } + }; + + struct VarOrderLt { + const vec& activity; + bool operator () (Var x, Var y) const { return activity[x] > activity[y]; } + VarOrderLt(const vec& act) : activity(act) { } + }; + + // Solver state: + // + bool ok; // If FALSE, the constraints are already unsatisfiable. No part of the solver state may be used! + vec clauses; // List of problem clauses. + vec learnts_core, // List of learnt clauses. + learnts_tier2, + learnts_local; + double cla_inc; // Amount to bump next clause with. + vec activity_CHB, // A heuristic measurement of the activity of a variable. + activity_VSIDS; + double var_inc; // Amount to bump next variable with. + OccLists, WatcherDeleted> + watches_bin, // Watches for binary clauses only. + watches; // 'watches[lit]' is a list of constraints watching 'lit' (will go there if literal becomes true). + vec assigns; // The current assignments. + vec polarity; // The preferred polarity of each variable. + vec decision; // Declares if a variable is eligible for selection in the decision heuristic. + vec trail; // Assignment stack; stores all assigments made in the order they were made. + vec trail_lim; // Separator indices for different decision levels in 'trail'. + vec vardata; // Stores reason and level for each variable. + int qhead; // Head of queue (as index into the trail -- no more explicit propagation queue in MiniSat). + int simpDB_assigns; // Number of top-level assignments since last execution of 'simplify()'. + int64_t simpDB_props; // Remaining number of propagations that must be made before next execution of 'simplify()'. + vec assumptions; // Current set of assumptions provided to solve by the user. + Heap order_heap_CHB, // A priority queue of variables ordered with respect to the variable activity. + order_heap_VSIDS; + double progress_estimate;// Set by 'search()'. + bool remove_satisfied; // Indicates whether possibly inefficient linear scan for satisfied clauses should be performed in 'simplify'. + + int core_lbd_cut; + float global_lbd_sum; + MyQueue lbd_queue; // For computing moving averages of recent LBD values. + + uint64_t next_T2_reduce, + next_L_reduce; + + ClauseAllocator ca; + + // Temporaries (to reduce allocation overhead). Each variable is prefixed by the method in which it is + // used, exept 'seen' wich is used in several places. + // + vec seen; + vec analyze_stack; + vec analyze_toclear; + vec add_tmp; + vec add_oc; + + vec seen2; // Mostly for efficient LBD computation. 'seen2[i]' will indicate if decision level or variable 'i' has been seen. + uint64_t counter; // Simple counter for marking purpose with 'seen2'. + + double max_learnts; + double learntsize_adjust_confl; + int learntsize_adjust_cnt; + + // Resource contraints: + // + int64_t conflict_budget; // -1 means no budget. + int64_t propagation_budget; // -1 means no budget. + bool asynch_interrupt; + + // Main internal methods: + // + void insertVarOrder (Var x); // Insert a variable in the decision order priority queue. + Lit pickBranchLit (); // Return the next decision variable. + void newDecisionLevel (); // Begins a new decision level. + void uncheckedEnqueue (Lit p, CRef from = CRef_Undef); // Enqueue a literal. Assumes value of literal is undefined. + bool enqueue (Lit p, CRef from = CRef_Undef); // Test if fact 'p' contradicts current state, enqueue otherwise. + CRef propagate (); // Perform unit propagation. Returns possibly conflicting clause. + void cancelUntil (int level); // Backtrack until a certain level. + void analyze (CRef confl, vec& out_learnt, int& out_btlevel, int& out_lbd); // (bt = backtrack) + void analyzeFinal (Lit p, vec& out_conflict); // COULD THIS BE IMPLEMENTED BY THE ORDINARIY "analyze" BY SOME REASONABLE GENERALIZATION? + bool litRedundant (Lit p, uint32_t abstract_levels); // (helper method for 'analyze()') + lbool search (int& nof_conflicts); // Search for a given number of conflicts. + lbool solve_ (); // Main solve method (assumptions given in 'assumptions'). + void reduceDB (); // Reduce the set of learnt clauses. + void reduceDB_Tier2 (); + void removeSatisfied (vec& cs); // Shrink 'cs' to contain only non-satisfied clauses. + void safeRemoveSatisfiedCompact(vec& cs, unsigned valid_mark); + void rebuildOrderHeap (); + bool binResMinimize (vec& out_learnt); // Further learnt clause minimization by binary resolution. + + // Maintaining Variable/Clause activity: + // + void varDecayActivity (); // Decay all variables with the specified factor. Implemented by increasing the 'bump' value instead. + void varBumpActivity (Var v, double mult); // Increase a variable with the current 'bump' value. + void claDecayActivity (); // Decay all clauses with the specified factor. Implemented by increasing the 'bump' value instead. + void claBumpActivity (Clause& c); // Increase a clause with the current 'bump' value. + + // Operations on clauses: + // + void attachClause (CRef cr); // Attach a clause to watcher lists. + void detachClause (CRef cr, bool strict = false); // Detach a clause to watcher lists. + void removeClause (CRef cr); // Detach and free a clause. + void removeClauseHack (CRef cr, Lit watched0, Lit watched1); + bool locked (const Clause& c) const; // Returns TRUE if a clause is a reason for some implication in the current state. + bool satisfied (const Clause& c) const; // Returns TRUE if a clause is satisfied in the current state. + + void relocAll (ClauseAllocator& to); + + // Misc: + // + int decisionLevel () const; // Gives the current decisionlevel. + uint32_t abstractLevel (Var x) const; // Used to represent an abstraction of sets of decision levels. + CRef reason (Var x) const; + int level (Var x) const; + double progressEstimate () const; // DELETE THIS ?? IT'S NOT VERY USEFUL ... + bool withinBudget () const; + + template int computeLBD(const V& c) { + int lbd = 0; + + counter++; + for (int i = 0; i < c.size(); i++){ + int l = level(var(c[i])); + if (l != 0 && seen2[l] != counter){ + seen2[l] = counter; + lbd++; } } + + return lbd; + } + +#ifdef BIN_DRUP + static int buf_len; + static unsigned char drup_buf[]; + static unsigned char* buf_ptr; + + static inline void byteDRUP(Lit l){ + unsigned int u = 2 * (var(l) + 1) + sign(l); + do{ + *buf_ptr++ = u & 0x7f | 0x80; buf_len++; + u = u >> 7; + }while (u); + *(buf_ptr - 1) &= 0x7f; // End marker of this unsigned number. + } + + template + static inline void binDRUP(unsigned char op, const V& c, FILE* drup_file){ + assert(op == 'a' || op == 'd'); + *buf_ptr++ = op; buf_len++; + for (int i = 0; i < c.size(); i++) byteDRUP(c[i]); + *buf_ptr++ = 0; buf_len++; + if (buf_len > 1048576) binDRUP_flush(drup_file); + } + + static inline void binDRUP_strengthen(const Clause& c, Lit l, FILE* drup_file){ + *buf_ptr++ = 'a'; buf_len++; + for (int i = 0; i < c.size(); i++) + if (c[i] != l) byteDRUP(c[i]); + *buf_ptr++ = 0; buf_len++; + if (buf_len > 1048576) binDRUP_flush(drup_file); + } + + static inline void binDRUP_flush(FILE* drup_file){ + fwrite(drup_buf, sizeof(unsigned char), buf_len, drup_file); + buf_ptr = drup_buf; buf_len = 0; + } +#endif + + // Static helpers: + // + + // Returns a random float 0 <= x < 1. Seed must never be 0. + static inline double drand(double& seed) { + seed *= 1389796; + int q = (int)(seed / 2147483647); + seed -= (double)q * 2147483647; + return seed / 2147483647; } + + // Returns a random integer 0 <= x < size. Seed must never be 0. + static inline int irand(double& seed, int size) { + return (int)(drand(seed) * size); } + + // For (advanced) stamping. + struct Frame { + enum TYPE { START = 0, ENTER = 1, RETURN = 2, CLOSE = 3 }; + Lit curr, next; + unsigned type : 3; + unsigned learnt : 1; + Frame(TYPE t, Lit p, Lit q, unsigned l) : curr(p), next(q), type(t), learnt(l) {} + }; + + vec discovered; + vec finished; + vec observed; + vec flag; + vec root; + vec parent; + + vec rec_stack; + vec scc; // Strongly connected component. + + bool stampAll(bool use_bin_learnts); + int stamp(Lit p, int stamp_time, bool use_bin_learnts); + inline bool implExistsByBin(Lit p, bool use_bin_learnts) const; + inline bool isRoot(Lit p, bool use_bin_learnts) const; +}; + + +//================================================================================================= +// Implementation of inline methods: + +inline CRef Solver::reason(Var x) const { return vardata[x].reason; } +inline int Solver::level (Var x) const { return vardata[x].level; } + +inline void Solver::insertVarOrder(Var x) { + Heap& order_heap = VSIDS ? order_heap_VSIDS : order_heap_CHB; + if (!order_heap.inHeap(x) && decision[x]) order_heap.insert(x); } + +inline void Solver::varDecayActivity() { + var_inc *= (1 / var_decay); } + +inline void Solver::varBumpActivity(Var v, double mult) { + if ( (activity_VSIDS[v] += var_inc * mult) > 1e100 ) { + // Rescale: + for (int i = 0; i < nVars(); i++) + activity_VSIDS[i] *= 1e-100; + var_inc *= 1e-100; } + + // Update order_heap with respect to new activity: + if (order_heap_VSIDS.inHeap(v)) order_heap_VSIDS.decrease(v); } + +inline void Solver::claDecayActivity() { cla_inc *= (1 / clause_decay); } +inline void Solver::claBumpActivity (Clause& c) { + if ( (c.activity() += cla_inc) > 1e20 ) { + // Rescale: + for (int i = 0; i < learnts_local.size(); i++) + ca[learnts_local[i]].activity() *= 1e-20; + cla_inc *= 1e-20; } } + +inline void Solver::checkGarbage(void){ return checkGarbage(garbage_frac); } +inline void Solver::checkGarbage(double gf){ + if (ca.wasted() > ca.size() * gf) + garbageCollect(); } + +// NOTE: enqueue does not set the ok flag! (only public methods do) +inline bool Solver::enqueue (Lit p, CRef from) { return value(p) != l_Undef ? value(p) != l_False : (uncheckedEnqueue(p, from), true); } +inline bool Solver::addClause (const vec& ps) { ps.copyTo(add_tmp); return addClause_(add_tmp); } +inline bool Solver::addEmptyClause () { add_tmp.clear(); return addClause_(add_tmp); } +inline bool Solver::addClause (Lit p) { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp); } +inline bool Solver::addClause (Lit p, Lit q) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp); } +inline bool Solver::addClause (Lit p, Lit q, Lit r) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp); } +inline bool Solver::locked (const Clause& c) const { + int i = c.size() != 2 ? 0 : (value(c[0]) == l_True ? 0 : 1); + return value(c[i]) == l_True && reason(var(c[i])) != CRef_Undef && ca.lea(reason(var(c[i]))) == &c; +} +inline void Solver::newDecisionLevel() { trail_lim.push(trail.size()); } + +inline int Solver::decisionLevel () const { return trail_lim.size(); } +inline uint32_t Solver::abstractLevel (Var x) const { return 1 << (level(x) & 31); } +inline lbool Solver::value (Var x) const { return assigns[x]; } +inline lbool Solver::value (Lit p) const { return assigns[var(p)] ^ sign(p); } +inline lbool Solver::modelValue (Var x) const { return model[x]; } +inline lbool Solver::modelValue (Lit p) const { return model[var(p)] ^ sign(p); } +inline int Solver::nAssigns () const { return trail.size(); } +inline int Solver::nClauses () const { return clauses.size(); } +inline int Solver::nLearnts () const { return learnts_core.size() + learnts_tier2.size() + learnts_local.size(); } +inline int Solver::nVars () const { return vardata.size(); } +inline int Solver::nFreeVars () const { return (int)dec_vars - (trail_lim.size() == 0 ? trail.size() : trail_lim[0]); } +inline void Solver::setPolarity (Var v, bool b) { polarity[v] = b; } +inline void Solver::setDecisionVar(Var v, bool b) +{ + if ( b && !decision[v]) dec_vars++; + else if (!b && decision[v]) dec_vars--; + + decision[v] = b; + if (b && !order_heap_CHB.inHeap(v)){ + order_heap_CHB.insert(v); + order_heap_VSIDS.insert(v); } +} +inline void Solver::setConfBudget(int64_t x){ conflict_budget = conflicts + x; } +inline void Solver::setPropBudget(int64_t x){ propagation_budget = propagations + x; } +inline void Solver::interrupt(){ asynch_interrupt = true; } +inline void Solver::clearInterrupt(){ asynch_interrupt = false; } +inline void Solver::budgetOff(){ conflict_budget = propagation_budget = -1; } +inline bool Solver::withinBudget() const { + return !asynch_interrupt && + (conflict_budget < 0 || conflicts < (uint64_t)conflict_budget) && + (propagation_budget < 0 || propagations < (uint64_t)propagation_budget); } + +// FIXME: after the introduction of asynchronous interrruptions the solve-versions that return a +// pure bool do not give a safe interface. Either interrupts must be possible to turn off here, or +// all calls to solve must return an 'lbool'. I'm not yet sure which I prefer. +inline bool Solver::solve () { budgetOff(); assumptions.clear(); return solve_() == l_True; } +inline bool Solver::solve (Lit p) { budgetOff(); assumptions.clear(); assumptions.push(p); return solve_() == l_True; } +inline bool Solver::solve (Lit p, Lit q) { budgetOff(); assumptions.clear(); assumptions.push(p); assumptions.push(q); return solve_() == l_True; } +inline bool Solver::solve (Lit p, Lit q, Lit r) { budgetOff(); assumptions.clear(); assumptions.push(p); assumptions.push(q); assumptions.push(r); return solve_() == l_True; } +inline bool Solver::solve (const vec& assumps){ budgetOff(); assumps.copyTo(assumptions); return solve_() == l_True; } +inline lbool Solver::solveLimited (const vec& assumps){ assumps.copyTo(assumptions); return solve_(); } +inline bool Solver::okay () const { return ok; } + +inline void Solver::toDimacs (const char* file){ vec as; toDimacs(file, as); } +inline void Solver::toDimacs (const char* file, Lit p){ vec as; as.push(p); toDimacs(file, as); } +inline void Solver::toDimacs (const char* file, Lit p, Lit q){ vec as; as.push(p); as.push(q); toDimacs(file, as); } +inline void Solver::toDimacs (const char* file, Lit p, Lit q, Lit r){ vec as; as.push(p); as.push(q); as.push(r); toDimacs(file, as); } + + +//================================================================================================= +// Debug etc: + + +//================================================================================================= +} + +#endif diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/core/SolverTypes.h b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/core/SolverTypes.h new file mode 100755 index 00000000..5b7bda7e --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/core/SolverTypes.h @@ -0,0 +1,426 @@ +/***********************************************************************************[SolverTypes.h] +MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson + Copyright (c) 2007-2010, Niklas Sorensson + +Chanseok Oh's MiniSat Patch Series -- Copyright (c) 2015, Chanseok Oh + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +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 AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + + +#ifndef Minisat_SolverTypes_h +#define Minisat_SolverTypes_h + +#include + +#include "mtl/IntTypes.h" +#include "mtl/Alg.h" +#include "mtl/Vec.h" +#include "mtl/Map.h" +#include "mtl/Alloc.h" + +namespace Minisat { + +//================================================================================================= +// Variables, literals, lifted booleans, clauses: + + +// NOTE! Variables are just integers. No abstraction here. They should be chosen from 0..N, +// so that they can be used as array indices. + +typedef int Var; +#define var_Undef (-1) + + +struct Lit { + int x; + + // Use this as a constructor: + friend Lit mkLit(Var var, bool sign); + + bool operator == (Lit p) const { return x == p.x; } + bool operator != (Lit p) const { return x != p.x; } + bool operator < (Lit p) const { return x < p.x; } // '<' makes p, ~p adjacent in the ordering. +}; + + +inline Lit mkLit (Var var, bool sign = false) { Lit p; p.x = var + var + (int)sign; return p; } +inline Lit operator ~(Lit p) { Lit q; q.x = p.x ^ 1; return q; } +inline Lit operator ^(Lit p, bool b) { Lit q; q.x = p.x ^ (unsigned int)b; return q; } +inline bool sign (Lit p) { return p.x & 1; } +inline int var (Lit p) { return p.x >> 1; } + +// Mapping Literals to and from compact integers suitable for array indexing: +inline int toInt (Var v) { return v; } +inline int toInt (Lit p) { return p.x; } +inline Lit toLit (int i) { Lit p; p.x = i; return p; } + +//const Lit lit_Undef = mkLit(var_Undef, false); // }- Useful special constants. +//const Lit lit_Error = mkLit(var_Undef, true ); // } + +const Lit lit_Undef = { -2 }; // }- Useful special constants. +const Lit lit_Error = { -1 }; // } + + +//================================================================================================= +// Lifted booleans: +// +// NOTE: this implementation is optimized for the case when comparisons between values are mostly +// between one variable and one constant. Some care had to be taken to make sure that gcc +// does enough constant propagation to produce sensible code, and this appears to be somewhat +// fragile unfortunately. + +#define l_True (lbool((uint8_t)0)) // gcc does not do constant propagation if these are real constants. +#define l_False (lbool((uint8_t)1)) +#define l_Undef (lbool((uint8_t)2)) + +class lbool { + uint8_t value; + +public: + explicit lbool(uint8_t v) : value(v) { } + + lbool() : value(0) { } + explicit lbool(bool x) : value(!x) { } + + bool operator == (lbool b) const { return ((b.value&2) & (value&2)) | (!(b.value&2)&(value == b.value)); } + bool operator != (lbool b) const { return !(*this == b); } + lbool operator ^ (bool b) const { return lbool((uint8_t)(value^(uint8_t)b)); } + + lbool operator && (lbool b) const { + uint8_t sel = (this->value << 1) | (b.value << 3); + uint8_t v = (0xF7F755F4 >> sel) & 3; + return lbool(v); } + + lbool operator || (lbool b) const { + uint8_t sel = (this->value << 1) | (b.value << 3); + uint8_t v = (0xFCFCF400 >> sel) & 3; + return lbool(v); } + + friend int toInt (lbool l); + friend lbool toLbool(int v); +}; +inline int toInt (lbool l) { return l.value; } +inline lbool toLbool(int v) { return lbool((uint8_t)v); } + +//================================================================================================= +// Clause -- a simple class for representing a clause: + +class Clause; +typedef RegionAllocator::Ref CRef; + +class Clause { + struct { + unsigned mark : 2; + unsigned learnt : 1; + unsigned has_extra : 1; + unsigned reloced : 1; + unsigned lbd : 26; + unsigned removable : 1; + unsigned size : 32; } header; + union { Lit lit; float act; uint32_t abs; uint32_t touched; CRef rel; } data[0]; + + friend class ClauseAllocator; + + // NOTE: This constructor cannot be used directly (doesn't allocate enough memory). + template + Clause(const V& ps, bool use_extra, bool learnt) { + header.mark = 0; + header.learnt = learnt; + header.has_extra = learnt | use_extra; + header.reloced = 0; + header.size = ps.size(); + header.lbd = 0; + header.removable = 1; + + for (int i = 0; i < ps.size(); i++) + data[i].lit = ps[i]; + + if (header.has_extra){ + if (header.learnt){ + data[header.size].act = 0; + data[header.size+1].touched = 0; + }else + calcAbstraction(); } + } + +public: + void calcAbstraction() { + assert(header.has_extra); + uint32_t abstraction = 0; + for (int i = 0; i < size(); i++) + abstraction |= 1 << (var(data[i].lit) & 31); + data[header.size].abs = abstraction; } + + + int size () const { return header.size; } + void shrink (int i) { assert(i <= size()); if (header.has_extra) data[header.size-i] = data[header.size]; header.size -= i; } + void pop () { shrink(1); } + bool learnt () const { return header.learnt; } + bool has_extra () const { return header.has_extra; } + uint32_t mark () const { return header.mark; } + void mark (uint32_t m) { header.mark = m; } + const Lit& last () const { return data[header.size-1].lit; } + + bool reloced () const { return header.reloced; } + CRef relocation () const { return data[0].rel; } + void relocate (CRef c) { header.reloced = 1; data[0].rel = c; } + + int lbd () const { return header.lbd; } + void set_lbd (int lbd) { header.lbd = lbd; } + bool removable () const { return header.removable; } + void removable (bool b) { header.removable = b; } + + // NOTE: somewhat unsafe to change the clause in-place! Must manually call 'calcAbstraction' afterwards for + // subsumption operations to behave correctly. + Lit& operator [] (int i) { return data[i].lit; } + Lit operator [] (int i) const { return data[i].lit; } + operator const Lit* (void) const { return (Lit*)data; } + + uint32_t& touched () { assert(header.has_extra && header.learnt); return data[header.size+1].touched; } + float& activity () { assert(header.has_extra); return data[header.size].act; } + uint32_t abstraction () const { assert(header.has_extra); return data[header.size].abs; } + + Lit subsumes (const Clause& other) const; + void strengthen (Lit p); +}; + + +//================================================================================================= +// ClauseAllocator -- a simple class for allocating memory for clauses: + + +const CRef CRef_Undef = RegionAllocator::Ref_Undef; +class ClauseAllocator : public RegionAllocator +{ + static int clauseWord32Size(int size, int extras){ + return (sizeof(Clause) + (sizeof(Lit) * (size + extras))) / sizeof(uint32_t); } + public: + bool extra_clause_field; + + ClauseAllocator(uint32_t start_cap) : RegionAllocator(start_cap), extra_clause_field(false){} + ClauseAllocator() : extra_clause_field(false){} + + void moveTo(ClauseAllocator& to){ + to.extra_clause_field = extra_clause_field; + RegionAllocator::moveTo(to); } + + template + CRef alloc(const Lits& ps, bool learnt = false) + { + assert(sizeof(Lit) == sizeof(uint32_t)); + assert(sizeof(float) == sizeof(uint32_t)); + int extras = learnt ? 2 : (int)extra_clause_field; + + CRef cid = RegionAllocator::alloc(clauseWord32Size(ps.size(), extras)); + new (lea(cid)) Clause(ps, extra_clause_field, learnt); + + return cid; + } + + // Deref, Load Effective Address (LEA), Inverse of LEA (AEL): + Clause& operator[](Ref r) { return (Clause&)RegionAllocator::operator[](r); } + const Clause& operator[](Ref r) const { return (Clause&)RegionAllocator::operator[](r); } + Clause* lea (Ref r) { return (Clause*)RegionAllocator::lea(r); } + const Clause* lea (Ref r) const { return (Clause*)RegionAllocator::lea(r); } + Ref ael (const Clause* t){ return RegionAllocator::ael((uint32_t*)t); } + + void free(CRef cid) + { + Clause& c = operator[](cid); + int extras = c.learnt() ? 2 : (int)c.has_extra(); + RegionAllocator::free(clauseWord32Size(c.size(), extras)); + } + + void reloc(CRef& cr, ClauseAllocator& to) + { + Clause& c = operator[](cr); + + if (c.reloced()) { cr = c.relocation(); return; } + + cr = to.alloc(c, c.learnt()); + c.relocate(cr); + + // Copy extra data-fields: + // (This could be cleaned-up. Generalize Clause-constructor to be applicable here instead?) + to[cr].mark(c.mark()); + if (to[cr].learnt()){ + to[cr].touched() = c.touched(); + to[cr].activity() = c.activity(); + to[cr].set_lbd(c.lbd()); + to[cr].removable(c.removable()); + } + else if (to[cr].has_extra()) to[cr].calcAbstraction(); + } +}; + + +//================================================================================================= +// OccLists -- a class for maintaining occurence lists with lazy deletion: + +template +class OccLists +{ + vec occs; + vec dirty; + vec dirties; + Deleted deleted; + + public: + OccLists(const Deleted& d) : deleted(d) {} + + void init (const Idx& idx){ occs.growTo(toInt(idx)+1); dirty.growTo(toInt(idx)+1, 0); } + const Vec& operator[](const Idx& idx) const { return occs[toInt(idx)]; } + Vec& operator[](const Idx& idx){ return occs[toInt(idx)]; } + Vec& lookup (const Idx& idx){ if (dirty[toInt(idx)]) clean(idx); return occs[toInt(idx)]; } + + void cleanAll (); + void clean (const Idx& idx); + void smudge (const Idx& idx){ + if (dirty[toInt(idx)] == 0){ + dirty[toInt(idx)] = 1; + dirties.push(idx); + } + } + + void clear(bool free = true){ + occs .clear(free); + dirty .clear(free); + dirties.clear(free); + } +}; + + +template +void OccLists::cleanAll() +{ + for (int i = 0; i < dirties.size(); i++) + // Dirties may contain duplicates so check here if a variable is already cleaned: + if (dirty[toInt(dirties[i])]) + clean(dirties[i]); + dirties.clear(); +} + + +template +void OccLists::clean(const Idx& idx) +{ + Vec& vec = occs[toInt(idx)]; + int i, j; + for (i = j = 0; i < vec.size(); i++) + if (!deleted(vec[i])) + vec[j++] = vec[i]; + vec.shrink(i - j); + dirty[toInt(idx)] = 0; +} + + +//================================================================================================= +// CMap -- a class for mapping clauses to values: + + +template +class CMap +{ + struct CRefHash { + uint32_t operator()(CRef cr) const { return (uint32_t)cr; } }; + + typedef Map HashTable; + HashTable map; + + public: + // Size-operations: + void clear () { map.clear(); } + int size () const { return map.elems(); } + + + // Insert/Remove/Test mapping: + void insert (CRef cr, const T& t){ map.insert(cr, t); } + void growTo (CRef cr, const T& t){ map.insert(cr, t); } // NOTE: for compatibility + void remove (CRef cr) { map.remove(cr); } + bool has (CRef cr, T& t) { return map.peek(cr, t); } + + // Vector interface (the clause 'c' must already exist): + const T& operator [] (CRef cr) const { return map[cr]; } + T& operator [] (CRef cr) { return map[cr]; } + + // Iteration (not transparent at all at the moment): + int bucket_count() const { return map.bucket_count(); } + const vec& bucket(int i) const { return map.bucket(i); } + + // Move contents to other map: + void moveTo(CMap& other){ map.moveTo(other.map); } + + // TMP debug: + void debug(){ + printf(" --- size = %d, bucket_count = %d\n", size(), map.bucket_count()); } +}; + + +/*_________________________________________________________________________________________________ +| +| subsumes : (other : const Clause&) -> Lit +| +| Description: +| Checks if clause subsumes 'other', and at the same time, if it can be used to simplify 'other' +| by subsumption resolution. +| +| Result: +| lit_Error - No subsumption or simplification +| lit_Undef - Clause subsumes 'other' +| p - The literal p can be deleted from 'other' +|________________________________________________________________________________________________@*/ +inline Lit Clause::subsumes(const Clause& other) const +{ + //if (other.size() < size() || (extra.abst & ~other.extra.abst) != 0) + //if (other.size() < size() || (!learnt() && !other.learnt() && (extra.abst & ~other.extra.abst) != 0)) + assert(!header.learnt); assert(!other.header.learnt); + assert(header.has_extra); assert(other.header.has_extra); + if (other.header.size < header.size || (data[header.size].abs & ~other.data[other.header.size].abs) != 0) + return lit_Error; + + Lit ret = lit_Undef; + const Lit* c = (const Lit*)(*this); + const Lit* d = (const Lit*)other; + + for (unsigned i = 0; i < header.size; i++) { + // search for c[i] or ~c[i] + for (unsigned j = 0; j < other.header.size; j++) + if (c[i] == d[j]) + goto ok; + else if (ret == lit_Undef && c[i] == ~d[j]){ + ret = c[i]; + goto ok; + } + + // did not find it + return lit_Error; + ok:; + } + + return ret; +} + +inline void Clause::strengthen(Lit p) +{ + remove(*this, p); + calcAbstraction(); +} + +//================================================================================================= +} + +#endif diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/doc/ReleaseNotes-2.2.0.txt b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/doc/ReleaseNotes-2.2.0.txt new file mode 100755 index 00000000..7f084de2 --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/doc/ReleaseNotes-2.2.0.txt @@ -0,0 +1,79 @@ +Release Notes for MiniSat 2.2.0 +=============================== + +Changes since version 2.0: + + * Started using a more standard release numbering. + + * Includes some now well-known heuristics: phase-saving and luby + restarts. The old heuristics are still present and can be activated + if needed. + + * Detection/Handling of out-of-memory and vector capacity + overflow. This is fairly new and relatively untested. + + * Simple resource controls: CPU-time, memory, number of + conflicts/decisions. + + * CPU-time limiting is implemented by a more general, but simple, + asynchronous interruption feature. This means that the solving + procedure can be interrupted from another thread or in a signal + handler. + + * Improved portability with respect to building on Solaris and with + Visual Studio. This is not regularly tested and chances are that + this have been broken since, but should be fairly easy to fix if + so. + + * Changed C++ file-extention to the less problematic ".cc". + + * Source code is now namespace-protected + + * Introducing a new Clause Memory Allocator that brings reduced + memory consumption on 64-bit architechtures and improved + performance (to some extent). The allocator uses a region-based + approach were all references to clauses are represented as a 32-bit + index into a global memory region that contains all clauses. To + free up and compact memory it uses a simple copying garbage + collector. + + * Improved unit-propagation by Blocking Literals. For each entry in + the watcher lists, pair the pointer to a clause with some + (arbitrary) literal from the clause. The idea is that if the + literal is currently true (i.e. the clause is satisfied) the + watchers of the clause does not need to be altered. This can thus + be detected without touching the clause's memory at all. As often + as can be done cheaply, the blocking literal for entries to the + watcher list of a literal 'p' is set to the other literal watched + in the corresponding clause. + + * Basic command-line/option handling system. Makes it easy to specify + options in the class that they affect, and whenever that class is + used in an executable, parsing of options and help messages are + brought in automatically. + + * General clean-up and various minor bug-fixes. + + * Changed implementation of variable-elimination/model-extension: + + - The interface is changed so that arbitrary remembering is no longer + possible. If you need to mention some variable again in the future, + this variable has to be frozen. + + - When eliminating a variable, only clauses that contain the variable + with one sign is necessary to store. Thereby making the other sign + a "default" value when extending models. + + - The memory consumption for eliminated clauses is further improved + by storing all eliminated clauses in a single contiguous vector. + + * Some common utility code (I/O, Parsing, CPU-time, etc) is ripped + out and placed in a separate "utils" directory. + + * The DIMACS parse is refactored so that it can be reused in other + applications (not very elegant, but at least possible). + + * Some simple improvements to scalability of preprocessing, using + more lazy clause removal from data-structures and a couple of + ad-hoc limits (the longest clause that can be produced in variable + elimination, and the longest clause used in backward subsumption). diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Alg.h b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Alg.h new file mode 100755 index 00000000..bb1ee5ad --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Alg.h @@ -0,0 +1,84 @@ +/*******************************************************************************************[Alg.h] +Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +Copyright (c) 2007-2010, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +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 AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + +#ifndef Minisat_Alg_h +#define Minisat_Alg_h + +#include "mtl/Vec.h" + +namespace Minisat { + +//================================================================================================= +// Useful functions on vector-like types: + +//================================================================================================= +// Removing and searching for elements: +// + +template +static inline void remove(V& ts, const T& t) +{ + int j = 0; + for (; j < ts.size() && ts[j] != t; j++); + assert(j < ts.size()); + for (; j < ts.size()-1; j++) ts[j] = ts[j+1]; + ts.pop(); +} + + +template +static inline bool find(V& ts, const T& t) +{ + int j = 0; + for (; j < ts.size() && ts[j] != t; j++); + return j < ts.size(); +} + + +//================================================================================================= +// Copying vectors with support for nested vector types: +// + +// Base case: +template +static inline void copy(const T& from, T& to) +{ + to = from; +} + +// Recursive case: +template +static inline void copy(const vec& from, vec& to, bool append = false) +{ + if (!append) + to.clear(); + for (int i = 0; i < from.size(); i++){ + to.push(); + copy(from[i], to.last()); + } +} + +template +static inline void append(const vec& from, vec& to){ copy(from, to, true); } + +//================================================================================================= +} + +#endif diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Alloc.h b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Alloc.h new file mode 100755 index 00000000..76322b8b --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Alloc.h @@ -0,0 +1,131 @@ +/*****************************************************************************************[Alloc.h] +Copyright (c) 2008-2010, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +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 AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + + +#ifndef Minisat_Alloc_h +#define Minisat_Alloc_h + +#include "mtl/XAlloc.h" +#include "mtl/Vec.h" + +namespace Minisat { + +//================================================================================================= +// Simple Region-based memory allocator: + +template +class RegionAllocator +{ + T* memory; + uint32_t sz; + uint32_t cap; + uint32_t wasted_; + + void capacity(uint32_t min_cap); + + public: + // TODO: make this a class for better type-checking? + typedef uint32_t Ref; + enum { Ref_Undef = UINT32_MAX }; + enum { Unit_Size = sizeof(uint32_t) }; + + explicit RegionAllocator(uint32_t start_cap = 1024*1024) : memory(NULL), sz(0), cap(0), wasted_(0){ capacity(start_cap); } + ~RegionAllocator() + { + if (memory != NULL) + ::free(memory); + } + + + uint32_t size () const { return sz; } + uint32_t wasted () const { return wasted_; } + + Ref alloc (int size); + void free (int size) { wasted_ += size; } + + // Deref, Load Effective Address (LEA), Inverse of LEA (AEL): + T& operator[](Ref r) { assert(r >= 0 && r < sz); return memory[r]; } + const T& operator[](Ref r) const { assert(r >= 0 && r < sz); return memory[r]; } + + T* lea (Ref r) { assert(r >= 0 && r < sz); return &memory[r]; } + const T* lea (Ref r) const { assert(r >= 0 && r < sz); return &memory[r]; } + Ref ael (const T* t) { assert((void*)t >= (void*)&memory[0] && (void*)t < (void*)&memory[sz-1]); + return (Ref)(t - &memory[0]); } + + void moveTo(RegionAllocator& to) { + if (to.memory != NULL) ::free(to.memory); + to.memory = memory; + to.sz = sz; + to.cap = cap; + to.wasted_ = wasted_; + + memory = NULL; + sz = cap = wasted_ = 0; + } + + +}; + +template +void RegionAllocator::capacity(uint32_t min_cap) +{ + if (cap >= min_cap) return; + + uint32_t prev_cap = cap; + while (cap < min_cap){ + // NOTE: Multiply by a factor (13/8) without causing overflow, then add 2 and make the + // result even by clearing the least significant bit. The resulting sequence of capacities + // is carefully chosen to hit a maximum capacity that is close to the '2^32-1' limit when + // using 'uint32_t' as indices so that as much as possible of this space can be used. + uint32_t delta = ((cap >> 1) + (cap >> 3) + 2) & ~1; + cap += delta; + + if (cap <= prev_cap) + throw OutOfMemoryException(); + } + // printf(" .. (%p) cap = %u\n", this, cap); + + assert(cap > 0); + memory = (T*)xrealloc(memory, sizeof(T)*cap); +} + + +template +typename RegionAllocator::Ref +RegionAllocator::alloc(int size) +{ + // printf("ALLOC called (this = %p, size = %d)\n", this, size); fflush(stdout); + assert(size > 0); + capacity(sz + size); + + uint32_t prev_sz = sz; + sz += size; + + // Handle overflow: + if (sz < prev_sz) + throw OutOfMemoryException(); + + return prev_sz; +} + + +//================================================================================================= +} + +#endif diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Heap.h b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Heap.h new file mode 100755 index 00000000..b73f9e21 --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Heap.h @@ -0,0 +1,148 @@ +/******************************************************************************************[Heap.h] +Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +Copyright (c) 2007-2010, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +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 AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + +#ifndef Minisat_Heap_h +#define Minisat_Heap_h + +#include "mtl/Vec.h" + +namespace Minisat { + +//================================================================================================= +// A heap implementation with support for decrease/increase key. + + +template +class Heap { + Comp lt; // The heap is a minimum-heap with respect to this comparator + vec heap; // Heap of integers + vec indices; // Each integers position (index) in the Heap + + // Index "traversal" functions + static inline int left (int i) { return i*2+1; } + static inline int right (int i) { return (i+1)*2; } + static inline int parent(int i) { return (i-1) >> 1; } + + + void percolateUp(int i) + { + int x = heap[i]; + int p = parent(i); + + while (i != 0 && lt(x, heap[p])){ + heap[i] = heap[p]; + indices[heap[p]] = i; + i = p; + p = parent(p); + } + heap [i] = x; + indices[x] = i; + } + + + void percolateDown(int i) + { + int x = heap[i]; + while (left(i) < heap.size()){ + int child = right(i) < heap.size() && lt(heap[right(i)], heap[left(i)]) ? right(i) : left(i); + if (!lt(heap[child], x)) break; + heap[i] = heap[child]; + indices[heap[i]] = i; + i = child; + } + heap [i] = x; + indices[x] = i; + } + + + public: + Heap(const Comp& c) : lt(c) { } + + int size () const { return heap.size(); } + bool empty () const { return heap.size() == 0; } + bool inHeap (int n) const { return n < indices.size() && indices[n] >= 0; } + int operator[](int index) const { assert(index < heap.size()); return heap[index]; } + + + void decrease (int n) { assert(inHeap(n)); percolateUp (indices[n]); } + void increase (int n) { assert(inHeap(n)); percolateDown(indices[n]); } + + + // Safe variant of insert/decrease/increase: + void update(int n) + { + if (!inHeap(n)) + insert(n); + else { + percolateUp(indices[n]); + percolateDown(indices[n]); } + } + + + void insert(int n) + { + indices.growTo(n+1, -1); + assert(!inHeap(n)); + + indices[n] = heap.size(); + heap.push(n); + percolateUp(indices[n]); + } + + + int removeMin() + { + int x = heap[0]; + heap[0] = heap.last(); + indices[heap[0]] = 0; + indices[x] = -1; + heap.pop(); + if (heap.size() > 1) percolateDown(0); + return x; + } + + + // Rebuild the heap from scratch, using the elements in 'ns': + void build(const vec& ns) { + for (int i = 0; i < heap.size(); i++) + indices[heap[i]] = -1; + heap.clear(); + + for (int i = 0; i < ns.size(); i++){ + indices[ns[i]] = i; + heap.push(ns[i]); } + + for (int i = heap.size() / 2 - 1; i >= 0; i--) + percolateDown(i); + } + + void clear(bool dealloc = false) + { + for (int i = 0; i < heap.size(); i++) + indices[heap[i]] = -1; + heap.clear(dealloc); + } +}; + + +//================================================================================================= +} + +#endif diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/IntTypes.h b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/IntTypes.h new file mode 100755 index 00000000..c4881628 --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/IntTypes.h @@ -0,0 +1,42 @@ +/**************************************************************************************[IntTypes.h] +Copyright (c) 2009-2010, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +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 AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + +#ifndef Minisat_IntTypes_h +#define Minisat_IntTypes_h + +#ifdef __sun + // Not sure if there are newer versions that support C99 headers. The + // needed features are implemented in the headers below though: + +# include +# include +# include + +#else + +# include +# include + +#endif + +#include + +//================================================================================================= + +#endif diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Map.h b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Map.h new file mode 100755 index 00000000..8a82d0e2 --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Map.h @@ -0,0 +1,193 @@ +/*******************************************************************************************[Map.h] +Copyright (c) 2006-2010, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +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 AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + +#ifndef Minisat_Map_h +#define Minisat_Map_h + +#include "mtl/IntTypes.h" +#include "mtl/Vec.h" + +namespace Minisat { + +//================================================================================================= +// Default hash/equals functions +// + +template struct Hash { uint32_t operator()(const K& k) const { return hash(k); } }; +template struct Equal { bool operator()(const K& k1, const K& k2) const { return k1 == k2; } }; + +template struct DeepHash { uint32_t operator()(const K* k) const { return hash(*k); } }; +template struct DeepEqual { bool operator()(const K* k1, const K* k2) const { return *k1 == *k2; } }; + +static inline uint32_t hash(uint32_t x){ return x; } +static inline uint32_t hash(uint64_t x){ return (uint32_t)x; } +static inline uint32_t hash(int32_t x) { return (uint32_t)x; } +static inline uint32_t hash(int64_t x) { return (uint32_t)x; } + + +//================================================================================================= +// Some primes +// + +static const int nprimes = 25; +static const int primes [nprimes] = { 31, 73, 151, 313, 643, 1291, 2593, 5233, 10501, 21013, 42073, 84181, 168451, 337219, 674701, 1349473, 2699299, 5398891, 10798093, 21596719, 43193641, 86387383, 172775299, 345550609, 691101253 }; + +//================================================================================================= +// Hash table implementation of Maps +// + +template, class E = Equal > +class Map { + public: + struct Pair { K key; D data; }; + + private: + H hash; + E equals; + + vec* table; + int cap; + int size; + + // Don't allow copying (error prone): + Map& operator = (Map& other) { assert(0); } + Map (Map& other) { assert(0); } + + bool checkCap(int new_size) const { return new_size > cap; } + + int32_t index (const K& k) const { return hash(k) % cap; } + void _insert (const K& k, const D& d) { + vec& ps = table[index(k)]; + ps.push(); ps.last().key = k; ps.last().data = d; } + + void rehash () { + const vec* old = table; + + int old_cap = cap; + int newsize = primes[0]; + for (int i = 1; newsize <= cap && i < nprimes; i++) + newsize = primes[i]; + + table = new vec[newsize]; + cap = newsize; + + for (int i = 0; i < old_cap; i++){ + for (int j = 0; j < old[i].size(); j++){ + _insert(old[i][j].key, old[i][j].data); }} + + delete [] old; + + // printf(" --- rehashing, old-cap=%d, new-cap=%d\n", cap, newsize); + } + + + public: + + Map () : table(NULL), cap(0), size(0) {} + Map (const H& h, const E& e) : hash(h), equals(e), table(NULL), cap(0), size(0){} + ~Map () { delete [] table; } + + // PRECONDITION: the key must already exist in the map. + const D& operator [] (const K& k) const + { + assert(size != 0); + const D* res = NULL; + const vec& ps = table[index(k)]; + for (int i = 0; i < ps.size(); i++) + if (equals(ps[i].key, k)) + res = &ps[i].data; + assert(res != NULL); + return *res; + } + + // PRECONDITION: the key must already exist in the map. + D& operator [] (const K& k) + { + assert(size != 0); + D* res = NULL; + vec& ps = table[index(k)]; + for (int i = 0; i < ps.size(); i++) + if (equals(ps[i].key, k)) + res = &ps[i].data; + assert(res != NULL); + return *res; + } + + // PRECONDITION: the key must *NOT* exist in the map. + void insert (const K& k, const D& d) { if (checkCap(size+1)) rehash(); _insert(k, d); size++; } + bool peek (const K& k, D& d) const { + if (size == 0) return false; + const vec& ps = table[index(k)]; + for (int i = 0; i < ps.size(); i++) + if (equals(ps[i].key, k)){ + d = ps[i].data; + return true; } + return false; + } + + bool has (const K& k) const { + if (size == 0) return false; + const vec& ps = table[index(k)]; + for (int i = 0; i < ps.size(); i++) + if (equals(ps[i].key, k)) + return true; + return false; + } + + // PRECONDITION: the key must exist in the map. + void remove(const K& k) { + assert(table != NULL); + vec& ps = table[index(k)]; + int j = 0; + for (; j < ps.size() && !equals(ps[j].key, k); j++); + assert(j < ps.size()); + ps[j] = ps.last(); + ps.pop(); + size--; + } + + void clear () { + cap = size = 0; + delete [] table; + table = NULL; + } + + int elems() const { return size; } + int bucket_count() const { return cap; } + + // NOTE: the hash and equality objects are not moved by this method: + void moveTo(Map& other){ + delete [] other.table; + + other.table = table; + other.cap = cap; + other.size = size; + + table = NULL; + size = cap = 0; + } + + // NOTE: given a bit more time, I could make a more C++-style iterator out of this: + const vec& bucket(int i) const { return table[i]; } +}; + +//================================================================================================= +} + +#endif diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Queue.h b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Queue.h new file mode 100755 index 00000000..17567d69 --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Queue.h @@ -0,0 +1,69 @@ +/*****************************************************************************************[Queue.h] +Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +Copyright (c) 2007-2010, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +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 AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + +#ifndef Minisat_Queue_h +#define Minisat_Queue_h + +#include "mtl/Vec.h" + +namespace Minisat { + +//================================================================================================= + +template +class Queue { + vec buf; + int first; + int end; + +public: + typedef T Key; + + Queue() : buf(1), first(0), end(0) {} + + void clear (bool dealloc = false) { buf.clear(dealloc); buf.growTo(1); first = end = 0; } + int size () const { return (end >= first) ? end - first : end - first + buf.size(); } + + const T& operator [] (int index) const { assert(index >= 0); assert(index < size()); return buf[(first + index) % buf.size()]; } + T& operator [] (int index) { assert(index >= 0); assert(index < size()); return buf[(first + index) % buf.size()]; } + + T peek () const { assert(first != end); return buf[first]; } + void pop () { assert(first != end); first++; if (first == buf.size()) first = 0; } + void insert(T elem) { // INVARIANT: buf[end] is always unused + buf[end++] = elem; + if (end == buf.size()) end = 0; + if (first == end){ // Resize: + vec tmp((buf.size()*3 + 1) >> 1); + //**/printf("queue alloc: %d elems (%.1f MB)\n", tmp.size(), tmp.size() * sizeof(T) / 1000000.0); + int i = 0; + for (int j = first; j < buf.size(); j++) tmp[i++] = buf[j]; + for (int j = 0 ; j < end ; j++) tmp[i++] = buf[j]; + first = 0; + end = buf.size(); + tmp.moveTo(buf); + } + } +}; + + +//================================================================================================= +} + +#endif diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Sort.h b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Sort.h new file mode 100755 index 00000000..e9313ef8 --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Sort.h @@ -0,0 +1,98 @@ +/******************************************************************************************[Sort.h] +Copyright (c) 2003-2007, Niklas Een, Niklas Sorensson +Copyright (c) 2007-2010, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +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 AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + +#ifndef Minisat_Sort_h +#define Minisat_Sort_h + +#include "mtl/Vec.h" + +//================================================================================================= +// Some sorting algorithms for vec's + + +namespace Minisat { + +template +struct LessThan_default { + bool operator () (T x, T y) { return x < y; } +}; + + +template +void selectionSort(T* array, int size, LessThan lt) +{ + int i, j, best_i; + T tmp; + + for (i = 0; i < size-1; i++){ + best_i = i; + for (j = i+1; j < size; j++){ + if (lt(array[j], array[best_i])) + best_i = j; + } + tmp = array[i]; array[i] = array[best_i]; array[best_i] = tmp; + } +} +template static inline void selectionSort(T* array, int size) { + selectionSort(array, size, LessThan_default()); } + +template +void sort(T* array, int size, LessThan lt) +{ + if (size <= 15) + selectionSort(array, size, lt); + + else{ + T pivot = array[size / 2]; + T tmp; + int i = -1; + int j = size; + + for(;;){ + do i++; while(lt(array[i], pivot)); + do j--; while(lt(pivot, array[j])); + + if (i >= j) break; + + tmp = array[i]; array[i] = array[j]; array[j] = tmp; + } + + sort(array , i , lt); + sort(&array[i], size-i, lt); + } +} +template static inline void sort(T* array, int size) { + sort(array, size, LessThan_default()); } + + +//================================================================================================= +// For 'vec's: + + +template void sort(vec& v, LessThan lt) { + sort((T*)v, v.size(), lt); } +template void sort(vec& v) { + sort(v, LessThan_default()); } + + +//================================================================================================= +} + +#endif diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Vec.h b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Vec.h new file mode 100755 index 00000000..9e220852 --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/Vec.h @@ -0,0 +1,130 @@ +/*******************************************************************************************[Vec.h] +Copyright (c) 2003-2007, Niklas Een, Niklas Sorensson +Copyright (c) 2007-2010, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +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 AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + +#ifndef Minisat_Vec_h +#define Minisat_Vec_h + +#include +#include + +#include "mtl/IntTypes.h" +#include "mtl/XAlloc.h" + +namespace Minisat { + +//================================================================================================= +// Automatically resizable arrays +// +// NOTE! Don't use this vector on datatypes that cannot be re-located in memory (with realloc) + +template +class vec { + T* data; + int sz; + int cap; + + // Don't allow copying (error prone): + vec& operator = (vec& other) { assert(0); return *this; } + vec (vec& other) { assert(0); } + + // Helpers for calculating next capacity: + static inline int imax (int x, int y) { int mask = (y-x) >> (sizeof(int)*8-1); return (x&mask) + (y&(~mask)); } + //static inline void nextCap(int& cap){ cap += ((cap >> 1) + 2) & ~1; } + static inline void nextCap(int& cap){ cap += ((cap >> 1) + 2) & ~1; } + +public: + // Constructors: + vec() : data(NULL) , sz(0) , cap(0) { } + explicit vec(int size) : data(NULL) , sz(0) , cap(0) { growTo(size); } + vec(int size, const T& pad) : data(NULL) , sz(0) , cap(0) { growTo(size, pad); } + ~vec() { clear(true); } + + // Pointer to first element: + operator T* (void) { return data; } + + // Size operations: + int size (void) const { return sz; } + void shrink (int nelems) { assert(nelems <= sz); for (int i = 0; i < nelems; i++) sz--, data[sz].~T(); } + void shrink_ (int nelems) { assert(nelems <= sz); sz -= nelems; } + int capacity (void) const { return cap; } + void capacity (int min_cap); + void growTo (int size); + void growTo (int size, const T& pad); + void clear (bool dealloc = false); + + // Stack interface: + void push (void) { if (sz == cap) capacity(sz+1); new (&data[sz]) T(); sz++; } + void push (const T& elem) { if (sz == cap) capacity(sz+1); data[sz++] = elem; } + void push_ (const T& elem) { assert(sz < cap); data[sz++] = elem; } + void pop (void) { assert(sz > 0); sz--, data[sz].~T(); } + // NOTE: it seems possible that overflow can happen in the 'sz+1' expression of 'push()', but + // in fact it can not since it requires that 'cap' is equal to INT_MAX. This in turn can not + // happen given the way capacities are calculated (below). Essentially, all capacities are + // even, but INT_MAX is odd. + + const T& last (void) const { return data[sz-1]; } + T& last (void) { return data[sz-1]; } + + // Vector interface: + const T& operator [] (int index) const { return data[index]; } + T& operator [] (int index) { return data[index]; } + + // Duplicatation (preferred instead): + void copyTo(vec& copy) const { copy.clear(); copy.growTo(sz); for (int i = 0; i < sz; i++) copy[i] = data[i]; } + void moveTo(vec& dest) { dest.clear(true); dest.data = data; dest.sz = sz; dest.cap = cap; data = NULL; sz = 0; cap = 0; } +}; + + +template +void vec::capacity(int min_cap) { + if (cap >= min_cap) return; + int add = imax((min_cap - cap + 1) & ~1, ((cap >> 1) + 2) & ~1); // NOTE: grow by approximately 3/2 + if (add > INT_MAX - cap || ((data = (T*)::realloc(data, (cap += add) * sizeof(T))) == NULL) && errno == ENOMEM) + throw OutOfMemoryException(); + } + + +template +void vec::growTo(int size, const T& pad) { + if (sz >= size) return; + capacity(size); + for (int i = sz; i < size; i++) data[i] = pad; + sz = size; } + + +template +void vec::growTo(int size) { + if (sz >= size) return; + capacity(size); + for (int i = sz; i < size; i++) new (&data[i]) T(); + sz = size; } + + +template +void vec::clear(bool dealloc) { + if (data != NULL){ + for (int i = 0; i < sz; i++) data[i].~T(); + sz = 0; + if (dealloc) free(data), data = NULL, cap = 0; } } + +//================================================================================================= +} + +#endif diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/XAlloc.h b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/XAlloc.h new file mode 100755 index 00000000..1da17602 --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/XAlloc.h @@ -0,0 +1,45 @@ +/****************************************************************************************[XAlloc.h] +Copyright (c) 2009-2010, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +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 AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + + +#ifndef Minisat_XAlloc_h +#define Minisat_XAlloc_h + +#include +#include + +namespace Minisat { + +//================================================================================================= +// Simple layer on top of malloc/realloc to catch out-of-memory situtaions and provide some typing: + +class OutOfMemoryException{}; +static inline void* xrealloc(void *ptr, size_t size) +{ + void* mem = realloc(ptr, size); + if (mem == NULL && errno == ENOMEM){ + throw OutOfMemoryException(); + }else + return mem; +} + +//================================================================================================= +} + +#endif diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/config.mk b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/config.mk new file mode 100755 index 00000000..b5c36fc6 --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/config.mk @@ -0,0 +1,6 @@ +## +## This file is for system specific configurations. For instance, on +## some systems the path to zlib needs to be added. Example: +## +## CFLAGS += -I/usr/local/include +## LFLAGS += -L/usr/local/lib diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/template.mk b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/template.mk new file mode 100755 index 00000000..3f443fc3 --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/mtl/template.mk @@ -0,0 +1,107 @@ +## +## Template makefile for Standard, Profile, Debug, Release, and Release-static versions +## +## eg: "make rs" for a statically linked release version. +## "make d" for a debug version (no optimizations). +## "make" for the standard version (optimized, but with debug information and assertions active) + +PWD = $(shell pwd) +EXEC ?= $(notdir $(PWD)) + +CSRCS = $(wildcard $(PWD)/*.cc) +DSRCS = $(foreach dir, $(DEPDIR), $(filter-out $(MROOT)/$(dir)/Main.cc, $(wildcard $(MROOT)/$(dir)/*.cc))) +CHDRS = $(wildcard $(PWD)/*.h) +COBJS = $(CSRCS:.cc=.o) $(DSRCS:.cc=.o) + +PCOBJS = $(addsuffix p, $(COBJS)) +DCOBJS = $(addsuffix d, $(COBJS)) +RCOBJS = $(addsuffix r, $(COBJS)) + + +CXX ?= g++ +CFLAGS ?= -Wall -Wno-parentheses +LFLAGS ?= -Wall + +COPTIMIZE ?= -O3 + +CFLAGS += -I$(MROOT) -D __STDC_LIMIT_MACROS -D __STDC_FORMAT_MACROS +LFLAGS += -lz + +.PHONY : s p d r rs clean + +s: $(EXEC) +p: $(EXEC)_profile +d: $(EXEC)_debug +r: $(EXEC)_release +rs: $(EXEC)_static + +libs: lib$(LIB)_standard.a +libp: lib$(LIB)_profile.a +libd: lib$(LIB)_debug.a +libr: lib$(LIB)_release.a + +## Compile options +%.o: CFLAGS +=$(COPTIMIZE) -g -D DEBUG +%.op: CFLAGS +=$(COPTIMIZE) -pg -g -D NDEBUG +%.od: CFLAGS +=-O0 -g -D DEBUG +%.or: CFLAGS +=$(COPTIMIZE) -g -D NDEBUG + +## Link options +$(EXEC): LFLAGS += -g +$(EXEC)_profile: LFLAGS += -g -pg +$(EXEC)_debug: LFLAGS += -g +#$(EXEC)_release: LFLAGS += ... +$(EXEC)_static: LFLAGS += --static + +## Dependencies +$(EXEC): $(COBJS) +$(EXEC)_profile: $(PCOBJS) +$(EXEC)_debug: $(DCOBJS) +$(EXEC)_release: $(RCOBJS) +$(EXEC)_static: $(RCOBJS) + +lib$(LIB)_standard.a: $(filter-out */Main.o, $(COBJS)) +lib$(LIB)_profile.a: $(filter-out */Main.op, $(PCOBJS)) +lib$(LIB)_debug.a: $(filter-out */Main.od, $(DCOBJS)) +lib$(LIB)_release.a: $(filter-out */Main.or, $(RCOBJS)) + + +## Build rule +%.o %.op %.od %.or: %.cc + @echo Compiling: $(subst $(MROOT)/,,$@) + @$(CXX) $(CFLAGS) -c -o $@ $< + +## Linking rules (standard/profile/debug/release) +$(EXEC) $(EXEC)_profile $(EXEC)_debug $(EXEC)_release $(EXEC)_static: + @echo Linking: "$@ ( $(foreach f,$^,$(subst $(MROOT)/,,$f)) )" + @$(CXX) $^ $(LFLAGS) -o $@ + +## Library rules (standard/profile/debug/release) +lib$(LIB)_standard.a lib$(LIB)_profile.a lib$(LIB)_release.a lib$(LIB)_debug.a: + @echo Making library: "$@ ( $(foreach f,$^,$(subst $(MROOT)/,,$f)) )" + @$(AR) -rcsv $@ $^ + +## Library Soft Link rule: +libs libp libd libr: + @echo "Making Soft Link: $^ -> lib$(LIB).a" + @ln -sf $^ lib$(LIB).a + +## Clean rule +clean: + @rm -f $(EXEC) $(EXEC)_profile $(EXEC)_debug $(EXEC)_release $(EXEC)_static \ + $(COBJS) $(PCOBJS) $(DCOBJS) $(RCOBJS) *.core depend.mk + +## Make dependencies +depend.mk: $(CSRCS) $(CHDRS) + @echo Making dependencies + @$(CXX) $(CFLAGS) -I$(MROOT) \ + $(CSRCS) -MM | sed 's|\(.*\):|$(PWD)/\1 $(PWD)/\1r $(PWD)/\1d $(PWD)/\1p:|' > depend.mk + @for dir in $(DEPDIR); do \ + if [ -r $(MROOT)/$${dir}/depend.mk ]; then \ + echo Depends on: $${dir}; \ + cat $(MROOT)/$${dir}/depend.mk >> depend.mk; \ + fi; \ + done + +-include $(MROOT)/mtl/config.mk +-include depend.mk diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/simp/Main.cc b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/simp/Main.cc new file mode 100755 index 00000000..d4ca8873 --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/simp/Main.cc @@ -0,0 +1,251 @@ +/*****************************************************************************************[Main.cc] +Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +Copyright (c) 2007, Niklas Sorensson + +Chanseok Oh's MiniSat Patch Series -- Copyright (c) 2015, Chanseok Oh + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +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 AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + +#include + +#include +#include +#include + +#include "utils/System.h" +#include "utils/ParseUtils.h" +#include "utils/Options.h" +#include "core/Dimacs.h" +#include "simp/SimpSolver.h" + +using namespace Minisat; + +//================================================================================================= + + +void printStats(Solver& solver) +{ + double cpu_time = cpuTime(); +// double mem_used = memUsedPeak(); +// printf("c restarts : %"PRIu64"\n", solver.starts); +// printf("c conflicts : %-12"PRIu64" (%.0f /sec)\n", solver.conflicts , solver.conflicts /cpu_time); +// printf("c decisions : %-12"PRIu64" (%4.2f %% random) (%.0f /sec)\n", solver.decisions, (float)solver.rnd_decisions*100 / (float)solver.decisions, solver.decisions /cpu_time); +// printf("c propagations : %-12"PRIu64" (%.0f /sec)\n", solver.propagations, solver.propagations/cpu_time); +// printf("c conflict literals : %-12"PRIu64" (%4.2f %% deleted)\n", solver.tot_literals, (solver.max_literals - solver.tot_literals)*100 / (double)solver.max_literals); +// if (mem_used != 0) printf("c Memory used : %.2f MB\n", mem_used); + printf("c CPU time : %g s\n", cpu_time); +} + + +static Solver* solver; +// Terminate by notifying the solver and back out gracefully. This is mainly to have a test-case +// for this feature of the Solver as it may take longer than an immediate call to '_exit()'. +static void SIGINT_interrupt(int signum) { solver->interrupt(); } + +// Note that '_exit()' rather than 'exit()' has to be used. The reason is that 'exit()' calls +// destructors and may cause deadlocks if a malloc/free function happens to be running (these +// functions are guarded by locks for multithreaded use). +static void SIGINT_exit(int signum) { + printf("\n"); printf("c *** INTERRUPTED ***\n"); + if (solver->verbosity > 0){ + printStats(*solver); + printf("\n"); printf("c *** INTERRUPTED ***\n"); } + _exit(1); } + + +//================================================================================================= +// Main: + +int main(int argc, char** argv) +{ + try { + setUsageHelp("USAGE: %s [options] \n\n where input may be either in plain or gzipped DIMACS.\n"); + printf("c This is COMiniSatPS.\n"); + +#if defined(__linux__) + fpu_control_t oldcw, newcw; + _FPU_GETCW(oldcw); newcw = (oldcw & ~_FPU_EXTENDED) | _FPU_DOUBLE; _FPU_SETCW(newcw); + printf("c WARNING: for repeatability, setting FPU to use double precision\n"); +#endif + // Extra options: + // + IntOption verb ("MAIN", "verb", "Verbosity level (0=silent, 1=some, 2=more).", 1, IntRange(0, 2)); + BoolOption pre ("MAIN", "pre", "Completely turn on/off any preprocessing.", true); + StringOption dimacs ("MAIN", "dimacs", "If given, stop after preprocessing and write the result to this file."); + IntOption cpu_lim("MAIN", "cpu-lim","Limit on CPU time allowed in seconds.\n", INT32_MAX, IntRange(0, INT32_MAX)); + IntOption mem_lim("MAIN", "mem-lim","Limit on memory usage in megabytes.\n", INT32_MAX, IntRange(0, INT32_MAX)); + BoolOption drup ("MAIN", "drup", "Generate DRUP UNSAT proof.", false); + StringOption drup_file("MAIN", "drup-file", "DRUP UNSAT proof ouput file.", ""); + + parseOptions(argc, argv, true); + + SimpSolver S; + double initial_time = cpuTime(); + + if (!pre) S.eliminate(true); + + S.parsing = true; + S.verbosity = verb; + if (drup || strlen(drup_file)){ + S.drup_file = strlen(drup_file) ? fopen(drup_file, "wb") : stdout; + if (S.drup_file == NULL){ + S.drup_file = stdout; + printf("c Error opening %s for write.\n", (const char*) drup_file); } + printf("c DRUP proof generation: %s\n", S.drup_file == stdout ? "stdout" : drup_file); + } + + solver = &S; + // Use signal handlers that forcibly quit until the solver will be able to respond to + // interrupts: + signal(SIGINT, SIGINT_exit); + signal(SIGXCPU,SIGINT_exit); + + // Set limit on CPU-time: + if (cpu_lim != INT32_MAX){ + rlimit rl; + getrlimit(RLIMIT_CPU, &rl); + if (rl.rlim_max == RLIM_INFINITY || (rlim_t)cpu_lim < rl.rlim_max){ + rl.rlim_cur = cpu_lim; + if (setrlimit(RLIMIT_CPU, &rl) == -1) + printf("c WARNING! Could not set resource limit: CPU-time.\n"); + } } + + // Set limit on virtual memory: + if (mem_lim != INT32_MAX){ + rlim_t new_mem_lim = (rlim_t)mem_lim * 1024*1024; + rlimit rl; + getrlimit(RLIMIT_AS, &rl); + if (rl.rlim_max == RLIM_INFINITY || new_mem_lim < rl.rlim_max){ + rl.rlim_cur = new_mem_lim; + if (setrlimit(RLIMIT_AS, &rl) == -1) + printf("c WARNING! Could not set resource limit: Virtual memory.\n"); + } } + + if (argc == 1) + printf("c Reading from standard input... Use '--help' for help.\n"); + + gzFile in = (argc == 1) ? gzdopen(0, "rb") : gzopen(argv[1], "rb"); + if (in == NULL) + printf("c ERROR! Could not open file: %s\n", argc == 1 ? "" : argv[1]), exit(1); + + if (S.verbosity > 0){ + printf("c ============================[ Problem Statistics ]=============================\n"); + printf("c | |\n"); } + + parse_DIMACS(in, S); + gzclose(in); + FILE* res = (argc >= 3) ? fopen(argv[2], "wb") : NULL; + + if (S.verbosity > 0){ + printf("c | Number of variables: %12d |\n", S.nVars()); + printf("c | Number of clauses: %12d |\n", S.nClauses()); } + + double parsed_time = cpuTime(); + if (S.verbosity > 0) + printf("c | Parse time: %12.2f s |\n", parsed_time - initial_time); + + // Change to signal-handlers that will only notify the solver and allow it to terminate + // voluntarily: + // signal(SIGINT, SIGINT_interrupt); + // signal(SIGXCPU,SIGINT_interrupt); + + S.parsing = false; + S.eliminate(true); + double simplified_time = cpuTime(); + if (S.verbosity > 0){ + printf("c | Simplification time: %12.2f s |\n", simplified_time - parsed_time); + printf("c | |\n"); } + + if (!S.okay()){ + if (res != NULL) fprintf(res, "UNSAT\n"), fclose(res); + if (S.verbosity > 0){ + printf("c ===============================================================================\n"); + printf("c Solved by simplification\n"); + printStats(S); + printf("\n"); } + printf("s UNSATISFIABLE\n"); + if (S.drup_file){ +#ifdef BIN_DRUP + fputc('a', S.drup_file); fputc(0, S.drup_file); +#else + fprintf(S.drup_file, "0\n"); +#endif + } + if (S.drup_file && S.drup_file != stdout) fclose(S.drup_file); + exit(20); + } + + if (dimacs){ + if (S.verbosity > 0) + printf("c ==============================[ Writing DIMACS ]===============================\n"); + S.toDimacs((const char*)dimacs); + if (S.verbosity > 0) + printStats(S); + exit(0); + } + + vec dummy; + lbool ret = S.solveLimited(dummy); + + if (S.verbosity > 0){ + printStats(S); + printf("\n"); } + printf(ret == l_True ? "s SATISFIABLE\n" : ret == l_False ? "s UNSATISFIABLE\n" : "s UNKNOWN\n"); + // Do not flush stdout + // if (ret == l_True){ + // printf("v "); + // for (int i = 0; i < S.nVars(); i++) + // if (S.model[i] != l_Undef) + // printf("%s%s%d", (i==0)?"":" ", (S.model[i]==l_True)?"":"-", i+1); + // printf(" 0\n"); + // } + + if (S.drup_file && ret == l_False){ +#ifdef BIN_DRUP + fputc('a', S.drup_file); fputc(0, S.drup_file); +#else + fprintf(S.drup_file, "0\n"); +#endif + } + if (S.drup_file && S.drup_file != stdout) fclose(S.drup_file); + + if (res != NULL){ + if (ret == l_True){ + fprintf(res, "SAT\n"); + for (int i = 0; i < S.nVars(); i++) + if (S.model[i] != l_Undef) + fprintf(res, "%s%s%d", (i==0)?"":" ", (S.model[i]==l_True)?"":"-", i+1); + fprintf(res, " 0\n"); + }else if (ret == l_False) + fprintf(res, "UNSAT\n"); + else + fprintf(res, "INDET\n"); + fclose(res); + } + +#ifdef NDEBUG + exit(ret == l_True ? 10 : ret == l_False ? 20 : 0); // (faster than "return", which will invoke the destructor for 'Solver') +#else + return (ret == l_True ? 10 : ret == l_False ? 20 : 0); +#endif + } catch (OutOfMemoryException&){ + printf("c ===============================================================================\n"); + printf("c Out of memory\n"); + printf("s UNKNOWN\n"); + exit(0); + } +} diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/simp/Makefile b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/simp/Makefile new file mode 100755 index 00000000..27b45f49 --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/simp/Makefile @@ -0,0 +1,4 @@ +EXEC = minisat +DEPDIR = mtl utils core + +include $(MROOT)/mtl/template.mk diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/simp/SimpSolver.cc b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/simp/SimpSolver.cc new file mode 100755 index 00000000..ebf9e33b --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/simp/SimpSolver.cc @@ -0,0 +1,825 @@ +/***********************************************************************************[SimpSolver.cc] +MiniSat -- Copyright (c) 2006, Niklas Een, Niklas Sorensson + Copyright (c) 2007-2010, Niklas Sorensson + +Chanseok Oh's MiniSat Patch Series -- Copyright (c) 2015, Chanseok Oh + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +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 AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + +#include "mtl/Sort.h" +#include "simp/SimpSolver.h" +#include "utils/System.h" + +using namespace Minisat; + +//================================================================================================= +// Options: + + +static const char* _cat = "SIMP"; + +static BoolOption opt_use_asymm (_cat, "asymm", "Shrink clauses by asymmetric branching.", false); +static BoolOption opt_use_rcheck (_cat, "rcheck", "Check if a clause is already implied. (costly)", false); +static BoolOption opt_use_elim (_cat, "elim", "Perform variable elimination.", true); +static IntOption opt_grow (_cat, "grow", "Allow a variable elimination step to grow by a number of clauses.", 0); +static IntOption opt_clause_lim (_cat, "cl-lim", "Variables are not eliminated if it produces a resolvent with a length above this limit. -1 means no limit", 20, IntRange(-1, INT32_MAX)); +static IntOption opt_subsumption_lim (_cat, "sub-lim", "Do not check if subsumption against a clause larger than this. -1 means no limit.", 1000, IntRange(-1, INT32_MAX)); +static DoubleOption opt_simp_garbage_frac(_cat, "simp-gc-frac", "The fraction of wasted memory allowed before a garbage collection is triggered during simplification.", 0.5, DoubleRange(0, false, HUGE_VAL, false)); + + +//================================================================================================= +// Constructor/Destructor: + + +SimpSolver::SimpSolver() : + parsing (false) + , grow (opt_grow) + , clause_lim (opt_clause_lim) + , subsumption_lim (opt_subsumption_lim) + , simp_garbage_frac (opt_simp_garbage_frac) + , use_asymm (opt_use_asymm) + , use_rcheck (opt_use_rcheck) + , use_elim (opt_use_elim) + , merges (0) + , asymm_lits (0) + , eliminated_vars (0) + , elimorder (1) + , use_simplification (true) + , occurs (ClauseDeleted(ca)) + , elim_heap (ElimLt(n_occ)) + , bwdsub_assigns (0) + , n_touched (0) +{ + vec dummy(1,lit_Undef); + ca.extra_clause_field = true; // NOTE: must happen before allocating the dummy clause below. + bwdsub_tmpunit = ca.alloc(dummy); + remove_satisfied = false; +} + + +SimpSolver::~SimpSolver() +{ +} + + +Var SimpSolver::newVar(bool sign, bool dvar) { + Var v = Solver::newVar(sign, dvar); + + frozen .push((char)false); + eliminated.push((char)false); + + if (use_simplification){ + n_occ .push(0); + n_occ .push(0); + occurs .init(v); + touched .push(0); + elim_heap .insert(v); + } + return v; } + + + +lbool SimpSolver::solve_(bool do_simp, bool turn_off_simp) +{ + vec extra_frozen; + lbool result = l_True; + + do_simp &= use_simplification; + + if (do_simp){ + // Assumptions must be temporarily frozen to run variable elimination: + for (int i = 0; i < assumptions.size(); i++){ + Var v = var(assumptions[i]); + + // If an assumption has been eliminated, remember it. + assert(!isEliminated(v)); + + if (!frozen[v]){ + // Freeze and store. + setFrozen(v, true); + extra_frozen.push(v); + } } + + result = lbool(eliminate(turn_off_simp)); + } + + if (result == l_True) + result = Solver::solve_(); + else if (verbosity >= 1) + printf("c ===============================================================================\n"); + + if (result == l_True) + extendModel(); + + if (do_simp) + // Unfreeze the assumptions that were frozen: + for (int i = 0; i < extra_frozen.size(); i++) + setFrozen(extra_frozen[i], false); + + return result; +} + + + +bool SimpSolver::addClause_(vec& ps) +{ +#ifndef NDEBUG + for (int i = 0; i < ps.size(); i++) + assert(!isEliminated(var(ps[i]))); +#endif + + int nclauses = clauses.size(); + + if (use_rcheck && implied(ps)) + return true; + + if (!Solver::addClause_(ps)) + return false; + + if (!parsing && drup_file) { +#ifdef BIN_DRUP + binDRUP('a', ps, drup_file); +#else + for (int i = 0; i < ps.size(); i++) + fprintf(drup_file, "%i ", (var(ps[i]) + 1) * (-2 * sign(ps[i]) + 1)); + fprintf(drup_file, "0\n"); +#endif + } + + if (use_simplification && clauses.size() == nclauses + 1){ + CRef cr = clauses.last(); + const Clause& c = ca[cr]; + + // NOTE: the clause is added to the queue immediately and then + // again during 'gatherTouchedClauses()'. If nothing happens + // in between, it will only be checked once. Otherwise, it may + // be checked twice unnecessarily. This is an unfortunate + // consequence of how backward subsumption is used to mimic + // forward subsumption. + subsumption_queue.insert(cr); + for (int i = 0; i < c.size(); i++){ + occurs[var(c[i])].push(cr); + n_occ[toInt(c[i])]++; + touched[var(c[i])] = 1; + n_touched++; + if (elim_heap.inHeap(var(c[i]))) + elim_heap.increase(var(c[i])); + } + } + + return true; +} + + +void SimpSolver::removeClause(CRef cr) +{ + const Clause& c = ca[cr]; + + if (use_simplification) + for (int i = 0; i < c.size(); i++){ + n_occ[toInt(c[i])]--; + updateElimHeap(var(c[i])); + occurs.smudge(var(c[i])); + } + + Solver::removeClause(cr); +} + + +bool SimpSolver::strengthenClause(CRef cr, Lit l) +{ + Clause& c = ca[cr]; + assert(decisionLevel() == 0); + assert(use_simplification); + + // FIX: this is too inefficient but would be nice to have (properly implemented) + // if (!find(subsumption_queue, &c)) + subsumption_queue.insert(cr); + + if (drup_file){ +#ifdef BIN_DRUP + binDRUP_strengthen(c, l, drup_file); +#else + for (int i = 0; i < c.size(); i++) + if (c[i] != l) fprintf(drup_file, "%i ", (var(c[i]) + 1) * (-2 * sign(c[i]) + 1)); + fprintf(drup_file, "0\n"); +#endif + } + + if (c.size() == 2){ + removeClause(cr); + c.strengthen(l); + }else{ + if (drup_file){ +#ifdef BIN_DRUP + binDRUP('d', c, drup_file); +#else + fprintf(drup_file, "d "); + for (int i = 0; i < c.size(); i++) + fprintf(drup_file, "%i ", (var(c[i]) + 1) * (-2 * sign(c[i]) + 1)); + fprintf(drup_file, "0\n"); +#endif + } + + detachClause(cr, true); + c.strengthen(l); + attachClause(cr); + remove(occurs[var(l)], cr); + n_occ[toInt(l)]--; + updateElimHeap(var(l)); + } + + return c.size() == 1 ? enqueue(c[0]) && propagate() == CRef_Undef : true; +} + + +// Returns FALSE if clause is always satisfied ('out_clause' should not be used). +bool SimpSolver::merge(const Clause& _ps, const Clause& _qs, Var v, vec& out_clause) +{ + merges++; + out_clause.clear(); + + bool ps_smallest = _ps.size() < _qs.size(); + const Clause& ps = ps_smallest ? _qs : _ps; + const Clause& qs = ps_smallest ? _ps : _qs; + + for (int i = 0; i < qs.size(); i++){ + if (var(qs[i]) != v){ + for (int j = 0; j < ps.size(); j++) + if (var(ps[j]) == var(qs[i])) + if (ps[j] == ~qs[i]) + return false; + else + goto next; + out_clause.push(qs[i]); + } + next:; + } + + for (int i = 0; i < ps.size(); i++) + if (var(ps[i]) != v) + out_clause.push(ps[i]); + + return true; +} + + +// Returns FALSE if clause is always satisfied. +bool SimpSolver::merge(const Clause& _ps, const Clause& _qs, Var v, int& size) +{ + merges++; + + bool ps_smallest = _ps.size() < _qs.size(); + const Clause& ps = ps_smallest ? _qs : _ps; + const Clause& qs = ps_smallest ? _ps : _qs; + const Lit* __ps = (const Lit*)ps; + const Lit* __qs = (const Lit*)qs; + + size = ps.size()-1; + + for (int i = 0; i < qs.size(); i++){ + if (var(__qs[i]) != v){ + for (int j = 0; j < ps.size(); j++) + if (var(__ps[j]) == var(__qs[i])) + if (__ps[j] == ~__qs[i]) + return false; + else + goto next; + size++; + } + next:; + } + + return true; +} + + +void SimpSolver::gatherTouchedClauses() +{ + if (n_touched == 0) return; + + int i,j; + for (i = j = 0; i < subsumption_queue.size(); i++) + if (ca[subsumption_queue[i]].mark() == 0) + ca[subsumption_queue[i]].mark(2); + + for (i = 0; i < touched.size(); i++) + if (touched[i]){ + const vec& cs = occurs.lookup(i); + for (j = 0; j < cs.size(); j++) + if (ca[cs[j]].mark() == 0){ + subsumption_queue.insert(cs[j]); + ca[cs[j]].mark(2); + } + touched[i] = 0; + } + + for (i = 0; i < subsumption_queue.size(); i++) + if (ca[subsumption_queue[i]].mark() == 2) + ca[subsumption_queue[i]].mark(0); + + n_touched = 0; +} + + +bool SimpSolver::implied(const vec& c) +{ + assert(decisionLevel() == 0); + + trail_lim.push(trail.size()); + for (int i = 0; i < c.size(); i++) + if (value(c[i]) == l_True){ + cancelUntil(0); + return true; + }else if (value(c[i]) != l_False){ + assert(value(c[i]) == l_Undef); + uncheckedEnqueue(~c[i]); + } + + bool result = propagate() != CRef_Undef; + cancelUntil(0); + return result; +} + + +// Backward subsumption + backward subsumption resolution +bool SimpSolver::backwardSubsumptionCheck(bool verbose) +{ + int cnt = 0; + int subsumed = 0; + int deleted_literals = 0; + assert(decisionLevel() == 0); + + while (subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()){ + + // Empty subsumption queue and return immediately on user-interrupt: + if (asynch_interrupt){ + subsumption_queue.clear(); + bwdsub_assigns = trail.size(); + break; } + + // Check top-level assignments by creating a dummy clause and placing it in the queue: + if (subsumption_queue.size() == 0 && bwdsub_assigns < trail.size()){ + Lit l = trail[bwdsub_assigns++]; + ca[bwdsub_tmpunit][0] = l; + ca[bwdsub_tmpunit].calcAbstraction(); + subsumption_queue.insert(bwdsub_tmpunit); } + + CRef cr = subsumption_queue.peek(); subsumption_queue.pop(); + Clause& c = ca[cr]; + + if (c.mark()) continue; + + if (verbose && verbosity >= 2 && cnt++ % 1000 == 0) + printf("c subsumption left: %10d (%10d subsumed, %10d deleted literals)\r", subsumption_queue.size(), subsumed, deleted_literals); + + assert(c.size() > 1 || value(c[0]) == l_True); // Unit-clauses should have been propagated before this point. + + // Find best variable to scan: + Var best = var(c[0]); + for (int i = 1; i < c.size(); i++) + if (occurs[var(c[i])].size() < occurs[best].size()) + best = var(c[i]); + + // Search all candidates: + vec& _cs = occurs.lookup(best); + CRef* cs = (CRef*)_cs; + + for (int j = 0; j < _cs.size(); j++) + if (c.mark()) + break; + else if (!ca[cs[j]].mark() && cs[j] != cr && (subsumption_lim == -1 || ca[cs[j]].size() < subsumption_lim)){ + Lit l = c.subsumes(ca[cs[j]]); + + if (l == lit_Undef) + subsumed++, removeClause(cs[j]); + else if (l != lit_Error){ + deleted_literals++; + + if (!strengthenClause(cs[j], ~l)) + return false; + + // Did current candidate get deleted from cs? Then check candidate at index j again: + if (var(l) == best) + j--; + } + } + } + + return true; +} + + +bool SimpSolver::asymm(Var v, CRef cr) +{ + Clause& c = ca[cr]; + assert(decisionLevel() == 0); + + if (c.mark() || satisfied(c)) return true; + + trail_lim.push(trail.size()); + Lit l = lit_Undef; + for (int i = 0; i < c.size(); i++) + if (var(c[i]) != v){ + if (value(c[i]) != l_False) + uncheckedEnqueue(~c[i]); + }else + l = c[i]; + + if (propagate() != CRef_Undef){ + cancelUntil(0); + asymm_lits++; + if (!strengthenClause(cr, l)) + return false; + }else + cancelUntil(0); + + return true; +} + + +bool SimpSolver::asymmVar(Var v) +{ + assert(use_simplification); + + const vec& cls = occurs.lookup(v); + + if (value(v) != l_Undef || cls.size() == 0) + return true; + + for (int i = 0; i < cls.size(); i++) + if (!asymm(v, cls[i])) + return false; + + return backwardSubsumptionCheck(); +} + + +static void mkElimClause(vec& elimclauses, Lit x) +{ + elimclauses.push(toInt(x)); + elimclauses.push(1); +} + + +static void mkElimClause(vec& elimclauses, Var v, Clause& c) +{ + int first = elimclauses.size(); + int v_pos = -1; + + // Copy clause to elimclauses-vector. Remember position where the + // variable 'v' occurs: + for (int i = 0; i < c.size(); i++){ + elimclauses.push(toInt(c[i])); + if (var(c[i]) == v) + v_pos = i + first; + } + assert(v_pos != -1); + + // Swap the first literal with the 'v' literal, so that the literal + // containing 'v' will occur first in the clause: + uint32_t tmp = elimclauses[v_pos]; + elimclauses[v_pos] = elimclauses[first]; + elimclauses[first] = tmp; + + // Store the length of the clause last: + elimclauses.push(c.size()); +} + + + +bool SimpSolver::eliminateVar(Var v) +{ + assert(!frozen[v]); + assert(!isEliminated(v)); + assert(value(v) == l_Undef); + + // Split the occurrences into positive and negative: + // + const vec& cls = occurs.lookup(v); + vec pos, neg; + for (int i = 0; i < cls.size(); i++) + (find(ca[cls[i]], mkLit(v)) ? pos : neg).push(cls[i]); + + // Check wether the increase in number of clauses stays within the allowed ('grow'). Moreover, no + // clause must exceed the limit on the maximal clause size (if it is set): + // + int cnt = 0; + int clause_size = 0; + + for (int i = 0; i < pos.size(); i++) + for (int j = 0; j < neg.size(); j++) + if (merge(ca[pos[i]], ca[neg[j]], v, clause_size) && + (++cnt > cls.size() + grow || (clause_lim != -1 && clause_size > clause_lim))) + return true; + + // Delete and store old clauses: + eliminated[v] = true; + setDecisionVar(v, false); + eliminated_vars++; + + if (pos.size() > neg.size()){ + for (int i = 0; i < neg.size(); i++) + mkElimClause(elimclauses, v, ca[neg[i]]); + mkElimClause(elimclauses, mkLit(v)); + }else{ + for (int i = 0; i < pos.size(); i++) + mkElimClause(elimclauses, v, ca[pos[i]]); + mkElimClause(elimclauses, ~mkLit(v)); + } + + // Produce clauses in cross product: + vec& resolvent = add_tmp; + for (int i = 0; i < pos.size(); i++) + for (int j = 0; j < neg.size(); j++) + if (merge(ca[pos[i]], ca[neg[j]], v, resolvent) && !addClause_(resolvent)) + return false; + + for (int i = 0; i < cls.size(); i++) + removeClause(cls[i]); + + // Free occurs list for this variable: + occurs[v].clear(true); + + // Free watchers lists for this variable, if possible: + watches_bin[ mkLit(v)].clear(true); + watches_bin[~mkLit(v)].clear(true); + watches[ mkLit(v)].clear(true); + watches[~mkLit(v)].clear(true); + + return backwardSubsumptionCheck(); +} + + +bool SimpSolver::substitute(Var v, Lit x) +{ + assert(!frozen[v]); + assert(!isEliminated(v)); + assert(value(v) == l_Undef); + + if (!ok) return false; + + eliminated[v] = true; + setDecisionVar(v, false); + const vec& cls = occurs.lookup(v); + + vec& subst_clause = add_tmp; + for (int i = 0; i < cls.size(); i++){ + Clause& c = ca[cls[i]]; + + subst_clause.clear(); + for (int j = 0; j < c.size(); j++){ + Lit p = c[j]; + subst_clause.push(var(p) == v ? x ^ sign(p) : p); + } + + if (!addClause_(subst_clause)) + return ok = false; + + removeClause(cls[i]); + } + + return true; +} + + +void SimpSolver::extendModel() +{ + int i, j; + Lit x; + + for (i = elimclauses.size()-1; i > 0; i -= j){ + for (j = elimclauses[i--]; j > 1; j--, i--) + if (modelValue(toLit(elimclauses[i])) != l_False) + goto next; + + x = toLit(elimclauses[i]); + model[var(x)] = lbool(!sign(x)); + next:; + } +} + +// Almost duplicate of Solver::removeSatisfied. Didn't want to make the base method 'virtual'. +void SimpSolver::removeSatisfied() +{ + int i, j; + for (i = j = 0; i < clauses.size(); i++){ + const Clause& c = ca[clauses[i]]; + if (c.mark() == 0) + if (satisfied(c)) + removeClause(clauses[i]); + else + clauses[j++] = clauses[i]; + } + clauses.shrink(i - j); +} + +// The technique and code are by the courtesy of the GlueMiniSat team. Thank you! +// It helps solving certain types of huge problems tremendously. +bool SimpSolver::eliminate(bool turn_off_elim) +{ + bool res = true; + int iter = 0; + int n_cls, n_cls_init, n_vars; + + if (nVars() == 0) goto cleanup; // User disabling preprocessing. + + // Get an initial number of clauses (more accurately). + if (trail.size() != 0) removeSatisfied(); + n_cls_init = nClauses(); + + res = eliminate_(); // The first, usual variable elimination of MiniSat. + if (!res) goto cleanup; + + n_cls = nClauses(); + n_vars = nFreeVars(); + + printf("c Reduced to %d vars, %d cls (grow=%d)\n", n_vars, n_cls, grow); + + if ((double)n_cls / n_vars >= 5 || n_vars < 10000){ + printf("c No iterative elimination performed. (vars=%d, c/v ratio=%.1f)\n", n_vars, (double)n_cls / n_vars); + goto cleanup; } + + grow = grow ? grow * 2 : 8; + for (; grow < 10000; grow *= 2){ + // Rebuild elimination variable heap. + for (int i = 0; i < clauses.size(); i++){ + const Clause& c = ca[clauses[i]]; + for (int j = 0; j < c.size(); j++) + if (!elim_heap.inHeap(var(c[j]))) + elim_heap.insert(var(c[j])); + else + elim_heap.update(var(c[j])); } + + int n_cls_last = nClauses(); + int n_vars_last = nFreeVars(); + + res = eliminate_(); + if (!res || n_vars_last == nFreeVars()) break; + iter++; + + int n_cls_now = nClauses(); + int n_vars_now = nFreeVars(); + + double cl_inc_rate = (double)n_cls_now / n_cls_last; + double var_dec_rate = (double)n_vars_last / n_vars_now; + + printf("c Reduced to %d vars, %d cls (grow=%d)\n", n_vars_now, n_cls_now, grow); + printf("c cl_inc_rate=%.3f, var_dec_rate=%.3f\n", cl_inc_rate, var_dec_rate); + + if (n_cls_now > n_cls_init || cl_inc_rate > var_dec_rate) break; + } + printf("c No. effective iterative eliminations: %d\n", iter); + +cleanup: + touched .clear(true); + occurs .clear(true); + n_occ .clear(true); + elim_heap.clear(true); + subsumption_queue.clear(true); + + use_simplification = false; + remove_satisfied = true; + ca.extra_clause_field = false; + + // Force full cleanup (this is safe and desirable since it only happens once): + rebuildOrderHeap(); + garbageCollect(); + + return res; +} + + +bool SimpSolver::eliminate_() +{ + if (!simplify()) + return false; + else if (!use_simplification) + return true; + + int trail_size_last = trail.size(); + + // Main simplification loop: + // + while (n_touched > 0 || bwdsub_assigns < trail.size() || elim_heap.size() > 0){ + + gatherTouchedClauses(); + // printf(" ## (time = %6.2f s) BWD-SUB: queue = %d, trail = %d\n", cpuTime(), subsumption_queue.size(), trail.size() - bwdsub_assigns); + if ((subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()) && + !backwardSubsumptionCheck(true)){ + ok = false; goto cleanup; } + + // Empty elim_heap and return immediately on user-interrupt: + if (asynch_interrupt){ + assert(bwdsub_assigns == trail.size()); + assert(subsumption_queue.size() == 0); + assert(n_touched == 0); + elim_heap.clear(); + goto cleanup; } + + // printf(" ## (time = %6.2f s) ELIM: vars = %d\n", cpuTime(), elim_heap.size()); + for (int cnt = 0; !elim_heap.empty(); cnt++){ + Var elim = elim_heap.removeMin(); + + if (asynch_interrupt) break; + + if (isEliminated(elim) || value(elim) != l_Undef) continue; + + if (verbosity >= 2 && cnt % 100 == 0) + printf("c elimination left: %10d\r", elim_heap.size()); + + if (use_asymm){ + // Temporarily freeze variable. Otherwise, it would immediately end up on the queue again: + bool was_frozen = frozen[elim]; + frozen[elim] = true; + if (!asymmVar(elim)){ + ok = false; goto cleanup; } + frozen[elim] = was_frozen; } + + // At this point, the variable may have been set by assymetric branching, so check it + // again. Also, don't eliminate frozen variables: + if (use_elim && value(elim) == l_Undef && !frozen[elim] && !eliminateVar(elim)){ + ok = false; goto cleanup; } + + checkGarbage(simp_garbage_frac); + } + + assert(subsumption_queue.size() == 0); + } + cleanup: + // To get an accurate number of clauses. + if (trail_size_last != trail.size()) + removeSatisfied(); + else{ + int i,j; + for (i = j = 0; i < clauses.size(); i++) + if (ca[clauses[i]].mark() == 0) + clauses[j++] = clauses[i]; + clauses.shrink(i - j); + } + checkGarbage(); + + if (verbosity >= 1 && elimclauses.size() > 0) + printf("c | Eliminated clauses: %10.2f Mb |\n", + double(elimclauses.size() * sizeof(uint32_t)) / (1024*1024)); + + return ok; +} + + +//================================================================================================= +// Garbage Collection methods: + + +void SimpSolver::relocAll(ClauseAllocator& to) +{ + if (!use_simplification) return; + + // All occurs lists: + // + occurs.cleanAll(); + for (int i = 0; i < nVars(); i++){ + vec& cs = occurs[i]; + for (int j = 0; j < cs.size(); j++) + ca.reloc(cs[j], to); + } + + // Subsumption queue: + // + for (int i = 0; i < subsumption_queue.size(); i++) + ca.reloc(subsumption_queue[i], to); + + // Temporary clause: + // + ca.reloc(bwdsub_tmpunit, to); +} + + +void SimpSolver::garbageCollect() +{ + // Initialize the next region to a size corresponding to the estimated utilization degree. This + // is not precise but should avoid some unnecessary reallocations for the new region: + ClauseAllocator to(ca.size() - ca.wasted()); + + to.extra_clause_field = ca.extra_clause_field; // NOTE: this is important to keep (or lose) the extra fields. + relocAll(to); + Solver::relocAll(to); + if (verbosity >= 2) + printf("c | Garbage collection: %12d bytes => %12d bytes |\n", + ca.size()*ClauseAllocator::Unit_Size, to.size()*ClauseAllocator::Unit_Size); + to.moveTo(ca); +} diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/simp/SimpSolver.h b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/simp/SimpSolver.h new file mode 100755 index 00000000..b4c6b803 --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/simp/SimpSolver.h @@ -0,0 +1,201 @@ +/************************************************************************************[SimpSolver.h] +MiniSat -- Copyright (c) 2006, Niklas Een, Niklas Sorensson + Copyright (c) 2007-2010, Niklas Sorensson + +Chanseok Oh's MiniSat Patch Series -- Copyright (c) 2015, Chanseok Oh + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +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 AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + +#ifndef Minisat_SimpSolver_h +#define Minisat_SimpSolver_h + +#include "mtl/Queue.h" +#include "core/Solver.h" + + +namespace Minisat { + +//================================================================================================= + + +class SimpSolver : public Solver { + public: + // Constructor/Destructor: + // + SimpSolver(); + ~SimpSolver(); + + // Problem specification: + // + Var newVar (bool polarity = true, bool dvar = true); + bool addClause (const vec& ps); + bool addEmptyClause(); // Add the empty clause to the solver. + bool addClause (Lit p); // Add a unit clause to the solver. + bool addClause (Lit p, Lit q); // Add a binary clause to the solver. + bool addClause (Lit p, Lit q, Lit r); // Add a ternary clause to the solver. + bool addClause_( vec& ps); + bool substitute(Var v, Lit x); // Replace all occurences of v with x (may cause a contradiction). + + // Variable mode: + // + void setFrozen (Var v, bool b); // If a variable is frozen it will not be eliminated. + bool isEliminated(Var v) const; + + // Solving: + // + bool solve (const vec& assumps, bool do_simp = true, bool turn_off_simp = false); + lbool solveLimited(const vec& assumps, bool do_simp = true, bool turn_off_simp = false); + bool solve ( bool do_simp = true, bool turn_off_simp = false); + bool solve (Lit p , bool do_simp = true, bool turn_off_simp = false); + bool solve (Lit p, Lit q, bool do_simp = true, bool turn_off_simp = false); + bool solve (Lit p, Lit q, Lit r, bool do_simp = true, bool turn_off_simp = false); + bool eliminate (bool turn_off_elim = false); // Perform variable elimination based simplification. + bool eliminate_ (); + void removeSatisfied(); + + // Memory managment: + // + virtual void garbageCollect(); + + + // Generate a (possibly simplified) DIMACS file: + // +#if 0 + void toDimacs (const char* file, const vec& assumps); + void toDimacs (const char* file); + void toDimacs (const char* file, Lit p); + void toDimacs (const char* file, Lit p, Lit q); + void toDimacs (const char* file, Lit p, Lit q, Lit r); +#endif + + // Mode of operation: + // + bool parsing; + int grow; // Allow a variable elimination step to grow by a number of clauses (default to zero). + int clause_lim; // Variables are not eliminated if it produces a resolvent with a length above this limit. + // -1 means no limit. + int subsumption_lim; // Do not check if subsumption against a clause larger than this. -1 means no limit. + double simp_garbage_frac; // A different limit for when to issue a GC during simplification (Also see 'garbage_frac'). + + bool use_asymm; // Shrink clauses by asymmetric branching. + bool use_rcheck; // Check if a clause is already implied. Prett costly, and subsumes subsumptions :) + bool use_elim; // Perform variable elimination. + + // Statistics: + // + int merges; + int asymm_lits; + int eliminated_vars; + + protected: + + // Helper structures: + // + struct ElimLt { + const vec& n_occ; + explicit ElimLt(const vec& no) : n_occ(no) {} + + // TODO: are 64-bit operations here noticably bad on 32-bit platforms? Could use a saturating + // 32-bit implementation instead then, but this will have to do for now. + uint64_t cost (Var x) const { return (uint64_t)n_occ[toInt(mkLit(x))] * (uint64_t)n_occ[toInt(~mkLit(x))]; } + bool operator()(Var x, Var y) const { return cost(x) < cost(y); } + + // TODO: investigate this order alternative more. + // bool operator()(Var x, Var y) const { + // int c_x = cost(x); + // int c_y = cost(y); + // return c_x < c_y || c_x == c_y && x < y; } + }; + + struct ClauseDeleted { + const ClauseAllocator& ca; + explicit ClauseDeleted(const ClauseAllocator& _ca) : ca(_ca) {} + bool operator()(const CRef& cr) const { return ca[cr].mark() == 1; } }; + + // Solver state: + // + int elimorder; + bool use_simplification; + vec elimclauses; + vec touched; + OccLists, ClauseDeleted> + occurs; + vec n_occ; + Heap elim_heap; + Queue subsumption_queue; + vec frozen; + vec eliminated; + int bwdsub_assigns; + int n_touched; + + // Temporaries: + // + CRef bwdsub_tmpunit; + + // Main internal methods: + // + lbool solve_ (bool do_simp = true, bool turn_off_simp = false); + bool asymm (Var v, CRef cr); + bool asymmVar (Var v); + void updateElimHeap (Var v); + void gatherTouchedClauses (); + bool merge (const Clause& _ps, const Clause& _qs, Var v, vec& out_clause); + bool merge (const Clause& _ps, const Clause& _qs, Var v, int& size); + bool backwardSubsumptionCheck (bool verbose = false); + bool eliminateVar (Var v); + void extendModel (); + + void removeClause (CRef cr); + bool strengthenClause (CRef cr, Lit l); + bool implied (const vec& c); + void relocAll (ClauseAllocator& to); +}; + + +//================================================================================================= +// Implementation of inline methods: + + +inline bool SimpSolver::isEliminated (Var v) const { return eliminated[v]; } +inline void SimpSolver::updateElimHeap(Var v) { + assert(use_simplification); + // if (!frozen[v] && !isEliminated(v) && value(v) == l_Undef) + if (elim_heap.inHeap(v) || (!frozen[v] && !isEliminated(v) && value(v) == l_Undef)) + elim_heap.update(v); } + + +inline bool SimpSolver::addClause (const vec& ps) { ps.copyTo(add_tmp); return addClause_(add_tmp); } +inline bool SimpSolver::addEmptyClause() { add_tmp.clear(); return addClause_(add_tmp); } +inline bool SimpSolver::addClause (Lit p) { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp); } +inline bool SimpSolver::addClause (Lit p, Lit q) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp); } +inline bool SimpSolver::addClause (Lit p, Lit q, Lit r) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp); } +inline void SimpSolver::setFrozen (Var v, bool b) { frozen[v] = (char)b; if (use_simplification && !b) { updateElimHeap(v); } } + +inline bool SimpSolver::solve ( bool do_simp, bool turn_off_simp) { budgetOff(); assumptions.clear(); return solve_(do_simp, turn_off_simp) == l_True; } +inline bool SimpSolver::solve (Lit p , bool do_simp, bool turn_off_simp) { budgetOff(); assumptions.clear(); assumptions.push(p); return solve_(do_simp, turn_off_simp) == l_True; } +inline bool SimpSolver::solve (Lit p, Lit q, bool do_simp, bool turn_off_simp) { budgetOff(); assumptions.clear(); assumptions.push(p); assumptions.push(q); return solve_(do_simp, turn_off_simp) == l_True; } +inline bool SimpSolver::solve (Lit p, Lit q, Lit r, bool do_simp, bool turn_off_simp) { budgetOff(); assumptions.clear(); assumptions.push(p); assumptions.push(q); assumptions.push(r); return solve_(do_simp, turn_off_simp) == l_True; } +inline bool SimpSolver::solve (const vec& assumps, bool do_simp, bool turn_off_simp){ + budgetOff(); assumps.copyTo(assumptions); return solve_(do_simp, turn_off_simp) == l_True; } + +inline lbool SimpSolver::solveLimited (const vec& assumps, bool do_simp, bool turn_off_simp){ + assumps.copyTo(assumptions); return solve_(do_simp, turn_off_simp); } + +//================================================================================================= +} + +#endif diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/utils/Makefile b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/utils/Makefile new file mode 100755 index 00000000..204cea54 --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/utils/Makefile @@ -0,0 +1,4 @@ +EXEC = system_test +DEPDIR = mtl + +include $(MROOT)/mtl/template.mk diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/utils/Options.cc b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/utils/Options.cc new file mode 100755 index 00000000..ec5a6e93 --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/utils/Options.cc @@ -0,0 +1,91 @@ +/**************************************************************************************[Options.cc] +Copyright (c) 2008-2010, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +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 AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + +#include "mtl/Sort.h" +#include "utils/Options.h" +#include "utils/ParseUtils.h" + +using namespace Minisat; + +void Minisat::parseOptions(int& argc, char** argv, bool strict) +{ + int i, j; + for (i = j = 1; i < argc; i++){ + const char* str = argv[i]; + if (match(str, "--") && match(str, Option::getHelpPrefixString()) && match(str, "help")){ + if (*str == '\0') + printUsageAndExit(argc, argv); + else if (match(str, "-verb")) + printUsageAndExit(argc, argv, true); + } else { + bool parsed_ok = false; + + for (int k = 0; !parsed_ok && k < Option::getOptionList().size(); k++){ + parsed_ok = Option::getOptionList()[k]->parse(argv[i]); + + // fprintf(stderr, "checking %d: %s against flag <%s> (%s)\n", i, argv[i], Option::getOptionList()[k]->name, parsed_ok ? "ok" : "skip"); + } + + if (!parsed_ok) + if (strict && match(argv[i], "-")) + fprintf(stderr, "ERROR! Unknown flag \"%s\". Use '--%shelp' for help.\n", argv[i], Option::getHelpPrefixString()), exit(1); + else + argv[j++] = argv[i]; + } + } + + argc -= (i - j); +} + + +void Minisat::setUsageHelp (const char* str){ Option::getUsageString() = str; } +void Minisat::setHelpPrefixStr (const char* str){ Option::getHelpPrefixString() = str; } +void Minisat::printUsageAndExit (int argc, char** argv, bool verbose) +{ + const char* usage = Option::getUsageString(); + if (usage != NULL) + fprintf(stderr, usage, argv[0]); + + sort(Option::getOptionList(), Option::OptionLt()); + + const char* prev_cat = NULL; + const char* prev_type = NULL; + + for (int i = 0; i < Option::getOptionList().size(); i++){ + const char* cat = Option::getOptionList()[i]->category; + const char* type = Option::getOptionList()[i]->type_name; + + if (cat != prev_cat) + fprintf(stderr, "\n%s OPTIONS:\n\n", cat); + else if (type != prev_type) + fprintf(stderr, "\n"); + + Option::getOptionList()[i]->help(verbose); + + prev_cat = Option::getOptionList()[i]->category; + prev_type = Option::getOptionList()[i]->type_name; + } + + fprintf(stderr, "\nHELP OPTIONS:\n\n"); + fprintf(stderr, " --%shelp Print help message.\n", Option::getHelpPrefixString()); + fprintf(stderr, " --%shelp-verb Print verbose help message.\n", Option::getHelpPrefixString()); + fprintf(stderr, "\n"); + exit(0); +} + diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/utils/Options.h b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/utils/Options.h new file mode 100755 index 00000000..87a58151 --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/utils/Options.h @@ -0,0 +1,386 @@ +/***************************************************************************************[Options.h] +Copyright (c) 2008-2010, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +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 AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + +#ifndef Minisat_Options_h +#define Minisat_Options_h + +#include +#include +#include +#include + +#include "mtl/IntTypes.h" +#include "mtl/Vec.h" +#include "utils/ParseUtils.h" + +namespace Minisat { + +//================================================================================================== +// Top-level option parse/help functions: + + +extern void parseOptions (int& argc, char** argv, bool strict = false); +extern void printUsageAndExit(int argc, char** argv, bool verbose = false); +extern void setUsageHelp (const char* str); +extern void setHelpPrefixStr (const char* str); + + +//================================================================================================== +// Options is an abstract class that gives the interface for all types options: + + +class Option +{ + protected: + const char* name; + const char* description; + const char* category; + const char* type_name; + + static vec& getOptionList () { static vec options; return options; } + static const char*& getUsageString() { static const char* usage_str; return usage_str; } + static const char*& getHelpPrefixString() { static const char* help_prefix_str = ""; return help_prefix_str; } + + struct OptionLt { + bool operator()(const Option* x, const Option* y) { + int test1 = strcmp(x->category, y->category); + return test1 < 0 || test1 == 0 && strcmp(x->type_name, y->type_name) < 0; + } + }; + + Option(const char* name_, + const char* desc_, + const char* cate_, + const char* type_) : + name (name_) + , description(desc_) + , category (cate_) + , type_name (type_) + { + getOptionList().push(this); + } + + public: + virtual ~Option() {} + + virtual bool parse (const char* str) = 0; + virtual void help (bool verbose = false) = 0; + + friend void parseOptions (int& argc, char** argv, bool strict); + friend void printUsageAndExit (int argc, char** argv, bool verbose); + friend void setUsageHelp (const char* str); + friend void setHelpPrefixStr (const char* str); +}; + + +//================================================================================================== +// Range classes with specialization for floating types: + + +struct IntRange { + int begin; + int end; + IntRange(int b, int e) : begin(b), end(e) {} +}; + +struct Int64Range { + int64_t begin; + int64_t end; + Int64Range(int64_t b, int64_t e) : begin(b), end(e) {} +}; + +struct DoubleRange { + double begin; + double end; + bool begin_inclusive; + bool end_inclusive; + DoubleRange(double b, bool binc, double e, bool einc) : begin(b), end(e), begin_inclusive(binc), end_inclusive(einc) {} +}; + + +//================================================================================================== +// Double options: + + +class DoubleOption : public Option +{ + protected: + DoubleRange range; + double value; + + public: + DoubleOption(const char* c, const char* n, const char* d, double def = double(), DoubleRange r = DoubleRange(-HUGE_VAL, false, HUGE_VAL, false)) + : Option(n, d, c, ""), range(r), value(def) { + // FIXME: set LC_NUMERIC to "C" to make sure that strtof/strtod parses decimal point correctly. + } + + operator double (void) const { return value; } + operator double& (void) { return value; } + DoubleOption& operator=(double x) { value = x; return *this; } + + virtual bool parse(const char* str){ + const char* span = str; + + if (!match(span, "-") || !match(span, name) || !match(span, "=")) + return false; + + char* end; + double tmp = strtod(span, &end); + + if (end == NULL) + return false; + else if (tmp >= range.end && (!range.end_inclusive || tmp != range.end)){ + fprintf(stderr, "ERROR! value <%s> is too large for option \"%s\".\n", span, name); + exit(1); + }else if (tmp <= range.begin && (!range.begin_inclusive || tmp != range.begin)){ + fprintf(stderr, "ERROR! value <%s> is too small for option \"%s\".\n", span, name); + exit(1); } + + value = tmp; + // fprintf(stderr, "READ VALUE: %g\n", value); + + return true; + } + + virtual void help (bool verbose = false){ + fprintf(stderr, " -%-12s = %-8s %c%4.2g .. %4.2g%c (default: %g)\n", + name, type_name, + range.begin_inclusive ? '[' : '(', + range.begin, + range.end, + range.end_inclusive ? ']' : ')', + value); + if (verbose){ + fprintf(stderr, "\n %s\n", description); + fprintf(stderr, "\n"); + } + } +}; + + +//================================================================================================== +// Int options: + + +class IntOption : public Option +{ + protected: + IntRange range; + int32_t value; + + public: + IntOption(const char* c, const char* n, const char* d, int32_t def = int32_t(), IntRange r = IntRange(INT32_MIN, INT32_MAX)) + : Option(n, d, c, ""), range(r), value(def) {} + + operator int32_t (void) const { return value; } + operator int32_t& (void) { return value; } + IntOption& operator= (int32_t x) { value = x; return *this; } + + virtual bool parse(const char* str){ + const char* span = str; + + if (!match(span, "-") || !match(span, name) || !match(span, "=")) + return false; + + char* end; + int32_t tmp = strtol(span, &end, 10); + + if (end == NULL) + return false; + else if (tmp > range.end){ + fprintf(stderr, "ERROR! value <%s> is too large for option \"%s\".\n", span, name); + exit(1); + }else if (tmp < range.begin){ + fprintf(stderr, "ERROR! value <%s> is too small for option \"%s\".\n", span, name); + exit(1); } + + value = tmp; + + return true; + } + + virtual void help (bool verbose = false){ + fprintf(stderr, " -%-12s = %-8s [", name, type_name); + if (range.begin == INT32_MIN) + fprintf(stderr, "imin"); + else + fprintf(stderr, "%4d", range.begin); + + fprintf(stderr, " .. "); + if (range.end == INT32_MAX) + fprintf(stderr, "imax"); + else + fprintf(stderr, "%4d", range.end); + + fprintf(stderr, "] (default: %d)\n", value); + if (verbose){ + fprintf(stderr, "\n %s\n", description); + fprintf(stderr, "\n"); + } + } +}; + + +// Leave this out for visual C++ until Microsoft implements C99 and gets support for strtoll. +#ifndef _MSC_VER + +class Int64Option : public Option +{ + protected: + Int64Range range; + int64_t value; + + public: + Int64Option(const char* c, const char* n, const char* d, int64_t def = int64_t(), Int64Range r = Int64Range(INT64_MIN, INT64_MAX)) + : Option(n, d, c, ""), range(r), value(def) {} + + operator int64_t (void) const { return value; } + operator int64_t& (void) { return value; } + Int64Option& operator= (int64_t x) { value = x; return *this; } + + virtual bool parse(const char* str){ + const char* span = str; + + if (!match(span, "-") || !match(span, name) || !match(span, "=")) + return false; + + char* end; + int64_t tmp = strtoll(span, &end, 10); + + if (end == NULL) + return false; + else if (tmp > range.end){ + fprintf(stderr, "ERROR! value <%s> is too large for option \"%s\".\n", span, name); + exit(1); + }else if (tmp < range.begin){ + fprintf(stderr, "ERROR! value <%s> is too small for option \"%s\".\n", span, name); + exit(1); } + + value = tmp; + + return true; + } + + virtual void help (bool verbose = false){ + fprintf(stderr, " -%-12s = %-8s [", name, type_name); + if (range.begin == INT64_MIN) + fprintf(stderr, "imin"); +// else +// fprintf(stderr, "%4"PRIi64, range.begin); + + fprintf(stderr, " .. "); + if (range.end == INT64_MAX) + fprintf(stderr, "imax"); +// else +// fprintf(stderr, "%4"PRIi64, range.end); + +// fprintf(stderr, "] (default: %"PRIi64")\n", value); + if (verbose){ + fprintf(stderr, "\n %s\n", description); + fprintf(stderr, "\n"); + } + } +}; +#endif + +//================================================================================================== +// String option: + + +class StringOption : public Option +{ + const char* value; + public: + StringOption(const char* c, const char* n, const char* d, const char* def = NULL) + : Option(n, d, c, ""), value(def) {} + + operator const char* (void) const { return value; } + operator const char*& (void) { return value; } + StringOption& operator= (const char* x) { value = x; return *this; } + + virtual bool parse(const char* str){ + const char* span = str; + + if (!match(span, "-") || !match(span, name) || !match(span, "=")) + return false; + + value = span; + return true; + } + + virtual void help (bool verbose = false){ + fprintf(stderr, " -%-10s = %8s\n", name, type_name); + if (verbose){ + fprintf(stderr, "\n %s\n", description); + fprintf(stderr, "\n"); + } + } +}; + + +//================================================================================================== +// Bool option: + + +class BoolOption : public Option +{ + bool value; + + public: + BoolOption(const char* c, const char* n, const char* d, bool v) + : Option(n, d, c, ""), value(v) {} + + operator bool (void) const { return value; } + operator bool& (void) { return value; } + BoolOption& operator=(bool b) { value = b; return *this; } + + virtual bool parse(const char* str){ + const char* span = str; + + if (match(span, "-")){ + bool b = !match(span, "no-"); + + if (strcmp(span, name) == 0){ + value = b; + return true; } + } + + return false; + } + + virtual void help (bool verbose = false){ + + fprintf(stderr, " -%s, -no-%s", name, name); + + for (uint32_t i = 0; i < 32 - strlen(name)*2; i++) + fprintf(stderr, " "); + + fprintf(stderr, " "); + fprintf(stderr, "(default: %s)\n", value ? "on" : "off"); + if (verbose){ + fprintf(stderr, "\n %s\n", description); + fprintf(stderr, "\n"); + } + } +}; + +//================================================================================================= +} + +#endif diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/utils/ParseUtils.h b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/utils/ParseUtils.h new file mode 100755 index 00000000..d3071649 --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/utils/ParseUtils.h @@ -0,0 +1,122 @@ +/************************************************************************************[ParseUtils.h] +Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +Copyright (c) 2007-2010, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +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 AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + +#ifndef Minisat_ParseUtils_h +#define Minisat_ParseUtils_h + +#include +#include + +#include + +namespace Minisat { + +//------------------------------------------------------------------------------------------------- +// A simple buffered character stream class: + +static const int buffer_size = 1048576; + + +class StreamBuffer { + gzFile in; + unsigned char buf[buffer_size]; + int pos; + int size; + + void assureLookahead() { + if (pos >= size) { + pos = 0; + size = gzread(in, buf, sizeof(buf)); } } + +public: + explicit StreamBuffer(gzFile i) : in(i), pos(0), size(0) { assureLookahead(); } + + int operator * () const { return (pos >= size) ? EOF : buf[pos]; } + void operator ++ () { pos++; assureLookahead(); } + int position () const { return pos; } +}; + + +//------------------------------------------------------------------------------------------------- +// End-of-file detection functions for StreamBuffer and char*: + + +static inline bool isEof(StreamBuffer& in) { return *in == EOF; } +static inline bool isEof(const char* in) { return *in == '\0'; } + +//------------------------------------------------------------------------------------------------- +// Generic parse functions parametrized over the input-stream type. + + +template +static void skipWhitespace(B& in) { + while ((*in >= 9 && *in <= 13) || *in == 32) + ++in; } + + +template +static void skipLine(B& in) { + for (;;){ + if (isEof(in)) return; + if (*in == '\n') { ++in; return; } + ++in; } } + + +template +static int parseInt(B& in) { + int val = 0; + bool neg = false; + skipWhitespace(in); + if (*in == '-') neg = true, ++in; + else if (*in == '+') ++in; + if (*in < '0' || *in > '9') fprintf(stderr, "PARSE ERROR! Unexpected char: %c\n", *in), exit(3); + while (*in >= '0' && *in <= '9') + val = val*10 + (*in - '0'), + ++in; + return neg ? -val : val; } + + +// String matching: in case of a match the input iterator will be advanced the corresponding +// number of characters. +template +static bool match(B& in, const char* str) { + int i; + for (i = 0; str[i] != '\0'; i++) + if (in[i] != str[i]) + return false; + + in += i; + + return true; +} + +// String matching: consumes characters eagerly, but does not require random access iterator. +template +static bool eagerMatch(B& in, const char* str) { + for (; *str != '\0'; ++str, ++in) + if (*str != *in) + return false; + return true; } + + +//================================================================================================= +} + +#endif diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/utils/System.cc b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/utils/System.cc new file mode 100755 index 00000000..85611bab --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/utils/System.cc @@ -0,0 +1,92 @@ +/***************************************************************************************[System.cc] +Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +Copyright (c) 2007-2010, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +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 AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + +#include "utils/System.h" + +#if defined(__linux__) + +#include +#include + +using namespace Minisat; + +// TODO: split the memory reading functions into two: one for reading high-watermark of RSS, and +// one for reading the current virtual memory size. + +static inline int memReadStat(int field) +{ + char name[256]; + pid_t pid = getpid(); + int value; + + sprintf(name, "/proc/%d/statm", pid); + FILE* in = fopen(name, "rb"); + if (in == NULL) return 0; + + for (; field >= 0; field--) + if (fscanf(in, "%d", &value) != 1) + printf("ERROR! Failed to parse memory statistics from \"/proc\".\n"), exit(1); + fclose(in); + return value; +} + + +static inline int memReadPeak(void) +{ + char name[256]; + pid_t pid = getpid(); + + sprintf(name, "/proc/%d/status", pid); + FILE* in = fopen(name, "rb"); + if (in == NULL) return 0; + + // Find the correct line, beginning with "VmPeak:": + int peak_kb = 0; + while (!feof(in) && fscanf(in, "VmPeak: %d kB", &peak_kb) != 1) + while (!feof(in) && fgetc(in) != '\n') + ; + fclose(in); + + return peak_kb; +} + +double Minisat::memUsed() { return (double)memReadStat(0) * (double)getpagesize() / (1024*1024); } + +#elif defined(__FreeBSD__) + +double Minisat::memUsed(void) { + struct rusage ru; + getrusage(RUSAGE_SELF, &ru); + return (double)ru.ru_maxrss / 1024; } +double MiniSat::memUsedPeak(void) { return memUsed(); } + + +#elif defined(__APPLE__) +#include + +double Minisat::memUsed(void) { + malloc_statistics_t t; + malloc_zone_statistics(NULL, &t); + return (double)t.max_size_in_use / (1024*1024); } + +#else +double Minisat::memUsed() { + return 0; } +#endif diff --git a/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/utils/System.h b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/utils/System.h new file mode 100755 index 00000000..fb2fe939 --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/MapleCOMSPS_LRB/utils/System.h @@ -0,0 +1,60 @@ +/****************************************************************************************[System.h] +Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +Copyright (c) 2007-2010, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +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 AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + +#ifndef Minisat_System_h +#define Minisat_System_h + +#if defined(__linux__) +#include +#endif + +#include "mtl/IntTypes.h" + +//------------------------------------------------------------------------------------------------- + +namespace Minisat { + +static inline double cpuTime(void); // CPU-time in seconds. +extern double memUsed(); // Memory in mega bytes (returns 0 for unsupported architectures). +//extern double memUsedPeak(); // Peak-memory in mega bytes (returns 0 for unsupported architectures). + +} + +//------------------------------------------------------------------------------------------------- +// Implementation of inline functions: + +#if defined(_MSC_VER) || defined(__MINGW32__) +#include + +static inline double Minisat::cpuTime(void) { return (double)clock() / CLOCKS_PER_SEC; } + +#else +#include +#include +#include + +static inline double Minisat::cpuTime(void) { + struct rusage ru; + getrusage(RUSAGE_SELF, &ru); + return (double)ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec / 1000000; } + +#endif + +#endif diff --git a/thirdparty/QuadriFlow/3rd/lemon-1.3.1/.hg_archival.txt b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/.hg_archival.txt new file mode 100755 index 00000000..f834209f --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/.hg_archival.txt @@ -0,0 +1,5 @@ +repo: 6ed5fe0ea387ba9808e21048f02c665b16aa8c23 +node: bdabbf66b2ad131199059736178664f44c69adaf +branch: 1.3 +latesttag: r1.3 +latesttagdistance: 11 diff --git a/thirdparty/QuadriFlow/3rd/lemon-1.3.1/.hgignore b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/.hgignore new file mode 100755 index 00000000..73230edf --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/.hgignore @@ -0,0 +1,53 @@ +syntax: glob +*.obj +*.orig +*.rej +*~ +*.o +*.log +*.lo +*.tar.* +*.bak +Makefile.in +aclocal.m4 +config.h.in +configure +Makefile +config.h +config.log +config.status +libtool +stamp-h1 +lemon/lemon.pc +lemon/libemon.la +lemon/stamp-h2 +doc/Doxyfile +doc/references.dox +cmake/version.cmake +.dirstamp +.libs/* +.deps/* +demo/*.eps +m4/libtool.m4 +m4/ltoptions.m4 +m4/ltsugar.m4 +m4/ltversion.m4 +m4/lt~obsolete.m4 + +syntax: regexp +(.*/)?\#[^/]*\#$ +(.*/)?\.\#[^/]*$ +^doc/html/.* +^doc/.*\.tag +^autom4te.cache/.* +^build-aux/.* +^.*objs.*/.* +^test/[a-z_]*$ +^tools/[a-z-_]*$ +^demo/.*_demo$ +^.*build.*/.* +^doc/gen-images/.* +CMakeFiles +DartTestfile.txt +cmake_install.cmake +CMakeCache.txt diff --git a/thirdparty/QuadriFlow/3rd/lemon-1.3.1/.hgtags b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/.hgtags new file mode 100755 index 00000000..b5eb130d --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/.hgtags @@ -0,0 +1 @@ +57ab090b6109902536ee34b1e8d4d123474311e3 r1.3 diff --git a/thirdparty/QuadriFlow/3rd/lemon-1.3.1/AUTHORS b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/AUTHORS new file mode 100755 index 00000000..4019ca62 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/CMakeLists.txt b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/CMakeLists.txt new file mode 100755 index 00000000..7aa6d430 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/INSTALL b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/INSTALL new file mode 100755 index 00000000..3fba5b26 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/LICENSE b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/LICENSE new file mode 100755 index 00000000..5b1c4255 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/NEWS b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/NEWS new file mode 100755 index 00000000..7908ca3a --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/README b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/README new file mode 100755 index 00000000..52a768c3 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/FindCOIN.cmake b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/FindCOIN.cmake new file mode 100755 index 00000000..d4ed735d --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/FindGLPK.cmake b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/FindGLPK.cmake new file mode 100755 index 00000000..55e5e3ee --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/FindGhostscript.cmake b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/FindGhostscript.cmake new file mode 100755 index 00000000..3366a000 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/FindILOG.cmake b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/FindILOG.cmake new file mode 100755 index 00000000..a09fc9a2 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/FindSOPLEX.cmake b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/FindSOPLEX.cmake new file mode 100755 index 00000000..d27cff0f --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/LEMONConfig.cmake.in b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/LEMONConfig.cmake.in new file mode 100755 index 00000000..b0d2d8b4 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/nsis/lemon.ico b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/nsis/lemon.ico new file mode 100755 index 0000000000000000000000000000000000000000..bbfd8c143d940ed7afbafee3c8fe0aec27bd546b GIT binary patch literal 22486 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
  • O{~HE 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 literal 0 HcmV?d00001 diff --git a/thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/nsis/uninstall.ico b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/nsis/uninstall.ico new file mode 100755 index 0000000000000000000000000000000000000000..7495f7c3c270c2a2ff3bd0fb9d42c1aea67c3c41 GIT binary patch literal 15086 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 Pc&R5s8E;BxqoecR;Ig0- literal 0 HcmV?d00001 diff --git a/thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/version.cmake b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/version.cmake new file mode 100755 index 00000000..91369e1c --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/version.cmake.in b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/cmake/version.cmake.in new file mode 100755 index 00000000..7cd4b689 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/contrib/CMakeLists.txt b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/contrib/CMakeLists.txt new file mode 100755 index 00000000..b6c11e2a --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/demo/CMakeLists.txt b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/demo/CMakeLists.txt new file mode 100755 index 00000000..e0566f40 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/demo/arg_parser_demo.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/demo/arg_parser_demo.cc new file mode 100755 index 00000000..1bafac0c --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/CMakeLists.txt b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/CMakeLists.txt new file mode 100755 index 00000000..4e6567e4 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/adaptors.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/adaptors.h new file mode 100755 index 00000000..1a40f8ea --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/arg_parser.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/arg_parser.cc new file mode 100755 index 00000000..35a73d9f --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/arg_parser.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/arg_parser.h new file mode 100755 index 00000000..3fbe75c9 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/assert.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/assert.h new file mode 100755 index 00000000..f6c1dfc8 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/base.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/base.cc new file mode 100755 index 00000000..a057b41c --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bellman_ford.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bellman_ford.h new file mode 100755 index 00000000..310758eb --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bfs.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bfs.h new file mode 100755 index 00000000..e5f4e5c5 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bin_heap.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bin_heap.h new file mode 100755 index 00000000..02c66582 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/binomial_heap.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/binomial_heap.h new file mode 100755 index 00000000..5bc13787 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/alteration_notifier.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/alteration_notifier.h new file mode 100755 index 00000000..d14fe363 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/array_map.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/array_map.h new file mode 100755 index 00000000..355ee008 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/bezier.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/bezier.h new file mode 100755 index 00000000..9d8d1413 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/default_map.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/default_map.h new file mode 100755 index 00000000..23728e42 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/edge_set_extender.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/edge_set_extender.h new file mode 100755 index 00000000..364ca2ee --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/enable_if.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/enable_if.h new file mode 100755 index 00000000..f0d8de4d --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/graph_adaptor_extender.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/graph_adaptor_extender.h new file mode 100755 index 00000000..c38c8e1d --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/graph_extender.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/graph_extender.h new file mode 100755 index 00000000..755a8907 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/lock.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/lock.h new file mode 100755 index 00000000..09069998 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/map_extender.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/map_extender.h new file mode 100755 index 00000000..f32403e6 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/path_dump.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/path_dump.h new file mode 100755 index 00000000..3e8cb8dd --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/solver_bits.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/solver_bits.h new file mode 100755 index 00000000..c34212be --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/traits.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/traits.h new file mode 100755 index 00000000..53fbd456 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/variant.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/variant.h new file mode 100755 index 00000000..b8301892 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/vector_map.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/vector_map.h new file mode 100755 index 00000000..d60841de --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/windows.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/windows.cc new file mode 100755 index 00000000..7ad901c6 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/windows.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/windows.h new file mode 100755 index 00000000..c09bb128 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bucket_heap.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bucket_heap.h new file mode 100755 index 00000000..92dbc08f --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/capacity_scaling.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/capacity_scaling.h new file mode 100755 index 00000000..ca64b56d --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/cbc.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/cbc.cc new file mode 100755 index 00000000..62331b1e --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/cbc.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/cbc.h new file mode 100755 index 00000000..968e504a --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/christofides_tsp.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/christofides_tsp.h new file mode 100755 index 00000000..2997567a --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/circulation.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/circulation.h new file mode 100755 index 00000000..b0f717b2 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/clp.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/clp.cc new file mode 100755 index 00000000..7c0ea74f --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/clp.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/clp.h new file mode 100755 index 00000000..fd331ac1 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/color.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/color.cc new file mode 100755 index 00000000..a49167b5 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/color.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/color.h new file mode 100755 index 00000000..02357910 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/concept_check.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/concept_check.h new file mode 100755 index 00000000..38355b0f --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/concepts/bpgraph.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/concepts/bpgraph.h new file mode 100755 index 00000000..2ebdeaf8 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/concepts/digraph.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/concepts/digraph.h new file mode 100755 index 00000000..dc3c36bb --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/concepts/graph.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/concepts/graph.h new file mode 100755 index 00000000..76e43da0 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/concepts/graph_components.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/concepts/graph_components.h new file mode 100755 index 00000000..9df28f37 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/concepts/heap.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/concepts/heap.h new file mode 100755 index 00000000..8c7a2512 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/concepts/maps.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/concepts/maps.h new file mode 100755 index 00000000..88b66b51 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/concepts/path.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/concepts/path.h new file mode 100755 index 00000000..18e4b018 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/config.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/config.h new file mode 100644 index 00000000..876598bc --- /dev/null +++ b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/config.h @@ -0,0 +1,22 @@ +#define LEMON_VERSION "1.3.1" +#define 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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/config.h.in b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/config.h.in new file mode 100755 index 00000000..37d8c04d --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/connectivity.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/connectivity.h new file mode 100755 index 00000000..6bd85a18 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/core.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/core.h new file mode 100755 index 00000000..507943db --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/cost_scaling.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/cost_scaling.h new file mode 100755 index 00000000..efecdfe7 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/counter.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/counter.h new file mode 100755 index 00000000..a0049918 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/cplex.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/cplex.cc new file mode 100755 index 00000000..029a3efc --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/cplex.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/cplex.h new file mode 100755 index 00000000..c17e7926 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/cycle_canceling.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/cycle_canceling.h new file mode 100755 index 00000000..646d299e --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/dfs.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/dfs.h new file mode 100755 index 00000000..6e9e84a4 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/dheap.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/dheap.h new file mode 100755 index 00000000..a3ab6252 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/dijkstra.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/dijkstra.h new file mode 100755 index 00000000..1564a03e --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/dim2.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/dim2.h new file mode 100755 index 00000000..0b142210 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/dimacs.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/dimacs.h new file mode 100755 index 00000000..616879ff --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/edge_set.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/edge_set.h new file mode 100755 index 00000000..399b7a26 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/edmonds_karp.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/edmonds_karp.h new file mode 100755 index 00000000..92af3cba --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/elevator.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/elevator.h new file mode 100755 index 00000000..e4adcd59 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/error.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/error.h new file mode 100755 index 00000000..f9377045 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/euler.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/euler.h new file mode 100755 index 00000000..3a3cbd06 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/fib_heap.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/fib_heap.h new file mode 100755 index 00000000..3441722a --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/fractional_matching.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/fractional_matching.h new file mode 100755 index 00000000..7448f411 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/full_graph.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/full_graph.h new file mode 100755 index 00000000..b63df2e0 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/glpk.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/glpk.cc new file mode 100755 index 00000000..38d81151 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/glpk.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/glpk.h new file mode 100755 index 00000000..ccdc54ac --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/gomory_hu.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/gomory_hu.h new file mode 100755 index 00000000..c43305f8 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/graph_to_eps.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/graph_to_eps.h new file mode 100755 index 00000000..29ba8369 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/greedy_tsp.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/greedy_tsp.h new file mode 100755 index 00000000..95461717 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/grid_graph.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/grid_graph.h new file mode 100755 index 00000000..a3dff0f6 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/grosso_locatelli_pullan_mc.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/grosso_locatelli_pullan_mc.h new file mode 100755 index 00000000..669e1fa3 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/hao_orlin.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/hao_orlin.h new file mode 100755 index 00000000..0eeaff95 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/hartmann_orlin_mmc.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/hartmann_orlin_mmc.h new file mode 100755 index 00000000..6b60a85e --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/howard_mmc.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/howard_mmc.h new file mode 100755 index 00000000..69023634 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/hypercube_graph.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/hypercube_graph.h new file mode 100755 index 00000000..2cf37ad4 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/insertion_tsp.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/insertion_tsp.h new file mode 100755 index 00000000..fa16825d --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/karp_mmc.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/karp_mmc.h new file mode 100755 index 00000000..1f05d436 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/kruskal.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/kruskal.h new file mode 100755 index 00000000..04c2ddb9 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/lemon.pc.in b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/lemon.pc.in new file mode 100755 index 00000000..e85bf765 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/lgf_reader.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/lgf_reader.h new file mode 100755 index 00000000..2f49fa25 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/lgf_writer.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/lgf_writer.h new file mode 100755 index 00000000..0695287d --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/list_graph.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/list_graph.h new file mode 100755 index 00000000..2a236cf9 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/lp.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/lp.h new file mode 100755 index 00000000..567763f0 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/lp_base.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/lp_base.cc new file mode 100755 index 00000000..312fd631 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/lp_base.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/lp_base.h new file mode 100755 index 00000000..22d3e489 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/lp_skeleton.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/lp_skeleton.cc new file mode 100755 index 00000000..fc1c143f --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/lp_skeleton.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/lp_skeleton.h new file mode 100755 index 00000000..27285a49 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/maps.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/maps.h new file mode 100755 index 00000000..1bc49e91 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/matching.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/matching.h new file mode 100755 index 00000000..5ee23412 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/math.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/math.h new file mode 100755 index 00000000..5da50b07 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/max_cardinality_search.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/max_cardinality_search.h new file mode 100755 index 00000000..bfa9edb7 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/min_cost_arborescence.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/min_cost_arborescence.h new file mode 100755 index 00000000..1d0a2b19 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/nagamochi_ibaraki.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/nagamochi_ibaraki.h new file mode 100755 index 00000000..57a6ba64 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/nauty_reader.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/nauty_reader.h new file mode 100755 index 00000000..896f2a60 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/nearest_neighbor_tsp.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/nearest_neighbor_tsp.h new file mode 100755 index 00000000..065e145d --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/network_simplex.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/network_simplex.h new file mode 100755 index 00000000..6ccad33e --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/opt2_tsp.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/opt2_tsp.h new file mode 100755 index 00000000..686cc9cb --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/pairing_heap.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/pairing_heap.h new file mode 100755 index 00000000..da6ebcb1 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/path.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/path.h new file mode 100755 index 00000000..baa92c48 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/planarity.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/planarity.h new file mode 100755 index 00000000..bfe8e85d --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/preflow.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/preflow.h new file mode 100755 index 00000000..28ccd67d --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/quad_heap.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/quad_heap.h new file mode 100755 index 00000000..27c50fd3 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/radix_heap.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/radix_heap.h new file mode 100755 index 00000000..8701ce74 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/radix_sort.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/radix_sort.h new file mode 100755 index 00000000..d8087566 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/random.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/random.cc new file mode 100755 index 00000000..02951210 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/random.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/random.h new file mode 100755 index 00000000..8de74ede --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/smart_graph.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/smart_graph.h new file mode 100755 index 00000000..bdbe369a --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/soplex.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/soplex.cc new file mode 100755 index 00000000..d7517231 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/soplex.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/soplex.h new file mode 100755 index 00000000..be73f3ab --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/static_graph.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/static_graph.h new file mode 100755 index 00000000..1f04e408 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/suurballe.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/suurballe.h new file mode 100755 index 00000000..f1338a29 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/time_measure.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/time_measure.h new file mode 100755 index 00000000..3f7f0778 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/unionfind.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/unionfind.h new file mode 100755 index 00000000..3d96b372 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/scripts/unify-sources.sh b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/scripts/unify-sources.sh new file mode 100755 index 00000000..6aae63ab --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/scripts/valgrind-wrapper.sh b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/scripts/valgrind-wrapper.sh new file mode 100755 index 00000000..bbb12229 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/CMakeLists.txt b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/CMakeLists.txt new file mode 100755 index 00000000..96fc5dd4 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/adaptors_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/adaptors_test.cc new file mode 100755 index 00000000..9077db96 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/arc_look_up_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/arc_look_up_test.cc new file mode 100755 index 00000000..2f4edf52 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/bellman_ford_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/bellman_ford_test.cc new file mode 100755 index 00000000..14faa07c --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/bfs_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/bfs_test.cc new file mode 100755 index 00000000..976fa88b --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/bpgraph_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/bpgraph_test.cc new file mode 100755 index 00000000..45fc5b85 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/circulation_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/circulation_test.cc new file mode 100755 index 00000000..3b3a4a97 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/connectivity_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/connectivity_test.cc new file mode 100755 index 00000000..4ab343ee --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/counter_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/counter_test.cc new file mode 100755 index 00000000..df31dd4d --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/dfs_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/dfs_test.cc new file mode 100755 index 00000000..ef5049a0 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/digraph_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/digraph_test.cc new file mode 100755 index 00000000..e3ff5457 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/dijkstra_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/dijkstra_test.cc new file mode 100755 index 00000000..20cc76b3 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/dim_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/dim_test.cc new file mode 100755 index 00000000..0b2b9250 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/edge_set_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/edge_set_test.cc new file mode 100755 index 00000000..dbe74a9f --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/error_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/error_test.cc new file mode 100755 index 00000000..15275198 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/euler_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/euler_test.cc new file mode 100755 index 00000000..11a39e47 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/fractional_matching_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/fractional_matching_test.cc new file mode 100755 index 00000000..bee866c0 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/gomory_hu_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/gomory_hu_test.cc new file mode 100755 index 00000000..178f21fe --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/graph_copy_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/graph_copy_test.cc new file mode 100755 index 00000000..9a7d8155 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/graph_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/graph_test.cc new file mode 100755 index 00000000..283b02ef --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/graph_test.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/graph_test.h new file mode 100755 index 00000000..70558b76 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/graph_utils_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/graph_utils_test.cc new file mode 100755 index 00000000..19a934a2 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/hao_orlin_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/hao_orlin_test.cc new file mode 100755 index 00000000..c245cb7a --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/heap_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/heap_test.cc new file mode 100755 index 00000000..38e15771 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/kruskal_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/kruskal_test.cc new file mode 100755 index 00000000..af36c72f --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/lgf_reader_writer_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/lgf_reader_writer_test.cc new file mode 100755 index 00000000..25d9423a --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/lgf_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/lgf_test.cc new file mode 100755 index 00000000..839afb15 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/lp_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/lp_test.cc new file mode 100755 index 00000000..914a3764 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/maps_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/maps_test.cc new file mode 100755 index 00000000..5502e046 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/matching_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/matching_test.cc new file mode 100755 index 00000000..dcb1d3b5 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/max_cardinality_search_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/max_cardinality_search_test.cc new file mode 100755 index 00000000..c01066f3 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/max_clique_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/max_clique_test.cc new file mode 100755 index 00000000..d16f0f99 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/max_flow_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/max_flow_test.cc new file mode 100755 index 00000000..f63874a6 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/min_cost_arborescence_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/min_cost_arborescence_test.cc new file mode 100755 index 00000000..3a5ea36f --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/min_cost_flow_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/min_cost_flow_test.cc new file mode 100755 index 00000000..15dcf542 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/min_mean_cycle_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/min_mean_cycle_test.cc new file mode 100755 index 00000000..e7524546 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/mip_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/mip_test.cc new file mode 100755 index 00000000..641ceb5f --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/nagamochi_ibaraki_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/nagamochi_ibaraki_test.cc new file mode 100755 index 00000000..94ec29d9 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/path_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/path_test.cc new file mode 100755 index 00000000..f2d96038 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/planarity_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/planarity_test.cc new file mode 100755 index 00000000..0ac11eeb --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/radix_sort_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/radix_sort_test.cc new file mode 100755 index 00000000..6ae2debf --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/random_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/random_test.cc new file mode 100755 index 00000000..49dd8b60 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/suurballe_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/suurballe_test.cc new file mode 100755 index 00000000..7c00f212 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/test_tools.h b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/test_tools.h new file mode 100755 index 00000000..33003566 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/test_tools_fail.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/test_tools_fail.cc new file mode 100755 index 00000000..6407cd15 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/test_tools_pass.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/test_tools_pass.cc new file mode 100755 index 00000000..b590c15a --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/time_measure_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/time_measure_test.cc new file mode 100755 index 00000000..4e7155a9 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/tsp_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/tsp_test.cc new file mode 100755 index 00000000..398a812e --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/unionfind_test.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/test/unionfind_test.cc new file mode 100755 index 00000000..e82d8e64 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/tools/CMakeLists.txt b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/tools/CMakeLists.txt new file mode 100755 index 00000000..64b7df77 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/tools/dimacs-solver.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/tools/dimacs-solver.cc new file mode 100755 index 00000000..60da2330 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/tools/dimacs-to-lgf.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/tools/dimacs-to-lgf.cc new file mode 100755 index 00000000..3968645d --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/tools/lemon-0.x-to-1.x.sh b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/tools/lemon-0.x-to-1.x.sh new file mode 100755 index 00000000..1dac1be6 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/lemon-1.3.1/tools/lgf-gen.cc b/thirdparty/QuadriFlow/3rd/lemon-1.3.1/tools/lgf-gen.cc new file mode 100755 index 00000000..390c8ae5 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/pcg32/pcg32/pcg32.h b/thirdparty/QuadriFlow/3rd/pcg32/pcg32/pcg32.h new file mode 100755 index 00000000..aa06f28a --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/pss/pss/parallel_stable_sort.h b/thirdparty/QuadriFlow/3rd/pss/pss/parallel_stable_sort.h new file mode 100755 index 00000000..3d8854f9 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/3rd/pss/pss/pss_common.h b/thirdparty/QuadriFlow/3rd/pss/pss/pss_common.h new file mode 100755 index 00000000..628c0f98 --- /dev/null +++ b/thirdparty/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 because 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 preserve 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/thirdparty/QuadriFlow/cmake/FindEigen.cmake b/thirdparty/QuadriFlow/cmake/FindEigen.cmake new file mode 100755 index 00000000..f6d26641 --- /dev/null +++ b/thirdparty/QuadriFlow/cmake/FindEigen.cmake @@ -0,0 +1,263 @@ +# Ceres Solver - A fast non-linear least squares minimizer +# Copyright 2015 Google Inc. All rights reserved. +# http://ceres-solver.org/ +# +# 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 Google Inc. 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 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. +# +# Author: alexs.mac@gmail.com (Alex Stewart) +# + +# FindEigen.cmake - Find Eigen library, version >= 3. +# +# This module defines the following variables: +# +# EIGEN_FOUND: TRUE iff Eigen is found. +# EIGEN_INCLUDE_DIRS: Include directories for Eigen. +# EIGEN_VERSION: Extracted from Eigen/src/Core/util/Macros.h +# EIGEN_WORLD_VERSION: Equal to 3 if EIGEN_VERSION = 3.2.0 +# EIGEN_MAJOR_VERSION: Equal to 2 if EIGEN_VERSION = 3.2.0 +# EIGEN_MINOR_VERSION: Equal to 0 if EIGEN_VERSION = 3.2.0 +# FOUND_INSTALLED_EIGEN_CMAKE_CONFIGURATION: True iff the version of Eigen +# found was built & installed / +# exported as a CMake package. +# +# The following variables control the behaviour of this module: +# +# EIGEN_PREFER_EXPORTED_EIGEN_CMAKE_CONFIGURATION: TRUE/FALSE, iff TRUE then +# then prefer using an exported CMake configuration +# generated by Eigen over searching for the +# Eigen components manually. Otherwise (FALSE) +# ignore any exported Eigen CMake configurations and +# always perform a manual search for the components. +# Default: TRUE iff user does not define this variable +# before we are called, and does NOT specify +# EIGEN_INCLUDE_DIR_HINTS, otherwise FALSE. +# EIGEN_INCLUDE_DIR_HINTS: List of additional directories in which to +# search for eigen includes, e.g: /timbuktu/eigen3. +# +# The following variables are also defined by this module, but in line with +# CMake recommended FindPackage() module style should NOT be referenced directly +# by callers (use the plural variables detailed above instead). These variables +# do however affect the behaviour of the module via FIND_[PATH/LIBRARY]() which +# are NOT re-called (i.e. search for library is not repeated) if these variables +# are set with valid values _in the CMake cache_. This means that if these +# variables are set directly in the cache, either by the user in the CMake GUI, +# or by the user passing -DVAR=VALUE directives to CMake when called (which +# explicitly defines a cache variable), then they will be used verbatim, +# bypassing the HINTS variables and other hard-coded search locations. +# +# EIGEN_INCLUDE_DIR: Include directory for CXSparse, not including the +# include directory of any dependencies. + +# Called if we failed to find Eigen or any of it's required dependencies, +# unsets all public (designed to be used externally) variables and reports +# error message at priority depending upon [REQUIRED/QUIET/] argument. +macro(EIGEN_REPORT_NOT_FOUND REASON_MSG) + unset(EIGEN_FOUND) + unset(EIGEN_INCLUDE_DIRS) + unset(FOUND_INSTALLED_EIGEN_CMAKE_CONFIGURATION) + # Make results of search visible in the CMake GUI if Eigen has not + # been found so that user does not have to toggle to advanced view. + mark_as_advanced(CLEAR EIGEN_INCLUDE_DIR) + # Note _FIND_[REQUIRED/QUIETLY] variables defined by FindPackage() + # use the camelcase library name, not uppercase. + if (Eigen_FIND_QUIETLY) + message(STATUS "Failed to find Eigen - " ${REASON_MSG} ${ARGN}) + elseif (Eigen_FIND_REQUIRED) + message(FATAL_ERROR "Failed to find Eigen - " ${REASON_MSG} ${ARGN}) + else() + # Neither QUIETLY nor REQUIRED, use no priority which emits a message + # but continues configuration and allows generation. + message("-- Failed to find Eigen - " ${REASON_MSG} ${ARGN}) + endif () + return() +endmacro(EIGEN_REPORT_NOT_FOUND) + +# Protect against any alternative find_package scripts for this library having +# been called previously (in a client project) which set EIGEN_FOUND, but not +# the other variables we require / set here which could cause the search logic +# here to fail. +unset(EIGEN_FOUND) + +# ----------------------------------------------------------------- +# By default, if the user has expressed no preference for using an exported +# Eigen CMake configuration over performing a search for the installed +# components, and has not specified any hints for the search locations, then +# prefer an exported configuration if available. +if (NOT DEFINED EIGEN_PREFER_EXPORTED_EIGEN_CMAKE_CONFIGURATION + AND NOT EIGEN_INCLUDE_DIR_HINTS) + message(STATUS "No preference for use of exported Eigen CMake configuration " + "set, and no hints for include directory provided. " + "Defaulting to preferring an installed/exported Eigen CMake configuration " + "if available.") + set(EIGEN_PREFER_EXPORTED_EIGEN_CMAKE_CONFIGURATION TRUE) +endif() + +if (EIGEN_PREFER_EXPORTED_EIGEN_CMAKE_CONFIGURATION) + # Try to find an exported CMake configuration for Eigen. + # + # We search twice, s/t we can invert the ordering of precedence used by + # find_package() for exported package build directories, and installed + # packages (found via CMAKE_SYSTEM_PREFIX_PATH), listed as items 6) and 7) + # respectively in [1]. + # + # By default, exported build directories are (in theory) detected first, and + # this is usually the case on Windows. However, on OS X & Linux, the install + # path (/usr/local) is typically present in the PATH environment variable + # which is checked in item 4) in [1] (i.e. before both of the above, unless + # NO_SYSTEM_ENVIRONMENT_PATH is passed). As such on those OSs installed + # packages are usually detected in preference to exported package build + # directories. + # + # To ensure a more consistent response across all OSs, and as users usually + # want to prefer an installed version of a package over a locally built one + # where both exist (esp. as the exported build directory might be removed + # after installation), we first search with NO_CMAKE_PACKAGE_REGISTRY which + # means any build directories exported by the user are ignored, and thus + # installed directories are preferred. If this fails to find the package + # we then research again, but without NO_CMAKE_PACKAGE_REGISTRY, so any + # exported build directories will now be detected. + # + # To prevent confusion on Windows, we also pass NO_CMAKE_BUILDS_PATH (which + # is item 5) in [1]), to not preferentially use projects that were built + # recently with the CMake GUI to ensure that we always prefer an installed + # version if available. + # + # [1] http://www.cmake.org/cmake/help/v2.8.11/cmake.html#command:find_package + find_package(Eigen3 QUIET + NO_MODULE + NO_CMAKE_PACKAGE_REGISTRY + NO_CMAKE_BUILDS_PATH) + if (EIGEN3_FOUND) + message(STATUS "Found installed version of Eigen: ${Eigen3_DIR}") + else() + # Failed to find an installed version of Eigen, repeat search allowing + # exported build directories. + message(STATUS "Failed to find installed Eigen CMake configuration, " + "searching for Eigen build directories exported with CMake.") + # Again pass NO_CMAKE_BUILDS_PATH, as we know that Eigen is exported and + # do not want to treat projects built with the CMake GUI preferentially. + find_package(Eigen3 QUIET + NO_MODULE + NO_CMAKE_BUILDS_PATH) + if (EIGEN3_FOUND) + message(STATUS "Found exported Eigen build directory: ${Eigen3_DIR}") + endif() + endif() + if (EIGEN3_FOUND) + set(FOUND_INSTALLED_EIGEN_CMAKE_CONFIGURATION TRUE) + set(EIGEN_FOUND ${EIGEN3_FOUND}) + set(EIGEN_INCLUDE_DIR "${EIGEN3_INCLUDE_DIR}" CACHE STRING + "Eigen include directory" FORCE) + else() + message(STATUS "Failed to find an installed/exported CMake configuration " + "for Eigen, will perform search for installed Eigen components.") + endif() +endif() + +if (NOT EIGEN_FOUND) + # Search user-installed locations first, so that we prefer user installs + # to system installs where both exist. + list(APPEND EIGEN_CHECK_INCLUDE_DIRS + /usr/local/include + /usr/local/homebrew/include # Mac OS X + /opt/local/var/macports/software # Mac OS X. + /opt/local/include + /usr/include) + # Additional suffixes to try appending to each search path. + list(APPEND EIGEN_CHECK_PATH_SUFFIXES + eigen3 # Default root directory for Eigen. + Eigen/include/eigen3 # Windows (for C:/Program Files prefix) < 3.3 + Eigen3/include/eigen3 ) # Windows (for C:/Program Files prefix) >= 3.3 + + # Search supplied hint directories first if supplied. + find_path(EIGEN_INCLUDE_DIR + NAMES Eigen/Core + HINTS ${EIGEN_INCLUDE_DIR_HINTS} + PATHS ${EIGEN_CHECK_INCLUDE_DIRS} + PATH_SUFFIXES ${EIGEN_CHECK_PATH_SUFFIXES}) + + if (NOT EIGEN_INCLUDE_DIR OR + NOT EXISTS ${EIGEN_INCLUDE_DIR}) + eigen_report_not_found( + "Could not find eigen3 include directory, set EIGEN_INCLUDE_DIR to " + "path to eigen3 include directory, e.g. /usr/local/include/eigen3.") + endif (NOT EIGEN_INCLUDE_DIR OR + NOT EXISTS ${EIGEN_INCLUDE_DIR}) + + # Mark internally as found, then verify. EIGEN_REPORT_NOT_FOUND() unsets + # if called. + set(EIGEN_FOUND TRUE) +endif() + +# Extract Eigen version from Eigen/src/Core/util/Macros.h +if (EIGEN_INCLUDE_DIR) + set(EIGEN_VERSION_FILE ${EIGEN_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h) + if (NOT EXISTS ${EIGEN_VERSION_FILE}) + eigen_report_not_found( + "Could not find file: ${EIGEN_VERSION_FILE} " + "containing version information in Eigen install located at: " + "${EIGEN_INCLUDE_DIR}.") + else (NOT EXISTS ${EIGEN_VERSION_FILE}) + file(READ ${EIGEN_VERSION_FILE} EIGEN_VERSION_FILE_CONTENTS) + + string(REGEX MATCH "#define EIGEN_WORLD_VERSION [0-9]+" + EIGEN_WORLD_VERSION "${EIGEN_VERSION_FILE_CONTENTS}") + string(REGEX REPLACE "#define EIGEN_WORLD_VERSION ([0-9]+)" "\\1" + EIGEN_WORLD_VERSION "${EIGEN_WORLD_VERSION}") + + string(REGEX MATCH "#define EIGEN_MAJOR_VERSION [0-9]+" + EIGEN_MAJOR_VERSION "${EIGEN_VERSION_FILE_CONTENTS}") + string(REGEX REPLACE "#define EIGEN_MAJOR_VERSION ([0-9]+)" "\\1" + EIGEN_MAJOR_VERSION "${EIGEN_MAJOR_VERSION}") + + string(REGEX MATCH "#define EIGEN_MINOR_VERSION [0-9]+" + EIGEN_MINOR_VERSION "${EIGEN_VERSION_FILE_CONTENTS}") + string(REGEX REPLACE "#define EIGEN_MINOR_VERSION ([0-9]+)" "\\1" + EIGEN_MINOR_VERSION "${EIGEN_MINOR_VERSION}") + + # This is on a single line s/t CMake does not interpret it as a list of + # elements and insert ';' separators which would result in 3.;2.;0 nonsense. + set(EIGEN_VERSION "${EIGEN_WORLD_VERSION}.${EIGEN_MAJOR_VERSION}.${EIGEN_MINOR_VERSION}") + endif (NOT EXISTS ${EIGEN_VERSION_FILE}) +endif (EIGEN_INCLUDE_DIR) + +# Set standard CMake FindPackage variables if found. +if (EIGEN_FOUND) + set(EIGEN_INCLUDE_DIRS ${EIGEN_INCLUDE_DIR}) +endif (EIGEN_FOUND) + +# Handle REQUIRED / QUIET optional arguments and version. +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Eigen + REQUIRED_VARS EIGEN_INCLUDE_DIRS + VERSION_VAR EIGEN_VERSION) + +# Only mark internal variables as advanced if we found Eigen, otherwise +# leave it visible in the standard GUI for the user to set manually. +if (EIGEN_FOUND) + mark_as_advanced(FORCE EIGEN_INCLUDE_DIR + Eigen3_DIR) # Autogenerated by find_package(Eigen3) +endif (EIGEN_FOUND) diff --git a/thirdparty/QuadriFlow/cmake/FindGUROBI.cmake b/thirdparty/QuadriFlow/cmake/FindGUROBI.cmake new file mode 100755 index 00000000..6cf5ce5e --- /dev/null +++ b/thirdparty/QuadriFlow/cmake/FindGUROBI.cmake @@ -0,0 +1,62 @@ +#### Taken from http://www.openflipper.org/svnrepo/CoMISo/trunk/CoMISo/cmake/FindGUROBI.cmake +# Once done this will define +# GUROBI_FOUND - System has Gurobi +# GUROBI_INCLUDE_DIRS - The Gurobi include directories +# GUROBI_LIBRARIES - The libraries needed to use Gurobi + +if (GUROBI_INCLUDE_DIR) + # in cache already + set(GUROBI_FOUND TRUE) + set(GUROBI_INCLUDE_DIRS "${GUROBI_INCLUDE_DIR}" ) + set(GUROBI_LIBRARIES "${GUROBI_LIBRARY};${GUROBI_CXX_LIBRARY}" ) +else (GUROBI_INCLUDE_DIR) + + find_path(GUROBI_INCLUDE_DIR + NAMES gurobi_c++.h + PATHS "$ENV{GUROBI_HOME}/include" + "/usr/include" + "/usr/local/include" + ) + + find_library( GUROBI_LIBRARY + NAMES gurobi + gurobi45 + gurobi46 + gurobi50 + gurobi51 + gurobi52 + gurobi55 + gurobi56 + gurobi60 + gurobi65 + gurobi70 + gurobi75 + PATHS "$ENV{GUROBI_HOME}/lib" + "/usr/lib" + "/usr/local/lib" + "/Library/gurobi502/mac64/lib" + "C:\\libs\\gurobi502\\lib" + ) + + find_library( GUROBI_CXX_LIBRARY + NAMES gurobi_c++ + PATHS "$ENV{GUROBI_HOME}/lib" + "/Library/gurobi502/mac64/lib" + "C:\\libs\\gurobi502\\lib" + ) + + set(GUROBI_INCLUDE_DIRS "${GUROBI_INCLUDE_DIR}" ) + set(GUROBI_LIBRARIES "${GUROBI_LIBRARY};${GUROBI_CXX_LIBRARY}" ) + + # use c++ headers as default + # set(GUROBI_COMPILER_FLAGS "-DIL_STD" CACHE STRING "Gurobi Compiler Flags") + + include(FindPackageHandleStandardArgs) + # handle the QUIETLY and REQUIRED arguments and set LIBCPLEX_FOUND to TRUE + # if all listed variables are TRUE + find_package_handle_standard_args(GUROBI DEFAULT_MSG + GUROBI_LIBRARY GUROBI_CXX_LIBRARY GUROBI_INCLUDE_DIR) + + mark_as_advanced(GUROBI_INCLUDE_DIR GUROBI_LIBRARY GUROBI_CXX_LIBRARY) + +endif(GUROBI_INCLUDE_DIR) diff --git a/thirdparty/QuadriFlow/cmake/FindTBB.cmake b/thirdparty/QuadriFlow/cmake/FindTBB.cmake new file mode 100755 index 00000000..13f4d929 --- /dev/null +++ b/thirdparty/QuadriFlow/cmake/FindTBB.cmake @@ -0,0 +1,425 @@ +# Locate Intel Threading Building Blocks include paths and libraries +# FindTBB.cmake can be found at https://code.google.com/p/findtbb/ +# Written by Hannes Hofmann +# Improvements by Gino van den Bergen , +# Florian Uhlig , +# Jiri Marsik + +# The MIT License +# +# Copyright (c) 2011 Hannes Hofmann +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +# GvdB: This module uses the environment variable TBB_ARCH_PLATFORM which defines architecture and compiler. +# e.g. "ia32/vc8" or "em64t/cc4.1.0_libc2.4_kernel2.6.16.21" +# TBB_ARCH_PLATFORM is set by the build script tbbvars[.bat|.sh|.csh], which can be found +# in the TBB installation directory (TBB_INSTALL_DIR). +# +# GvdB: Mac OS X distribution places libraries directly in lib directory. +# +# For backwards compatibility, you may explicitely set the CMake variables TBB_ARCHITECTURE and TBB_COMPILER. +# TBB_ARCHITECTURE [ ia32 | em64t | itanium ] +# which architecture to use +# TBB_COMPILER e.g. vc9 or cc3.2.3_libc2.3.2_kernel2.4.21 or cc4.0.1_os10.4.9 +# which compiler to use (detected automatically on Windows) + +# This module respects +# TBB_INSTALL_DIR or $ENV{TBB21_INSTALL_DIR} or $ENV{TBB_INSTALL_DIR} + +# This module defines +# TBB_INCLUDE_DIRS, where to find task_scheduler_init.h, etc. +# TBB_LIBRARY_DIRS, where to find TBB libraries +# TBB_INSTALL_DIR, the base TBB install directory. +# TBB_LIBRARIES, all the following TBB libraries (both release and debug versions, using "optimized" and "debug" CMake keywords). Note that if the debug versions are not found, the release versions will be used instead for the debug mode. +# TBB_RELEASE_LIBRARY, the TBB release library +# TBB_MALLOC_RELEASE_LIBRARY, the TBB release malloc library +# TBB_DEBUG_LIBRARY, the TBB debug library +# TBB_MALLOC_DEBUG_LIBRARY, the TBB debug malloc library +# TBB_FOUND, If false, don't try to use TBB. +# TBB_INTERFACE_VERSION, as defined in tbb/tbb_stddef.h +# TBB_MALLOCPROXY_DEBUG_LIBRARY, the TBB debug malloc_proxy library (not included in TBB_LIBRARIES since it's optionnal) +# TBB_MALLOCPROXY_RELEASE_LIBRARY, the TBB release malloc_proxy library (not included in TBB_LIBRARIES since it's optionnal) + +include(CheckCXXSourceCompiles) + +# Usage: +# try_TBB_with_pthread( [additional linker args...]) +function(try_TBB_with_pthread result_var) + set(TBB_try_ts_source " + #include + int main() { + tbb::enumerable_thread_specific< + bool*, + tbb::cache_aligned_allocator, + tbb::ets_key_per_instance> grid; + } + ") + set(CMAKE_REQUIRED_LIBRARIES ${ALL_TBB_LIBRARIES} ${ARGN}) + set(CMAKE_REQUIRED_INCLUDES ${TBB_INCLUDE_DIR}) + check_cxx_source_compiles("${TBB_try_ts_source}" ${result_var}) + set(${result_var} ${${result_var}} PARENT_SCOPE) +endfunction(try_TBB_with_pthread) + +if (WIN32) + # has em64t/vc8 em64t/vc9 + # has ia32/vc7.1 ia32/vc8 ia32/vc9 + set(_TBB_DEFAULT_INSTALL_DIR "C:/Program Files/Intel/TBB" "C:/Program Files (x86)/Intel/TBB") + set(_TBB_LIB_RELEASE_NAME "tbb") + set(_TBB_LIB_MALLOC_RELEASE_NAME "${_TBB_LIB_RELEASE_NAME}malloc") + set(_TBB_LIB_MALLOCPROXY_RELEASE_NAME "${_TBB_LIB_RELEASE_NAME}malloc_proxy") + set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_RELEASE_NAME}_debug") + set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_RELEASE_NAME}_debug") + set(_TBB_LIB_MALLOCPROXY_DEBUG_NAME "${_TBB_LIB_MALLOCPROXY_RELEASE_NAME}_debug") + if (MSVC71) + set (_TBB_COMPILER "vc7.1") + endif(MSVC71) + if (MSVC80) + set(_TBB_COMPILER "vc8") + endif(MSVC80) + if (MSVC90) + set(_TBB_COMPILER "vc9") + endif(MSVC90) + if(MSVC10) + set(_TBB_COMPILER "vc10") + endif(MSVC10) + if(MSVC11) + set(_TBB_COMPILER "vc11") + endif(MSVC11) + if(MSVC12) + set(_TBB_COMPILER "vc12") + endif(MSVC12) + #note there was no MSVC13 + if(MSVC14) + set(_TBB_COMPILER "vc14") + endif(MSVC14) + # Todo: add other Windows compilers such as ICL. + set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE}) +endif (WIN32) + +if (UNIX) + if (APPLE) + # MAC + set(_TBB_DEFAULT_INSTALL_DIR "/Library/Frameworks/Intel_TBB.framework/Versions") + # libs: libtbb.dylib, libtbbmalloc.dylib, *_debug + set(_TBB_LIB_RELEASE_NAME "tbb") + set(_TBB_LIB_MALLOC_RELEASE_NAME "${_TBB_LIB_RELEASE_NAME}malloc") + #set(_TBB_LIB_MALLOCPROXY_RELEASE_NAME "${_TBB_LIB_RELEASE_NAME}malloc_proxy") + set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_RELEASE_NAME}_debug") + set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_RELEASE_NAME}_debug") + #set(_TBB_LIB_MALLOCPROXY_DEBUG_NAME "${_TBB_LIB_MALLOCPROXY_RELEASE_NAME}_debug") + # default flavor on apple: ia32/cc4.0.1_os10.4.9 + # Jiri: There is no reason to presume there is only one flavor and + # that user's setting of variables should be ignored. + if(NOT TBB_COMPILER) + set(_TBB_COMPILER "cc4.0.1_os10.4.9") + elseif (NOT TBB_COMPILER) + set(_TBB_COMPILER ${TBB_COMPILER}) + endif(NOT TBB_COMPILER) + if(NOT TBB_ARCHITECTURE) + set(_TBB_ARCHITECTURE "ia32") + elseif(NOT TBB_ARCHITECTURE) + set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE}) + endif(NOT TBB_ARCHITECTURE) + else (APPLE) + # LINUX + set(_TBB_DEFAULT_INSTALL_DIR "/opt/intel/tbb" "/usr/local/include" "/usr/include") + set(_TBB_LIB_RELEASE_NAME "tbb") + set(_TBB_LIB_MALLOC_RELEASE_NAME "${_TBB_LIB_RELEASE_NAME}malloc") + set(_TBB_LIB_MALLOCPROXY_RELEASE_NAME "${_TBB_LIB_RELEASE_NAME}malloc_proxy") + set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_RELEASE_NAME}_debug") + set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_RELEASE_NAME}_debug") + set(_TBB_LIB_MALLOCPROXY_DEBUG_NAME "${_TBB_LIB_MALLOCPROXY_RELEASE_NAME}_debug") + # has em64t/cc3.2.3_libc2.3.2_kernel2.4.21 em64t/cc3.3.3_libc2.3.3_kernel2.6.5 em64t/cc3.4.3_libc2.3.4_kernel2.6.9 em64t/cc4.1.0_libc2.4_kernel2.6.16.21 + # has ia32/* + # has itanium/* + set(_TBB_COMPILER ${TBB_COMPILER}) + set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE}) + endif (APPLE) +endif (UNIX) + +if (CMAKE_SYSTEM MATCHES "SunOS.*") +# SUN +# not yet supported +# has em64t/cc3.4.3_kernel5.10 +# has ia32/* +endif (CMAKE_SYSTEM MATCHES "SunOS.*") + + +#-- Clear the public variables +set (TBB_FOUND "NO") + + +#-- Find TBB install dir and set ${_TBB_INSTALL_DIR} and cached ${TBB_INSTALL_DIR} +# first: use CMake variable TBB_INSTALL_DIR +if (TBB_INSTALL_DIR) + set (_TBB_INSTALL_DIR ${TBB_INSTALL_DIR}) +endif (TBB_INSTALL_DIR) +# second: use environment variable +if (NOT _TBB_INSTALL_DIR) + if (NOT "$ENV{TBBROOT}" STREQUAL "") + set (_TBB_INSTALL_DIR $ENV{TBBROOT}) + endif (NOT "$ENV{TBBROOT}" STREQUAL "") + if (NOT "$ENV{TBB_INSTALL_DIR}" STREQUAL "") + set (_TBB_INSTALL_DIR $ENV{TBB_INSTALL_DIR}) + endif (NOT "$ENV{TBB_INSTALL_DIR}" STREQUAL "") + # Intel recommends setting TBB21_INSTALL_DIR + if (NOT "$ENV{TBB21_INSTALL_DIR}" STREQUAL "") + set (_TBB_INSTALL_DIR $ENV{TBB21_INSTALL_DIR}) + endif (NOT "$ENV{TBB21_INSTALL_DIR}" STREQUAL "") + if (NOT "$ENV{TBB22_INSTALL_DIR}" STREQUAL "") + set (_TBB_INSTALL_DIR $ENV{TBB22_INSTALL_DIR}) + endif (NOT "$ENV{TBB22_INSTALL_DIR}" STREQUAL "") + if (NOT "$ENV{TBB30_INSTALL_DIR}" STREQUAL "") + set (_TBB_INSTALL_DIR $ENV{TBB30_INSTALL_DIR}) + endif (NOT "$ENV{TBB30_INSTALL_DIR}" STREQUAL "") +endif (NOT _TBB_INSTALL_DIR) +# third: try to find path automatically +if (NOT _TBB_INSTALL_DIR) + if (_TBB_DEFAULT_INSTALL_DIR) + set (_TBB_INSTALL_DIR ${_TBB_DEFAULT_INSTALL_DIR}) + endif (_TBB_DEFAULT_INSTALL_DIR) +endif (NOT _TBB_INSTALL_DIR) +# sanity check +if (NOT _TBB_INSTALL_DIR) + message ("ERROR: Unable to find Intel TBB install directory. ${_TBB_INSTALL_DIR}") +else (NOT _TBB_INSTALL_DIR) +# finally: set the cached CMake variable TBB_INSTALL_DIR +if (NOT TBB_INSTALL_DIR) + set (TBB_INSTALL_DIR ${_TBB_INSTALL_DIR} CACHE PATH "Intel TBB install directory") + mark_as_advanced(TBB_INSTALL_DIR) +endif (NOT TBB_INSTALL_DIR) + + +#-- A macro to rewrite the paths of the library. This is necessary, because +# find_library() always found the em64t/vc9 version of the TBB libs +macro(TBB_CORRECT_LIB_DIR var_name) +# if (NOT "${_TBB_ARCHITECTURE}" STREQUAL "em64t") + string(REPLACE em64t "${_TBB_ARCHITECTURE}" ${var_name} ${${var_name}}) +# endif (NOT "${_TBB_ARCHITECTURE}" STREQUAL "em64t") + string(REPLACE ia32 "${_TBB_ARCHITECTURE}" ${var_name} ${${var_name}}) + string(REGEX REPLACE "vc[0-9]+(\.[0-9]+)?" "${_TBB_COMPILER}" ${var_name} ${${var_name}}) +endmacro(TBB_CORRECT_LIB_DIR var_content) + + +#-- Look for include directory and set ${TBB_INCLUDE_DIR} +set (TBB_INC_SEARCH_DIR ${_TBB_INSTALL_DIR}/include) +# Jiri: tbbvars now sets the CPATH environment variable to the directory +# containing the headers. +# LR: search first with NO_DEFAULT_PATH... +find_path(TBB_INCLUDE_DIR + tbb/task_scheduler_init.h + PATHS ${TBB_INC_SEARCH_DIR} ENV CPATH + NO_DEFAULT_PATH +) +if(NOT TBB_INCLUDE_DIR) +# LR: ... and then search again with NO_DEFAULT_PATH if nothing was found in +# hinted paths + find_path(TBB_INCLUDE_DIR + tbb/task_scheduler_init.h + PATHS ${TBB_INC_SEARCH_DIR} ENV CPATH + ) +endif() +mark_as_advanced(TBB_INCLUDE_DIR) + + +#-- Look for libraries +# GvdB: $ENV{TBB_ARCH_PLATFORM} is set by the build script tbbvars[.bat|.sh|.csh] +if (NOT $ENV{TBB_ARCH_PLATFORM} STREQUAL "") + set (_TBB_LIBRARY_DIR + ${_TBB_INSTALL_DIR}/lib/$ENV{TBB_ARCH_PLATFORM} + ${_TBB_INSTALL_DIR}/$ENV{TBB_ARCH_PLATFORM}/lib + ) +endif (NOT $ENV{TBB_ARCH_PLATFORM} STREQUAL "") +# Jiri: This block isn't mutually exclusive with the previous one +# (hence no else), instead I test if the user really specified +# the variables in question. +if ((NOT ${TBB_ARCHITECTURE} STREQUAL "") AND (NOT ${TBB_COMPILER} STREQUAL "")) + # HH: deprecated + message(STATUS "[Warning] FindTBB.cmake: The use of TBB_ARCHITECTURE and TBB_COMPILER is deprecated and may not be supported in future versions. Please set \$ENV{TBB_ARCH_PLATFORM} (using tbbvars.[bat|csh|sh]).") + # Jiri: It doesn't hurt to look in more places, so I store the hints from + # ENV{TBB_ARCH_PLATFORM} and the TBB_ARCHITECTURE and TBB_COMPILER + # variables and search them both. + set (_TBB_LIBRARY_DIR "${_TBB_INSTALL_DIR}/${_TBB_ARCHITECTURE}/${_TBB_COMPILER}/lib" ${_TBB_LIBRARY_DIR}) +endif ((NOT ${TBB_ARCHITECTURE} STREQUAL "") AND (NOT ${TBB_COMPILER} STREQUAL "")) + +# GvdB: Mac OS X distribution places libraries directly in lib directory. +list(APPEND _TBB_LIBRARY_DIR ${_TBB_INSTALL_DIR}/lib) + +# Jiri: No reason not to check the default paths. From recent versions, +# tbbvars has started exporting the LIBRARY_PATH and LD_LIBRARY_PATH +# variables, which now point to the directories of the lib files. +# It all makes more sense to use the ${_TBB_LIBRARY_DIR} as a HINTS +# argument instead of the implicit PATHS as it isn't hard-coded +# but computed by system introspection. Searching the LIBRARY_PATH +# and LD_LIBRARY_PATH environment variables is now even more important +# that tbbvars doesn't export TBB_ARCH_PLATFORM and it facilitates +# the use of TBB built from sources. +# LR: search first with NO_DEFAULT_PATH... +find_library(TBB_RELEASE_LIBRARY ${_TBB_LIB_RELEASE_NAME} HINTS ${_TBB_LIBRARY_DIR} + PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH NO_DEFAULT_PATH) +find_library(TBB_MALLOC_RELEASE_LIBRARY ${_TBB_LIB_MALLOC_RELEASE_NAME} HINTS ${_TBB_LIBRARY_DIR} + PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH NO_DEFAULT_PATH) +find_library(TBB_MALLOCPROXY_RELEASE_LIBRARY ${_TBB_LIB_MALLOCPROXY_RELEASE_NAME} HINTS ${_TBB_LIBRARY_DIR} + PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH NO_DEFAULT_PATH) +if(NOT TBB_RELEASE_LIBRARY OR NOT TBB_MALLOC_RELEASE_LIBRARY OR NOT TBB_MALLOCPROXY_RELEASE_LIBRARY) +# LR: ... and then search again with NO_DEFAULT_PATH if nothing was found +# in hinted paths + find_library(TBB_RELEASE_LIBRARY ${_TBB_LIB_RELEASE_NAME} HINTS ${_TBB_LIBRARY_DIR} + PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH) + find_library(TBB_MALLOC_RELEASE_LIBRARY ${_TBB_LIB_MALLOC_RELEASE_NAME} HINTS ${_TBB_LIBRARY_DIR} + PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH) + find_library(TBB_MALLOCPROXY_RELEASE_LIBRARY ${_TBB_LIB_MALLOCPROXY_RELEASE_NAME} HINTS ${_TBB_LIBRARY_DIR} + PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH) +endif() + +#Extract path from TBB_RELEASE_LIBRARY name +get_filename_component(TBB_RELEASE_LIBRARY_DIR ${TBB_RELEASE_LIBRARY} PATH) + +#TBB_CORRECT_LIB_DIR(TBB_RELEASE_LIBRARY) +#TBB_CORRECT_LIB_DIR(TBB_MALLOC_RELEASE_LIBRARY) +#TBB_CORRECT_LIB_DIR(TBB_MALLOCPROXY_RELEASE_LIBRARY) +mark_as_advanced(TBB_RELEASE_LIBRARY TBB_MALLOC_RELEASE_LIBRARY TBB_MALLOCPROXY_RELEASE_LIBRARY) + +#-- Look for debug libraries +# Jiri: Changed the same way as for the release libraries. +find_library(TBB_DEBUG_LIBRARY ${_TBB_LIB_DEBUG_NAME} HINTS ${_TBB_LIBRARY_DIR} + PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH NO_DEFAULT_PATH) +find_library(TBB_MALLOC_DEBUG_LIBRARY ${_TBB_LIB_MALLOC_DEBUG_NAME} HINTS ${_TBB_LIBRARY_DIR} + PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH NO_DEFAULT_PATH) +find_library(TBB_MALLOCPROXY_DEBUG_LIBRARY ${_TBB_LIB_MALLOCPROXY_DEBUG_NAME} HINTS ${_TBB_LIBRARY_DIR} + PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH NO_DEFAULT_PATH) +if(NOT TBB_DEBUG_LIBRARY OR NOT TBB_MALLOC_DEBUG_LIBRARY OR NOT TBB_MALLOCPROXY_DEBUG_LIBRARY) + find_library(TBB_DEBUG_LIBRARY ${_TBB_LIB_DEBUG_NAME} HINTS ${_TBB_LIBRARY_DIR} + PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH) + find_library(TBB_MALLOC_DEBUG_LIBRARY ${_TBB_LIB_MALLOC_DEBUG_NAME} HINTS ${_TBB_LIBRARY_DIR} + PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH) + find_library(TBB_MALLOCPROXY_DEBUG_LIBRARY ${_TBB_LIB_MALLOCPROXY_DEBUG_NAME} HINTS ${_TBB_LIBRARY_DIR} + PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH) +endif() + +# Jiri: Self-built TBB stores the debug libraries in a separate directory. +# Extract path from TBB_DEBUG_LIBRARY name +get_filename_component(TBB_DEBUG_LIBRARY_DIR ${TBB_DEBUG_LIBRARY} PATH) + +#TBB_CORRECT_LIB_DIR(TBB_DEBUG_LIBRARY) +#TBB_CORRECT_LIB_DIR(TBB_MALLOC_DEBUG_LIBRARY) +#TBB_CORRECT_LIB_DIR(TBB_MALLOCPROXY_DEBUG_LIBRARY) +mark_as_advanced(TBB_DEBUG_LIBRARY TBB_MALLOC_DEBUG_LIBRARY TBB_MALLOCPROXY_DEBUG_LIBRARY) + +if (TBB_INCLUDE_DIR) + if (TBB_RELEASE_LIBRARY) + set (TBB_FOUND "YES") + + # NOTE: Removed because we don't want to link with the malloc_proxy by default + #if (NOT "${TBB_MALLOCPROXY_RELEASE_LIBRARY}" STREQUAL "TBB_MALLOCPROXY_RELEASE_LIBRARY-NOTFOUND") + # mark_as_advanced(TBB_MALLOCPROXY_RELEASE_LIBRARY) + # set (_TBB_MALLOCPROXY optimized ${TBB_MALLOCPROXY_RELEASE_LIBRARY}) + #endif (NOT "${TBB_MALLOCPROXY_RELEASE_LIBRARY}" STREQUAL "TBB_MALLOCPROXY_RELEASE_LIBRARY-NOTFOUND") + #if (NOT "${TBB_MALLOCPROXY_DEBUG_LIBRARY}" STREQUAL "TBB_MALLOCPROXY_DEBUG_LIBRARY-NOTFOUND") + # mark_as_advanced(TBB_MALLOCPROXY_DEBUG_LIBRARY) + # set (_TBB_MALLOCPROXY ${_TBB_MALLOCPROXY} debug ${TBB_MALLOCPROXY_DEBUG_LIBRARY}) + #endif (NOT "${TBB_MALLOCPROXY_DEBUG_LIBRARY}" STREQUAL "TBB_MALLOCPROXY_DEBUG_LIBRARY-NOTFOUND") + + # TBB release library + set (ALL_TBB_LIBRARIES optimized ${TBB_RELEASE_LIBRARY}) + + # TBB debug library found? + if (TBB_DEBUG_LIBRARY) + list(APPEND ALL_TBB_LIBRARIES debug ${TBB_DEBUG_LIBRARY}) + else (TBB_DEBUG_LIBRARY) + # Otherwise, link with the release library even in debug mode + list(APPEND ALL_TBB_LIBRARIES debug ${TBB_RELEASE_LIBRARY}) + endif (TBB_DEBUG_LIBRARY) + + # TBB malloc - release + if (TBB_MALLOC_RELEASE_LIBRARY) + list(APPEND ALL_TBB_LIBRARIES optimized ${TBB_MALLOC_RELEASE_LIBRARY}) + + # TBB malloc - debug + if (TBB_MALLOC_DEBUG_LIBRARY) + list(APPEND ALL_TBB_LIBRARIES debug ${TBB_MALLOC_DEBUG_LIBRARY}) + else (TBB_MALLOC_DEBUG_LIBRARY) + list(APPEND ALL_TBB_LIBRARIES debug ${TBB_MALLOC_RELEASE_LIBRARY}) + endif (TBB_MALLOC_DEBUG_LIBRARY) + endif (TBB_MALLOC_RELEASE_LIBRARY) + + if(UNIX AND NOT APPLE) + # On Fedora, code using TBB might need -pthread + + # First check without pthread + try_TBB_with_pthread(TBB_without_pthread) + + if(NOT TBB_without_pthread) + # Then check with -pthread + try_TBB_with_pthread(TBB_with_pthread -pthread) + if(TBB_with_pthread) + list(APPEND ALL_TBB_LIBRARIES general -pthread) + endif(TBB_with_pthread) + endif(NOT TBB_without_pthread) + endif(UNIX AND NOT APPLE) + + set (TBB_LIBRARIES ${ALL_TBB_LIBRARIES} + CACHE PATH "TBB libraries" FORCE) + + # Include dirs + set (TBB_INCLUDE_DIRS ${TBB_INCLUDE_DIR} CACHE PATH "TBB include directory" FORCE) + + # Library dirs + if( "${TBB_DEBUG_LIBRARY_DIR}" STREQUAL "" OR "${TBB_RELEASE_LIBRARY_DIR}" STREQUAL "${TBB_DEBUG_LIBRARY_DIR}" ) + set (TBB_LIBRARY_DIRS + ${TBB_RELEASE_LIBRARY_DIR} + CACHE PATH "TBB library directories" FORCE) + else( "${TBB_DEBUG_LIBRARY_DIR}" STREQUAL "" OR "${TBB_RELEASE_LIBRARY_DIR}" STREQUAL "${TBB_DEBUG_LIBRARY_DIR}" ) + set (TBB_LIBRARY_DIRS + ${TBB_RELEASE_LIBRARY_DIR} ${TBB_DEBUG_LIBRARY_DIR} + CACHE PATH "TBB library directories" FORCE) + endif( "${TBB_DEBUG_LIBRARY_DIR}" STREQUAL "" OR "${TBB_RELEASE_LIBRARY_DIR}" STREQUAL "${TBB_DEBUG_LIBRARY_DIR}" ) + + message(STATUS "Found Intel TBB") + endif (TBB_RELEASE_LIBRARY) +endif (TBB_INCLUDE_DIR) + +if (NOT TBB_FOUND) + if(NOT TBB_FIND_QUIETLY) + message("ERROR: Intel TBB NOT found! Please define the TBBROOT (or TBB_INSTALL_DIR) and/or TBB_ARCH_PLATFORM environment variables.") + message(STATUS "Looked for Threading Building Blocks in ${_TBB_INSTALL_DIR}") + endif(NOT TBB_FIND_QUIETLY) + SET(TBB_INSTALL_DIR "TBB_INSTALL_DIR_NOT_FOUND" CACHE STRING "Intel TBB install directory") + # do only throw fatal, if this pkg is REQUIRED + if (TBB_FIND_REQUIRED) + message(FATAL_ERROR "Could NOT find TBB library.") + endif (TBB_FIND_REQUIRED) +endif (NOT TBB_FOUND) + +endif (NOT _TBB_INSTALL_DIR) + +if (TBB_FOUND) + set(TBB_INTERFACE_VERSION 0) + FILE(READ "${TBB_INCLUDE_DIRS}/tbb/tbb_stddef.h" _TBB_VERSION_CONTENTS) + STRING(REGEX REPLACE ".*#define TBB_INTERFACE_VERSION ([0-9]+).*" "\\1" TBB_INTERFACE_VERSION "${_TBB_VERSION_CONTENTS}") + set(TBB_INTERFACE_VERSION "${TBB_INTERFACE_VERSION}") +endif (TBB_FOUND) + +set(TBB_USE_FILE "UseTBB") + +### ** Emacs settings ** +### Local Variables: +### cmake-tab-width: 4 +### End: diff --git a/thirdparty/QuadriFlow/demo.sh b/thirdparty/QuadriFlow/demo.sh new file mode 100755 index 00000000..5f8b3dd5 --- /dev/null +++ b/thirdparty/QuadriFlow/demo.sh @@ -0,0 +1,7 @@ +mkdir build +cd build +cmake .. +make +cd .. +./build/quadriflow -i examples/Gargoyle_input.obj -o examples/Gargoyle_quadriflow.obj -f 1200 + diff --git a/thirdparty/QuadriFlow/img/result.jpg b/thirdparty/QuadriFlow/img/result.jpg new file mode 100755 index 0000000000000000000000000000000000000000..cfa3cc3e8d2d5b1975e02824f03b1ed1b2538411 GIT binary patch literal 596950 zcmeFYWl&px+b$Z46o=sMR$Ph}X@TNW9Eyh!iWev@EuIwDCTImH4#A~(AV`3=xVA-$ z6DSnt@XVZjzU*he=RNbB*|R_Ve_4~stgMw}uB=K0KmC> z0B#omY5?4O|62cg#=Tp31bF{igaicm1Vn_y#6*NdM8u>Nq{JlTBt%4HKr(U)N=hIl zF)0-_6(#lEYs%Yh00|-92GJxA4iIpQ0OM6m4HqFTw*;N!6CNp5BYH<7-iI=3#vmVm zX<2m>bBln;?D~erNxrA1W=_6-uhKHJzB9z6f0$U~2S;UmMAr38759BRjQ-UB>vkSM z_^%(J0=PDr(0};P_74L8An*?Y{~+)W0{*x7%A-N(TnQ0}+NMPHzWqKM_OijUru*#zOa%wLTSx}(w z>$(RURlhX3EcKdx%(_+nwfrpY;}fzFAN9vnDj3fGB7OhcmNBdW%7o6!js4<=Hv>AKWwi6lHDKxq3Wx%q}97}{fyR`_c!)}kcjD)sw<^|Hw zD3MZ}6ygvQ2LgeD;Bfei)BpbIl%4aj_i8j~H>QGU1-&Yp9Px`O3S%kPZ<=D^T`ELE z#mvF_9{xb|qmTzP&C7eic@d(w0Lu8h8=h_<^g@c~Lt2Rx<3igQA$Q)W_&!VJ2}arx za_yJ8jIk;Af9TE^riigM@^uOAE{)b!PHW3dWltz(i|bh3YpkAfcE&Bxk&z&eN&(GEWwfRNMpWMo}@YMDX#c1Wm@}xR(6KTO}?Q z_pD>SfM$g4d*83Fw|}J-G&6>r(j3c)Y4JcHnHe zI3DV)r*1($9A3Q8ozjMq)eQ);)Zz-@F&f&f*?X%Ncm$^30+@pr8NDi1 z3J(eUgc+Q@`BPAU6MN->CsSszA!r!v0a#C~kQ)e;vOgjZ#o8jOnrggMP;9Hu*0Nm; zS))HQ?0yL)=ILl~(@8pPRE4EVPG|$W6BDWVqK$v#{f%9$o*y_b9LbHVvhoyu^PHZH zPw#O;g`DUT&V$Q~97{z^z#2F>-$Z5^bzGS8*G!=$)M~Ubv)O(N+O({#0@pVIW2gz* zyVt3{G4P4MCr}6J?lDYlq##u23my&Deg7M`ZuFtpknbwnPHd`*cPFsiV5iW^M94ED ziIW=ffH1w_@HyS&m3M^DR&l28{rIsbG;N~JSp9}s#>mJwSGA^W=|7>2LU8%Gm%WkO zG9DI}+yw>;iA^aSXFpt>3wMpP>{-*0vHn&Ce9j|n!ctLjqUv!31b8J7P{aac`W66g zrhhHC-Tt}Ps>sClHCV-KJuOEL{O%rsxF7%qmEZg_&JCOf1t;v!+#RcV*k6dQ+pzY9 z$V^0j|4^3M*O4R<$#|+h6@T9f0bkJ}Nh{FchUIhPoPD@b*w@pMvOJLX_%nlCcyB*k zp0HY`H4e5+eG!(3oppk*IKknF)LX#sm_z#OE5+BhfXvCROTKCbvc5M2 z%`2WXAg6H(I-4!|sd#uv5n8_E6WeyB5=s%T%o|%3k?oT0DZ!B6E=R$7iJ{)IoM!Y@ zY3Y-WwlWH*jM@>YgMeyt%2pyqD?@@s&Gq`+MPyDzG}_9jix+Aq#$vkn7l4B_{*wEs zW=;w-Ui)aU7oCpSo0vOGm^~Y=&f5748I69>+EkSfRlaE@P;^I1f=C#^Osp5nTTw9O zRcaSMqZ+rHrE#ZY>3TQ3j6KuF@QQG=qti(9=D+G8-~rC}x(G?GZED_{?ZDgsBYqq6Xp3d;O}@rGSrTuGOdiM23wiZAQPjm<$l8aW)s#x43BCOyXF+TAzoAHVA+AD!;{{+kEbrw5HDVX zjORn>=a2QZ)&@JtKC{0-NxI~R96O$?q3sOOW4h>t8Hz$JUW%9B8%RAJUk-_~REHLo z;B^iVW@=^XsVAbI|No!}Og}n{Kkh#u=O%-8drmn^wI>CVf0%z&U1c^COVpSu!8aFO zi-=W^Vd#^0+u&|S9NUFnX{|4K?b(ZbCj6VKBe)uHB3W$XpuxxCkziwNLSVvkuz178 z#o=#>4!*>CBLv9u*K>0*aAV4#T{@XYe>mFpUcEH49ZBW!o!h|bBdcj9;72NI{Yvws49I-{w~V{NpG-H)YPReHws_sjW88~va3wlRL0E~_0XnwJS#yQ zps_1T8bb*#BkH>aRLJa)P`dgY%WS!{wBp&7H>eNG5gl-5Pc)11XCuHL3A%KOqd~Rt zM;72l?px>uUUIZ6cha^0eGLm7W$EMTnDi0Q&=z9rpNvBzUm9@(F2G)N7)6u>t~XMZ*h-onX11DyYCWqLWX%j}3+& zcYtQizO1{A6AElrP)*PYtQPQ)s>cPxpm6wf(to3dxJw>uuJ8{i6QipZ(82+}P1@Xs zxQQoS54@PbT<+@daf2s?!CEPt+|>MBQY+q~5nN%#8zhOSebTL65B#D;@`*m{gm+c< zO>o~a%@AOft>(h@@yejQJ=InZ^XpUGWKC7*k#(d7lC{s_{N9y`f(=IiamNg>U~ z#mno;p+9u>AJ}~;UHyoE>dsug2vRv!Z?@x`RspWDQ+}(H!~vc90TD41IRh?JWhVG( zEZu|E%nsqPKq!8}}rF1cH_$pY3FrjzOFS8HbnW%u+bpAa$itygU+eGqh2H?)n= zaNGsS7C`pTmrf+*-L2ofdhGnsm9d-i^y{fIqphm=_d>TK`gPyJH&G)VC9>!5YLG`sbv?1yR? z{uL@`b<3I`W2IQ|EI)PO@?$mGL_)aB>PO~Xg`dVRp2%y1krbx2Ip0z6Q&T6juS=fOtaNn)b_Y{C)Et=Pfk%QB)I~`y{lU#$W^sC-cx=_)Ahbe?l+TrQcV1-M?)B&E2)4g}=nOG68lqtR$j1$X z?n!lz+o1Ntc=0A!9yc9wh6~*SNLLHzxqp71mxR1j49iR$mt<`@U>WkvA6-i{e-c^e z{%irkTv@Q$?1z&$6jc1$?HsPS>x#wLWIS3$uEK&QD@MMO@+wu}O;`A_5rF$s7< zb+vTw6Z;k#{1y)^cA`MjVBz&{(!RL!CSbXvu#D-$e;Q*&kclcL)aq5cQ z1L3ogL5jE5QV|YEGo88Hb15~i__k>WQ6m+4eI{HQT&g`(RB$S2VUqQK71Yz-8|)}q zm?C3}kn)qItR1_DBNZU`n!Ae8Pi+`<2P0F4v zoUHBsJ$D-_rlx8Uw)t?mt7E3ISzpAo?VZHR=BqgH)X zMnSZoi`h6HKW|F_{AVfFBH|$IgXKh_pLgUY?K9fDZE`d1g4{>Dj8qzzA=qxHzF3yf~o*l@kz^katQ@3LK=*LYer+QLb34Eny_Pn>AB=R{h zsvy}okIeZoY!4TfwR>wO?BxwuUaTc-ElY9yIpri$v3?Tyqw>kCJ$7oQmj9gNRR&89 zwtJ%%=*8AV<^!DQQMC(&D{V%dC%MXaTK`-+shQN0( zb9jPQ02KnN?OgonFzGaPjG=c!$Zw{&d6BDkgTYtKa?MmisyH{QORF;78s}aw|Ib@EDjXyQ5S=2^-oEk$)zraGHj?tI(iJ;kC zmQr|B&zzy}lU`;oA4k{nRzn`Qww{uZEBO&Ie<^k_FJ+Mdz0>i(qG6&WqTar}=H_6l|8bPpRa)!U&$p9V+~M z8AlkUHaBy?2u+R5g)k3Zo(YHqh0nB(Fq(qOh4%K&L(HDzIhFU=p~~EWD;ydTvpbZE z5z~2ME8HWGKxIzYPW>N~cyl5k(eH`hdNAsKbiyAoSZ>@?+z`$21$_R|&+a!Oim1G3 z66W3ik5`y?#PywA=1t+xN}M z9BJhWnkfdUH?9xIX2f-&0`{d4$B)m#H1CI_B4k|2KuI$zHbC z$h)k$KlRuB+;HI04-SmM$dSy<__8siPY85$viFb{k6Sp^3e(*~iB|L(Qh#kZ_36JF z_-JnaCC7DJu`gU=#6++&TGVvzU2@tI?>@twix=k}qD=Htk&g~IuH9^< z)r}npcAdDm?h6Nc@81Gyuf6M2eq0Y2Y@yM|C!2-IL85}82b`-SW96z|3p2<3=>z68 zvoxdMY?dvMJoPCrUh)j`V${+6_`u@|91k%6O_7)0&7;Btx%QKY@uORSe?lAf_$ohm zbF+XunF@U{|9TKZVBK}zhg_~!Id|$(yaf!dreOWBg)2gPm(w*%ofYjaBIzSmlrLUA z6YsB!w4n)9vr_)JM$sC`&!GO~i97PGMe3DdA=%RE6$~U+%xfp=ScXfdEtX+4#py_x zriCJX8r!4ZX3kG(bU}3HdK`Zdibd_WGra$hKCrB4phfxBIlv0PDt(fY@dkmLZ3`}W zTok2s@mIwDzxvnztJ?TKMhnu28=kAsf}?lQf9;0nr|0aY-Ri2GV1ASyjaEB##YDgu zJVcQyxemvp)ALo>6|`T4>8d~{DOW{5W|1BiF!2O$uv+o5JOrZ}q17I9Uke^7s==S! z)**5LU93+Xah8nLmEy@6YN_;x+sQ*M>?S0|xx_cDlu28&WGnc%!1vpY2fi+q)kMvS znG+1viLAfo?D+E?Xj@DyaiW#*mJQ%8W%bHt=&;Vg&!^;yko4IR^bw~GL{DtJF2D=) z{ua>3lbg*A~u*sRiNv-7oPo>hGR`%IXEu>+qgEeoAg53WkIp<0!&ws2xrX z2!wXUXoF=sjXdI&Mi);6lT9@YW2|yo0dE-M^hoGfqa1XerY(6SeH@Kk^C*|u*E}3Z zl;$sGwz51~*|8k0qg}ko{?_!RuC0Xda*8{fv=o|2rR%Y=i5;-M--2u8ICpIpS4t3skl53O>q|ysh-(=TUx=9Vi_j?tW=3;u&{FnOz$Uu<8iXP-Gxc^f0G6Bd75I4yH}^-Hw>9-V|83@_3=^BbV}zls1dfN;b6sJMd4BICsUz zzKoHzR&q?ABv3PA+L&V{J^s1~lIG(?zv>RAP`hbziL(XEd5fbDbVRp+f`?p%;!n8T z9fTD$`KTm4JaDx>EwFcFg>t|0{41Kj%lGxwm-j+V{i1(Rkf7M1w@Rsl1xUQ<>+2Qn z)?f4cn-fxolm^tG^+2b#b^y$epLoEMl}LRy&qW~*rLpnr44q@NZ+ zFNw@}pV>gK_9}BtiBH{gL-b{~Vppa*WCX0Lqd=3Wdabf*fBGa$v)xJ~?tB2;WL6Qo zb+IFHA{QLi1TdCW<=%v)^D*_PeJcz@5z&`m|1;6x*=1MYUVe0w?;~{3hWkqGY|+Tx zLfE)jiUbe{#H0cB2;ZR6fP{&981*xu(ObZ7qPO1CPVVc&%Q$l>stUX}OZ4AJJtL|0 z)XYDV^3`h7B#yk_crt>BDMSUU35C+Co?Hg!HEj4Y5(zyGyPgL1k^c&v_W)DONGdrP z%|FF^HdLT{KKI4bv*!n#{iQB*5OkUI6R4`^zc8}@VNS|-<94MxD zF#IWBr+eNJ5b!J6bdV}4NebGLey!MBOC&aDG3xNRwJB8O;NmpwazDvp-!I_h_ zEzzC;TNkmGp_p!(Xv=B6!hPQszR=6-r1;g%!@s_<9yqIBtIg8eb27}B;q^jeiUkg% z3rRs~{-Usm6z|1NyUPDji~c+H>fatCy(xy?Sp5`xCBG(qnt2qkHsXYAByytSnCcXz zse^zV!u=V664XjX+{t_pMcto2 z2VAJFpOvfZhKrolc>z?hBDsZRm`?)j&olpLPD?vOy)UT8!ylH`rEJbT$u@9w*&Xs-I>(^l_l1?imeIRa|^Q7HkQ z{($iwjIjU&ityJMiC_t+50&!VC*7y{U_zodm(V!WrO2%Ok?gz52o>NfEb?sIg!f_I z!LO09u40LZZ;NJ5aeq5Si@z00poEIy1>9HRD-m1CNHj0PeD2-pfUdl~NK+s=?p7s! z!Pzn2M3IU?D`LZEtyVZmpb+cg2xmnuqZ@>@zuPIFw>~2c&D%f>{HKpOA%yH_T40U}8N+~JcACa&Eh#VZ&1q^;Y9Lntt%4)dE$OabM6^B}4 zqHh5bVHF1?j zv)(IhMF|iB>?bjS1)G$tBVlvOI{JkZQ%i>-{hxH zcse{fd|VnJ;kN%3_jDg!cDi!iO)50GYd0BWvJXcd7TcRfx%*6QSj>_#q>5DuAT~^+ zRyYl!-L#yV69Um`ft!ft)J?^#mfd+IjIV|KkHKb z$n<`OP%kE~VhrQY^~yCS^$F@1v%!^A4w5fYYStlGlmG&&4_B zP~+HX^JaUtuOG5@vCqt{%^OKfi|aV5#MctLyPmD?{{~7;v=3BX95dVdIxVTZESKo`m^H041bwTLS66F9qwjHce!q!JsjtwAXZfRN%@7R?0Qi_AgIf zRD<Zo9-K$5OuicH8YU^{?K;;sW%S*P$)S-7zq|IBfK9%pS`OwG~G2 zhpsuz9Oj(k@lE-#&*PQgv4v^w8t+d?P#N1xJj}0N{OYkyhS?h*En6>tx+7LRm2Pju zwmDLfhq}tp-Lt4~#_zt*)e(UF)17X9D)T~#Sl-&F37kYC2Sr#=Uo;wUm;O1&N2`1q z>v(r2-B0FCPWS7Tmfd3TV%EqoU7&HU?Zo4!CX+5T<>@8hPB3(H4;IP#A1AqoGwZUe z&HcZzhJ`iziV94L0e>ok*QK)T1=*;P4+d54QTx~E=&7~3uZp~{z30+(USFx*81 zl>bU^zed2zvt27-?0Ki5ya#gq0$E5>+`pAVSkT92gNA4v@{TpxUS5=oar zP#Md_DTvFKA`bEiB*(i^e!O$ctptni{UzpjxGcW-sWZ$cYB1B>c*^B|;e6Bcc}b#} z%ujN&zhenS+_@gzw{_>Qb&dwqt<|sB0Kv_?vF-vT;r0Vo>Kqu1dByH%;D*sHGnbL2!y;r@l+_|ih; zs>tY`A)|TQVzrP@P}D*)=Xg$_tC@8O>EqHDa|tA8k%)D3w@cm(f+yT$lQbJ)_<41U zkh6I+K{mElE2rAHX{T(w{%Qs%^&wq%o-C=!9B!)O3@G~j9QDdlO;`2iQK;C%=Iy2Ztkmb)aY%zhJz`-vJo(OnL~Gh6v*dK*X4HoxO($93tsEq>*Q4Gx_?-p$D@GHx zsSl{N4vBYy&AC2_*?WJsq1h=8>|@+3-Ih7FcB`8A<}7lCeQB3?Hv0=NDkDq|=w$sj z9IaHML*z7TSX7y`)O51O-|tppBt_Dk+F#)vH4JhpZNx}8(rAYxxfO}RX#A%6CUdVjIF36{$j_?w;m7Et$KJ*m~y^`N6QVcEU9CAy(h z*#Ben8}M^ifL@5Yjs~7qNTNgJ8z(6|o;&%K8ihg) zv@`wNq7=V$+2ygzTA#N32rXq#8`sZg@3pWIQW*?|LX*MJw+`wAJW!}Q2m<0iavxC+ zJbJytE&KXWOYz&@7Ns-RHe{%qIWJ>XxOyDb-&63Dh7wX(FAkN|p9!-;kG-nq`llK< z2HDQ5kz4AUDE3!RbB_4NYDpPRN>Mz_JdG%pq_js5yb|P-ejpOfe+ z==_D=!-!xCmRk!#yQBwf>s^!D9sTG4yT!?{@SvCliV!PQL+|4e82sG_Ln2t)7xvVv zCous=Us4yVo_ECA0b%^gI0J^SS@gz@{i7l?Kr_NPqS+J!%5oK{_@1voOqEF`A1lPZ zu|Ub-Ru9Xp)k>JMMPBw2;p$y?*it=K-Y-#cnj2oJ^!$xQe{(VcEzvm#)R!l&*UI9XHV;dTZV!|2|udW<}K|V z%BRvz8}7JgAwABOb|igav*M*dsOfAAX)mQR7f5sReQvMNWP6eNBBzyuwFv=QD_$YWlnC-rve+ zQdNL*IgFb^&D9S70+lo3U=pd4pF7Pfz*IlFz!AXYps$Cop(;fC#PI>|GQ`cg83oe@ z=iZVcps)>krw@Zy=q2E^3w#p}Po8<(Ia;#);k2Z{PgbXH^{0ugysn^5l!_z35Gs>&gZ{o)gQ^}q)9bYz+IBEPTM z&8kI+CiW*xzh9JC2S0$G>nj_$HBtZ;B~ai{!k3YK$m;U|@^xtjiR1;+`U+hQwDqO5 zSEk{^9*7m_qk&XLxM;gZy?2RWh0tBKDD=hzX;#dt81b^tai6xiqXQD2k`^zip~Lk^ zlb11qxO1kl>2%ShjF!22VDjlBnXmJruSwXO>W2XcmUrW&C30ZDLmy1fUd74lZPA}0 zeWx+@_EVKk7Z{qIb@RSYTdCP^!12{>x$@uy-BZS_nFCJ@v_^TgV>dOhQ-@NAE>4 zBzd+*z2ip`3+^~_oo*AE@!9wkw&_vI_QP^z=~2pRqR- zw}9~W!dn3E(d+AIv!%w)rggpLePo*Fm46_FX1uH`vC)V)Wn?Q+?fDdx4;&Ar)54sR zbA_hJU^EWrt)qsFyZ7@nbh_~xvJ8&$K)}0Zp2I|f1*565lcesw2$7Xan`c<;RBqf( z9+R508;-3|mYCs_r@CY6ApV=6qyUnETuP@LX1D4Gg;TQyvwtb?Y)jb|sq*aeU`PlC zWypf^8L%e#rX+re_H{B*;VErs&ri5`7n7N4LQZCw;6dqlAOQe zB?+oQYMrt-L9~Jk+oX5JdYN>(BE=iW`q*@aU80^3GRWvbL^VNon%4M%qPpg}y1Vm# z%pIgHj${*?__Le7?NM-fq98sRKaoU^IYXZ0Avv>k)K)$`Qd~xoJZg$C8pHL?mC!@$ zFJJJ?o8u&hTu!A#FEWDUb6-8axET1|-JQZ?-15Q~PmT41dNgp|E zy=Em3g&BssAyx~DCB`v&uTNI^Zviy!wYf7UFGR~H!m(0)oH6{zEUzEx8SY^(cUme3 zRxXN`u6idtOdd!x&Sr>Tx9;FevFL@}86a;a#=0tpo)-NX`|hXrR=!zE`4*6J%mq8Z zVu6b4>Y7(r3G0YChBAAe9R!WBM7Y*f@2G3#x5C;t>g(>Q$qpf;J}f>G$4tn*LY{Sr zzK7xqAFl;}y6k*>WeWKQOS4hCHc&yTe)t*F@+K0t1H6+y{5|rfGJlXJ2j}K|VgEMM zoZe{uFGBnq?>>oXlU8u-p*SxFMTmLYmUeF9$QLI>vX-I1@%@E?Cfhr{(I$33-8ppY z%jpb0#>JBGe0l0O*<*`G6E8zvZ44R%J19ME>EQu0pZX~dxPp? zDe+l2JNWd+kxQDZnNTRC^x%1dys4RnSJv5#bt#X=bJ*~{ za5DDj-eFKqupX$|E6*Te^wEf5lR>YuTh1{m-PXn(wDb#(;vUOXuyG@B;0jqYQsC%>y1V1&`Q5KRr{3E==M`q zSlrh*pe3%!%tM6)RBjp9?Af!hJ^hhDvBoQ;lkT0oHeahs2tNR;6faGbJXm|)^YOA zz<3ZjM?74i$($~ocYO zgEY>T9Sjvr-ZhR-xHEJ6`|lF=uBk0(psRUHy1BTbpZP04R$eBViV!`nN&M0YW6f`w zwBi*;xC7n)cu#L}38$NmF9Z5wM=bcth^*pB;Eau<{OT|O!tPm1&W{uj6Ycxl5i~uAM zXjm;aa)RY5YRXZlRtH{^^FmLZ_T!q%F7WZ2s(jYo<#0EKN;}*k=1>w7kGo;mJmbZJ zaO;a5vH)VHlcZeTdoUN0c$!1^(rb2EC~P#-^Ukk?CTiN`|UWnOA)-x&e}3)VB)i% zH$AV@e{n+rQWF2@a7&Vz~7_m4c@gQV~#q~K9na@}$y z00|D_?K!CwckQH*^UXgAhpvrB%xZ`It5*ivQ}dgvh5|fMTnuLDy6+!D)eT=*_Y%vk z5EFAjD=J%-fCP;R-dzpK(i56$x`u-hNJI%`IM?o;;O25 z#2hGbHgWdmO2NCPZ{q|qyXbm>2`|`3Ie%}ZS#w9Bv`PJx7?k1|$`Gjt*xH*n;}W(N zjUe-Oa#Oz}E)#ZzGpSrsnYv&p1XtlPV&-_}#-v)O+F4UgLw1^L3a`xWrey@ z$M_wy+$ou@(sMnKdS(j_i>3|G4d*HD*SiGh4Dm<6(lTsNgBa-b7wljPT47pde5G*I z+IzamOJS~UyM}f;u~EW`KR%3XCHxj;6(*I z!A9>E@G!o*K0;+B@ovI>*3bS`+PnTN8EbGla3Et~}^5qv7+ z#?Rf7R$ou`t$Q^eAYFVmu1Cc(Txz)f)F2~{r*w?bg|l?H?6^R>j=TORcEL0(v@p;A zv-#jc(J;dX&l=;&w2Ep25&DRxH36y&B5*;#@A!cCu#bIK#M5(U`;mykE#;K&$|;(5 zoi+BXA^w*kSTs9R*^k4Sl**%^D+x!diSkXL!&W85W}FVacs5H|7}6O-*z<%`-K{b8 z@MfoYSCM?XIQ^N=c2#D@13&rI=FkV1+%N=u$Nm(`c)oV>WI5C+P}FBCkYKox26Pn* zwKnpx2vTdo=X4PZ3y1`(m+;~Hf;qnjMQRW<=G+Z{yfiKh3-Xsvrp7=)57N0#4foLZ zdZ6&@t{?7h7$y4~L2sv3j^v@-icQq*V12KyIfoi_|Gq4L z6+Bu~WSAb1WNzZZh1po}kq$5Z5}2bo+wZ{IuCutIeSg07U{Z;5wMO`Cb3|?vd==X6 z3ZXY`d#W;(tnb8i`1D+BDz$H^DKJ^qN8CEuIqNYrL~>zdWb= zTdKyho{>Dg=ft(>`9iE=H&t8BAYzij%ViEzF>=X|-+Z_bkiEW0W>cX5DWVFJ`H*Hq zo$3SkccN@wP|IeNynu2SpKVECtj)BwD}*(Ig4uFQ{skI^nh#y$G3D#eOTp`f#@?4S z`OZ^9m{q~-t7f{2+k|wlhm;bAe5w;PCuD$AzlbE%BTXS;;QrYg(yf=L;T7Jp>G>r? zGW$**!q}E$`~?VkX710Xs6N%s;JnA>L0Vg)dqR;xd8rvZVV3mit||K4e63J(ZKY|# zm`G0HW6oq9O`^$f!$?N6SV@i}2ZIVw!=MFsEZ}7Pd^@)NOL)C2L(7;(!e5NVK5@~ zyL_vs=Tq~hYFcZ9REq=#U#+(4bP+$hj;~v80Vg}>tf(MrM9NVid?q+FUZ9cIojgH@n>uSY87s-d zdpSPN?#<$drdB!L?n^p?JWskeP{Jt3@+X+BeBZn5EPzI?Ve{YFyk1pFYfc zg;~gg?d`cpLuFQRJXu|CL8%Ao79gu-gH_b?Lt)3IfIuwW^UFf|4v$Zq79x#UD?)hH zbBs)nor@HTIOS649ZMR;9Pj(*Ft9p;;t?34( zFQppGxRpos#awIQ)BOJCKp6@N4K3_+A8Eke#2#8ix120C-j%JWPV9@u(>J=J#93)S zf=JoiItCZr+MknE`!BNTyAH1ozc!j-O-W89+T{o+?_JDJH|QzG!z&qF^@(0n9rE5= zg$lqyPXcGm9XAW9Ghy#4sie%gBNmocI8JzAgnP(w6xCVjJ%b&8LR zs>kDRouSP_K-b^f2Tx;0p%)%eAqiwWoKh3>Nb)LU!BE|Slm#}WsR0&Rleh|)2hHp`BQmA&dnm#E2D7K?@09SesaUck zm}AwmXPw)1jRPx4C!Pqn^GAu0_h(YEv(`mLebb*{I0~;;Uw+Qoy_^<5x0ax zXa2y#fb{U_n;~$LB1_)@@kPvuS^lkB_gnC0LPL;$e6y#1WW<{vf48x9=d9~&7g<3r5BJ-$KeYvD=@!P)ts}`{bRU~`zV#P3U z057g#I+r}{5K7-Sv-p)O0WLMXWw*dB>*n6#$I%VlscmLDp7)cI1o*tHEwxyO;c4x6 zFD^}}vxW}b?$}9M%r?EKXVG=Yt_|^=%I5@f#-|A)5T8O@B7Zk3D*6cIj6rcLuwR7!|#h+=9%4TY(ZXMa`Np_5tiP zca~rv<9#~7T=RWiX{IFOb^KXihiYSD!12QU+)o#20sG;?Lc42&ZzqQ+5ovkve67@J z?sK>^YWu$cH)VzBHd+iav`?FeI4a_;Cx;iVm5(Ug=TPY<)XL#av*(?!dxX zIoreh{#DXzX=__|x}&q*(eq5}IzH}uGI{C}4zZ^WHcbrI^~Ybwbmf;XE4-V^93&Wa zLxqOQmmVD=>wU{R^JX3<4cyZ=)yAvV39WibX+)shcr)#}OTh2;QzF+M$7IU~9^(2z zo2^&Hn1+&s94+~@J5iHYN(zm^Y^(jJKHi5DR__WG@7KSkeDttsd5yhjaB_c9!&Wyc zLTMd{LHV&x+G;SA!K0xt7&WE%Rr--(N+3nT-)egYZv|I7T@tW+OXkb@-E>PNq<(dS z400bR&QEDWnTSG}BHot!oT^tlox<;?w*~DDGRm4l>eZ{B7T{_vhEE9G=oC1^*-9`Y z<0kyZi~n>oe6OZO;>+k4eJGH^k%6KXFCrMhxxsyUQ(xMt1tElhoHqER$G#->M~vNh zK7V!w&w%|{2P_y@u{YM$42%R@UB4N`dR(w1I3fo!sOr;x$iG;0g3syfal+&UV7?xrPm0- zX-)XQODH=1UBkSt7>pU#jm7R-$@3r)>6S zX`Sh7Vakv=`9<=Nm5UvclUKI@WfieNub|bsvpvkojh7+Q?%vp@eKXY7=2Ht|=sWc3 z*jFVD?P!)-4UUL`K${ab4G@>KD(386;EEQaxsLXD3J=_2q33Q3g~GOZaJGDCP9rxc zxx0I4j`o;qJevOvE}e6m=Q%qgEl6)`3Lij#8p+3aiw!b%k{cy z3gvKXnzPNvzL{_CxoWI&+?DKsAF5n_jPN&5UWB6A-yTq%Q*(Ubv~6#aoVFz@(|mca zBCC!I2S?X@fMXUC{#1PY)yadc=|=|t7i;es)npj1Ytp+&XoB?KOM)~(PzXJMbdbp^~ovnAb9Q3!Tr;v#^2OU6ZFQ$>mnp>!+t&Qd_+Aq&NH9ww4sq zGZD1~!?@)!!sqb&8i=q}*kL)rCE)jhHxU zIUbesFXjh?#Jn8@v`wICIybXgM2P{p%z2#Lsx97Vwqi=9H!AGM_=ElgNUCOn7T7=h ze*UEK=*skyj)~D+l;BI_M)o1XUU-`CJKL~oFbUGwh0^@-ggKx6XfQ{rnubotY^nJq~1AV zeSI)|w>Fc`C9XA-3ELhyzuUX5zxwUW(RU3m`jVWyvp1vc zsrZ2YA0E5KDyDkW+>NV`0ZFl(E7GH<<-;%!JB3 z6O(?F!#my2PWF9L;?LXkKR!h*@yMrnN^L>ZH>Mp5ujHZ&@?2_9)myy`DQLeH+x9xa zoa7=9IXjyI$oc(!NJ*76vPRrx&(Q9EhJ9@vDj%LvGf1yZ5Fz&ukM+jOU`7#=8aU&P z%YBT<6iUNKxB7$~S*Xkw7>d34RYKoXDIK$ul{&+B5X=a{wd~}Rz?RI#@0l+$w7k6w zM@*1Wna6IKcd7me4ofmB9XKbVkpJP~N{{spdS#M>Ii&IR!ku-UuFUN0pzhq~m&odzFn+Ja-BDXbmu!UjrOJQ|;YZobDJSRE} zoI&6PLAW9H{dVrkBzl-V@iL5>f*%I+bFcUz@S~bh!hh$m2O<~AS)mIDA`X@pQNFBR z$^Zc=prXdX)Hy?sY^{qHEY4Qjiv(Fbu%Fkneb;#3ywR&Ay);C~rxF36;k;O|39cXMoY!@qOrC_sOXhNQ z0)u3}z8{YPix!3RW``1lR-7`Ez z^Cj`Kt?lx}(94?P*3wn(A%~RA3#rRWbe=V+t#jGrn7VMDpA{j@c@^|4>AT)P zO`s_cO7;S=i^9!Hv-{cLrvpp7>f^)i`wRtNT8?Wx1Rjp*2rj4<^kkXj?D6m!JZBJt z3Q1GAcE$A!PHd{HqMAy2k9zec?E;jr7=<6p-FX@e!Qwp9un$gq<-zHOS`|$v6a;eYJecx`WC|bmJNLEUs zJ*Xu0x71AA`g5eo96Q-oF}3D2Sj0bqjizS?7=eL$( zX+8Ek_h4|SI>gBAn>T5jsU6X4qVnG|m~jEJTJ84twFnAR4~i(l9^FW9Kj86P9xI$% zk5P#lbef=rG=ds3mtOy&&T)N=7g{GCt@I($^M5wroP=X7kM6T`E*mwUmCZPvtn1{$ zO-!YBk6J8OoKwim=txN=TaN7}bsENl6Z|eS^~z;ZqnPzMS062`A7%$c)(xJCWad+# zII|21R+#Oio%aNbj903@Wp@h7l&RJys;z|r9Zlx0vh3&d5H%@pn5f!@67E+&zR?2E zzeeOOE*;&fjF_xnS1ad?ZTO8=vspN07et)h@w1j zg1PoDI(AFL%giPEW<8rbG67d<$-ANZR<#MZgv=?m<&ey;k39;a;eCzA?XLu$Xb?t^ zf~JDaK(euWaUEKb)7{CLX3S*lkK-xqQ#0WR8S!BkOgx9jHXb2Edum#Rmf0^9xA45l zkMwm@jRWX4SCRq%)c3*wtrgD)%?5?sZMNwh4w;W$H7r*%7TQNU@zhDbI-SaiIwLIa zavK<}idv-!{Hd}MRSg6-62t8l~U z^69F2(WHpm))2dcZgIbY^o|09eIcq|g?kwzKc;Gmnp$HiGG%O6=80ntM~3tp$lldJ z*h7>ZTQ?7V$2^BNX~sA)EU~Gr(t*erMJiXN-ES06tFKu|o~j)-ss2*xh9lni%uQoz8-*j(B77DkPBKq9-wIy6~Qxw=%=^q-5~o#Mlg8*ccq!B z6mb<%_^4JiXAO|=_?`hUQc@>|hzi{5&fXJ(>E`J0=}2sC%Zx2?S@(K;{7PiP%h0^3 z)pq~Ua4OWLgD77We_t?WtWhXx<2u`2eQkW!8oh2IT1F|<6To@DI`q`apm#jBt2JF1 zpr~kHBWkw)x<-l2@7b}nO0U+VDl5ugYCBOP)>c4h9t(*$C;Y-q(wz5q*?tsnO$^Lk zzy8#9Na0TL!{$_LFVf_$Uf`(!C&Rp}VZFGc={$`u-#q(0vO;Zs5`MB`+w%WaSNPxG zxf^DNHNMXVBkywpLdUcUhY)JV^{Xe~0(>w!^jYCwt zL?j6u77}hs2QBHHaWJHBdt$3Ul|Bib@)jUGIU>Fu{jJ=xTdy;E9U>4{d_u|a^%qBY zWglpoo0@_`01+9P#FHd|EKq-Oq}u@16&-vL+N)NTIm)qv)_QaImDRPv(&ezWHO%AQ z{mQ3a_k>TV(#erKA8#H2aWduKe|TcLxBMc49UVeOT%YNv$#!wo<97{Wj&_b)cfXal z@XK1ih?AQdCLsJDo*)*tlaES0-d(IntF_(Dly_s&8J)GdLP4J0=+oV*2f}l5glA+{3N!b&l_+Sh@dZ6gy z$j>2L!~$QUX2&ZL!sN1!Qf#vdLX>l@Xq+(EEACZesGBZ5O|& zwWYhIVvpEjSDF{y zUNo)PTLNcT(KlqrYLfT_g#1?EpaRuP7FiAQw|QB7HKB|Z;<@8mE$j4a-E?%b+NPbE za60YBqzz8tfr!3vy2J46d5`2fi{XEG2f6>#!y5O3;XL(_AoK8~bEa}%ZO2H0(z$9t zVg(&h>oSkSDO{S${Mvz{(t;E{v3c5J_b%9Rj4d9?xOg zcF=yILa<%$)zaP}#fN`*gm$Vg_LC2d?orbY-l9}YKNM;-^VEz7U;i1+rs{huBdVsr zU>S!JA$8RMwd^*VQ+~%w7NdcIZaE2TIXJ=i0~3}1ziVW=(mVB|S<19uhdex$(?)MC z{SQ@HQp=U*$YK~;mmKuz2A**bEpb0r9pVq%=C(h+Ychh5@&90{t7O_s$nE6y@|nO{ zHyTP|b_Jo%AUXh1gIqFV`%!Is{>1n8UR98+tAL32ugb6p<#)|x4#5-Z{0{U^x&XIh zm{SDy5H{h*Je8L@;KaB-tR4NcF>BO8aOG26U90uv)G-%7RLAI$i$L7u>jv}?dTlUkOZvY|^F&jy zNR?2J><7drHz~klBNRGOyKc68Ql9MNd6?t#_x2A0quL39e7uB8TvnM1D2z zi`$m?+5mAg)$4?=Veiz;I?aE0z0lhM8cheLd@o));#>JWMr?afZQB)Z9;sDaqf6B` z|Fehz`UHsg2JcpfAnk!Ns}5K8E#k*+M|y4ML&-y8 zBnX?bQ*V*zt^_;kJw;ipUf!VXL>*n)O0u@WWQZ!;G2Cz{><8h!w@NU1vK)9(g8xo! z@{qyAj#GNWMZd5F6O+5iVgR9kjepLbG0Fu~OUtWH`7R;hiAX^X^CU}HiDcfe(8PhM zXbL*IZPL<8fHn9KKVirKFqVlB5~SsLiKcXekZ26MO#Nm#!HS-oLEVQJ>c*>(&B=a; zLyj(@ACb zCg>j?g5I%aQUpBT} zI{kHRk!Meq4nWXbslXPZ|MYb)*~=Vhwu;h|ry9)E^HZnXob_NPid7m~lsVS{>j+ z0tXaT@cY&;eYquBss5XeR13nNxvc*VRj(M|S2@*0qn0@~9-pP%>SQ1Z-N4 zcT&Y(=InS#mGI)UH1J2@-sd60;?!N@4BDu42LuAYsQX6$BI0NVDQbbT zWeaC1EY4}h6^^xk&yAB`2|rZS5}Qn8x}I}mI;1fK89bbO{a?4}1?7o5vlZ(HD`o-P zH{-YBO7)b6*);kcmxz?Qw>e4s;sWq(Zf>$TFj1T`hiq)7Y;11(qS2VO`m{yMCR194 zS<~K9HQNYnV>*BcuVJ)4P=+q}EZw_F>1B>(o2k%u@dUAWg*~aO5*s2H2E}0V$3r!A z^2~c6(!EIH)UgfW7uD_lwKpKo+pwctCv3IBv1)R|z{B5ddw5D^9XwmhK2N}b2jh)X zpMPQl93Q6VO=q#V!+BkWOy1VZ)Y_-Mtv2U;O23T6zj$zMF~=Dkx%BbiOQQknWo1Bfw5o6*dW#2>6JoT}mw6Y7c!;Xc!;h}moJYm*u6X=tbZ#+HY`Ty!yE zsHzq>BNMy*zxz^La5D0FZ8Q=-(XBvvQ(lBhz4_Lr3Xi5-{ee`#qu_dlT@3FMhPVO<6gUm}b`AlU`W8Y5!w3$s`5w zv82$8Sj1%k7}mCZHFcQ1G<|d6wTv`H)|Cu*BSk6*yGlLD$&DMrI29Sx5Ju4tjYgOVInW0rNn=0RQ#2P z>dzzBN?S~-LludN6)`u%1iRBKdvFw-Z_;h$Mk1wte?M#SC{f{HaCzi$oJprkRRgh& zagBjK!Yai9{1?&IN&7bP4E&}Yv=Ne4e5?FSnb^d}=+9L1hl@$3qegj_m#SZc1?%>svr6AP-|&_YFef8unGr~2 zf&10}egpWw$iDSseIPf6i!YNQ?T)a)PbAbgbv?!%NS-9OP&Mg+=EFm>K%()mZ2?-f zKU2=vsa1{bg~Kzp+|W0p9Dho1vz!w;Iy6Kdtyk=Y84`ix)jx4JCEFEtI88||woO99FgbK@>LAa4@dsP!x?I(6jA<-IE##*^3BVCc>nNpU*t3!mMsj{ndl4(v{0&0 zaEH&}+P^|SI(wHz@}tTUncG(k9>IrBvk0$zkza)#cwD_(p& zS5a+}Qp0J}M>9f^j6J&~VGYM_E5QU_Q0KbbC)6vu;mgggDxY9Z?OWF)lN1-1u}2mm zF5yKtFIsHR*$-FauR>c30F{LEf?H{(d;Ch=PYg(?pkOli+a`M84CQuEA|d7W8XefE zyYWm?hWCAFBdJTqiPU*WKhGi$n**Z%Ly|Lsi&+d3#JCQvPdY44%v5T_TD?(m7yLFz zaBXI8EyY1fcs~XVM$zAA9aS7|hMMl0^qI_inwrEdGHUz0pt0>2{Pr#eM=8hY(P8}3 zc^(`T#@7e?Z(@JAT}n*W_`CBIt|Mhb6U1QMSf@VvqQ{EutEt#(%J=f*uu~q zR1&dQAQ1F{wVb<7lTcN2k)?gyQ5w zry!b$Z9jdcpp)@1poxilK|gbC7dI`FTQ&LV2SrjslOxc?=RJJl{_zi9Mv{>^OZ9Jb zFA|S-GD*sLLBc~G6%wajvKHKP4&UpV zN@E(3nM;RSiw`(TvKz<{wNkKgo-L9Sx^w<|CWl-H+w=S5>+>Pgdyqxx8_|O>* z*KC`yR|vBI`XF5hQ8JRY9=xyNK#WMG#dU>x1q}P&COW}-8Z6!bI2#uj#o)JFdF=7gEAxL$e?wbqd2!R<_azPV5Ph7r7#(&*S9KIvZ5zvx<$g4H za`O)_&D>w&KgbDX(${jAdtVEC;*%8g<u?6}s`{^9VJs&s<`&aNep^T8ZYpv`2eSN| z1(XLjAFf`$@|Oo(2kzkN?J40*OJ`VJNu!3l97+{>RhPqDZQGNk22xBQB#}>HL^GI@ zKTVdB4%m`9`%^p8km}5yMcz1xC*DKf03C<;^feG^eA6t~bk5o4=3v$l^B83+dxTWR zlJDUb!?j+yZSL@$g=CKdt4R$pl_^WT3ip_P=zRNbgA@e_NeAEL2Wu;b2^8|f_?`Io zJ$1K=4Qme-h9rjtnOsR4bak!XlBz1uX*r*Rb*Qp8R6m}lXL2005P$x6ze5idfS~ zEvDDr3-zaW3E5jQFAB=kgoL8B#Rs1_e{5277=ve{g1P}V(qVTlWwCUwOI2-#V6rAg z41mrTE1|&Au|H{L;$@BMtrkk~>4(5``m=vk*_NvC zm{<+BdUcnb;hbpV8m`WnS9Prj+ZU(jQ9s>ZTnGfn=cE}<7RqIThZ&d(avSygPiekrQ(Lm?bf9^zQWAk=>N#y`;$|ny=VT6Mw&VOcg}<)?}&qYYTiAO zzZpJlsgOF7P*>`@&#zWCIwbFi*B>Y+cqe0jQe4B@RQe@ON$A`|HTGzQBWWD)b5P4H zT=R>C2ld~T#Ww2$vB44#Z&8ojzKnbwo2|oStp0d#9+&*ik_p-zJyzE*vJsg%5NGcn z_CO>O!-Q_*k?KBD@L#aas$hBDbnY#NO`cpaTnM3?YvzLghMJCD6OT(6^or(HCG9_{ z`Lrk7yN1TP2G_!B5=j=ihU9)(O>{&B(oHY}2)Z2Z{}zsZ{W_`2LP8*j$8$e&?9zU? zqv~QQ#2|qCTAa#tb{qiFwN;DPJ|j;_F@OGaEP;NYiC&rM4cpoe)$zbd%4VRe5uc4g zYkM>7qbxk_xA{vpRfh<$77%RZAcssPe>l-rRN%ki@ZhMl2FKO6nnDX6M zXaTe|LlVxZJ%Cv|D}7W$!XW`B8jy7W59NLSVSHsE3*Oq+^*Q!`HHVCIy`f` zINl{x(+{50l9T*pn=?s54kN|yY?D?LuZ%K1zES%vfcNDKR3iT zP$^<5Gu9iv{m|JIf24%a+8YwTcr0|4ZPCm{S?+<4_k6~>I9gDT4G*yYP7@ux_@jEy z#cj8(is7<0Zg3M_Jgo6!k8fI=N=?;ch~)}Kq+;DNmLZ9pZjj_Y{n?RF&SGz$7kjjU z&-mM1vv<*SFs=+Azzld*L~EVOlunTIbAWNIGx0Yjo=%5@scI!5D{MHg<$FQOBu~Pq zovFM0!xI-q-Qv%TVh+(QIWx76M5zdNN@;(!+o8x2Szqg8;v%$(&mxdnMkz9r!Y7;O zl#yJO_oNOa76br1P4F7CunJIypJgc}iUhPB()!9n%O0NoS{VJ{C-Qcgl9919I-&Vm z+W*Yn$)PJBuZ~4H-&)LU`uBRpr%@laD>-P{bH{F9N@9CJ=qpR6!A-4CDXnupd>qD| z5x7KYz3q;$JY-{Yz`{{6O3+~9M@^rAQ(0X5!AhI5DrIgP!I2>TqhW{6=teb4Jntsb zc5T_ZvvqgWrP?m$ug}G&7d}x4qlh4S-A@T7H6xFr=c8{sQc~08;Lu$2WytcM4X$NO znL?B#O8^7)lm6q8)oxAkN7_|`c`&q8P9X4SlOvIj#=SFtQhnRl_2!laUlkvg9WQsQ z1yhum@z<`>+Y05^^ea90?uL|lQ7V#DKRJh47Ri`uo-Yq=R@#Z&aUO*%7J|C=3@{hP zjw}!wCj6iK7EPaDQ#-*-KO>pb;G0aWdEvp1pI&w$L#sCnz6E+a2iU)Y9m`hNklk(S z#=ngzE8=yiH=++!trShH_{gfK@9HQck$ld6_Xg|!Ei5KUnd1%1Q>PL<7tn+#D`^Y1 z$wS9PYL~v$e$i0x3E7*}2#k$fy^wq8P}2QtiaVbMtLGYjO$yho`V+{aHp$?nNhnwT zHHDZuPd;ab$&PFH#%x;-?tC` z;UNdi2{X4%tXm^#sVz;*T-r<&MNd9IdzdRMTVh#T@c>qx6Xjj~ek+giPY0kv@ z5lK&z^2JRP9rlH8X)}DO(j~`zFGdx2W2-k6`4+fDm8%mG1*Kiv!)cP7!ov8SoUImq zqsv}BvO#@FB1{#p;r)xeNKHiwZSxBh6`gt?)h&c`nWPle44V_~Y|_F8uy;PGh2h~z z%1662QcUMB+F(x6=~EG>tW>u*05CeV53PpsonZ~Hw<;HB2ApfA%-C_=j)YGu-}Q#U z!lchNM7x+BWX1cRYn!LOrW(Xm7C^e|(>sgXo#dpT+f6Z(+WD?dcLl9L@M)UC09gOh zm*Zrlvy}~JJgvl~Ge)KRPQKUm#AViMrq7b-ToNL$Bg4@;xCSs8d3li-DtK&sCk#ES zQwlZh#2q_=w3vChv$NHGbcFI|)&J6*N~{Mm;V&h=a`HGM=jIj_tvI|uCN)ZdRDego znS<#v!yh`QgX=6>O)R) zKRmY&Sf(=wI2_12z!_&-PSi~lT5`Z6i1_k)!GlEGBqm}`UgaCcFwouuN2w`xVC}e$+odLVb7IpeysN>18wQ+v z-2NMRXgDWM;8Qu$$;iI;Ocvn5Eag(03+~`YKlAsY#*g&jBc`LJef~^pIe4VYGF`;< zj%0&ULi$V{V|=iw(b0Kj`ugdj9Pbq63k){*PvmcgT>)G!HGXHDyaJ!z ze?vK`s9T{?^dc?oc)geowAlQCIkZ9B(1Ma~xgc2^wNRfMou!o%Ah9tFCs6S|8_P)H*n(z&Z^l_q$)uE`hOaHoQ)D%r zWf*_ltFQ{vZiIKrcus2h5nHDt{dw>0{P$M1$4 z5nhE^{?NZ}S}nSia{h#7QpZKNBkndg<;^&DwoCKYo7glBXRC4R)sR;v4K?-o0To`$c1XkE0~)d^ zt|V;$51kZ%7WxlQPul)YbY19Hgk5x|@xxieE_C!ES;={3x@gT9fA}lD2#EJs!U>M5 zq1CMx9`>vgY87}F5(ME}WiY$5+BhW`%Gu;;)ZhaG&}i`DSr*Q+JpEho|MDzf4hPpP zc(rPb$fV2|F(V6cqiMwLroG{10=s~+xr>va@Wi6mf|dqJ777PJ_C6O&MV|tZTsVeJ zfqUOOHSWTN4Y?Nn@P@-;EpvPGC5s)Fr>INxVxnv(t%mc^|A&C$f2o@O zU%k4N)Ax`i{Z;t6;wm$TzlLbf?5EA6*Zot+GXQztVjpSbGhhI%tSP{>5LnNMT2(IS5c)796 zddOdvH(`=L^3X#pWkaKpURX1vh2JT7hOJyaiL!7Vsx+H$=mFeaW7^Yhd*5xw>Eawj zOUs0J|Jrtf5}7sd2V?`{1NdMz*fz3GNLgHc47vhSvIBZdBCJd)IPHkWK=Ry1<}*oi zPadGDB%K0}14S@#g`pR2wW3)XE{pE@3$k{s8H*HuoL)7I2bD!nEaUO)7oPCa@(|7L zdq|Ky$2i)%9723?XCazOO!#u-bWYek08sL4!c(;J#hvHr*uL??bg3G1$33TzksKjx zanj+=?wK{efmu2_2A+kfQ~1#CpVmOEFhpsdt+zswHeZcUi2Oq$3pNdxwIc z!t-%r^a+O)@Xp`__^@|vSvMG$mYkIld*r%A@p(1q?v*@<=>iZ#{|@ZC1Q&Nse6zap z`beI40rRuR|7QpBz4y8bnMI4{PrlnrD!*hN0Q>JsansG|7%3C?C<@_RhqaZJu{n#d5PtyEan#Obv|PZGMXa7CzvSl6-3D+PL)(kMcUVr%{nQ zoc3ss^e~{SnsGS?xywV9r2J~9=oGBMIvt+ee@W9DFN@GqL4O*Wb8yWgaUpNP-{a;+ z{-pU#o^*d78M!5&Q}KhonZ7o0i>>Iz531MvEoA8;%iwZeCntfNtRq%$S`Ltb6phg^ z2LA`FQvc$O@AOUXB(ZRQqD|-vLlCGrU3JryDW!T*%S)7>_k++k3z@aA*)my&7{9ag zOhteB$v#u#qfX`dD;)r+nU+NeVooR*!JNUfI7h7!ozZW31%Adj~k3P|J~stV-?0KJAJW{#-HldO<8``P!9*q7^wsDb*Wd5o)rGPzy2Xtnb~7xF>QvH0CHYD=3Q?1A5MX<%>8A3+Jg+p<-3rCj3QcsYjyoJ&bwJ1~RWu zxczMlYLZJZ_uN&@vAOck2UuaV(UTOE>CZ8#WZN88qB$`))_a)mQ6&X&7D2}4!0Xt* z1;ju~60zP6ae=DuuUw+j==izW-nFtttT7i9pMGo3P`M+X%w8TghcNRLj(8DRl?Ol6 zM{a|i_?h>V)&s(c!-PK}8jqIOJjU0_XFk_1+q48QL~#>614n*b5y}$H${384=Y2Zk z^E_ilY5ULDP1g}6n3|g()xsO69l6ux0ZWId;{FI0#z-Jj^E?Tp3m4b8|B|;{MY{Gs z7iWz_);nCF3KUYJ?D-#oDvv(DyCz(qiq=i(11&C4HA6@zHHw1l9XB7bT=X12*o1xY zr(UR#ODql|%MC1hrnZ(s1&&yg6N18Nbe`CAmS@sdRNX3w2;bp=kD|eKxTn&5xaM=Nsf3rLo|6;Q zND}N$uG0}c7CiDbimmgRhUKV@LHbSo3S$6?YF1S}{+@&pW`zDP?Auu zo7(JcK3FrP<9m8^8Yx2WbI&R~3H{oaYsTU^I-fpOG|j4~+0tqAb<+q0eQ(L2k=*)`vmOi`Y-B# z>43E&U+F-b&ib2Pl%*_v!-$ex?}+sC$)n9b*CIzTpLWe}l8ks)bRs`3_eQqt3Cat; z{^)9wen3DgiS_meMlLHpqCYZi?#9Z;S9@|?qH;m#NSRrZ&o$m5Q8}6AgSkXQMN4FR zGP<8h7OXAO5M#gh4TX#+oQ`wwN9=c@W}WI0!}Ch@NkMV0j#(@`h4Mj9QH_HFWMRT( z4IjE_EaVL+rO7{+P3Uc2^po#Yd$6)hz|CYw3>tB(h~S6)w@R zA*( z3zykL#+Xo@6tj6v%3Jq+!WG4o2w!*M)`03-_q@zZPx9z#XLm>1*%=6RI+ zb|E^g`PJd&KZ>|lCJ#l~*uGqbni%L*+ihjq`K?R&xzs`4G^x0Yg^h8h2KGaOM+P*i zl$RH$oSMR8LzvLbV_)8_nf|h0)TYT;e6-ZOgoLLd9JBHPzKR@xC$_LBmj6FA!SB!8 zexvr;Dl#|ZXI>c(n+l|*FIw6D!*l$=4VLt<8>_WL`%3|ma}vY6J>45SfVG`HO^Lci zQwQb~+aoRdRne381QavT{<*zF;tI#ENxY>on%Pg+nK-6gulGuIH)-4I3!Ckv=xBR` zaD2lMs+j}DQ63_rx)Dq-j-Fmt4f45bsu-^?om6q44nAV_Q87ZH^f^9h98`*_9oC;W z;%1jvN{-8>rE{PC1obUu@8r3)Bq!02_GyKmG@6u00sa5*%!`t^Vf;bk&E2jN?Hs?x z&8`J%2$#lrw_(n3A^7Em1aA766o^G2cbgZ7NSu?f#DF_rI-nE|GQj4KcTf4y83?@g zqB|SC8B#=rZzf8#X1@Z}wvhX>#y_~Dy-QyVLMH!Ggv?xOOjq&pccu!a;woU}NyCKz z|E&tlLUvF9w#aQL-1GQghNJKAeDxbdYDdgcw@S+ZmG-!yD(4t7ML7qF#4#t7>uLh0 zmSQG2%JehZoFgoYNp#L`djpGdZaa5wUm)i_HZ|t$#7RAR9vtAFDIM^}A=T<1mSBA> zsGciN~$tcn%pN8Q&%Ig^9%Ut`B(Prw(I5y z?aNblw!GGzY!5fXFuLBoAm)>cr%W!tM5dk6pdONS++v$HH7AV0Mp9MSo4!^M6Qu5i zNlL9f<+Do>^F4Av^G{<)MxAY$?nT7*vuHwo8XqY|m-Qwu|F-RgQCO3x5s08OOsz5} zvujV=(y;`sLE|AquR#bPMmI)!Tb-G5X!^K7&s62Z#QQ{$m*OC9h+j^NB=h28cppvDTpf zv$m00L{e+zml{H%!H8?)#tZlbP9xz0FmtB@a^Q(QQ6AWhobRChX?dM zjX1NV0KCL?D-NYcLqSce3cwJssvU=}~arHf=Q39oX7KrJL_4q)RhO zRP^c*h&VeAe7|DhUKZ&_2Uj)Yfuk5EyWen4e9X>gT&-{F&tG>7|EJls724BXWwv1* zAIlpxW*y|sD-#9vEkzVy(WX+a?$D+=J1$S!+Il~~!#aD!w@?~_4JFQs2)S$Oz@M(e z-t(@rgCgE;qYk22?t-8-AzkaR!a0<42g~DBFo2Gq9-3?&Qb(pKjYH!e#AcSj+HPuH zC5vjgn^PJ+bET+~1_NG(Rs-0da=nv?;G@6B*McT4z5ZOQVIRa1x?dI79NW}wo|6Fk z_Sy5HdGJR|qrGbjhMGG2c8@sdIy~v?!_VjbzyElg4ayQ194pN|D&lRUcB*Kk+T&SM zpdVEPPz`_)ww)teh7->ur=I))9k&sI!CkeC#Q1fig~ZgM zQ}kk@Yt6BrAMHZ|H7>NMiaP148cqr>bh59(w?3=L_qz6(tG3b-px;(m&De-{Emfuw zHIt$OBuDVVHJ|pUcuT5;S}I_jE9~6&W4?BsZviKVsc|Q`n7?gWoh=4LrJTmwE|!g- z-5olAPZMT32ohtl9}5XS+d{cV;}O-pk86!U8+KOwY_r+Kf21T;nZE~m zhM5i*GyG|34@6mqtA4MtO!q~@+E`25I~Wt^bGwk{}j zW(EWRu5F;$l=KLA8XSR?fNusZ6g~L#hgt5_BcB$e;&SC9Qg)9oRvDD1M*BHO$nDQi z3IZETM1}f^;R$k(S^sFw5_qVES%jD+H|3#mLSHo1lx?NEyMf;~a~?|4VEfGU_i*kL z`v?9Tk9@RGNRCavj4g}&ZjKLip(^okh_3Oh>Y(9`b6y1y?zyo%W6S!1jb~Tcht=0EzZ|ML77wAS zllNs@-w1pT3cKip^1~i19GlFiA>D?wBqJf2HB{$c85q#S-~ULqS3a{wFVdbS_M&xJv5 zUMBz~Gc&qf=JVL+m#wFuQS15c>e_O5J_p|EFEWJHxKnP2bRFIUQ@$-iA)}b4?#M(< z(P@?8Pkw*j3UL0I>S{}(*0k%1)7iH@0~Dpc6(28hB?)!@?m6mzi{aNgCgI`hmPyo} z3R-R4!0`1Q?X*_ zYSJ78j+zX9R}6kzOs1)+%?*R`|KAGX*3<7at=G6Y-Y12UL?t3oY zUZz~nG#UqmO%FYqkOzVf##6{LUPH~3KJ#(6o_l(lc7L&d zEq^WIKJQh}qI1lmbisMI3rRGBYKDfsr$1pV1TRh=wD3Px7&`x_DDkV6!Y;V{FYVj06~2TcorN_Z~# zx>_*X3am~-AtT6bF{MlG`36P`yCZS zvNsf}fgxV2BNCGNuD}qN=em`Q0LWk!-w@Sbv^>N6>NIA+i%E^w`O^n$8|&2_<3(z?JnD#2 zO={biw6b1YKR%Q?>@CtA0M&%(I1z)U0(?*HJv?f&PhSgn%W@d*J3fwH{69#0%b>R3 ze(RUw))trI?#2GNyM+dK4enOlwF&N8ptxIbD^LPK0+ixfoEB?=;?k3Q-}^b|%(Lg2 zIeVYXBs0k*uYO6c>ssHn)~DSQBUY}&Ea(D8%+E!+^!t7LuiK z1#%AgQPUQE==AgW!+5!EhwoBV`0`}X$t{!kh#^U$d*@rlaHll*EG6%%v^q#Vd`V{M zW~uT0e|K2%U*Er!CHZ~tjfK+p;$hKXb$2%S&3XYdKBiLQxFL2P>6!~BalJdf!p@fKUfH@C0atS$a$Qg7S1J%x%J7Nfs zU}7KQ^K*V;WL(iW`C?hWMc8?B2#Uhp`ct`8wGzFDa6FhTZ#VXNj`&jW5)P9Ud6BPr zeQ(>Fw_9sIu5$l;ORrI^6|Npcgq`klYeetPu3kAW4QK7<&yg9 zKwJgRLd;JrBS_3&?IfRYm@Ia8yF`hMnZ{c_7KR%pf4TC$Ib~6DzHnLeK`DA z?NUql_0V6Gy`LwRPtD!rI>kRDA@Idwuq~dH0HT#%3}nf@lY4vn87%9KEMt=v$*g66QN-1~16quO zHyIfR4T)DxY90VqAX_jS(ho&C+V1h?aObO>9gbB<45BG2R6iUYe+8#)D@|M{^msq-nf&)x@Nt2}gz1Mj^=~Rv4g;Ifj%i{5hm?+C^Hnb&D z6lC>T$$^m&_7P4EzUGI5e(V3}gZe%BT{PlgnX||i8|N15{6z^gDFumQBSj<*rgVX$ zlgDKBYY$&uw{069NAH9N;niDB^<#5IVEOkU@?lo^&w5Hm2dOQF!pegrhzFD8FTmqI zDIKA5KC+cSh#{Oi_;;bKh^8onGEq1!>5KEBy@khIGqa}m3$dAAjAL9l)&|Wtu z42eKUMs9YBF^~ZZVme~tM$4_jVI-}haOp3~#B$S9f_`wYhLplMN!`+g-~P3|r(g2i z#Ao4mpn_R!?3D6jLgc2_;q<^>kGmEBHWoPH2biSd)(F}Zln z-`yRFTfidJbCGD=6iHMNl9sEH#c%$SH7pG=lY3<4uQ_#|Y4EE*VcLXSiOOSeD3kRI z!=kc5b-KwKp3MB~YV9jlZkA~NvjPJRsgy7c;=d#miX;Q=hvMEiUuV||gk)bEfg&uRNV+j=+H zT#RWHb=>KBxdguuFZ>Q@l}ctLGmxmbw~UPT zI6j2e=jZ1bEQoB0afw4`k)!j>Q^w5jV4YR0pG-I4A9yC)mMnr&q95ys>Q6>Ew-NM2DSh9JzPCUJR1pjoC+uPs)+WV7A(Iu$6H zi9d52CV{V*=|^#V~ywLC(cMucEMa)errHhPQ3o;gAac!9>`Q18HUXp%(xznE@if8R|!Xl1U}GjELDsWegQauYL}xd7>C? zsY~2_DY+E9E~2LqA20nXZDx)C&V$TO=52fT&oI3nutvQQlU*y*F(jRUNOfX@S)JJ- z887!CU|ztlN;_qo=Y1jTy&0ZDw_?*WdwQO&>J5b`B?Qcy3oa7tn7+NJT%pPm zUUWvve|S`m%)#RVEwLz9oi$&WSb_OQ21nlKB9;JF#;wmDw>RLA6n`~^JLGbOI#9g zI9=fW>~HV-Sdpn!6WImSziB2kW~cUT`+|)?vemh@Ab=S@bLKpTGrym?8&u?83nskV zt=;O!wnjD1jjQ957-_^WK<%-NAiStNEcUy*DAYU10|XIY==S<#)Kf73&gqkLqXK@taNym$oD|oCpSZ7u zTL6E$^~n`kEjXegS_qG=UT}OMK$$r2wRBl5>-VC1P6k9KFA$TPEVS-d(9>Ho06<2JD{GxxvoyHN(vfDapvO%g=UFsO# z!dw(+BOZy~?z=pUBO$dU)+TpK@z3TnV5DS4XmeH zJL(uetJh?3+qAZQO4iJfyzz=GK*?nj*figijnp){F0|>+rz(IOXK$3LFm-av#m1Dt zI%-9Wb9E~N{Ee(sPz9w-hIqjoQm=nM+{TRG>W0+uBpL3fv`zu0h0?I$mPa9jeIQny zkPLA?l}zfK%kupf_X#_%MUj_Tl-2$k({@u|i8w4NGo5Evgp&ewA?HtS9@t8ayZm)Y zj&Y&ozYiGyU)|#=(*KNm^w0IyyE|XXAK1uHN={ocGNM_3J!ZeDu|eU$W3)Lzk@*I0 z7UbiX5yo5j=!VGF?)85iR_atjXvyVf@Rro!zJK(02%;W5lAxVIi<8B|vQbkMZElxH za$5h&#eX``=&0cn#RMgD0cSTgIPYTxsPu^Trx`#2TcPFQMHCuKuTOThm3pEpt9D`* zb%YJOP<;JA$4_DfuDHW(8dlilTTix9+twJ9s*P&}E_MI(X1N(jlykphV(@~RW1h~b zXL8D^VOKEOa;vHsGwB;=Q%0s9Q5}-Dy=&WRT_R2Bv<}Z{JjyI3!H~2DRNpHiOkJ)+bAQC4I7L=x5vyoDN}MgjE*pxF9>q zE-SUK3;b z=$)1lYeta+D!+-|70Fw3?gRlBv{*Uk=fux+V#A&LNegZ)mv>Sxt8z36Q@)oa{Cw(o zW*+>sr!$nhk0xHDPxB$k-iNd;L>&=3vd_xzuM7As9GR_hBpvUn`u3}Un7@(wzO_-> zDW7HAs0{h8X@PF|+PcJdp9AkXAeI8sc$3$YTT1S}3}GHvdzs(<{4rPoc!$%-0l_xg zyjY{rlT3=-+t$jB2ad)s-Gum-Z zbHTA&hH3l$&|La#$HUsuDp6h$b4Qv+a=)!`VyPy<<)XJi-l@YUYg_JQVmcF37eAwLIbv0b?Z(eX6&t@79{jp1ClzW`cV(==nVR8dfTN16(IYH@ z^6^@(6EBCUbjig}1Sw_}2-O(4O=gqC|3GyynTy1TfHN!Vo)Z!xheh?E!}tWB9R*+A zwBf@G7$R$8MhzESFdk1q2yaM$U`#3oazqQFa@r4A}V*vh&$Vw`FIiTPRrq%GkLQAQF z8ajtE(%|A^hxRN{WJ~Z|T_CdbHdy5soQ`_(((Ie`WU$?o*j-eG6Tp&gUtmSs=ee3P zS@iB{hhD_b#1)g@fZrI`)%=?mp6Bj}*x-LAC`OB%5c{$b8w6e*4mq3&%#_@d@@@qyzq~FVRzRtiPqn zYO>hj;>`Ewu=V4TN3^t#I$qd6bbo$j1tnX(v#BNl03LxuGm=RD@9_?oAD2<}PLmV9 zhC=e-P#XJzSTZOq+|A3`-(?r`Zq>F&HWQTz=5s0dFmnfAgVP;9XHXya?Mc^33Cp7& zh(Rd#)MXYVRi0)3qMQI86UTD@!H!wfvO+RwG3Z(p;Yci;T1ug*u>0QhSG-2@k#oC7 zgn0)^9tk@mE7gVeIb3oGIe4cDb1)HR^8&S6R_VY^QKgbwZOY`O#fn-V5&`GSft1Co z4mv@Jopjn=o>wwCvsdH~VUK^Xf$wCNuB5vEqNKs;Bw=&u1vui@BrkQ9Wd}#GRgqYD zWX>Cs^0R?=v`E9(-*DBmW4q&x{6}{+IJ2^@gY$KF{qZ<%_BZf@FHa|*ukh&R$Z0LU59f{(W4z`Z z(HD~_6kFu3R3kDu0Gu3N?yQ2edWUElzBlsQ9$b6u72`_Yl~gj_<0s$;AyMeEa8*Z7 zZ5jy$B~ZVW1jN8(!Hqjxd{g@LK~87NG(L-j>6b{zUlj05rvN-dW_0cAVpyiX2-!?i zhVVXrE9r#~;ka5R$D<035kCS+Ri_pQ#+(%yrmLz?x5|VG&z3JO)Ye5 zJKxE`fPOSZD~`NgQo|So%mfQ0Q7{?#5S#re$o@LTL5GE#FhzU)FPq%KgsxrbSv+Vi zM^@$-9q|Pl8Z){zpRV_RDvK7_k4pAr-z7a z*;CRP`RQ^AC`SEtPWF!$n!4Y_xACr`#5?eD=_ung7Vw<%DgDq0y4sSRU`tQKO!^EJ zD98qpeb{Zm_zf4PwAkH|@x(|SVs^N`1`It_%-f{8hG;h>u01sIRj427)WpD>rxI@| zZZ?^$^MHbaQsBfYWV{V|E7Z^%wG{zwq&B6FfNb^*PdTp}0gn(s{im;8$!zswZ3$bS z&~1&a&)c2CZKPowquW^NI`;+!Qdowp*#<_`H#of`~5{D8%+uV z-R?#a3A8mqG}`7ylA(YHWJf*#A%~yvQf7(_-+nRv#xQrvj(Z=fabPeyqkgql3JPVX zYZg86!Zcs|I%XI9rf|syHgHwDQhY0e43o^})LGO@e38!abFGh(ULzAAYXQi7Z#U2m zjkY8{r|u~9KD;Yif&tOBg{6evo&Wj?^443qmi`>hf2tkw<|$`$|2kz;f}_sr@*x_f zY^&6MrhfAMwpX_Y)26aLSjhd$Zh`7F^Sd`W8_}Rwq70y?qlYh6(W}G=zvRHQto2@( z=i0);k>scTpY<*M7Bb$#5vtL{$=`8|pyCmO!s@D_7`M{nvk14-yEM4WY8+Azh8#1> zYlBB2I5>&~1evO-nR5RktN;Kmq5oBH{%^h_Wcj`K#_1OBwE11)kn7H!nCj@h&LXaN z>BO;GdIX31!k+(}7%n*j7i_}11D^Bt_O)%GaYE*yjZnlj0<(RR}Y zo6ac+{59ROgFapA4K4Q&)|>~HjaM0Yt73%h(ua8xJ_dD%vQtyJ>^OQg5Q=&`D}74q ztXKPPLq#7~D^03_DQN~gl2s?Mb%KMVWxlle<3wpMiYim>mMutL5gQwo&2}E~YU4}O zdw1?_?Fj>=h)_Sqe!uo}eA1S9Lg>qEk_+z;zOKE!f}{D$lhuIA*`$7hGtWl*$ace% z=?zDgP`2f3?gBnpeq=7imq{pQZ0I_lzZ!(vyr#oR$Xw!Y=7ScGl_T2>CwO*Dlm53=1g=tH|laNJH5lBpSo&z_Rirxr%s5F@w z#EUD4)!|BX2`IDOa2dg}DlRJ7F7fIt?cQ#}9lR@?{JD|KEX^&&ZM4_CUsFdxZkOV&3Kf?S{HnA+7mlIcoRk$KLyZE}D&6BBuKFlwgsgK!f)}gAx zb?&4`(1;~r03c23Ws$yNjjiAfz`b)q)8ER*wEUv*)+tLO5I6Sa25^JR6>D4$jkN1Zd|f= z9L?f8IquwcjyJnp5eL>Dm{fybq}3t?YzQ`m@Pfk%ynKJIt3K(8Qn*5*C<%(T1>tn> zQ$O$%qG}^xi9jZcfxOX`Zc3a46|1dSgmaGc*bbu@MUf~tSrkkQ3J<@$tJ3$Y(;$4; z>1C!?Q6W8wCHYzv{Ooj_Y?G`W?vXY>EhCgY0vi75jh0!T#~Ugv%u+*OE8Aj=!Avci zLQKpjC{?v&CSye3N*ap+rB((4USCHQRrpqArbS|g z27`_Gqn-dZQ+{KxhmMP?eK<5Bhv~>_+3|IAn5P7ASgQ_Mcv1)nDpZ0lP%rN~-U}FA z4GweP7~Ox$9A}ZJhvA@8MLt; zb2Hjv%VgcS&rdZju5I}7r#ZbiY0`yRxKwIDdTv18HgoquNu1by2n|A5(2i*%@W@`9N0ZhY$W8OrF+Ig_JRE zU}+jubm zNEX*Q5}*Ps6NkH(v!D!uhSmOKWfKBk(xUP7^eKE6{)}3+V0%gB!6u(B6-B$$QTM`n z`2anT5xj>ii@D293R4KEFje(5gi;L$PK()J&DO=&`u3WOMmxB0c#kU+0Kk~Nk*JWp zICOg+W6$-6P7X^tO-i>x!(&Oek^CVG=+^=cH0*57@^vA^XI5Oac>}BxoEWIB$jj7? z+(Ra+#NJHkW8lj=KkiyC%{l<*6-i@*bHBil*tU5obv|@)h$l{l)O)zcQ*3=fJ#p;7 zJGXpWu9<~2bInBABfF{W4u5@cH&o_{CX&rXBB*Kh?_L#S`!oW0~U&gVuEu1Cb$tCRflpw6j#+OYS zUvv14(a1(XgVAK-t=0^P5*hOJ!Up6kYLpXo#n>u!)^7Rp0P*#5gzHHC;v~5d8Y?C< zvxN!TlClafcqVXH7McExi87wBNF@)ti>~+DIJor>XOHp{9k032`_nj0{BV}gXLxC9 zFe}iITs<0P(H_&zN6+VOw)Xg;t!cYjZ-cU-7|Juc+$iL-r|s#bs6SRp7GYXe@ve#i z&(kzoTcsuBn)Bp-m8#C)UA*0!mS^PfHNiD{zKBoiLb)iJ>PQ6CU!U9fhSIxUahR9^ zrRE^)Q6^_(sYJv3mrf_p>umFF<)RW}?G%+aYtPjiR_jXw6fWUVwOAy9(Ik_>cU7hV z*&G!2bZP*_M<=5 z-_({{?T3||<4sLd}4Q2dKBLs%aiep^8yT9UpBXg<5+jHIX>SRUSv zuv|er|ICdLWVZ&$4v|}tB7j%I+3=nWOl|M_!Ij!^urqGBqbQ{KJF?<#PhDEso|QGQ zeKJCIee*U`*dDXOC6M6wVG{ENA<}HY){qUnyF|N$0W=G|18&^h?F%PKrwcE43)&9I zc6PxJcMvj9rbP*eFQljsI9)APOnO%D)RG%#h%lf_r4&_aWbTSQvMl!@gpK=~0cT!N zD*{bNvozNlpW>qHIw=*kU{cH-K2}?0&6#po1W1IYv~`*cAzVBxKViiBhr8tGLksn4 zqfbs1@!l!9dCs3s)D+>Tgk)LsrBB zWvfm{Oj4LvAXoWa`X>J)RD0+(0&vBChip0uC@$3U347a>Y#!Ni#qbx!>HQ#7#_^Un zviMj=DggZ4^V9WykyHFBSQTVK+xQ@~VG7t2SVzbL7Zr>PFebiWp?f#b5s-Ug21j_=Ee-!4)RG#hl)d7KzR1L3Bv3EG)E^%U)IRCX zCXlVPqd^or);kf){NrJ-C)A8EEH{#C{*6;D=e01~B*Ok|3VP(o0jTPH*N~xM!1pC? zGYaR&*N`Y2t1;&aM_uXAQMCNS>+9W>JHnAOXDJK>i|#mAO2q)9R8_fOy7r%k3cya- z;`{9Q@%#^y*5@k|11cF!JZ980|A+ zSn1A|NUAItoJywK#?!~yt0`)+2%>igdi?tcyL32HSk3YsJVXE8s{n`c4PR^~T#01+ z$B+P1%3)ej-;AURpQNAk%ILg_|K@3!-MH@W0=KC8K)^Ug0SwjlSq%Kdmm85s3ArAJ zgsoc?7pg1?635rL@TMEmPP|74EFk<+oHFBQ$1W63`F_C$uZxqE+{~LNO>?}zZ{X0? zSLFd>#cwp*7RSo8Vn3?#u39qib5lmpQ({v>7(X9X#jN|o!_LGdfG@?Q=c|bUCnL`4 zZQO16!gT10I-D4OIx9DfWZpE=YaFgSi08_?@#o-~r|6%5Y>0Yt$zn4_(@! zxgw$SJ+^G`;5CX z_|LUF*Lu|L`a;PSS^fn}tpCx>^T21G0?s%O4{IXHsIel517(CG%g|dUu%vjsVBwS-f z!*-UtRXNwt`x|Ld((1f*K%yc=AJa_=Ww=(>l}Q_U1#f9{ z{MKsT$sesD7XCGXQ^TaYNozziAvNnmLj}wW2Dm;IY?OSv`DUfQYQdvE+9EDn0xx0E zX6_`0yPR6SYIq!{K;G%hwq5a)n5bnfT83}H*_nKUdcgTjUS~l%s?J4}ROp zz@&|g*w&DKilbIN*@+_;oLqg-9MiO<$i8TcMaO?fxoclQB8eY#vKMTSi}Mh~P}rRZ zq5LVu8BiE`Anqp+hzlHE9kD7x=m%8UeXwKSN3PbDG8Oc$F9s8^zUg9^*Q!TZDHwj_ zO}N4IAgjN6YLD7zUuISz7s1>7LeD`&PfzGNR;8XoLA#%2f*wUeu z+%V+)27PP@^61q${Xx3uTrZotYGc%eN94tZ7!GxcDh}G#+EmswYg}0mbgc|`JxN^J z&wk}B;LgR6Poaj7Uit0kcp`WrGNz7jytt_(=CX8gnaalRy~RfJ#<*;^`P4|pxMqG* z-g8!U#M8?R?BxD^P(^Er=QU3WVK2}vz|c*nrAzSVYVM=KkH!iRoLh)c43}Q(u6g7m z_E7t2_InCKjF)m()j40o1j3X@UC%m%ZEi4+M;;>IRoT+;Wf3X{|J-aQyz*9(#I0z^ zo-{n7f04^Mcm{LDN4@yE|H@Yao_lli=esIxiJmGD8QtC(ndW4-lvnu5=+x0W~T z{NojbUH#443juSK;RSxlE5|>lZ{h~_dxCl2S8)}*)0q<9T{D?l88NP3<4_zgNit1u z#>AuHNYT4TG^l;7#Bf<6^>;Ie>x=xBelxP;Xl(Skzo3_P@37b&+^xCc3g16~p@* zC0|!^4^B4+jKuMT+BbU+v2Cc|EI4@Q9kIMTE+rP2z9(<^S%qZm&g&1lOBJGB0kO-h zt0l}$EM`nH_o)9kgk3PoglOQGC5JgvO7#}BXSK7}?l>7;wF7%zw!X?M`Z`urfq|e# z5Gcar{GN>qm7X;-v(s_wqvOO__&(v=JlO~$OGY2yS4p8Yl;S|OLiT{AfSH=;6P&l8 zAcV@FqFF?^g>T<2oFjQX7ZEq>hTC001{D^#Js&IEFld*zerw7YE(sZ$sSilcc|A77 z_oclrMC6gT>*ucU=}nh6lMIkt&D?}f#v5E7B&T4_DBy)^XQx1|ss>b&*nGmQ6%kll zg#=AcM8>x)cy~)>ar&N-HC=z2o{W5X- z2VipqV`|bOI3^w&2C3v>$2GeJvsUWbExJ1lQw`9BH6&mnI)oIfYzpihTKGAmo&-sY z7S!zIwy~$6o}D4JYU0WenV5i;x23*INtn> z`yBbTXW#!=AIQF}a!z_9tvZlVroZTD!0o3##kl7t%~1Br=$({bw^H&(zzeWrp`Z9h z7W^(4wAOsQHYJ9S!#C|CMs31_L85pe@MnoLCNlXq^KtsRup7B)bzpj?4fS> z)J&t}`mCO^-pTq`FNZ00MFYE2gH>8+#FILd(t%xlPh_bw8dhwadaC*N}Py|iR zJ<<2RGF6|9T9xnUzU(H7;+Tgum1xweR}rz`X+*R10fv|2d3N0<``FDNF2x0zN-;Oxy1+|vwm3^D_ zFi4sOO*2L2#qr2tAzk(cf;Z`iWR)?hDq0K;&(ouBmwu>dY99y8L};_NpmhF8(9W~e zp}7*(Iu(y82!s;NhR62U8ilO#VTF6&rj;mqy!< zu2HWlxU)lgZS6WYsNc>8{m@x6m4aMhMBE=Nw;Ov`u zIg?{?J5sj=>+pj{Sh4X#p7^NnS6dhn)ozch={yJ@?7 zpn3@DF@~hTHw(FgCG1o}zJG zQ8j%l`<1nGUWOE(BR*zisQAW08Hh22 zf)S19?@pFnSdv%)KRL)Sy2fd>54!eSWn{%O8K#|+V8^9 z(-?iWEx$;^lGL_$=v*&@3WvmpER48OtS&m1b9I#sW{XtuK|)mip-jGkIHn4oCzX31 zy!cM#32mR_Dt_6(RxkB8sqj)N>b2-QC{$N=Xi(VryAwZTUdP>+8MnlEoMTYds7b?Z z-R^6~p{PdV^{m=gDmQ$kw&XX2P%*b~>iAo{?nJVwO-kQQAFU(b_$<48t#5Ci=b_E{ zv4DG|&y(zPqaON@MBdfF!yA9{;GsM?yE?kR7;CV~4A-a@&R>*~u^GCfrT?dv<$vr~ z35-S*>>S)}c6O95@4HPkUa@4ZcB`#T#5}MxqCP;lh#FO+BBR9EWSc>CrB$_AiPWyQ z_fxIOyRYelTl9&a50MbE1ta*gpep?Pg*EN;m$QYBi=36Dy-A(fM)M0?6?VEOIEq+- z{Kqqn$CuPTGk*@vH3yC~4n{u* zJnXK2@vIJCE#E$!zjCbQLJv9DLRv|G&*ECYzr!Y0#WFtGxtRCC<|0WNsPyh=82d*^ z1qReLr3bLp;3$%)Am^m#{DQA%4kZxzGD3bwYQz{9EWSHff@m@m8Y&jA#143JVQ^i@ z$>H@hlQ+ErlZn*NsCySHrq{K)aOT$BqQ0wSn>}@=C}gHPAJfC*preiWG;`0(n#eAM zj9x#AE#>sZ+TkuF8{PLgklrXoaAtQv|8yjKoUJ0}ZIX~-vm^x$rRXxfWt-aTxirPF z^P{}m;|4TMEd|2F4KXt$*VD9@api02xqxQ;k0yaKLeK%W*n6Y5irw`5QAN_T2N}~_ zpWUb~-w)K0MNm1VY^uU+m4+W4x#@Q!!I)|QSeyh$$|QZgO+z&7mBCm_lrAHqExyCv zE3st7Qe2sO~0?Lv(X;`=MR?07o=Yt@``)ZZNNK>Q`MStt<9!i zJ{ceu#s2Zjzed*CsF8RHu+a5|D2`>SBET0&=QDjBv^BsRVGJ{r{LC!CW3t%|Zs#i@ zh1wzEcWA~jV?Y~*J@WZ7GgW8;Us%S0o_7a2Y>0dJ295HLDCJ0y5E*kZ>xpPduF0PK z?vq2HYT_IXVx;I$Bxa5ZFZcY4wEH3hk13nN`x*h=d96gNvyUB^toBSd`)P!OkKyss z-ywO&2<6ZCFCsLohW<6~hV%13>sANN7~rvA5wt+OGqtoYG?L-xGV^6OcTdPdK1gw) zk88Lz4I143N}dljZ70Vm2io?|NHUs&EdkU8ZLGbZ%q^sv{6KM>?y8@!KJA6 zFAAkBF~7`w)sBqg=A+1gGJjUbyX!vXT?S=A*2@EP!QVogx(}__|7mc!|ESSPV<-~b zXxmRkhv&3#5xC!4fNNWQq=lxn){LLB?-(7U4LMy+Dv zu%`WH*KfWUn{(X57?Giyu-^GraB)8w8tnxZE7-?vyqL57DXEbS<7I(m4 zVh}X1W5^_YL4ivKfv`%G$rqm5sn%;#5fRHTS<*%sn9Jt82{e?Vcq%aq9tH$Sg_h;F_UU_ z?h*R&3ZoHwItW5C2>Z>bBts}jQ?V`ZkZ~m<`t(XXOom-UZa|0la-87$&UE|Iwf zOP!EZmexrXTX&;~L@4W9ZDWe~g*@VAHPYP^9HP_N*o|2XCLZ>M6mt(sMC{Z)fK`dK z6AMQ#1obJCqr1@NI(f>4QZnpdnB$Hkuh*G4Wb5?IEu%|#1Czzid%5ntj(c8g!khFL z>A8?xT6M7<)_~`XrnAkdh4n6c``yxx#twsg_i`FSO!}|U6zq^($W~bqt4;B-c-w!s9Sl>6D29xZ8_m(ROkUd#Yf^21&)sz<;F}BvOb}=FAN%7bR zcxcJXXGNyra5UCPU$=!_emNDefu!_cI^;qiwX-dms~?qx47`o1lcN(TwF-^?qP(6X z9D^I>#yug#u3d4u$K_3i5_Pl1|N_syBz#oo1&iN=u2yE2@~g}Wx>p0~7|$;ep&wNY{MwtI?wXwIPLf-y(gFORT<$!=|+D> zr*|(|L*<->otJ|1CUI7f+lCjj^U&)HB^zgi_!WE8?`E+^JE^D3^qTE@-;IZaky_6Z zP2VP)j4wplEXqP}y0D9wXJ++2e<^A;>qe22leeukp?fLvCPuHfU3hUb>SMHCsk_aO zG;~3W-ud|`K(+v{tza%usxc1F{lkid)bc-mzWR%!4(?|mu_v(#`k}Mwb$1mL+3(sD zqo3T5veMX%hL6mpB3iB~xhXfAwxtq2Tv*^dq&T^mwr0cjjys4WH39FJO*v_NS^LHl zMdn2)#|hg?X{7qC=s&N8nC|`ynW^;{+HEP`d5DQ6 zsFdXL!^$!p;ps05*N;V(LP;xu)Y+IBqo=O9pggy8b0r?DA>7kc!XeLXN7%;;K};>Z z)9<~FZd4dOeZIZOc^WUneWmSnY3%^}Hr;IHj+5?($S+$8-#!>w;z#nw$&#CYcDhf^RiA3VYemU2_PZ-=IxNj z%O4IyX~yD#oSt6S5T&4B`SGr=;q=YYxb}f(I>!6;oynI}`Vy5_tli^m#l&MZmfT62FQ%JagnqPnHSmull zDaoazoEKXS)kE31<^VYEm#hY%)3x)!#a{E`Pe2T3*eo$vTPEsenqF9pWIXs6b4ukGf+{6r66WpX;=$7UHq8g41qXA#;xo8Q4J?>T%^>0DB0 z`l@nc@i6hu?)I?mpJu83I5=7dL=-sZ-W@Ag83`+Y2_?heV_{+&D+vvJ7-hr_4jtxS z>Pyk})LXydPYUyqNNmw_B{J9EwdkvP%zSUz7Ve(0{?3SvUQ3%$rjLDf^G{e6vF@dP z^1G(}>dO0u_ScOQSHNAw}2UA7y_%Ri#Sgl5BIaoC>d(bL2HS zwGz_~CqE8dO5UJSzAeLGLFFgv`ilZ%c_1aT&{_G5GRpgYlC$s_H9ji0sD;UZl!GZc z4&H+`fG#&fINCr#2Wy-h-}YYKxNL|19LT{)5HLEdn7V%LglgDXZa|U=VPyo?c>4%= z+lTx14MiY3WT#Fity%)FL6r^C?fFLwFGF(XnX^u;!Uh^*rm<2?6ob=k59S=GIzvWJ z8@jv|tG;#S*{Ne=u_Tr^O`6@^M2t6Wyw#aD@U}t0CBja3%yD4arK6}iV*iyi@UzwO z3P$X=wa`YSg*pKy1JZecgHV~Xm0u9ZI}2+;pD`!&X6D-CKIb#!i;PJ6DMDI|XNNH` zuf_o%Ke>{JRiPbS-8fhaO!yc*^aAORsOlV6u(ee+gF)&)F_k1a%7_GL=5^2oVX#*4 zTYH;3TKOq+Uy~c36>ELd>VEU<2F-5@OKWwwl++|DPPY^kJ7GV>zzYMOHo61hyc?M! zN=0WCUU$l$N$)K+II&NJ7Q5L~91)o*t#gEoL|Rzp|f~bsyme0 zu`oFj9|5UPAmzZ+ydSdDYhsHXmX4P&`68xYWs(Fic3gcv zMLx7ws9aAj1=#|hn#es8ukpk@-}s$(8@yf3jIg{piBph@0mM&!@V6e!jCiVLiTy>H zSkdbT^e)FTr7W;_~nZgaHaN`WKW01?6 zR)3a|w;+T87wUCAX0YEUPeS}3*pM^Q_`3ntQ;i#u&2XEwakrz){f{Z%#C4{OAt>^F3LBP4jOIw+SxU$cJ?!~SA8*Yp&>I;id8#`cdz}z-pIV^>c2Pv zCP}u)$o1A!&sXIU7}>Py4&LL6=locHujWY|gjm$VK$lOu3j0@vweAl1-d0#8(Ld}D ztg_d`icbu`!fu&}g-Y9OnZQ$!n2DJmS%`OzZ0i3!K=Ekfffeit`YjPxhnvBTo@yYU zYy|2R=pgtAY>#q(Rku}=MkD2#N5Jz7f2trg;DCFF@8RvinjO$+ZG@JK#)rF`tOJlc zV2Pd{+4Q{tm%RUTqZONOuv^#Ed3&)xopKB*cai<>rEpUa8gAugFst$uXfKZ|O~53d zQ6r`Q6Svt%3tXt51-Z@KdfOqTd(-TmyJgoRcm(N^2XOE23luBlbF#qhVfCEKD8`6T;R{5Wn3jAB-aZ&i7S0ri+Jt*htH#R?~DO6ge82%?4Y;7uKe zYn+Z<>@X-0z$rHoWi?VS&^!6spRlXYIoZ(j|6=W}gWBNQcU|0}xEBfT1d0`RE$%J> zid%6ln&2*lLJKX$-JKE$5}++kaD9ulxCD52zWv*Ooik_VocRuu83>t>nJ~#(dDeYj zmt7lDGBf}4y#9A1I`KM1=rYG#tA)FrIaxkGZF$0M4Kqc5-H9j8(t4rJ3|)u}lVGtP z^%1<&#hCYl9nY6A>cKa$L_|&Pv@Vv9x zuKE7t!G6vCi?CW+;*REHG_*XFy6EG)v>V-YMx3+<;>24y*!5J9{%*#`sd-!l4z}o2 zHSCE8vVG6zCHJ6#YmAE>*L(Yn;0&4YtEqc>jZ!OPYj77Txlf7U(}Fokr2@=P&#{HQ ztlw*97HD2~zYIePxokIm{TQ7h?tL^Y;3*I1bL4h9TS|ZrkG8E`f6S}&RySh1NuZ?ujkq_K44u{)!s(zh@$=t(3v%%U!(h6 z9BB4-iUdEVB(;Mdj_|x0c*UaM2z@%nxLHxMo%?!J{I~T+7{pHW1O~lm{M;WvGT|A) zfzb8fb86x4D^~d1apE!74NvLjmezmoX<=o`fBV&d>m}F5Wc}Ly$HT$6caFn_NMm<- zDlr5nz_aG)#FNG$Hb%Z$3`&oDVIV~-hZPz443ql}vqfxZtrD2L@6T9IDhwsfs5A3Z zLaQnb%||!(WQN)8AE{Ho!%$wq|NFN0|J!dCefDR`zD2Q1;A}dFG1SCHnw&^vsm`lR zL~=AViyoh-vW!Ds6_F8<<`{2ES2q+`d=1J=rupZ!hiwJO-p=40#jOSxW$d%EvKC=t zU}CVa^6W1vf9ymAb|b>-248?DRg2rCQyZRsV&s!cAu$wFDGGUxObssaf#R)--(8!n zl1nzA%bffq#>0+pP>NQSYq1uV?;%;-vEV%o7dcK&keL1jInR$z;ps&m0*&7ie;A&TCJ$~uqO~xF#8$<{q8H1pEJCthQI`I&++H(t7MSk=k3ZG6Ow{avj9P{Oq zDmye!p||Pk`cKHo7^SUs_9wYEsmy7*3C#Ydi4IVTk^q4rci=-~9ku12_)ZDi-M=d( zIV(}Cx%!ho#!ys3irK0MC>n(s+Q{`pFrCPJp?7#!?8s43Kwuxzqmi_DZTkCwwqO!B~Gg@1NF5=Nf{dQx#&~n zcuN7*O*v{k$NWV=4ge-9Y^K3RroM>aa83Ce;2*)6=^-8Fn2-`)8+qVvVE&SSKTP_yWB0Heyd-YGJG;_@6m;a--P^Y~-C z%3VjlE6ZL3uIKbL_yzW`TUhp6w1HCUnn9>))}Y|!0KgtK1mb=kd~$obD?Bus4`@H7 zhzAwmaBH6 z z7V595I$2qIL#Zk#@+?%vV>bU$A}W!!R2N~6VPb{7X5!7;Mr$>8CPKMI zvX@_0z4K-Pd|rVsRKEyLyJBW9#ra>5$bl?ga~ z%})kO8$db?Ioulb9$i#(?dZq9^Lez8$J0DF+Yyq|ei_JH^!+TnGrDzC0av702t=eD z3vi^52nPU2BC~OwmS6uziqZ(1WncN0brGG(MweL|Rq7hPcg8twrfhhWxEVn^{zwl8 z;TD#*o@5lE5X9Ocz0V!t>d&#L1*{^mo2IJ;k#u!q%C&AiATKe9^}&GRnLXn+e}G*F z#9}ynm;^oQk3&EZ8wzW0+oKk3pOWWWDb8$h)|U^m7qn zYLng~@+=M+o`4REoz!&71Fx`S!1kowk%x+|%I9}=I$#LtYy$}nEk|vj?1x%vqx|&_ zst@CzW1$!2Hm{)+h^Lk*(|-8apHy_Bb9qsTCi_tVZ^Jo_&iXs&|O|5?(c? zl9W|gc);m|QhO+S%H*vr!Vul5IsHpQj_wvsGflF~ZsdS1N0fjQ_0natgI8XT>i57^ zDOcdmCa{)7N!2tnAU4x4098d+5$jE1Fu3&Nw_Ss9!E_}2PyK{Jacus&a`W<3P)>^a ze4Dwtm#;^_4%G>F1F1`3va@eHl&H=^qU!t_$y`xzp?f-REcAyj+}-HUvt7MmkFAUz z#f@<2E@aO|EvjNvTA<8DX~2rlHoCOZOe&n!q-=kqKZ!mAB@Jqt#U?dCm7>fde0BzD z%@H@;dl7!^A3dn@#&^d(9gd3^6IMYciJG|nJhfsoLUq>Fj@gJSf zC3)w+Xi`;!B3@~Ie<(Mt{)QaWk8*v?i%UYhIj@*niVZQoJ;pKz6-IPFvJJr~Z1 zK*%@L=flu9?N6*Bof&g@(FOz!)TVYE!^{jycH1)3x4Z6;1Z+hj?u<^7B7(Xngq^Kxc8IR=)S0Usn znUf2Af|}4{Q#2Yq6aI^~QF@PJMPU4kwqSl5M)O~<&vUkHsPyHwN3hrF@8XN#)Eg}c zPCj4}>U*9vNa}T^c2OI&x=c_~*eTo1SCYZC{5!^r!JH!>&Y!z@sg-A@QN@4(JM8X@ zX;Yp~*Q^fWdfYQNhOhBjg3avC8{Ph;ef z*ll0=_4IUS;~(ll-nnK!zKJ)MaGn4g-bOJWtk3>S15tO;79hCFY}6yeT(m+-%KiGt!xJG;Piu@Cn=0`jde*mLtG*UVA6JwUCXr^y4Q`xr6)5fF*?a z2RfJCBaYnRaYCx}UJb$~Ut9|4Utjqz21K!Yg#ninD*h@UiYQ>NkdW{lYit$Y^E{?Z zPba#14nv${EFEYU*OS+5SS51K($X_0< zVpPdc(L<`YFh-;nug9ge!e_wi~;lsHx80G`@2M& zhL|*+1l6)y&+GXYEwN*RH`U&*t>cYDqxm0;@;vCYR;KEDL4c|0SgbBzwrjN*@gvzCr-Sg|kCfodODqn_KiM}Q+z%)| zuJ#%M-Dpb!Q}epkJYsTpjd4_uJP0odPPxz@AjjD`4{-{jA$_NqU%YjR^AtqgHg zAe1S>!o4-7B)bk!u@9X$4IdjeV~&2+hqKqvGxQ6KnsagwOa0VMIPVt?xy(3x_+1f? zlu)aF_jF$3n9VDaV+BPre#*Z`d!0p3TuHJ8z;kj#Aaqz!0j{ExhwHumO{pR3X6}$F z5Amh1R5n`G&1jiw)w(&(0MZD~PjZZVJNuSr=Q`n0@i{QVWo^A1k0pnqvEX%6E!BtC ze9j4u0KQ-~f{cZm2wc0RqWfRW+mJg#3UOXUh52r@7sWi=C zlCSgqqM(=8xG$2*jVJ4hEVB^id{L|^S0UHMmW67BGez3{T$4@_h=rbb{XL?6xEeJB z7G3R5!p$t&w5wk+@mi`(5WK(6E|;|GrtcVQJhJ=p@Z^k;#z2cCFMU2^I(>GrPuE)ol4YydO(i3pU;o2%; z(3>ogl^e4xfAfZZp?|H`M8x1GV%(}%IW zs^g8OPwok2BNR!CPPTK&G$)#9@8iB9aBx&^NC_sJcca?;s79RsJnk1$%`Z=EQGf)O zp(3r$9Lxn)Wi^j&AlLG|qu%)#?N!eg-{#JX<3dH5>b~mOGKV{^FB@bd=&;dcK2>r? zm5#6~U;-3H#0w3TDHd6hX-e$UQW9pA#h-(MCT#ZlO`9*Z_I=Tikqi7W;xn)8CF5vg z>(Pd-6q#nf)sCJ-u>lJa46E&H0&6Y~quPAw#Uu@_9aVil9=i0ghBR}Cz0s}tX}E}D z*idAqgyEI(XVBf3Jl8+?T)>R@mXEclgGF*X!|bhO04S7@z(LM*4nM#Qzu>(8N2mYH zdNF0os7>OU_?v&xOw3pqVUF5gdNpp@igJ*>!r{sByB|mX9^UOtdV+R?f^(Tm*9yZs zu;1rR2qOw$pIZV>vW_`IUw+a)Epi+gWEzh#55Gn4@@1$cPkmmRak`|PvgxOJYe9(T zW0)yeho2>gr{M~@D=d84HKcc|>~naY_?CBUAK{jKE-1~l#MR@Cjkx|!9)0Q+dP+K8 zbR*Oc)_IQy^ZE8JXop?>ccR>FVl)b?7i%@&U>oWqyU^I>AhfQ^-PQHu`yCNmXA zL4VB*=_J`-lZ1cOnUU~ARFJWFDTB z6>PgW#LXvhze!!cs-5m z2UqwYpdIxQyfB#%H8I;`QF0G0rXNyN(+~y#RwX633HuE62bJc|%Y;_dkU_fnuNmKb zY5b>G-wkWk5u0bih3XW|#m05;Uo4Aoju-yZG3j|?!|tOK`?~@uNJC>=?-UET9+6Ac+Sz5QmCF}{Gq`H9wiR* zu*NCTgS znk%3+{EzHt+{)YPkFXgVy0KSYVKq&^KGZaxG+|7br~K2`qYzF9G>_}S|4LPIK}Gj8 z*DK-0?xJaajGY_`t^O6VBx@#XO*XATLmIXpKyl2$IMG3G83Js6zh>OTGg_*ZzHWj% zc*XnI&&`KduX#MT*b?tm$x`Vkt6#jREFY(Lv5mAxXb940`{sp+uwJ zmUPgncDaYpv7}0}DEXHV&aJ^DMD--yj=3>xhudn(rwrigvGmYO>$gUGbbXRzqBP-DZS^n-sZ)cGx`@b3F4AXnOWSsg{|TON|rc=>;@P!ndCz-k$Z>6-e}bh5$|u- z%KUr9R6#!iEXzmQqP~bbYc;cSV6pES_$o#A>pjEr|EVy7ha=r~{)yx9<`?t)E|8Y~ z3#c?~!dPHqw`dw(?vZh}<%So8e!y~1mRXeU zRE_@9+iPXbLT^X=_p9%t3(ey!nRzChL=z=CiorhB>Hq_BGK`n@pT_S?<1LkWSGCp( zu2_zXIEwwLXk)ZCzQ&)0%;Uz5^}E>T4arH@AAJ-p9`QN6=7rM;Ic^CkURua zQGk2kDA2#?Bg~~)D)g;W3x2oXQU>li&?-lU}E zDDc{&F>}y}MrlSDH3+L=-`G9oSg;pSl~G4oJoKRIuPe+}O~-ON(cwY#;dA~cVS7SqeI)~O4hj@ysKle-E^R(qaCjZ%`q>m`+e$V@qrezw zrr;DFu^{rh(TIppxN2W&wOv&kRj;3v3;QsG=L*>gDZG2ywf+EEXCeCD%#SV{P+J8p z=VaF$68#tL)wwA2`CJ|d9qSL@vJ-3^4?!O}Y^>`veMR7v)IfEu5x2!3uRa_=PKpwo z^A{mi-bA*)5i=UcJx@O;ZkLZ@@QD=H=3qNN9amPIKOTn3ggr&;4vbf(N;{paaZn3|}o2EAj(F z$F^p#z=vFp9D#d^tqUJXA}eJmALhRw*|>0B_#UrSdjK8VQI6QCzG#Jv{=}~@4498^ z1ss87NH}cvl&NJIDM8pBUPY@?Dyr`O;p4cQ*$cX;#$AOx=}>Odh+gBXu9gSUJDEa2(Ofc)qKLh2D|_n zupTq|VbrR#k-@N7kx-54CH?!4E8r0eMu%c=XZkKjzqXO}w_`3Ux=QlB*13T?+q*4|_d9rE39XzZ6s27wg%7J$ z1Qb3_v&)@HP`u-fSKg@AHSpux+Cq+Ke1o9h?YKC)NJn735SNLTAO8Tn`vu!`47sre z89TsyY-m!9x}YxKk@sHcQTOH+6sK~C&*!9k6|H*IzUW$_O5};^aG79i_ zALjQyJXY$F6`r5DQt5n^0($S(gd8m&iY}A?ipIYB{@wZkuHGzDd`Te#n^AWR6+-Vi zGp^{j-F8%(4ZF*eZ8dhPdq*Q;zHB^vi^jjT#b8Jq<9^MC4bQ0G{evA1vt z0d*~eVrVxBS>nu86EQG?JL{s5}M0wL&alH z!FTIYj2lCIHy6n7`B&46%~AjxI3b5yn*mmZoIrx_yQo5Rg}f|_It&hdbh?C1Ztu|1 zopZVmcxZ?~Bek>|18ZV3G=LzE6tRD?Ebg_bBB_F`y+&whWPA6G_v*$wk)IvG?&n7h zfi<}{kB7T-RMx{!7Magazf5-gcxqp)pHG@puc z(Edl?Fy}^u=@X7s^R03wpVJPlwF*hk@+`X#(c&2FULZVx?%Ei*FHuiz{JsdwEIWyi zT&zcBf{-|Z`FGZ%o}oRnD^Hf`)p@B;sCC~Iu?zXGkxDFj$cVFHX}O57ihnEff?PQM zgitwxO(Z;Rp^5VJ?&f$gIh0WAgY8^G-8sL!^ImW%7Aqd1!OeBTms%AX|1^Iu>@%Aw zj!y9zf(CW3Q;*5y0s*@Z;7-Ep<(evPtCtIaz&$OrL?~K|73So+`8n$REb;jlUs;)x zkO4zesv5@GYO&wOq|#A=HRoOssB%b?0^Bca^HBO(JU1Wn@1MS4PW0mBM=$u#mK&`G zWu^}%wXZqbJ3ft?B5cxIysjxnXy;La_Z;?Qoww2%&}G@qt^+rlps|5XW2ZR3I5J&+ z_GHgG&k~(WG6I$`;y7$9S=ee(Auq#4g7D`K39mp<2GjRq(Nj}Rmrl6&{FJF0F+PwG zrO!Z5$%Bp;X?>+LE&cV@eAL0;D#ImQ(plm?$BxBUlufQN2P`-O)wwhq-ItL2fm5nbFW^O2A+IlQWDwJ#@g^wsLWFD~>&Dj) zD}YSc^2bg7?YLKJI`zM3?q`Us$kwa2JDdfl+79#f5fXGU@YgrOoY_cjdJ&+Ehuh~p z&#}3w<;Jwt6|IbQB1!?8qwvhST3N9p3y&Y5rUn}aFJ@5d)dEY`3CQ18V!2n@c`Z02 zKvK)1zur#7JZQ$WrL=3DUTvKZgeBZw#QXb~xE|+-4J#fk58i1gv-eqKTpyq4sMQiM zrNY1Sz^ct_tt7KfwYt%AxMQoYHkbkg934;Q5#FM^y1;g}g(8ao;rIL(jn`(~LZ_*L zV45gVbHTk^8(2D?>|ohGia$AvAk4>YSK71)G(TjBb^vwE4Ap=5?%ZF@AWbycNRgfW zYWrAf)Ui4|E@^4o$d-7=GkKa?x$z`KtEiFJ_hoomisK`SAu4X;x zj#B||LTBH}8n^)&T{DzKQt5^R46EmN{+B-4 z^2EjG^A{C#vfql|N%N#w$?GKBD|i}-mZbpyVxJuGZ##~hxZ6jSoxWM>>>S&u=((vh zkzzDejat2-f-9=%{BMpQZ7yjhr6N8G=|`!f((xfi7v1 z^@W>#IZ}x|~4yS7dxM*pYrc9>ZXO_tU9*QaCJ<4daL;&P#A}Xp+vv`;X3>;$E zgac!-e_85g-3yB0_v&^i3sA%kujpIXWm`G28u39K(aPn*xRJb)rF}y%*g8f16!h5+ z>cuGQx#2xs*sF#(1{J<4)f{)Kw=x=No6!EJRnt0_lt+*?6_1P$lkM}Lv=wF9b`h&q z`J}af#vQ5XA~>axt^l!rUNwzkk1VpR}EmpBT*equN<_A}NAk_P!lXGXJ@w2{k z;)tM068ueHEq`V${b%;hdWF150=)Y_7ZdyJ!WS{;iz6$!!dCtru5Y)!8+{#XH@~@$ z$?C8K&sBZ2hL3^3$>v+gN>Jno21eHDFT}I#n0%z|wAbE@;FzJ%v{tTHFJl7VOAxPk z_eVGK%qBJB6Cino`K&3-K|mydaYLQX!Q5;3KEZC_>j~3A)r(hufzz7)C~FA@IKT5K z9D<44HOpUl8adn5ES(eRbyo1buO&>Zf5K>MISVMr~F?m`{n zY@cPc4!YEQZSYesRbct<|Zr zB3vZxcHiW(7}`?crQI)fI3OeU|B*Z4_0Ub+n7?*cvYFe-#Nf3ns`kbC+eMYuiMf(@ zj{pVF--go;|Bis;q9>^sA>-H4#5*U9_d=q|tRL3$XVS^@+RbfUMlloDIz#Gmu>o31 zD`K@1LovhTpC;M&z~!Am^XG|99($Lx^7K1Gj=vYh2f18dVg}1PI$gQXwJhY61nDYq zo@h=W6UlYlrYI1@cZY1-R+5v&dQ!)qquN0$Np(i)t$Bt9*670+&UQ!fItf!p%1+xk z9?QAv%CZ^Iy<5Vd4euOZ)0V`k6bXUSk|2%ru5mNp?_<;2I@diK94@^gEdZ0wr39xH z4wIGM>~so$isE+vU{A+C`{T49viBDwalfFlDY;!)R#&ng4UH?6WC8hk9^8wd%lb)a z@{WGKXU6HYjNBat$WXy-$%GNC8zf&eMTRy4M)24H+7T+>KxF;n>574 z++2@fNekYW*MOYWbg?0 z?g4(YXwO;PF-8+V+`{Yxc?Bneexqk z6P(VXrv2VCT4*Ad(btH5q7dA3wY?6)dKMcPaIk8!b&l?}ple%@bn-FoOD5sSf5s8C;UaK3z?Kr^(g7Nywy2i7r=8@4P=t5L8e0#arqVvKrwVV<#aXh z9dLEQDi1$JzIuBN!&u4c7_L=yr2y#3zt09Ezu@l8Hp2Od1}p29tyQh5r9xKYN6{5mLjBrX7=%`bzUPdjIb@j*O7gC}7*j`dNaP^Q@QBKEZFp|+3z=wxJse#|| zv$D1e?ku}w+PY#KUfsH)M?-4JXcA{V1x-3^rO$F)=J<;iOOn7LdUc|^H5An#b|aeW zw8JB=Bq+$WBkLnVW}m76Gkv<8plqvT;VPgj89m^rt#EN(ct9Svg9<7-Wh0X%<4Ar| z0GFK#@6(+Q4Xl2a874DCa1~8j;YFxijygxxhU4DlM`Cl#!j54wml!r_V!H4X> zeb*^2oR9N^wAa{Tt=jTE#F4}W$3@L`Cj`uz1w?ANg!fkX>TbZQ+kZcKAs0>55+q$U zn;jCMDsV+gv==T-@mh*nZr6f2^rxOry^lPdJliCPi{^ICw*n7O(I#GFZeoPB$`j4u0hc(|Yy@_XsA|D!|eIrc4>My`1$+NP2Eo;fm#xs&Ta+V_uZ z5Fsozf9`gIiaVdI_&mn$t!OLJK9Ge7nRLsM-9NpX!R0A0=#{y_^m;At(mW@CZz`9w z#Y!n^zuEJ>SOGc5FcE4Sqz+IPeLMFi$~Q_{X3=UBZrtab)cgX0By)A&;{P;uW?u1S zC{P54Je(krU1hixurEJbx@y}yE9cgVkVliwo|f$?ka(?{1ngP9b8wMJ|@}~CnR+F01)DmT@%ow%??u@mMC+IBik-bD3 zk7KFXdSpNxK>+4`e2I?A0W*I3&?0Zw zeg|u6etSkZ(?JPT-9;>3EdYhdV>cQCr$!K|m^J^rvby!(&AaF|Ilqs~etsLE+75Pl zR@c%h%-C#ZhC`u5>$N8TkA8rfJg=W6t%EmXM$V@Xw@Q2KBbAG4w{s?4mF1pUm8Qh5 zq{g_3qzbuuD@4@FW>u;}0w8%ye+G5TrPGJE)viLD54X4Byn%zIJe}rzK-j8`JDrCkrL0ABO^Q|42o}Ge zUI(gv_u)+>*m8`2Sabv56xJxHCyXQe@>2dqd*}3*?)t?MgS%AM;q`N^CEXdO99tnE zYz$P+^+i1tE>m2Tu}dVV&C$`aj0578V7we?;^=}xkFcaTp~HF}eYhbgwm<3l@uBu3 z=b>5r<<~H3pN{^>(YW3WOEvAUy)|Oy8ig4!mIOOiz#T0ok&d>ckpF+V?ElZ*;g7dl z0tJUp<>k$5^>9Ff>%G@oBGYE1C=qyi%=+EjEj3g0K~C*GZpJ)i47_3k_^ zXA11Be;}m{N*xPrGZ~-)OhUo9P#m@nu@TphWoNxr#B3H}4O# z8FXLYd#hBNUYgTb;(|Y`*Nlj@nqH9q7jjm{B!!_E`vyaUQK|nyw-GxbG zjg^8bufb^fwcJGZo&P`haW?SFm*Wjrf91r+z19+UCb3ptR)d4g#Z8rYJzKWwn1;Pp zGw|qD$EzFy4GG9ZX(c}Y=xX2I+#RIe{%zk8oD;O~xk%pfdlOpu9Xqtv4bK8u(?I*T zB>+n{hkQi}57CHEpg2dMxibOR%0x?{IG0L=XZIJUTVUnNTMiIHTrftj zH8wux9Q*NH2oc`P9Ws5n1Gl9F<}M#D!PE{O@+=ww_LIYleF^?W38_3mS~b(GLj|@E z58aTdgBr8-tDxdzX$}jsU0~;Oty{Bs0r_CH_Ne&FA*h~$aR=_H#V{R7s}T2L)Hfo@ z;_E-AGrK1Veg4V4Rh=vo5Uq6^ouj{*5|{wIkZgk(3KpW>FOLaR2)T6W;4@^djqVeR z%GX!5W(^)~1fJ}p!kX@ED`bEOjrc-%h9Ak(AoB`e7o6>qPRm?7uWqeY@27$qY;B4XQk&v5YYh@PPqYE8 zMVJa})f7Gy*-Lq@r2imSG?W&K6|(M-h8244cUGOAT=(U3oVrmdJQOv*DR9riUpO*g z)?Gd5M8^g+kmwiH*aMUXlm{aix`R0XX*4Lpn38zSK3ULQw!Few$yLbJ6C_TOiZR?QY+Q^H9r{b!9)=5gd!-&Tf@hC1e*ZF2@AJ@zxilsRg?+TGaz)^ey9UvhrCfU3nO}yb&>BoKh2m_Tp`aE zs5EtU#wtKE1M<|qQeDR4L_s&zfTJf@*( zu(4&mgxfMlyNHxH@w!5{iGUqV_Ku;iI|LIdZG`-NvX_hXZ?&Z<_*@=&!6BPQPgjYU=jd#%NNp(z= zcOio22F^%7bQy8pg(D24r6yBW_+_(e^JjYss+w=8$XVUnG@x97(abhe=2sI5#9NCz zfj*;BgB+gI{mHALYmu@Oh9%1*y9m9n(t@w~or75o=i>W@eofFim;vglJi{%{3|(qK z!qxTRbe(=PvtC_xHP1Ni8k^q*GVL6GMPRyojw!+j(*{UV#u?k=Pu_YHB&FX1UBsy# z)45!o&!?uAO|gvJ0+>b~N@7RLe^ORiso_y#u6V~Wsbal8_LfZxy_y=A_6gX(T;eHM zkfsUsu=JU9RLOsy1;a(TY8h+>&l8aiWf=O%+1Wn7pecbV+ zIT@132$(XD*riR0imeRpUGl^oreCq??-FbTpnjyS-clYPQPtmPaT7=;HC|NJdRx(`Oni$LK-dkaDNn>&AqUj`)cy{!j5HG|j!p5S zUQx`EEMGJya!F{9KPqt{-_j^75L59$&b#`)W6OD`ZT2(W!0rR z26|?p$DT5x^y}$y>|}!UttWI$PV-S>7m3W_UY^t^7eT)RX|a1izg?1#5~=$g@y-itWG|pcDxu%U`&KH+c(5Ne+lDL5u$woMuxWwseYD6tQhyC zlFrsNl&p(~7}2HGq?qzM-mDX)rQqviH_zF&oDgapCKM|vx`^%dGG-$csvvO;T_VNB zqrE;ZYCF1{E%gm=pN!XAaJC*Ct5kXEPckhJegyfroen|qauogK`-BlaV?IO(v%hEU zxlVjm&?RNl6xzQ=j9P6Q7vAPQV zXq5=QT{cEY5>h;^zf+L~k{p;CaPZ|5%&33dc)eluM>uV>ySYs`RHebOSa(-awnF`%XVICf98jFls^cK_;ueAaC=X@Q{1m@PrTp<_(7S5umn?ffRD^MLB*n+t2ub zC6ZiGV#lku@0{wwoGASukcdR>@Ds2oLN(~eXYW(3ps3hiSf&x8#~(f?d~{aMB4ZV` zH>xd2v)Q+4?75Aa>TS)+>N+rn1GW$CkCIFHm9{(ZJuedmOjxfH#P6JL1k9BMcEI%l=L#b>;#h8g{6sWy$E~fgKx}VKKIedl7*|%5M z*LK4CfK@p5UtT6&hL&7vJ=xf`pt=fas+ul=pq~COL@uGruf(1Kz1v|uCeF; zhdp!6^W8Fo(1bb8Y1(~<-#y%^SFe1>{>ha^@x&rpqzJ7e{<~ z7v5_W;>kb#c!p^A_+1dH{7+}HhXqTXIZG+Kjs^zvORRK|hS`d5;893j!%8KdcrVbF zJ*}Sf`4^`V=NP4?UJE<;@I7+(G@VXVl$@%ra#i&oxgiwfSw}}l@BcuA{trs1Vc<>3 zUrkWM1m8dTUMak6xa=W&dqk4J12)L9JP0dv4q3i!CcOVeW>?{QdvauuJ*h4LelH@S{VXp!w*T z<9fIUof&PFrimKu-at{{c+Bj3jDHFk>p&1cR_1d$AisdR*B>3hgM)sj*9AkMm5eq8 zaRq>*^ffs*OXiDIsi+#BoSD-cG@=-D1ZhBB`t;m!frJB!SbHf2H85!WaTkGUy@ZeWYPFZ9a$z}Q)s)B2m-aPb_Ku+-^ zlx{~X{Yc8?ZnRY zT=GJc)ONx-HW2z$ap8O}gO__Qwm;byd3xZzwfD27XS)EP7d! zet*unw23qI2ghKNRACgVHxWqp{s!ym8yP%69$OgrvYgE}dYwsn1A$#;lKGjxrX}{F zXHK9|6so>1qmnfB8WzIj;@T)b(8aw^77$Z--8NwFdccX2$f2BP)5zzCv*X0}xQcwM zW1=g4GAU&s={N{>It!&)fzQHZ)i^_*8u0wD{m-4QQ zc2k)wy_Kb~;?PtT*42BZ2bct1XKG^0COXCw)a5FCpN-4EK1nYEQe4Rhq@ z0@PgObq&e+ZDNlz&t&xe4qW!8;O*qQA_`HRF81-=V;UrUme{_tStsDy21nBRIOR>m ziPuEH_ul7*=aoe(v&--awP@1M`HfPx+JDH5Gr=q9H$X24E%}W$7m8jK73YOAGHis< zhnIPR3ZfYz*ne$7m{&m>8d@wd&`3gAIlv%#4@9}BbM~OmkLZc^Ew;Z`R`>; zE{o}5E&D)4=CR%nWBbXwDZWt3!iEpO0z?bl46sK_C;$5XTa!1krw^XY@AtqeDk_X( zK}gX)gV1#@&uir-DlfWAXDvxm2P0}5aGa_+2l>c%Zy`l-kb~%NP?f0L$hg9(+9<@Z zeT(MUm>CmcXW)Xv8jxM3&8$cgz42%xwS|C(okK=I z1~?t=ftPxKrQ)dZ?L8Uo9W6L%GkT?VJAm&#NGiE{^ypJ1+@Qu!CKV4#G@xeBNxa@Ae1_2wHWIP?IOw@D zb9ED?GI>91CKEmY8TMG1y$gQ`3)%_0IfU#&HeM~*OE{D3J0&t7Uv`ujRhEF+M zYn8+8HinqDq{W7q02xXs3Q_^rv8-PEmQ|UWD7Wfm($?(Hl&@G{%e|+gC5NJ~p_;0k zT-K`<_wIE@!%G|EOdaB*@4F6QWY0@v3L9~|XTp@4a@3*|;ytc$S?}|!OC1o=&<)wi z1rwo~_BVb}Eoy_^X|HBOHPru*|A^BA!mr)bu_@T3^b&#-(%Sc5yj-T?UC8q$isTiy zHXL13{r*5bfm(FB4BV2KWytVKR8r|-D67GLUl2t71&e~R2y9gPi&pnu%wlE8b`2rrf-rlLZwz=ZN=;NMuF5T)Wrs^S-Y$Z5d zok^#yioXSZ!zsGFW6!dON3FgnO*_$;x0?L$FkhB|#~Qg7{y9$bF{-YEL@SE@fPKf3 zpN>tAI$(B^JEgR%TaT*PlM|mU+gippJv0$8q1b|(bD|Wr(JBm_2kG=kzTEclWFtpU z81%r-YR~8oKjP=LQq*eVuWEno;t;qKLVH`Hc!-l^AWOJwP4=*y-Zgt7S$L0 z8o1|n7STKS1;V~Unv!YS-(MN7!f8fWx;pXrb$|MIAC%8~=SxIT-mW5%r8{GTG6Kzz zYeS`69dVLX1i+^i?5Q!{C_ZLvuJ61xRi^LMVKfQxZ1;fu5JcU|Vq+H?dBYF<|Ryp2MwyOV&wZH0W^LxLz zQHom&!6_cx2^0#&A-ENHOOO@_TA&oy26qTjXmN+&uE7J87WZN;+5!cNes_L*kNpOo z|FgzA$Z;}quY1jF&d;1uk(pwjG$_9*uG?OJ+A!GM_-tFx3g;+zMEQg(6-}jqYqHsd zl<;>9F284qn=+`qr1AFi{2SNBNkm5(&J1)?oU$VSf_Ataa|kH3seZ=&2u)eN%Q*i% z!eNphxvUu9L<83mU)n=l|A@n*dq|(_VMONxJ`GL<2F|d=>8|#yw6Z}1LGfYI#s-7( z<@8E-L%|%e&HW0D;k>RaR)Nr#N=s7={BQ}e+Ewjgi!^?U=50!Nvk=Dd+;DAhVCHGI zo-R;|y17Ve@oUj)o41_K^ve<9O@G>~FB_Lxv|lZZrRoOAAQPQo4{3vkKya4AH9O!R zzS`2V+sLU-TZ+JNzO2#X1hU9k}=fEa`=5AR5S(2w? zV$8e^Z}15HQnJe&W00)^=|_ybQx@BLeXSnv?N5z2%w&hMr&p)g$#fS?R!)m5M$5V= z`ka4NNNcLD=F1FZvjNFP$3N+}3Rwy#>ge1>Hf#@zSV=PILMf`1rSR2z7u! z(N^Oa?h3PD{lPy3he)=l^}=f=OVEZU5bAqYpXGPDJ?4mf1UKY|h(TpV_)hq{VLrf6DGN8t=cAKM#pTHJ?zg+!p*@Jjp~e zS(4mV`Zp_4bA|nKk%(K=TBl51VJJI&=?UfLT8m+u&;D(t~EZC|%^-dHjuMB0uC)fu`8>6nrXuh62fPmY%vpQWPGeAL zL8NFzL+7xJ&9^n!7)&hgidxeGZTSUCR+4pgT0J+KnX4P@Y@=LJa#R~BTjDIZ$$+Wc z>Y0gkS3xT-<&3_bSg;4_(&wb8ByAhut#H?igg%W(x92FiB*P71Z{v=-m~uTcb%($@ z3B;pKZBOvo$@OYPgYZ5Z5&7o)m}Jh+C(iGiWm?>|u56YG4jf}zv_%4Tfxsn7X;Hw`k0Rqio1l5p!a$5|oNDnFm$#sL9VaEq0f zlXXZry`qyt zV=J+ColLOblx7+jberfNIKy{qD~{ye@SqU)ckpt7yX71Eb2_Z%;klW+-{LV7aV^#k zTF({uY4zTxyFRIUcC~ej%BX(*zBakpFG*`mO68?1)z~VltG_ zJs*EMcT+!gVEgxvv&-FE>Sl(sGySzQPRz6XT0|MncU7WlALIhHJI)Mt`q_YPDLs9@ z>`-zsKLCa0?^LD}#1JJ{z|mhgaT|6&5RTy{lpUYTuGcF`Jnr|z4?2r(E}xmR1*s@A zgDqX`XR(XbvpZi8rV1nN767zneS8)uSWhuB8CGfX#&o=_l~WVB#DbU9+&M`z;}Mx= zHh@NZT9>`w_bqhrqUPVM--*XRdN%bR)>BBWP0j0SO~X1X<1Wnci)vcu6D^F*3!=&n zDeZ(Em&tp&fBGG_F{GOgGSg;%30xSgH|bS(TK+UF*2XrGtsfuy#twUSMPYsp*sbHw zxjS{!=V{q-inJs~2Ro-%O5`=RA6OE93gm^%vx3AN>*%bMr$^Nhbf5h(#X7??OkH(3H_-*Ia^_aQ6tnZch0#;9PQlZ*4pKNbkSM4)|jGd z;i(-KRq8Y6HxvL*!kTuX=mvajvlhjVAYYM}GLCH$HZH4_oNdS#SC88-v~QF01#k|f z5X`Dw+w|+{*qz7iR(^txcik?=e>@VJTI#&=Mz;T)R)fhG#kj(A-Cm^<<7E1Os6@R| zg3upYr3{tl7F;&n?70zSpGjGnxDN`d(A3i#=@?fcxxOjVtF_l$rI=}G7U>kpl}6n-Jr_tQTk%F+L>hO13~0!hfEtyjq^zH*7yXwl_#<)c zQ_qL%eL8f}x-&_NP{S&rKCTEO4vHjO(1;49z(|Mi%@OAp>xz=K_pR5;syK+@=BqxszS1@%a~5$NrQWv=pNdKzB44dgjH#UN3bd^jTF z+4qx=@x_;WYckKiHjXh3kHvqdf@@M004ZF5_j0v)akHjCApoF$~?6^r8{(&dF(Orj$%>1Z6JGd z&X~52AD;)%a~Z9Z@$-=OjV5k&3hLoZ?2LsH1d>Te$e>b3qptY^xK3RUKn%rUOJy+RH4qlL%))AS^3|dzLpsk>f;w=H_lLf9m$PQ^z_vE>U~V_)Ug1 zUZ_hE$q1rt$a|h7yBO#;#JR63>tM>PCGejswL=Crg*iWuR1A>2CIYwkh7?s&QWS^< z*257nA5|gLaj3&2Jk!2}S@he1@!2sb?|*RkV{U@q)69a&ybnuI=AA6rP+fs~yZsQI z_*nY%o5FT=j8^lOhb}R=*vCj;$L$y&xD?K!MfNNai#{EaTtJFRXa|I|C2>UA73bNY zM&x?MbI{Q~#`ojH>6S_=a5Y9YN=l{}u$;OSA_n=L1+QAD{dl3?yX)(Gm z%Zik44hN=WjR}BMweoFg4tzVO52#U_dj<61#dC8Xy@S;>yCBaXZ)J?ab2EyWr#yxp zu*L{pW({cUNw> zSo1*5Py5RMFVE^?fz%PDjL&~q@fO!V3@11HJBS~}*ZfYT$+EopA=7eOrSB%x>TNha zGdnS!$tvtLCm)K8F6X+m^}Uo$Y>K8E7Sx&Aqcaj2_e7Uwb86d7I&n$9CPoY)5WIL9 zxPY-(lZN)Vf3E;aT^0vios;`u@ZhD*TfW7#DNJ( zV(3f{kG@yeMOE}J-?K7GI1`}6xC#)dw46c=4Zgs4cEBh^ablgG14#x8u+}US^yvq8?g=C4 zz-!YPc`L7yme&3;{R}VfxEj&$KWiJ*5h6@|C<8}D6=Cr5gzChsVVIA^T3)~vd=*g4z8^e?hS3~@p9WgH&$%$GQwd!ozI z)Tobr602L$TTKugidSnHMc9yv1Ed!8u!WL0r?v|dqW^J?FDvD-2Mypy9qg` zpE5snX&Xz*1QV<)A{A!GW!VJu`}5VO>_sS&Ai>`-L_M5`#}<=X3voluOh?mtYe-3{ z;{R&*aKTVa?H&-wzRhmcS@g^Y(CqK`s~$1N%isG>vX6g!qhE^FnI)PMB#I^uI=pjb&T$q-%>&kWyCfuxr?rRd(tGq{$VXT`j`Z0F^1uW z`KMymqEK(Q?H&u0y#zBm%(-o2ZNz5vNQOb*Lm;ZTH!<4GLJJs6W>-d!BXdRo824I% z$sfd{La)ECu-vaTDdf#9hUOn$}k}1O`AXeVU4YgK2Fs!6sRqCJogyg z6=A5Fx76b3dA2MCwKUNmctSeA6$5eN;@*b%7QhNwxBf_0-Ff&s)-UwMm>IN%a_deQ zd67_P9m|FvDKn>OIcm#o=|yLAGwPg{cD5asT{7??Ee3}xy^~1k@E9@9LDc`&C~Bm; zv{Ryrx6jKB7>)gA3HIt9+)NP(fW1lDU&~{GZ+0|C?adi#$qoi&|Dg3UjV1ZvEZ+ zzc_BW8ej~``#@WKx1B=uKnsAVKB^lm-K;HRjXc1Rk0F=2?Jc!4Dl!QjPWJAV9R|3C z?|eOEigfi5SIYbE5kkWYXtyeVK{MTf=}pGmO>R^xgKE>(&0DEPT!VufOev)YX*lB2 z2k=D8(_{puWhu zZSn5B4H+3n*H=QsU$#}liu}aLg3vUFhfR(m`y~j{I!~?3gaMJg-bQ9AF`5KYbyAo0 z%oV?jcPo9hV^HK|gq!)q1Bh4&_yK_%)rMe(Xp}WEL!2}NRjYnP_cYS0vE@`6XM6ib zUz+_r2ZJl{jbR~8VgSL+d^HZG0R%iX$Er@=$6hS6l9hkg(_F@$;nb?6Ef3Zi@O*z^ z;U?6P(lJ3O%3wS*CAOffq1Pb8>EPK~#W3i-t1gw-qM zKt@31l(jrzJKnA!{o`N8heStoo>iDH@`LdIwmwH#w)yaZ&yz=f@|eUo0t z4rvzfH>;Tiuz-}oH;W<0dDKLwn=4YTCEa`<~QEa>(AuP28A(W}x^c zx1M+Sih%J!fJ^NQ5t=Fm!1LMXB{EQNLh7VxPnwDcqDPVmWf02!)hbc+vDu}(xh>{{ z#qtq)a@7$kz>%)^61~yZ?3di+UG#wNx#K~`XMYjjN9igEfjm>~k-9?vVO3u#Z5uVj z@{)7ueBEGxlKHsooV9w>3Rg{G`~-A=C4M$`C9Wyss^T7NCaE=J&1e)9F(yOb?luan z-B<;t`jAAO))>=D?+@GaUN?RQiE7poNbuKak~%Mx2zm*?#lL%-{DyTGaJyQOaINX? z)+Q*{QtZE^KQYW|j7AMe*cJ9Veiuc8*D^CX2dc zf9L*~3;$IAWTwBq#aXt+b1ACLZtJ?`h-`AWS|GgZ`e)f<%>TiN=>qk8WZ(y_ED9`S~0k_dw3Iea_7f_a)MrM z5@hLK;(iM_1g(6#3QY7}?NvmarXX1px>+d?*Zj_~Odc>f&&f z^=)+-SESLc%{|(P@Ag|u__uerpYa+;JKVOV1rG1n*w%2lT>}LCgKLuh_FouMCKkUK zWrN5YASf2@z|H;H$fm(TyBn;GCsD1Wi#3HJbT`N}%j+j!*JH;rGj}aB3LTA^9KrM4 z;~Mf`{PjRG$u$!W0hfj6eHrJK11$_qIM1{?j8$9&H?^0; z9MzsU#g{WAH5OJ|?1nTgwCPm+8IU43=UgB7E(#+5Mt=j~@%RXRd)h_Mhv<60(!m~| zK(bo~w!~COXbVh6H$ws@`xsjyj{c#&v&=vfj6uYr5N)mM0>kw8`+ zZti_hnD{Ozs;fglViDOUdQIOYVh$S4vSo1}u$nqqDu>**^PO0_2hN*85#q5c*5T%L zQnI$(jxe2@=v;(V*4~${D&zY_%1g^3ky~vyGVI$0$8QoYh-QVA z-ZN(osj&J^$HzUf%CEyw<1KFFTo<3@p^_$$&~8+gSR{INbHi>q?%Z9BJ*>7{qG5R7 z?&t?hXwsP9o|Bv7{3^1#d5V+xVMVEl87=5}$|%9|9u_w>xrxke3*}6%GhSN4(x#jn zi7+Tifk$a+TT%>VP-RFiiWnNK2MWuEH@U9Z{QZ>?*m|NGPmDb0S3TxGIdz-bB((~i>qQU5tLv5oVsh{3D{JysaZ&k@TxmNWjjCxBh-6?J!kqW*R+y&ixEgaJMWne;yt|NpLm0M+`y_#4*AcINi*PX2`th(%= zLg6VPRlkHa4~n$6a=N)+IK()uUYp8Rhv%?yUaT%T9Mu1o&1RX7$7hHK@oXOmTwq z+gLu0*Ni!}Ij7xEPzpmor02G|NOV86INLMu=Sj)g7pzytL}7VvON9Zw|G{^x2I1A)6%g~ zJ+XR9RG{$V-AG8%!I1R$0`)CCy#K^@qydxggBL4^xu)gsOIM0_;`>-qUC1x;CP zQ^6QHXGB>|kf_~9tc|%8dVV$SADcNq4E5Y3?zdqWWHRlMuy_rRIBg5akvlx9{)GIY zVs-gm_pl%OQWbl19x6ulJtY0XfqCu)>q4+D>&H}{0%9Pv5D_~U^MB1R{_l;rsxS54 ztL47DWwYg_wc!hTv2z2D3j0jtemOQmMom{g4k-!dW*J}V@;h1W3kmc; zxxW6{=FwFU;!AFeu(#^G31o9>N}`D`>a!X^|KWcJKEt(Tq`RcxO+BRi_DtA!vA!VV zM6G@)UdFr!AV$H19Shi(11F|{7$3KvZbKmAi=Uc~?%w?Lo~OMVQx3nMxw(4ZP<$H% zK0CX^P+|s+{FCSAM_)I^_V@#Tm(~<3^Ai>-N!io-d1JVA>?rO28Oqggq0TeB%MylY zlNnB5Id*6~mkPy)@$nJ)#^=jJKN$lJF1P zkmoW!fYn`yb4kJpuCtPKm=%thMlaH-RAm$J##4fALn7dCj^1Ld-5 z_}jECRHE9On1CTo?P!((4W;&Npc12~fd*?P+nAjw$$+!9@HKiwo{b%c7KoW%Zb5Jb z2vOstV4?(#D2%PEZok+^ioy7?kRjG$J)?Jw_((D>?Ag%M1}G(Ct&(*a$H(TsR#cQY zIWt^MK{73P%bAVEaJ9wP)^*m4I>Z)lmUb^e^Y*2ba zt0U(#TaMQey!*kEWXYXQW>1b|d9McVJ{)YhhJ+Tn8_$ZV;UDPmCc_=4W5_%}_k&n7 zMqcs+za!{ViQ<#GSNAswrzvc^{T$`5+V-+5ctY0-_lHrT1EGk~^N_PEpC`E|XlcP6 zrnlPSZEM!7eO(R;2|@QkL03u8+sFH}kzO=0;nA|9z_#3FA?2C;g%8F)co$kHk5MB+-DkN|+18OF)LWO3)fJy(eiSw}T`{m;tc74f<%Y24R1ZXtPeVoyYX z(TFSURPDDlwqDzz(bu2W%+#ow5pQu@+H%K)$VH6i(@m-O&!&YT2>Wy6tWu2sa2y zuBg*=0JupHVDp&VhO1*f+i_>Z?_A1N>yW?eL#_HgcS@eBwmhaU5}=Sw$--O!y(zbzFk%l$ zn3Bzahn=g3OXrbgk93jt`-L4;T`%*VvAHf&nJ@t$iWYe>YDky!Aby4l5-IM6myJ5L z1ZJ-4?)mnRVOtvYN8mqE!ywhpKp-(n$~stNR`Oq1#Kiu&*KsWzyj!#4KapPwHoKnYRC-NAqxh{eDybLE zp%p#HbT3KIDCZQFQ7McsocCSbmgTQ1d%C$?tPOsoRa8vWASdFBVL9 zgG~Qi9hGO4QY$NH(T$$r z6teVApi?t|=cOsDJt})0r~<;w?-^0rjyAS+C!Y$2oCF<2bNF&NvZPvt5L5;hn#7$y zQgAr`{7j`(M=0SM7=8=5>f37bc?|qP{LiFw)$PRU6Ix7XZ^=%2IQPitLhQ)eReT;G zA{*?@&IESy55`P`{_k7-Ci-9TpY`9w0k!4=T2>69eoSdYb9J8NR8cBdd}QATm%^1N zUMVPs#8a@Hq(E9m1If*)@slikmF~WeG93G^_J&Ci9J_6126G zhXj{jQDsnxIt9|=I1Xp=jU1Gi%T}h1*)@tE(*UN6jPbJFK?2c>!O3Pr+;i7BY>{He zhaLO)T&C~b`q<2qe@wN7x8P(LM!)mPa!r4*qj1KaIFZw56^WG?V-%fmvJ?$Uu(27z zz6?^){vj+^GpG%PWQZ0-gOAC1)wNqkltm`t5pPq>;I&gXCoC2Uoa_)Alskmoq z+d3G_(qnP5KpI8~KpD{4zsSYYyeY^HSc8k+$L0uqeQDkI({xyS>(shUI+-)~b?vf) zgX))sf6T2^^;&om>~l#Po-z+ikd#xVY0=a3)#Zm(E$)Qne-E8C-gbO_OiDEXvj`wR zi#E`Q6cO#&n0*T*xn_?^cEzxoksrrp1Q9kIcj1cd zC6#-vi+|RS=Z}#!jpQ-W%|^bN&^;eKD>^NDGP@T&QFtJkM(jW`^PI%W-3(#u+nnIi z7bi{}jkNRy9++}^(@;AwjylQmGVv4mB|M+E6phvs|Fqd6X546WVYU`=PF-8%HfO>? z{CQDabKKb^_~ZIl3WxR+w4edo6;_mmj8~sXN9~?^Q-Ia_?aK-k>1LNb!MYVh8r0BH z0Oz*6zF07oW7+|Vh;?}2Vfp;hX=BB5lcA~ABdK`F=la1Dfk-50iOY%oxBy| z^f|s#D11^gGbZVO@^sT*rsig8=m%ff9~329zkO^jFP-> z;~KUb3;wcsrqxv^t7akdr!CwzWIatgXlBY zbB)RM3Hwv=G~$*-`D$tYozIIzV&qb8KC%LJ&~QTd&zZfqKmT+=X=-B;J;IeV=gGBk zLFRpHveUo37IV*B`U~}Q=;aY%0Nd7D56DjK>%7YK_W7dXBhHe%_;!AR7p6;bG!<5) z+S!z7T9zL>pH!ZoOTUy{nG>3u)c;F0hB+jidvv9>)9$=EM-Rc5Ia@zc2f(zlYt*v) znLn;g=BlntirsX$bRH+iQp#Gq6C3XDcep++V2AC{ouy$q~;GfZZ@MXACpph?*sN`hsr&Eo;aI_ zqvva6`ZwA%(YG6{fc4%BLRv3!yCtbKBJ4zE%E)0|$V|coe-Jd-D{ocB;=8LvTsC%| z_)!bzQ}v2mN=kg0s=uEJ=8Bl~yKU3m$1XmmNR;jM{+ti=y7UU*GR3V-lyYpXO{YBn z9%8_e1f)J`Xn^Z=Hgba%LdkCUx#J(-olboJWc0Y(MXl7Lg>Bocpt+wA1*RGg24|q& zB|1ox5rx8v9Zs#DhLCx}WR&x)h;c5|Op1?!Ay6)CCf?lII+-&}$BcKXE5i8GK{RQr zAk7u$S_lT5$erBQcAikgbu;8hGdyqP$ASd74`mV~=nV|BB z=CHxy@}=gLCXvp`XHB9CDJqTjq!-wuh*5kcQ1uFtalW2r<9*21mQ z_#LtTN%*JL<$RF6&(fW_#ZnN_vBlim@bu#jH*s5d*bzT|<@?60hA*1gSa+%p`>xBM zF4~ZHUJQL>LdG?H^Cputazn4bqwNc_XTb~mIE{Nkun2QOpOftK5|Uzgw%DX}?>dd$ z$*$+T8f_4$u8yZEy-jI&kS<61nZZ6y)n$N7zT1P5SjSxly<5~4X#VUkUqHM_!p3V} zyW<6Gz6|Ev*qDYWUX?dZHjWNwV8Zc9CL5q8hqJW_gal$f?oO&JJw{(6q{n&b(c9>U zX=WkEF1_4h+EHs#i$<{++HR6wqza>FJvUoL#G?~X!z9om8FRv1PfI*M>n)q z=DN+BPETP6I&C#O*d^&g%Et~KCUiQfU~uZHyk`oky01~)fukz{UFrU?+AhCg^X>M7 z<5h@ryJK@-XfmYo?{!njfFD8dOLu}VV})Kr_Yd2hmN8jQS0U>HSzD?Ur(5F|#qfF! zUt^Pwr|xAyzpj>uCr|8;&1+3LSczONPo%-25rzq8BU(RR9O21OA3R#lf9u6ld%*uH zAjS580P0wQl}!?uleAbo2LJlkY0eO>EXjxq0KzTrFlo-<4T^ zLZqK~$!fuW#>T>V*pjA=FKG>2SF2yjHRTQ%V3XDYz>oPvL3$uOu^Aj3Tondr;)|?Kdj?_ zkF)p9gP{dd$;ofegA&GaN4g)+s+sp!Bw>rzE)#-9hYw{v8KNe;8fxf-QPil280%{V z1NJ3n_=0jfvV$pW;OV!Cw{^>@^+ELP*54T)N;i`Yx!Bw49R9yKvEab>vejv8)-bC) zx;1C_l2(p+7j&qNR4NCVJR{nl=Y;)xnCLA3V!c6U)x6TTsIXdBv;Ht#HF9>q8341N z*X;Yf%3XB$L-Xv@2;jw0Dtf-bM`p$zQD}v}%HcedjZ^=U?(OuZQ4_4l?l)a241thik-EXC%of73wjp3@G?JlNkSk*JgwgvHW5A4M6SjA~Yj(DD+JDcgvKo=u&=&5A(5&LAPAfwlvvW zdJF-Xf`UE*hXT&VhG65tptIqhUL*I?MkFORc08K+twr>mYcMZeGNj8^Y5*2d*+mw9 zApC~HJkOE+BKFfI^ydYK67tJkT*WmIpG;mvFBYFMxQ{%A?YI)yawshwQQXe+z%&CH zcYa!LZ%Dp^!L7##IdQQTaX~Tgc?vcjHX!{}VW^Nlbu+PQYj9SnU<%o81*fPf*treM zm8H?SodiKFl@mGtlOeerK5C5G`F>cf!DdZz!Z~Xv!p?|BV_;(!V$)r(4xB_={xm;( zNPz;MzO`5ca4j?pyP92q031&26oxpA7^?VqpW9gAQY(`WA!S8J z^*mpUoReJ!ojk)X8&JUg^LnR1YLSbb6RuVgTj66x;brK#dAH>% zwTf^P5BvJuHOWZ>-!+?R{JxH+IP$99^z%Vk<8KjQ>q&yxZ&VH zy8HLLxu3zQp|HisA*vBzgPM%#`4HxYG?9eAM~^}pTmY<*cMuL5MYP6IWvi_+b?c%f z{^y4Dam(r?gViN7F<1j5%ep8zU@cBs8!OdI#>JH(K7nQn1s&KJ5u<*8(n(N0*U222 zMSdX@eCnm}ICR3p4D=P?NgT~^7uo3*`p6ci#wei z3?e&ZG<;4+orIJ%<+Fm1^XwOI?}f&|7l3O;un&Mzbh-N>h_y0Q3vx2a)I)XnH(P=r zX^&|P42D3{fbe~Az_F4T%l3L(!uZay^_qHKfR(%Z5piCDUUia>0ClM*HrSMVc55ss zxmC7AHimuSm0#6{7K`e441?=izbt(Y=$~C#7hV>g&jabvQ1&PYk2IAxoOe;e*>lG; zEyK*Y^>TVvGXm~3HN-4Mjf?gfeUrwEAdfwEV5iXk%II{mX6tA3bC>SoKdgp|MvQbH zTI?3e*Fm4ks;xmpN^Z7@m+QK`Tw`yT6+_F~KJwye3DjoO2V%`(c-M~Df)cAQeXC^= z;}nA~>WRgvdeA~??d!BN{+!MPpR?YFHe7)xiRrYh>cC}wv z4a7hoya7E%j0g9d?-cU-Y0q$&rT3(!50%+F(J>?Sh*SQpUEDHFs!&(s%?OSb6%bR4 z-JH$O)w!2Wn>}sb;IAsX6AzWCF`xg#^7M{_*jY4%iwJR7!ZU(K8kxF6_LXV4)2I?} z>yb*oi?}Eys@uOFn7%zZ$`aU>4qkT%fEPfGg{AEKB+llK_-ju>IOE1@x-Kt?CqJ_M zCbwe!bSCqN(Ii(B->@9JT8=B+P?Ar22>9AgFqu=R9N~){u|?y|*nA^V*G7T=8pMQP zi=Wi~-!-QH*_MCGkG6iDIJJEu{W2zSWMpR2XeQSno3RIn!1^mVEk@9;THr0>LWEd& zwP0vlwy38kZ}rLrb`%(a8g84dH|aq(=v8Bpa(;lNF5*>K@n-o9d>D-^bR!C)jq`Vu zX}9NumSj7zfwI~v^9FAr!wy~P3)dqrvGo@_8ee{h6b@hRRVsEdRTk{OB_Di2Z|J>{ zf_pw7?-gE>i4LCSKOhNba>@+u$Qgg>JhC}qyw)*E14wq;IsO5a5&2@j)XMQixhHt} zgeDUBK_pu2SyblTs15trx3y(P+SHd_MuoeH%O>W!w0#3fosrcd zr^2-Y@T-ZUOv4erF-LEyAPLQLk}=8FJrKol{03>YF1l90zSnG?exWJxL!RtPHVJnH z)`Jx0S?_o1dZ+eb=VYgKax>k>%{>Gk*w71?@)EaSV9L;bc*+n@Tq$7 z*4CnfxX{yenL84ya2iiedw z(Pl9+!-kZKAmKDi%B3dp1=!*XlkpcVyim_TXOB}KWkZ`DSd-6%3Ws#mEzCPi=fiRI zdm$Nm?^8cQU+=hgylSXZ~1ckW^_j# zSLbxD>iVmSPKj34e5(FSWXuJjGO>?qo%d{2%*d}J#MjmN%4+z^-QMh^vb9m7&9ZT+ zcHN#JsnmzfI-~MyaN(@}mxvLQh$jxsOKswVeW7T=iHIMm$ep!yKHqZJpKc~ay@=KK zJ#FdXnojsY7xS9J76%|`S#53zzONeM!?cX_X;0W^S{5eXXE44YArnZWPf~T-k&FBO zl#9s=kDqzgxQiTGuSA9zmX_SqtO7r z(8R*Ifg*ruygSQ}hUd>1K4kgc4Iqx^iC~sTEeYnOUrtOLtgRHiV++e)gYvI`uv55( z+e#dJWWFq8`0(>$;e3u~$6wavYI=hvC1c)zBQZf~ZA8$X+dk3l@-4k2oB)}MCsAif zEX_ve0_#hBZZ?=7BfebC?>iE=yT)c^%Ua4f;KR|8Mnl#AkzD0Z&h#`ehQ!U`QyR9T zOUu$Fk+CHh6?{Gh?*?wQ4>-xz#(7);BOVGh1A}f z*-hNO*wLJ}$FOrOoBi<*R_?mQg0HL&AL9xQ$ZF8RS-ASS_$VSR6a0>>sqipL_Fvdz z@$2tg@qEVJpAPu27;+UBIc>ILYQ7FAB8v~LOL>y)%jW&DkibFS?6z2#+o;3WX}2zO z(iq|atByEn<0d1HVP6e#(%=QVf4fnN@o+ecGc*m(c8tfH`ug-Z__#DzO53`-2O$A^ zA=kqFi;YYJyX%TPV|2|^CL=!?8~nWNHM*KM7{N3$)}r-w!tj9NYUgtqSxUri9KmP3 zbqf1$Ks$8@?)pe;Ey=sN#=L@!7qllwhfOQljHui%P|$`G@%uwt|8I!B=A7_%l2Vt0$CQUrT*j-yVs*Uj(CHmdtp(;4@sdU8hAUkQzt zxLaFUVb`QW+R1l1gxg9Gg7NW`znmz0t^1SZGrG@p92>B zT46IqYQGER659{@Aw$MppV*c$`1_&y)47mDg4N98)Ouges@rSPHE8=SKD6+)LvmN8 zfh8Nh^|O@>Ls@)$&Te?Q+XryZFUQkg?Stxjb{t3B&NHXR+8@ctwregcCN;Kp&z<;D zoeo&ba4z4q)ny7*zeX52cv7dJ|M6VAJ&p0VFN~2{#bbQdpw8M%l4>qN_(-eXiFYzA z$9k5C_lTX6bHJ-VMM&%oocV{zemAw~qL&2Y>O`PAp=;Aeq3w}ST`sy2Fj}u7!2BE} z`d|ZE?W3U&+Dx&vcvL2{tc0#n$3l-Tu|)2cesvszsz-etiYD)Nbm$;Hs z{|Rb{Ung2mZv*^koD?%ZC~rAz;*6X~wLjR0<$iO z-zN0+T#IB3ntNJ99kpgm+%cD)d(26Vi%Ma!Y)O3y3@>3MX_P^om;xeAhPT$ak`K$TojL zvrmew@l}3xr324OAoos7d6y#b#3e$gK`WmxzCqE$=Y;RldS}6jZbh%{eKC{5!34FC zdUSM17h6{BXO8Apimz~pS~TiZDWajH+cfcI&ZAZR7z}poJIi~JX{g#TL}eh#=k`I9 zNKGd8`De!zuUDzd4A~M>sm(H*9Ux*LYR{i30VXbi#mKEE?7f3qq#p5n*1*mjkB#as z0sW#V7%#duWoQe;%)ip12g}EoD3j*SjUs)@W`PC$Ol!}t%}i=48x2t!@ryOsG`yEJ zWi+Ur`lWUHo7ng|t&y}M%DkZ~X2{Xxd6-;DHGM+*dw6oqljw>Mq=$LQvU+ZIr_S|) z)7C2EaR74NhVcTLOj5MJ>oYKx)NVo)bl>;;@)85W3M#N~mhCKxX1K`)I)C%$)G}8p zf=Ir`&T80~Ru^#CO;V4SUda*Pm*H>qn}5Ev$d|P++$Eegw({!lpB-wduWk*JQVoFF zZ7i2ma!PKX28VAS!?Cu+##yVpv&R}Ga{1|07^Ce^MI{rvJXbiMsyD@pTvACg^FPnt zlCXE>Zap74pTT3HSX{T6D0cR?U(CDz#5oWHHlcy+sc56e1lONm&af>IHC-#S-I$!| zmj-lav3vA3>%`r4R>ur(h&)A{w%sP|W{ntgjaIV!LpoI;%gj1B4kzg?1;z5cAe3~VL5QF9&n zp`2-SwwIya>IN$NQU~H3=%s6;pA5QI~wA3bFXqtW6{@}q}k+R zVd~8SL5On6#z3H{IY|&m=%j6Cf%58&9_?@KR-oMH-zTfbH8~ub<^iwA4#_EJR_$0{ zjjrDxv7LyBRga8oHd1}`St+<75y4D2f}1-MUP?5atifQWCcrB!A1FhN%Z9vfWEP8ua@j`zAulW?k_?=`K+ zU`(o-w=%KciPv(IMW)kQhy9znFs_zbNpdq%Z?Fo+0fO;?ygHa&MRx5RwdqQ5lgW#F zNqon&VBN@ln~*|?t9N1tcG8r0 z0&5Xm+3~m3(MZfL>q^rmw4{$MMZWk}{f*9!(O)WyJPhkxCN(9Q0|%W7&-_XBlx|nYp7BL30Qz>47HB%FY zWe6(|YSZDh*3Gi8wfkQAFBznIHePyP)8mMSH{wo9uyl6O1+U^FQ3RLRE=Vh>Z=K#R z5S)=$40=mt%L@H7LR`Vo%M?z+0E`HTVK2=gv=N)~qi5aUd@OI?)dKk?kR}bouKZe0 zq8(tWucp&l3`WUiXo5n?eh(a{EY_vkPG7j1gdRVx^D$Yb#NGr4x&&c*+c|V!b;Gyt zwcg@l!;)Nn$~e!PHB1=4$atOMglW0o886Ww!B+9S)9KuV0qK~xk6z@Y*Fs65mA z-ZCM4A(^aWVXrbx+7oc_w*;??3_9zA)uS_AJ!iiD}>sr zAP@T!Qc5~EU1@1pIJcm_z(R|xS<9Z}-#rW-N4XTtMTp_#0Ki}{w~hDutt)$*ui)s8 z@(xF8cAXw2wd-(LIZ9a>gR)^%R(mXi@MDE12zc%{5I@7pTU3Lh&aODrLkfK#c#g^B zDX-P%7?n|`*K;ZE_HrMAF=^q#a_4%Yg0Jo{ip1!n(9jE%@*PI}a-kvV4!m5Lm;>Gt z?M3`$8vJ|uxBH>BTC)J{^=Ch1VME$t!L+N4SXfiiBxh33@r46ySeX5x>l>5{U)5o= zfFbmF4sbkmTjFMQy%@1(XYe1<4>tAsLRJ@}1pg~+}K%m ziUc%a?*(5p_QlB+g9>b~o{N1J9fpf^c9#zi%Zh0`JQ# zStp)vN(qdEWupzos$!QaV`po*?PaT1?CQNKWnC-n_0{%DF)Ja$*)B zhq4hWLmP$4M*Y`o_M@}oM(4Ef9yJ6=OG>d6^=aSoM#vvLO97!tr*#UL=)Cr~uRi8lhGU&1<|RLwuzzUo@54e~ zgiGe{1=2;KPEZZ*xxWhDlINo(Dj(Iw28yCAyRt}ocZtH3)n2ov%X`ym&zbmeJ|}e) zw@%@!-fGS7gKa+xZl$IP6hQY(?ep^E`4}$oX~7L>5Q0(UxRki`T&36I6fdct&hoh3 zi>7^aHT(JX=TY7FL{A$q=|?Qmy1B>8iGSb=AZdRG%MR0SQP27Wi(9VW=1qW}T!qYv z8Vf4|Kd*HEwCMaq7}&uoM+CkxjAJS7vO2NsbREQ>nq+qV=NLt&AQ`EIcx#v|P!|6d zlW4UPzs|by*az(t9Y%djU8l5V3C{n{;L>l2vJQ3Y8( ze7h=nFfsp!broJRW&`?%)g@c`4=V>0abHr`8N44*JhM^R?OVXjEV1!vj5i6fS26Fv zTJ|j9`%i7{WuIH(8dG6>R_&?5`Uu;uAu*C zv+%!n4gZ6K!yWIHy8*dbZb8-lwU>r|M@vl~z{MZwD9xjkhY5&L+S=Y2lV9Vsv77Rr zkhy}7ql*DlHP?o7HsbpWV^uA&4FXHnIqJmPGnRyJGpPLDjq^EeTA5wj1TT^2YZa6x z^HXyRWEIpJ-;<=jE;59)a16Y|avSBaMv92wXg^$7-M)R<^in0lc)dF_3fF9XWTE*D z%@gufRllJn1DQvebSqksSvasBgy?PfC1beS;}G}F)*n)_@e}vY%}oN}_flrXR)6%G zwaF}{vr&VbdF*0ZRA;lt)g8y%sf<7nPj zrUiJX7d!jo-j)jHbys{eAp}m`@5GEF$5yO_#!S%i9U;GK#yW;>hZAAvKfHxFWGeTG zZL@y;socG;5L}u1>-6kliBIv}veypE$tNZhyx6ZZehYE>bkmKx-{tZ(Jnm-NC)ai(WV)Pa ze&Wu!{47ezICnUDLgN+p1U3VHWSZs3sZ1P$TTP4bU-$BaaS&I_Rfx-Oqa_bM+*Od5 zz~WU(Z(9+yUJ0BnQRF9X*7_#?*Hzj6l#eCr()Sk`z$w$V-gH5&8nZeW73;g#k}Wqb zcnLMiC_-H>^~>_v#d8C_T6_CzD0XsMK<%6TpBC@u)BYSK_WK0g0*vv}Gbr=L3eWxY z2;H>DJvsB7(ywt1kGfYTjdV%ss!iDyJuQl-T2Zn|Puhwp-~^XejRFn|L+u9)>f!@< zCn14L<$9EzK>1tP7Qaa?8IEStTrJ;Evn$H5@i3Vx+*aLpNwP)Dw>3YXw;Bcj#ikTDF&QCwEE{9XZ0v)YXh? zuP9;AEH1(z!oUpi)!r>$Aj7+YbtHqvlnf~T9SN;}y0nh=om_5Q_|T2hzPjGU8t+gi zS6d4pY*8$T?_O7*phcl%1rw#;<6&pa`fP(9{qeP=kmEwfQ#5=E$)a&J=TC=lc7#@HtWK^&opC=lA?~Gg06Zy|E{^k z#~x(Xt;-^2*2uvnfoCcmOCYZ2jGK!TeqUV9HL{0HMf^FOl#cN~A@YTsnfLi|Q4$Hv zGiHi>F&K(w0J2o@wNo2bQE3Cc$z@ed3RkI{ZEuE z8TZaEJIGykNnTM)rPU_zT|wH&5g|kIi90p0Wb94qa-6+5kEPC716r|9ne1`R`)hh? zxz7cILEFB*oRDcSCh)paccAE&jUHlb$W-<*{o~~kNlOyfSvg>`6 z1RZ{9s~&!A7cDUIF&o)Y?Q_$7(NOI-rr$Z&xal3XCnXzVoGKYxZ)7anfn4 z?x5~T>K8P;{A@;BjKk;0waC+yh_JkC{C?1&lPmi zI_wnU1Rl2pWyUIB?l-wM1|Sb7wko~9U5ha3OON8RhR3m%I@BaoKte8LLN8%ZE;;TZ z@9!_6zK+%3ot_OjzI%Y<4cA^$Y`PAp21bLKOJK_HOKB;Qv;9Wf{fn04t4A@Z*{yCK zA+=Kq*NIrJF)DMG^3G(DG~&eX9XZ@=&FUuHvv51auUICfYvMfOwV{^Yf?e0VNYEbF zMvsfQrS*F@pLy?TM-PQ)xrHQUU0N@u`t0NOj?j9~v4TrFfqd{@i$?@C;bMm^1Ot0Z zG%4@C$FWSASs$!U9oJRd+}x$g@!2%O5uh-JoOc7NBbgZuvnjCQYvCbvf#;V}N@7ar z`sr`2=w-*9=Fh$TH2R=j3Vyfh-&sUBCRsmRBF%-=>lg^tGU<-FYaU$UK2JiHqZx<8 zREBd5-R3Hv8!P1oGk219)+uXIkCOi26eW&rhr1u~VNW7Yh>J{Qu#wSIQt2c_NtDNA zlR^%4dP6b9k4PCqu*Qi7lcXD_ix*0hWs8ESdBG=rEYAvwsKh*BDvfH5rQ3DsVZf$8 zyynE1@HTCV+)}M-chi=r*ewKrIrbg3rLP8=tfHxt5b{~^Y0f@-BK3nHMBIH{c zI^I}INUrO~5-`lH@k2qtc4c7DJns)mgx?;aovUd<098y|X0uBE+{|FyaqMTOhR3$b z;isR|APO_&r(`O^^4Lt39qltaGxv#TGwV%DTRh7EmtAfK{jK@JX~(0-mi+!))Lrad zWD~yp3AeSAlgc*(AKPQTR)>XlY@!i2<}!UPLD_XuKNk53Jp-IV0 z=4{Xs{&I2B{M1zK9uh}u@9|aaJXFiUqSs=ettp+TO|4}>oOXQmjSUfHXMpO~hJ-68 z&CeZfx}NHyHuJ%U_r8hC!lY zx~3AV&WNP!15UYj$0BfQ&FuCbO;uV-NbMo->V+#&qCBm%h{WB!>K)!P!TG>6!)XwPbF@v+@_?uBF98U0fyLjufm+W~7_= z>v>2M4DWPy5U~%M^%DE5`p-*!KQr6Ctw&E#tmUm?a0UD^;x0=0TIzD{L{NNcrRA>% z0|8uuw6}Ep1vca16I;y^ch)~{U`G^~##0OfMz;rqyqBV9HL_Y33YAcHHv9O1b@vh~ z6B2UCmrLpmuC`)<7Z&+h6|~RF2N8e;#Ynz^jb&+Bhw1za;Ojh_f0Cy$_Cu+T_e-yL zeXl^hCX9)6@qC@&-zEB)Ss~J8gsdD)a-Tsg+iq_H(e(ZOeI55yTNi;+Gy>gSZOc9& z69jXwHx~0{{g)L;dIpD0rZa8Zq-4gzte)_`_B0SZ;-K6o@@eA{(J`!o(^|qQ@_G&%vR#aKPvqxc*8?3@U+oGlZ2Rr!x ze58>moKM`PIU*tVM0{-C#`cNDB{(px!Yw7oDaonMm*3C@bvH@6m?ydz34|MWGDLW( zY{MDDEf+y3wK**xFuoHe2cGtI$?-zoMc$qwzXc*f4W0PjG}N*4j%+eld8(!c>af1a z#f8EAkR?XjD(()t4Y5T%95K}H&OGTFeWs08u^@+eqO zOAtxzh!678OziHd3JlP!?{t++4!o`k+_FWtDW^0+AH(2Ba?G>eTM9QlTFDjggpk|o z6kJfziPa|2i^r7Y{Ko&VxQ7cvq>=>J4jjGB?)GF?`pRF2IU)R+zhDAL6datCk2pBV z6qPW!GD-{^ObP{5fKQ+7{kg`DV998U?VitfzOZ^$A?S`r_%XVx)Mw{2MKc?l(9csW z>9~c}kO(J`*cNZfS}XQt=Nh|sL;l5ZcLw>IL$e=C6n^o001%h*UDPI8v*I^;$!peb zxpe`qc-q))*p4gQnc~YhaaF9A|CWwbNI8icYmC~`+o?rbiO8mU*K01RJ0LdFPum-n zt)QVmAYB~4fWz8Ni+97_X|3gaXu~C6#AMm_|uMWKi$UL3?IsUW+FxXdJNu$*GJjq2gB+1`0%a@V; zvU?Y7LdmuU?UG7*Vy zXSb-=;E^v=ewK~FQX|{;RL$9BBXpFQ?!87&f7YnFo7ahD+ljj#-Q&uFS{Csv<|`E$ zvF6IzgnqDF72-roWN6&j(Xxc6rr!0Q9}H&Qzx))e^fSDmv2uP%>doQR>wunmvbq6d*L5N-=^s*Kb)%p2}AF$Fu6tD zaJir@s2rFJ(w?#73^}lZN^`VYCm9grv|iKx%}*#fWRXEU%u_PzF}lobHS(Qc&~q55 zlh%g$hG{yosm#RPK%QKF&oc&Arjfn0y~=;4EZz%d zZ+Ry(X9RQD#we0pT&iGbPUf`g`8qD#VEFr)p$j5iJM)A*GDHXy(F{8

    $ee`R`Vkxtl< zKnu^$N-RdWNp`qYcBt+hod;PW#Z)?LzEpZFyxR+}Pn0$QsY)wrLe`fOFP{(OKl4j8 zFCMMvkqo7#^je}fzY}B3@q)ZC@#&Iyw8h2xUY83H2!};1OJVp@MBtyNDY^VOpe8Yw zt+Q*gLY3%>$QGm}g*TfofwMNJf!vTpK6YYaTB@d8@q>;NJJpVeXj2PmxY4s@JWSwH zM>y>j0x2`sLPt4tr|kQfrR8vQwYT`>XfE)i7`oVAW9n11us$WUjwyyaY3cbz1TMo} zY9)J`fz?GR)MFAM_6LI=R1+%{>~~M%nreM5#WtZn9NFKD?@XMJxXJgH@0ui?ZOG$Y zm@p0_x-^2;=VV&tJ)&Q0f#It={cm>Fr0`FBzTCz9M#SvU}aW;~Y5*H)yqVx)Dt4$Ln zr<#3fGRZJVYq$gM3bePq*8=0TiA7z zIU(ue&|Pz!YaRO@^%&3SN!cr7#-fTZaSK+W^{T8Ub_yFB4V>^v^{!Hm58OocPJQOS z`~gBKvn({4FtHyxbqD9U4ZT!$8An$l>W0%;SSI_u__08+R1foY}B zF0e=?9>sLHm1>DP+NWByGqQltRX93yb@1cL~@)b1vee&~$rD)GtIoN?RQOr>Tt z9)AMrckWnvj)@5Vo*f2`JoSgGt~BJ2bz(|5Teti4F4J6)-%4#8Rq8~wnuebKkjO?a zlX1f9!ke(2MB)9&xEGl;)O+3xo=;#Xi;EL^^0d*_JbQ1m;1|zp$~$o71m$7@Iz}#* z?%{)$s-(TIz7nx6RVScBoPte@M$1zuB!}k3!}$wcuP|!_q#U5G*l&Zu_6s_-vAX7@B95uvi9R-VXcl0Ts}T%Xp8s| zK@O#N5IZo&;VR(!LtKEbJe$U-ZrP`#KS%iKEc2H2-Un1gKCGVg5FL#n{Hg^keu(bg zx$ePQh&+v@j^^_C?86L!bju^$k*vV?L)uDtoiv8qFv9U&#~PEwl*?nf{ojo zHLqJxW)3d5^#8ExoWKf*0*6M$?Mf|442$aL%<=JR@!ZLa6q_nFv9mzX$}^tbpJrdJ zDwrRg86>S`7}F8|8pS$wM?Y8#e#}mRIoUzZ@0WQ!ymReZ_zkq*)U>a3JEjmoh=<0a z61ntiS`+FX&!#vmO$){zBu*29C+v{$<=;&sy_9Q27sCN`r2&Dh7H%orNY zta6)0v2#=1ZILDIor>Thgn#$B;Wp=A4+WDc_3V6tCM1(1n_MS_bRCP26ms3iFppE}oz}k_Gn&WfuKE&}ayL{Z z;A6i7y~j(FM!&uDWMPUViZ6+F6kJ2NIL4g^v3D=~`W*AtNqVgVewcB)AN9|Dpm`gc z!5sOT&;Dl|XVUY}5K@Q6M}}SsjF=Gvw`XBv3ek9KH7J$1Zn5HW=Xp^ycj?fhA~y2K zhCy&C0WL=qHjCNwVpP6q_BBQBMC)4{q20K9mD=S=I6;#UIfYwx(h>_fIjRsJ|J4xw ztILKLEgc@FQ^$v9>E&shE$7WmYdHfMb(e(-qjUsx2P3@tDQb23zUwp%$8KvmyE2DA zri5QKx5a%TsbPwt?MWmx5P(VtFHm#Hs!$?ZloKKPMuDLx+zhQEoxUa>+vo1H#TK9X zeHIB1Az}08AgnO&^Ns}U^hrrfF|;t$^{T^vcgS&(eP@QU77_Y&b>mIZCYX;M%f|O(_5l+0_?8DqlT3!OD(Pb ze4rJ+e^|zvVSjU87B`f3A2l15bzi`5&1L*wJ`V;?&d$3=ur*a`@%^o7;TS;h3O z8%Y?(yAE;PYqYm5^e&gJL-2+08s>V!_Co}y}{kpI+U3m^3 zeG{C#SC>r#O(rW(D7h)f8b)ki1Ix$-vp23g<)%J#?|V6Z)uc}j3f8ptiUikTGr64O z2u4Rfkw?lU>c}?_92|7t5d=Kr@F4D4Q{<4a|1xokPQptw(v10|k~O0oSuG zuzJ}1*QGWsJNqJO5pajI^gNBFQxNW0*Br|GZoV9pv0#Fb1asMH*-UEMD-bcOGW)p3 zz$?FePknP15?7KMz|t{rv%a!Mhm~UuH1FiKw{wqJ>ZnkxrN^N-FkxPBf3kGIdhqO4Jh`EP@=_>5O%1Ui*&OlNFQJ z5HyjSPb{73noR0~sS=){ttknE7<4F$)30Rl1G+R@8A5TpKWQx!mes8H>)zEBeC}th zY96;yS8wp#F0((EXOYajkOs@^TOyp?d=5eE%*=e=Fgd!#cihN$5~}K7aut|FH*J(M zJDfk1#JVDq^0xGmVKafcfN{=b`b43*_;pdJcklJ+`ECfu%`LQPxfWCbSbWH{r92JF zG3gflghy6^eRtK1c!wf>f93yURZh1$>n!eu%l^!54uW=|%ZP43l_%4=3N~c4P#z>u z-bd-=wpT&ah%|0*;r&tDmw)y#P2AyfYm3*0a8r+!u0BrVF6i!uN?X3>$B0*jEDQKC zXLwx2zg#7mllk_WyVSPMgW@e8C}%~NBe?C>k9={UAb)Gw{)AT5p<9OGd!RY{Pok$e zKF1gB9mUIN?>^zK;o3x$qw`v!D+!f#+8_m@-3XPartdJQOGjxvxd*^8KU|f^&I=HF zK6hJ*|EblIyl^ce16=3lU~!Y1nLW)wVe9ocE)6Gw)s_7y!oUCT|L-ir$VC^X+ou!6 zYsF7xKcobOyJO07DarxYrN}SwLM{62*Fa@{`lI_eyaoSaxi4pV->;nw`t$0WUp`Z* z3GfaG&{l++lBkpkrStsRQVsKLLT%fZFx##pE!|v*d=w%8K9T53!ju8&`S@z3wS<=zsU&K= zI{(Scks@)?!4L5e{Au-}icya4m!|XAstC}p2P3k&&k0uA8p;eof9dWiaVX#C{jj6C-h!%yWH#a$RxIglc3G{0Kc8=6SD5bGWB^rOn$eMrF8x?&!V=_M;SZ z4cy`iOpCpIkz3shVfQY96h>Nb7HR2r`H|~|0#}-$PSx+F$ZN72kSjAM0|6N zEo|RirV$~FDt1hJgP5pRV9YYJ(ld$Ccy_0(eR!+ne8RLkdabr-=Pim-<)!8f!pjav zpiPQ|oA%+c6_CpJ8ZV>4exkis+YTP{vX!ao5b;r(5E30>LUW2-t#=>ih|JpY)_xgL z62)C7>^w0FEbNe%OamFwIBZyNlybeoV7kk+i7~kD|7xsLSI1b(9jx8Qx|@0pBX?SJ zQ#HjEjR}>Q_eH=?r3=km!aa%4hEh=Y8G4u=n!>%8)O(wu)r01pUSr5BF*%b=XVOc@ zcgOkq{(moP{`2ib-@Z7I?CNkRQsV8%0kxwvpVk|b{ce~-&i8|(5-(G3a)wiUC~#%S zuFTi39z2S7M&@S?s0BgGPx#!F#kgl3LbJsu7ohy2*%sbzeg4yiDM7wJ*17h!DgS*!Qbn>+!b_p8CoS#O+yZ~p~tM7!mT+p`+2o8;6K zw#@BXfFfa75_XGAucCaikS+-MHLmJR0K9$MTPDm&J^dh@ctHr0I%ocobyWJ4ByMI?02qY&HQC1NhN=OOC*u9jAl~E{!vi9u2^S~?&ef1xf zdDn1z>k^qPBk>-lMl^{Mhx2o~sOTdjRQ9C$gmTJLf?jc(kk=dZ3~^}{=4<-jcsRRM z12b{b?u-z>3@Bs}zVz?Tkhw2SQx_vhlsN6Yf--V!EGohlzm-0!0~L=RHe;g*e3zh4 z+Vl(#519rd2(m^Ddppq9`Qsemx@G2CDkOrKlzh37Dfo;6BXg4j$ID(UGbK~~Tz2pE zv>=P*6074O!%EmwufRa_*x~Ty@s%-oj!zqOJu^nitAE{9W757G?^2@>%vA$8X}$Nz?^b*F!`m?Ug_EV&=}O=8@@Z zF&$cAVIIty#3+w)TwL-E1D6`@sk%QIb6>$(LG-|sHksk~MwEnJ>Zpj3X){jBN!%y< ziCZuFbHD>Gf=+_kxdu9Xx>m?l?Lf+ynh0kK3iHW-SU^oz z@aB@;k`TGY2#h)Ebow7w`#-FU!8@(n)4h=? zkJszy@m#DSn4j=lfA$Q($j%jm1M&#q?zvDZQC&8^bIV@baW<)W%vI-kY-#&q|IG6rL}uD>jP)0D@%~>+wDv)1(s;c9v?xU@J28DZ zAvm9iro#ugOc5<{@+J`24fAQ0MA`eId?~fj(xahv@|LcRew!xj|5%TXXO-Dh$+8lti%m+JCzMd{(PAjICz6emkjz7R!dkEd!L%cQ=50I%j< z>dT4Jf47jhn=7m5XNQtu9A(;}+Pd#w&N_hS$6*X1yS%I-p<@ZK_=j@romdK~d(yxAn@6=&$DK`m8m}eQW zEfoB;zBZ%DYT`pn|4OREpI=Y(&~RZ%Gs&SCnL{YQO1w3kxZlb5$FGotdC12W&4&2S z1@>72PQRS==^Po4;D@QW>x+N#q~n1{844vlQ&68yl4FaNx(59ZcN72DEYJ1g?b*F2 zk?Y(l!-s4qfR z7uo&5B%56v2I?hlmXcd~$rTF>32BL)IR@e!i|!L2t$9n%bmleHftH7K`oiglbx0cD z)-~tIm~&s!d`#C-ihe7`w$~kvBN-h^_<3f)pg%y2NE&>5#$c{ndwIn~4OlF6REG<9 zJC*_7K}$^mY|pv!3wf(!nR0#~x`&oFm6b66rF`>|Ku6oRlN#ckb2d$ybdo<@ZZZfM(lA!b$7lL_rxx_#ug}jV?JLs2MTeS z&+CIEadI&&T6&&G^~=7VN1?|2zT3YR3QwmyBnUuA&Me&Dj_K?yi%p^~^vh=YVj4U* z-XX@r1Lmt{{oNVmVfi{GEuz|2PnqLp$LHJO13#E6e>S^xVM^?vw89Co2qluOfispD zO(B%-9?nyHzi(R~t{WN*g~9qsaJUO>3!S5@J;Z|}dfH(3}$ ztSCulc-b;Vge3OEBLcUpq~-(g_{m=i>A;P73<1hAnurx0>|>w+Pb6KO$XICG zI~VW7W%FxucAgU4l`UDcqe(I`mw~9NisjZy9(-NE!a46C+=k2?du0iU9wMKsDTAZ}S#T1=0sWOVU5!@)C( zNX1r<-}+JIY?~B z(D#v*A6v#2Nd(cJpOac9Lt?Li=Jejx2%nfgufxxW0a{w_P1fu=m)%T<6?{J8`tsup zND6b~waiD@CJGJAKhG2~Qbo7WoLRzV_}Y?atg_X)mKDwARyuLXyxI7#M~#(Rm48Uc zzx=Zd++l1FTOTgJQ|bi%hL*q6Z8jV#|I6Ftb!u9lBkM-3G+nc+!eJeppGxGjcjXu% zv@M?Ck)nFAY6+vXe<+yh^I1!7(yIAoz##Af{u}TFNbJR?@jOUj($D&v&MJKFq`p~h_Kz+y))FP{$k!wsUM(Zr3vTit>!+16c%NNn;dv;_&)VrITR;K>{% znc@T;!GrY^$=EToVaNWw9kGf3BycM?h z5Iz>xWp3)q5_AhpfiV|vuG#pY^Q9AI9@l8hxVzaA>T7peEb1B9oAER_)1xgk5SJR2K$nIbJoW3YiXHSA| zPw#{V^?AMNq=HpQ4o@tyV-wcHU5#9>vB_D&#dqUZ(_^Zsohj9W(F7i8y=Q*ni-+** z1(TxQF7tWciU}o38@Yl-8m(fdMb@$p!$3A{z-ms?y7q|Y(fOL?LB;)u!TRiqIe&sq zO8BcyQ0bq0C7gwdPg=WVSA|Ka*h=?kS3K=f((Y(*HTo}qqU9H)?TPwJgF zaab~s5cMY~VO{;~;3JN;=gwCNvY%*C#oGPFuRAxsuHi0OW+PMH_-({x@lYc9&RXAVL*-cMPkP9(fieD~$nk#laLI)-dS@(Bxy z9K{KJ=J9dT(I<~3VPy9QR7CRw4kC>Z*y#4;B%gq)KK_fQqesI1JnDoYFW@*hFoekc z$VTIuhvC41@XOBmD+gKXroXvLTvA9Js|$qk!`g@KP^Wg`AQ_-z-O~`BK9_TyFbddm zJ^CsMTnn~C&((}3q9oEetKVx_39I#Y@NL^VIqrn!_34q()ghdQ)7)Kt&=$JRVs74# zh?p}8Yj_R_kJ#{{`hRt%hvBn zI7T^ReDckvLtN39wfoLNPseSXJ8np5e9S5y@zwj1alXu?cv2VU^~j9?#v}+gt73ib zKljG4Zml=V^UJJ**`wO0Nae|QQ*uA0wD*sqjzn0O;Gup5#{e>i_x!G0RnS=V;36zMXOD*-i~= zn^S$yaY!(=u;}#}_Ddh93lch5(mx=a>s26n!JmSJcxTsd)!jpR>w^{p*quks=v}R) zIW#E};Mk;g*@d+jA_k=PlmGmLz3>w!USPVPc4TecbK+#gy{gszG(^KetOudN} zvOb@Ygl$7-c6jl=umG<9P7xJIb^!%Vi>+e5~yXvZ~p2H zb%!BeCPcNoBZ8_Rc>GUt?={)c<7J1BlzA>et!9?S6Q9P0!rv<}oDh%_ZztW+FzuV? z9-R-urh&cH$JQSVg|FedK-XvYvK|Jb^k0mJy`Q?c5(r>>jnzp{FlxA1Is|c}EF}-m zb;qV`kiym06_F|yb7}7n#ZiQdO~Up`KQBbE9Pf)Cm6`cc1`*3|odUZWJLUH<7GpkD z^p*dZ;J3BEJQ^iy2q6wWO}muv-Df<3oJb=&vk_0Lxvi|%%@VgE$jKa6Gv#joG{2Sh z^kU|06k%2{Xfk)Tft*a(N_2}$Rm-6G#hqa|yYo`(+o8Yna;uJ;Q;aph>&;b(D11B! zgTUXP_n)*AP#3p_s145twg{%$H%~>w%$pkeCgn-rYAE>1GvXI&dn4!M{|wGG#^0Gf zya2Z9z46f5Tl$v!-8udE$giy1&MLc2pLL}{kyGRo&kmG>=!9bVLn!;hg!t;ZDS1cV zR-fGRggMoW%ouft_tIoaLKGNIabSQorVX6u=b>itVs5hO#;nx8pm1xC2Rv^!#StJMGHQ?M+ed`>T$nzx03JYHqHj_S7Y+mri=}wWbAXBB-w`}4RQ6<)$ zen6_8PVdS@^jsD1Ob$F4u@pjWEX1)F6=-M|e=7)-NfbOg5wZ6^Eb&U8)W~D*{2wBt zZS?NEPYWg*VXJ>aqZ))?qyYwcu8mL!E;WTH!W~D z;1d7D(YX>x;zq_ZZVGly$>tfVjIw)e>GXO_yr$?ki~cR>MyED+Loj3~Xgjkck~UK$ zHimFq`zGP4NXI3y&qs3;AG*2nP?sCQ;AT_crTU_IDLuk#r3Fi$6F3F8;$DCCmo5^Q zi}-62Fu6Apc^X=uXEnR?^O42%D`f}Wz=CJSIKTrkuk=D1!A$*R?Q(~u>xyQ^>l|P& zjqm=iTaO39>=R4smYHpzsx42l{Ix_0e1nvHfqO-V>8W+G8v8n}%m!ARzkBDPjU1F% zcpT&e=iz-0N}EsC4$zJym&HpRW$~*6l=E*$c*H1Vx0>w3c$8PM_G?D8t>ziSOyfxd_{`BDy>(=I@S8G2zH zA{D-tId9Edw(fT^XNQeHQNm*In8`E{AQ9UG<_ZVMjeB!+-@lL3aT4t8eA^cfGH+4= zW9l}SbiWa~E_xxzOQ}gHeC58~Mt-n*mi?kEm}(lgqZu7)q!+j3pb7C|(Mx?qBWEyxFd#Dt=FWsFBR734v(JgE5#uy8G>X3`HYt4Jx)z z$`;rt*1~*PWhrFOI!@ywaWpUw#QKa$_?EyvGdX44m-Qf!iJft3$Z|b?pY1evN2{TU zG9zv(U9MM*K*~9p6#x9Rj6dI!aMScnn{9UeEUPa2NwLB2TB30Y{;N9{9F&;q<04P0 z8vs)6aDMwZx^kM2;4bx$DNYfkc4>H%*Wi>d^4t!gxG>u7Tz4IGgw*%FrrxM=H&QPM zkB(C>s|ezL@34n?pcF%1+@&L1n>u2PrZStF?o86TZF5QsOaT#s`3bL)C`PPF(X=&X z?mc!mj6TOewZ_@RR(aX1+5t6ZK)b~b|67vq(6d*W9{zQjU)mfxbV$`u26kGt(dE*M z`pa&*uEh8ZrG>|y>q{wpA2Eg|^;*4e@;l3QEBpAjvE4Px5-+0k5keg*XAY!fsbr~# zF42XA$d8vKEIXazQl<=09a;ehz8%nmIEIVMMX`pWZ`t8F>K7MMmmTkZ?EW&-88vfu z`nBL=GMxU|Wa`^D%7pyrD2e>UEvV!_EUSZ@oU{G3Cc3qtTsNJbbq|%CGtfd{o4SdJ zXpF1_?rnhufy7qON$HM?%GzQ4YOj*VDt~W;i~U(HiBGAY6rV=AHezBD3xV<_mx-v6 zpEiVt8uH${F+JTIU3HK2@ar!!pQKvjb*Y;&DJ0#-G?9 zi`G>-pAL;#7mB04(y9&gI&w!s^`C!nQiv`o^_pvT%^4a}_bHF}a2;hG3X-YbJ${?N z7I0RO^vkZ(X8m&4Rp0sczJWIK$49G)^e)CR(w4{3#Ca5PcwD>^q`bRV1E+|SjiPp+ z>*vRP(Ly}MO%(-%Jn2nU+;_;9Ugn0)mh`M+auk6pWWzQ^PwGUzuCa5uqa#cWXshd2 z%dB~W6|C{=dg6WA9vzEV#Uo95AJ|%*?VWbeL21(N;ERol*aQOj))|0Y=GBFWi5y2I zhBgWRlK^8kY>QyDc|%`SnaosQ!dVBR-gjT)ZC{eedKuepl2y#5RjF`{!cX}{|EVbg z7WU)C*?zYSukjRt*1($p{N$aGSM4XQu;m)WBCn$R?x;1n zuT~RpC{c4~$%ss!Llh~4Ddt%c1OC?(xXOLI=S-Txb*B^RUT8dCYRN`y#*lVpVJg5z z;P6z%PQ+m4|Ksefg4%4uwq4wdYw_R^B*DGKt;OAg6))~u+#OQ1E$#$&3j_(!7I%sk zFSNM4Ki|K#W^JsQ^<^(J*?MN~Cv#udc^(JSrnu0iPw>&|gm*nzy?qbM#Z-eGSQt9c zO+{dw*C^A)r1--3C*voNZ|o{Jrz1b}KS`10Pp!*=Z#4KO&qXIJIJX#8RF2|MV+jh# z$-m$Lq+SNU&Q1T1HT3^$KKlRt)v15?)!*=o@`)+;^&d8~NrSU?h(A{B(@ob^A!ABL zc5^7U-7o%Z-R+|K%$j+_!0ma%wwgFx-a3mFthwiKLR=RA#}^kAO_U4zH}*sct<``w^^O?!X>ISvAFH)J&tt>&9MIf>Kt%2E>>eCfj-J&ta%T zD7*f;@K-SA9JTYLO>16ezlX9CCUOgY#Gp<>bKX?0YP{t7n5)`#_A0wsgmTiS7um8O z)3yH3U(jmj&$M@Z_u){&e<;m(CBKrddtN({us6ZD&V*{G_YFozc3!}yLovJK+uE5H za;FIwiEzarK=Tb(N?Ht?olXfm`Dpl@X1y_E>6G2=Ind5e61*I8xc9EMo6zZHll5XG z96EtRhcYJ$np;X@K)U9(D?bH+AnTSD?K@3gw*osVh={J|oWNwJB}gepBn=9-jiAV> zY~hkw!^Qt{!GTnzep=qEG4$%3@D}ZJ=g$<5kmv$KMJ%$b64SEz{Nr=UBxX=#8;QsS z8NnZFoU*gFuIuPJ+XAmjkike+f^z9XQyvFZnE>0YaO58|Pl?RJ=3WpICXP=Vgz+uC zW3WFswmQjx?Z}qTkn9y#)woIKtE+yeTc6Zlkams%roQJ! zNg3Wj9Wocaq|r%t-9iDijS zZ_BQxAwT1VSq~bUhL5iX&nIa6ZO*zD1Ym_fQU-SyvnN6%@LIm-B$Z8jXDPmQS!{9j zmY*ecGl$9<@QdpEQTzXgA|Bah~IEW;ptu~xZB3HRe<6}9A+uG5|GvDlR3(PN=-0^HZ{#02A?D_`a ze%tHmo_PZP9>e9eq7klOZ`CI;TGo71^l#eXgH3zm;`&lTe;yAVfrn0GTfMUay)QDW zuvM-OPXkH+=Wp(X^w+au9@{fFVe8*rPwx&LNYVxX^m3>RF0F?^yS93)x079h5j`5$jtfkr3~*gMyAD(l z0f?-pNgE~-<<(;g)#f~!(j@Zu*`@)*q4zi5$?3>%ezk^K(c+H%qr z$tOt5B$&8#)&7--Q;F(dQeCP%VqXd6sjAbeBl47u?9zp=-Lf_(1@qkd28H%qWwFaE4`f*E!Y`%Pp(j#rj z&O7V63msV1gm3hnYL_U`W)>>+gyvn+2I+%h_L|ydiJt{4T4~$6ZU450oHf`I;=3-P z3pJerh{c4(-LaUCE9cGS!K{3efH=8<-BiwG|-3{mB?3!vv*oZ zqaa3Cn!p-FZSJb&W7xt0M-Eu;;3kdvCyECypWYj2qFS=QJ6UtB#5+UWuW1Xe&01q& z$pLB{+3IbLjjd^OR|1e_>c(}ISv5YV1U)t>ef+aowNyE@xHN zyz5{`s$v-_awo{=&cvYo%o-ny)i-tr~LenuO(88|T)rtChtD$EDkB`wwt4+-* zsk%aSYvCB-YaptyMsA0F=r2mqmaG>hlf&6#Me1K;A`Mb%M5C^DuAZLZ zd{Pk3ushth41hd_WQ@7iRWxt5H|NLnLBJng^fN5Su-|nC!)3m%tY6|`E|{n-2~2S# zgMYEgjC-v8OSP$yH|?5yh(gq0VC3*X9_*;fUJ zh0wnt_s>g~9ytn~NjboZb%ZtAqQ%1DD)0Eu2^W4Y-Kvk=jV=aj#^ha<+|p^nOUwL0 z&?^#FHbSdfwkW|LiIn@DYWd2nqWtb$11l3+;?0nKS#iBoW=6j?9J!xu5ip!MyDtt6 z@GOmbyh-OR zUT%-jZx&q%Bz$IE%HaKst%vm2zuuV3_XOD$5Uka2P&=GuTl;<5pvdEz?7RHq{|~r= zVpZ{AtxY^FMs^KViOb3&0%J!ECa2@M) z5WgDi>1)gB{1jJOn)0A-N`FT%EegLDLn6R~EII?$bxwPYA@mlu6NKtoFBO3u4RzhN z{PfOzFxl$>I$of!THV4U5@6#*-$&#aW}6VaAL-8{la4M26LAa)Th=1 z%DCc05^kAl%SsQLayN2iY)bK&So>z)`dfybN&=C|+huYOz2d$n(~RNz^n= z2Cp{S5{5-p=IiG*WCeEbb-oADWY7+Qrp_hqq;V#yCu_|xuj=K%)!OfhMiuFS zVGVhZ(#r}2cDJ4xc6_826mg+Yw_NVy0F~*><-Za)!j(5;66i3d;Y_T2vc3^y`$QF~2jp2x|Y#tdb9 zd;xxgMtfml%h-=%XOA@k%fL}Xr=>)^+D}t+IP%B|(^rT+Q@QB+ z|BtJdlkCTX3rR!N%ypWFF!iM2S)Yf7tMvP{l1%F>oD4n;dw*(Zkqp4WGTk^hMjaV2 zb+LPjko#!}DYucKa5c#X!~D~9BH5MK@Ks*V&ned$prtTH`TTbM5_;N2BM}sENwaqC zyIL=xpaPmFarhnbABwjIZU$Fq0Xd`JbrGz@q5gPBI=}tWyWNI9`P#kH^;@Leq@EKMN0@uaK?}>r9XEIBir8U8#oG^fr?!q=hnd?{ z^f|Em?COajfZ=(dRk;{A=8w`}%jEx1D3=D+oFLb2J8!MfihukOTQrhYSY*_@!p>2q zLmddBVtQ|@p=_`Gd;fnKqItaE=-y=R{TtBFtlOAxAS&|C`y+ujm?v2<*kDvsrx@~6 z&be{mHcyfg4@ISvMPpe;a5*2XP;X0M{C;9?D8hCFZE{9y0FKXyfTT8xF-B0oU?NFK zQqQvvSI7JjemfUe=JxXigl{?Jn#%jq=@=wF?H(k2Y&d91imr9aCaBJ}a0#wYm9;8{7IzYDbV;6jUh{=(PxmC=yy zX+l%hbLR?)6JDp!t%sOxV6&z4V!UP91_)!eFG~i6SgbPt zRhKniUU6nz>7H{kAKckSAt*HeMncBAU;@rN0fASCgHLL3H6)ND1=2jH8$XP`aw1kUdk@p z*%3Ces+u#K&v7Mr83Eb?IvNv*PC-E#uAuyHQG`k~d&OMe*w@oPogpFxR}Wkp7JE2W z3Q>k`8#us;=vl3p9h`>GWp`dXckVnY7Ic}@=Swz7snyRx$UPdi!n9>f2k{9I35e!vawY_CeSI(%?iul7A(p`^9WPjzF*yHg0U zllhJw{PJiZ_Ew79AYu+dVr^n<5HVJD9naNy?G*7A8)IE{;44CH53;$1u}`?^%$$*N zyD!r{cJ@#Yw~4b9*~kma&)i`*R-^Zzi-+f#Bc083<|krz-IR*iA|H>D+g$Qs*+8>r zfcx`bkW8)r^TmZ}le~CJ^F4fnAP8G?Ro68CRnReyn+qD#CHadxc>W_N+SuIIe<<=z znkpc{Yd-Z9JRC`&+0dd0KZmk#QdQol?E3qAD*JAUu^a6q;#^D;5K=?)1xIjl#Lrgn z`34<7;pdUO_ZuepP!;N03@kl~cfCC#J@abb$&f8;k-eSw`}`E${*|$Gw)hJWo;Lk+r_ zC;GrQ@XrbUDgOKH_$dUo8Uds8n;O4JVJ?9n>JxTAXNWM(N7@cr8#k@+?6G^8$UDf$ zqH*fPmKy83Qo%ohqyRQ74-gXp;?gv*j@@1)(+Q8nU_D_geXG|IkOP2(2JmZFb{086 zANtOGeq1zUdNS}KDQDN<2UgVM*~P{gH7gERh9omQ{A-co+W~nG-MIG@@1KEvJq8RX zIsCKd{h|3`Ls}Ts$5t~d8t9psxEYvm4euAHv`>veEB8d1T35|tJz5#pTNHfM|2e%c zZlIUbd%ej1*;!!XHq*nMAhZ2>Tu~S9ouiNF?8_UIddRF_fX3sT6QlI4W5V1VtjS^| zKF`=WUpG;u`GAG+sNC{9Vhy>TO8&>jlbX&6C1t>|je$5k)L=~`_&@q@f?8#2zF&89 zDIUzWm%D(HaCh<|pG0dr;-7moUTW7|XAb)wMxzj?T2C4^uI^*;OmpGJfNK$(c+P`7 zk`%TKL6QX~qyRshPz=;Pk)gES&5ndDjV=cWB<FqGUzZjA) zAkB)?QFrH#!m)@Qk95Fdw^~)};MHdQ#bozMOH6&=Dw|zOSqiT57u!9=eJw3e+mI-d zCY}tkg#4t&@u;4Gi53@X&l>UVC5-w<5EI{z-bR>I@|$SJGzOfYd`H2V8vd8qCyVLR zR^M*`E}#G1gK|Qj4efS<=cD-=19`2=Ki5ES<~9RX*(pGJ4u%Kl=7P>sRto8awE^Jc zQ$|l3vxb6*Mb7Pv?GlRuig<1yN%k@uD%%iyhtxLlIH?rM>f=w3(VnxWfO^L=!bsbf zS455K*k7p&GN~Cdgw*>k)r#Dna!Ntk+`Y#ZS9@5JvfL>=3eW?Gdys)1`}^+{6#h{D z90SeDvvk2k3O@uD$;1myqm;x}jzblATHvaU{CdDW z!Zy436I2jWc3iggtY~Oi&pBG}G}sZv3*Oby^6XHYDWet^b}W0eXz)z?LAz0? zdbY8~p4eKR^oA*g-JWUOk(neu@0eExONJ={z+z^-vr3~m*P1zLo%s-1y;m!NxbKaz zS7(ghexuNl9v`C-?A)wtC5iK=JHGS%X|$)-W1X1mFf=}%u^N|#B>e$mOQ^&i_F0Vj z#B$Bxqj1Xp{;)*0p2vAtF8VRHV;qBw^(=BM^~RD+_QIyET+pa)CuZf^Z@mYG=LKeap;d^-MeHj2&KcUoC@PnIyMfG1bF*&r}iPpVUi& zlO7dn5!>uR3RiKy{(;GcJUs0;BBu18E0=sUQkfKuO5mRs0L({+EMU@3TpB*ei{icc zr9LC^%oc1iSJh`RSp@Qpd3iI%k@w6yv(X0u>qRgRwG~jjPZ~NB7p2S9O_jbs2HXJ> zP^1#K9|`pmwt`$-Pcoe{j*wAQYS#+Ck{EmXESmURLN_GeA2x?k72&NXko0%6IGJ7L z8yk8?X;Hu#jToz-pUdsYFj3lRe4zUPg)N^)UuDKz#KI)R-LPBfNN&Vgcm=3CXM;h2 zPV+z2kG#C17sAJji~gO^VodPU?tdu%+WUX@=+3QwYe9a)ht!QuT(;#^QmqMWql5$A zadMuLvR>m7i+hnvXWRVt3P?ho!4HlxDAl-PAe0byW;~vccqN{CVUhx258!EA89$Sb zPqQ~ftVWJvo_jAf8`}^d)~(4&vJ=YgZIzjb-H6QNNsjoa7bctf$#c^FZ9lfhRJ_v= z!(B7#Oe?8`^7qaA7QiZ%c?h@N84qmOP{|Nq{{8P_0E?C^>4>Hm;xA}jqWk#d;T_L;YshJ# z-Lk})hpLHB75OLGZ(S_LUvDfRMVk9+m~H54gD&`tuDbEr4N~O#+1pKQ@eJ9CS?n@} z)g0X2E$RHbiEMy9BU7tc)5chP?LzlFh7(2+#b;;B5XUtBcq0S#1Vc1!bnq+A3VV6k zeOkui9Vz#n#}JK-;WpoWpxas_J@&kP=Sn^6AOn-CW^La9$+7paV#1i?Nk9G$*0Z6< zNb;0B`^ZX}L6)LTRK`FVEQ)kq&qT@9WJ!Cd*MykJ+iA|{0;?teU_?R`bwY%0iY;H;?l^rscc`0k0H3n9BQ@ib8#r5%@HEQCmzU#rp(DzlEpYE zSHx|6`cv!UNOhk{ox8!GI;)IJ>VlMaT=n%o5F1Kx6FzpU-f+Qzag4ViKSZUQqV*Gv z2|^`9T#v-jCBEwmP|#+(y+tdA8nZ?2K*bxC=R$swEI}8)IGy{A8c)?Ent+1}R~;CG zOZTWQvt~WYFz`ix7e6{N6 zIqOzz7Kq7Z4w-zS0;ziTC0<;f(V}37YY)1vb-(Aq1yo9S({jODHz|~#!i0e>LwK{| z?Yl~KOD%6|cEudBlSoxEp_M%PR`Z6zXuI=ZcJMo&{gi+^Hdw~}0L`pOb`ZEETU}9} z0INxhqASB>l6}W*Y-JU1Z#`cv1*e@%H`cVtJGAI~Z(Wurm(lRM-)FP`;POmaHrF$P zG}qjNx|cCQF2)n16Nq0t`5vv@(E*RW29!1K+MOk;sScBNHUx+NPNMU;!fI&RNxax} z_JU=T(mP%D2WkEy_YW7^-IATvv+KWxwx+p8s}Z6Nvn!Ochp=L?>$~`FkJxx&dPrhI z#j5kkvucQ0`*kO9lW^qLnzXaJQ1qCJUj3whisDJC=_oo$&a3d<15z(r$Q`<_H31eI z^G}TX1_!5Ls+CAw7?}N#ZxZK0)Sc#TB?sM6(9xYv=~YLXg`0y4S)Zu>eFSRnqQSWzOm`jIwA@FPyOwMS;OZj;-*+3@)%;~?+*Npt;>!> zue|s>uCEP0oWJT!TwPr@ygvJvNSSc=)3{KD+U#MlhFKwV)y_)rDEfwNMv11NnST1z zye6$R|20N!jv?p`>?*2OM1$SzNBy$SeNx|di7$~AyYG-i;nJjm_Is<01L~?Sr}KBi zB2M1`_aYh1A$nYFYt&ahnDRX1ybwnb60jOaWqP$pe(VG_e$v#bOSw9)5vxnn#MisQ z9+ghwGQ!vad`hqHxx62vaDxC?!rxaUn`z^b`(P?jnIL>KH=OAW`(N$x>N+j;o#2)m zjT_x&V$ zD$hjE*eno+33Idd>m;&45xXB8(c(Qo1TJyHAIU&cDj8$Q2X8;Z!;v%GZ|YoXlc0lt zw`<1p&J;w#xHQZh5L=1LIdp+RlYv5d6qN+)n<5*J(^0qX{Mg@tCIr>Jq z)J)sg^E$P3LtpzeW_fR_}})0u>}<%{Ksm zX-?|-vA~xDFroG(y8zP~QC6Ao$scXq(VPF?Y@~$tPEU3-aZ(Tam39UFz0?`JN#}l#4{!&D` zHm`%F)82E?HR0zAg|xODU?;9Zdwf+pYD5ozuHJD}L9CKm*(f0RS|0P2B8GS`Fgdva z9Mv#q>m&YvGyGd%xgoZFb}gl@-;ZpAy&uPqGcd>Kgmap`NUeE|q&LFWx;@ow{lbMi zZ36zhLyv?kyoqqEZIkIP4Zd}tSLg}=PKZ=LcQ?N;MjbzVh8#|%_ zeIM;lxL1X5iJ#cLz#sto7727W{wnkaH;Dae8~8lX-r=-!`S1n=?IDGH6m{Mvu|9;w zcH|ixmRq0mH5;1;HZ|eez<=tvzRLGTo=c-k9aq=-*po7w_QthBbyIvenv0U+Ul+upZKTN1=s9G1qJyHuG0E` z^?UDnSMXcf`7xF`XN*2yR+R*3x`aJZuCipy!<2R`!}^0;cjy%K%OWS;WB4v3D*OeZKAny- zYv8V0p|{Ng8ouBN8ps6Z4=j@W{*V68>w%Tarhs^(VO~q+Fu^X1@;46zB_Wo$^F~bD1H+9Pogm!9$V^lWPAH>mCQcR&c@#XS zdv(|@fX8*W63g9lZ;k3Kyn)PV_O-KYZ@kT0x4_YUA5Bu%7;-Kci%ci4YjMo0VL!Li zu3LhaF~`VyBP&&HOF7RbETIjRWJUnreO@J1O1abFhQ!!pSh-G_Bl^M?*9L0h8 z%^j3mg6hUF7Nf^g?E)!CNPYqUqID(~ZwN%zH?DLIE-X6RymnEEQRP+`h3oie*C_d0 zbs6Br984EcZ!>FBXy)%UZsVmqtN!`hH6_66#%U^Yxe`&BSY3sZo zAudrys+>jcR{1-cvy%NKH*+N2mpk7Hz8~5P%M~|(ysv8#Ki4hRWqUsYoq6G?(Vxgs;RBj8Mg`JSi4kkyt@a?dUAmG6 z_G9I6xP#Bxk0Q5gCBg_-MojiUta zw$b`|sncU^1F(K)-r2z#HC)8q1S8x%TGC4*i0Z-sh}xJt>lPc)z>RZeD7ooTPavS6uzCO-OL5luE9ib)Q) z#wb2+AWsyKZa4xHM%toIMXC`AX2!)$c4VL}>;F?EG1yMgdi~TizH_)PDbh~1uoz~i zw#eG}4M4Bcih+ZC#PC$oQPO$F_nBcik(e5HLwv8F^;KJ-BD||#w(EWsK+6a0Ev@n{ zs3%s-9&784A1%Mwn7Wlzog}BhGsaS?$Fx|hHp@WY0oRZr)}HZwmobiD?Ti-b z{ey<`zsx}yZNuE2m*q`8-qq!=O~%5~Ox%P3Ax(AeBcOx!IsFh$X__*qV*laFnlvocqm>wIAhYT_jUv(ctXxXU@$7ND^BGK+PgC;k7W~x9Wd;YU zf#vG=Q7il0wOgTwSVHP4JqqI({kGM%?C=tS2wwWH6P6=UhK>3H^-D@CyYn)9T!nJ~cyq__m#V8zOw|wYEScl) zduQ$q)6W|>c-0rD4d3h~5cB$Lb$Vlle)5)1V^-cB>^VYgnF96oWX1w9R^W^KY$NP4rb9zI%EPy_JGOT&aS+jogX_P5#%O;xsE0EWn7hfiAwr-v?s>aazFz09$Zi-wsWz z0`ABskNIcvHCeb*3P^mhN?f)G-V-tLk`+gsqj;cY#+?qz;bGXU1!m7`)3{El)3|sD zXRH-j*TnKrX)KDwn<3ThsUb`q$Dp+_CH08-OlF#@voMBTPpS{+AwPxxVk?GIeH1zz zoDD(S$1%oWopfmca$sB#>(tk%O=U{VR-4v@R=aD%YA9-fCb^tjgW=j^X<5N9fyDpY zMep>UmjxDYoj~o=8R~kyR@O=oV>&PeLCUYPTXVt9>mcM?6%hr93pljeX!2Y$xysGs zwrOWIHw4TTtog5;V@~t5=)&G=_L5$4t+;+OVs)voRikp7cmNA*wjh2IR4^Wwf^=5N z8$SYoSak&eEOc++3OSz{|Eem&N)=1JJ3 zxU1uNG~_{#=a6yM02#6^x7}8FP*ol9YRUz-6TOOYugr#-AQi*k`6DuzUob$@b3j3GHmDe zZXy5H>=Gph7#xr(L%??3lmtbkA$)8iVI*TCV;_5VOwS1eVtD=L6BNwv@N)4$_F{R*%0GzGg_}if8DZB~}Jz9es{m52AHE51gp$5{U2SJpJtl(NB0P zwe5Y6OUd7^9r;^(g(ZGpM)=b?Kau;Z&)A_!MLY0#g}3vyUTJ!&8U*w{gYsVi*v%C1 zYnc!xG({S<;KnIvc5CVo19;D+Ylo?=vGlHqnRDxfgQLWT4`tkkp3@;f3&Tw}eG`c7 zV+e`^UMq)B0Pv9j00iW3VPYx5-tOI-p*$;m=&3OuPF9$EFF<- zu6-%(M)LWK6$M^AJpR3?YM{C`vo@qz_qhRfDl0XAy!(|V%M2Gt+f7Q#xi6^wPCZmsCMzaG|e3yOx z?Z^MDwejLGS~)EGv2q6XDeO&!?LgTjMm(I2bRW{8@bs*i|7+HI@oF94(aO8<1=f;_OeVl8^7+|A&%4{22MI>MmoBaTeNuw#2`} zlsCRF>9rCHkw8E%8_86I-cei%Zb%3M_@bYhm@HZe8lUY0sHwLB9PMOaVPr+RXwYC& zK25zsKg1v@XWToVA69dDB76r~2rCehbr-S|H`^u%of_;1@Ra=kw$`osF zIUPk10QI;tT`scQht47;c0>AKQfI%0cg_z)fy~KzLWgVRlS)l|9A9XuS+N&W)-lBR zZ0;3~=2QMm^DquCcEBP&e5x^PUD)ls%Zr307Y4*_<4izaa4kE9A5E8y%o2&{W0E2g z%5}ZC1A-&BhEYmi)w@Cj8xz zGbDc>jjQWE7@RWt1I(m=mzD=B0|Glcsd1c)sjDygzB4jJexf(VF86sscCdIv zLi|;lVo-V!HED@4uYkF~7#}j_Cuzs;pE)%b`K22%XIXQh}S$CbhZcYEGJeTdU~0|lDrty^`oRW>|^xzbs>mJH3XHW}=q0FvWUkE3K2 zc8tAZyvbkTxX!hA_`ncRUuDGvMOWP&8JE}nvzX@9N(d3D_euBGJCEU(vE zv-QO?pc$WNSkU(&0S_?{b_sZ{|8JdDNt462j%jU!< z6LBj^mPvl*3s@raX$C88v#Iai521(+LGN%fBeOJ+Ne?mwAt5}ULU{jIF@L9umwgAv zDI@VIE$w808RV#TgrbH?I;UYpCd8+vAumU0pCjTnE)Kv&Ldy9EJ4cp0X!Zh6{w=Lt zOPgX6Y&H@u&W@Vl(5d#WpxLUN*4T}cUyUj9^_y2*d8&o{&I|4K(SVtD>aT8mf~xB8 z+52>vGidoFMVEibl~(D~v!m19ha_AJyw{t;_PlL&-Sg#JN7xB46c949#Eot{Nn0c) z=_g)gLZ%{d(2YBA{zFldK>B6c2HCzPy$fmD)}&eRU0K1-88&i_`xNDHc~qK+)xqCK zei6Hz9jBsaHWhPiNX(@3ee_~!ldhKve5*;ZvCjV`r`dY7-NQ03wk8c$(Ul1-wZv$< z;sP6`y%G9qJH;~Z>xZbW@Eu*b7*$*jXwoYVoaa`N|K6_LYW;8aD7uMwBzLyjIx@_g z(apZM%S+$y)zL!!op6xh##R$`u(z(4ZTOe3cBGmj#ch;MnMFh6PclDNB#aVT9w=T* z*5_b-W?lUG6g3EZ{>@h@LyM%-6c~D;mg~i*rtp)Qwe~FM z#3>vncr1H{R^D3#bAz`ojht$wZFkKwBMt5;z%-OASHkgcqGTvR1z;Oxk45F|?)oQh zIsX_tZuRDd@+jXsWlb8flD@153XN6tsn!~(&rVv25E1D3BsvK=aQAeP#eV>H@jl1i1 z)nZ9*0NUk+{^k5EI*yMAs|XN*PsYV$mXuM^z&3Eu4wlT=2&3QU-oe|T3w(g z%j`p0^yZ)?HAZ($*w;TU*FoH`vN3cab0Q>lFGX`a@;RJcU(FUS&nAz$o@6^ypO3pN zb|#H+wbGkuzx%{v>s@D^LIa`fymvIC!omjSC-pGz(SGR)PVW&gGTWxW8!7Q}`jR>L z2ATGdK%jX9KWIW{%E?TL6ciYh=uKJa_fqnz7XRUid7 z0wJF)rsgBZ)49Ckpc!3FP|g&dB39ahCPm`3oB=ddK zD(vD$wJ~;Sf?k{572Y$ODFTs(dX*GG7U!~ohK!Ro60E=$y6D2 z$Yl$*&ojl~kC`3LeZSX>$3wdfD~&!2)Q5Pr)m)}EU==oes+Nk(PrK#T5yS%YI2Us| z7F%USU*ca<6x#WYm>Wk{7DZBd5ulkoxX@2Yi?4p$Rd{M;MMgr^c{ce30FIPiX zTvk>Bs!z;gF_!N2DTGz){-UqXD~d9Zs-uANa&S@ut`7Yl3xm%Nn{SgZ2A)(8JauC~ zpFxHgprg8M3(a61;nbs}!jHvmc5P`PpZgL$7c3cLlH6_wmu|XJ9t#xjQ2A{~YLFeB zI(X8xp4Gc&^AbZ1F5t-oo6iF#k(Xsp<0y6b^rs_<(i!E(a@zYk>4GXh(x5U-t{ z#E=JbDwpa}NnvMF#15l!&D63VuO~zH{WgGCG%v&modztQOCND&$(ZFk67r?($RTUZ z;EoQ!Gli^|Y5tvN5Kvp1@A9r>zoUrY;dQ%07tMTvGvvc+t*HI-M3FpW;u^WzwuOq_ zVLi$SD<00g8}TTSN~&(jSRj}q-BNY8J6Gygmq$0~s%bpDt(&vk=}g`#Wel4R z_!-95WWD@8HlJk?W6-z33%}*YW$*EAdqe4k@q>^j#irc%9^I%agRg9pF5|c}b2^{b zZA-V+mjQBu%NZBb6UptqiO#l%Zh=UN;@pJ^;j&C{j2si%<{V1ZcBjLK$g4L(?+Vz~ z3~O#TU2m_iJ~P6PHjGKHvU})En`zWZeo~LU9&=1ihqA*+;R9D5>a=qziL#fWqEumI z4qm6dEl(Yy?>f8?l4wV7I2-QwmBy$w=Z23uSQS#!4#`m71ZE;?@QW|(OL%QUrM5l}#7DAChg=AkHnU!&+7(#CeCOxt=;@+|g({Exfo4&-J(8j)%* zbwV||Sf#x%2U=AkKXHB{>?6G1UXrXL8YxU%bnLBHjmJx6lcSND%VT64_h3U{z4<5) ze?5Wiv?}V6Zv*yCMb)Hgkt$5C!!6Ls>t1?r+&vPO!sP~Dxp%w);CDI9pE!*IKm002 z-nnx`t>xo$-G%;MH5zU3V&JRuHpv+osrdaLN*gc*HN5tlPOMLaSS@1cp!CSyXX|GA zc%^2I*44XR&C_UvUaCxVRFKUVstjuc@ewKX+RIz}ZhcpAB&nl&`xRk|-j{js9||o8 zP4cSP$%Lm~wxO*3jrUH~T6ToEx}~hvLS+&)u{0WlC6UR4tlDk(SzthK{5HtPb@!}f zbgk!iOHw=sn@i{y_v-Sn`8}F$!`8FjO|&q|}NpXbCtf z2GEa{yP^~->;Cq8U|N$8Ps&YH)WcLiU-$qd>TguO&s~Y-W8_)lr)Mx<(OEni)K#x% z`vv=VgIcb0G+leRZ8Ni+7WJsjtsIV(RR3y^+AaICBS~WG2+XQ{0oY`Fr^g)^e!iOt z*Ve03wheo3HGqRiM*^c>>l*G62$cxC93z~%w*Sq9fffPDi*OOYqq(Khb?R@?H)nom z$0*NXcb^kE_xq8Nu>?bNuouIKqUUvM0+~12+v=z~*tKDDPwXA#M3tpC7sZ5&#baxy z!>_Z%7;=LUe7+clZfQjsnD}pC_#sh#A@5GRs}j-2+ng9v@74EmBlwGiHQe>TmKvT` z&x|k^jSHi9wpsEx<4or0ZS{rLry9e^0v^kine#XN&8+kkwZ{6ou~?cApl?r=pq zO8Zg}X)YagY-OR{d;0ZxeM9+@VPREk!QgrV_SR^7Xb_^UXZL+P9i#NizCxwdjD8mY zMW)J^rSuIF}uBqTe)&Gz9EY?+dVCgGpJI!9zC5p-jk)>eeOdSdhKHKX1r@= z@Abc5+`8jUB1IG8Szmi*<_)uQIja}E<2hzN;E0*3s)cErmVpG88w3LUf*iO`-D#|N zekF3)I$_pEel@iSRDWQE`J+ek7LBOASHi-1l{P>9b#l;jcr4XG$?s19);KCu;u08x zl@A4I{4+HV&mm&6X4ELhNqf^salyj2y-8|a6XP{*yw<;;Z-ejkp!@@(9oHV zfr_U`P^Y|v39-pKSes2hdFWN$rC5q*xG}y`Gd_|n9ZhG>IE+izky|!%>5k;fA(!>S zRas!UP585cxY!t6eIdc~P?^d)Gf~rae%Q~TzY?x{uoxkjSdf`LhZ8NK@z8{m#I;&G z&NlT3ifN>g8z60*%<3D#gy*%hR8lJJY_2$V3^ZfKD}BxPVJ^iNC#SWeqOv{l3-zuA z?+wY)xVMN`OZ9bw`RcsBD{2^sjLn>)-LfU6MSx`-{cq@ZdL%^MG_%(AG1@)%E|S?c z%(GcTmQnnO4Gfp0Q)+(;x0i}8yo)s5_*mE9=8GvgADcY6IADP=@ARhY2}%4{y^395 z)+qijJqV4!h3EVlrdK^cXghTv=n!;=7fp9Iz7#iVUfWPPy4P&nwbjPk$cEPO?aITx zn@M>IOD#TC8`vG!WF+DYH&vdX#dmY~sOMz_%$B0STTYlr_nD*~uOZXkZ=|M8V{a)? z@nOLf_F&jc$jx^6Q@OHQX~UDGULlS)aUGh{&27#Iv#y3s%wRKObI3#|3BA*uciVg2 zvMXX!ce20#SJKAO-s9_%P|oJGnK>)b2eTF)PtGUt9Gcu#c{p7<(V9u(;LgWi-k#mq zxLu&-*V!@|Gm8Zj%_eGOz^M4n-XJ)zqjGPM55pRaVdL_CXW~hxNz828cfo$-Lz_|U z!uqil#SDGaw?jP=vK5@9F?%H@j^fCa$*uP5z#kPX+g-WN9n=QXQ%6^eAHFD}$bGSi z=TD7Jw9Z6^2_^Yt>$c?`i0t+F{<%mAUEE*#1}u~iR>@8q7=A+oF6;8|ibRi2OS^KR zQwSEgy63nJe6(~S;&;8*yRq=XZ)-1Z5~fdR`luzkvYf8&C~yBNd^tr?_x{V$%j_;^ z)Rp#Ifa|ODR14EUw^|vrM01Ko2d)5pJ=b(V^kCyx)>4Ivlz=V!u+n2hk=tY7sE6uG zaV+WtXu+8MY0ke=sEQ{#6VOFZs^GEtDW;wyE&`RybA>^F#RAaWsjKb?aiU}b*LGVq zyXM&xrW&gxqP#&Y!A_0X@sv1L*ik%|hHYwvz_%g&t)LF4+tywF2^jVL0JtkcKgv(< z4G3*SU0*n<52YNgxsHiuK=?xjv>pV!i(Q^s9uWU=iT}8Qty%b>_ogaiQeZ)&a)63L&V3Uw;-sx6FNP0?_Qwiu=kB|i ze&5xXnurCWPQS~VoG*ra zwKih9Fxq)vYy#lfOswKcVJg}hH>51cb%++ih^x2q*&N_I?@U=MQoZ2w;i>TiXLe{Y z#NaM9s;gbHW6CnVXV)8-F42g1ybP0;&i!9qtuGh1yTe3kMv-h_xs9_!(`*jMQo+wKux%%mbPv9{@C2lPjyFwCsg+1ym_%?q zSEB86)S8Do`G*bvgsD(@yyi%`AtT>PXl)%6nk+Pmo79q2@YG~my)-ZD*?BDAoxJ*o z8q&UgL+*6;OOmI_14U{PgLKjxUAX2^I*!I45Lf}A*OP5FeHNd5;Z|48CjAX33jQPh zApLqAUYN;XFV0s3B^Fbm9#qKb5-*@+`KXs5UJ&S7slL>Aal=)hAy27&g9_L9Vg!$ z9-%BhPZv^C&vr~Z*F^MZk@rx~%c z)5QOTq+cS;FCppp_<6Ll&Xsn4*Sg{KCvF^jrEr`TA)~40!32Xof1+g4lVBP9<0Ts zXn^9y9U9!-gKLrC!HWhfTD(AUXeYm!i+8SO*84weCD&Ow>wIPJ{dpc1J|cE=PYwPSYJOv+Q<}=|aTh$d0{K$kUO${v7{G|VdK8Bh zhZR`Rn)3EBI=9}M`(+gmnJfJM`uNdP_u8P%O{z4Y^N(SF`el&_xy*&ACj&be44!OW zHRyeGn)rA(hHaj#^F=hkREt^lgY5~3RK7&@izj{ki2R6hoE&o;Ld!;uJD`c9Vr%jK zIcb#;EMhzAzds@Vc9;J$v`>G9j3jG92f~&&u=oHCmPQWxPzvA#m={2p?Q*wo!11;k za%S$1nG{AZS11E2sWk>whqsc5<(`2@3~E3Z%wS}_#=}1h7QoRFPkb$;tNoxwQ)Pu6+JAn=9qcG&H>*2~N&k6vDd3-q{C%VHIF{I#<7FQCKi z%Ke0o;%rhaf&_#&z09|MCQzL*Gh)HLsl}ox(@Ps*QD;k}OooSa^M%cO?Al5F@iuOy zD^5Kn)fE;xXylhclK+Wdsp*uSoOCKAxmH#+OKcpDER?@#o=OkiWFZ10p#-_{>p9OJ zw5S56v`8~fyBfTxl@`Ml)8ALNNS7!@0&Y@M5Qv1o8yY0%&j8?S)vl0+cVZ@cO=qZ# zj7Li!u~=i|T?Uw8-~vS54okS&WbnP9C3&5(ATynSv_3d?V2sq|3aCD`$K)H*KKN4I zE2p|^acE2~@j3C2d2vWJ=gY5y8=!Iogk!+BY120z-7#WMLR*rPzzj(YeCXa0I<}Rb z?e%tnbSxD#N1HHgsAAWYrV3qgAL9g?!y)4v4MoM3-B!ILq`K>t zfIFHSFM>M9pL@}^l}dsP7(QIE*mAj^ug*6G_B;*)`J;Rvb;HmMgREMD2 z$l2*tF+G9dLi6eWQzOSi|AwvDFI*>4Zz~0MkTx4KpE3EXou2#-?y*c_U{^zj3Bh3D zgyqj5%D$fqt6yYJ6d&uG9o;WE@wUQOYo>{V}>mFG=Rw8*(Xv_xdY#V*Im6gn|M9pqvOq zf6`x#08&N(uTuVNqP3JX&?0D~fjiu2m|4ZB=m{v%nUY14*!>>FXH9}Y&zGsnG7Y$C z0Z3|jyx)xG_LFbfJ1KvwC9usc5g20BIoG)VCIJ~s+PjY6VLgr%S}5@#Hj1mP;!7jT zUKuY2vMsz9nY8^8k9 zw;N=ZL3pZFK&&u|_HH4CmJTN|V!ea5EvlcCE#!4un>6mA4S;3efS3ewvvyrSwcg7# zT)^Q`eMhSmL-%e0U-(m^+o47WuAaQKMMw^{A$nBb0<%||sOOBzcdN%NGOGr1EEc^> zuy{Udbg4VI$Eka#z50cSCX?XkLup<21}M=8cgKa`je5sSJ5quuz`5UB&QgTUN$HwL zT{QLpsFkKo`6W15{PpPZXwq ze;^qWZk!rFaR^qq^z(ti3806G3oUYa^(xFTwfYT{p1{CXAWfeMUeH{q*j{K2-%%8N zae3?E3a$@LseJR$(Kbr@6^xLB#M%6JuZeY^8b7Z7(OgTATbyubsU?4QotJKqV3N|y zPi{?-;Q2H%m>3rw9oZFA+K}KiTRU^McG|7FrlEl!g$)N9TUP+&q4};uFAOB3H=ZpJ z|H%6M^~1Ni{r`jK$cptuzn~UBBltP=!lNr{5Yoe((;5jD;MFaT{}dD{K!F87>o2#5 zWtj>ul08oy$Iw>rr3;#?W!($!7?SK;90q-ldQMEM;Dkc+Uc+~=7zO;;xO#kzFl&rx zQ_!8Cif~9ink6jFU^XJWC(*GM(ytc{|!HtUnt#Cep~X0@y}<`6{?5R=sqaxmaRjEFABcN% z%8f^)HCx;&^o=F*{*?s1&j`nF9tshxKE?03jk!{u8@t~mUmHWDah z7oz;6G;hy55Ny#TDa9250L3T6Zj-XLQ(GILjDrRuDjkP9qB`xVP9OSow7_~RUwIfK zh-!w|6kCTcBh&Tv5&6P}^}2^>#isyeB^kM8d3>+Uw6!jA8g|5J6ND+{px!1XZS_(a~5lMnu@A>Bv^%+SCiE^phZaK&|Gq>l{iOg$b`1?ufD zoe0$Ahb57)8CD_X4yv@_6p!N2NHzT%c9qiZ3yLbwZPab}iZ36(gSw01Gb3Ss#|rr) zT?e>s*{7_|y!gT{`<)Ql%IbS7pS~Iih(#rY?Jelrt0?`-s{?Tkh|Mdj(JLSwiM2=X z^Pi(PiF$e&-kF34C$V3fyzn5R@oFGB#m&Nl^XCQS~AvhJSwhmeC4Os zD9Uvg@sp9^yQk~T9hBcY-jV-Lt0l|a&m!2)q{w5fjoF`(JkHqAZ&^h!^mTDBhoy`OhJ(Gt`4tI$OTB@~^!JOF z6YWVzW?Z4^hF)^{C-c6tZ;yNks=lkPL|)z|3RkA3Faegs8-Fg-qX7HoQKLJY;!UC< z3o!)Twa&jPQ6iT^Wyxssi=j_FHf=>sG;V}`e)c5kW*v|);HpKjdW>Rx%s4f<)bQuF z<4n0zC(C$+F2VQC-BtVG={Uq$RT>t#4EJv!HRAXzX5wUUuX%F!$_wYYzM=$LN^Xk< z!t@UoO=v%TrMLE2>C@l^1BL&eE8-bR0)@r$JtbQ?n9< zd!=vqS8_3u8a>ZKU49B9JfLn@w~n{Z_R$$f^ixi?F{X-Yh^0TQz+harRsgbvCbvc~ z4UTN@@Xs=?Iw6PW&+FWR_UFuy$UN2b>S=QGC{j!>Y=bYyY8 zo43HWoksa3Z!kTjW8$Y8+lCj|_67mDL?1>ryyHSGiT-d}a~~D$ROl!=9si272p(|` zRfc|eZgIiMmI(55QFomL5UDOu$5c04+FRpqy?htn!qwWq1_0XY5Btd@@#vF!UYHM9 z90>)ne{nRq3Wr|!k;Y(+4~~aRxNcZu$$WZ;ft#!Qoe@L`i#7og{A8sYKIzAejmy~^ zw)E2F98PJ_sdsJVtR%>8h}X|{9o9|a?}}!p_Yk0)K-BGU<9{R}AUHjA3Nh(8#cusN z2()4)jak(znWGxyui?)`JCBnkQwaGg9dHw?aCdcH)G5K;QaL12c{R4)(Ay+7o=K>E z?fA2lNzu;stFW9cW8zLYpNg`wxyy?;wfFU@yyD_;?WC*VimbEO9vjQ`mGP=WzyZSQ z@U3;d{SO_(<(N&$9^xoBjoz4n0y0mdJbw8#kMp<{@9d%Z>gNlx2y?g=uc8v?*z08{ zG=8{!-rqq!2FgI`0#S%7dkXlb72B4s`9pwBceE>*BQD<(kf~3p7I9zje1wJS?2Z|q z;ZeVd&tG;m%gM*X{n9>SN21O;k>KyRpV72@D~3sj|9Sh7*~rTuZx*GS%0?T~M{FLf zbCK#rB(~3N_xW`Bt_Dp6bIo5%8;kdFVlt{?Db?kI0etgBy#uzM^GmBj50?9TRL3LM zyFTIg6Vd%ZT;?{Mh+p5dq!xU30<%Gh3gRpSC&~#?sPO!kt;;OJgpX*Odhu zf27O!aE4+PwbQPRj>_s|TWf0I<9_^YaZPi)1|46d@?-pB>-Eyoy~4^ts~<9tK~>zB zcj%PySU*gu)>1b#&*eH+`r!YwtE5vW>pM&|GGS;n=5o0eX(b*T<-_trUF*}_kZ=b* zg8M785~)|{Kp17p$=0p1o?- zLZW(u)DYSY?jPT6pd*z3Fq}$XnmQPXwP$HhJbM9NW1iC-#CGA;pz3YI;gz+4^lk6u zw>?z16gdVcWUoPQy>}Jk8GLGgJ}3gQ=c1y2{0IXjk4A}g*2r4UPYg}NO3o+zIc+5} zWl5+L^aH-_{E7AC@!HVWcynk`@H0GQjP6Awj1N!nbEv+fw>x)IwH#yS(pGfVcfs9l zaKaHpQ=!b05Ir(IcgND^fu+aslaBEve`HY&>?OH(E#VkuhZl@vz@rRw?_13T?@^;Y z=|{lytr}-Eu3D*jjFVL*OP)04ck3aYs1e^OPY4}Lj`MPBMo$R%`^qQy`AG2Vf*5HC z)3pwm28D|K&lWJ&qm=<894yx}t^G z0*v|`xNDP3H#>(1g{cq)DKUQtO9{@V`w7Og1Yldh->$!P(p;hRoOtTC zisRH7s{2|8EQmVp9L~g~S)OpS(<@?PocgH~4#c}h4!2RN#lMqGJ4f-afBL4lYUIH# zRt$PmYA#*|9PvlkMM)M$?%Gf_1FqPgd-*LT42l=Dyx=EBY&i3D`_77ultZGeQ&u$% zF-&JSQA6;7(D-92dEPv=_q|Rk7ddeK0cZaPHICvjlbDXCs*;&O7Oc1@&VLIwN^6_k z>=+`0_p8$?g;{>&KfB^J2bd^4|kR51;8Rv z6r^h{CU=O1T`)(kz#RYKWT$!Vcvf9I1-^r1??0SDex@pU*QlnclA0AgFG($nyD_{G z<;YzTX(mP40SsidbaoQH8T-@T?`l-gJO7OEf@pa@on->9KCxOd-1|&Y!b~=c4yoD#|2|!9yejRZ=I@ww6vqFffd53}A(4R{k2yo=gzMxv&meDb zgj`RZc3tLg&&|OfOO3V6D&u=6>ZO{li^(P-<+|{@awjV)W(LWl;zZ3TiJZT~~Y5h@Zl(*}g%%-8~S+ zrPs(5W}fz{=b`q`SC#+U4e`JG=D%HXrfz$8^=k!MJM5_&Eu_3UGHiY*NyIcYQu*pg zoPhyB$H@-nAPo_dVLc&9;$*g)+h5QT_LvW)!?x4x!yll@i zy1>u^>CggPMHUvcpw)Q3TDQ<(!D&gy_i|pvJ;Mc~j$%6^DgfQUwz2u*DEUH3sQvG1 zo!K|Y*#9&wzJB@p+F~5|GBEL3&=o~s&&=7byq)FL`w(R3it{Iu=fJ0Q5oE0;Dml05 z2af45(EdtSl)mbI*^xTg0~;0hZ48zgnVW~vh0~V`PF~xqzcDV8sB=v52}E?nu>-ET zr6V>jmG?uB)C(Zt>Cx4_&lR*QxBU3{=*s`G!+&{a={9o$=Qy_KABLybOVdtN{SyXq z?TO6}%clU$qm&l-P2|(35l7S%o?^Ne&_nY0_LUb567MFTJ^e$vYr~mHNHks&kuZk` zJSCoN4ON;)d)6`rjjURHNFCy?MwhKeJ)is)?t1s9G7>KO2Vz;}|2`gdy%-Y7#!gzL z{H@$rcB}neYT(MBfTVjN{Hukb87p~+e3yhP1+Dxshb=Z0xTsNAdG4!;afu#zNWn^p zJ+mIIikN>hx1e_3uDNA>3PKJH0wDih04mmG({|7C55m_G@9+$>5v#KHZ;WTA`E$W| zrDA5hE?iP##irJd?06qj5Pt;1X;K$ep`v6bPIg-RZ9=lqxv>qL5fEJljG}Wa&?+aU zi|>-yMraADqs10W8~ggP5}G@XbIMi5varwf^J z-eMI%UC?|0{lYuQwD>81XyKLLYO<(Mex#n*&wPh! zLo^(!RJDED1cO5}g@~?>VnbRMeK^sJUw^#v=8Fr?2E}3A=-nsNpnn+HZRRx%d6sd| z>r0^jz}3P{;1jmAInGfs(uCd)J1q)N%^w`2Axl#L0tX7vK(8`Z#!XPfk>9JA033_h zIc2@@qTYOSAjpP#s0D>^UyqOT-ii}n>+*f<^7t{aRZ1@($r;%QOIH3n3%(zA|0@F+ znnd`iodPQ5eqKOjpL*n=+HVO1eEls5c?vS~k6mCceR6-ECrw3OL%hUAD? zSLqiAO}oClI}333!mj^%s%tZ{JW?UfRNoZ-yk7LN2P-stDc7$ zo4;0n1>75dtil*^kKYtce6uNTS!Gmve>V9g&i5M?jmV&^LiO5w_!nJDHPU;83_IP) zngrykUL9gQJQ~I)W)XskAsOFB zB%vx`_cJi*7ns<6&QdJK=fJ$)2zEAi=B=!-Wmm@dSU)aJX*Rifa_5l(OrPWnm{E8S zZtPXFh#TBm)_-7mz65G;X3k_(aqveb(~rsQz11@K9Y;@)TDLF~oR?=_dXmnwfV2_L zp{3LU#Hp1Ozv6+DFDn)Fm`nSlr{^#*2%%wzwi-ag`ke8f0zNO{-S79DnZC!jhj|AJ z=B$6hY^^BjgIJ|q$x*pU<=b4Htgp;H3E%FuJa0-Hc44_x_Z>(iAyQ{00f++RB)*eK z>{V39Q|_>-iKzLmRCW8tD!1FRgvFm|va)pWxtWP(A|Xr#&*Hl1`FtL_=PT|r7wp#Z zHOtU15JMMqn4wSGR(YMwZ6*(LnJ7Iz{lQ9*3A7ey8k^k6 zKXAmqqSjGg;qNK6SJacpJIcUd^%OFzA|w3Qh&9pXsh#EDisd3brwiXlnzs?=Ustaq z>+aM(D&Dg1_>a&{+jRciIqf&)dia{EZgZ*`pfs0K{i%{1yN)gpEyK z_DkSKpDjIEqeEJGStc?NBUm z#_Y4QoLFcfY||%x-Ee;WLDz=>Vf2z;c7T%-k%k7_WEJo7H`3S=X*rf?F3eFdIA1`Y z$V#^SoMdPZ++ZtH2#;jf=2UQ=-BQrHIF{mMoWf3GKhnNu*!tL*73rb>$|z9wj80syDVa-{|CL2l7=sc@F~^%-#m{fu73T|wi`<4Qq@l03{;tMdlg3Q z3E$UhEljE_SP%@B9{F&*jOuq;TyR47-b4(H#FEoT52|sKiUavwK?0c^%+z`-n0@0^TKav9F!Dlf87$t8+=o!kr>hT z5_8Fqx8@3jxH|riO#}wO&$hkUFx2cl#)p#9M7${cBK@>sz zAbUa>j&kIsa^hEoIyw@u*bqH?$ni>B(z&SwXJV~^T4@yb5~P!-Iw=0Cy|6wuj;5q2 zZ@%ILCqg?cxM&yW%b}n3w%E9I^@~%K2o&&A=g&#Xwp%P^2}i21o)gzpRh>e^H__-I zS7eo-(UA1uNiHVM$@lo!RroWfEw(>I0lM{Xn3GzW-qE0sE^^sH7ys}sa#xYt@Ci5_ zgi9d);mm2j;5*H3OWJ%(3d+Hn-)Zdj_3rYYU5rG#>=JStGk)JZSU0vO@%$?nJfn(^ zWP*)^KQuSz%xVmqcGrKp=g;3+)&Djop?H7k@)9rTv9gMirYVMdTT_a;S@a9sOLfZT zMn(HnIlv%IjaB1nlGQU9Cau5>0MvWVsUNZ*Jh^(s>;`94kFGaa?SP}?T+JpKjveNx zVm1#?u<8Q8@cn6Hy4{# zl@74Nq70)bu;vXbt#g{NQrw=9+=m+eHez(&fUDJi_X49C8v<6NRqEPz`E{YMvQ{jh z>fLiwa-*Aiym2<_T8FkgQ)g>~%QrXm@UwI~=-N=*juH*nZon?ip}R>r_$Z5|1uw-j z1fuVjOxjqQ&S7(c5=n%*XtbTTZjBy4OqgEDQO1{wi4m2WxnwFwz{0PKK%gh|mvr1@ zd^pd(4MaXUd-z$GnH0y-cc{KXihVgTZge6wB^_+|MQfcL8*{}9*4wflmRoGvA(5D! zyap8*++Rj{=(C(;M61Y#4a<>o z-mBKPJ2F2B*)II+6-*d}Tt;H4_}GP&uJf?c9y zWV*ddCD6`z?`?0>z&CZi3wpb}q~`u3pewLjG*|UXDQNhsqP5M8QoU>0a2L$R77*^i|m=AA`vIOE(X$K~!zDKjZ}qkh{5q z6Q5!BJ#n5j7p(=0Dq`Vu{+#fflzS5>I`|J`R9CFmn2pCi>{*gxBY)+4zE7d=>fp0< zKNSz>C5v`Hcs!h$_UKA{Hl5gUU)tUD`|8`z!T)X|+QgB_fsFUy!*JNvyNvEo_Dc+f z_nG7bzid5m1iprz*q(WRtZuo^wzj<(8PWsR%d;$>u#xmU1Ro~b|6OYZDG4*-_YPXL zgEX42MUM&pvY^g5hB@XsRe*Osj#2`iQM1ev1@rVgDUnDhMNuSo{$iIz;CVRb7>XQF zUva{b?w4aYv||){m@sBbg)bmHT?AoPYR)q(k*m%BW-bENnX&sD@V&(|$DiNJ7g5)i zRpg`|EEwKC;3w1Gj46X9#zgNuV#deH?Kk}DtncEe$v6#<(gfL(YeC>_JzMDmzlf9u;aszUDs~4iLR6cqzuD|<8qX}8L4sYRqwp| zV7bdqcC)UlD;BuVyg+CF7<-$*p<`RQD+zmCY_@|}+i4au5csju=~CfIQap@rD1>!W z@N{;U!K(Yy){x^ZCB2kL?5J(o%wRz^d(96h#nc<~WyW_wJfkvGV*RJ_UT`t>p5Uau z)5o>rrnX8OkYF^hNuie$t#AEas`b;|SGHbh`2;sK%lIYMhqlCo%Wr;Z$1yE&4mP|(u1&5U33CPK(CPvw ztrt!Cpv3gV`W34Z+q~w!TW7d;gAE+N*A{eJ-TFR<;vtJ2nmX`n?gW&5k0a%s&jBh?>JR-HMxfw-@~yBg4a3@K_0H z|335}{MF0Zz(1Y!3H?6gpO%LlHYR9(hN*2EaNK*Iiecza^>J??dxMnXz#+Cnuu z$m}C5fzhCf;wvzzgV27B=S+2N#KN(Gv>7tUcbRlYxO-HP6&5`3m9yq;$^^at*5Zw& zCXx8S*NUDY@5Y<2=8QI*d_XnIH7e3EpkKBTr*FxzkzIAbsC{(c1n|y&7e{*znQ|U5 zA(&fzv8QXry?JGEq?~;?cYe^8U_*pfa21g#6#T@j%S(&Ih84dgu3jM<^mvk_K_lV? z`tC(@yqq})JMI?B?%5bqsy6b`OkyZvBP&-V!y+i8AqeFAt2UP$X@P7>1bf!Kt7i3b zlwU`6GeGK0M{6F10|%ZhR!pS~HTo-Bl2!aRZN^K6yx^a!ZGIR2=+Sk%ot5@emjGZh z^SAOvh zy&%IJSXb4Q)|+NEe&tZ1U~k*UiT7cs{M*H_$UDNAf~&`e`De~$`(r1wJr+-?p|As-byddF+{5ZJ4CzfEM$4 z^94=$uD%<|a1ii~*4Zsj@&)_SpD7=%u>NALRTj(me2ppv@pbHx5tEpZrzdHPX%DcT zx@ppOKaCABxX!2Tb4Ind71IaG+(MjAH4b12S^jdjKs@-M+Ux=@Ubx3E>Mdqbq}|r5=k6agDjO9ZaQqn^dDdrJ;di!}ZU}))@Oo z`)W&vbXUfGyhKK_=sfEvgWx$1I_99q2K#}+Lsti|1p+wh4 z7JOXBlf=!i3uLcs*SGPhk(&mPTey(-J*A4J%|{-_S<^XyNn-^I16{HhiG%~;=wuw3 zU(cB1gMe6*qxUu2i};^|?5%?Z{X{!cR#dvoO)@xbnB;Tmrz-EZiG76k%}bn+uP%x&>{I!;WMR&q{n+@0C7^Fb6k( zm0>@y`@}(^*m10%OokXYvvqc}c8E+AO+I{=cP&7P}?q_ zn)IX8RG$uN*uf*=Ny9T@bGG1;~e z*S>m*A@yemIoT+^>$>z%np{@PoiuuaA2Wog>Gv#}qb)w>q_n`lE$R;6-@@I!%(^P`31$;rTTbcQT}~%ADS0WTebZ z5Khd;9vU0(XyxUAka}Lh2HfPlf|03T+f0n?aK-7|d>UA{#EIN0sjR4OW|1Z*&FHs- zftV4vFu7{c2!!8YVSVS(Ti)VE(G=Hq+XI}`7#1pFpBAqM-MS&(mH# zz`#$sPog;m{mo)TY>{6Xdi$W4?}c3uepB>C7^H+VAdb z(V*t&C?s)qoaI%?Y!rX5Ds{Bgg4TU_-xG%H-R^CDylJs>?7D8_)Ai!<_i|mN@^5w` z@M(@sJUPr>+)5AQ#j@ACe~nc`EEXPc0zFzb`Uc)MNpEY&to6~XNi)k2X>s&!T8mb# zP)QqiEuZrkZSo@QFI*=~h}3K!QLaHP>e?Bt7@@-lS!>*g#qmXHt=gQWU#swBQh8~Oxwp%M$ke;h1tTr&& z2`}w>&H$NNF35C#Dyw}w;xk*;XP&pHqKHThdh)}hsH%OlNw@l-rq~l+ zrB?^nN}3A6!IZ;d0-u3EU=oruPzALTNmIsZL+-G`3%-bDS;blJy9&$U#Jb6AySt&* z!o)|JT-5PpXd2jQ`}z~XH8yT>Alnr-*@#T$)+58{w&hH1+)R#q9Ii}GYdF*Con7sB zRac6gQ$;f&?(eH}8nh${S1%O`!L*<6qx3L9lZW^OmBNzbRD17mZk}e@&wWJ=4l=RaI zxw^E1hjY96L<0W=MpS&K=VjiPVf46@e^-k?V*LA(RYNP)9%m8YGhJNfpk{>;!d zy|j_qFK>K$K6)IHxc6%~8ifV^(N)D4r>d=x6d4_`JSqEy#@W%Vs7p;5f>(t1>T_+p%=Gg0|DvXq7K}coI3kZCd&N2)M_^`kwKyeLw?C|}E z(L&$Spmw!gcf~9{LxI<%f6H+t7!i@vdj-UefTo<`Zt(M$9d-NG&?Oq$qdGj-KUOMc zFxP$_0)P>I81IP)o02$zyeF2+{127&j!v}4;?hxRiJ}N|Es!M@n0C~Wg-x{={ZQtj z&PgK`Hd1B8-;O2$wt3Mk3BpKCxtdI8i5;pxMJJl>My%3XT`fxQ;`5nq%3{f z^T!;W!e-sx{)Y5jRtl>&MjtYEn^px;xeU4MtIy*L|h9u`>}8=**g4*f(=ety|+OkIvzj3EYpAJk}R8_|Is zwCwi36UwhL5c_(5yo+()`M-U0SpptY$sLmbP`MY!$cG{Efd^ij=`I1L)68p@wawP| zv13$k<_Ycs5UCLe$%l}~S`nw3UwtWguHI=5+QmrT)@!A zV!{i{>8WjIU=dE%4@(IJH!5$s3O>+?>35oZQTcoYi{#@&Cu6|i|B1;k{1=naX-*9A z%3U#<3Fv9CJm;urT&JcPZ9=?LKLlWP43_=%?f)^hb2U>XJ{`2s9X-b} z?U>f^+M!&4P)37QG=Z4}lX{bT%rZj3Zd`ZHelFQFHB7(O0y4)hheP-zPCB%3^S`E{ z<@EwfMUJu`*uKH}EAc8~3W0le!Qr6xLw@pzi9c+Y&x|^lF*rRahuikA%sD6M?HBH4 zo?1&ri#_GzUIJ3-a25kT(Z?g&i2Zx4jK^$fAUtgAdA?9Jau-L&BdRl*e%|g;=|msT zpzCpalfL3EMSe_rsG~!Yy!Lo$%f?h_-!{OBwWyn-hP|>Ct)xC_-|XEL7s14nJ0&4O z9G-|mo1(m1Odl`5M0HEC+wHjj!{8Zl$FoK}3^9r-OAjHX56kPD=hrG*!O(9{gN7_C zzZuJXDXwUOif1jI+M)oAV^KPcpo>2R#wkQ+o^t`{Db}tt{j*zL0O6Rp+(ytiNv*MM z?k@3@4lv*XD{mLVLU;Vy{(ehw-OOF2Gs-)9UV^Qr_2%a*!<`YTFGHEn>~~opdiyuT z$FI9SRh>>Oy(w8D=nrZ%${wE2;{*2)BZ^OP{2qexUlV~h4wO$|XVI`+bYR(c)xb7HT5 zcsQh@=@YMbUP$hTDt|tC&n=jo+Sh6ncOTJjarIY7KjsBTjzE-%Z^f)+G3Sw{%nuwo z%cS)5O>s2eFZ*_#&^>yBM!VJt?_Z64P}ku!Xib{% z+;Jfzf7}3)PEIqA9_O>(BYr2L7hRlf3NoeV41X)H?1*O#>c=+MX1Z$dNGh(F5%mfiBTTHGDssTn)M#xXW!i7$gWIDn}PK!g+cM24& zKk-{XP&0x+?7QZ~T0>$sOt^Wrf3{S~i_(D^fj8khXA@~fDb zb17s@%)`*@BS$WrAE=HdgV?DKAuh2&d>)no820>0&(9&y!XoVUIz&+#5gBu$6!FIR z|EEK;z>^WO=1nQ|0IZ}K;N(^b@gmzrM(`~E{XiJbly7_9>~SBdY>s$bKHO;FZ^2=x zffOv~!MhRPqzTlAZ{9XSY%4MH0*7+Ya~=VfCXf6rf2rQE?1gwb^5gaX1QoVaDM-8M zx+1i5-v6~{nHR##VUd-!!SSJ(`TTzXVO_`({dU84R&rD)6iWMaGrij_hMg&@e8`qz1WL8T9Ju=r9TSc9uJLuES*p#w^^Q75x)F( zP}kT~qBR%DNF9Z{$i(2G%(8_N+5KY!Zs8L`yItVPmj{FV=;G$a<5*b5dpn@IudKAs z&flJNzNF^Tk(*z+qt(sT#;xcuX0sL2+NMI{=SCKFsO_z&X=4ifP%o(HCZ&Yl#% zsidFL7y(F+F}43Nk}){V>x0yoyWKJo&cdp+tF^?HUr!4jf@o^nu?Wh2k+zZS!QBwA z?td7|*Utz(E+kb)TXI>xVT#I8*Ii5MV`X8Ys&|0CX350b#f82y>G^6}yZhjkT=&Nl z2a;}4QtYmF|XL_}0px9=NhU5&z5nzgux92ZTTFV@2;Q~UGU8ru-Mod~_q z7$FwdWla2+N=a&@buy5qFSb6u0%FHx zoH+G9oI;tH?pJ+!y~W}hq{6Y5#0t@t=uzQqTw+NEE0 zCfcP~6rURtGOF}-_!4rp7|UX)WNYPoonszXa3_=YWvFa;Ty+AH0fHxFS0R{=ug8__ zd;9GAirp|Ei8SK3*X}FlGVKPPE}PA!Pe~0+=giOMKCT@x40f`N1$Q!A-H?@A;u~Wo zzCS}PVu`UjDtEin912!1HF*{*>K*ES+zi>T$y;0`6FtCA#$V->Ny~h>03p{I17Y`0 zG#*c!vhLI^R@c`XHCNAecvdT`^r7ZKDPhBZrwS`%J|#`7GjQR3P;4M800@xdiLkIj zHa$&Qa-NOB?4i-*Q8n$K;mvnzh=TTTY^&vh`q$wMTzpXNVf|N;Mm)ZU1n)|_m^#-U44`R#uqxyMaC{netwAabWNssa3u6E0bMbJpWCM- z%8{A!y?-`CTxRW^gmH<<(rPvd}6rt zV0QedgGp1%I~?#AjTNXTX{$8=asn#(VS*ot;b18LTK}qwdFLMn?aD9=GSyzl(`i4Vi9eb9VC2-{w-1H}t+AvN`VHM^IYr z&r7m(r);G{ja2o`dp2aPHJfH+lgK z9Q$mLfx1Q3XN^bX7PC}G2F165o-i(?t9`2@>klkbvARIswWQrjV0cF zCdwAE`7C(TJN-5Sn8PBMzWCtZ;Wl?zDy*y8{~k9#r!a};lNHF3n3P25n97~WYCj2$ zFJ@u^;B(jZk!80vul+i!LUn0@8_pftqQ+3#@Ks0~w;R<=QoKhH*t?|`@8hc&C9=Mx zgrSP=(=+tlP

    0)_q9hTYq=xilOCsp^}VFcYYo7pHlT?g1Vo8v^gWB0X~fVIO@+| z2G3QKxvXb;L!3mU92vwPQ+M_2IrZ%B%?t3`dN?|UPH<#ew+p08q(s^-$R8{{$S7|; zHyu-sp+{xX<@o^vVLviCB6F>F{Hv)e-aS5yh;REnmV?Jg$ z@Dyh3GUa^OZ zsCaG30T-9|pyyuK8V7^_$1_0Zbhqoh(*MQTTL!fi_Fca~fnvqAc<`WsLXqO`P~0Je zP`p414#gAPA!za9?q1w0xRj!8fzaYk-`vmpoH=top8J~2{+7vP&(7Xg{%ft@dYNwK z0OVrN%@j19ahviHG_e3yGHZ*eJC(lutTCJgVqms0=`BvpQ<$t@DvyCI4m6Dj1C*T$ zoj1Niv5N@;)u$s*hU15x!jm1JD;pcG(=!8W%Hn8FU4^hX+(c*V*KmWJ*GhISN4%RASp{pmyoNZu0To@QQF;x74-}kf zs$FnMFLYkjmqOp2L1ts{#{bUZ?T^MQSmw_P`Gv||U~Pue?pLCkrn+YM>!GhLrTYNg z74QdDQqSi}p>ge`f3!EVP8JXNd?w9AzXiTqwB-^aoQbgoD5UtXjJ{8Ht`fQJFU0S!> zYZ8Dv-wXkaA=XAe@<6nSgfje)Pn+R;^e4TBT^trYcz8rA8_YB3bY;I|=qT3|)d-(x z!>ciEWlQh0Emlr+F`lIi?xOK+kQ$e#XUC7AShKgc=idcYZg%gy1K01SI#tGvqFj@0 zMEO{5i;|PRzJHi)+8Sr>Qm}8(Kv`(tx$xU%^q95qqoj-b9UL6Lw0T|D?S7);V5fE( z>-olyPp2<|D@|@S9h_0@IIY~)*vH=Eci(n8zW1x(<>_i0Y~x-AQ2DF{W-7p2X$CHoXV*>(7W8Y_u>({kw@!7q&ZH-j0!~7+mq$=XZQ3tJWWKfk zZcP+3qTP19Qz&YUgBQsEBKeA#MmG>+FB;}twt+TAQ~Oe}IadtmP6iZt_TKm2Tq4*={R)QD;3 zusMd;dG+{L;>K>IY%O78v#=;vq+UCQsF#8>zNL8>1&0`w5Yz75o2}rjA0Mon3V{aw z{V$E#_;m?88qM4y5<1h`RX--QJ}Bz(M&6b#yjiiLDFZi)P8k#Wl5uv9UE7eZay*#~IQ~P3if*LkJjM=81mp~_5Zp|%0@;PlUwO%h>rII(o(#fC|p&hUq^orX^if0y0D zqiQje##fv$6*$#F&OK;+~q+48Lq))q>iuCg#?JT7@bsM*x@5sR!}{My)W*O~z`%kOP9XXUm{(GE+A`jkQ2cRaRlSc@`FJm?P%mJS5a!OQ~@9j#~2#Jv77tXemT=n^NU?_en8V0;(GT z5g|8fD;;spo7OR^rX~!xPjrs)C_EHeRMl;P$QK6}Gn!h0flbB0+mV`>hJnfF?g&JT zCLnMs5HG8_;GvkXz&_vUQEG!^oi+_^%-ICNFBZGJv1AR#l@f|*;Ri%_ed6#4+(>mf zST3~a3SIVwYS6Nbqvkh9Q8_JWwa%sNpj#QR!D;|gFJ3y(k>aYT;?$Pl@s-i|@!A(^ z&qb_bkoc*Pj`WTQ%Vrmp?*-KFc;L4X=u<@F;6_{DdArvS+jeF1`BQ$xt*VKgcHo9; z>LCt8We+|>Ii!OmMeH3Us$1W`XMKl*^3B5knAUajm~|ffjz(!H4%J{xN85f!03oRD z(;>v#Gv3MdK;))T7Sq=<{v+T!fQo7r%`1EceA=0CTDvPqa2&VZ=x)kAea@>7O2kh^ z?C_mU?hM8yzLNf8J|GdR(Rh+r1Bb-lSq>D;b3DwF1$Xdw>z>to3b;EcI>ao)A!C6h zI-V;85)CU+;02QMC*zFCNI|vN)Mq?Ys=0jl=&794Fu#s=ab>eBMUpj%(_V?B?h~8f zQ>Av+V@P#|K3i=w$we`9P%ThU595Y>75NA=7P4VPQjAZ_Cx(?*DehWYyWGhP z=$<%)-vuxKB>JrMxZd@1G6tQ?=Ho~T6KB;QZN7J(U%#G?3XbdW<{Q)_h+LN@;?E9} z3@>wWruRh9c-4d7Lom581`1t}xGo*GmwklpfpHY7B`BZUTy49)nZ%y+%idHiM^m1# zV}nH*HaI*%<9Aia<&-_FPL;8fCZ#5?bb{0K^A^3t?5DOz|VkY_KPt&QHd z%Ib*+rHnCZbnk;ZDOJ}YVr9G}-!WYK{NMoA?FBF475;Cxfv@Mjd`|k~RrgUDg?P-s zzNWZy?2)luxX(xT!suk$k6!;NyRB`L)y}lx5aa7j%x(OK;nMUi)ozSIj$wlQI`8AS`R( zg^c6ktc>5jWB4`%3bjWMF=v|R6sydJS|GyAQ|Du#BTaxmxj5pQHai@3%E92d*5d7S z&--WJRS;0(u^Vfm>ZQY_WIUyV#8<@DWD@H{Rmp2W3KC z=|rR59q~G{PY`7h!%OG-V>RbAkpnEN?k(|DQE3pR<^z$r9jz1jd>cBUo|2C@Qha#;oBON z4r?v=LV2$`@@8dUS{{9V8Is1KZE)B~tbRhV5NnHwME3;A6M3<7Fbpcqy!77XUHk3@ zbLIDYXiVagh=*vXOg%z198nhJQCerR(gLB8j(>JX?S-YrRb~RyR6X)ej!n}|$DdxX z3lm5K3*pfx?4InJ7sLD&d5gZq=9(*{3a#%@gTBWjE z>aD|!e|)Q3REK+rLv|ZvWJc-fFXpe23P;lJSW%0_+x8Tj{lltc)Fj(hL;o-W`6vEi zOwn#W)a%m^`Mc-2f1TNNI^rKxzVKYMtk!lHAH)UnM3auBBEzx~*(7h~~{cJ30wmiJ% zyF&oA@t51CFe9(bryw#y-ei3WAt6O}X@uoXoOEV?{#4te`s0%7lM@EKdv7ez^j{Fg z33LC1)|rTiOy2#A8!IuGziVDm*LQpJK^BCW20IgVk5Qo;&(5xt)J=Pnh- zHk+y(W-Tb*&ZmuhbQDZOAkg^qf276-E^DX3eDt}EE;rl0Pn513vwou_C$<1hWw0Ao zUDh%izgJxY{grJ|bAC$rZ0hHf$PUM>#zyh$CjO7Se1U`B!^*iL4EXPx{GuqkScc2A zF~b(doY92W(@!RIcIJ>6_ym8+mr5R5foRz+0X)b1a&!h%sTgXbZ)P%KY0WRhm?KUp!SSE&c!5~NG6obJ5NH89fwj#gYl%C z3MfwVpI?1za^2^Zq8yC+EaFI11lC}EH!15$vD*s{4j>IEcI?WeU#z<7K{i!d_~7i# zaX_2##nKSv_i4ZeM+8lREu`EZ0gpHo0a$u3`u%E#dDLW$GCLTLd@NbwpMj{Zm!MSu z1>lf;5gABG_##D%^dV(%#sG^+WzgNS{Cj=Mno0V={c*4H*I=>+7}I7Ij@0TYt%YPq zxqQD^q^y=hkQrByj>yr*ng>tR;a}rk8xsw*qV6{rAQkXhmg1;^=gtucKX@zB(Nib* zQrS#PK%@579d+1f^l5>af=yZt3id-6!E;?95?q+0?h&|Ler_sem_#z$Qj|_}q$7r% zR$}Tsp&J-SU=qyT1Or&EFi=^9-%Vi zRElQA$(l{54Xfd(aZ@mflI)T^hitZ=2FBsUj-!Ct0kHa5K1k{(+*%^!1uJ-<s{V zVA)b|H!9TCH@v$?z?H$u&|SJFXBmwFA3Aw&XZLQ|GOCmx!p4}ZpQ)57|BLlar)zkD z*_)G4^pG^ab>-)*34Ug`#75r~lE%tfl3!AzhJpT>A|#)BfeS?Rv?z>EqM^^eeRge) zUU7^yYtU_x*ykp&`&DDdmlssKxkuVcE9bN?%JuPO3%;I+UPYu@n9#L0cQ=o%IM1$; zXx|$(h(#ZZ~-cXaWp1aiLg>%8#iEhD`1=Y_KxkubK3AqsfzZ$>TY%UTIx$H;mi45 zGRGA-0y#Gp*QnJvA-#q)A~4m+hXc@71-G@%d&bbWThJUaqob7_;p;oT>0P4?rQPl? zz}e`<`u``O#WEw9{{PXjVHHVah79SYlPEyrV>_Q??RFhQ{)Udd|X`TF_Ec!$h1=1Yp| zN=K&A52#G1kmtQ@-92F`D`MLb)cbk^*?UpSPqD<@&0mK!%_FmLJq}W{_=uk6fzsnv zv|FtoHnMi&nReG{^BR|WrFyDJ6c`@KKVdT7Llw3;(@5BV@;n|V^JL$dfG;M!s%gcD0%tF5u12)s%kI)|Pu2&0+b2ID_rdl^5D zLUgKrHTXQRzDw+O{qSWY#f_IkL;tC$%fu@?Z!VY8Nmv~leqRt`m(QO6h5il9&IeT8 zuwD37gw`r7r@xBAJ613(4%-9I&>zsL2qWiesvsyU!b7{R!v)~Nr8bAXFNF4} z@vcq?WwUUShG&QBS`7PDNa&8z*32GGt*ozky;+Fs$cZs-EfZ!p68};+tkpU2D@to5 zLsB;dBN{&V;P=PbWHS)rX_9;Y7R(9Qef{j&$WZ7LpNywUdo_&qb=G$_#B75u!d+AqY%4cNq%WEyk4L3K)7t%N)_st+qY?n7$u6;6_RIgOKeTg?` z;zBu|HJG{D0l- zaP0MID@BKxHKc9_6$UeF5Gj-IQ?a#UW2NMLm{(@!WMt$WE&G?pUssoeCt4F6T!WwW(OFvXDhaRB>4)U1M2jHFBcsLH zbpnLh5a9?9iP;|~Z3Z4MncJ@fwitX4XmQ8aI$YxIIryvae%l(B`-D4<;mDvLXpE7? zR{542H900HzQSx5bXe3+4mXt2EzPho0~N!VN(m7>@3Amb@pq*pZ(5Gs^KUx%bpQq8 zhbteEw-e*S*=tp4AXdHGnGarzg!7rQtf>s}vIYQpNz1~oX4 zno{skO^UowQQO@=jCbUauMvQ3y1X5apG~HdM|7)0F-q~BSLvUy z1jdA|Uy0S7w_Yx`-A06Tr(#YHn&AMe>u9mY(yd$|#hq!STcog}m+rDt-OO)ouc9xe zP!wa)PClr8N@~Npe;CTpGS{fC?SAw4q6bU8CA~ zy{7J5*f96QHwzyLx5rwJ64l##S`_f>+j?NG{d!5%dPj`Ac4OO_U5Lf|deT@nQBHlG zN!KPCE1;8hhn=ZyF_le<8aaE=RTqpiIPl3eERnoY)=fn_vySm2eW9?~bo* zYqS2fVMZiP$xr1aL9MJofD?}w0L?RM^-ey-(wnPbg%mbSvv5goK60!r^M6BpBKtnK zx^X~I+np}np3H2N5s^p4UD(HKzAqUs_e>2Cp7@QH_{;30W-^ebF{A1HR6|$UwEmg7 z1;=HB$?(Lx%ohRJNy5qu!;ed-UX4sa&kCM))VG)wa=FG9a)oXd4q@yDQVz?j62nwXjrbq)ScI$c=IR ziR<=tGcY)t-M$tK+-jy1osXyooBW|l9_wo$`Dh!Q97+a28+Rmjbu)$OBSyc=nd$d} zFZJp;_jN$E&Bn^KT?-SbK1!*4{(P|jlKGDS9$_*}H^DbdJ0mJ9wJ{aZ2J%sE#@;Zt z-v-vCcN)Axm4ZEKza8B_DW3b-W&&D;P?VSMXH!)17Z)MEwt8Bvg%ehxd+&?yCS~<_ z5T7Lwj)c6L82DS>N4vFB^bR+I&vOJPcR_0!b?=gI(CFp!3mYPgsO>dp-2=}fwyU?A zx_WMDDR!;ly>7YQbUkA5{%eonZt@8JfnbA$PS-$G^4VZ-bK>#NT`UCcFlRRqK`-^? z!V&Q~Ms!cZ`icEYejct^NIgYB-s05a^J<)``<~B(9{P#pESsuqpO@L^3w5RXO|D~B zkny@nu**Om4WL@MLUzeYN)(~dal0pcjIu}P6RUe=?X|>LiIQ=L zrYRqv+S!gSzDv#*!zZ1%%7y^39k*#XrehyBmIBAx-TJ~pebang?V+;SMh=IH?4jcy zObsYrje!`3$40y9W#T^0&l-$=wz@s9?~1y&m%Q~7H7)DFz<3;KRQLNJQ4rk%XV$++ z<-E5mG&TseYvf3Fn4)zh2G{qVS|3t9RxsjwOa1klpv`DgQ;oxKc%`bIU~|bN$eg@< zv`iQ9IJhQ8h^u*|Fks|QQM_rZ_4aqIDC3dka2#REFU5HmYpMF~x8Fmg+Y4*9i);Hc z$G`Qm2vze1uPRK~=wLwQ@m#_&xDIR}+mayfT0)n7&oz$jZcJq3`9-6@#FXJKexi?S z8h!}~lj2CE$3(A{D3Fu7=-{=2R+;-oe&^v&m`#THKa39>{zSRJ-Kv$)7r=#Pr6Rw@ z)}T4HM(eJ@ykzZazBeDsinC{h)rjg8F;$;Zm`JssnVI`Jtlt@!Q5$#`m*8BIVfQl~ zh3Wy4UemgS9Y^5JEXSHA3?*!=IX*eBA2$u*l}r=^W)gm)6#|Hw8X@lr{dT z-6O>ZF;V!c#=we=53n4Vq8)tTWGM66v>`A|aEdm3^3LNz+*jp$QPT7A()l6@-j_{N z_2h4L4pUxlk#hkpCq#b|CTFKv%HxgN-&b~?(rLO^db?9Q4FDY^HJHnr!G2VOpv9$) zMpjnNFxzpp;OVWmqCJ=Tv^BMH-C@Y!<}NtanmmEtyazv0P~RlXjtsNKcK1i08h#H9 znKSa!t2;QOJkvSv+i-7mUO91BT{XP`iUX21*VPk}mr}+qI!l6}3lo)f7`pL#&?+bK z{`35W!Li+rAhe_+-<&$dL+0A4U8a-u=epg?(Kh{qQjpXATKP3Cu4_{IhowQdR*Ncr4Iy*?Fv+F@YM-7w7M}*0SVv~s9fM} zsV6z3?jrTBsR7nZNOTA~!heXfqkB&>6#7eJG3>uVHssX$KN+LvoixQ;qd&u{DSzb( z+>SOK0g+gqJ~J>@7-0w+v*j)*RTLT2LNoR2uYa|I)D3>{hfB=@N z3soc+09+-+Z(6*qQWrUFGU%HC*D{!k`18#8=gTVH$5(E;6_X3-p8$ z<?2G7>w0N%^wLLFo zTX_APH$G9%WEGFm)%*+YZ82oa$}}i2^Yd1fPFd{mcEdZW*iZIA``>KsRjr1x=?v-V z7npGPJ{0Pg^d0K6wq(GYIb!?kC2#J;{Mc7j8@F5?DsJ>g9XX&eTGLA2vOUAjxjX!W zo$e^$nxeB?Tg~MeU6j;KS-$duf@ZCgeG7Rut0$%?kC_$?|@`$vDzu z+pO?m=~kwYQucvo`C3tq4$*OSR&`ZX)zLDnN*+(=Y^?6`Z&|d}KWQQV|%@*MfqJb27&u=~9uRM_Bb5i}m zmQ8g58LxnjG*%Jl0^+x>EnGNf!rd4mSZr)#A(z^{&6jQ8V*X(e|8V-^)rE zN5mcM!2Uq;;ZCF0ylG~!r+wE6BSZ+B)>EuS+9 zCZmfFM{SKBwXZdCXU2S;nOAYRhR1u7YZaN` zzaUZy<~cG#!Nka}q{VNyveO~8vYH21fe$H%7bkNeo9)&z{tq2X0#YQo>p`GU{g}}? z*;U%QEK~glOn%ExV}&Qe5(QRA9VeeaR zO|9F1vOf4QPCf#!BCJ1%Fq`jMa<#b7YO@)(Rs3ZFc$>W>F*;{s z-$X<@`gT$&pr-sw4f?_|@DBWAvB=eZuvrb3AH-^<_4 zW}5{qBCRLC@PDO(m@BdvrWF&^vGM+52+4B^Ibw}}ZH>0`yto=Gc**3{7E;aJmXod4 zjC`=ODOJEO4%PNBLdy^&L{aE?@AO7<|HTlR1o*kr=KkTC=D`yV=Dgz?D5Z=+?2cdn z*REzZ_>eC;gfLT)9*5x^STe1YOsToOk@KAlr}4n3Rqkia{*k0iG$$9jom2~5I0g1& zibGQ1zoi`?+4S(+asT1YEA$VeavDmpwv;-N+&a0>?)Vh|sJf555LA2W2miAg;-j~w z0iWa1FQs6lSql4uO2bc9HM zqtkjtN_l*=%&MDFOQRQ4rhIKR_pX+P3?7t|lT(J1%W~BvdT-M2z+)W3UtVio%_V&d z!J2POR2#4Oq4K|3k)H{Z@ofjEYda1L%6tNQBae`th0R6n_W6vWIR)$=%h+wNF?l#J z751tx@s*msB>a6`Js{rD3fXCv;B=;JTgmT)JPof$$qyipFmQvCTr%>Hl_hFVbmK$Vo9C9N) zoIDX1RNda>-GZRY;0;c>d7f?d(q}1Oayqt!vh$vSE8)de14Ef@DiSZnzyQ;s!p`^t zwltnp0SR=mQ0x2@*mGsw`$WRI1Y8?-Fp`djUQwW9XKLwMN`p#hfR~n*meL{iDRiK+ zg}Rz9mo1Rs=GMoiX^->Mvy?&Z+w;_jn;Si}KKTX|hA(oA3jU2~K0q5^5Fr=ClZ&M* z4QKuM$v>p0>s-@?K7hfd8F76CoX@p{mp+K?9WiM>)%d7-2N?D|Wx>OrW>0JA_{W|7vmn5V>dFk)W5h%JKMVqsb-uz^NtgP_9XP1V z`3X?mDfp+lg6lAKY~zmgDr_Y`VH`7+|u3NzI5U z{d!o!e14#44Yz5<$5Ew4TYVt~MRbskK}&1+@T~s?bS*sXm&TlV$`$V=R_{h^_Q!{Cy*pus3Oj9S2V@q z5?N?qFCP$Nw}t2svw%ZHd3K1Hre{!=_x>ax=R2_tQpd7u1E#N%V(;$c8N%OM6`Qs804$j=J+gxYm zQP3iZbi2zk3>+12MMyhU{rJTW0isQpF$SxOkOTEiC4Q73vk|Y(BqUt-*Eb7{vfWC$ zEgQe+nH=R@`|hM4oOWcVT42|F+$0UDW8E86i#$+n;rkgBm%Sn81#{YJ7XAH2be>91 zgBiS`v1o>k-Ti*0Mo4BPPtJxeJWMU`qHWEZen}*H`lqaDbKJVPUy+X*$OhWRRX-7@qi~QCZ9Wr!K0Wfi+QQp@@o9QlP8~N{v(;!heRi}kwa-Is!6{!hCQd_< zKG1d4Eq^BvGcR^?jkXJtvvf-H3pnF^`ZlS&ncpH6Nh9*XYhh5cTyD#Sr{D0j zJ;qal2(~|_B88t>I$`Z@Z0~eK;0}Kx-oRM?MH#6GL4v^Y{4)KX_!He+`4iS_xrJ2C zrz@_D2K-{ZR)E$wg_Cs(K$DgmQm6)CGx6E%2_BRELN~>Z|4u)?q8`meuYI{npTm_<-1S!Vj$gq zXC$p0eAjIVF!?^1<=3r)m?g`i)|6cvpHEvf@c34C-@oGAw zQ#4q9B|j08+NS=rvRs$S@XXrqB>MCBT#IYTKPPfrgvhEI*eb-qy>H0%vy-}9-UJ=N zk@)hb-7cY0c*V~wp51AOz<20BTZCONajqS^q6z5`&B|&lDY8wq-!z32uu^#5@@?rQ zLx3&QDFbGwNm=Cd?W{W<^p95IL>Ym`J1eKH-!IMuY>FoCD{Q7Z*k|JRm_;cyI&)kVsx z3FqDYM31oM%)0tMpUKKU42AI)>#iy1`6F++QDf0?#bpYnG}g;p*0*#1;7dD`w^aAF z$rV-&2e8mMlBchqDUT11@RVx5Aw7NF9{egf+4B{{_&0^IzjeNBnQM1{1XE_*3`c;J zAiq`i^c7Z${_~6CPU8>!#9>cK`7)nnXZtIKErY(hY_27c-iD~mx*brjh!}7s*Q#8{ zvh+P)SQ}=J08_L?zFqppqzR?3A7wH-S}TjD6{bSLqx``Db~r-BdKic+!|5)jeO0bsZo8PoqZYqd1)P8Fq#)Ss1c|`KuNaV`5v0Y}v_dIcorNoRRTt8^kBM*g zgqJYO93@hJ))_e;o|s=0x*@|Y|6z#Vse^?Gd6?Ra=Bx{TjNRn7Maaaqc~g?J8=h1} zDwpu;ypIyoTC&`(PAG0e_d?@*K*W-n=I2#de!r+5!vF* z>5knmR(pr<#HjmNB)}tQM5`2?BJEe@8?%s?xVla}^0Cd(zv&RZR$$W>22-nX+q}cO zC)Ak3t)Ie`^e=X2Bg2o zc3pC+ZJ+hR6-__*NkVmg!<(X@jk{d>S%TYeh=9oEx2>+u1|;~$0*qSSLI5)7`+D7D zL-ZHbMlY?;Ze`W8g(W>coNh5JQ_y9rr;r95@Hj~(92DIo$l|7ox^*L|{B`8E^T#fM z$6H_=pX@5_hg~I=Dg17qKut>NugF}h2mz2%q|#|7UPh;h&!AZ7Q?DUY77y03IXFA#mKH7uo_j7<35u#mdU|SO%c{Wr^1QXI_f;M_BXYG-4)JIE9CKuU!&`t zRs|yrzV?KNMH#_FVaF42a5jLA{5J+rfMx=?>KC^>CF56X|MFs52+G~)qVn2OMWf-W zQ}+;nc_^E5fo0gB|A>%@+P+6W)>}x|5%zqG^llyT3U-;tW{@U`EzhM(dV^^lk!qvJ zw}}*PDXIRQK&s18X&nJ8fy%Txv?xSAwyIu=RlR(Z^36$s-2N`EWqi7ni5m%qjQ;u(X6fkj{c-$3)dCoe<+? zu}KTje;EC6lrW&L?92TGX$P2#4PK9c%}sm6U=8q3esv_0P$^x39A-a}dweF06XKD`(4o_=HOkLOCWP46Y03eN-1& z@P4#HyH~8NdRtMO_d`-~%1cq)sE{ZNU^v>yqa`pXuS7@`#gj_?Vw*$m=pV)mbMB)y z!UA;O*7s6u52as`6fUK2R{3rz=J_-gMw^`1dy23m*C+7j1A$Fy10-xC&f)YpdDne#*)KLyH z#q7(4X76{vZyE^~sxp?)tcuZU<~ zZ&&RrMcZ<900Z6qBivC_RclgXB93%sjcf|vgLImW6-2mjJFm^_!^ zPWae{zvb`BOkty2g`YB*%bmA0HY4`t#agm*3QDYu!WD%NK=b3bO%4v)pQcn-@F3P( zRDDG=lVl=yt@q`p&9uudrJi}dRTioivrXjsvGi(sVEWK^c(2A$098eeJf7V4Sm8Yz zCb2bAwCvwzvF~3nmWi0N@nx1K0IwKdxKdxGn;`^?D4wdA;*#ZkTUFixGd?19_}G|W{j=4+T;PZ-5Cc~rQ6v~ zZ?EB7`a&^*ImqvyzsgqVd$GBVdCU} zUc4xFOu~B;{>!pXZ`ZV;ypovJB1|i)$QbVjk%RYT1Za+Lw;yiRbbr$r6x#h+RPbAH zu60*2&F^)pCEI5Tt}RDdJaP>tjH3YCX&f$w?u})ug;vy`{HUBFuZ*%9_vc8NmUTMy z`JP|!f+*7>uP-3F^ZVu&b{YxypX6(1>mI2fKSJNX5_(Wso}}|QYchv&-MTM41x;d{ zoKFx)J5h+OOv7T9>Wtx~kE%rGnbbGDj0xpDx6m3l;*?XO1|gv6fRfe}-7(#dSTmwM z?+(Vn981&bmv+Z|W$S4iiCvi1JqkZ!O)Rn2Qh%A-mU*(5U1f`1?3F4L=01w?FIak- zzM_@_d6Wo>(p8Inrs_z(GOHDx$2GvjXo|p1uK^Pnwhg~NrC0THugUQ&P+s>**n+x# zDe=bhR$P{@IH%3UB1vSqjkxix!7IgO?+kBlqgyHbbqL#`bK1l9ju@f&9Dfn^pdiI% zD(f(zFq}U;D3`8v_HDwIal(X>$~#aOv!j|rU17HRd7S8L5C_}bYrFTlt3nif-0)ou z4KNSw{4VIt#L}A26*cdfkywE)vl>|@t-2~{8#ZYUv4rhdlhoJ-slN2iYok}l?AG?W zqvio>6IM^n+xzmBj$0UtcjMuMpvEVocjE*m&p@CgJ7&H#p8Tm18w4Nq_cdBAVc$&L z?ovv=A%{j*c^kduBs=@y|3za5`Yrz5Cz#i!(4Q*y z0e+cxCxNLG!3HPt+|RStR@F!AZM6VXGF&ZLrBf~0VJ$}_(QbCUW`QOJwa~p%(O9q3 zaOkkOhH?=Q@-`xzE*z6|TeT+M2ad=i4tQMZGx=CkXmv*6l}D-C4Tm2y+!KP)Tn@i* zIGSvMF=ROk`2~H$#TDNqSaXeh0?&S^Kp+q|L`W=}>w#v#=X=@0j&%dyTN5@bx-$$b8go#4X+G>Gk8_`Mh5+aX>2cMv4wEdB zH112NZcKJak5ll(_YWud2;9c^eOcFW*fb(v_oAcs2Se# zEiKMzH{K;Bi{sDh$CW?q+BkQ%vB96}kAHuk7dup?u_79WTGu-SXpo1&k=Yd9wh+C} zY>A^#4nlF$hM3YX}wKyQW)x6biZ4{6CDu(#TX1% zPR8Slz|2qT4gh_C7dEyCHYd9XHZBLLf})UuK6+R~CRwm%aht%W^kvh(E8WYqYfG$d z-TAQiU|TuV5Jy_hHa`4WD0wr8Ifa9s!yx%Pec_JtmMpMB_O4~l7`z{Poxvpk^OPOu z7{U^mWr2!HFbe=!KdyxzARqh#tlM&b81ZiI zZygv-Td2QW6s#C?ytzsG5bjucGB*(L{6<8Al~#Tk5Rq(Sky#}n%k5T`xfwrH^|&=| zV#kruNcAv4Or8x!LP}jYipYdDUF5EJwjtpJ?a)Tdw(W)NGdp z?jV;8Onfb$*HI+^cELmln5x5-EAh;zCq<`7O|KT(7qGSpb8BY+bLwz5l-0e+p#Wh! z2xY&0pAs-;L7Y8ahBcFWSs|6+b|FvGrF5=Sw~tjfB0pTj zW?98`Ksz$^^u6c@Q_w0cKu&qc!^2`dG~|9N#1H-3?>f;fp_P5$U+(Rn#JS!7UM`(= z_%lIsq1rqF^0my$=y1ujQbSJ;YrsB?jP@G-pY_mcHWTyryT1j(=9q8j(EgP5jv!xz zw;l?RQ5&C7lSLruv`zs?lvMeLwa(&;^6j<^hkd~h6Yhmh0{LM4AA^fZMDi&oOdrD? z*+p0}ClZ8VqCqc{rSGCLPLrk#^YZn~IedVtip5L|OKjr$S$&=Imm+CbS!_6qZnwYp zJ$=ry1D7qJ11bv5&MjG>rx=4NNV@FopNQ*yE^EjH_^7nb_Kfg-tLbDb94{LV`iDUa zOAMGBjGPXNM~?xmocbf(E_~hnapw|`HR*I^i89`w0jizMgz3oEKH`^Z5P&j3YoeE}@i56L{p9JK zlNYNIDPCr_MUac(;1M3n#xpXI^lO9hVRhAjTJw1q&J5sWy>-`!x<)t#x-tn5J~pg` zUaF{%wR1gfqcfE>F9qygypNp50&CZh?(~F*v(MskvX`m^Bu%5g!bcJYRJW9`2Zh(i z*Ufa*?$diwmgn@Dgq`olyc4k`>o^G!zt^siOJ`^s_<|ccqoO1755vT2$(tj&0zPIw zxyyJ^tR zoa&^;=9S@Kl4U~3gkX589qQIa@Pb-)T&gRg96u{p^F=3fN~Cau5m`a#*wKgI**A%$ z6mud%!U1TkVC(8k8LaDnu!4sFU##HWf$vBb|L!aM7QxMyL$R74p2vafUal?#9qMG1 z_bF&<-}L?TZ0&QGVHxPa=M7l||3t+2E~62rkM6k&`||i$u^jr&@brhN<+ScqP>|N} z!C}JamtlRKm-ME*i*?e*jSt1L{soTvP)Brv2c0%4L^qF^k8PptdfqBOlj@}|JegNL z^QZQ*FKMpqr_W@fwdy~{6U_UlUgf)V)k1w2#R}xtym8TT4aR{;QY{CYDcm;PtwkyN zgW8;5X7DJ$`h$}a_W7Y3m%}leMBjQ|+3*WDgRybU&m)ptDZmp}+|hWsvEIBw>AkmM zc7j&S+;z^MKe;3CGTKGByKVh`*gdlVik62q4f3{m0J3+gG`MQCvL}Dnw9j^g9?|A+ z6Wt7(-aZv@yh-tlwP9lj$`j{BcQRq3u91h&XRvD*+Vaq`)32M=b7dQWBxXBJ)BcHv z0&ERu%q?1K$%tonPJgaaQyJ(mbiwT9uyuCj1 z9|n_~^cYOI-7`5a8(+?*$}1~=d|*&3X^0aI!y_gTzurM)=hO!0_uM=B=O#hiKR750 zm<9V&V+c=X4PJQTLFn%o@U_Z~ML!X-n2VQ-P~9(3&2wtS(oo-}mn3Vmx2 zyP11^5K4(Km{X^m(uu z5z%`JDOxuCJ(Hg8&anjed#+)o(MN~5=EAr!^}3KjUP@-}VpR0%$8Iz1o952$Sls4| zK(qNmK?7r}d>yvsS5lKN^@bFZKa4b*4%4RiOqbsnv;cSgG|)M_#eDtUcPR$;gJ8q$ z(|BG}p%Mx;?D8`j#aK!*%A3%gnB;NBu4YeD3)m#QzOQ?^hVkA)%&$!c=?15Fh@)10 zozt0+$eMEy(}OtsDFal)1daIw?khY$`CVU?wXB{z9Tk}7I*fCSns;XNk(&<$4;Ama z=7j6K=ZEJ}84$kr`n~mQQ#1}?N!d^I&DuNuT;8OYHf-F52>PKH`Ir=3q6|7A&lhC zhsWCm@J6^>2Kt+(TCOxB;tBCBJo2Ee#Cd~HvJsuDoAXX$nr(S=uJKw zF`7#S3tpFAS%EQLeUM(SyvdUB7-ZA{=SJw5S<|dxSUG{xL8;ZY^4H>&WPsOp$J&jX zJ~8-fa>rrBxFE+yp!{EF`&Ll{)M)(`(i|!hk4SpwnL31}QC6;Ri|d(YJY1|{Paj0O z&=1-CZf$-3!KBLuNSC&1&bo+U`6)&%J6+NJ^OME$;L0StY2(ePeii;dt@sW<4hH42 zhWfz~!W7ZRZETfoP`siRdIY>E(F5KGd9L?pP$~JjJ#O42P_Q!Jz+%3{C?;JOM`t9> z9jQhVRTi4{A~9mOPa*irxH0LAsRvevR;Uid&$a8|pF+#!+fY%BiOw?XQWOP9_E7%x zr*r#_t$XH;=|I!zLWTDFy7m4sJ5R5FoGDR)8kvr!MOAS#;=qcAuVQPfhNKN{n2)-H zd-$^^I@~!xd(9>KVTV*C<~os(KO8^5fnL&jO_{l(ZzI1IG(`q9r1UOyUKM8MUGW^x zx)psbB)52q4bsm*nj(pqR&x^FGuH$r71YzwU(;G^z5@+C8+`nnZhFh?0#Lsq>kv9QJz&A7+;M4=d ze^DrnD-Asu(y~92Azh;JCLdSv=4nz7e`U^m+!I2D5v+hEdS(_{Tmo}|y<651s z9S=$C@Wvbkf#(5;QzF`dy?eu@Vqw|(P2}QcajsQKhF_VKi3+a;swcddMNFz zGI=){$Vd8xyIeB4Z47H0{5HBb70G-Q@Sz)607V>Wh@^+Jwik^K5uBN?c8u4%JbGfT z{;akAkRmXup2&<(Hj+;JiIDjRlQJQ5<`f36t?h>an>&kOV({?2rX8@>{>J#~h3flG zEexlSXawu)KdAj3{0W?YQ(nGPoEYvhl+m^{7-R9Q11o9A?Crd-mpOJ8MAlfqjHD|Fre_&sd=^?1PhHJ?ul_6jxLi=P7nYI5FvT1Y>~_G!dlR_ZO+ zehuKYx8>&n;m;*srG(~p^B}w049idtv3~K%>_Y~ChG+#w_t836hHL2fSIX8krvx(A zA62PHlT%g;fL5!W8Vu|EgCI=(TdP_t7KWJ15VN9#N$a-3H>c<-JnxUun)= z{~N7iZ3Pm-eZBaN-Xw0L(0f_y)Gcd65E8dEF&`XO!tCB&@4(*+sGPfx6j9S7 zbSv-^Wo9fFWask!UC(E7$i<+A8-*idUsj>tk7E20qzTfC@X>v(ZXT077iT}M@DuceQ0$1HpSqu@f zwN=?u#Zlr%bO%2q(E3 z;wo=5I<==S@E5oz&$;?V2{R_@V*RG)d4z2DAInUXlVWL&9+Q&}Lx%4Ognn{c3vNBu zCJnWI{QTW?Mr?wis6NB;$9&@%Cx@HK@9xpif*jCo?%O5wMOzNEBtZvu3QdY*F=f}V zy^3TB<{JRI5DZb4_>lZO{%P!tIMtzP7z@mFA8~Sg{WpZiZ?^ucJ$Vlf3U^H^@1=aI z483YE4jsWkKn`Hm(1JBO_ED}k@W68;PdhGo4_FAO#_uIf4N81Tw&ovksDaU(H0emM zlb=U2-czJdz0MuKpnmx=y>6;_Q{-E-?79Fs)yb7+jm$zLqQ8@?Q&0u5C{oW+!#=)Y zB#hmFDYtngb_5368i`U0^1&F|y7ZOgQy7FY?8bOsgDL1TpZBAFzNJzX??Zl{r=+@S zwnw9_F43muTyUosY4nxtWjFt3&k}0=FAAB^K6zMhI*emu>?0qktHpXg%|MwhP^V|Q z7o%U?URoZX(CoUUnVOoY^YdFgyM9QV$3zbVR>@Q#pD=A~DF3-#_&xA6z7d5hO7iz) zlEL9<(TBE$o8_CrU!wdUEehUxznP!3i^@D+Ziec0fkO0!_zp0+85ai`q9~#%>Di9{ zL0%Q?y%sZM9rw?Jn;^|eQ}EY=ufQ{mb#@1Ddi z-WUCS@Yh;rE*_0}A~nUWCU(R~x=hk<%0U+cR+18^_V=4w+9OFquClB(2;pZoDz~Dy*F{TfHdxELTX$hBnE|lzPU&t}(#wR5 zhl=}2Bf}d;stJMo2+b<&XntHS*=!#U zn~5h&h^lX~IAE<}Fo`8>X^F>x|D z8gXoHWLFuvndygcRJIr1n~ylTHK|2{J~r#mEZZ!~0YlFsBKOcxt@tVGn}WB78{JL2 zTsoI1nrdNj3+m%|h=>A9SA0(i+t6WmzJ!BAYoc|8>`>tcVz+z(m?T)Y7)ROlLrp0< z0V9W0a?Ouqsq7?7V{r|KQzXcJD0o8DPe0*(Ww?i}%LT4_*~faT6IhJWO0YPnVCPFd zNEvVFE;Zn}8%m=5_X2@Vc&`vX0>&GZyuCQQS}~=qW=7Iyztw#xE}i@q>a}i9r=ars zt1Lm|lET}GPB-YoGjRP4U`Axz?22fTls6#qjKfY#NYY`O7eI{e@-{Bd(p>eby_J*? z-y|cSqR~8o>=ESRd2_PIE%iI@d6&Q(NC}lXoCw{y*5^97LR2~I7;{c7vu~4=NWzIid>hG@Rm^C2u{ORv~w@2Ty|>>FqN6L&8;dMZJW4Ki{-9AA1Er@Y63o<; zlqSCX`7bEP$e*kf4-nJF`3BN!Z1>=_X!jCyJ``-mI?u9U(n%!-5Hv9oaJoXJ^l^F2GtBMWXc+=v5@}SB90*$u88B3n8}DSle-k%23E5t$Pqco! zvLDe?$XMq&MDd~^HR`E5nC(jhe#8=-qcw#URsuA>?|(Otzn82UhbQHH|6Jb0*ehJ? z|H?M%b<_07Vr%qHfeL2oSVM*3hr}T*cf*fa)oI^S`(c7b99n+=M^xU0eG_)Qb&+id zBT@Lw(TK}7vngxn`3}IVYtbb|R2h|l5VXe;k5C4tWhSi|=;_sIH!)F~T;vbHgUwdv z_&A$c<{1INW${4%GxSq9Uv)yWOKqxH?nx)qVov6Q$W)-g);6YkKcBXhyA)tw!5>W2Fg?N=wm#XzTrg-}o8hNEgZl0t>nLGV83iHIQ1(-^PM zLAwET58CA-3{DP2J43@|gVXG?ftMKFtaIHBCb!pE4gu9B3msRp6nJJUCg|;fYT;pH znUjOAS&3vQR<>3*DLmyWZ5$OT@1`3~{_ip3s6v;owtu!@txd&-TgvpWv^LL~B<%c` zuY!SzGeWf8a_h_!)N)gJBxI|bqAywD5xZtr?6$3JcPSh&ni-lh~{p51)#G}_5!P8G#Oa6(Ym2K{U?mt)SAX{M7(iOyNh;R zfnIG*U(gvTy9ySH5uPUlBQ4>7UbK)dU-aHe4+UVj}v26t0Ui(ZoSL7`*M68^N|cLujLLs5c!mxpc--KkSa0!4yF)*Tf|E zg~2J9|3mom^~Ixx<#mp$&cFxdv`ZpI3_rRr{eiDhpi-l0?|amC{l0I*n%0Ja9E*0v z16n&~!F7{2LjqZMZT)-sjQQ+H#!r6!VpzyPY#q&2?ZYR|5Z8^#A9A zfc<|j2n?@*%mMEn69V&L9fnyF4)AxsnQB?IAM;c$0!QCM)87(UPMe9i(BCMmKbW?6 z_{w|MiaTweN)k-I9JY>n-B33uA?I3Bqb|&o-3VGnS)V=EQ1Ok>SOJY+ug@H*-)UC+ z5HDrWB3D_k<2`{h57PViiiO%ds2eWAxX|g)!}dy$*w?&JtfWaP@~JjW>l^AQj!G`e zFb$*TP$0k6g{b2=utOhv$_RcozUr`G@d#82tl4UyZL{r{5vIYBSOcx-hLa!Nd74s$ z-P*f;t}FPur%GjH1tXqYm+}xv03P9X*YSy5t;Wq(ecmp4Azcrw|M{mx|6W35_Fojm z*2<2>GKtTf#l5%t#jL5}PK$3Ak(v)Yw-5=~Lu2(*MQo77#b@#U@&vy#=fu7r8thP;O5}ru65o1QCS8r0~W$ zsdUHdr*si$HaS?Y ziK@K8052=6l7S>%XEMY!Cj9!fb1Saz-}r2R%p?BUm%R1elrd?2(#;{mfbL$oJC`~< znsir4Ju-y{kQ6`_JH%6McWjnhIVa+{>M7N?V}#fPH*3LBX$OD0n+yq$?=D}E`D8if5Yt! z<4U|+F9++BT%v)gzMSQecUyAy1R*m&fRI|w3>iH~`XH&1=QL=!+W$DG+5C@lTH~90 z8}B{uev6I5ZD&|=tnXHhW3y2rCe)xIr-{rg1VkVZIss;5-*1BYl+*ue$yux0aW3F> zu_7S=|HqqxJfvt>EQ9VFyN+!g0HR&^C83;J)eWy6^3vzpm!yC|lVPk(llz1`c793p zdIZE&_#nu!E8eB4&}45c+TJGVUgh|GY|gCf%VZfgZRgi*-jRfNM<~NB!2hR@gn@xC zA30(EkB`J(U;zsBx_^>KhAjvBQ&n1>O$@zhfnYus@i?GOMt&+X_%ow78=Ez0=jX@q z-RWhcC4-bNc2P0uBwxMs5%?M&v?`Vc6Y~~J9z6}$7azN&ksdn|WPwenJ2D z1?teyFxhs>%_eCvI3=u@>H-XM%2mw!J0z(=a>?^VM3hLNUE)tMCx40kpE+ad;dX(zJ9`=CNn3*7zoX2Oos_Q7O7=TbK;v2Wt08>`Hrtz~6KwYV$YXE{ ztw-QUz;29-JC4$ZQWTA=G`?vRHME3*@t2pE7@iypW1Td~4KtO)?)KE9sNek~P5~vR z0c5rkET`Wa-7p+zH1Tns$O~mZLN+l}&TGlmY;r;b!SmlW3<{iS{o(kn1CZ~E4j$A3 zAq`X<`SRUqpwpovWR*oIgPtvlm@|M>BJ1{Mh6rQ@J*=(!xX zMyS2iP!wY7jcW{1AmAdsN5&nVUKCxM0UL2t!9c*RyE{S91nno{jP8y7f*%Yx!)raK zG&l_JeO=7bjFAIkh;xM|dY7juzNKMCdwx%1a`jL}{b?YJdP83jboKVxCB+-*Z0e!i zFu2q$6Zhrz;ELOscIWE$7N!p9KZKYjHpnOXpiQ;3`!1&O36^qEB;);BkeS%MX9x9$A@Z~fK%axiN};t2V0o^~zsKe8 z<|oWgt9<&_LUWf;&ScN~uw1Y}(wv$5fL(l8ARjf#Tdo{`T~hEnaCV_X(4=+sT*DOK zZ=q#ZSXjycf=>F39$d#mvM6z&iYa}XT8{R?OyB;ish#<>p1L|LlrdRmObNCcS67x&u2C3(F1lUP=pGdz#s`N_r`cD|kKXsf5zNJ`W6hr2ed9f1bY zHk+5rGEo@#-B#x!2}Hz6O6G|1OqO?r8aYA?`~&!M8EFuNqy2p>k9edEu?%FYYV|^g z$^Y!8`xG7ZMs_m9J}I!Gchv8lHs>`gSMVlNQ^#bWEa`AQtNm`9q*9sCj)l_lvo^wm zgJ&?C2MuOTdgz&L^^+kF8W}v8Y8lFW-sot!lzaeG6oOyWn4O+5>+%$_1;2_9q_>DN z4q~2Rim8kUQeBZjH`kK7L^`YB5s67#66iD8+U6SDWDfx1rP-KTaB8ng*Yesx`;IYJ zdKvVlS5Z8ZrrEhb#+lvrt{PrHmo%2DIicUQsP(8^aUQi{;9}~siWL?2n?MK8kzA|s z6dQA}gl}}VWV~N==3+xZQ~>f(LYARwcgctR%CXksYw)!X+b79W*ZPuA0#^O=nw0JQ zqi>=+1dVBEDzop7_Mi?`hp40*e>UB@GLjK$27R;&&a`@u#@11P&%gED@6;Aa4tR`j z359VN+bO0Y)_+&E%hGE!9YE@Q->Ran8YNQD6(TYYX% zaTvd+wI713b_^`zYSuCRZUR5Amm{V$rhO*+cid<+5UuM7O1R@wXz6eB(RZWGc=TY8 zuR+A+!A`)r(R_H3TbDC#6YV(bjF<`Vv@sm8;BUGnojIesUf=d(+5(Tl^p7qQOA@Ej zz4gOwylOXsG@YLQ)&NrjXMzxreT}J0-^)vt7q~pN_)xRlCs04r#K}@4ZzVOYW|tkb ze8$Xb3nt+9H$rty-v->zec29x|7_~`+zsYJyhCRc_G{%4x~{TSfW;gWTQlC??pVJe zg-W<)JQzM~Tj=1L>SEPt__Ye2>vR_W1=fD*&rPYyk7zVFGr(pN!mhd%5;Zs<`P1?R z#L`m&3s&^nUT@z_tW2A9$4&0+?PnSI`H@*4{HT`X(J|LirU6+)T`;rn(lUy zEMqd~*2}eMqchBIBU(4~?YpS5T9R@W3ol2>RuK4HK#j+w)Gc|l(&i$IbG4kjMA|3R z>zujy)09qpreY&sKRI^s8NblpTHA#yez_CH`{RxeKVb%7PIFUZQ^Vhj1-e(OczsM! z!bF)t5xF<#e1nfaJ!bw6xL(9|d^!)!iK$Aa*PnE|E|n*x%z?xQYlKD7-QDG{DJWaW}qQwFc1T(C0InbM*8YJzX4{x}|92^Sp+t`#fNf^iq$e4|o2d&U=b z8jbl)2RIXUeNxm;wdwU)S`RFW(+)^kOPJ*u_vL;dU$nDk<->WS#v(OOG+;y=q4{LJ zvNi{(E!6FTEW=@@bFOyH_u!dyTbYQTBKj88@1(w@)CmYwW}g7iQO`q~n+aHSYjO@hUju{4DESu``W0=`w|k-qph5{XJYgqP((C z+|JD_K8N_$`N>k|x$tcDbD4jE2ox&bsud7hf6-lyhw+PDn`Es8e$IkyHvu|VUi8*I z!dHwsfGS)+snw$d$EG52k%{)!MTrq{DMJ%1QaW6kmE5}v5d@&)`Y{zkDwMC_K^)!c z>I|D!cfgI=XaNhwO)ILGPLZ=Ps2Rx|Vb7)wU2Z1(>D5r;$?8juEuJD(%;na$P+m6^A5kg_T_!0Md^(4X zmz0b@w?1L=SL5!>RNNlSdE2dujNFsj7Tm2yM82+AgZfs9LS*2{ET&CDs48wlO;7x^ zgk(>0vjbs^pS>W89KBu>y8RG;env*qAGAE;2_mMf;xb)gegL{cbuUYo&8h1-ixgK$ z2Sq&N2YVh~{H94AB1l-Wa*M5ubu_bNS2juZ)<@DlFKBINNNgvcsG7`3*2f!)kk}qP z8xk>s5i(^sL+KlWgZnMulDx1PnKa(?ZsAa7{IeI9Sl&*!OWvh8(h z`>osu-V_yeAKx9;t1lG(s)7FAhPs8aJMlJ^j$#Pa6WW6JrNrzx@d71(fG)s2)si!& z8uC#iEY5wlT;0iSxHqT%^&7h+f{P2_3LzRg>nXW__MmEVV%KLb|D-#}tHbVLT9CdCNV-|%q*VXI4_^XW|LospFM(((S!~V&`IEx8&() zLW2|1^)?>UGI`7SwiZ+E8ny%)EQLw_2er^FYTrG9Mx(cXVsA@wG#8!~ehAgy(!L+y zJFX1tz5VqkWA1$yLX&pp&iu(Ex4!Fr=SOZ&2i4_YIf0)P+c?QYY9n<==Lj(nc}DpO zEYuTIYEb)sQKo=?m6?Kq$1@IW`;JDC(~iFLomE+bL45~mP5ruhA+`I2v;gHBLLw0w z6HEI({NuJm!^?dGe>R*V-rh{3YPg9hG2xl(CwiWsBvdZ2kfm`HlC0vit@ug#9(*i;sfpCR$ldjfhu_sl=YJpSCiQ% zuY9xCvS}XFiIb>*QB77A&nE}yy84{sdXIpWoj7wN5a*w;@UYNXSB zVHG$jA6N7=#fmze6!qT{6CGi3*i!yjrIROr2XmqK>u%7!_6s}-z|~v&KrJ=Mc7$cm zafN(L1psOq{#@NYDSf~HI&d@OK@qNZcb%oHU@;i5f-v_pVDEb|l7$!Y+~J5Z#`oG98bG=e4^B9+{@CS-%V^I!Ol5TYH@W-&v_kHG~@D$@|AM zPaWH$!*7ZGDO(fpu-OL1-D{V(iTGp2+7mPxbPySGlpsZ#DQiXk^>9a#8e?ycn<0 z`T8|)Gz`G{s&Uhr11&w`P8V$X;LJGg_9MA(F-%r;eINe%JcVAk4fyp>-l+8eRJdyD z4ovwdxva20u?c+2??m(Lyyt7@#}~d+#+lfnqMD@QoC-63ST~&HB)OO0RFy=)!@JF6tG@x@5DIxnGf)uuS1-VuP`d?%aSOF!xGYzoubBV z!Qk|K;fw?&+CVm)FJi>|Mfhef_ekC?$Gh)cc#cG028U!cnA5`+UgM@0hY7J4vm#2& z54<|h`vh%T7CFspw!{;fN`Z4oF27tEl0FPV#zGj)IXXjf--6bIOV|@p_UmOmmgd2< z2bSfVeH>}vUuIc|IYPi9lhfbh)s2JC3tdX}_M-*(aYY4J2uwRob*uagEf8LVt%NZO zpWM{rk*QX$xr?|HXjNb>f1`8T>Kof6xU@)X=N*6Zrc=bFDExW8=B{QqI)=wjnVoMxqR|xs0gxRpn6o5;NwL`}WJjk~{Dv75g3gH`N_eUCSV%gX zIjBRjWpbEYx-wh*@L9Y@uo-mc2g1U3mFnyn7#q<5L_v|W_I~i?9v5h_A@ii#KH!F{ zv*ke96^spP98x*3ux&<5X9xWK95TNtp~*?T8!yN&Iz^Ygaf@=3;v^o&dj>WePvGD_;zl;@mfYg7h&WslXDws1_t zq-KmPEO%3}VN;dheYpnqk#GVyA1!sz27^zPpXMj*vmXF9K(^U;f8jlA_RrEuU1q&8 z;X6V5*Dc92bzw*1s(W}!Sb@Zp#k?C`$&G962tSQENslGl!RDNZ{Uf>Ekz3jhY67}( z+cHtbSB&4OOnndg;Uhiv1*%6**1FgSs`raCco!pk601O9S2)0nm~mbgx7BZayT$M- zASMODqX)al3>}YwY8n{XW@$+L+{3D1zyJzGCM0Y#efZ_cxoIPoyA*O{%ZdO>tC>gc zKa?!AZ!%`2*?wrdJWYfS9+5?Xf{{F%){*HEzVV&7 z5?Khc6W{n3<+`IWRq_x4f1w%hzxm7J7QQsQ-PIBr-u*9%t3>?D+~vz2iU0Bb{iD|e zY=Rl;XX)lvAE&%c<>Fxju*~s$S~#iUmN@six`Z!Fgoa9AjVjNT8Hfe579#%Fvf_U^ z-5<|{*JJGhBFAiLR?J7*!82T+=Gwnyp702jWaP%6m$5j&9p{*dUx{^b&qR-|y(8yC z{Rk!)n^(%J|3?^nj%7ytMgqrP&LM#)|1Ss}z3Er)0BJD7buqSJU~iur$QJ&F@`W-} zpm7<7_Ji$QJcDr34^+|t(HS7~C~U)UUmmV22FJ5C3NqQoUr?TwC6wf+MS=fCVK3P> z3`gCVnjg3K6LkBa4}CRh6)modY5`S63FfiK>XF3>pXrs;{FCy5K6T=-hMzX)tHq(g z)wz5uE?J10nm04jvplN#boDM~+^t9-|5o~SxTs04J!pSXpmpUe@v~*COQ}rWTlt{G zgF!WDy#D!cF3Teo%zJlXhe5X)x~czR+f54~3<) zEzaj>saUPc$x@RLCX-AwB_ZVld#*YDtQplE&FZ(Xo*DH4+EP6{dU)zjz&d>tJvI53 z_2i^9)Qr;|nVg1CPs4;Zo{7b@@JaWbMBGiW^gi7V8*Yv;jdj&0ir6DoF+@#7xCq1^_g@O<@VGol*f&uwvGV3?K9gOHV06+aPMxpOgNuKn^YJqC zBMtTnl29X?vwO0YP0CbZ#KYBqERs%>G`B(|dUNxlOl=r1oqxQog#xrLt@Hy5^dT~z)<5S3>xxjZ|GYD-)QC++rN38Knr1EQ6ZlwbVn%KYqy67yBqGexHjk2 z>KmdZN2~|av=ln`I51a?#HK_9Ji3_DS^(S6*MY(KAS&ff#te)G zi4%_K_C)0f6~)v>Z)^m~#)r2oG~c%T*5hFI9C zkI*H4iU2Tmz7%l;?58p;r5f0HLlw3g*=n?5H>$ozE>JIMP~Iy3W|@N3MC>FKN~!dx zFbv&s-xHs+?9somiP^y$Mwh=(9F&lZvqC(0gG&hiVcVnTQ@fqe@-K?)N64$M``4Fn zaPh*^9}3;+`271nf=VJ0gY~Rhfk(dIepR$U>`&d^KX*dPYR&qevi0X|uKsXlQ4$03 zxs4hmmg4*C+O}+Q;>@3wDT|M7E1Oy#6GQvuL;0#{>0`#lx7GO{$rt;BNC)ZDEky|pD7vF$4x8x?%L zsMQH)s2@{AiQT{Xn+rc&Mm3}4EDAuG(9UQfJVnV*{lb+~^xPYPK+ez$;@pq)lkg|p zrd^>M+L?tXY>BsP#G@l6l2%G{7Be)n3B}fS?+z^H@H!AFd)v@&FPAgHKGKrcp&^O` zshGhcxEC}#9LIHrH!t{W#^lAa*hv$64Ycp$9Jz0eN97dRi$$&o#ezT~+1KWO_l*&j zc0k9HL(@iFf0_@r>{k9I|CpKg|5V0)c(JvY_CX1GE76?dvi1I^GBbo5XTs*j-(O=x zDRU_Ty7erw`$O8sWTkE+(u|AF@UF2j;1@>N(B0dl-l68+fkZz=2U`=3@>8lm+}|>s zGr%`!gC$X^R^t?10+ih8nC1>i4gck0X#&WXl`@?A&D9J zX@$z`3>VGKQGbx6p48P4^iYEQ>Imbv@pEjxOe0@P51DpmOhlK&M1MY(v^27^FM?HO zFEv)&N<>k7U*TYLAr|+++rd#$h)aFuAFgeA-e%x4FP%5sm}Z!pK{sOgHfG9)X#{1r z;O|qR_ipR=&Bw&eM~zPT5dOuKTtd`SwtJBu9Z{tYfXRY5hi_5@uK}CfcRjG4yrSg! zJN?9^5mLO$_(GzUu-c*GZ*7JcoGybJIJkBHSg}Tn8=YI>P8vU{_!r+yRBMz1R~Fpp zK5jxX4^=EtH1e|5HZQTs5@X#CIz1eF497i4E_2|$Gk!-uRlF8?3M_V?L19}DhuhN#Zt_61Y;3(C0Jz`~~A zl=hrE?!u!Xdv28@ISs(efx0((t$6zGbPksV2>i@nlELc7w&^~}SW-NaXHC4Q+RHx$rd9DBPsrEfDjBbn)ZoN>ds zY6VBE1Ei+QNQHX9<$HLNe=Q?%zPn*F-Kj*XpmR1~b$NefMX*^cQ*I}ra)Z>j>`)ie zSAmOvLrq=m(KH!zL-x*fn`zg)f2@atDM~Q-;#9ECg5|pCBcn2Q?Lp@7%q`JJO6OEn z_L%Pn?uI~0^F*H$ppiC!pFk&})=E?mMWyw;F(Iy_dV+MbzUQjT^e{aFC zy-6!k=VM5r9WtC*Zb&Z){BT%Q=0q3fmR{I+68)zV3OmGi8_p=joQu7MdjoP1x zM5;^DwyIJMu&)<>8b7Rsm)dvzYzNh5R;UWfTyV{;5iQS3(OHF%#`>AZwiCfF#)kh6 z@b6C>Im6JR{VA%!AL&)z8Lqk*;cCprgq{$o8W=F(J*ZB-I=6lJPTi~AaTQo+ne3g% zN6v}qW_VhAM*Zo`Fih}1p`lf6iHPjfNGO`j8w1UL3z}l#e#mWg=S!8}UQO;=A5fHB z!$R!Ex5Z(m>BO*O@k_Zvm<}0HlWWqY_KFP7R97A ztuz;j3d%%2TiOQ{b%gx=4w1#p*cO7?ySx_S3cjpB$Z`Y6U>RokQ+g|2yaphT>ellN zTcQIyY5pzI`YX5@_mYkOxENn*>pG`ts~x1q3;@bxlMUDC`5Psvl}13M)e0ctRg+_x4{ z4GyULRUjf;>yyvI+`6{wukbbPaN^oyK&{nEpy4v+&*Y80VPsottNwRnJJ(^C)0;jm z6jBr2^XHXpJ8g^HxQ*5y9$}{mf1|+2BrjqG_5A(Hz9sc;!+|r$`fv6J7+yW`EvbAf zt9>h(cxi0{!*0Z6n$@>tI+Qiix%Z53!|^*?1-0n+_K zZI5?H-*{|WY9<8pLxNE?tK3_@3jGq3iYPeFXD6Z%+rJV2)ylWRb5W=2L!l-CoVLzs zsE1bj?PXc5hLqw8^Eb(~?uLrbSu$?|^|L*m06OawoBN>rVQc1UbzJ>b-lUO%^0*CPrP6&@&fjugk)|WqbUI;c8 zyciz3Jl>vZeyV6+{qljE0Q1gMOkGndLb7%7zjPOt8{R&+l!$g4^!MN795RpE_nz|- z)N4iKCj;^$})qb_A}L zhMIpSZLa@h*2Nh?-(Y9@ON)0Z{jSiau`13=!MZtQ@NY1G_tn)C{jPdf>euY5{jU5C zO6>6ECKIW$>JhGHPOF!1VCWq>7&(pBWH({%&5!43@8A(-l*YBG?{Pjbdot**=ZF zUgY!j8oQ|PYGvcZE`)^-`JN)4YX#4Ux^{E?;Q7CNP6ft5=JuY22>j6=uDuwfMv;GJbJpA77?l&zx^AS_xxJRwQCt* zy)(U zX%5u+qM84IKkme7c=s>Pz)AMd#{(WIa<-a+7LN zU^UQUAJpIuYW=&=1;6*wrde=>83FpaZyYWd$Uw)Vo-^x) zr}28CwPf8_+mb4EOoY!#kVI~lHQvL;lz;RVcwWO)*~X0uD~aMsyfa|=uH#K<&-dM+ ztH`EFe`L+RWd{7Z*|Hn_gFfG;6jSKF4vkK&T4NQH=vnrm zv!?%%Z|{(m>4*)&Qo}jY6uv6f*n(|1*92UN*4Y4v1zpqGZAU1L#wyyG$>K7*6I1tA{mnw;~)vrM$hkl(>?TyAu zIPL}UNY{7B*p_bCqcYj6is`ZV-^-M0*_zwy0!|&8lwmV1kF*o8?v#$Ed>d9!wI#`T zXJzIc!+j0c+$%9Eq9KsA5(%wS@`6CeN57eCH}k^-YG+u--SxiHK{!`bn0lh?>nfTr z2chQ}QELKL@l_p5Xj8_Tr9Nxj0=0Wjjfo+jUElWdiAO~2Q`j;F;NggJ{ZKZY6bTO2 zW%|u$_pa71BrM6e4_-9Vu)|MY^i(rlUFt`@q27JlU`B{p-?a5Uz58C7yKGh1j7N>* za{w*1?Nc>Gu*S~kmv$UHbX8NdX^z=`Fz(GoTun4<)dmlAU`g!?>O+gk&%n=UynQcm~BsVizz*vRRx}jm2)-{| zjZ8QNT+2;EC9STAM{z)-p(+8C8Q4i{!L6?QSH{$${B1dkZUu`S!au6y1w#x?gS|L_ zM>xIFtZRH=hJ;)>mwo#131L%LC{ShL`t^kCIII-7Ko`e=LGe(_E5U$f$DK);fK3NJ ztMaJ2c60ktHsS_bqe`m%)k6LP@&lG;C^*VYM>N7WppgY$VI%>W~uFRNN= zAIy||*|Cj?sYu&CBJO|Z{uw^@qY3{Y-Ni{TRkIzi?|s9Fh(x`kqQ@8?ed)p@&2TR2 zKajrM9@*YIb`FeYX{5OjS?IXC4N5=$;h^0Z5Z}?_tm(~Tr9jCc*^N;lRfNi2BK2R9 zg9~;BWKs=MlI=Azd2~C!$|qi$0W`EnL8u@f41QwdifeTAsu3ze^}+cs=bY)C)3LuB z&d;crrSZ=_XV|`~W=3zWW!@KXzWZ$s#KcNV1uFQ4zu!%E9C6<7!2ed{XL<@hyHr&O zw=pHl$HbU`5)>a=Z3lCqOn^=qLzttvT8qQ*tPu33d3J;EdxFc^^> zg7qIxNr;?6O^@Pp)yCsjC&giXYvXk*NrpCyTvbe!uwTNEq&jdh@KtSOvBcoZh4|lI z-{l>@3(=d9`Jfpc1;=U=7PW>jX4VCnnyp-SHjRLv!6&Q$N8*VRUpItP z11Len1b}+@^K8-P(%fGg=l2z*trlaI<|dBZKX}9O_sqr$rd&-?F<7|G<}6gpb30Pp zwhuZ|PdkDbcYUuUHgp)DQtjMWGoG^5g8O`kX)9N)+TF+Yyo^L}#&!WYfIk_qC6gL? zl{YFXK@p>JKK%S*ikJK%Cl`I4eRGM4HV(hISAyUR?YNh0LC4@?VNeF!c`F5drYXhy z_zscpbD{9_&>jl)k*u$&-*s#m#`#aJ8(AhncytV+{dj6jB56Q4Is+>PI+XJBRL(uD zP-2K9Y_}c!X@A~^mY9I(wUuhgIzAmgA^)ohi;c7Oo)Y#ucl;#*B1?WvJg_E%<@X9B z2YXsV#0V+r%zaWqK1~Kh&|vB6!Ym{uZA_M>!w0(Fy=>k_O3%c13ph|CHuG9X`Px$6 zycCaZlp$cNU3x)xR-PgTueL96zp@B#*L;KcZ_oq6y$MLj-$3>dH|Ih2V z-j90Jx(rIT%qrW`7kKWPU=*O!@qr+)$_hzOb;$TmzV!x$m#hjc(aF<;{^xB=Brlk z_C4dh3u2?c{WtxXfAViT_CJjBz?}B0SC1I(Mobm6MLzo9P+AgGlU>Cf7uWPeW9aN* zGWa$7@rdNbDV@cAjErj8-EOH&`1F29{K-us6Ah+$)uzWk&sOAaX?4~hiyDB8gB3uA zR>-}dD(3_fx343$81-GjTn&1dSt*efaLUFznu6Bjw9Wp zqfV%2l(LPA*NTrhE>Ny#{4)*q*|?~9kw0wdlBnxgmzSyTCxuXu*ML1FMnX{WHh~o& z=aRO-6+Rg3D_*1uA`}S`*_Uay$bDdRkt)?#ijy`P3sufH-z84VyG={CKrf@~p(Sj+ z(T;13Cy>e2*u#^jIKQ{k>F1M~G2UUznilP#|~47u1I z9+QKRNY9r#PV-f!CXzl2@qaK4Ge1Y*h9j_80cZbPDyl4;ErK#-E{w*n=XMY?gm}Z! zvX#{ifiPH9RO)yR;7o{ZJe9zNh$DJ6kw>82X-{?fsvE16u{$O2-u~DU-5o?lL`H-& z;XJFAPxP*?KSz4VX}rTU{tv@f;v@7}4aG+E+_33!OmAr^`B~F`Uc?_)o!Hh3xBkv% z@m6TghY?DvEc`Y#8$*LrrZZO31qy9D8xx+)vAAi;{)M`?g+4|VHt!WNOw0IK6l?** z_`|{IJE*dFF&& zVI{mwL7%5uS#IoGW{XP%i~9}Y#b8bj3`fWMRe+x&eg#M^C4I?ihlSN}`s}s6=^FG7 zm?f;0rc{6ESY*gqWjME11J*wY(y0+8R>h98&FV(dSa#iOe9$MxPvHQf&zc$#D0zHH z6uNV2=PSB}1T!CWDp9yi`T9iu`Jq9YgKit39X0gm|JjuwRp9+>?BI638=^ksy)i-v zlMFe|Fp#J=>}5oT91gu8lg$2kHZN1s<&ksY!jRDvIZ>L9iGCn}=i@s?#c)bu)xKzQ zXa^^=*v3Bt&Ds!Iy!*}9CKodNw?GaaAb7b=zj(-XmG>xNSsPNq`A+YMNhYK2m$jIH zF~T@h>6N31)4YYmspkN{7VS=Ad??xrA*-RRHd&FYDubKUQVt85}hd8!)kvzo` zl+V1-JC(71`sKBMFGa0rKRb>>>JEH&4MD)PBKsGmUSz0e4ZhJ(>3aA^lACY3Ng_2bhN-7jOb1q;&4)GOPfImCm4(R^v2cf7gRN>MpNbw#Hi>wj_rBNa$D_G9yWZZhRVW)dS-E ztp9W8k*o#_h|3%!+}wj=bnv@Au6(4veOV*iv5c{6Yc112Z7jR<8YuALbZ07xQVm*|K*6RpCh# z$b{2Y6@f#HmCUZmwFLq}Ik_x8`u4iakEq2#gsVj5mlcyOlGQlKIH>Q{*-9z37xC?U z!vB1MvF18i)LyNuaU&Op+=!{euwA~@bzQQKd`gK+eh8H5RgO_hg9NTMr^N786kFd| zo%J`jYayHi-m#%o;Ko>?bKAk1#56h>Rg3jcS5XAJF#isFICz=Zwp>Q(|AKq?Le)Rt zc1=@!ROAr`Hq3mHz(^BZ;7%#vm}Yj!=&Zdt8tvf!R&Gx)Ilb@k!~EDs1$;0>XMfcT z^%l6&7-nc=`E*N>8{w|zb#sat1X<}1!;Jifx>MjwSh}0bMm8^fucq30S@f;VJheEO zwVJx=55^8@YuJaY#S~v^LIKy{^)d(E3D2>zn86r5F3=c^q|Nd+f%YOW`lm?Dytg?= zGzIF4JA~rgSI-6dsKL`wd+FjIyL+!%ecI|vk4;18JNsol*S)sE&!@En^IZv@@BuWe zOBjEmbD=pIxg$ocTH<+gTC1y2Aro6!#%#nVmoB&3GY!pQQ1D53TKaZ9T;cCdl2AMj z=BqM&Jy-qVw>C9pV0X&=5MKtXA}%8oB6DtTF1FN;;#9aw>ryNZK6|?43Sh^_{iI!EarchCgxG;8R=7 zW%B2NwjuC47bo_K;lL^VOa3}XaTj`r{{0se$H&iCUv;!z&`jc7ZM z7|LLcOCXAdmyy7QN#YJ~ujNHYuKLzis6?OKB@;KcmrhsC=l3a;I49@dW2K4`_{=~U z-;y1O075e{2h^XL=)nPnDA$kujnk?#8z#c^+0oKETH@<{5-PKLjvZN`}% zL}4A#pni=M$5!s-inNmVDuvCN%g$etWomokkG6Wrl3aQDt*s94PNE-qepzO1UcCXQ z_`gvuIc0E%7O5t@cNZ-6n=x6gtM~a2L)4A$q`G?6_KTb4c%!%MGF6HOpjK_ejGe=2 z1k~fu=0UqwWJKgmW9-b?XRyF4MtvI?Nv+zgAyB@2z<$WOEjwU@`N9aZkiMIOQhfD3 zg`>yISCnqO?Sog1jnbvKuZZ0W<5wd$SmSsIJp+QY^Klg+&&i%qzEId^+zFQnsjuyRB9?{XWDFY zjq@^`Uk|);%qo=%nj^JH-Wi0pJza*L3^eol&^~0jP6n|wznd%VMd0#PJCnxpPc%z^ z*ko1LW!qy5T4ja>3#R%ptv1u1N!JnjR!56<@EA9zH=2xylIwCG@!~rn)s{9BAUyP# zoPkdPZ`+jo+-+J@zAt|5`K`BzMqSwPpJ{f6L^yD~dLFHlZltQ>NERMUEV7jxC`Ipt zCw(DnpbHYZ(Ya&l|NYmR#c0?B*J>1l>@(;Z-fwMk^J5 z9-3zI@7Lj}#U{BNkMHI%zB)(o*vP$?wd@F6KD4T^4)_NVHN67)eLw$vbYdj1?XHig zJmr7eoQESYRUVE1+ZEeo@tv>+?Vu;`KuD$Qq!`Zv>H6zo-*LJQ+h+%R6;zAE zL-uv)PG7XsYh--%$IVuyco{Xz#n?Ko&nKGx==0I-)O>tf>OE%}6T)WpZJFZmQAP3Q zm1hvKzvz_~$W?p6nZ_(|clv`ps5Sny4zk486Ir^5UQWtnz4TJ)3hh8#Gy+ z9)r+m30@`Y!-%j%>Bh+?WUC9%DL}q-ZP^_RGWF%`COK4+@3M)dMWT+T+02|y>(K-W zrboBBdYm?YG&A5Zm~whpx6AnbvZ5n2^pm3%X@jUUKKa~ypW2MQ@E30K9W&rj@_LT6 zGNq>^)7*Mc?0YL6q$VGpGA}F{00Yk!RxwZtz{|C9(0=tR59b$=`1(}g3y5asg0)a- zVm|-FqiyjThgAEuB&WIF1@ob{D)!cF6Vg!$kZhGL62I6Y^7REZqV#b#sP`Va#X6@ES+1$7w7Mk04P$f|rVktLJa%%lTAM!*SWoz{Y<81)xcr@9 z$^VOki7URPooh1o0;dc2y*z8kdCQKLn!FOMYFe;6XAZ;I3|06%FB zRkI6%2Qx*LU)3<0`H2R(LV~{)!~n(g=+xxGRfy<}T#PO!+4(5grz2xR*rWLNIA2Aj z39f+nZq#lTMh|=8Lfw096coNk?r?MGcrQ2bQ=!qn>ISTN*-3ZGL{4L!H?QX(=jt5L zgmS^|G@bQ9cebuV_2uKln7fCjztz^ke3jtxte8PM(hIZrM2UaZZ0+B6kAWX-&+@&d z(}OFt_`3}(0>n`Hmr|2f95^iT9b1ud7Ey>^SUZNsHJ{QKiN%F?0 zLpG|;nRQR5LCfFB*O$ZG-iuQwE+$`JE=@mob-`avf9Vhyt-91ifncNtEbGSQZpxTS z0LgNZn99>wKHC>ZnsOPY-s&ixJ ziFa=>{k&Dz-u$f#=bf!RV<+va=R26cQXD6EKa|lGBr9G@N$}4Eea(wU$OAGRBZLmW zjI5AXa~D*Vx?kG#r@b3|$=hy3E8lfC`b zt>x$TiK=bypoZ!kZX$*=_FQR zcrw~0TC7~XcpJnLr-~84|7^tk*KgwJ^(;}lnnX9rtpf0mV+qIjl+@&~RK-?}+++wk z2*)uPrL6jI*yKFaov^m~xENhBX>O{AuE0Ul`DRHivPs@pnFIUZ-;vCOK6iRC zk=$Wd2DdP|G@oNDs@D^Mes3W^L&F+0n9{)*ulAcY#N~O>5ZDwlhjg!=+iBZVW783< zo|`tQzthF%Sho2i?MUEF!3Yx6Kx%7KqF2Y=W>!a!Z%78ia0}k}33$eq_V+FI#^u1NASCIP5&Td$nD}^UZz>C` zWZ8OUe9v+@vzBe)v-wDh=i70!Dl7gjU(?IbJ^NuiE>3W4aS42b?%$~7N=RpTaC+ z9_(gVXE4fxj;{(HxGoA8;dQ(4*05?7ecqTkhFunnBeg2}!#&>JuXgmGr?CBpv3yBY z^i79dl{&I;OxHhdv*W%~4P+qlufAMCG z;an6~G;_NY2ppGOX0aZj0ZuB-sl!s%SUz=juPV8sY*yQ@IkYuPVc7upPLRelw!Z>5 zvT2!<>rmEw&i;bEuY9og4B6>-Jfs6N}LGYfS9svh2QmZvF`HgA`4}|1~V)Y7+ z?~hK-5DiN$+G-eg1~7VvU5ASYpU6#(4(_=`yzm0pn$^@~;bLE4U$9zv|3m&qY7UT% zY;HL3f?0p0H5!{8OI7+m47)xVH=-B40&Y0RTC3S#&+WJ;1sdrsu|_k?`j?M^G4dHC z%GT=B!vos-ekRwFWyiXrqrfmbpiK$4k>d~h?0GQP?m&l_0Ni`IcPaz*9$|tRRQ$$D zN(*t{@2dZOVQt={EP!V zQ|$TdyVL`abLDr6>nql3_@#Cc~vbreFwr?g1Ha3;*o&Os^<(pQu> zz`;SkH2{!z{U7|2p)gV_n~vH(xru-J_9i9{6rF^uPzq&^#An|ZGd=ylWLqQ zb}|b%0w1MtGTt+eZ}Lh-)w7sP<4|BjS$-$%t$v9xWh7cPJ~Bq&1dRPHB1^ONEF|NZhgL8bn!E=v$|#7y~U*71s3v^Ndl)@LX4Rm zfI+Gvtb`^XlU0tb)8`9bwEBvabB6wI&;PJZI+zj}L4apT5qT2_!hqt$6D1cuZ9BN} zHQXQl5?yK7<;hk4&QDBxOUL%n{)@O^URDpDtun;_bc5c@Rj0pEv*>uGgCUeP$u~sS z@eNP3Pg4m5#7A3?$EiPtl_7E1l2vt^m!xx0SZ_AeId9#`Z2tS2=ngsJ z9WyV;Kt1_K;lsfQ`=$fRX~3NVL*n$a>+(-2OH+5x?Ay}x^hczbmAUp*6Sg!w&#nd% zR42mOl55n}7(7%~T6bh%x|5aN{&o{v#F@tP9&}JEis4E_ARnhUqb&}kJd~9)RAfl% zsw}0Mq^+G(W9D4*p{k`T1s_tgKJlOSey{|>n?Rxj`{r*`YUY2LMBnrOHicL2i5G#0 zRsC~wi)2CIZL1i1-ggqQCHa-aI1pZ*pV4Wg9>lb-BjfUt{fmn@ebyI)MzUFa)7x&5 zN^Prp#7YPxw*j*bha8;DlxNRSjxiY=k()*z+UT5>le}(KLJniqvF?6}6UG6w*J=ws zI~x`r9}W)VBh~{_0JTQ;i*xPQifDDY*cBVcJcL_JtTQp{Il~MxmX@!dVG5*5a2wYL zWnQ7IlO}=;qX9?R&A5TG2ic}{uqIdWom-LNhGjXKl|D`O&n3b0elop(Z$Ql&&ux%N zwkIoF!2&HlsArCFa*>Y>TuV23WCD@)jL@2>Rg1^Dq4jRWE6_*bG3_T4MP0aQy$np< zxsRTme4IP=QqS8q$K#OAefYPhInRg@g^EeG13x6uO9wKn43C!ce(s;FU9RbWi=Gxc zg4>NXv;(F=ZhOhjL&k=Db#K{n`Z#43m1Td(a=xn7)*EyRY<2o~R9z@}q)3X@%58^5 zgqh5uicbHbUu@Q&QikV~Cc7D5&_V^>?l!aEu^gw#zhN)g3RCcEPPUEI9LV%=ge7cz zs&Tu0K!~*YZa#gMy@i}`UG25XXHcO2!{A(=DPj#M3UhpZSJdiM_p-j*ccNyozR9^@ zHXQA!ph4BtnL(SZVdo<(H$82Cm0pdYrMfU! z#rvb5MbL_ut0%E1xr$s%FmfPKemKpO40)8{W7r;q4e^|~+Nk60)-g1|ntW~B$zlX# zc7cO&FPJIh0QVy~^r;oui1~@_bySVdD?8#NwsokGlC-um0suGzeD9WY?%e9VllwN< z*tQ|myj)nlJeYpii{2R4Pc#e3p?oR`9Jl>m!k1k?UB$^GAej3Y=UdMv*mn+F^K)u^ zX8=^DP)vvkpfOV(&lE#3&w**dGLK$xVS=_pW`Ebyt=@*r)j{t+>w)n4*0Fb972sqe zTejSyLkKn=2xJ=$<>X|wYrcMQ_I7dPgree~Tdz4Cw4k}u2#$DO?>(&NBTQmXK_(=R zo^L{LH&rv;oPQT{UU7Ryq;*ky-lfIk_hzx4gRwIt*CKurZH{lD&2j60;oP=c%PVGL zz8V(mzjHg&#?9~qY7Dn4DHWn|?92_7cwxEQJ!zs!;i9yNmv?oa)^p|B#=^+vQqEpf z_n!TSF>>`~4P7(&%k)+5Z?q)*w;v~kM?x4+FR^QA-`z2m(adU5-w1;e%?c}2irAYO zfDAtBg-!*Uta|N6qnS<4mb3q3w+X8N|KGz=S$#TnQZE;qaDHqNJZdq4H&r%`5W#N$ z4}(N#FEMsN{bTsON)E}#QCprYX^=VVsFt}~5Ys}zuo~EzJ#oJ>Za8xq?cMzako}qy zb$|ccyMf_j=0qol0CjDW(xrv@Ff#5sW#5|e>Qb1%8$d2^8RaV%Z2R=Y>t^}!YTz?o z*>Bn#bgkr1fF6KD`ZE|EHTA}1pp{-wL-SccKdwxYQ`d@=pLbEL+YTP4$9Zcl%)bFw z@(uJc0BiUKX${+l+DHDw*g`*0Zz$0JV8)fl`Q}%7m(Bd-3=hct34l)X4?CTor*B+x3&Nhwp$V{%;b?r z;;FHK(HmkQe1{fo<%^dcsOb^4)L;V5BHUF_%exou=ZtGyI z(y*y=Avy`BV8FWImKMX|-S~7F~3Y9JY zy_Vhd#;e;ik5q|t6W@k5IMdhq*^kKX7F+oSk%C$Yf|>XBqVA z|FFo`5cZDR;NcRR)ioqd25|Omj%>TEO)i1sn2T#DG1apdG(DzR_fwUx^md_;L5_&Et;p+d_t#Vx}3 zi#IFx*GwFpySCi=BQu#l8g#BGy*@X!rIP|E)}lY&K{A!|2$eh9F4s0zR_KW+Vpo

    7r36MiWz>_V#eIzZMZb?(Fxj^NW^1|VJ}}X( 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 z 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

    ?R^V5oA-zUu(}qqjLB8WVliJ8-<-# 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�&)D5=I+IeB9b$)wQ++wSVH>o|2dwZ~oR@8^2%)pZ=q9iX-^SzU^ zlZHYEd=WgrjRojnea6*5r}lb8^O_o~XKg~(P+7}PEh0@L$Cj+9!^y|6#r?Xapgo&c zM?PEoX*0Qj0qL1)yJoAU_0p=LA~27z|C6<>A2Unu@h2yn`@&dTZvU0?r^<+G2+sxp zJtgGYuO9ogT%*h+PReG{U!1@Zu5PK?c2(EyGVl%d&QrYbWFKK^y>W?=7xh9@F~=~J)f zXgab48p&BGEc-N8%uX076@IWW8dZ^MXQ2e)o8%I}@9 zaskHpk}Gm6HwWOJPFaJ~!l0aldq86s3o#835f0wS>7Ckt zpe$B(xLB3Q5E94}7SG^H?G8KQBHb;JY<#e#wGPj#?`0CV=+dEy*ibd|~ZQ#0*xQm70}OMa-VQ-a9{-l-kO_-W2mfzJ2m3 zh+bY0H>w&k{wC9K_58(dFF6(CTXJ>6R_U4dGpB{f>&KqN2H5y}tFo}p3n7jZ3UhQA zi~&N;S_*qiV%K_s^XIXwo9C?78ENsNFTd{IHG8i|!5URbK8MREK_le78L{XFb6LnN z!90Jt`bozawQLTLG-ibd*>9B|g)0s)LqDxz8cx!TGEwh{R5=P$pAbr{TGf>(L;NB+ zNreD_2sAY63}HYz2|5%2AfblkCF=!9iUni<`9|%VCXs;`Ah+d7hp#&AI-1IrE=Lh@ zwRWRgG$BkMa^$Agbzc{r`*U~*eF{JWTmIE3m!!#Q3madw#*TnDd3}pdtM^5_szujK zb6MfG4HF5OH*>G+4U?TBTwo*pT_M=leN;ThNue~ODEr`Y-%_hP`B|w)aA;3DS>^CI z_2YPIKGpVkm7?C2mZEDr07TuDmlqiiOGQ~>GDssynG4IStj%TVv$0||8N6+N@a%hS zM!t*w2ThL|2s}KDjOUDmQdiue=b3n|-H@6m_!3V|kh-qHXo{oJ5lKFJ3d*R416`7k zlQltU(VVJ4%7%E3@wjNBOlgZPhAR@2l#QM;6hh#rh#c^Q?Er$aJRa1!wpIiuJqSjN zrZf=8X5(v}ZCt!G-xEMT`2bgiew=X;^1QLZNi<69-kk`Kml@}sNue$xWV7{s4li=( z5QyKXiUom~{d@Vk&U}1hjqGU=>}ESOi!iPg)EQTLH(SdNGE0%jGxHhDi!jS0j{IC> z-r&<+Zy3B8_r6KndLpjdv!B_u((7robG#y>|$fXg^+toStt^MrM z8AjctO{knBY!*!n@V`53PPF9s0!xDs)_dlT0Wl=Yv{l7(2*rZtrwr z%^}rVGRJ$zE^ot_TT?Al(2(zCTK^2>DJ_u{UtW`~R}QnnWG0VR|H{q5|8x|>XAZ>A zzKpmZmjV~JhcQJ&JRh%&4)qp%h6co-F8LYMyJwF#LYtt^okG3aail-;z?^l!4Q_8vb`WZr9BWrYh0DHRF=;WN%+e<`L6IEjG`uw-Z(uA&fvNIKL{CfzT16!sB}<=Ivg~)4cRfz8hO<(VF-;ugQGH z7fbyaQ#%BpZHJ$Q?iYEO!eRp~6o9plT|e( z$)OUeo{u9`Tdw~>%X}Bm4KwK9+`QFX@)TH0sO}!9b#wx_#MCO zvj%4OckNFT-Ams;2uEGpzcGx1nv43=v?}C18nC?K)9Wu2{_|BHA$CCP^=s!-qHAM8 zxPS{1pl`ve_xj@%7TGbBmh_VyinDec`IAY>8hog4^Xi<^b222;0KKR=)wu=67e zu{`z}{L^ar{vhawAdi5V!1`WYnnLiS_Wxwr`hPY|6kK4>`!*@Gu-)P+*vOgn#Jt76 zw2fI#NM%GQ4;Al=5{&Ht*qvWR zGL(-cUyg^kn<;@M8~+jb1FXHWnrhuy};^>IqfBph1)5;M9Y;zoafNg{Ze!J>)xqcFP_N z_mQrzG&M`{lL1oH=?I$1ce$W6>WsV$=>3F~e$3P|VuvJ+u5eNo@ZhY0 zTB8ErYc0KQ1>1aSj74~~tGro$(!0BOj|vSZjW;Dh^>uHPz8vNxl73v1Tz(_z8aVMw zuhps3R&Cyd)a~szQq96PQ!(}|w0>r<=k@^m8Dmv;T8BNs0#o3w3lGAf=KJk<51j-$ z&vzSeyCheNUrPiAaSRlH>Z>SsXU(7ngmDvz+~U|LDA1)({FqW$ly9rsH6S$BdIWYG z{L`YIo%DWfRb24T88ge3yHRbm(W zs}Nt^$cg`wliid13SU@n_X9#7!P`#Op2TN~o+~}65UfI%{)msgoXU-y%TT}tKVTS!5MGj6GAzbU;bj|YALZj~$unSL|F`kmwVCzs152O$%ewTo zq%e~o`?PPALPp+Ldc&F&mvopQH~_mz*K4KR0M8u{0qt+x8t&Ig+%<|Ra7#BCbl>3T_(|Y%c6@=K~e$y%U<%Y5t z_vwhF&l^_jGIDUyF-gbWmZ9z{0p6afB!{#K=`4c`P_F$4LnhZ=ky7eOYNl-U#>1cN z!drp@9Q`Ndai#5SpW#LU^H-rz^HzKkyB&bq2b>Zv^E81ub_1``Jh>hJcBe0!auvHX zP0D_z@#W7mYW+*AYq*?992CBj9Y{XDj*`? zULR{P!$RZiulBPUryKf`nU_JUrT~DqBJ}C4j-maND{YCrVfZ)m(WMq!a?E#lg61Od zq99IE@@Q!y1Bha?O1=d4bGtD4j@6_KO8EF4k(co&_lI2ezaGaH6@R)LAC0ynIXd$v z-#dlYwS86nS zb@n(EbF9YQ?`=I^u{e>C^&WKhU=p_6I;eXEUNOXEp&u|CASmWDjqBxW7j=C@VO2S2 z+=~#*a_5bbQy+FS@`LaPs!_2GFEpL#0bkFz{(m?K1l^qb-6n>|`ge;SOit`pygMun z%l0g>-*pcC8nADrR)R&0N0vt_1lu0fq7Qq6Y~EYx%4~cv*Q(1Dv+lFcmQb>4t6UWBb({j~7lyYuPSmk0!$czoiVO!&q> zo#AP$DPuB7*b&)jvUR*3xM}v|2;;HLdoXUC?y>iZfg`op$>zsa0TE4q)BCuVBOwY& z3Ov*r(}gNo#(^6SgG2R>5$jlroF3azOQ!yqQ{ zl45Xb3P*96?5uTi_djUm;NNb=%(8W+B|jre(o&y@yHWt+#B8d+Uboo$Qu%*zr&)V8 zhVxYPbDEQ;!!~kT=2u52NdRuKj9pwK9-&_+$Y50@OaAJQ@eg^D$Xv1L%o35SH#!#lxLC;I?Y z#M2E=^}bl$k3c-~#X@4i7ZQ;)sVM#)6q?Mt+Mv_pVHNx}8XZ_?KNvX(h5=x=@$pa? zY*C}TL;69dZ}-LAs}n_w;i-!xLkn-=GgWi}AwYIZ^X}1#&}!s0d2#0(Kum2L{-=u=h2@39^!I~Jw0JZ_G`*i{BZ+p&rUniP)e22>sn%KT-HwaX;*eB{02oK zTN}9h2knXF@i9ui=RiT9Vd@mX3pSA6FpAKw+s-v#ky4%%CR6IN zSly&SoIS{=Nxdzng2MX&000>Pi`CksZ;;uhQNi<=4~1p1nAEL9JO|xDwfCul#eni z0PPaSl<^%G0mj5nHbut1$I5;$mj18C!K~-L(_058zURUzHLSHh2Oy;c9Qdg!BiRWw z9`|8DM^b6Lb=;=)FU{@N#Y{)Y)SXMO_4?Lolg!{lW`emcKEuewqoQ5G1bGxG`SeY4 zum!aXS+?Sjn(M{T+KqRrK7+tKTn6Pv(IAb!aA;Vntr!>SWB7m{% z7@)TT{rjj{-IW}CtlF$aLt@NAM#eVb4Sd{s2E4}g2k^6YJ=uKYGEtF2921k%c!_A% z4xK;H>RulMvCtoqlt`3N=I-M1z85b?D2YFDTG6Nf7&s7EDQ5@Ru{%0qa~$r-a9GRT z|1^PoEno2Ri%d+x9qz!)=&CLr=#5d(1e0}#Y9QI)*b5Uk=`UN>L3%ZaS!&jz+`Xki%0(*Um zXmMi_tZ+Zy>GG*_D3RNgv*j9oFP#DoqOlwL%_J3{OZ8fExFoGNByIFeb-6?Q*e~VM zbZX~JL_pEn5i>mNqp*-GZU*U&I1P~Axf6luG1GV{wp7zuWYzc(Q)c?-S6;)yN@E%6 zM08v%>xUc=J}wQh@UvsL(DP)E-3@U@Hb;tfpS<}`E^hA5+)G0MQ$cHUQ-m{|d@ z@PXM$GT%38dBRMZY$eo0MR#hb<=3+XXKHL;YQ|aUEosNTHaAwMb*v$oF&>=+WGdUK zS&(ecw9h>Bo_yzdvh8#=FH5T;vm30}a~I)NJB!w?KA5Js(9u3sCC_W>2pDmhN_#d|+ED)5-(IPa!T2$g;-ueq9GPhE zA!*u7L)(*4B)amtAm8*CxXQ2V)g$xhn-t>ID(yhBh-0D%H(y2@IqkZEm`S(4i5AAf zwKg0C-s8Mn##NZaf`@zSFfbuzCp#y02n;XD{^n9}bvSdaOQ3Q?d@PCe4Qriho0E`8 z-P98?o6z9NuvHRmDcK5@Ai z2`0Nng_qF#jK6W2(+`HuA`NbE+k|XO*iKHMqpaxS^wo|rD#VpqwUN4v7QDX^nD1;+KX0QP@Z0VM?AxU zG}4CUdO5i<_Xl#dD`|6&eki#-d!yaFhKek>=fjd{Sn-@_2Vsnqx|Y%X6yfu{m{*l6 zzh3T3HHwM0y9UWJ$HN;vcF78As1#;M#Z0O^e{yH56c8P`x4_tWv+c1asn{yD=eFHv z+uS;QcCQ^Vk1}=6QC}~U;CBrpYTqp@Z>4OKaV~q22HS(|$Hwsq?zTjysl?_TVul~~mxPF}|J zHw#6)zsA_3o-{svfee_qJ2@DKR|?&p_N3ZzwEAXV_n&m>+RqA&O_4o*DA&P9OVA35 z7|V9UI(RX* zYkYG)8e8d0h!o+5lEXh^?R*&`wpKf1b<_fA7-hkUJO<6N&o{er=IZWTtg^?uZw`57 zjgt~XWiq^y;P)!_ElYUNqhsQ{-nOM3p{oFllNHX~waHj8k&#>L7)wU9 zRbwYkycrZN9;Zr=Q5O1G*6Mb$-gdtdAn?}elmE^sxGq~oK@?D|)U7h5uzz)xzFZH`EVhW)vZ!)U*?Fa!;vYp@}5x%3snhMcxk^ zZI~sc_+R<`KB+w527g0aP*9IT!)tX-r_qaCiiIo5$=$T3%L z0@3JGub5PHG|a~x)s+>HWp&EjLhAJ&@8coftPY4P{uk^xjv=$o2avdqaU|Q)+eKG4 zQEFuUAxyon{H0(G4kWtiIgpGQi`!}hoAv#BrznPFX;b&ZA7_OWd_yU*&pfJW zetHrwl$^Lgln{7mAKs6bv__YPfekF6E280XLZVUuE{^0fe^Z{P=Kbx*4TI}4qW^IH zZbu9djH+khVEWQw+2OqFJiwCPp5NwDS$NZxhG#Iw{@(+xP3gDtHyF!y5gZFkvZ=E^ zUT?++XK%mKg?PLp7KAVn&%q*^gUI(a&L)aFSPEjaM9nf z58g>LQWHTk@Sag#S5@d;gg6xVc*_aVN(vq~I{voyt+vhq)}5|CfvJ^gEQ@cY^e$`S zZ~P@ZFM9U0hC9Eak|7p@awrM|7fMQ#0s?_=pbJma8;I3AiiOT|I;^p*)$3Vw`4~)_ z^OD~YjKmX9W|`NBIQ+~tzvmg7NHB$8-ZzlG%K2Aq~T`~@tT`H;U+a#iO zS=qO~MvZlYrj~gtA)?;S@7k7Q|JDK1GNEaW)q~c3kNukK#uKG>G*VZu%tVXVhYliw z5c4M};@K7hd=E_y*dAB)=f#LnTb|Z6HliuxIT@iHan{Dw(&WxLteSVs5xD3%AHXnm zZNP_uJLpejY3ZWOnzL8&iwXw|>$G7G1@=u@F z!%Iyc_6i8^dXFm$`Q3I|e-Gb}P6Gs?mLtx7=|}MlCRxi9>%@+CejWPl?ThBdep*d+ zkfGPpQ z*n!0${l(k}oyKtTD%%AybFX!TWE!HZGTU$2^u@_6ub z1##>`^^bA?;EZfou?NC39@&s9_&SS&VA1|(72kFR|I907NJoc#=47IzPk|&xP^V}( zI;Fy33$gkCmQ>>Zskdkt_Z(%+;0?0CbokA;&WC7{Br!{^g#`=A~9DEpx{IMcY{hwHa`2no=B!d(q%-h2mD6;O-Et zxD_cBmlE7bpalxWg9O(W2_8y|Ly)2^UL1;a^X}~I&i;SDnf%X8=9!%5oLjEaB>*~| z1q31}&#VzC#cX}&a{G(2ZF}R@LFQEMN$m3k__?fpWCyh1G+2y0r)yd~VNtv+kR*U7 zrM~+jJ8#6c)4y}_y;fatqPk(ar^YBjl-}Ips2MZGnKkg>tG1KZ>R6$UK%YNF9WO<35w+vmq`$!OE@9@b%{+wGfG1HN#cigV8UonU-hI=#2*E*!GKgHI2 z^}{!Y_75#s&@30j9kV!1fmg?#NW3^8QTX5~r^sOuK)iImxxL-w8g!+K>m}ihJ?||m zNZ@yga^@$ekRJg302F*_1d?6hyyLeVl)dIlaCu6Rv{o1<`nTn!j>o0<*;CPI8EQ(5 z9hm(SPs>d;Ht1nKsrnv5?RsmS#d;Nrn)TDxr97{FRTSXh!`n8`NkT@Rs8E$thlw$i z80i`Ypyey}D#}~uEvyvpxC$3K3Uj9NyF8!>kvXR7nwTD@JZJgclXXQ0yjviWl+Rpa zi*Rl;eUOpqofXYBi7!p=U>N!Hs7XH3P)K@ZsU=sY4^nijj(eCVNppBc*IneW`i8E# zU2tm&74tYhv^(DKDkwu=7&ScCs>`>eRlsAWt`OtFLCTgXmGI`KUo!y?jE-$ynZ8)S8 zvb}dFX!7)!d(<$CCFH%KlX(OA_W%X8&tMU+sVnNWQ$2{U+p#J*f%=@*K#T0ZjVCs<(CiMM(v#0v)Aq6iBLHuoK0X3)0&h{qgKI+rU2XlY3~H5WsQrWw?g6Wc?YgVk2~+XlwGKNJzv zZ@kETe(G4RrF%kl45G)zu#Q1m3qN~WUqubWE0FoNG-5aI)8lW@fXp(&0mQ+gqz{nOl1|-k-!59H}xmw<75VrO&;}6nK4}4wOp6l|8c{ z5?XV!OJOhZX>SqrUO&YaBdFYkuhN++88iv}DGbD@pvR=KcX@rg_#CL&SEN?!ekZc8 zKd$EX_@UnOv@J$-lMIqc5Oxe!$*%?pcET$$AT>N!V~lV2utefKMR#@2>V8!tfFwe0+svyS|i4nIb8Xfkpr zNvl)4yp5t&`87bn}t*HauInEc6|eJ}ep8_oSyO|w2ojxZmk@C7w8;dxOviMGCK%StWYe=Zab9^j=9p8E@|Z`}`40(o zvwwG#eLh@dfEDaz-?*5(l$)VE194dYQbkLSYh=S!zY;T1O_V(3s|qk+j`-B`Hgo0M zxVP39`?m2naLJ+a%M}Cnq5U`AJqZ(YNQozJvBCft&JQtMkoQkcy~i>RRI z?^nG|*$?%rxOsQHfEM98nVH;&oE3V34~OxTIU;U6woc>i0+{tox-d|Uaf()v1YpLi z+K#;SLrjzjDcO|69#gC+80SU0*1hOWtpBZ$U-M|#$CO9<(kmQk6#J)ndbFQf%U;=J z9xJYRo)fRr`e_V(v88j6a?R%JNF0F|{t&ghs!o_xK7NaZ8;R$Y*mGG*k@rMG4usn} zwfOTgUu1KmS6=kA-HQWryK$S@u-!{*HN}{NTAY%m4?pNtE5jSb4zqtR;Sk^tlS{XT zoQUl_UlczcSPHY8HMefqH59`7i2XaP>v(v&87Uk_r@+q#}Kjw7jOsx~O?M$F1*39H9t+*k2 zY)|FOQwU~8`}#u>VSeP+Q{TE}8r;79tfsrC9QWtM^rURUv3x}~i*_8^hXB=I-Q3cW zZ$-0oA2M#%ZM?shr~HunihT_x{EAN!Kr0x3O+;f+#8uRcMIowaZ6PAH{?l`&8FmM! z6RrPH5_CY7L|C$#z6iq7a6ni`WJPtWSC)yttGAM<<8;-)=x z79kr0sst$XAl%anR_JWjDHmF=hSfgLbS2M;St$KwF+gL@W4P`NfQW)rwU$@Ly0owR z!Bmwa5TNbF@Q>B*$)ibc-V_U~vNxq34x+4>1BQGm%6&PiqP19@n?^Ve!_9Ob`E(qf zC;LQV9#=YK+U@Gd($@mL5l7*39U;;= zk-XIkSGJn$Tnb;$Ot&o*L`3Ar%ucZ6woHYWIAR(sbCaOYHWKO^jP*M+qB)2tN2BJ8 za+%0D$c0BSjd7RN2l@o>EWa%Tu^Y93l75?t8ZT6RGB$NRr=K(+<8{*XS2Vz;P!OT0 z_EO!xIs(SS$L9k4I-Tpudp-(VTTlgv@j^vd#izvNh&0~*EM(%Rzf@f*%Ir6UR$gLu>~hg}J;J}U(qCXoqH{lf?n9v=C6 z^rm0Wxy9MT`Fycve?%|M`_vrUfwtE8TS=VyGG88?3r(X&z(OF9G!Ve`(0y@Y?$1G)38^+xOgbPt>8B58lq^=|5&c;o6`VZAVL}gHK<*6w9 zrkx`dSWj&s^If>wM77PjRcLS0A&0omSjjUNF?2U~KAPeqBBIdNO|atAHChK=x@+5M zemugCYSkr4hdy}Ne|}F!p%8{!B$=iK;;e0XnIv4qgK9TZK}p1(-3u7KR_atb{OjWv zm+>TAv;-wGMb3pOYGWqsPCHV%_KGLu*_4O(TH92kQ{{GL7BthGNRfz4&m@XOY~f=V z&7bZ~R3WpQ#cFp5&qt^fal2=hM ziDq1VQ4a?9F!r=xN-UZj2EE8ts?u84>^h?~b&8cABMUH9rI=dgxXM49+DfI*rSqX)3hJxg^jp943L zj{G`-51*~iIn|zN7JJVKr=2R0VamNZDtGonyT8q>C3*9391^>loYhn`H7}HMeVMeR zBxzZ}Jgl3}aN-Xxx|6IUR-wc@Gz#--?46?2q;yY}K~9{GCt#)-F(fjGJnbJwn#h{O zgtJxq%gknv&VA1`O({%G{1h#et!9S%MWa&%L5Sdh1G~N>J#;04Z~V|Y;(6fqd+xAc z_Dtssa6z%g8rx);<08w}hO#)4LmQ!@B_xMqYR@(;Ptck1TI>IuRxp?H);iU9% z&@@S4&Z6sHCg!5*u@#3vG@S=~iIMV%!~PLb5vW4QKetDhVBA8g2B({#4rI053*J|0 zwg~54;(7RTV?idRMK>oKzD;ENJK`tf9R#t-y*&CXne~}Sb#`Wb%?~n%7{0#&ymj2h zbk9L}+86VqURy)w_YTcLDG`g|y~^+JKYe|}i;J#-=G83zJF!poh_Ak{>GOf8Rf<76 zSHIea*woHa?x0Mf(eArk4`SqVQrE1#KFF0ShDLrk_+%BS>*GA*!Ht?QOYv_PoF$6+ zQaY>?VA1SK{Nrw@p4Vlzzc_$ni7ncLPo(_*%=Xu^WXectTm7ATu-e?j?(+=9k{4(^ zH|bPq-;y4apHKCu(`@=jEGIr1CKvkf4L-MKdUc5~Sem`I4W`~rBz`H@-mKk`#dBBw zmXIeyWLJJ}DT9`iax%9{1y^C@sQ1$c6qW2z+LdE{XS+WNy12(1RK3swhco603!lMQ z^*3ony9uskre{KeZq}HG?q0o-PcWlOnpjv_%n#Rgn+Y>?N?i-lQ=&k@LNe*-mqI85-rc0N)MUUd%E>)w9VT%fL z+~wI5+y!V14=vbfs?U!UAgjJ&_%f2}SZ65m%~B9@T^TAiGM#w&q_uQaeFIBn;I zbKDc3NNJ)2*c0vf-u3H@Q`=PD&ut#w9D&^HR9MMGf3S{FjHwQ?aFQ)M2dq#ri=1ay zhe>I65-nuDY;HQA$HrTp_m~X~fe4kgvc9_0f7fEa*ok+Q87i6m^lxP5%ZP)ekfEEi zHS#O!JZ%yi&+Y_XJKzqgj;DUiBn>~tFzxX(ffM_KlNcs_r=40PW8&EAYPY)2PGLqx z$iWg{Vf>8$P|zPTb2-{SndDG1Dt2}Fl(6VvmQV`Q_4)44<;7ab6!~w}K|RuWI?ynm z0A^>RoW`GgFzR~q3O!792GUcJktsb6k1&0-e7D*On_Y6%nrlR5)^;)=@fifmwd~QQ zh}Vuw7#(QzoObneX7*`r7@c**!5?C4Q98hkR zVnhk{cKh2(M$C=su1*{i#S_d401_-e;&S#<{}^CmM2y-CshQ4*VO7m#+Y&Hp%=bO;}TUT1RaU-X0L>rWY!uMLj_F2>xhABAQ--I`kpB^ z#};sBltJJ=D=X=XBEob90$u`1%vTl@f_5uurG=9RrjUuo;@0(th@oe*cmgZ&0d@MHM zXgCn-Bv?T#IPqMBjJ>Jr^hAM-!d}ry%34jK(|bHo1vg&8_8P>vWrh>7XYXp-Fm|P?H+h{1to2 z6Oc2X(estbbRRp*|4#bt|3B$^oNkR;hq1zjdBQU))>=Wp{%Tt z4$w#kJUxqS{D;B+&aeSLW<^Sa9Z+NLZV`9&WGl;!grPqWoS2wq@6>tAL$-e;P)!5R z6_r}TO`dMYREifKc#sq3Es|(W^d6^KBA4`)@-xyw4$FNB-UVF9Ks%?Qa|N=z+7$e zu%T01o^)LRq3fb8y_TDRpv8LJicJE;G_j1j<(+*6Xw3c+;@E&i>DsqhsM zbxN`9!r#?;lq|eVVe2BpQX!dGyi*J*e$-RAPkr+|0ZDAfwIi2p?qh-q)CgwQw5#!m zPU*p@01XIR19R_N-ci-T6<9pM!!WN#m=95S&1wx1D~*8eavC7j|C zRDM+ZFnmY+491pavVWf0!t3_)%kNailf0FW?K6g(^v%#Uhd%_=p&&vlD);)Y&H2ib!((RR4k zX+Hpdj6gi1x8!t13F<+P)hjNXNuE1R?psT0QDC?=f-+3wvuT=|)B9zIH9+W9ajNSV zBa}=tUqaAH8!gNxMY+@eblcQ=xl9hCa+OG;Pc9a9k*Tg6tuV(u@0O^r0h^SYOsl@k zhgSg27yam7I6GlAI3Pz6;CyCTd|xAqbBaBnw{npcvl(A{a9iDMe4H38JrL4Qgl4s( zyJ-<4(uey(Tk5S4V?hw)GKnP5bi`)^7LHq14*Bm zwK)&R?+Rr3My1?2k3SAigabz_I79QDM_7cXMH36vIu7USf|}h{>f0AW$kE(kwD0l% za)&=E=P5r9!caOM{?Gk8sFH!LeyN@5<|F(fY=@>ak5c54!in-(-%LxkgR`ofGy^4c zoPT*Wm4}Upf%pJ5wsJE@;XWDss^}TP= zcw;TxLnf9K`-$#QhLpxK!veP&oSU->6yjM5l@`y61W4FKdX)HQY)Q1?|jmOh9;=-_CcQJjXgG@W8}iYGx2Xaws$h-G9|HoVz8Jm zI$T~5u}$0xt+WNLT>is2o%dLu`iH^ux9jvDM!yU?z=vzsy)WVY_v_!Kbl%m9-*+m) zv<11fqyI28S=*?gT*xUgqUcQ=763@2CTw9Oal%;`ZNcllHudXlTXfN~%9S>_m8SaJ zzh8+51L=7g7dsbf2I+wl@i@%qHX5i1HU$oeI5od+w&vEnJQBO_{xT9&Om@ncgoZSw zq1}&5x*uf&UpSs#Qkd46BUxrA?u33dSa>E6y~O|W-$0krr>~zm@W8`esEK? z%!KkVkgY-gVPLd)*3kurt>~9}I60k1C?1(1=td4Sa|_Mr zerMI@lk4wY>-hTZQ(xD0&F`wXdxecExa@lGq&XfNqjtlIG~>83(jCZBi(NJYLV7|B zo1ceqG+lEn&nsg;Mvv=wFjwFk1l89HTnd^eXx!mO-Qjz&9C|OoEObyGkVo34!4g8= zHGY9Yn+sXaGz$7JfMRdnw8(V?KTS`CxIrF&F9Pp?U2si)@G`^ zZBo7?f*|o-IMiLPSD6Jb_1yv#%FWbU{QOttxeQy|d1s2Z$mUAiR@DpJ{U?H%EnQ>W z&ZY}ip|s@R`R!XaTvW;o4)dU0O_E$DM2 zer>6&Iulu|ZR`QZHQT)n$$pm?PRG8@=npd-?7jM)|HjiCtejq#(d4w}Nm4`KmjkTF z#BFXn^g{09@-@lUW)kuFLe|IrJR5be?FpC0cHHM#^=!Y0Blh@VY}z)>!~ZTi^Lc?- zqvyf%q@va8kIR%1l}xtd*AjKf9wg&T3FL=npBxuRBif(l@VY5$$Nw#~QNlF7SN(@U zBYnL4_rA8Vli$U8#Aj53^ebY}f^nK4-)we-wPehdno4uSr_NhyF+v+xh>8ryB<7*vWgu2fg9c#OKvTKsQ0 zo6qh|C>_3cAw4?MyHUqYXgiVD3rRe~Qr1M4BT4mK9w*-rD`S|%gtz^c!K~-wOO$oC_AR{-nX4-o5RXwNDskBEWPYQFzMP72 z$$fD=VXdh67+M%34AoaL?gWWUb@h>Dm|HNNU_v2Je{yoV7GWj-rEW(u{egGGj1f;t z&jlP@sr>4CFZ9YYI9X=f@37M!k&CZOXX}bpr9)m%#_%KqiQs*pNA#tVcV{G}Q{B`}Op3}@j zBR~1kVsm7Hj!EB6TCF`N)>|dh^X_cy6w}-Bqr+a1pDmxmdxJjnzvZ(P+pF|L=UB;n zZjw&wkgJI>Er$TOsnF(q#`e@@(1V_l$lx6|3ZN?H;&|`QM6(CoWG`7FHNbN+{PU=b zTI5}j=xPp0y0!ZzhBd$5l~bC+q=f{((2Vhf(q_fibGjZLYEe+TM?UMkicnZ}PxIjF zJY3qB@XvuCjb0y2sZ#J%7=Fnx68;pu)$<{pKZ|?ySI^ZTsPM?^!-f^J6X^Ka8-p(- zcVXD7HsW%Xvi0ny%{W2vNM?5Wsdnvl;@w_5wt`b5&uJ7P;e7K;p-RSZkIMaUmoPBogtPuge2@)KY$oo*4I z%<67-HqSOjmt#79%(xZF&;p&rj`uYgeo<-+SK%Xt*tc6@Qc&tU`%*4 znaNo&y4V9QPSQVDCZ)x z#nyMJX$a0Xd11*r!q>rQIzbA8ck@tt`zNa}5fDnp-v|8M;Y1YC{XcOB^-wr}eE5f< zCQrFmxMN{A;kD&^r6AP$`#SWbG2BG{TRFwVq`|dHO2Aln&$q9fS88jSO(=u_~6~?mtC{eH1Mdr2AWbx;DtU09ahKKp|;ZpS>1=062jtXSnJFgHAHJ zoYStpd~v6G2?~oYu>LiGe+a)w-PipNzrR)hGxzm z(f+OM47#cxD698?YCoIdAGA;=Rtv=tPz#GB_nKQLV`k;}tn0&8sqxp1;;;cnWOXmS1h z-!hJCAe_7Iut9t`{xd_x_i2au82f)1wwP!Zd7W9|n62lR8LFJ+MG>Txe=J*tK3nj777%Bd-K$XV1X-+}2$_^2% za%-q+DXxIXJY42*21 zGOD{~mF}P-iNZ6f=WexzHQpdpQ0PC5B3GN#x9xAd z5)M}`Qz%OY@F5u!~uheqhPlQ5NeP94D${Chv zK9&w*a#~T{oYpXRAYL~+y)%q{p~s`T4462AQk%(X~;XSt=O2*7A?TrmU{9brWmua%vwz}_ARTDgk#*QLV!AnG_sHmg&Li)r1k^l8`qlYYjBHK(w5>dYtI=JZf+rf)BJ0vYp7l6y_aW1SXk z(zP}n!FIe(8uvgYzFo%_U_8B~N8VXj#X-Sxt`H+HB|QjF!9Lk?n&(KqERO>3{Ueq( zgk@XY>2xiK?Ht=dKc&d!4ulS9L{5{jD`F6WDc*ob%&?RowLPW)<)+LYG7%Q>2?Yz_vzwkL7>u6k!dr>0WE za>ULz1s~Sgq*q?6#dFihNp1abpF=dW-e&$VKDRcxy*G=x0MwP$*jE_3nft!#3)Pz` zkG8fDRv0D017E14JQ%P%@56iI87Fdq7huoQa(uYw7UW4*!9&3SU{eN|N%naEt;S5^ zsQX!K>q{KNp`O^f+pAJga6e+U`^9XXPr^`IHB z1Cv7Zgv)Plg12>bnKsCJX}X9OW(t}-gCC7eFDp7Sp_YT7d>T-tL~VS}WV+H6F5aBA;PX2F|bc{poQZNAqMTZ=*S zW0%|2rjd&W1_DP!WK9~5urm)~n?yGI!Y6t2zhIleLDch3R7M>9DZ0Qpa`6*GzrY6P zSIA5a6z~3?sDC;v*jp*;EV(~qi!2b@bByb`;SHLS@-n%a*UsHc{!UOa5~@P`+5G+7 z+o$oa>=hZ5D#g6JUz>t-t^9xTdmaY=(e^SO-L#R+_z)QH402z#(RS3I2jZ)SsVYP& zz7~>{?aF z{!P5+L`Nu9u}#$12|DvbOUXvQ^u}%ekK89@!cRRDJ7P~5SE2B>FFvk68!zsC-kY>; zxmWTPw7;)0Ove0_O!&lptZlTIP4pGt(~~ugc}=0+k<+xXzKuiYSclDX+KmZkKC47x1LLZDz+GhOLL5Zw@_|cj*%ujX4lnj1-Du+o^FxrDlv)i3%E!;a=F1I0391F zr^@)DIk3Rx6sN{AG0WE&}e(=^@bwK+@IRI zjg1*tIu5IoZ+<`MS(5TL7fU`TWeoP=qv!Ktf0wK4e7<#E)Jm8g`JtQ1Xc&)KuVgnJ zpZ+T^f+`fbt8)&AJ~?UQyJQV>T~?QD(|QW;2Ttk=dv-#6W ze0mmsEZ4g1?$tr**G8jcO?B-u3>U8Pvg7xQIV?5pp*l2A2CzsJjy6POSut>!ka*KLM&i zC7EPrY{Gx?$wIaB-6Z0_{mn0{gm2;d(P*^F~{ z`1`z#5w|TD-EW$}GV4N-vBo@qphM&&&Oq^6h#&xM^4V&kG54kNWW}ji!t;W=^-J*k zk@h>CGKb`70R0$41EXnaX|tPM_a5x=y^^VkDQvqy9O+I7BnAShE~|n>BJonlDEm^7 zHdjH5F6(tJ^GZoUdH@hg?Q4cHUSABg5vgJ0UFEMd;G!?OT6;C1z^^>uz#85Itgd$_aw3@0| z`CDd?{+Zxh#7ev4p3NcQi(}>Zc+);TfFA|oRAiADpr+~4e<;_vkS)?l^lflVfiZt* zrOw*gAdG45u~qH-THKGJKV@n~nF8P^KZItkx1D(gRHSX7@@8K0X~@?O6<0c7DFcBY zl+^1=gvDej(EvfB3|txlTeGEG>9Sj!wzcsfaVGkz!G`hyL#$`!z=2X?X>DM%zb~TZQ_r{7*4MlnVv~YN{pts{Mj$PrXk;})FkwEWz)5xtU|O)_=9iin0ry;lDL`z}}A8FS|pl0QrVH@vv@ z68d_mb5v(ILA)XY8u5@djEBexpLj9l!XV)YuhGj3>VAo{#CO4$?Qj0JFmT9WDb0?# z29gK{95MsQ5ZX_y@6{Tc4%|pzHz_T%CWVs3U_SIm8Qf9oVR10GAavX73VZgw1>jP( z$2w;Ebf$*d7t`-C5lh0VVoYDkaVf<9a4>dob0_Q4cpN`$JO!2Htsy8c3(abT{hw`u zh^b6U<%`!sTUQ?X6-w-t1IoQV=C?_Nes~^9NwwtKFuNr7(xQ2xUC(2Qeg5)DSZ+LY z1mQ~K72jqR2!}&_M4~r&0bc8nu8h{ zmSLYMR4oR1xP zw$_ZjpU~sq5LTZ4A_JRKKzO$L9cVm+_mh-($ZaH;?Rw4>2`Av#m) zj`MD0(?5;xEt?n0^Iou5w!m}IFH+IaSY?=DsxOKt6Npd&BGszpEzd=9T@^^0{ZQ@a zJsXc!2AOS5fvLjwD)anfO7i_0FJdb}vC%wCF#$|rrZn=oF-Guqt^e=>7&}8*K=J?p zs~uUjT-(EX>ov6yI-M@D>kQMGwN;eyw#&_?^mW80?SL|=No|5c9^nl$tA$-6ck8e1 zuPZntsMHlw>vCY-n1Js_v;26HbdZ>6?p=V3)Gu)Hy3v1$srvt$4ertGTBmOBA|a#| zbL93R?oPh1U}=2$FtvPXHe?SBVQ$p&LMxsw5hO)DDpQa@{2HQ~-e! zizmV2MS!S^C$}-iADarfN+eRn{jTM8OWUyB==@@3IHvc?(3UmDfc%vOj_liCoxv7; zDSel5#Vh())N(%(t8BKrhgq94=hRO4Wn(eR2V5Ff+M8vU z+h&_q~@~7)s%}@oOxY7!e+un^b%hDG25T%AI1?r!RKJ)uKAex1fr-gNlcqL zNXco`LYP-3^0kXlTW@N0=+}7@)+WJnT{8E+SG@?`7NJPo*5b*Z?}?5IKc0OH zeU$&pc*~@`Oyfr6Mp9Q(7*53*3G*XLR<4TSkf|a{ZYid63RdmvZw)TGZisPM$}inr z8+jFTF7N`$G?B+T`lNAC3@;8wv`A=hjcaC;KFTEa&0z9~Aptkig|WlSBUvRcJ2t07*8nZ4kxG%|8nfTDq+toV zpIO|KES{2ZCYO5~${A2A3EQMROP10}`amI~i*{jm9=2&SDTt}_WSUGwnik~gV(SZm zdrGV#Ewr;dqX&k{p>MN29fB#UeIDYI8{EIp5FP!^P1z?ZRQ{VvY=-=uabYsrKmSST8m#D!TF9AE(KRtIf&3aB?_5EJabe7Ip@o zY{ha|(M|}~b0_l)Qb`qD0Vwl%l*kPP=;(@fHq|g4;;N!5kHX#vcSqkal-73A6y(jq zrDy=XRyJB5J!2|lEb>c-)+&i(8h&RSzbDJKh=vdQehf8>fFIdM@>DxKu21=ds%)Oa zlrF-3j1DMUd)h1{2nz{Abs4x0YBxj*n@M~gc(-Eweov?h2XP{bOo!fVJB0_AVDe3b zf3AsMd{mU8C*23U4owgo8gU)=fjbJW-m@w+BNpPnpoczfE|NY#<>F zbg~j3-tZO<7sHF+ZptfINlkh)XUOQ*hPz+#Q4mP5f@QSN6J0dGMJ{T>hnBHf#e6{o zc}x{T9*`&SXAZvB{}1FCJd@pW_~uN`h?c`fG-4EFM=+^tj+13NDdW@V%eze+ugQDBEIvn=gM#n z_NLCTBe0utC(|79Y&=tIUW8w~PdUyxsq!C2$wNN8y;pThLYGZU>x#P7>BpEMY`p=l zOUyi%N{ej+($vADi|^h$(zcgpVt(G>yzw$TYgJyZy=c^OF~=&;B>AP+j;F3V1Tw<& zvixT)Bl(m)`KK|rY5DSgtl6)mG{JaY>fYo-COIyT&}UPQHpfF4aL)!hx+goe67vCu zj(i~((!I=_pD3ojl23G}3&1-AAmil_SmXGQvsY5ll2Z|iHa#u0>-D_W$$>!wpw0~3?IV?qc6?kY{emauf#+-LG>O;cl zt#u32?9AO6r?3$Cq~O2UrdTimCjXhhsS;O)W>~lU_m8^`qUgjLRou9f0?BFdu*j=> zvBKIc-+a+QYM$8v8U`R)m^ZHrSK>a`9a3>B`kkL9W>4y=5he&>szG@M$TZy6kV=cV z*%On!?|XlO&~4R;PP|S(4a~f4D}wxvd9-xJuo+j_5>6o8b&aAL!L-?ou$>wW7J%u0 zO58?;IEsxjEzH9&;L7 z0wi^nY!j*#x%u~RW%~KiTBNu1lb0n0-`SNnF{T9z#Eo z9uoNO9b#m-*-~mHLWo=+wu5^ za|;f`LtHXezBpB=Ajq}oLGmu-2zfbv-Xi+=>MY(fZEMtEfK5JDB>_;pA2!YIj_<)9 zpPF+W^OoB_rius;_?{t8)+%nP(-?FnAu5$3Zxeq}mf4|WH$T-nX~dUq{3et6wO&n# zu;-Y{-%?lKx=&ll@sZE9dabFNwEU^`F>_6d&P06GB=Hhs)8FJXSHJ~-?Een^QU)7V zCxcXX{n6xHs{3oU&yOJF(5rq-=a7?$E^hU=_SIKf1?^I|z$EM#JA^L+7L%C`UU68M z@wR`$h4a%23zm}_pv`OOGL8pFn@L3SFe z5HL~JVjp_5p69h1p-P37A1C7tI(OzMP%kJg5h}BB#>c6<(yTFtJIeQqX9Q8u6(>#} z14r&qsK=zCtA`-RC9CV3QEV9IW7BcHJ+Y#UU^Hm;?L?3gVi~XQ0uB` zn>S|is}(Iz2Bi`B{v9V`09*zYp{#?WKi&)DWm1Xu=%yr2gw93kkVp~_3y&2*g_A%# z)(kd`_mfCQx7`Lk6vd-V*6-XtZX;Y-6PWg*vxZ_NI zE-n%H^PYj3NBhb@A#1$}+9gxw=t7>``GBIc}f&ubJ?Vyb;1#jO&$>w zyX+b|=jF9fKFu>BSE>2(RHD~=%XnI%;I>gF^0bj81Q2oHGqrwGTecR zbi%Z#rJR-Dkyan@lnj}JyjM|qhx}H(^lUw699ZjJ&tnYP^j_8+ocK#qhl_6eiFo$m zKIIWg)DH}_1Xp44=4A?Z!_(YaQv?B0Y*JY~XnY&A2mnxcoj4zuJNdNq@wZb-RsKT( zUe{UFuQ`U(M=5{;WLNHEL`Z5_tn=df4P$Z4Qb#(yHI4mg?(5v1N8NJX6Ur(xb_KPG zlvtib2pw@x(DrR&40Laoq4-4RrFZB*jGF`TlVATZavtQ+GUZP+Aw0HW_2H3p9ZE8f zd~193l4O~$55#NQz;=hoKoNRo@47-06i=U$l8LYze_U-$Km+fWAt{fis}>;ox3Z1P z{MA3~>E(+$_?1&wmF0YTKL3=PkyEoc*a_g1=RB?bh00oz{Lq^97zTAe&1hRcI|2R2 z(%ClxD#BrLM9b}M?gh~Mld<5F^vUq%w3PqF+FO1_^}c_+w3N~?NY~IY@S&s|Vd!oc zx=TP(Kw{{Q0VDp+dH|JX0F_cH1*F3>zq8hPaGrl3?LXk&Yw!EI-tjU-MM-yg zm_erJxc9^Aj0rVgvn)G-b0@IfmPlqpec!JM3}FS#ep(w*0!KDj8IOhr&JTyto?z&| z?Pe&=^TxYzmXyff-m=RLIg*5eaCe@d}qCYzsYtOk=W)==Ae4V-p3yU!$Q3gGp*xcD{Yf24{l)&wVQ}C zn~>z*d05dC>V1f+W?M7$4CWxeGIJs^LN5o%A;VRJnH`gs5dS*^=>NC+6u+sy-Z@k5 zPq~Ixb&2FFh>gEKftlr!wk(Gx%m>G=4~~g3@nfd|S&2Jt05QA*KBasC-4W+_@rdV# zuMZ`ZAo(x811g*JdG6vBh}n~bq(yd<<+7eLAEHgJgxK>?wnF~qd)8wM>b4(^dzR)7 z^0Cd{pOet@N&z)=)tp+T*zC36;BE|L7E!l{GS-NBNaLAA*1unV;n@xx2sWh-3u8M_ zC{@a~ADoVHI_&E(kT>1iE|t>N=AsnX-wBY(8*6(McxTmS&P-tMKR@8V)R7|74n zM3;_u-P`Ip9o=(T*L>^9oT(gOt@GvP1oXOLrzA(dBL4IhOjPMILQi?g<&#ADi}Ll; zqz=#{pT&RYuhx{B(3Db#@3jUTOlO!-1`&BY{9tCS=RE*^Jk)$&&l5e z%8wfMCfU++Eb?saz@r8k_+oreHlYSeLi+6v6<6DhS8d_JO%d*qPy1-8OgoKQ6G`|- z%*Qm7h!l&%u9!Ii{>Y?Uu-c^w?nXTy@-LE^y8<@s#Udo%tm-OkI ze!!p6@xJb3}MNi#q?TWz{-|Gt&LZNKWoHoyBwGu~WAdljPO z=H*4I+8*XaT1qkBUvX@PbuS&6geN)>{&FVe9W#&?y{&Pzb*W3At%Uo zg5bTleF0!sST`SuftH?okM4yi9o<>&FaVM*1T>bNd}ND$tnuSAm8ng!8aKM&(G4@a zz*$=9OkNd3R}{9bpN!l*eX4!dBVgF#B(!P4e(c{5<9fTycQLZWEhp#x4=Vxm_Iqlv zscD*k3*R`HM(Sw#OzK|fGU`S9-47lsUTbS&!$hv}35(cL18&hiO#*5SE@9aE-GsY> zv(@MgUtlq0+=rVyH5gyFP5J%y@2MAUDNZc6oUT}WtVz*v+~sMG?XQ31q13m(%B(o; z+H_mr4~TCRY!Kx8eAqKCA*ex(EPv*ICLZ)NDPg(>OAf5z%2c*WC+sW09MBPI>xyEJ_PdRRxCo;21bQuP7qv!nG>e4tjhYCkD^ZOhJe?rjwIo2Lt;WBAAj~9g* zw-OL5IQ1CjO6_ua{grk^;_3E2y7lBXrFCKQ;(o3KZy~6i#`-VCio;nz|5aN)3p!u- zN<1)_wUVCG;z?F3Er{XWRqgi4Halb>d5VXSQ>2e@=y_V!IZtT}r5NKp1rC*1&$ayi z-lh~|`q%Zl?BsSuf!X6*QhPN4_kva1Dnn#Sp;LW|c6hsL8giO(cpmM_<=c_J`2=yslUyi7s z%O6uKugo`$A{D{BVMH`@YzD_fT)EK^jT|3DC1vMZU0nuCx<%UjOPNugRKltyB!aR`hevoCuOd-fS0 zN12P$0BAfzML63#&|mk7lq+a+a;<{@IA^w(<(bDorB){NwnFq^FdP5L5Kzt!;E|X- z;SwTYd%PZ6+dgb2Oy=7(O=4hPk#Z4t>6Dc#5Qd_UAl2>eSFn^6x*w0d z6}IaHHg>(S{%EFmL@3<@i-xcD<9CA34+grd+V1mV0ZCgLrR)&=5_j{C{3!FjJn;v zQpbit5Lzh2)F{AeW^>HRf6s~r@oQYlJEXHS6IVK@t0#KDq1ReAY3OgMUcb)<8nD5V zg&_E|216KD$e*vQbZ*hgmeX|A?AKp@0#eiu19ey5z4` zV!Syu?~fYQRoK!@WlLI}--6{t$(7~gGg>LX^tf?)FQlI#aY^LQOKIOVec3G27etWh zG5(xr(zJNMKg}J;&EsN<@wVcHf|Y_CbE{ELUd@TY{ntpYc!Dd{HDQ*WX>Wahq1{=gW z#m-Af8H;%RW6Ek2*|T1pF@{cTAO9F`-ZQDmy0&CS>1_SCV$m08iEvMX0#Qg^XA=)>-_L9xAn^4^$Xqm{&+KIX3dtlo0YxoPjW6~A@0V_*6N@Y}s zRs9^<9VatUXM17*6rbt+yCGHS%s9L=aCi++O^a~1a0C-1RL#;us?IgZNV=>uXl+{6 z_dip$uZbsO6B&;oP0gJ|C9Sc+Vx?f@lzGiAT&b`0V19UURg&WPIz1!&a5VT zC;ZV%mL%1chv(=!(4Z6)c5~;5u<;20fWuIX?fX*C9=CN~>K0hJ^~~LxhJQvQnkr=VFo<+kgT{3ENWVdh#ORDMB*=k8}2;;r3W$kK% zeOQ~b7{;DQMa76AAzU{xDOD_&LW;a%$WfZLD_Cb7eawRJ>M(*L7 zfAr0ZK@}g&9RAiMzq;fD#KQ7Kt6shcYn+(L+!*XsVArZsX~+)FduU`y_kD64?E6*h zxYzG#krab7tlbktnbfctlf`w)LB`3GAPr0C_!btD5$Rsj5ypK}kd4T<%CP(NOvd;2 zA6C?3F3o(1!a^CUH)#9y-^=~*3kHJjX6w3)+PkY`V3*|#xAdG8ew`y@7KPqWDn=5W zN2+?%?exM&JwFKM)F0e19?}6lYki#S4BT`? z+y1mlp)KPpE9fzh{o^m(W?7%vjT(qH%IrVV8 z6P&P+qz?L7Xur;J|D}VZE|Ki&6IBuLJGqUg*h0;XJDAb|o^JpuV*gGLV7RM&7^nb|RDrD-qfvjjtJ2fsL)R7w14av)fYtCKgByp*D;Q~pG ztVI-u=JVcq7VAW4nP(^3ubV9P?Au!4fWcjHE7o@R+4Ly1k603WARRJSDLLQJrVoQ` zwG#8TKa(-?Z~lOA2_n83fmKAfwQ)FSq+ltJ0lg%Cs>TdmSj0_fw!4;%cgx)&5Kp01 zneX8~0$#4}%k!UHSL6)bXCpPl@w%2poIg2GuSnzcD~fz?d4BALTKJQDb#gcld^fsg zkb{D>{%jo=RQ2f%{!05)`^c-kuS?xoM9U`NaMfCU559a#yN@oF8Fy`aI=O$j$@n@C zAymKMQee5`54{ZWUnL+U#Jl2sPx5=2E2+vQLc_?@=L%A9V(LlfQsPwSaE1j;(A13Y zZfu4Ogs1=nkNL@k>*Iweu|}6vCavh4f7Cm=`Z|DKgG(iO;+-hPb8D6_hlv+2NXb#4 zKbcgS_7}XMlO7lk!>Tn?9M0FSQ}c*TjS*vB@@9!=PT?QQGHjC4pZY&h=%!qE;C_)h z>&X8V{bkYRH;oJlSq*`z%wF5#YmV>z1s%|%N$Bx#WJ!9jjH@&ZO;67~8|~aMK*t{n zXkcUd_SBz5q7lOehtS$<9T0Gn!fdNF0`+o50R!l+qTLh0p2YUX-qVxhN3`LXmS=dl zrZ`Z$-2(>XaltAAifT)3Y|(i1Ax`tq7R8VRk6FGo%LAIt%PtA;9i76Pi*xbgwJAJe z`^XPAwYkHMv^HNEOo;!UcKNjsuk0ru-rC`nGhD4>Xo-VluS3ly(t!{Hw89Y~Olq)mQ&Y{3z~sFmio>Vd?_*?eEj0PBg@r zi(aM>f$NsH3E9S;0`@sAy8tLn6wQZlAMy4_2AQl08LA?*4&+?CP=K|>CcPotQ!35` z();x->)-J~k-6WGXOq8C?(;m@$W{De;Infq%vZdG6*`TV_iHYw-;N%?TPT|F zUbi#IG(p2H__d;y693YM+Se_b|IKhhAsKU2HJxgLe)@mCk=auD2=C}FN!uWJ1rp0` zOBu1KG+k|J@+aD921}?d9ZZ)fU5G9k{vDce>D3+id->@oL59}$U^!WvywphL4Ssq>xAK*8X>2ZioK zEX++SY9NInX30-{3?HIq@=6|EAGG2)(L^@e(y~>?CVK6 z_brHzT-_axu1izyFcIuOQxK865VA0P(Ypeg^!61KCGmc)xh~V`?eOreAA_vOZ{gyC z`}UTCEGOYCeFBzO&qx@O$IM3Ro;9BZB^Zu#?sAo2aG?M7+`mlT{KSllqr&;h=Gaj% z+ebs#PWS@f`y@8GjaP-T?6U)qGufOID@VS1g7J+kw$|S=Y~AmSCz8S2_2lC!(s*|k zK=G+^N`!vR$hKTMtqcbr_HHUZge`&h1CetAwJa?&ED*q^mElx#C^#K2F4Pp;$ z1bKAG&ppD6jaLa_i5fr+rfu`J?#-@JbT~I%L67a6q*#%U{5ylj_2U;U9$I)|7`A!Zzqw`W#nS6mh zR%=>Th9|tCvps4R-DF&;lW!~ja})Q8VN9D+_MTk(OF{z8t92n={~~7RI?51Joap#F zt@k6-$)OY)b23^Q`fV3S+gY|<#*22B#aIq5-CR^phQR=$V2-4B`safheZ_xPmcOFu zX!_6L!boZFdQg~fL9^$G^SOURGMrCq^!@3t8oPiYVANS(Z^0kk`B~>n+W-RXwVcUt zeqywwy7h8g%8f>No6X2n{Ov80G;wH_3|aWDr8AykHufxoflrN%Ezs7*7W0$%fk zw+FuFW3BtUb9Mp2Da4mczBpC>ko7mM{#TNWKG@Bl+!G|!isR&Qe9LeRzPH@D|7gL0 z8?pQA*+nyqZ-ok{)Ab83o{ss%NMrP=V9V*m49<&Snp@ZZ^*v~1f2H^;&zI|_%Kvwm z*&yP1i!Bx58s0^+cuy=>(aohGoOm?)j?THw=oCq~0>^JyqOm(?v0mQLKm2P$jFnv| z`V*gn0+r{h6i4Uc_v{#ijZ51&+m~0L4Dz%JFf$kD5zOM`Jin&rVd*ucn0cnLPfK9; zeK{$5#0XvJQK-c^YN9q2&HxhdkJ?`bt15|1Yfg6GL6cpt7KKj1--{TwN$-F$;D7F#Z#d4A^v@@SBO-9CY-hTOOw_psn&TQzrQkjGQ6l?m=u?k z_%w&Yq3zAZ}A^3Q*Yj$TRcr!iGvJykKaFDFJIoie%ODbtJL+log@6=l8$+D z#nA-Qr9w5V9;$SEZK?*7+E(ZQBh6zU+eHRZhg4@C)|lHhmGR0l#Xl^Sz6NlCn$tmh z-F@Iuz>n3ee^^rAfQ#p+RCjvw=1YBo>FSPjffPa< zkK#Jkk<-i)IdQ=wg{Nn}8$Zk?XDDmjUfkld&-Vaix;%eI%lp%X6@LU#7ds>z`o@(C z2U|W>p_H9dix{t|PaE`6a!alw9F&GWD*s(RDa>H$wR#05k*g2HG@L*no;=od3s}}K zhfyPYO|KCy&h@>6dlLvh(UHlgH=a+NMzo~Fz|&+2)o|t(~ZsiiD2-RM)S7ucf_g^qi*h9bhiHS`2^57?Yon6cO zp5GEv`BN443RTp`XVEIKv)|NIMo-9g*wkp~oMl)B5TKMvzCl>Hc zjkCJL>HRzVsyexjwH%iI35D;>QDGUlRClVLFHgr5Y}v;Z6DoB2@JT$Xa`J?ae@^|w z!t{JVA1X=i_k;Mm5tM#>&3R`0JpylIo8_T^n6=Qt=nTj;_K^dn^B=jYD;TtxnZfr< zbx^)+3p@}}9|PcP_tzds7W;=q#@nphev>h%mTtL(#GB4ved^gQc;0~!ublXXka)4T zS8sX1W)E2>0J09$mICT1c_^s>S-ji-hev1{?P+B&OxzDo;kQi-P_W#qzLI|DRH03H zS2z_@T28@f?N1@r=o$RmYwPy6ae*&cjL3x;AOIG$S}GIyGOk21kWo25g8cIG3v3pYzAqu_UZ3Ndnh14;wre7N-BrTQwIT2kn2c-tG~_f6+0S%1VDg`_6R z1!u4u%parlZamUl3Zqh%6Z?gX-P)U~3jpim42nghD*J7_&4 zGqSnP{JAYz$BE1WThu-Upiilq@0>GGdwST@=4Xzt?D;r>L#j z6QzF7>*|I$bdG*~3(2ddYqo*#1?$X_R1IeG7V9f|W2_(rR|m|T zVZLeMJppHWJ5=SmACqEaWZ&chO>Wk#g?5x_$HkaO5^~GAHg$w)75lC@u`<7ijGZwZRF^0q{y-*IX zlW#NL#q4+DJHA#sKPStDIgb=0rK9U#wz2=iGKRO4wLvHTo81W%m?t^*O8<(MzJnBr zgJ7iVpy@ENt^i>CE-ek(fezd_sQ7)b+>=)u zj4WL!=yF#xY_MEX4K|P;vwa+V=Sf5y_E%qxcy4vWyu{~;-!aof){F8v|DPx>ZX!>J z@x4tZk==smGc4+INc~+y6R@jOsVU`aU)0GNy0e|0>4*JE`+@sTB84tb*t#A-TEw*- zS>#02Xx7RupD#_$HH8$;1a5sY`w?E$^u)M(X|WH2z)G=?Af4eCc|R7*f@ro8z|UnQ zRn$7)$lZ0@b#n%pH>{D0w+BuC`GNOBS6RUz;*BgNbW-udy0aih63=mSjU9JJ=Y5pX z%AxiVdsk%yS&hl@P2nqW?KPzzc?@{6^DY7pX?ge~ct`S?=%W>9%HpA5;jfwH9u7#R zgngb+Yvm;wUXOVhXw`OZkCD3fbCdOIYJ)WWQ4ZBVN=<3v@ zfSMd+Oqkpg!gI8#f3Q}aIlDPh`U@UPTI29GX@0rWEzkNQX+0a#-E6?^&`JbuwJ-Th zJNci0=vCg#N&K;GNZwdYYQ&@TOE8EBQ6riN?=ZFOIySh@8=r$Z9xz zYVTAgk;9ieEv4sWORg!{vqsP$lwS4WVYP!SV8bN#yHZE%lvnA0110~k6lJU?`-&Lo z(-7UF^hbyRk>*&l6K>9N9te;ts1fZXz|Ote3Z;BJYK-!Fu-QR)3;))ot@qhoRp8L- z|Iyl%_~MOoVsmxJk+p{9oX~3vuzCOY#0eh-<}I`-|6RL9vwxu*E*s>xIj(-I6Yv=p z*1FH({H1@}Dp)4<)9FQu@BSrlbl^N2T^#q>`J7Q#ojzfb(GFVH8@VTt!~5f6Wa!E% z4yH6pAG=}NFCIN@M29&qI&U9~ccc!vw+6p>bBalxr6ftQ{yGRGOv=oDe?#K2Ez&p7 z;=TCLosEP(cTOB$nVt86N&HEvIS| zka2+z4xjOxrg*vC4`r?298*BumsgoW-fkOce+#~uF=nmh4M^-LuIR70<))=fk?}Zw zfhYJwe1=}Hgv&EO|GfS&0r$U=8_TY?!!OnnR0B%!76XMuUlBGX z`^jb2ZqqCbIm`AHR1}WdjqOO5@BG8+Z@hb(Hd!oRyZqFEH!AKny(2*#pz*BP%Sw|= zuFw44gRgLpN!sRh>Q5Q>nL_yzhpl2gN9K5`^i&YUQ&HRtS{k?CZLe;?=!!qErn`rN zzi7Ho`?G;CiZk&CRr$OX>R6qMm}seMUnI>eU|KTNbp0SkRJ2uabbRzK*eAJ*`bUwN zNYMf*w>hsxW5xFqDeR;yC|0Irg+912U#PA3T~W7B~ljteWG z4cA|LqV*B;n<{6W`N9lZ3$OCNcBStKUN-V^Qb<4DdwrVUdN~D`uOmsMDy37W&TCx8 z`-HvC%Bos4L^bDi@mngk!{br_ZmLG95gf(h zRA^a9T3w7r)AhHngzb!yWys z99{6H^OB~NXI**CNw&&k5U0r+0hw~uA!Vh;M5>qN+cE6Ib&FwQ^s$@Lc=n(|u(@L* zi~1n12fuOC`jxqe+hmvv8_(0jt)OEPBE;FIfb*?*6XX0-niBHLw zWy%^)8l8d_bHMLJ^)le+-3U>p_S-CBjxWRe0zR1EjG)hbUZ0}L#%h--b``!jjb+Zl z0htxCs;2n_QXG}OnHnTkbVj>2e(etf^NEq8O3|{+FPA|N6TlAbvEaR0V71;Ynv^3! zO4k7{lT`M>S|UWANM5lidjoMiDk&IdLE4`{$I4=qRRL7aZEQ$V)<9cFCuSdNCk$(A zCd0ZB!BpPD{@(R`ZHDpLK6+2JR!4eKs2*K#;F6yN*2j*LC;ah$MCa`#a3xcsl)t-3 zG)pXK{G2;sHr{EzJ%ec+mWQ1y2*gCQ9WSvRf}rMOZMH#g@+4+`seQwqN$&0EZq684 zo5gVj8?T5U`$!2_tQhs6?}IF2yX^mjN`H`Dsuo!=>*AiL z(h}fv79Gvd+JJyWKI8qkOLSjF7pE~>oPt1$A}3G&Bp{6~F0-YKhcm(!rbx%W zgGsO>XB+y<63*1;&Iur=-#(iK8x3T8Ykjb;H_MN4HdGm2W82@QPW^AVp@)Km{;lCZ zESt{%&wutm!Z{khdEpcQ$RG+O5lk9@Y~&>N zFH%4usMAl30-vhxfQqwl)@QQ|uAQVe0PC~2!$B@&=B0uoKl!^au2Gy)@=3vVj%1t< zq#1?O`ii|)uB10zxzgT}GeV(5!*RJo@mT;U6)eUc+LS{<0`clj9h8wv*EOSY-L%*& z*HVp+i+c|yC1#CAmd8a`5^8E{u|pgUr0rObNp;n_O`U7@O+Q*hNzz;NkkruwcqB|4 zfuEicMx6mz`Z-E9LuVtV>?Y~M%)P&AxGkgoQzomPuedbh9#aa-@qmbzG#8bQ_)xzk zuuIAl8%fXnSw&%VaH@aUwOIg4!Kx~x51M01qj2Rb;IRm z(jnZvKYkM>6(+?(3(JzWgB(v!cE-K$nIWZ?2cD)?r9qaFJp~rd@%U5vcmX<2?W6Ws z1X`-ufhn10ar9_mJwAZ#mOasNZHszP_vcPxjigz!y@uX-9(yEJee~V^S=C;wlW_B%# zcsUw2!8E18R8{Ii8_cQ--R6cY2K}7e5q%};gU@`FFP57v&2nsPIi~Yom3nA6v-V{m zC!@G$ERS_NiP^|L2%Si#qLA2jK`k1T7tqj49!@#*7U#eKpD`7aeWqer7T;Koe79xg z7`ff(z1b6k=+6sg$6r!iNJ|HD+R^hu&3?ggvm157P%cUV+Ctr%jdYo{8@j7s`!Ej^ z@d7|5xvh>LtFYTD>u-gKQ;`Z4DuIkGB0-@!F)w?+ORWb1zer48WoC{&2%ZR%(>cm^ zm>5DTQJ>;~STIdER##35Cp862epTGc^nX*O%Pf>GPCB4JVuWI@RD+5pQck=33J)UC3aD&2n;b!?(;d6&YkJ|nTh+PNso8B$z}Mb= z$Iqb&uVr-*3@lnbf*gNq4ZxYG>7i=k^m0{x01q}Sr%5kl@46)TD`OZ*y1~ zj$@z~!r$+3O2|?`u|?Yog}uvKEQ@UUi$7o$M_JI_B+9Zab_hFxeb_}BojzV`cjyX@lsnwJ)9 z6zEcsoDGn+C3ntbaDfebTlO{wEav}urEV|-l4p(=Q1~RGM*li3D&sS8TwtaH9du(vf`{+as+<)Wp!hrqL&@5ux~Lntg4FX|Cm?i zg)LXao*7CqIoR^!`@`6QLI#{7Fxo zB+*kOns&~;o!;FT{K7d^INNVKqf?I(vg2}OF|;wjyG_o#GEX+iHv!D|{hE{_hwYNC z`jcd`W)+Xq=ItFZHZL>>EhNt~htn&i5*qq1Pw#xm1xMfWz8hRCyaPM2Ygv{voOOu1 zed=beA@MUkH4MOJa^~PwBa3(K=tIeTT&{peTivoxn?7}# zsRi$Q)?W(JjQ+hoMv|C$HOc85qTd=s__0zg?4^}qLa`EqXIl(`^wa{9n7UFY>UvDs zMn&O`b=E`lKdjoOSDfY%%0yfO4=(`^V|z@+os!GL>-pYJ{%DCU8$_5(>lNtd1f^%I zVa#nFo@l>CkW1VfK|`>fn_aC@*sMdl_~qcmsRSP)JSMdxXYF*uOoSWnr6u^i>a*%e zz_Tozcp9=^;?R|+>h|b@%toTV&i+KLfYqM?F64URs%sd*ADXhLVsEkxo;gHa@0h3G z4kvs*i;wJRE6ZkN&vF#K6?dzj_Pb1}-xLqE&n&A!wR`^cda{U3Z1I%h+2!7deO7yW zh@03s!`gvCimu6QVq1q_ymp!E5n;ZFu95*Z1uFW@%jO#mER-D2CLnBFv&l!;Mr&M) z0!iI<2zacav{#w1olQW+rI6NIRiB4YZ!@zg4R*6ILoB7;a&_eytg{1heA$QP8(U+?^WgH5^_n*&=r& ztj>TSo#Ly;zU5rrnVNCZ+c<*GzZq79sbqybl)LQeu97v5fnR1YWP>O&-h}Bd&H0l4 zj%5;i1hmBxfL?pi_QI+u^60`Q8qRMo)!4MwiVrywpBMJOvraJbu~h+m|6Om==**)@ zF4{f^P*kmw=E{)!ScsqU`%{-N?J5E~w8-auKa$t0HA54&gD+>rvaZ#Nry8P@Vc*_6 zj%VtYmEo1ym*o-p-(+3WfuRE7qucjE6}nOsP#K2&*|2=PLH0LDt;;U}UWGkwnV}e^ST_9wW z;B5sTWl&Et+>gJ7T2jfrje*6jw5zKPJs9pusB6}|u)sM{5pk|C*(ek|?B(-`-(9#D z?D8j`t3L;tW_S6M9*olmkQdt~nq^x3qM5CdH<>?My`@3$zegd4` zdfxYCKR97(wZ`P3zs=Ob`R$P}kTh=d8kNo;e2lXF)+8;y$-f%iJN?Jx#Lzn+5Pt-O zL(5vv=^{@%B*w~;jpu|$Q$gmm2Df^j4dkE!sGNpT0?V1nw+#opNjDDCcz6YmADh0nrcMoxdyIJMwTanUr_>q2y1op%Glj z%Vl%JOVezUA3yz-6WW2p)N_$HdCM&s-uDbX zu3x0{S2}_}t-~_gr@yJCl{K_wxe+I8K6o3%-jWL`1ckD1;rewvZNHr27rPPrlVQrc z^t-aSp~u1IOYhlu6VH`pA(isv9d!C8o$j3v=_3#5KLKyX6st6(VdBt50kc_P;`?1_DDjuT)?gvaB&9UFlu9 zEzlpUH9Pn5`Nk`e`ZEI71)tOh!>IO)V2MNC@M$CO1^IS1uH@~|<4;(`Qk3!qO=&&- zS&64<@9h!dUQv!TT`NT{s-UGp4c!5A=deugK<8FsNL;pf)&ciub)rBdUsfbd?e(M%xNvYb zs&T(%vebO0nhP9t67iUx%v+4J4@bo*&i@JV(eoDCUqOG*b{Cw`?R28~X@lj-&QJL; zN+xCABVuoF*ZoIXHY8=t>3C(nkF}tMM1?wfG-arABzG^k)P4i>>6@+@fhSL)1SuUi zm1tf7gB4{%Xt;$-deo@i(#k-eHhyGzF(YdJD-xCR9w?)DCYr_ilYg>%1Fpf4iTW{|05?z+ToA429s>nrX2c46<;h(kKzIE95PyqTA{MC~$0Xql7oYQ9QAI{zF4feUFvVi3oW%^ihKZ+pg|1@oJcr>yw^L zTh^pkYRjJV`+?OFx`oziC??Mhc=`OzcDRG}r0PY+Vhk&9nN3-+ewTjEu6KXx{#HBI zs0>l;OFm+!r!fv({6^s+xGJQYHQ=zMl9z$UdYs<Q=E4w=V-+c)JdRU}~S>tk>#SN-`tMfV|JBep4 zh-T+LN`($V*9*Uu`&eYvmleswMlrb*S=055*@Z1w4mj9u9n4I-HK4dq{=K7cPcuiWn{VwdS-xBy?_+5JIHBju_j1UQf9;^mFh9o1W2dN^tqPVr0|a#vt84&=a$fG z&Tl@Uedix2hSaPDa%6P>eqQSs97Pg%qY+??s^8&lAcMkRuzZ#i)XX!djO7P$qD@loAenGjF}SzD!eXyr}3NR zstU7*uJXc&Z7JHTM^QTZsd>*Y7rC~u4`@m0s2EQ{3bNpTSZ6^qJF-hpllIg%I`~c5 zuHPHBujsjz6HJf;U`muZcojtElg(_I&Pe`uVHx^;AH7yK3njN_t85ol+tcRl0zSA9 zV9MZ8ffMe#p-@mZ&aP%aDWQ#riK^r;jKOflAq5^Bl43 zt5AkZM%cq6?bjJPq*drF>#s+8cZOM~J!vxDr`E8WR|>VwQ)=hU1NGNZWJ5_v0*}$J z&Whva?{dZs#Tp+KimOKtO~d|JpZ&a{XUVyHwH{tPX%%(keb60Yx;5)oGf6VwTfmTKSOHP$JN5#z}R7kP{)$_owc$sb|d~5oBtSl+FbjXEpFVk{F|}t z*@gCNQRau&fbIi^pkuJ^DRPdVPk;zF(X<^F6RCj&lNcLOksII{AdyK#Af@_4khtG9lN+Zrj4_W1$vQkGvsk`=rg*z2@PlO!b?`o z@c!5bRDdON1ha#uouJ+6nl*2l-+zopsJtJe;B86-xGqXCrY}*t;{5Sw z^QXN6nA~xbN(9+JgLSx<=J~LA&XvfZRyd~F7xO}ky*PGi|L+uVXyJvataax+l6&XW zD?p(60mH}KW{+Z*UU?_6E@~n%t`W8C1B9D#S)|miXbPy$tX)Y>cI&6u@$iM+2e8jbOBzC$L%=MIo>}9J!cCFCTj=TGV(V9AD5BT(; zD5@GFDlPm0i733GMz{8&Fzwgu(f*pKb8-WWK?Ec%(d}#9lwR$~=3m--VeI36Dz-=f z)Owu(yH0xO;_qmKw^{k*c^>3hdoeY59^;d=?f^Rp919N#oGH!~C|JbqP;(7dC6#mE z(1m}lA$G1nBZV10OCo%XYlXk73#D<4q?-p(h(4dWS{7vMwMB3wuX&`jvAjB)s1FmV zgoM(Q-`Yy;{J=1U7aCV0jt~D~X{FFiHdT{eVEK!FrUk32KAz3@HLBjz-CV-5(;Sh^ z2Gs*1)c0}&-U!AhfQ?%FKG~BT{Z0>Q0pNy z-lj%vwSJI*vp@_P{IG3b^=({rB8vxBw$|4txHG$#_EkzeyiD(oYyCmBW=p)uz*2Eo z6DjJT=qWTjYTC_yF@rZS+bJ2f_7&~Q)E^w|GHCWR4=i8Z3BIsD$B;>7F}qgHOll<} zA|h2VSatk={73K{eRCA;ZSxs%wZC{yD=e_*aN_t6D^Zk$Mj$_*b<^8rlH&-XC8IX< z#4Y(u#9t^WL+U7^sR%rG94`Ln6KdIZHrD&_iMR{1ZK1wuv)m6-?QvtnIw>-^lZ&R; zU6=}0@@BZUbiX9dTVLb0yhvx$$}uP27f)w7VkepB!d%PonJ;)qq0DS?LWU1HesXkE^*lK_1D z>(K6|vh`?AiLw^{MO9Dagt6xUmg<`Tu&&EXg|P5dzU9l{oz0A4Q-9^N+9~uHSHNUP zI-KpOTSPW@l>|Fto1+6j{P%C+t%ddA*U4j@hCxZ6ol*T-6VdL-0Vf51!;fhG;FDe2 z%Gji6G5?|jfHUruYL+50H#j0?=X2D!&gPWsyO}ou+nVjK=JP+@rbaKBn~E`W{5st5 z<9To#1$rssCTkmXOa5pzXX>%(%%Qu?`-U|Ai{dd=VNU@hOy$zmO=o%&NDbM5GOkdf zSVwRCBt_O*aF(L@`EqGjTpN7XTj3;*zls;=kFkkDJWXmk0Rs5xHX}5tDyl)ss2{Bi z0VkW2C)V};GTF;|K>B2u%55;41hPyFZ?40^{Y8+6&?M^paHPh)2u>{2x{jo}Z0NklK_(>+3EBj|VS@$s$&7E47!hj=*qGr2!ii z1s>E3*>28vWIzfnd$;~D^r~W&vBo{o*ecRgl(;!PHa@EuU&WST1)2vgYX(~4UJ=dJ zr&s-VmCnyp*!m|Gmm-j7D%{~Mwo}babY)}~H~v%lbi%~OiFxzo(WEiUN7;?yG7l#N zz8m`buSuCsOG`&q(@6)dl7SZ!>u^w1Iip_y44RdwLO?cYMdnkp?gkOCmwetX;YQRJ zq}#_Y_=QjD=~Cx7K-;5+n&{Ra3pXxK6PN!kP_XDUc)Q95aD|}q_-s8k#S1Z`BJY$X zU%E)K844#XXjp$)`xBZI&xA?AEPvX1C02MiJx*}esH2?Q+NDF@k%ZH#A3@#SbWZu! zJUrF$Vt031{y1`PXJEVWa#5C~L)x^3oeHqbWoMfI)PXXo-GD`3nwB#q=>{acP&!Yt zzdGk4F?TX{W9ICG610}g=~4eF6Yf`FM-yq1{)G{9?$VJ9Krd0RdRCZyy6M>DY6N%3 z)z->rrms%jy)lYb*KG_eF_mcL@g{B_R@E10Hp)@@ubo6S_k!077!4zMPCreYdDvZvw@+*@W;xnOXWu!5d#5-a3fIeZ!dWhpytQq@DY0=x~{f+3O9dKuAhP zHVO*PnX4?%>uyl(OsEC}qH(!iy*EC;rUCy5bj+s+$YOX#_ooY)^$H4wL09r52~);bTul@Gfjw5R+;pKD)f~%y z5+JhKv?8%uH;E$l@sA6q7P~Hz>|UTiE~h8Gh#oYvs&)DVrEFm1p%W@4mZjLRF!}$m zc3weEMt!$O5TvQ}-UFc{0qISUP5|k>g#b$LMFgY=gwP?ODpfk6cR>Q7L{aHox>5zC z7f;^rn>lmt&zqUdLX+C%;G%~IP$9?zHsIVwq3vpzqO zw=8F7UrKQ?*>XA0rb#dD1^fiOkonc)_;O=lh!L!d4R_U|72+dxSDvTknPi#>uIjui zq#`pAta+WuLJ$k|k;`3vEY$53+6K=y;%Tc{Y;m3JGif**=n3M81JdNQar$@W-&0MD zFTTTD2Q8G`Fa0!1TQk*Bc+;v~MAFq;P1?oWvKlkr=$oL-n;sMSANoV@|-LTDQ2{Y*kxB8LqA+ZoK*R z=lGgu;Rx?uX(W=LF=0)HamVDd`2VkaPmV1xnSii%&Id2L>YR3ii>+zUc!8mkW0 zZrr_0{{tSj2-ejvbLFadL@59yGrl0~#=q%T;B`Rl$eUu7c+CEsqPSc1*Ir&bbw#+EF^F%^1WTOs3^Yb;;JHs3M+^_n{P3c1m zP2jwR)ceXav=qZh44YM-`1iFF7LFP66Z-#J9vhK@^Q=CBtrqN#2)3d++(2ih? z;EqwS3&i&M_O|J5Q`{ZPLU2LPsgl8^4UOTs|L?uin&)k{F7VeU7;((yj$Cm5{!PIC zdCIlO>aUi=$A4^VJ^*zCBQ6aeT-PKz%TPh)oR5}W9><~`&e*g)9Q{7lk_lX@J`CDm zCjf5O#C$O&-)=$*xIvwYDn*TCyIqwAS594q*)PELw+8U3bK?lfnX}+7g@{k=>6I1- z`4M4%ACVQ-MGUO`z6!kDU1%f3P@7Dc7rNcvdahh)v0wGpy~jPw_pcG(TO&@?>V`hJ zR+^p2lq)=QrBs)mbi5Db>Tt)N+yaG8aVKfsLLA>{VxViVZF(BrWKFGOE_xob7yPtPeX^{mUkNc>l=CLZFC|IK(JUZ|p2P6*)-y%MJxr!S0 z0N*`AXDbtRJ#Ewt6>j7LlHxPD@bXJ11rKe z^|0hxr4_I(N5s!|7-t%2L(|#G!=yUA`r~pf!*j2;9 z(`>!>9pu2uBVbT~I%z~9-7nK}ppZdL{?`2M2n+bGRQahQXSME$wUp1Oc(o1u>%UXkU0JpuHI0u{6Nxzz4$KTTpAbFW5_IYqwnp0P| zj)!sn={y<1{cVLa<7+`$j_1D#$8`8n$r6!-bfu&mEU}a{WE#!NBU+-wTXL^Q3~g+n ziZ2(kcN{B(pI5#JKm}x}Y&Ti~K+8bIS^Prh5O`>g{J1Azwu^v2RI1@@*^Li(WE;Ck z46G5ac^sJg4A#y7gF8D1!(fwVjbG-v&w8E!WqVz`9e3Lv#Nw%Nu0L_}Xw|AdMUNo+ zrm8vav3@c;6IsQm%w+WRMBi&Umb_e_f@~zqZvMk#Zf1Y-ND(5Vk3~nsg}QdN`*yAP zta&-QLqR6rJsv(TQ**rj8Rz(IhLI+Hi!6$#)#**##DL_9u6-8KrXxd$?B5Cl2=!gZ*#KG5Wg-BUlCtdln6G@Urn5~< zMvxEZrM0Z4U;ZY_i-*-r!-h{BDRt{p<7fmsYsir)sCik3c!D>s#pq`Zze*YxSCaRk9B>Qu6ufR? zx>zv(>FP7{?D>hQW@?5T7@IS31J+ETM4w=9Fzn(Ey-$SfMLftOWtDPY&DNpEF9U!~ zU&E!hQ*mMVEoo%+VeMzLb;k7M+MF5_p)1QR?Z59^K7#ZP@ke9zEpD&$ z6^6(V2u@^5f&U!h*mhvVaujmn)Q%DP`cOv2aS=?2?f0AKPNezBW?#}q$r}EB?Rw2) zv+<^4x1#IdRz3JO;}S5W9s`R=aJw@*R?t>ML%HuO7G($8r>vpIzeR$0#cCTp!=1wKbNk=YhR znL31jFSS)*b($~nfO?nDT`P$~yz>6|5z58>Q=R}U~5T3m6NPVh$Tly0edpiAQ&Q5 z*XT{$rrufKH(!CDsLM8sVUxOys|tZ1lfypwVA3DzT`a@#%?ckD4i0?%_a@xz+bXxM zAYYX){^6XnKT1$RYq_=-vy~2Zv`H71{w@$MKrw4MU zw^jU*fFYC8EY@}j(HHGG1<@k-9_IVpcct7zKI23@$14V@GgArmzDw3UT7(Z@|6N#q z8z%cZ>F+_I`P-=?~tml^)DwZlU7} z3eV;`AMU7#_HqwFrDu-0SHf-6wA%)8)84mf8MN_J&C(Y*K$%KJkCRvaYkE^6BtfbI2 zJ%u0T!)%uO`rT`-auq@Dd6b=JTfRT9ze~S~z49gweJQJq>QALH129@d<8en>;2X{2 zLOIVbRxrz~%ZQD`(NA`rhZa$43mw>xzw7WLT&^w&8-B#4#@|$fcGRJ8x@w=ugxy5= zh>Iapb^-VL0*e;2BgE0zGhb#m=J5VyYq5f%_{vr{Fo}#GV02!b>JiCXhE)4h>>Hn| zs)o=UFFJwRF>pspg@cx-dM?x0iAE&}M~9cUu@*Tokhk6f8UTVlDK;VRrIdbSz|nBA z*DXYs5M}f6>NvJy9q}^R!O?>H+-C=um(SdZ?((B;oNJrGT$ixMS~bA8g3x`$ximYmV)eQ)U^tPM3K=r$iT#K&j+ug~hNWZottFW~vXTz8avD1( zS>ouhLI))~=Fe?fDlwXQl-#1j>qsSN0)|Q`dCXyV!$(5=+RMwuvO6j@5JdoMc8w`A zOndI2!gG&XmEB+UjrK5+EGrGQqt~WUr{sVVYBnQ`^7UpkgyvVY72q5v*QRdCY?+-a zqkS6oAFihAGb}7XHpv)AlHgQb8N8^WE<|EmT)1exWgyCeB9L$e1@*&)}6jlZRHiHt~9{>yDnET@|sVp-4GE9xG z5=}$nzc|&F0PKABX%C1))R@0`h@ucfIgP4YQs^1YMQ~Q4b3HJXo#_DPB#FZYK?dX|}cF{9i`(zuP%H$5? zvw!F%0^fX9mq{?7ud|uv!pjlily;nDb4R-*%)Xcp&ki^0s1eBo$L|`+1x5y%$oo+k zJql4R>J#O5X{NaUTH}RPi%}RuH~wcPY%e7FRh`|K1Kw&tS&@=^%#<$tv)z3VCwk=B z*Q_iw#IKn-@vEZ%^p#S5YfJOH%rI?IxqGVUKL*q+m_th0`XQ-+eWmmEm2n@yxt<)S zM{J1QZZTW3^{+aez~^K5+xK(`d|h$P9QGt2Rgay(b-{tjGG3U zR{p+?_?2~fGvd?+6c^ST!Vb3<+U73U&m*iy%+k^_^&5!+^I@{*jBF;n=+QL^@uZ}% zNcmdz#xYNygBFLlg@>sd5T+q;158mPx=;h&t-<2@slDy_2qvk2?o>NbeGo+{Qbv8; z(yy9?)$hm6$8VB+t%n2UBYeNeR$~^ddg0gBHy&|0isPFAHk|{0E}*EkGjxp+M8U;v zhLzlO#*BOov{sIHAKA(xm{(BgfHeYexTHq}&6p7ZQduPF`yf_hzv~K@P175J#vrfx zGADPJ4da6JaM>SBLIzLWY8y)E>WI}!Cd-_tcqk02+2}(qdHr((ziKe+IB%@g^iI?S zG&z6%klyI@G?IznXST2Uwl+A1A^To!O*{uNdP;t2vu!5Ldtq zK7WnfOFur#jZ(Z6l!k|;1WDIf9DV4jK1rUz-~ETrr$j}nekDY@CPM7BxttXtsxdHa zV$HZWkA^q$*cg)R0*(L^QJ4GF;^GP{ z)-wwsOcPpywJGhxwGINrgzxkqG|MRVPoDJhs($1N{Hs2LCH#4Vt1-L)cT?T%$q$T@ zZE%@is06?|0=dQuyDUmpo?EhT^8>^WiF8){bYDj9E6Jb5Jf;SKFeeN&;Bmka`g_wP zdrEhgUhCNNV3<=91tZZ-k@?$5HnME?KFrdxv$MW6!!;&xWO^hCoVaCt0o!uo1udi` z6eUC|!M0upq^wxV=2m=UizA@xk0u~VpkjnWAdcq=Gt1R^edxTz8u2l%k^cY*enLv{ zi|#5vu!R4^Q`#v61PpQsk3e=CWvqmc4eor&Byq1lM<4E=M$g^`s`kwNZK+f`3OSbl z%kXB(=k6a~`Rv+*l+#Yi6L!$u$Ng%N;vnOzv)cuqo4;nKV+prqFvLsMe|RJ5#0j?* z@LC&h@sKY3}$FNI9LFI=_NgMzP+h@mu#K%=OoFjq@Ogzkn_sKIvtmEv4mSgLe zWBYQM#6kDJZAYauG8|A+i{Xp145N=X_f1i_Il9b2k97LS_t#&E?<=IX=75gSLP%=y z>o?;#k-Q%1g&pG&Aw4|xfWdby*~^^VNjd*r{y9UweBTcPrKz_ zRcWvo{2L?nRDif_NSG zCqB#~UthDIxOL5$>rh~`NdNve>`4>(k~F{eB+NoH38Mvcl!37|(GrG#vdorkm`&2i z2vS_U>@e)Ld*ytA*y%!CQ+m<=!y8bk=n3S8epBSzw+0%JZ7d z(NzB79uuHRm`#{K6Djm*nY#fBQbOWi$Lzm;mUWX?wf_%qY~S$={@|gJSL1iBIAuv; zAn4C}Li)~FW|R$x^T!WX@!gk{Du=Ox5Zk$no8$_p(^Ik56^?fH+A+l`j-14ePT?dE zOy5mkoe%>W2Hq)XZ#{F4@#sGFuK6-{IX=A@+@~_XUOf2anIjjcppQt;3;xTEOrxbD zo}-N%lSPAsv9%fkno!?6TU^RN3(0?RO_GuAGs*o{E^xOGdy{g=2vm?1i!}0CwoqHF z(|xQG8pNSxX%)PssOO-=xV`>S01&xj-Q6(K*_l!~rKPrMDi@`}numW70bwZ8r&g#a zB>u{!QO(g*6K?5Q443gPC1i+-Wm6kDlWNAcK-G2(lKjx)l(Xf*BKD90!#mywez+0V z{8DhOqbZrdPrd!V6vEz{_rBA&_gMfQaddz=EX+ab9crp5W5}Z)TS6 z%=(QtnybhMLfJXVUuh|SloP}sfFBcyKOo~PR0r7XN5a*aw)W<&!m@=SVrP3!3`yXD zd#|#mU8cV8Qtt$~&Y;FsE1_VB`vXGIiy7CIu62OUpw@^z-^3Wv{s^4eXVrBMr#678 z4=wAC)301xt19<0L;w@7OxKKUe*~i9mwFAx9W$~9-M{4SeBGxM@ASM!LZXRappzsf z*VNP`<%o%iDFy-oR7Y{!=!29)(byvf9(0aahr6-sm`A2xAEb(D?eD994Lz&fCBA%R}qX` z>UuKp07JV>gJhH)$mpS`x!d1aBj7zS3H*CMMm{w&tO;;a8bP_RW>M%e!h5|R|0?1Y z%UPpAABJW8+^*S=U1@jn^P9GqMp$DK@YP#2E(OC%K+*1GSpN9wZOIjm&eKJ%kkFGn zwc~WpEMGnQ^}Fx(qx3i#Z~YKq!O%~UV-DB_$?xQU>0px|Hy(E0pKM7ED{^Du!Ta?# zjbo>>aFI+?vs3Hj9t%2raAH1$spA^qI;VcdAYtepP-HmhiZC38%N~y#C*AkMieYY> zBEO5CqCzoV`#187BLtv}PH?TXMMC%a5hWK7`tuKR%WKhgyS7ptymW(Vjij^et+Mum z^?msCXB&)VZgYOVBW_K!uO`SNA$Eldk($e=jZoI<(c=rg$?QD4MuiUWx3n!}WuO}} z((3r@IFrt;9fRphuNxWktv2LZ64OOtZ})8b!myb#=F8xGrU5HK1L zr;YqlR+J+`Mj?b^Ul5qLPSy3b2BVUB+Iik!kq;bBYkJg5FWCJ(d#;=Jf=4%Xd$L-h z>Y7Qku?xbfKPzZE$&jLle%tXqc`A0O_6$J|ZZT}uL!RTrDL z|3c?VmXkX8TBs;pra=7+bHLYGFQde6M-n}~II|bE>rH1kx=0$yw{$@}hHRZDH$SKQ z`Qo#+;jhK;RYI@Y{)Algb~SvDJ&H%vQtXo_5=kzvy-E{gMt>eHnf0Nj?Jp_^+AZFq zxV1PW?qdJTGimv!C-N(6NoEQ1m1#%Wax{Mycryn!ynnS%%~E0J8`~vLu$gaXZCcQh za(^ke^b04#7cRS`^QHo)Z3o=TSE*3hvxXk&6hPe|@J-q?+#PcSLdAZ&TUj$*;5>-pt-lNk=l zaB&qyGQf~XoaJ=J5A9#)_{OO5XpRYvQ^c1soWEXgFqA)Z>c2;RlkgvK@eO*YHn;q; z;;t$0@E;zLZ_$;Ygz1F&>B{+Gx6*Ibh@G9>$YWL}vsOK~-B-n!iEoX6ugxCp+LvA- zPOfSE@={dt& zbv)9WHGD(s5A*ItTW4a-;m(>kVt2TNa7@)-6FDifADdgcc?4K}6$I?`h`2jNn-xTI}eofnCjj4{<#XV-3{ka3%>y`8}k zHU3m48m)i-IS9n1qDsVl|GB)h?jk76$||66Yh{^EOw$2flll`)#rMl5(orqLM<#EZA^n_UfERpSj<1jZAnv|X^Y^R3uwKc znh$GQdqL43M>?@kU$u;-Eirq}GbWBTej#pAEX(+&yl|FgPfrCvW5HTJ0MH5LP~~|W4~y&Tj?pHl zvx+*ZKaxg6;eByLb_ksJ{Bq3^fq<7k9=(nxkNqJquBqD)1*sp0RbP!Zy-M-B8n1bUe}R52|Z|y$ga5KJ9WYVy)nlPmnoNT(72A20La{e zl1JB@{X`2EUH4S;&ZCGKKD&KbiG4dl8nHWT{~m|4c0|CYkM7>x;KtR^9@IZPY~nw> zo2{Z>pN1mNyB64QhU@>~eRXZx7-tN=YwcTP6bk<~Kc9J+AJZt}lH$39?7B69ai?aeGPI<1uLz|4stkk)efY}I}WV*+28s^GqDbzvz z8w#`{*!zh|h`f%+wFmRB8!^hi7HeitY2v~AleQ-xNOBh^4w9!Br>4FIas?DZk0h;Y zvK1fkLlNbiXjCLKCy1+w4=4rzBIweTpf2 z(6kKv=%>3;XKjQ##(`c;wVaE4J$>pysH4);p(cV?bUv355|m!;)n3&ZSXqOs?HNsi zhR;4aDQx081@lYeXUcGvR8jO%p8s)~A5ZgrANRAwX(x@1kD||{i|i(b1v`jG#JWlj z($b5b{kJ!#Zsf&>n^*cN6YZ^D36zF+Zj{!$8-53hQy?iQ8qzs~XW%@H3+E$aKW=cQ z`z`sbj#I8+T^g@57z?`6$)~j+C|GV*O6JzEi%XW9+aw_$Ti__^%|QEd)m~5L2#{fm z^%=WD5ysJ2`r|??N~AY&-^n3hm{Pg-e(8+O)TXZVX;X9m?F6toaPb(pu*9r~NfooI z_cU4(_8`lw6z5A!xmQNXV-zR;*WrucDmjw>?;`y8`IS$}#rDYEQ}y{93}8dI;T^I% zyYUMdKVA5=My)4$@ZkII0JonA%rIz$M`=JIC zNdxj{B)zW+-WMv=aH;XdrV6bac6^yZKIXKUpR;>B!2-Old6!`pxZ#%U0`?ZjE9WlI_$W$fBbK_hTKKkeY=%yUSJF{iu8>2-wh2dZ-N#BaH4_kR#&K5J&+ zL6g7U=!u?Ml$QUn<`cpalzJ?K7j8!$P(I4vS}nIyzbp2)(%FGp)SB!;Az(XUO3vTB zT~V!m-5M^@ytkpjJwSkzptZ_2aQ^nZo!vf@>rYJ|#9o)ehWTOamihH=X#py6At%G( zP*ujQ4ze}XU}7n}r!;Z!5|MDk`XN>I9wk6#18A!^CJ%N-)ShewrLl7+$`?Z2N>$;nTe2SdgC9O%_p$@nAK;>d}mHg+EmihV$?b+ z{^KLk_lYA|TC$CMV^GqY%`OWs%=Lip9@Fff=YJUAn6CFZYH*oFiD*p3m{3ayPvaY3 z{0#rWpsK-h&a%63we{qs!yotR)G8~-C;8}G$^nfTjoPx=>&Jynrp6_lm$x!7%1x+f zQ9axAu%j>YCl3dMQ;Xz`oQmARB#O6G@R|=#@29LEyiZf@$REy%5+OAfl6#Pf>LRUM zn`e8jmY;Q7-@QOGy83d;(Rs=(K=^~1@rTvl49>=}#qIEIZ=L$~k~y&=u7g33{OnN7 zwWCtO3PX!*;p^C>hlv4=>anMK%EkRJ>PD)67Z8K(?Yl}HTxC=V?(C># zeMXQ0+pCggqTe#Y`*+QC9`(6ZY*+(-^|UN>Ydn1Sq`0m-s&-8b^V zW~-{rL%3u%H1Yy3%6sKJW2=Hs&>Ld(Zr=yjA^o8GMt6o3M}?U8xJnST#?1>P)Q_`r zziTyLDs{O#dr0%=*Fn2r$NlXUy%WK+lzpm_s^2^`sek$$M8a1PA_J^g%fl+{4|?B{R`0??1u$8*!gc?ZxQn$5?KtUVRfC-9odxnE_~wv|W+T`K zP#wH2&G=Hyp(?t-smH|`^Ih}3v|#6dH#wP4s*c!2+hpnFh| z6#zGIXG{B>_jmBD7^;uVKo}mm1GRO(oaSee3zfhac0qk#QR~=;HAG?uf{q8WRrTr{ z)g_g6OFDS2R$2DCzO8v$Lf|xNZjLV4{rgYq{T}wz|2(qD%iD#BbGAzH9M+HzDP9@k zPeoN%7FZ9C-oJwj@&Ea~W(gwzAcXyEL%ax>&kARTE0OXAqp@uThErN~W)`m!a|Z%t zwcE{hqaTJ3VlB?NH7y70Dv@)c@0gO{06=C(`1ImeDcb+4APnZ9R}|8{fZ?m4Hg()@*kb5B-Yi|J=ZlNOc=vUh&;O{B2Ry`FRCnF zdr1)JSvGuB<2lPE~ zgvZ`5Wt*0COr=1;q$YNy*6r`DlV^8A%Uf-vOqK5k{A_%_GoOEW8e5iKZvMR2z>`l& z`W0-yo-vaSb8dg0dqmjUbV#Clx9t#pRiM!Mw<49~PJSW4+d^R`QZ~UL;;}{Jm3eoa z%#PhN2wnoMFtLukmXCxw<>)B;UfL7T^8D-<%(`$(FNz{RTzcffO^=K{kogq9^T(D5 z7ZF=;k|P5?DreE$S3!sacy zckOz5e9r5U%ke@rT8`b{W&hSxAJlr3bMR@Jb3fFzW;RTPLnEEPkcbO_8*!%w{=4{< z7tH6O_HVqJ#F=;fl%|qDPs(}z?9*+cJgW@Zw z-LzWnq2KGP1da3T7mbvRDTv)aLmEnJ=K3HIddaVY+CQ6}ZJq8|$?&I$0_Tw!CFo=^ zeoY#Y7KP&sYw}q=N(G@E?G2xO-~utgR4Nc`CD&T|hA_A^9O!ZuDeO03d+$zc$aLKE zc?WzUiYzG%%B}&WX9+v@qf)k2=T?n#h#&XiV4!j-7xuuiVj1>Z9Syr(r(1xXfFFFc zM*>-zJ_0<$Ns;%_F|c7QF0;tmo{>7_4riO*?J_Ge=11(hcmwt4539KYFE#;G1ZwD3_d$F=&|wWp#nShp9m%p-YK1)a#J zWsGl(?n%+r$F>sN=QyYs@sKKY0t#Q}&QoaY9vC8*CZZN%Z7i&s=sbh2EMIEPwz*ZX z-bzezPoG9bi9{=C929Z^187qR4wo*K+dnTfpY>4fa$^?<$5g-Zab^LtB5A#C!0dDm zZ{04e!)oBk)@u7X?X$OQ*lde7D~VSJZhH9o>iMs$sMJ+oHJ6$;X7N!STaxN5_Pz-vhrM2lFAO{TWs@elkU7ZCa2TVyftGH)zUgVkEty!4Am&SL9Wxf=iey~ zOm`VS;U@Y(+%;i2YD(cSRX*Om_3*tR^s7S2IN9C{*=o=I6diw>A;pXo>D3gCiJGLm z8Q866O5`I=b#v=y$MQMs)P}Wd)$O~wC0z=WwKewTRU6RvI+yyNhEvB0*}Xtmu-|Z| zS~Yvz;94AjT}=y-!1hNzA3ZLwrH{S&hldNeXLl?&FG#GDHY@~m>{RurCQPvCQ-~iO z9f^zo0iEEe@v?Vwf5O?)tD$}#9#9=}k>m&1x~hu}W?(;(FA7e!&j5qc9FcJe=E^It zCm!0w?w5`5y&rlskmL*rxulYbN;w6C^-m|~CF6e7Y|hoT9Fh7aK6EG5rozYdivu4Z z5JkH+IiuGCL*K^Y)6Nzie^`jK0-y6);fw^ADHq~}_QlSM+FXjH9HF71qoG0KpS^N6 z16^*ONN4FEDv@8L%mXgphr7VG&EACNd|#9czcu=G>iqKKV^|^KR~kv_qLeI|=)1Z_ z3=UoRTleX7(E4}oy(AtY%;TX6Tgh(`^Lu6~I?+Y*uTjqO7?8XlH3%fzu)8~CBCs+$ z{qlcO0!~edzLpgBeL`6uIXR0G5)yFFoRBbMC%7t{ z@}A2j3Q3p%Mvp7`_@!QI3|^Nw8zgV~J&Em6NvWh~;~I5O^^0_5t2`s|=ZcEXMyoOd zYQSd&O`k2EU~f#?$R>8Ln3~?*d4}F{W_kX@YxY@~SV$?9^T8fr7km-B^k zSl-jK>E<-ol&C0pp8-f7tcn3$qxG8D$+mPp+q#Y&Jf-A)aH>DxDQ~NY(hV+uV_D+d z5}^6G1@CVH`W_{TPp9&kd9swO8Xu|?Ma77# zr2{GjPsaUsbI2&W!EK~pA=RHR`lQ}4)X=8RY{41Ra_Ie&T}V-p!3H^Lj6eWYo4=}}ufTnu%R`e|_3f;BO9aB~X$H(+fEAf7?C@=ue7B`Xx0j~&Oh@eT;9)Uvd;X#bR-wD`QR zs~Wl>Z~70qyX*n$ZXYJy0AFR`}TY=>^%tQg;X17Dtsw&YJg$ zWN4Mui*Mq!3y-i7l;$6E*3ZuD=v#jy>xkVOw+vIE>&OjV+mECfI6|jXWj; zm+Q}{m!NnKAkRU`1n9#lS^~ zRZYNH@ZEk24^FtexNR>gxDHyVaP-^n>4vJ-imQ1|3kFA2NKPhJf8B1vW7JOok9e&LaR?o2NagklF{}N)6HVTnE z{XswJKjx98fmSf976BkBvn7b$!)pa50r*W!Y3I84@mb)8uW-z$E$Mfy| zA;IEeXXChw$-pC3of-j-rvlfGl+lZM12R#IG7rn%eqMi7^%s(6YxqcWwqZ4bN(*EQ=z??pNsk$gBCC+-`ny}%YK-X zSg!KPr`6%*mg{9aXv3x@^~!5qC~Hy0ZSmEuLN!AfK2h~EuCVZxve5>2RhBwxTSxeQ z-9Nm;n3Is?X6Er%FXra*kWAN^S?U>rtgaVV_f&GL1O{6*>cRwQYBp8R@-&PMC* zF)s8SnTw9qj>dufL@L|AY9rl=+&E*V<6FS?foIPhqml1eLSsYpfm7-(ZhP1`cD@Fl z*uApRmdR)L4I~Ol^2qs#PDY3697Mmz@s-A)&IEmz=CjXPmnt21arMYlr*q2MuY7e? z_5JYQax2FRP_uV*ACLR4)$JmggX^(P(i-cPo3i;!qd)kJ)I%hMxgAOQA`72&6hbw7 zBE)6u_V@eE2;7gmOnoV{?HfZ%>o=^i-oX1}y}bKKc&Vrz07EeNxhP$#s!_Uosiu}C z;hWze$cYDFgSCFJLz=*)MzHAEj!tSXNkAqrcCoqYyPX~v@?o4&bajJ$wU9p&w8EOh z&GDVGu<;Y@DV)JGT_yv;_&WT>($gRy(H3vWdL!XtYB!N*OI#ZbCMGl2`Yh5Wh|HI; zbe7HLTbTX91Mgb7l;L10A*r~}U)LGDt0k6NY`@VxHahLl2u-yg*GdINF|H#Lru|^^ z3+J2#B`<=6g@%?!N&ueaT;F7fdn~Kncv15X7H=vm?DOUGloKf!f3k9XD)^o_@M4K( z&oIwQa?5NY#aWJ{ZsZ&-EV0Q)q{2qk`*x(}GY{Bw|6ACR^i0;Lcu?1o+j21f`RD1p zUnTB5#R|++N1#Gr_+O^gR9;a;GzArWdcPVak7JxefJ3fTf0(Pvh?YDuv%b+%=Sbwb zo{uR=xhq6Yj`)Tz_-dKgK?8eM8$LSG6nsek;_Npkzc#CII3HWygU6E`cSRvs2PXD^ z4a;a156YbM{V#z+1YQ?)OVgkH6bDeno9?>(Cst zU%%(;&-kSll_!}#7M55tiQcnAoQ7sWG8^ytj|4p7+`sY<0-QU~ercnRSsKc#MOhYq zc7yJ8bC3M&i!8FDYeNa$D#zFZwCEtOH}M{1 z;g1wO=4{wZO&tagt0t+U$4hQpdRirS=Vo^mS>|VZ>XC~x_;6+8mmH)q9E7dbzW1h5 zn_CIN931f$b>x%>4m3E7ja1)7*TvC7=$OkV>fE831^T1!+03*{w3us_xzjYJfl{1F z=ggIXW;jBRg*RofZ|duMiqh+@V>%x=i}Qv_ngw&!Rk46mM?4E!+rdbPS`@(x@|!^w zb$ueRH7VF%+YbJZ9(J>iNir31=$~A82TI2@zc%XL6?AFBTH*d1^nJ;#}+b&!?FV6O)KejM!d-F+6y?A$Fx?M7fA%{FWzc2NzXm?jp zUW?DvV*b0#y^z|LxNZuSPB1yek(dEUOv#7lNM02jxNh4vxGA_ z$pw7226QY0;y(7ps&Sgyz))uJP+O|lyEmsoaHbEYDJyfdh5zt^_OAo3O2cpbR@Mv2 z-tqLHbaNJR(bjD-V{-MachZCIK?KtZeJa|hzGJ`v!EZt_R+nvqytbeN_wXmIR)G#? zK4gmwQhG+@jcJj#hNzrIB&DFvC17c~?@)@0VC+s3a)7TN#We7YHN&8z9L+Yh^$w)-xI zcCvzoAYm?L1w%?(`_$B!t5Y5s?3q|J;>r6tYtS~2`I@<(n3MQ`bV54r#(qua0+y2O zejPLvEYAttoS7em-b+13Iizz6uPOd|@rRw7CFLa-8xcqE_x0C*&Q6+Ab{soUgPdv(kpTCQkV9lYedWk{^+1J!8CsUYO2n*LHjH1iB&eYm z+0~tM@DopC1MN{Z8ziYASJmrQdmYJ~w2@q!0?lc_UJoclISWM##5cwreBqC?HVY9Ye zm4|AGUJ%-+ifB-l4>&?9oES)*JKco((9wz1Ck@QMn)0TJ5Z^myH*aJ|*wxT-eU7I0 zen9s+OW<2o?o&5`7S}PFGJaw_bMpVV3UHo+|8*6>w=h4&g311#YnlmZal;p9U25p= zoriK?rdY?D^Wm;x(xMU)UixodmXRics>C>3XOtzi%9qO?Miq1E6HbjLUhRP5e<1tQg%7- zrS~ZjbOm^L?Ci34EzSljnQG5P)EfQyvys6R+V6L{73H3IGeu!`&u|PtmNCuBO#FVj zmUUa0LN{(WJ>Ip`Oq7d{`IjIYdpIC+L+vT9k*LD)wNP6Ex=dng?uSGBSiy9L1C(P6 zQMjZCwNqyWYqrMi`mvs~PtjYBzAAe=41kI%I{^N#-U0%B&{eh1xrJH?0yDRQR@D!U-;H`VWiLibX13ZtgU& z&u*o|lFidt!+6mpCd@=hjEz!h|M%rX6JO>D)d8`L2h;bCda^uRJ?m1(Y#PI}%GVd+ z!?!yI+?41VO#PrcRN(%}_T*hRn&n0W1HbZ|zQ!3Tyb5hrI(;+rxc2?uvkax9JGT$p zT`3Pe7Rj>7*Gr3`L*ZD+-_!9Z@f??^&!+-JHoHN+BcFYjHn3nXHWeHeem4#Wd=J^+ z3(ZY+JDk(#3v+ALw(EIM*FY(ODhfOL{6m;MFfNTZK_gyM!*#J#jqLWOvQfrJDQNpx z=F5`O`-5h|t-@uHwjwu=8I$RKRyg#}$>kRM;$*K2dMP$q{-u_YI>ma_DdP@opGx`k z|E%_BjK1a1H-J*Xz%985_j=cFh|r+>kIxshjpDl5d5&EzCkx&mBSTbG-7SYs2_XuY zbFJ$lb7G52i56f|p(0=Wv;NlQPSYEC{mI2iMorXSPxSI2rvD~*nDfcJ(-iam8nrH? z99{J3isv)BF5Ho}LUG2z0MUK^(KR(y|Jz};*?mN}7qj@HMb%xqV30Rl)~)rC7U zfRPae8sEKARC<4-*VzHc7?Y&8mlQNe`4t^)ktJEatF1aUXOXtQ6cj%kn#jS?`MRg& ziu7bDdD$wMJTtfP*x^{B9FL8JLbWVyl_(X+7VQs5FxUf5Luk)D58ZMMIz$;9*lb@| zShW#lW}knWCa&H}6^)=sF?#Ly(`)B!ezldA? z^(1+)I=$9&T6L7rK^frxaqny^8JE+(fyuLU6#NfqT=49>Sj^3 z+LZaxzq!{7;nH*R}!yyvvdqh0rKa`OXTO$w^X*VktmrDMiA7bquPC!ZsamgBzC-=MeeN3y~ zsn2!?dmE&c=Unetj#_}3sX19U|4mVyF`uQgKX+-%*+l%&RnM z* zI-oXPS!cuDuZgs~ro84JKA}41-Ko1Fq7LoIY9rz=cB`zJWp5lgkFJ;{|Iz9Q`WI5q zsZ3mA2jvZ%8F0?wuEsETUgp)zj&3_{YRVLFmIPupEGcmM>wHQ_heODmgo%gVoO+jI ze%50iiE6R3I*@Uw&T9<>3fsjIQzFiHVQ3?$syj2O;G`-BS4Pg^V6%#*V;Gm$adD41 zzkKF=AALrXfBiT@c?fv9pWPqSsU?ARUR>~&K)cRYf4?;}9?@P0H$_4TLWJ2}4@kG(a9LeGtu*-OW7^u9oA zI&|dJQ;CZ7JL6D!n)xLPLcL^FmBaOl!;w3O@#rA89}y zW6N~ks@z=8)iI>vfL1V9Kq!P>zS3AE8|JJH_1zcUT^(L!@cF>?W;K5(W_j63eFE)h z`OMg=LS@IK1gwdfjSGUb;s&xC&|rKdn@^^{$8i}wh+FJBc**^3g_{zW@<1FrCGfm5 zdyaVQ*;4k9^H#cD++gV<${*F>5=~ry?1^aYfDzbjy3HRh+&r-s#9b855~p2IZN>Y9 zt%Ch}v4=562-Ns(MH29qbV|x=Zj&EB(Fd}^MC`EZwBv)}3UUEU<8zfCmH!^PsiC}+ zvg;Wu)FtRjY7p@AF@h6?NV^y_#+UcrlxPs?#>ByXz)95@q}-6tMqs~&U%Za+9Rs-p z3dDm*Ab)sSlmi?cX+Kw23ORNk%N_D4zl+K5q)~+Zyq_weE7=!Vc@@!GH5PUhC`2lv+6B^*iOTgrK<3=^;n5zU)=$y zdw=IQvJ;4;Q;De*$?ja&tJ63s*m>5gBkFQo>81yUs6B$q;H>m@&j`Ss0K`W7_obkox%ST!- zh{ps75$t7I7E&MHszGHeeTnm;*7BD`x;`M8+)g*`G5cOAsH6bC!_GE&$5yS@3Vby0bxi5sMCG}rX$iCK7d zZ^JoZCymgjlI6>@bfkOYj^iTw9N0==tuf>9=MDtXiBEJ0CH(~dC!hX#Q{gosJ^gXN z===6L*Pvf3((lU}!1 zVJ`XdF)ReW;`gbOf7}PfNvJ|`C-TBiym$Zn`Qax{Pw~?5OaFcHz2w>8u6&d}ep1;h zw51qrMHO-CFuIA28Ugv>CHn`HD8^nExQ+37u&5F#T&U;O*@H|0v=A^9im$dJ;U5C9c7?sB5bs z$%9QVaX~4D*3$=0mNYNMsJ~{g%~u?vF9-FnqAAEJTKPQFPt9+~o6J1iw@pFQN)?UP zw1nGS4(PbM#Lq>o=`i?n#LaJ;&TRey5qC&TZDuZ?+`=4HTHcSbtHQr5KzR*v#z}I< zeVg9zJP7oAg>ftP_L~ancH|wghM#$)HC2K!C(~E_xL6oHJz_H`4W@nQ)@yYtDHM=F zRV_f7TE0zx#=PZjgl_@Ts0C4M5yZjLjASCXYBh{z@G#=6vevbG_P!7M+U>J`&+-;J zIDFAWcb}Z>PUo^)HDxaqMC_`$p?LU%&}Zpu&t`Lh6Z#@N|I#S;=q=Wjb;lm3|pc!(e5iAw?i6cp<19+U507! zzHpNdC7e_dorGx><-f716aH}~ZPO-~0T!Yy)I z`>0NCQLH>5&`TeH7^lLxmw~8dIfbwEe^@((E45CB ziEud-B}!K{f}uQz95N|s2-r3J1_m$u3w*JIkqysu6yAGGV!oZ<9*MWKU_$xo(BiG@ z!ks{y!9D2wt-d^!Dsq_a(jt*;L=Y92yu5EW6d2%Xg_geWNCW%K;~Ap3SOp|Ays)@R z3s~(`wGvW-WqD#sx7X>Oidv8~F*Leau4PE&`;pX$XF2z%=?Yp1W@DD>`d@0Hs6_Fu z#7$FNenJ;ubM3Wz&$ioiXr=5h8eNrF<&`V&uH20Z)%%kDmpS&uKQR%G?dVsOUtLR8 zG6uH$ecYS*EF^@fX2pvPLdk)mu^?5HsuoogJ7=b<5t*{Ck+Ab=_o%#kaI+XmjZZ&a z95RUDMmlI6QvRYW$^rjrI7A?d#e&GL*pWv`C22Kx?80ZR`cP0Nv>~a6KkwV7BGHO7 zbfAcoa}%#;4@rn}6D-P>ROo5;k~2;FiN0=}Hp&$V#0Axlm9P^`IG%bqzZ`-xrezLs z0hMG+k8HkY_AZBgfPxXJRo+GDYh!?pOyDFC+SnKYRy7(kRb>wuQ@79G98g0)HmgIE z$G*$t#Z8jn-MP$_7~JpI|FsCRRwC!!7mj2*sAC?K*Ib(Hah6f|n{Mhq3neQ5{%1hE ztkG$s6f}|vTo1bhd<3q|3sABZFx|9NK~DBYH>M9z_7B;7{G1wlHw01T8bGF3g`SfN zYT@7Dyrd0Are@5`fsn9LS`)D2oLp8=5U8ImHAH)xQ=5v!ZETY~swL@3vDx=&;kvBAnx8=_ zrCIDc>rjnD_#IT^5&@eyHD8Wd8ph)hTns7%Qi%-r4#49OS$V3eL`X0c%#J(A`GcLc z&xSGCi2-&Ijb@a%zkOZH-L~wF{u;?S83#w~QzAn!3V_nYWD!57jR2P_I_}wB10go| z2G~~naBO`h*PPP(5Pen~yGRbhTvvt`+GnYQ4s24fIhP2h3*m?mP+1iphp^&EvSy4% zQR47LzTSS6J(UP`FthJKe4y*U_5ZLE4r~2s&+hd3eG;}V4>2-101XlK{&MwF_Rp3t z>pCuQ(Ua&riFhX)LFGyq7v`&aZ>ZCMLBa?U(| z?S{A3UaFvx=wNIT(RH0;^0YfrnQfg!-+yBb4S?4Bl;-B{)0QOl<>8VpW2CQG)=5k9cbEblr}=afBv7oT zxPo>*k#SR_#_CGQkcdPGgdP6CX z<@q5=ttQLSci)xsYQK?$PH;rJ4abif*we77i5ak`OY|nDjyXw57#9au|4#9h6omkM zSzTp4?(De;I^LLoL4vrWn~W4d!gNfht&Ly>Vf+5jZGyM2HRK4$@6Xh-XF1vwU+nz2 zPs-NL#}W9V>mxB(vpqv)iKQtwAY$KW(rxYAib?u?vvBHRhjhm);&>A>fJr=a*kILR zqlHCd;EM=ExHSIGguC1B;Yv$)kMDfT zjftOed(`0b9sf$&y+|vwMv2c^bmF1Ojw)`K1f((bNvAY_#|C~7>;d^X>to(J;=rk<5L3Y_fAeQWqK+lQa(L^Mcv)nmc|88N)>dy)Fcu%) z`JaIjYaGt%U-B8OP`$v(iiMuefXtl_q9z~jC>mu-6$>VfP@2Zp`mZi9yv!K8_RNt? zsw^eh&3cWupXMydq3ZaK%H}`pG~~~Kv(b#+lqZvvEP%TA^>e?_R&UByR?Oi&?(BLL z-K`g~4x+Xe@J)>c>oZD)xNnF!x`a1>JM=l~d;{|)JDC`X<%03Ou>~ZK( z$ldJHe`b-sE4on%ik-RcHCqqwe4}lGuT5dHxxFTbGc>iTzjKD`z$Tdc)Lvao$nf7W z*UuFOvmnR%_k!blbioMXH|j->nIm0B%qI2!c4=|(Sl+I>CH{xytmK7&FJ}7+H8d~f zw|lzr=ejaAi}}lL3qZ8ZUK7N!Y?UF-ZJ-4KIS7 z@7C|*?^VjhwZ7m) zJ+-a(cp`509*@o{PQQi}d}sE%gdA~)>eOb}uxjb0*}Y8|m@335Lp+FMlsvZUKxj4F z=Uvm@CiT=l_-)A*KATIMUOj2vGi=;lG0rTYDA_TZS424z%V>*H+6H*#p=+yk(}#`2 zAqN(SNAxtnEJ@+P?4E06$KkBOguv)#TTb^Qq9%R9GOasFgj-P0cwn$G0DxehE>tOf2jH81ZtmSaRKE+n>58laUsUjq@UAOh?X4+upB0!9(rwg+s(yfH2X?t9 zG_)iww+pU+_c)Sq<(G059-gy_{;KP^6iZ1ItOg5sO1^hckAwevO=ilZUEb9mf%2vE zyAukSw>YZex64C{emWs%`VubMCmI=rC#cP(QWTq2WxC{R=IKE<{(9uMcfPYlkw8;Q z7mfOI?MGc#X&Eg7Eal#Wmp`QPD?K=#>O3jz&3ipwiQsVA6>B&!3l&f7;||r5vCtuMDpI3j%ln@ zOi9JDuW6mll)INjBPx%5G3J>`rnW+OFS9L?n$YF_PFK&CWX(IUkv@K)t0dpn;ar=g zHE6`rX>Un4LF`AA?Q|z`#=gS~iiy- z*lRg)E=Adlz#Zr^L`qyx_MZo{f(I8W=H$QUjyw4VF3lerUP4Ykac~p$M@LWB#x2sLTZs1M8|wxrx?0IfL>5h^2^pSt^Vk|TEL99d7esAb?wEM zIYy7yXK!uBHDrOrgXqzt_>QsQLqc(HIVGxk!BE9u!PF?81sexuV?)*bO*H`*jYU3# zI!;Fk+N1As14{klUlRJaGKZ8|tau|sJ7~;l-W+R(n+}$z@wZTDr_xARqZ+1IihE-I z!$MBXoplkx!EMUT$9)>~{1VHY75uxb9&=+yB(2+T#8{E-T6BbNJVnS9M9lGA zv2UehaA&@Ye0&SrKOz4)z9YOny+68*YrIMQ^7-E)Igo}&=fm;`sTCj+c{14bWMjXy zt@dpdZ4AoTFK3PPQXBautQN5gmA0;lEBuF{KI=(vbiS?3j~tJ(OfX-r^3vJQ#EII| z`P)4WFJLF=9U+Lsxp+x7oO$9|(S|AZz)40+N4H`R6QlW2x%Llu3>M%w6YuZf)rwmw zzpx^u50B(afWUC1W9`k0mU207y9a*(Y0HK!0duEF%*X)~Nj!MV&Y#b6d>~s~Mhm=v z9oo|iSg1cc959&*BFUQ^>h~~XR>}#@Lwa!m_{#OOt$88_H#T`zGRF;YKV7T8UT6*d zewA!ylE$d|Fa?muOd-_kD<9Q?!6g?Lnd2^i8}~3MR8DYg)q!&8jm51mW5|Q_Cm@Bq zvF{E2u$BYgD+vL<1O=${J0vKGqd?|ntMQEdWGZlb-4(&;donBzk#;vEjdtNy<>r=N zzu{vmT$Mq<3sVZ5k~Abr9@;&e{Ur@CSxqw347ESye?=qP)i7knKzl3_C)=2+FOjCf zMx2&hb~uS_42Q}TyobSW-$(^Ox`kxB@fsg~o$pF|Q0b#oM^ehv7*(lMWqHygcsB{1 zdHeYTVAF%G8vnaxFL&Rmq6zr@~CTYw3kqIlS z3?isl_fH*L?6pGpEC2)bwba$Nnt$gl?(%`e;rZiOXDj3i_dhHX)8FNR6fnw=5g0LS z4nA{1l9Tk=JA2`!gipldpWJNAh0&VFY4;)S=}kqNzX#6O5s}t)f6QQ>#>WPvq-0lqX{Ux&p6j_(N zf{NiVbV@6(!RK*k>AMEoL-Z zDm%E|YjCo%6yPPErsBF{XVj$K`m#K0uF16$SYNvaE0bc+yZ)>x29*5m3~~Qv zrBuqN#tw&`(431n*wU9$!L%4gKWV@YCr3n3@NMEjfg)oiCBIF7FN=e#894k@^9>uG(@hOX|ejSc$xGa#Yr^H_9L->WT4xSXRDF z#7c*@4*HJ-9-p@***l$E58NXoYyHV2_aRIpN^EcNV`D|T&3E*%LqLf{R0c#b%2E3U zi;TV_TUi4yW>a6k1Tmt7M>nCNx|`hZccH4A+{#cWI~YW&B(zP^5ZT`#^r`K#A12M9DDL_;M33gY1BIBEu>?s(z(DZLI=Eq6uZahgQ0wp%&&p%__Y=U#{|&1IWpL{D<`kPX5r7t>hkLYcBa`aB58s?YGuy2v8reR+rpS zj>{S_(c!9)+2#5I-a!@~Q4(d*O%g|*RbM$AcrFi8zGKgDn|I=Td&i?EDvqM|D>($>W-mUAykd|!80XZjbPU%k9o>$o$!p~AS zQBP$hted%ThH2NVQmk0V)im5&Y{W(&LbNUGYY)z?>YG-^Sx~_(g(%ow4wU7odv>Gw&f#F^2~|oF7Fg9utebYFXnvh zKQN&zdzrNr{^k1Oj~7)IpsGkrNH?razmYl6K{ykLoKFZFl#2NRRi9WGWpIj0gqrnG z9a#*2f45W7C2f6#ZlMt|YmYT59jykLzmv6M8hGa7*#=THk8@J6!=D;HVAhpe1A7Ra z<2=s0fhKfB^vVEEN3ER*$3-z64%_kf$~5bI`^PQ+df5&quM=3#LlfKb%mxKy6RRk< zZc^{EWT_#zpYFN&Lbe#p1lv>qEQvnq>e7w z7^f8Idgd-Us6^{?{F^k+!E=RGPRn8#l}WU#rVWqwz97lPWiO^uRfe~Q#)g0C&JPgi z=#hlZ*La8R7rt(xJP`a)uoAU*Z7jI%@D-`5U#E$&n&Dcg%MCK1{UE`5{|Xx0C#p>PKTSBA-DN_IQyiUhX`F4wnv3V5S^8&=_VKPq<-CppK_w4?ZF z)OjLOW(qzVp^&Pl-F4(c&T}a(Hqob&w9XJoC~~P$ihFgK+O(ufHtWz4DDhYEP{&X+ zI(}cY4Bsz3E6<{ie9pCOdS&esKlHvh{xnNRunT5t_ty+u-ZiJ!l=sw%dccJ&J7~S6 zZ}@~s3uzO!1y5WERG9mHlwZ@*Oa&2`=ZBZoTJSqATMAGznfRIuJ;^ZD6{Sr|g=Z0H z5F7M)A6Fh}*oD~yO`unZt84*pj=F#5f`)0l7tWRy zp#^e&>u(2KZqlkUDiQ=8C=4sR`8VfGwj+`3F9zag$@;Z><6Ie0y@~rXXbrCeh7Mo9 zsb#$(OSEsBUYD#{MStj|d(ajA8!`t$*WGD1DxS*v=cy6NsQ`x7%W>lk_utLcQ_xYQ zv2BxGt`xr<=VAd3;h;f-d1!UI`4gGQ8)<3^heLR|*6 zRvCrmWV7t}wyX6-qn=-w{u8wMPAnrPV$jS@(6!!Gq@vhk^dtuO?VyLvlW}J(xIv;2 zO^vWg9FPMTQ5_8O7ZJnGtxVh@7SJ9mcs~yQdT2AAs=(Ji@Ek@D9OXb=dv!E6jwie~ zI^kc9HhdELr zd@z7Ldi1?<1TVmStbq%75zHsU=xwb-v8;1rHCCiwi&fNP6-R%`tBHCZ!3MiiQT{hE zwuByJs~U6?F&roovj{1X;6%+yi7s#zeasY_n?q3eY_Lzo;OD+4{Us~B`(u9X&aYd3 ziD8SqYIHwgXgt7Hj%ol^14(p6INAgum|W(j{6bS*6~{!m5E4D~`f`UFH&RYFmSc4@ zl@KrDeh6=c$eVxhdfY4T4RAkx`T7^P-Tj9;{xxYYvDcZ0rL^0K)$niOpA)91Q5BnS z^Mj2%8REujf56+@AJwW}JS41%)*q@464)9L5kYTyEo+nNHZ9!^YYyFi=C%@egE;r_ z+#*&_-A->p{X7s9uui7rG zI1$FuyrU95WG`lscu&h!>26DKNUW&B7PE9wD>GnPWh4M<5O-bEQ_f0LjFx0&o%sv# zPo%ix#JrD<=+rHDM~*@ZH^)bkC&10oBwsSS)K_r@tUi~=C-_@f?=J+Kh?dOSeuWH{ zAov-{0k}rwB6aoGZp??vO(E7*faoYUvq14_ca(ZAww%WyLA?&PSz`y}t2EtaaV0ytT zVKL8tAk65U6z6eS?H$z_rfVrvWfN?i^ZQL29l<5ptj(fL0Au{v5@7jzV}Qr5x|18^ z-*tX&Dhl2DeDasC5T5qf{9%{+OHPV2t@hFN9JegOr6v^;p;|?k$?X7wsa_ALMPm)b zoA5{ZIN|7vQC&?o;GOvos%H&FnkNDBY6U&@97CQ$B;yfvPsU?oW%t zCh&|ZTX-aV_qaS*m3Tq6m=GcR*F3sKv+rX=}IrH;DMXyW0ba?4l~#;s?~$ekYYT$><;TC$2kkR`q0DR zHhDa1iP0$6?E~q!oKrPd!rIvcdNEt}lt#Iims&$ zV0=EkOWj+H0TzNU1YreEUu7>+qnMqxIWW>Mx8;8J7#$AXizh!KGv(?>72*+?$?`(6 zn9bG~%mpG+%p*5I=;m>4&?&6&*G-l<`Xbi(1(DV1h^-;-S8#N5IXhyxJeK9glE`^fa zkc7+>Yq}xA2 z7nDB}ZZ0uD*GNU6d9t_u)v1#fd}z4Z5#{Z+tW)8*sCtODj%GODRL2X(uR~Rb?tn`j zSrkx2-*I&^p5&o<`~iGbkw{hE4RUPj%iDJ;IF!h<5&Z*&ZpA6Y?;4AQ3fovS?Ns$1 zCx6;zyVzu%&Pn;q5v1?g*%F4vH&gNYAnI3aC6uJo5Z4}vTQoFAPsuVSs)TI~3gALM z-WH+`blZHN2NfuJ*#C0A$Z3@NGpE>0h9dCAL3slyQ6c+!OTXj%R|e6&4xdz5JZdd# ztSR`Tqa1peR1RTxZ3Rk|lgDMcp$AG=4{b_+Li8Vl9vg+6f*ZW#p6(D!0-xdw7VHd| z7yb3*E=t#9FsY_1_{mP0mPVd-nW;IV`rL1~Kx;|nuwuK?|KFEZ58Z@?U2LC;h^u5> z2$SYVEXp(6i0DLBI=-JO03NPC`4K%Q!B;eNY8?P8z3B3>ag>c;8Jq|j<7)Ws&EzCoCfpa z1oGFU`l5X6yN62obdp^*mK($++doZKF4f2KR(W$zjPEIDP?JnrOYuz)PlqY78Az5d zS#bUFS)ZHD^m?hHgo#f803}Mw%2zk{$@86*Vtb0kS^f|*z_l9t-``@Y9g7`L1VT?i1n&^A^Ku!4As8%M%^l`Yr-dN@6g2KK z?<$!;x*r-4!B_tF6%N)n%qagF4o6@Z1S(Hb8(`g5PC!T^9^(Y_STd*pZcWa*sKmJr zcO3F;oyE3+D{s;Vf5{%VP^f5H*&DM^O|$xo*9q21O8~)Okp*^LE``}}R0vj6!mL-T zHFR~5<9Tca^`05*4^vTzV~J*BT!|(sUNa8ky^o74fkOSLd;B3b7cCaieuYJ~&DFC4 zsik67_888D268yl-=a5lL@1H8ADtg~z&*9*$&yxeK7TT2p|>Q1`17+sh8|9l3fSxA zBTu)8@MdcLr9BMs!HMdNocQ|@P-TZI&nbZ_RBeKt5Ru{daBeb`Y8(vy?!MtV1nCi) zy?`zaO`6oX*tcr&fn5-px^Jvq}CnHXVk<7i`9GIrl5a0wrS;G>> zahW{R9|)imR9ry*8mxJ0x?ohLS&G2JFGL(i~X^io$ZEPVO_~1Z5 z2DK^ylV9l#lWD3{EdFTplH#Y1geFCYju2VS*s*RLjE~~)i}%ng|6kWDgcx22DT|xq zN#l~)>;pE7u5#GX`@6hk#a)d{ze>%)741X$Byq?8yO6CaCQ3c8Cvmq>)r4n;kfA^z zPzXq`{ursg`Jw|{GFIK65S(^$uxF_7_Vb*7aEKQ;q`VCmdY}qw1m%_ zhm5MXRzn#`V*U>Z1Bd4kJRx|cs)CLTOK!TaX%Gs;qhQW8T`*;CrMUa3 zmIR0p)@EnthJv9X@cO+8~o1^+StsmWxxv&$lHmld8c*B40BmHr(4EllXm;D08-zy2|E1T3p=LoGZ;F z_t}{H!|YZ?K($bZPVnoxu)~j*)&!OVwvE5@?VMBjrm;`iEc9CzZECTAVwNeUThPa< zS3kATSEDYfj>HEdcds>NT+dULSw{3Bl{rRO6DN!#>TM@sFIVV-7u*+9(RTde?H9$r zobcVHDwa?6+wDwOU%7F@=tV1Pw`Or2|H_xF*Tkl-k~jFW)juZgTVh_WE1-w{^PmmS zj0YZqm%>3zJ`S>(sxNW7m+LEXW3o?Hvg#Hq4;jX)jQd0f#_jPVN}vPbCY>T|?{uDs zfka=Y5~No92K=_Nj7=9a*O9D$*FqzXRr-}wGyc$P$Ry1`gU#N*+}z4!M*CGi7pF6| zTH*U6hHkyyP47O-=+L${G3_G4T&IR=mQ0{&>r*rRjs+ z-9nQZT2IW~`*Y;P_l37#9RKzxEvNyn3c`GrP2!^6DANi$6Xy}y7jTG=)LTd2DwDf~ zT$9Q&&>dKpt|hLP-;|PG0z2l7_Z-b@Rxuseor$r(Z~(_q1BrH>MTt&}5TyX~Zs9el zev7~8COb}t3?DgNfo0Ha04Wiz4v~Mo#+mHGi^L}TY{og$wsg|niBgWNa@I}F2k$dM zuFE)@2*^R*+nV-6fbVpQ_Ma`+OsbKW8dYx6#++Xs~HYDR4is#pE3E!|pqOLt?Axq){+B$EeC_IWc-%7^UfyLfy< zTb0Bdprv>xY-tRU^!UxP!^3oRXQ&8*R18uU0|J9as}Cf$qZW#Q2KH$PXc z^5Hg>OD!V5_;k^f?jjZMC{41d#xN{Dk~Ct+k9AEyc#1@^l>!gt{V&RcV?Ch(H0#Ap zFqv&@b$|4hRGJof9rYKtXr2T5=Ma-2Q}YO0eHE&ZyA01QDd_1UPs0_S-o%TNP*WF( zyOZZm`O{k6yr{2;_F5e1Ar^~5+&a?=b z)TLVPDrCWuS}YO?`>{)baJnarJ~CtaOtC4a>OV%LBw_}Z8D`#EH%N*RH4Dm4D7)t- zy7fEezrhPF9*+dmt;T5?2E5rRYdz)|enZl?EhX_nsD)mQSG}GS&O8*a)<8;=mgEnQ zBsMpo;N;ei`3bmolV{^%pOsZ3PGtJ>Rk+4D zjXJH*RtvY3=>3Eg?*|=U=71s>$AOoI1a*9IpKt}=Q0Qh)ijjf)j-L81oXa}~N4;}I zN1^wMUkX9WH~cO zc>L{-H=~0+s$44iw)a*o^KE_!WXj8>n#9yvk<@~9sF7c3OK#Lwjg}VVJ-o?dR+9UF z1BR0L4ih`M(Kv>tA6Ct3J#|Y;Q>whoeC$3>niF>WKJ~h6P$It*@Y(=VTP#Y>pr!x3 zxO8sZ_!Rmdmf=EdCxH%!U9?%Vz>9=A)iw=RpM%iD?a(^Oy`#|YnLxGp5rY2ZK^Ed2 zQvsPm!)fzVF(EC19>~Rx5SB~5JmixnQ+eftCltaVAhCz1R;Y7veV?n{{-(#>Wo1|k zCN9SG2WH%hoAxp&IYoas{-pUP@i-ws_8&YX+V~s5v}qfqLU0V@#WBhH_cgA-xM7_% zG$euZyB+$@m%3Z5Ep_sJjrWm2ONE)d!r%_SW6)H!??cJA(`>sXO2F>(HdhEJ`X zP$?Ph@pr<-MUpE;LE2B6U>=qAT-cxOL4$dkW6Sy*!yfk#o3oa>*1;VgW{u*YK5FZ8 zSe89h>}O@dFMx^jgZ6G;m8d!f!R*c~;m|v4`t$T~{6vy*@w*C5tVpjZf zM?f;B?r&NJ=$(zLxt^95zdBkk-j;uKqHOlRv;14`50Nq*sTQyqk^mmu=$e#UX27_Y z4Es~-!NDaXgKqt04qontla5!}x*5|P&5SbKbC{D#yWa3Zwjp;szE(y3rBA4WuV}j$ znKWwmZ1ny7`>FBi!7UD#<)Uu4K>|}v19S)B^87hvU7}-BC(0cXi;+L2r(?fT_+{ZT1<0Z=tP(58^?#W0yuolH9d*J42sZ8mlGFaUA0B6EYj;rj zs2SEpCC-KP5~!toBRB>QH(q0u(Wfl2wGL6M64{d$Xn*Dt^S8){>EnuC zO#!>MUyDoEw*Kwfk>@S*@uS_vWNU4IVZX(|SQoJy!Izcbpf^wPO8j=^`~VdDK;#K# zpT8F)V<|(EytFLgME^-bXec=tOiy{L>})qlywApk*S75lb}G{#UqE+6i8NF*FA$sU zzQ4IzDVrL)oWgc;^3fGe;&t6B*lr6?gL7wQlI%b4kUR>UHlokcLStn!N%~ai;KP## zqvGr|hEF&FC^A$C$d_ZQB~-{dd*1P%xmAh8rV}j3y|VVJagclid91rDq9%g# z@_=d+%uRPqzwH2nk?sB;SQ7`=J{Kxxx?jEefpfBYMCr5d!$R$Ld)X5f#imPX@)UUT zl$w|!M1rxIbdZYs{>6&{MC_ogWB7BMsV3AK%RYhg`attJExPEus_uey8 z>*zUN3IyywR!7KB-rRq%vABe2h32;P$EEV!@-GhoXC2>6!5)Sh6c>{fLphWHfPo65 zRm{Bpy`1Y~?03xbMPe>-Rr?>-+9hVF{^dmJX8(3`wLp)neQsq*6ygryt;^iQjW4DY z?X?D>>iXq1hDVV_9aHP8QB2DlDG6#~wyP3xJkK2p9OJpQ zxmmw?t_B-6pY#FAem?-CBfwQ~YkIamd6;SlMlTASfs z;4vg__t}wc8Dy1IbH;Dfli*`TWcgbaCi^*hkrwwe+&fQrTy{N}o%=mGCK@0oCwoFh zPM0`l`S@(4C$!qpYfZ0znb-E19h*s{_dl$-sistT3f=%H1i{8Ha5$EEGP9OCY^7`2 zWU3duJp8oGfiW#jzc*181HwnDy5!s!1cW@mOVE9XQx8%y7ffbcK}rJzQK=A7SaSLg z0_RhoR(%uc>joJLx!pC^b7bx?yn9V#cCMh`V>b(126Z4Y84{~v2-71dUtMO(bM zL!r341d2NZcXtcc0zr$r6C8?bTigi}pcD^Q0+a&5p?J|2S{!;`?)!TG@1Bw0WF#5m zoaF4i)||BLwy1`{hNbXi^-jCs(Y1ol_P< zI2UEAb6$H9!mqZh@A1xF^uCW7S?WKLb@Bcb;8-aF(xN>U7O>Wk36N75HRs77K16Sb zo^|3UJlHa3xDo)3tNjH&Z_;9ZXUk}0FIILY7j1r_>m>hny*o%v`;S~!k^)~hZ{d+% z`-jPTjZskhC!B~?V)=&?K}D7c{+Oi3LBVA>_(_dL1?E7U*CIfa+-}A>=bJ$*D8lN- zhDmBUY}_ot{glhDmOj_G*Q2BC8PLPeDQ5Q&{-#bM%&-`W7wGU{-11R80*t=teFf zkFB!=mpdR(3#S*o&7!NIbwv><=bY?TwEgzp&C9$dRc5Asoy}2s(YE)kOX_EAdI)lm z;@F{LL-7S)2-?)w_<*40Tm`bb#=f}OyXM|>aY3X#QOYNnfc$qIk%JY9P?SOgpZJ{n zE~8PI{XLi4IQiD(m;cI z+Yk?n!^1wc(;2g5N(deFUEAuJwy!0?rqc*aE%3@Hu>?t_KZlUY~K8Fn8ZSuvzyV>gKr{-KvAsG zxEhBq;He*9G5*7#D~Wy#WckY=#{I5$l5N`+VXKtf$2?eKp)^PS{M%}9V6_dfPNVz) z7%|FWSxR{+ET8(n)J58-@s3*!gSE@W1HBRu;IwCGclH>4zu6cL8n#81lza00Z;*n> z!zG32nOSdmROfHcanxk=;1d_ERdv|=6cwx3dFnl_0_y2 zD`-4C-W#5IE`dQYW$-F#sK+UyzQJvuRz8sxi+g)plZVif1^-9TOe1Is-Cy0fn} zAecIxku*cM)1jJccKCY-I*ehztRv4~@`@Nqv1<7$8{M%@{BAeB)3Hlfc94#v;;_!F=>RGuyEZFWqJn z`EJDMS?sgr&mWCWW%mQ3m<0&KW|NIQ_(l&;0R9O}zT&9EuJw>4glbu7A0F2^I2W*G3U9OCX$ZQfnt1EgQI2=atE{56pZAR{3bt zNZ!no&NXJWStDcI(|gwWS8Uk)z`^1A0oeC9{6Yxi?6Y3j=&3v7%@JR0as@jr@lXO% zoV7#0RhS^lNwz>WXbrgVA0PH<%Fn}JX8y7M9+W35-O;n%&>DxZpE38K4=OpsxJZJB zt`O0OP9Q&^(+OlqXC7;Kzd}{-q`MDj9u|Mog~?@@N%uRa;CQQPn7WkVDCCB{8kgVF zC^h0>tVB}vi@a-(%JK4yjb08Z5JI;ie+@v0`Q)(drx{>jiY`OqANC*+vR_%n9!|f} zL&ub0A11{&y;>)&^MvuD_=;?O+1P~L{4$)Nl#~^32)|g&?Vp0cw&6xra0mGs&h|=V z1Or?dNlJhz`9q~=XebRnt=*fn-g$D-HniUL*F3VQYVtF1)UeBmp&AJIC5}0;h^CEi zR>w_jiCJ|4?vMStN8kl&+=Jy~6x64cj#7VK7Kk2Z(V;B_S&ivTy|xgK@D)DztyR?Q z)pWSK)%(R3F5$H{xtwH_Z)S;nnI`U(&{-ULKvtCxBOQ6Pq{$p`TOPG$u^Myg5YddE z!W^Fe_RZ<($7IDp_CKg}t6NaU#&v|OshvUmQ8aU=4Q06hN@eDn8-%9f-$1>&zd)pt zCB7leRg=%xQPX(F9LOPVWaRfl)(}Q{r*bJ|LYM4O4;x=_kncLe98pc#Or=^a&Q}jy zus*%ECv((sgSv>4k&7byzb#k&kge$J9*|Hd{0j2veA8*}CagQ4{n^BpdPnSj`!Y9XO#0W&`;)a4P1vyZtg4I1M~cK(ck#`6YmeR&lHu>ejWgFD z!M%vMHOW-LnpCg4_nMNkh*Gkt+Fx0i$%$CYj0+DnqZggc# ziosM~X6gpbl2jaZwoMSQ9^#{Zi$I3b$iqM%FWCvQoFP+ z#I#M|v0DFwFGAw3S=jK?U&%SuFV^mSQwtrCjR^WTxv*p*l7^INV zOp+@_5u~Ko#LEw%0}}c2H@p4!9zob1H1YevN`eFX zn00IUYve;bj>LkU$`084dCVWwPYSEoWrx4`qgw6HwE0_O#yGp}l4VOJ)o->GRNu7n z=7p*{m@~il1s(!0Unpozos!GpuXp|G0DH>>1)8d3>pU`f9pWHji!GISz-w@419U&7 z4-bD<#-`~=by9XryY6qqgllN=A77;E43G3oMET#B)AzMBX>?@P_E{fqs$Zwj%zZd@ zt91d;RyQ9u_d!p*7#h1Is7@cfIXrO1*vQ=LEa3^aCe;QT2XL|my>5$SaI&PsWM=!Y zDj!O_8)&)Gw0J>d=Pkxz%`9Gv3``l;WSO_gP}_76;T=BB&#Z?oE#StbAXlz%{;Wr- zc8K;pvZYq4g{(y01>ei)%klkMaaqOfIY{ja-CgxRN` zp&skt5`oEAUniWJKDwVTzpo>4qN5t^)f$R_WR%?w^9Sr6$ZujF7KXVFY&=M;xM<}9 zCV_%GmfdJhw&`!$oy|o?4dz+VVmOHfGg%LAy{s-gB8>vpN-CMu8Q%Of)|x#_DgT(M zcpD29G%PMvLA*j^`(6`S-v2iBig+nkBs%oe^~mi)ZWvzq-jz3Z_M>oLgJpEI8Mg<#oqq$fYlQ`p9DQQcTGcA`gV zVpoFkaC3n0a=UVZHdQ9o%h}h|cR}yq)zlXrzhWwDoU0DBuMMg>&)keAeH4sYu}cJR zcLMvr-0ZHdcS#<7-?%TUlw@xz*97AQM9sI{2zcfT<}JqPV{Fx^0-hFH4IN+^`q+gG zdH=F+^9atG*7I7&HT)EcmkgV53nfN|mO~-aaq%O=1M>jLy=l0N|3PMNNJYzUIcGX=qj{8lruK3)^q}CrG9Tcca6NKc3GB+F_SaRH~6f}i`k zpu+qm!**hSjd1PR zgi^en)d(!-G&qS?A42@iE_YB1C<)#vy1np3fY)f&Cgqx zr81at6S)q9(>cYDvaCtJZ}f#WRcvyn$!wn-Ju%MJlejT;d&SJrUo!@0I9^`1eGswU z_OokNn1z5tzeOE9v*Q$ITc78uG&T9Xb zVlc1J#5mAQ*rQg2cYC&JgK6R|UerNHg6mX$y4L&%YY*Pi%i9)j8jle$QIU!{|)c@MX}o?cu&Wos+9A6CQ88GDf> zI%|w!=>*6!ceGGfDmm8nIP5f-d8d~sTQzUueuAl}z@p;nC$W~ff~^1a3)F7XEv9_r zOOdI|x=`mWBS6+ifVZ(5%l=!aiBl01{oGp`rVLJyE35yP$h%3yA@kM8$oCETQf@k4 zcA6i*))0xAI(&>FAAe=S!EV48Cln)J^D$HTrKL}`k}o26iZYu_2Z2&Uil~Z;iWrOj z-$Od3S)s%^lhytrlo0G*`8eDzNi7bFdP^Q>@dSjca23U6a2TX^U(`~iG+s+I{W&rB zs>GxZbS$8lcR~aTa@{5;v$BxKY|~*62!R@fcq#N{w-*LH;%o9UqWNiK%VSA}bqqB9 zS+NE;m@~}EcZQ8>(jqxqRF9R%#8h9~X#;3}Fx#k{W)~*^*nhbE!!a@2%OzS4{kOYL zUOqT;pYY9G;b3`z=;-0koc-~Hf-KNMcC=u9B^UgC?cJFg8%)-cR)lycCodClT<%t< zE_#XhBTFI&QhAnjQMlkm6&A#%|AW@%(VB84Xzh35k^J5j+fqwxQAz9g(N-*d0+Skt z+T-Yiy-Hbzk~f5#hDCLJk@8cQo&J8TP}>^##XuWcXKAwz z$D>CGL<2}#L{$H=#P}q`5eO@hGOxAR4Z3Nn*mlXT=3d!pb7C`2NCUXIw=jRQZAi&? zv2w+kZH<}Lc@kLv=tT468b+J61tVJYT=~@vSmGDG+VB{{`=e)iDRhjVU)>C`2n{wm z`D-C+v0y^N0aB;-9fV$TykV`8zK+^HIhlcwMrR)0@;3=bE3=oZtsl0x zOw+1+t)fFs8rDJ0+m`Cg&Pt1otxrCzelFw;2jQ<$rmec%P4o210zQ34GpXigR&oFg zC8we08K}dfIa^QHh_cxNzIp>V#gfB@qcAv>b?tzj(E*c?7Y%e$ z5E*}@)|OIjXia{(7!K6rsiXj4lcM~sBJAv(Zg&MUAeW3WW&&Q%lsGjmw+*cSTKuB)#25hw{Z%_?a+;Cbz2G z?eUvv$gR5;bcNtO$3A~#Np7YaE71#@_b=-%P)6bz(9sBa5Xeb+QmJhpO&FSl_$RAI~bC*cjp%aUyp$%e^ z9HTV#X32^b-63aHfQUm+W^@5h9H#3`Xu!JPLBdB|3@5A680_c?)Ya#bjEq85wC)$t zL7?EDtHQ(fMZF9+no7G3KCxl-cO2@(&LUi^YiO%T=+JMhag8G2ScLqaTHkxYjncz3s2An)W*KhM9g_cBmm-OK^tbYVxNk5S6uQ^>kNa3iN4b0AfVMktKs(pnzuPP~=CI)Q)nF~tq{-Jn&*=18+5DpTtPem8 zhnQ%=4s0?U=`*jUjIa>!^ZN>VIUT{Bsm*$8j_ku3n-Z%6J|@5EWt(s4r(qEoy`1z7 ztM48niN&6;yaFPn)He0b8jafaS}5uggb#mVY-W4%+4|lFWLD!2v?eu5PUNDja-c9QL~Et77f8k5_Uo?CB4zNr zs)2b675NI}ZB~}L%S*G`#<)cE7XXyrWBN!oq)QfR*VqOVi3v8NaN-DjY@s6CbvvdJ zaP-?6ldaQmme)v;A_EJFc6O(0Y0ZdopT2EP<8<+K`aZo(hUd&P1*2wIUikG;xZ}d- z$&tjuN}r_M6-q6z5V*aW*Y5o`-M@qKfN72S-nfYm@{Y2E#qbR$L4p4UF4y`B+(lr1 z4jaWmp&)uSYyw^8ru;_DmgAZC7EisSaVC1K7oUbzl$pAeYGm@rpQVq=-qmo;GD}jL zUx}!Z-Snq9^ThHsZl;`B_X|-uf>^8lr89evNy?4%jQ%{xmc3;xyA$hD>ZuYDFPFnh zTZsEdADc;?xyVcA_9BisdlzaIzAo>Q?6kZHTVc~M4TA{V-j@NKom)0_Ys=ip&Lnj- zB=8njHsN=E)E5s>9^C?G{u~g&im8CKb|2oXNUVFj*=!p?R1}9}jUa!@^Y>Smmc2iY zX%V02$y}y~h{7{8&K@0Bb{h$CIOU?TH&ZzvJSwEx^0kgBdi}i}eU()48yXF@E&MLp z{GIFWiS2}+bif#@s%&R*xMDeL@`EzB@wRI|j@oO6wtKPnvX+ik2%rPYw;d{j99hXaBQM8=yhx@8E_!mTvR# z{!T|-36+a6OQAdU_?4Ei)0&yoKfyb@xk=t+25KY&xc92W6mix_?_cgL8S{(N^>=|TSl3lcPjqVM+`Vn~yrbiBsRzVC9xZ$fMdBc;_=gJap5bP6Ebsq`Ozg$R z^U0c?xcM&f?&CWQd}JXoLe{)q6Tu`S1!kn;-spX%wN1@}gO&%V`KEVT-e1V4C$%7q zn-1d93Dg|j*crcjplsqD`w#EWsTGPodcX1FCKROZpZ!Bn>T<1(iL6a;t>w7+Q57M~ zMXE}OgAPZ0=Ca0_p962ehBj}-kvIKmtsYeFGdf^GFp$Wm+H~VHPu82224@9**&PLHnUCW+L4Mm0GGw% zv|xPy595-oD;?qyj2QWaPXv`}ZrYbxaL%m}oY8i%bvCu;Yf-BaN3*0N*Ts0X^E08! za^roVR$!Tlsm-w6*QF^YqB)DYmh`?Xqy5;fY?wBr&}oz3y>LFK9!>bM&)3B~dm1FV zPH+l~=95c21#gL|`PemfXx2sSD zT%SL+rD&X2!K7~p1(@v%wT=wO&yqT0gPehH*100~eWy08MUbKS_GJD{fARRty^+Q@%32&5jh%ubUvA9;HKi{2xT|Eiu+WqAU?cuc~v~^E!jbh*6L-M%fk9mhI z2Q_?|DN*dzSH`aC8O@!H@%*RYy62-eY;$FwD9n=7&DW7wZJ2kuLN1!qss;c2S#M?x z4V2+rATV5Vi7!D`gFG3t_aYH`>l%5;G=0+j0Zs-mLgBrLEfLtFG!$A%=7jR| za*u7?_g(ky!B^uK)cacHtYaQWmedzrRqN?u#W8uxzrHvWh-AGW)1auG-@LLVIxspE z@3MK;xeh>>%wT_oS`Np+hUonL)&@0sL@d;y0mGm0MQIC-QzAPaM}vs}shvy$!u;J= zb-$e1jOZMsfR~ir8BKvFy9PO}jsbgrt$NWV@ON9_tA=!i*rUsR%GvVeUmbpTVG z7Om~n$80jf`fmyCMqF>UthHL-dwB(|O`5OY zKUloNpO*5>HIrz*sjhSg*>9{^Fn>cK|I=bwUNWQOf#A-1Q|kQaE()c-_1k|L`S_DO zWo0FaA&;k~T5OES`zFq6s8qyHdDS785T54#ze^mq45+hZ!kx|z+Ls%@S88&BW=e>t z>haNY#A$Qkxc|LZoFgL>m42#Ruj||IAMFk5_^CjWxzU%zQq-RLE<2|8fWuNZnemc> z$^X-f-O$XM*)0h+pIAY3ORQP+fKX!o$@N>RyU5Y5&Qz_Q!^czs)hy_`QXQh0%U47QO34 zTt(r^BAc7SIECXo_4>rsOIDWSuoeA;9)>1~PKb)K1A!)T^UAaT8vXr^EqWJe47-7$X~kw^@9{~> z6*_aA9m}dBuzHg-5V3K!Ui}Zr{f6amON%a5_=E%ZAs6I66Y}r#AyU6o>(oo9-#ODX zp-z%9WY^+@J060iyIdr0|3cKxBs4U*}r5d)lK zR_0g(X(`O5nnpYqb|$Q)!MvHs(1!B=Jn8h%Foa_$C8DW${%e5D!7~S&Qz41={91hGm z7wvWhF-r9)L&_!%v#o1z`4@foEVMZ2sy<~kJQ!OR$vX#i@GPR-(42&FI>K}I;}`uz zZ)50zzpb_|8G#-9X97C48Cx5Hg5Mu4rnV~O=XoAAsgTB)0(eIS`cPJ7HjE4XWwE4@ zz2Bx8FjwY!b$Vp$poS5?m}K<5{9yimPNyrpe2y}=ACtHm zTDXLSuDFC+Sn=Zy@rn4HoU8#Wt9`MjRX4Ny9oWV7XP|XvmY2t)lD09Yr0hQI(090* zYI8&QGe!}m`A6-RIOosxDNozNi`i;!nqUm~A`7pQ9>?fy0va+(G zDm*W&2J|Je8K&%CIJCu**|Vj!6V|)=m_dqivqY59J*0}reExM#n~GG4C7%EB*jm3Q z8dMu!dhms(IEtCYKPaIMb}XC}LQLY*;#)xM?9M3Y35Y{%er5*{mP!32?pkG04`S;H zWGT$%W&yAiG6T5DDQIKK$yf?e>NeU;FBPAomf%a;lUuhJ0S&XxZ#K+3e)hdK7&tCB z1?P|wC1X!&HBE;0wz$x-aGPXc>_b7>!Gkk)a$osKgO!6t_%mPo*LU z>5KbXxvkA+o5$Y>C4uVDQZTB4oU)5DK%l5;JIyP`zx{jQ%P_|>N|(bdp2p8Xs;*-q ztmigR9Nhd?-%1zR)0@HS+#q!TsUHh{0kiO3w`uM zpSbx@-QEu^S5_^|1q-4%ShtJly$@sBZOT5dZaqJbs$6BV}G`xgl}WVA*oeI0D~Hu1p|q7@Xp&zSVFot=XM zi_kLdii3hw88vSMP*6~iNzcpj9UylAVvXLy)CSX11+}v4Ixbm>2(3t%<(eM40YSlS zc`P3-jnx$Nr&bWJGcW5ifo6x<*Rjb^Jyc0aomJWJ_kUjuRiu)>EGPo#<*Mp7pxWODxk!g?&3X;VQj~pU<#*r## zd-fMaAP^76JhTkUdwjljJq%Cd*kzOy80?43fUn7rxrUA_x>s36n+a|bqq}YOA{^ID?@E8GS&uLC z2^^gXo7TVg(9mgdY(i&=qh-0y&WCokKX$mBH>}QVcD9KLn>MXXISC^M9?l!o4lN*l zd6om;HLe`kFbPQC3!gzbd}`l#>29}ogVUGvug?Gfsn#5 z``}O?LcI5EkiyoJU%S6wdt7{8DUJL-;S6hT5|;iZ#RGT7IiKn<;#ph#X3GG1- zeM#uuv`TcHZA_Oo0Rq4p4A(80nsG!jls~z{a-VJ1z^d8B`6gBca&8Y`$9m%n3vD$P zU+T@6V#TE~<{<3G$QDbZ&4$_iv}DMU9rf2M5u*{Nh-fyBEQlYQ^!dUX9h}W?4e1-L`*Z!+_p( zXp1`#sQI?A4QTq!VD3%B$f4So^pEE$UIL%CX%7Cy@rVhnJ-9C;_xqDUY8vqe>Kjo8 zmSoFkZU9n$%wghQ;i6)i^B$z>w9Q8Y{%qdLq5uFmj=;HiBaS1&NQ;_{{Ub4+tD)#k zrsI06r_*JCu)0(?27RK{c_cq43Qhl;9$;{65YNH37@GSeDD#*2EN;dN5$O`^oBCj- zv}KxVo3HC2Nps@Yb4(`6KI_aL73nGkxv>(52}r2rtGxR~K#3(&n@dg`E#RW&L8M<$r4giiC0@|FW# ziHD50pm++m`yV)60$KjcTJ#fJoJ3#*iw${3rfHR)-&)ocN(l%Aj}Qw+Z6J zYG8-J46IZ86BchaT0RCIJYQi^Y%U__wBgX;%=QpAdzUHIU9G|7FHS1Kywx%tQIxIK z9ys##;*33>yw0nPaBcP!C0lmpumI<&w$QMX8#bZt-;(0{LgE*UMMUmt6RYoSDa~@n z6lo1gwGW~>Toth<34580a;VaC9(pz}pO|SyYmG$}Nd+7P$2<^>|3T9~EAVIkWb&|Y z&a!e;cb&n>e<$#>xkK&d909!@B`c|QV#pG^=3C0>;XX|!%U0LASy_T~_fp_~m3pbx zMW`1=vNyBP4I3*t=`ZW(&d4{bk$F@(->1~{tE${J=MonZU752eXiHDHBnQy#JT@}) z3ip+Goh6wxyKXkLqQFq(H-LJH{uJ9NpV;Z+v09{N;#fo~xj03G2DrJqm(Stcxk8e^ z!`;o@Sy=2Psst;htmNdF5vMppX+RJwIGz{%+o8P^^!qMtV7GNYqN~p?EY?T7($BW_ zy?s5bF3-NneeGC!fylP=Rs08o52zb;+Mvd#uHNpl@#U=&Cziww8MSFsSi86gW$fm} zr-eMy<;9xemqTHp%_4m7RP)ifa@dMW181i1ro(pVATv%uu5`g0X=m)sD~(Fx@W$m< zheEf2%$M>H1ceYGA9FWfY<-HjFO8nwZ0Fm=A&StxAcCaI`&ogsNfmdATE1G7EfA@@ z4ndmkw6R=WE0eDvgA-I<7=FGnpzrLM;xkoz>Glc@>Vi72r2*oN6$EV_o{C~|q{m82 zu~Dv+vns{I7X7^~o*UI?mKO}2a`pQ;`F|XW1*Mm)knvf`pPV5+U{T2XL`{MBP3@OQ zuzWAr+4^~h@&Zkt=g*#fyGFEm!30rk)=S2pZf|g~2oYEHWeVf8n-h%UA6@_5!wpsz z{rqD~U6nuL`PnXIDhfZZlO_kV#7`xT5Y#@l8M05D-AnC z`c{A7jitfSS2g>~zjM@ja9-KlA(P2wbzRh<2jfitdlZ;Z1pbn)Ucy2=h`n@6iK!N< z%xIRNPC#wRSyDOo&r0uGTGv`nshR$Z>`J{sWc{$Sm7q((SmI~Tq23XXPz{Y;8pSbq zGMt7`UURh;%fbIw$D8kl*cpRnIA671WS^0tJKW>NCSt*Jb*6yoZ;ED$_K6OZm_`=% z_bM}7@ak%|X(x>Wyt8@tO9XgNQTg|b#((zRoq;ET46w3cn1tz>-1EbV zrq`BXX#p)tX2-M*ui^}g@B+vwXo}p7b4B;@rNvbU_GivjU0|1C*%xa%!Nle--CLLb z`WKH)zGJeDH3Wdv27c?@6x3TaXe+NFIxP$%~TWaUYN&|@96 zoSCp%Tsa+-+4s6zn51b-Biyf_8@s`hJ59P=@*LGTRBIQph1@jBKRrc~-%@7d1umJD zTI-z#@*oawI4L*+Ip%+n@2EK7I`{lS$Eth`L-A5^hddlsA8VQNT5~q@#eb|!?~2cB zGU~DKUs+T&XickB^u`DNU_Ok9<|)UQi)TBxAEx$$$#{815g}a?xtul{PRRXoqN@Ys zXWNzJ4&J+%TNpUes}wAsWt06K_@B*lJcys(+%pcQ50c0fPw5)>R+#Tok-6|YSd_3D z{C-r({nWM!VEw@y9dcCOv2R-u^N)6&W`i~$e@St4QYTIK;P&+=?L&vOl*r&`R7U-| z>rWA4Pq^>>+x5w{=;*JdDT*$c-l46EBRORJZ?zdeo?sX=?7B)GIsx^}6|!gp2_~#- znPbYU7Me=KhyPv4_sytq?SjG-HS}ebbcTVNY_1{tEbAv;=Qbp*8T~l3)|+$pfBu%Y ze2JPqUw@K|JaJVY?=IReZPp%8oOxDs@b&g^U#@A(k$JhRi1y8oj}|X0mR0hXuv$29 z!f{J%W9cg<#UM2t;b)u=PfrT`51OI5i*L+cCIqiM6cC9)SL^$7av4g zr1aQ)g2P&kQnlX@N5xWsN-RybJXbwXM}53iA?u#+-&x??KRs0ac)e>l`!d{(r-Q2J zb|6Y19g5`t-kuiDvqM3#Sj7v;M5u3IaZtb^gm4|lk_9(T*w0P6Aj&;i7Y|KEr(a$9 zFPTkFJ3qbh7r=NgRVX-yIVVgZ>s}Po(S7obuE;jd@@~Lc`Kxd2ALYG^o7X+(eAihO zt{8JoX}`BL_7o@P*X|yv<}j0MuS2lszPG;Aq62;3WlmkhqZKDq$Cd+uSY`C#{*7CF z!+oPs#?+|E^9G~L&g9c!0n)DxsZ6bXxE-m+ice=V48nktVdIap%7fgFY$DaxAGaxz)#wzwNwP){&xM$R zI1GszG>n<6a^A3d26(>s#PEweuAP)+jaB=-WsP30W00B(4H>{{Kk}`0VPOVB@F>> zlXe;g8L{d^6YU+{J#Vvci>|}vq6Ct;i;}MkHj$gDmx;3zX}YCBhv}!RI+OaJ369Dm z!j%(2@~lAC;G?6%kgikK4U3N93z^QZ_{P3TSxx@`xE-fnhwQRCTXI}7wY};sce53E zBTwL7(9?}i^npKum-9nTG8?H&vJ}m~HuE*3+Y#4 z&AmC=oh{A^PusuD0s@ zPU{J2Fuz1dtZ$Iw7 zY(8NTg{2eAYTm-4FP)*82lD`g4Wv+6)ofy@c5yQ+`f{O@kkLR+@vrMI(L_}LZbA1} zr5F6e;)uF=6A(yMQzb+^vzDu+;{pY19+sc(+ko;$-1j^gtegS#DRkYzzr8AU&QX+} z^1%ivYe>bPfBGMeGXLRTpbQhxVg)a!yTa9#Qh5qDi-{_XJP!$~0(eeN%pFdaSI6T;0VYD_px+%^W!=h6=LqsSi?-r zJHJ+{LsaBbJIggg;h#XEuQ_o+z#7z?Hn#A&CZM*U@XOAAS#{JK**Y(2Q82aV2Gr8D z6eqEH&xWQR8$QL!cA#d+|Cp?%2AYT6Fm6vRn3)5j?qccY@IfwO7$9d2*G>c?R|iP? zSx<2!IJz7p6ne7bJ&T-6aN;T2^v@(;KI0$XbzGLYPB%3uuGP#^Hq|RFx`Xrh|(fmjGvTc6I z7gs(^E0V2AokE0+X@@pLepXxSQv7mi9}xT>G^VpnNX5o_JbDfl^wgw9X23zWmg}oA z))=H`98D&Cc2M)lvg?YDZCpmh<)F;AyN!lEQgE6tn>@X)g+L0A8rg$h0Ecfk zfSv=;8W2ghPSP60Wcr-)$A-viT+337|2jL)@zuE|yVHBE2Ym}pDT&8mgo#UHjqB!@ zZ2IIwFb8qFj{LOGo`)&%v+4&CuoZmzcz(K18ymIbqh8%!?-q)-4Jj2jt5|facRKFp zJf*77q2&%p#A>3S=0Xi#Uf6J`jdD%asdXEBxU|gP*)45{tgoDp?+CPlOo8@6+`&83 z$&#x!dOg`ITwKd1RHX8*CL?%K=~H_yt|%lu==SDfvZWla;D&;i^OF;6!gA75?W8Fk z<4*hsh)8(%cVd!WSE@gaG`8IxJnNEUpxcB%(?D+|;=R?85K{G8r)AC^-xc$si+mtV zBif&}6C9-y;}IqAmv?H5Wj=AHIVB08>SX~Bc_@8 z!5bKfzZYSdXZPW%&B3d5t(yZ#dz!(tpzaMan;XsjG`phb6TY=$(+L_f%{)jjN~qt~ z#uGGePLw46y*AxN#7e%(6{u=j11!}>6TX--NTZx3?pGx{z5mw?`*^d$4t2 zDidhU7OdWt#le78ME_^uayeOoSjUL&YZ*UMDQJ&BO-yy4r?O%9#ZNx8UPO*lV`nI( zes$o0N6vxA`MJ8_Qd8)3>9|S52>m!ibzPHFJb3Bt%ONz{OjlF9n`Rg* zCo(K9@azJ8vs=5+4VMJRl#pblx@F5k`FS6IB)9+Yol9vW(J9w&d2@fnjEh3ac*2pp zJa58|);dk~OrG{e<|udIE_|o~Ep=c0fOB-$`Kz}4V5Y}SAG;yZqyy%0(S=D-gjA+6 ziU${a-A>O2kVS*&gu|&@Xk-r};HA|bA$u-BC&03hq6tn=afZ{T5zW6J3ki?OtiX@u zJr{n=Q?9?_CU%7`N;wfzKYs3=8LsyN`ZKCpYqd(m>u6S*kswv)VNRYnVFMM}$xh-I z6*GOKQ&|M9x`oLk3G6k^^9vU~w_=PzC#c}CAz~}F94)W_17~6Ru^yA2Ey!H-B z9-w7c{utHF2c&H~#EAT)-jTVHvRU1ykSg3;;3}SU;AU7;BA=UL9Xe(TTNpF*C|c@y zSO_>K1J(#=_s939iu}IkA7D+sYxOmrX{G1h=%HE_r9AM!d-bZJN)=sm_mhj;CrZ;L zfhNVz@l&K9&d#7-#n=PJo%(!EZp!2Ihn?CU6}S=D zi1aVat3{JD1vPb+{T8-XZ$1z$2*;+PEy#Z(W5wi;Nq&||*QaxB?@f8M=cg8sJ-D%p+TsgX6Amsos79O82Wgb>CuU>qUg5C3*K`f|jpHuZ(Q} z3r|Lz(?>D|ofSWpygR4s1+RRuEj`?2ZM3VbeaVk&dY}riZ>Mhfn)emGp_~RrsGG6Y za3Mr-B;T~D?ta8wc_L&|{bt?vy~}mcsb67rCtTMjkq`q|jiR6|FGaA{$8PkNXni!| zQ&Yk_H|t~X_cx1hyA{5pX)8C~tS0&!+)FHJ*KkuZC+hlJ;L_C#EZ z#e$7+tbp<_lr&l~a^@6u;pO^7{;Vj*$H%?gFVU{!i-<*Nn$4BnusEFD_8LXhp#R%0 z7s+*=+rAmM&oGf(owc!E=WSSbYTo2eb$(hY}Pf0r2LK)Wc+ z7Jj!HL4ie8oZn5OSz28T|6n`Qt}(wqH~w%YJt%sO@tV`g6YODMAT7ggEn zm`q6I+Nb^PDC|oJ!4ctfM%sqm6-&w8tW4m5x|fZi3L5KVnAblcVz&}QZMr#K!nkry z{OII7&O%K=Pwr_Kwkw-up95!Z!5h3n+o*(OmkCQfW2+mXKQ$)ns<7v@OtNLL&wxC0 zP@<5Rg1b?#(V^Ammk6uxlT+HJu3c{h>rF=8mX@Xg?b)s8**1j;jk@w#enIyQ`7(r{ zN+;^nvi>${gU{hb`Pl;a8%I(w%G3WjiTtX|6})fB+Ez?%sT>h z)Vjl>1qoe-^OR2nFv=-q5oe)P=D#wtmei8cySWC7k77eD1<_B_fp)QB!uEt+&wr1DJj-M zad$870ovkDu@-G{r#s)4+2_ZZIX}*qN&aV&HEY&;KlgK8PH&9DkgKf=qkjKTzDW>0 z(OWe(P7g&RSxAlwL84P>S}mei_P4EiQ|9`TJggI z9w`@%xH8bWy0hM)eher!&4oYS9Gy{{^WJ_E^EhDW3?Nf>rwEaHPxzT^2A%fEt^8hm z^c3~>v2p2PUsj@e^M^YK>FOS=Z|}H$!v2-Q91F4`3grEqT_fSBsc1SP^hp`n_~C)y zLZNrR3};xjyy3|m2EjX3vvr9@e>H1+V&67a;bVGzQI?0rN5f*@U_q$Zh2)jE6akY9 zDGO&pb`Rr*er;dW{;+eP7(AC#^Ar}QuI9c-er^1k=qqqN;SP&_TcDh;HY21IeE36n zu1FHcC+F0Qg^Y=V_FE&oX0W3y@nuuY=LZ5!-_D-zGeX)P%A^yrn++U8T2!33I!aS11$zhMJn|BDE33X#dZHKn+&l5%cd17V!J)>F!U6m?=F7n<=}uco zotWWJZW@+tdsU9P_H7LpmVzb`lHW<3I^F?fG&Umf?NaV|@4(q0+@=g!PTS}r+wZ2) z1Ip2#_mF=Xj&M$*7@o7O?`C@gxuonO61laXd%S!!qvO2HK5`YA!?-5{+D5Kn&DDOc z&0ntyzA+~3vTPF-&iV8yBavrUzB(LVBWSL-Q&NFUA+&<@r3UZS-89>I>Ne4ofVu_v=7J*&WCntkH zgT$sphn?olMXh{KvP|l%z>5-PD0rwT>d><7|A0;%w%N?g{m8r@p1663)!gmLC+&>Z z7hgA0l-OwB2tu%E4ztq))q2g3L>^!bb)k#q4jdWdSnI1*1^_K=XY=nc6>=?v()xd{ za#mfu_((haA$4d&V$K=oVp;R)uGolr>4rDDc~9W=?&=Z0f!d`Ej+l^BG=;YUN@gx+ znrNfGlH{x??3pV)^(Cd)RoaO=Luk!}E1z7tlR>a#L#p-IlR*!%`XeS=K+Y{6&+S$BD{4=QB2wVwtZPVY^uC01`)-g z!@}bW5Eh!u>mu|T{FF@vZ@#1tDY+QR#{G7FHv4@qryC+yoN7`9J({f>wHDt=O%d%I z279(HXZ7LY%xnu72H86{4JqS{V`oNTv9fjJUsE6INuvt(Lnr4E^SPp*6GihXe!D1( zbpcuJ9Y{n-q>-dsWH=p##&oU~19FVwkx*u)-s`keWS%Qy1g(FrrC?lo~oPQqGo9P#0 z$sbeCu-Wa%2@efv&dW{ybzqz>`uNqtZLRWp7dd>Xj)@U$NM+fk_eQEccZ(?P5s0Co z_)N8P4VoFvnlF~}OSN9|2Eyk6WRIpF2mdi18G|Ja{pU+7k5q=z)swWDrQ|Xs>sO)G zb;a-`P^TaprKSW0Z1)Jn^L_h%1Np_$=ysjoab%W0nonL!*B(yzi+lbsh^Pu13YYm=R%_Xi)+I8j}Gn^ zOB=WoJ4c3878_d6lp3vaik-(58TM1$IayF+tH>xQH(5B0hFT!h&cEx$hv@(^_v96F znUkjU%9VwPg!|YM)%_SKAt!UsM#n98L<$Z>m^l=-bXnujEei7KzFzU&cTH+uvkDdl z^Dm_fYw|H$YsfEQYw}iv#-fU%1UD@&T0YCInib+|hd%FjMNHazmRXCK@z>F8burH3;ERT@>f^tvoQG-S#po9 zjDvo#w_LqZ%^^1{P^$HVw)A*Nq5Epy5DMviNVHhQZyHW7a{6&ep=t#6$TG93%p0&e zF|Bou#=rD;nsUDg796!6+>rXf-Ctqc%0-kyAIjYj(8{aeL)y_~-5-@;N9u8~O=#}C zr^$+)N)NnYoL(`k+6ghU)6(>MUp-d4Qpa;NCLu173V7+tM=OjK{d_>&W#Fu+>hfX^CP+l2nozovJS1L8f5JW}F+__g|h z_3ACWw($6N(HrCA{0nH>?+&~ET&eIxLL4q9Gf|=`Av!gT(~e+g0QG%|mFRF$Xi@62 z2V1|^_|O|XC`=F%IE0-vdtET5jh1gg_cc19UP5$rTHn9-V9Y{YL09SV8=phfr@l9s zW!LfI9bcrzq>2Og@m{S|T?ZajR!$EkOM1j|T+=Eo7Bo8Jz+sV4aYh~JwgHJ(6HV4s z=Cj*jzRBHG(}VNJPdRSN(GO_0xeN-r=mXm-c?c)B+~8b~#^yhNR17MDO7XZUC)2EW z6q@Z@bHr##FkPY(r21~)fAFxG_tyodTo54w>E59A(RDY`CD8@)fgRRZ+Qj8k!f{R> zZ=m{C3TC$L{nH83PwxUcmJ)eGN0e)pm&J#cODgB>{%|lR9V_ubsesP{&7t50Vkrk6 z^}v?iPOJ~@@mm?5($T!$ZZwh+N{HjD-VdC{k{N1BIAGySABw_w3VE|wo^;8_QaEPh zRFD+utY>~SrrhHjldVa$SiqJ33mzGfmH8nwV^i11m3^5c`}IzvF+oDDvM!+5AP~Wl z4v-lxCPU~1u#j%Q_@Wxoe0H#&GP%~^%&b9sX#g9ZJ8*qpiBFwyG~Xyl7-c6$&wa2$ zI;RPSXb99FCsO$SNw>)ewZ7h79V_p=^bU~v?iIot%aHhKeh8yRppyccq#nz-92+^e zm9mFW{noVowl&k?VCTlDrXe-NN#(fh%Kp-$+)md7fnYl3oxj=fs4vZo$L_asgA3l#Kx3im};|nxnOPG@8 z?5w7vBV}(-bN*85aAk(<5kpkpda|)2A3sw1PBGcIQu>E&n^cn%7SbSEiQK^GQof-V zKv^)j<2EYmtnY)B_24`AyanyA#|*i5`@%<5i(k4lYm5=ZPpL3IViiDR#9n+#|21s1 zu(hoHH6d-mNe>Jnwl8F0-T2bZ)g)#{L#z5TN(kFxpFu$*@c_+9A2id6&w&8C`Y=kK zVE@|DFc#fe(_dG>m-2!Igpq>dW~-r0pW4XD%84d=KnZya>Jj?BheuZ=4EI-f)-zhP zio}~&eA7eIu3uOVkd=ZhY1S^8^y33ud>!z%{%}Ex3cjzlKi=vUwUzkC7)#e2O+n?# zJ(to2TNX(;jmKd7D_2cTAMgZEXS8q6315rA#!uEuKGG+9jxb3~W~mq!>fxv9KC!4{ zM!Ylq)htq#*{Vg#tTgSPywN>iIcTk?)KQbd`SSrNTckN3fMQpP##JK^+z)&K_;Dyr z#wqr;D|XcF9yzl(7!$dLEMT_0W=J1itoQew3otRr9`VKX*+cXmf;sJ-UjIX3&F0XN zTcrsO@}{PxiId}Mt#Mf)a9OTy&|>iYSZYNgSDx8@EQlQrl#EEr6y(<)+!pvwvMVk7 zD=*26HmBQn1tDE{dc#n*Qrq>5EpS%H+qLu6F>7&- zld57m{u}Xk&lN0FmFnRE_<)|^0Sq5NEttiWbu3*LCLDD z3D(|Reb(Hd3-Y;jb{`SIuii5)4v6Pv=g+OVcYagd7*E~#Ih%Yz)3Ec%JCW;bB{ws(?Bpa@3*_yqyYIkXl+{U#KMtNP(vrArG2?t} z0Z*<7AAQnZ8WrI%@e^TI&brT%-J7j_zexCkdqsD;wD=l-5|Pc|W3^L%wD-M!t@-(xwfwtKrv>7)j zyUxX*2J@OI35Pir$@MIs6t2SKdcGJ%|5P@;c&UyFjhJqG$}>JioZ>%oG}{!^z^iPX zK}>gX3!g=K`>`4P1&#P|(i|~-;D@@6BGeJqGcvPZtFo%IfFNOKd)AnWdF}oTExnuS zZFyK3;#H(ScjV5Ui5OX3e6bnL?-kQ-nYAF(y6Re-x1ht&vd?*E2QHUj{Bg~#Ei6Xe z@yNru`qzFv41W?@c|)A}MrRwH;p!ZjPkj)wAq2c@9$7Nr-wJH180m4B&Rmgo^CR2r&}%S-oRxoNYmED*R1QgT+kyVepD|4D?^6pMPR%ycc)^~FwcrcWv=Vn3*P5|>!HPFW>91$)i6Pe6 zh3wNY>ssQ#pOO1L{6)1~3k0 zBRJnsF1sF9;o(swa6rLHX%!XCpFSd@WX+XQP|}#OUO-)JMWmR#cEzT{NH%$r!t3AL zkR8PFRV6Nou;Ejiv`VB5=vqdnWs*PS{&g)--ML7p4`6PyUk!4%uQilTR*jO(PvBF5 z#^I9-86O$-Gx@$ zGVHFfVS*SCe`vn`L(L8_yTXD?&N6H zt!Dx$FbdeY-j|y(V+4&`a6NI`jL%KIJq|%oU}W7JG2Z(;i3uQb`NK8s?Ei4bDvaST zHsGhFZQEDgv5orGaApZSwDFtP_v`Cd7vV42OJhU(y+uTj4$}*fio9AtiZhKjL55mq z{w1I$<~sefn1=K}iwimbSzPeZ8N5>>Nm*KTX6f+q_Lj&PnC&(^tRdY^(eAqJ{Oo-Ta55^79|cMF)XvXITKJY?ANv_H)?y4a3XtPd&Y6 zn+%VeKM$@pW>x~Ou5M43f^uhlOqOr)Xh6ElZNj{xKd#?PwSLhwjws+tS%-kzb5J7z zTk@qsHdH5hA;AQAA2i@}OHmDpRgk4xNV_qJPp1e2Nbv#>Ubwc8i-Fj}0&eCGEzH=t zZ`IPF($LnF|1cb)jzUufLx4c8_yURec`mnI{yh&v0F^Or>n_HM?oev!kQ#yI5MpdB zk9cebp^nf&Xm^?Xo*)0-klbBo@9gwSTuRFqEj}^@6rTcgxW1dCd?D#J463vQuT6DY zX!3EQ(fR%$G(6A^Rj{SLOiJpUuVP@YHhfBpE{2>o5mSg#*2ti)z?ze9{GK)^uymLQ;SnzAzP7X%E z$E%!p6ei7e6-&X;*OB!V;xu;Ur3Tdpm9onwf2Uw)5C2fQMvFJ&9gYP?AFvhJX2u!( zW6FQQb~Uh6mK)h*{y)+eUvCL#{}rs3w{@|#{q~wkH0bpp>EyVi$5Ap8KEubP|9P~} z>6)T7%Wune(JC#llkaERhu60n63Ueg@<-3iocC*a3zJBSNtQbMSxSd)8dQP$qjLks zVyI0Bn2`ADZ zyN!{s6yJ|!7lv@AY%Lw&w4!9mATBq233mjj+hVYScVn?Qk<|tdar#&_=KSR@zWbW0 z<{e=e5R^npLnD$7Cu>&JXZHl~k#Yz^IBG(i&zH}xwQE;o@$j;nw+4hlIh)u`?>;Fo zq1Bs;=_?TvmjotYgyUS8kKJ6)x-Iqw`Ftn5wV28^=~HDp-ya*ID`MOE=FPAy?S;=~ zr-2IRC9>i(a^?KCFSOsXX{tD8CW6~s4lgu78rM@GU~N_~()WX{-nakT4d3f@sYpaG&GSk={Y>f<1S@)gq{5RFL(dW=`Q>5&JWw(C`Uvv zK;KcJ*$yx%4~0ZqPlHRGw;F)YSQF)Lb;Z@b+7#L=aAE6Z#2G3>dsb(dzu|bW&Wg)n zNYF}|`!V>(@aCF$Qlju3sU^R%F~3pS2RtomL@*OO+Y3_Zke&w=`4PXJH)B<~m0!q9 zYc=D_(LiuEONDYsC`8=yYgj1PJz~b{-Llq{w0bQQfph*$365nhjqs?naxlI(8>xzr zFuOFun|A3R3Py|T>V>v}3@nBd;TlAtLNS2@?5(P_@f?e%@kX}Bh=mM@rO#DP|7*jA zSF_dvNc#NS0J>!+rjuilK(P0mh=1o=d6L7@qfJ{Inw2UU0jr=aGbAijbo=B;4KHrg zf!mJs{NAa99z=-sa!i`fSAD?8q%QJ=*WQ>Sg7fdcTw;`jl1A%apc#Y^5K=BM^Sq#;k*n4OWL&a|@ zMfw9k(f^DqtJV;vOs^Pg98QUM+ZHSLL~xAn`mMu+GJqDf&D+;eWKMMBTr4ESBL%yM zz^93vT~XcU8CAXS;*O6ZfBl(d!feE7_@tWxU+JYTN_dMS)Ev2eQPoIdO5oufj~+~G zBP_(kCi)L$;$)USChyv*r8~x0slXzks!{BBM~o0=3Xnckmqt0T1dmc9iKxGp@@we} zvMyoqy{52zZwcDg@ee0h{1aVHmI0Gyq@8vI?;Z%!muQtH*)Bh+wGX(pxFTAmWSkvj zO99Cyx_t$j&@b;6zbxkj-#~va*@53Qs;Z(?CccfdZs1=PoOrv2SGwOkc*MU@MPrne zP5XgAR-&RHgV5U+1U03fcs~8b#q~0-Dr(rxDZ5F{+7%>kkM6S2!ZC`8ZDECeXrqe- z0Br;1Idlj9@b8@mx-Ru5Ic*QEO&B++PHRph5oQ`uT9=A&+5THr9M*lJLv`j-uFAs) z9jxPP|Fd^xui2N_A(#}iWDK8KNDYRRt8vooux4yR)1@_3qrz7npf?Q7OZdi;Nfyx2 zregm2kjxUGGj^&Wi69lin{6(817pui^AtqZH49?N@>OCW7qG4;auR;oIN!k~T4aZ^ z@uQJ;M>;88fobe2Ui@xd>{!4wxuo4&V`}^GH52FsPTeqfVrtezJa|NjSvPJ%Gk_w| zoQ;j~bBYb4F5j~u2hi(|pHMW%n1Iv7X-R;!;V&N@%5Zp&i3o~iaE*}OkS}$;`_|0X z>xC7`#o2;M$$<=tqqzfHz7MUHOknVn%3v)*L17+EBpnGGR;ly8MW#Eep|evv7kAD& z<4Ya!5cMxqzJ!L_PYPKBqw|+pL zx_}-dugBOL^c}p@L7o(S8H>_?)bcY=#;T(8e9n*c!dNJ&_tN)k2J0cBIwoO{%6#s9 zj%N1V^>bM@W|~$^+9xZw{?ocGzWFxN@{0B<|HlOoY6=N%S|t@`2X?KDD$rgyRkx7g z6XbSC$0)Ap*PxV*NK2Kyn6I4o6P6N_@1Sw%4=kfj;$@ST37$A5TTHe2w_uTjO$#TL=~r$IJxQDRt+^w8|>14I{HxZWk;kXqU`dTDX!*7 z-O1FnwE>jqcZawb2f36hisX$<>I)+XWllT`WWx7xB(?m)T_Z~Cz>8}Ms2Vremcs!Emfu~oVOY5S%dP6x-`kkv$) zwCTkp0hJJy_Exi?v66Ii3{9>Nv}ptHu7okL3w_Y6*4HJhsv>I0rES_B8Oh#*98VIngpVZY7 zz8Ne4wU=94Tbjo0fA8E#dRCoVOSBY<@(B);g_UHWlMD$xn1Gf9D0yY#Vcgudl~TDT zzHZB_p<+{IM9HDN6iPT5CHQTWb&Zi`-gGC5e5S7c8WG|e`ub;1h(1ayCAGE73%?tf zpX(-=SF zOFdu*mHdptYc*B&S7#D8&M2^@#LTtgT4f%=!Ea8Vb$t)LQ6C}d@x78Xv;Wnm)GMOs zS=?1gOM)UM{AaSL(}ekl2+J$KhC!lb{zmKNjBAo(S&SL~U*7iT7Hs1M(yMU%m>{(G zuLtk)m+Zkmr>OCkpYaEQiF(`q6ozcyl;#aX#F zv>Epl)m>&!Wx0sfbPl0>{F2)44Oq^8YvH)v7W#cvp|y>U47Qf5#Ak2R_|7q~k;=7J zfKqZYS18!@e&{mbJx(KE6b=X9VL*+mReHByDG^6}?LU;sI=dQ3zBqF61V>_lN310q zSDoE-+yEE52z$R<>w<@|aKRNf_XlSW-9xO{;Paw|@8NiJqtibW(uE9{xYgH1L z2+=1W(cU*X7Bgo)NezE$h9!=vE&D@cR&mA%9;4nIP>Qi`=k>iE|Cs#ohX<6BBhO1{ z-7wfbX=1s@`~B>FZdV;$#IRYzl`(cTSRl;JD8bi!;18)X8a;_eD~kx5P!56G?qbaN z>0@dp55yWNTP1_Av6)#};TCmf!O@yXGp@f5QXPt3th5uyYw*W*HR%PptJ1y9tvjg8 zSgUSRH74d0m2l9|v{WEYWytQQ2GFRjH99ClfB10^$4i&z z??Wr~%LKznKtr3`^qPOyKNOP;*-H?uQ>y>>226gmCgDHi{o$h?QF|e&pCVMMJixD) z-A;0Q&MXXQd|N&&DSdduyPxq^wB|h}>H=l;5B?rNy&0UGnD{0prCI{fy0bQy-YMpu z)YOzoSP|dk&KT3fx*WUMz@)2+L3VOP%CNA+ode~J0ClVvwwQ&FZ49m&jTLG86q(al zkI*8>qy+UyPK`9g!GY~CqV^7Mxaj^eO0ha0n8t3Z>`I8_fcfUrRsuNl_pbtWhaEU6 zob?wxD!FXf!fpR-7;>$B+G1dTVu?q2T&qd*>Zr%K;7=US2`|EB=71*+o|eTud~tbb zaVYCrlfOZ3u)E@W|&fmH+en^gn>grH)B%L{~t`eR=* zqT8;CUrlS6u48C)Y;k%|U{9Ch3E#*u2~|7=NQi~YoWSbO6Q9|4!cfuDgG^88KxEMS z+OPjmK7HwY-srwM`37oZNK6THb9lT`oBoHgXd#RYQ>js|}3O ziq9DMXerq04%*l~vPV@a^GrvI<`zgg?}2p2_* zr_UfG`HJB;UlZJz%&r9?FV7*JP|&`^uN}+Pnp4%)u_wM{W6Q`o!|*R}4(aZlpgGTG z87wKGtP=YWR*A&{ewp4Ax8=bn`GqGY@IMrX(t=(FnS6&f26cbkLVd=P*_&A!sH@ff zU<)jyiu?@3FS2E9qrd!M+gM0TD%=h5E5&PRxD=_JCRvq+U{7k1xhI=%e8RsXgW* z6rY3MBdH(zqJ>~@%9|AL+hXQO#j50loR7Pt7?rX8aL0aSs)mgcfbuqnCklh@=jiF! z5xBt(r-b)#pjmPBi$@)w_ofarf22E3UKXylkqjv-n~Q#^Joo4bJ|z)7u@K#75G9Uz zLx12k@0fRX4IOkHyAk{(^d^cMegg10qZ<__cDQ^9ZGKdLg*87wbIbGa<_9c=Q#Bx1 z=N*iCTh&FDYe;w1EO{o}P`Fj2#VbsI8heTejq!`68rc<3`!XsN_2yjKmnE6W(ztTI z*J#e&*eGFvQq#+v*tU;*D>^omlamt&4CNHv#eZdv|5n8&Ho5tW5!ebLL@zua=_x1V zp{uKhR6+^MN&Xr&ef+h2hiL&%)nVM6I28L+RS?e06{?$-ZAW z9b$Wu7o6o%9aX#(krUKeBpS<17PKWu^~SqtZ-K3n+J}3<%cZSn4dsqJFIkS|8j`F z#b&l8_fS+qdbG)eg(dG-CA$3cYC=ALXk683E@k9Bn%2lT+SaVn`f9pFlYzFcwa}_D zYEMS@ZorG*OfV!E`RGg(8?#Z zQX5w$w>vxm3A#e0&Gl7HRi=Cb#a8?aR5b0Lse}8x!wId-K}0|_Qqo9tbec$X(g+se z92OQ*ns{iwuIJ3y4&eGadn-U}&u0F!YdEu+q?OXuebW0=tkBZFvwnGzqW%ejH_m9A zdTo!69bCj~H5j1tuodBE%B2r;DczcwB!F=<(j`rnct(f;F@qtOjoYt@&D%b^&eBlX zI*xUci)Usv8@sE50J1CZAs?Rj69(#vY*p>n-3}*!32zU9y-K-(*@T%EQmfzv5mFwW zG}R@H;7+6A&QGPv{QU7#UIAc8wrLwohy)D*A;{ZoJZU@>PFrzjH}}TLlv=_RJC7 zG&$J{*Nla-;;Rp=Pqj2%$pIWcy>cevPN5#A9UxW$&wlcooJ=zkah5|bPZ2~l&8W(epHlYt&}|NH~@s2RlHOE4<%hDNXG?OsC;VS zM#tm8W8y)O+DbfxOWcslK0maM_5r(Zh{_B`i&@iKfN;H?x^soQgl?^Vy+1ERI2#T> zX^vq#F9Ca8s}}=Fzu5ttuO*Msb8K0`ZYMouAIuwaJ~Dk=Z(?IdG>Dynki&V;vDJ*r z*T=Tl>gR8deA_~ut#U5;$HzF$wn=rDy|69bwxnkQ^u zq?>8Hk<=Bg8qPn2Yn>dzBSSSb@89`#WHa!B={~ZuPdEOt)apaz5wYXLX#|i1yU~-W zWd$kT0_*&>VUmiwOb){zi-}m&;4YabTo85n&K!Wfo&rxMPe*C$!%YhQZ{ST00^LzrAwXnLGsc5^u5g2KX84?guep{ZLFAhB+`x_j$nK!iTyI4xC&byTTH<@HH{a z4ucvS>PNro3@em$JhY{@3v`>3poXQuV=RH?1GXwpr;q zVvcaxG_&{2DX0ZYbf^=Fbzq}fHvW5vP(W~tcEQ=1m=v-mFM24I>svdeNB z>ZSWOX2zF?V#x`d>d7G=cN1M|c*82T@3R^t9D`b6yi!K=qfNn83RlmxV&O#=H1caz zJWiUeOxQ;GwhvRAH~ei?=W*GbLcT5UGru!NA9$q+b45P$V$Ow=4;9sq{9a?2E1?CC=`Xnw?p0hXeB9N2zvk@qybKUf@n}0G(g+D|Jc9Lu)_Qo- zGvw5`RYWAYJ84e8^{RA`H{WQXNmEsmBYC@`ULInscBvJ`l9TW0l0Ps>r{?Ze z@i}Q=uFnlG+F8ZCR)0YLqpJ0H3^Hv~XFUwT{zmm48K0MFXRTDea-R0D89kHn&B@GY zf(V3EEGocXXRD%_l#3)671XI4W%IYxUM$DK!2my=w@D)dlTSgueZn2eF@Kwz7lpXF z>pVKL`_%-YU;wK=LkyT0_TAAfk13VA$D+_)sr7WX)@Q#!!E4Q@yAyjH%a&N$f}$}%Ol{K zQ!AEO8<|AYdUhiXUaqr@$|{Hi z-i3s%pbZGHj%B_VQG3_Ky01j^KrLy*yd(hhmq!xB*%Ys&-|5!3Vb715Sanv0c>WCk z38yYJOzfVV(Pz%34#ikneV2cj0|#0(X&U+ z*mWtG6`yNLCt9F)m~Mg^vdOg5d605GYq<-}zr!SCIm#QTzI1{oxYt@$sqfv_o)1P> z)`BD#Ha4k`vt|5GhN(Aw`J))cMo$_kIU00X9Nx<`&S%Cnxe#eKjx{@Eb)9$cZJ3v} zNAb(b>Z@d(O9eL=Wf2~m36Xc>o&?~ADFNvw!5#0y^8kk8&*#fD?)0bVQ?4s5i|(%F zh1At!G0pi{JUbBBlCGSA%`AaXwiX?!7Rps?O+-H3u*LTD)wwF!%Z}6ef19PcpA!n z=Lo8N*|Q3Gf187wRDjFg8Suvg*w{rjCQ)rIohsZcxbo42?dAJ)ijSyQyK&1g&6}3J zA|SlxAZ+7JmwVD#$mhE_*gurhH!lBB_9#-H63v!R34VG{@C-MRg&RxW37pqWyQttv zm^<)1si|nti02x`o!XEd&PUQ6n^fsP%ML(}+(M2T-N1)HmgW6Dch2Iq2QlDq;FPUN z6Q348mMO6^vlg|-DDO)Pc(&Wyd_RWl;cqKJknHXJS!WSAM^^gdgwvBFE4A-3sV5S~ z5<^4Z-#BQ7p@O^ZEsfh!M0r z|1=9fupru@56LJ>?uzMB;roy-8>x6IiUb8-#k=7B^kiqSVv(~`5P>o|^NKoJj+%~x zG99Sz#?5mz{hGpi=VUejCd*B1j=MLn53cf5v~eO?$B=^*m7QUZ`1U`IQ`dQp@k>*<+kCfh;2` zW%b$_;_tGLFEC0K=V`w+nIfWIzUB)W?RXTk4$MOAFLme-B(btG$GfE4Pba3-^Or+J zxNv9+zL-IFrfla6Ymzrj>1(+NvU0KW5Fj_bFI_d;%0&V^q2*z!xmENsq>33l5;u$u z3`Z@0T&LziRJztHi_Su&^Lh3wC}`g$;zgywBcN|Hy$$`54^S}wiOo$i}vZ~H#x z+;6|9N;JO+QFZ|ykSt44I2X!pIV;4N6X>^N#?uq0@zd0W@`*9IlY$%RfOX#&M|TvH z4>O&7qed&jcje0^M}K!HAdhOA3?845Y|0>;W1HFO+PE}<%?k8X>|xM>j0nC0t@fEX zW)y(kLpzFlAHvcv+(+!ZcK_ch>p0d;imYg?Jfusx0sH{ut*sCEvRsD~I0-7jyUh6e z;!!T)J}1ONY}e2vjhidN$_=%DDCOi~f8)^qq0~4Xo|HD>_v3Y!KSh0oZR3)#PCfN^+ z^Z4>_a!kl}KDAl3;OukF69&++gcP@_3-**cq(C6=zDgsd({v8caV7tePWuW|R_(N< z?7Al6)x7nu4p~gkLyLY`CG*sJRKEYw4lDdy4RnY|;cs6v-d%rWu&G+T_4@Sy(&HU# zj=L9ZiP7SgxIJBh6~v)^#b&5YMu-x0?9z#^h3J%&2Zcr(MZ(|#g7ZHD{CHq?{W9PI zIPCZ*Yk@W=*k`t1s3L&dusl9#gy75bX8V*B-j&Zk6v5Dr^^RW!pGWC+oS%y!r%Ep~ zWZGJ)CePV~#012;aI{hdz5*w&7ANnbLd+*layZ4^8#!&eULQ}o?zd*#3$MQQ(VQ;ANq<3R{`H??(H& zGsxRPkpPlI7=a!B=$?^LboxRwV#xa{yGM2!{nv&$c0Flu7b~R-EskE9H*G_>B5868 zI638h#Vz+()-N}C zyj%ukFV87}4No@+FTSF}lzvpt^YXxAnEd#$+Ujk`@V;mD=w^5}?s(*IHrKCSnj~EWgiP8@&jkWd5A`OjQ#Ff9~#kd_EJAr8y`1OZdn9 zJbBF6Q+4eoA(c8 zIjo`bXa|YKd{r8jabh>x_Q|B)-qTRzJzerR+e+*e911{3|3CQ#$^Xqaf={MKLz6F0 zWR^jzo;}5Mury-)9PDv*a(wxi&m=HrXoPLNs3!@5zCh=U^auU@Co`Ai5?GS21%o}6 zML{%P9Pan6K4phg&`M((hw_jjJ$O6J`n7*qyY>wG~oBx!Eo25lfvc(>RfSr?ZqMe5vxB}ud06Ne|z3R30Yu6vx;SQ z$hm_;3zLCTe?~j3po=y|iLbB6@H<^6nOBo7b;g#Ct(F@0#osGvVUV|_z!pqIpN4;d zAU17zejEvn4g6_p(q)TePhYTPac%u$)fk{Ck~4haGB&yvO&(1+Z+*@N%Iw|p1dDXw z(3C-ZPh~AHJkk?6ww1tWa*|XDEF0{eCin~Hr6C8?5mOMS6r<9q2>9&DoY5E7!u0P)GmK3AI6<2Vrj z+ZwFJoGd`jx1$276N?&a-O2s>kwrgZCAc&#z?|j2x7Q^e>BpW&f<-KOassMXTB@wA z5{CJj(3tz?s(~j#-Eft*dLVQDT%nMIjG-2^pa~z)al43@(Up)ik6hk@Y>qtv-|be< zyLKLy>+rl6#b!*TW{F@8G9(tpknU@0DJC;&ub*bEJu*ISa$^zY1^G6epN{QN^2OT@ zoX7{FwiZ-~WsbvE01%~bUN&3?>%z#CLM}LPM)so*?{Zvo-byXUdlXI_EiLjuE19KF9>WuBE9!rA|#ab9CN~ z^YQ0IU+o0z_m9Nhw$xrNH>@Cxt^PEEqhn$hznFSBm4E(e=t4tgU8kcI9dJR8HK*qQ z%}d_iouXVB%ZylmfoV*Qfmy}x9|~E3h?BcJ9Un`3m}K(MV+|svtKEg*flKr3)su1? znz;yzC9Iv4Emg;eo>(jTuYc8eu4mV#aO%dx2h14N9~~icz^mcK#A|@y4PZ#1j5L-P zIClRln_FmhAJ^AyvG?W6>-29&oHkLv|$=9?%>*rV!_NB)7X){F}SO zRqxR*1D=G5Md{$=R}NH1*$d*s?M{Smy&B_%@zk`ws9iC(EHcW=?^t$qw*6h;3UQmb zacRs?XuY0R9Hd$HLn+UUDUR4#2EJ_Ny{7*C>9`$*7|viYVS09+K$5VMYlZIMQ7fEv zLnlDX_~=Nl61QmO6>C=h*)DH5>a91Rj^&DRzF+qp)|%0zg&*V_1w501!5K z$Fx9N^GJvvmPUQD@q;Lp%ahzpyib!-(A|Hz%w??%d|%J0P8Le5G4N?u@maO^B*WcX z=8c^z*V2eh#6ThPKMdmNb_u|n2(yW;<{gJPfk5_&FRByCQWKMNd*3G!RRP8XGenLo zY~_q8xa^l?1!`wV-0XkS$J%V%elV^}52l_PCZ)!1J>N~S-(OfQIO8{6iJlQkgPv>8 zuP-d_Se`(@_=O3a!lFxn&5FdV*f?NL$|MHcD!O!^pBFI9j_jHW?(W9Ka_cAO7CYuE z$C#vao;YqbWn>ZJ5y>r?VQ?5z2);ZnyG>1-NWVmv_}OT%i}l$oI? zDdk<6gkvolk9g7Okd!mzgMlzps*778#IgNQDndPa$tnIUxr>wHb5TwtsSxIxGxC>Y ztyCnGNO84j8kzsS0GU72?px0pa?^Yr@yg9%*|-Xy+a%vrKaGe*sl-)rn{^^cJjK zdfvP)=vP(4V{UnpFjP_9a16~f#uJ^>!o&3dyoHQ;%InxNeHCrKy^w3!^6nrgj;%@= z+jHsGaa=1ErAV))=;Mr!7~+X`Ci1gA`JHRyXDfzR`z*=6|2p>P@Xkw+|=dX9oW5Yn=>{oK$9M?vscz*lPZ{)73YruX7KE zcQDDmea<>A;&IXl>SKdZDZ-oc+Syg!{!Nn%WX?BYdtu~acm@PI{YcHU1HYdVHG{8(N2W*%EW0iy zujjf`FIVNhnS9U1KVO;LK57_~IZ*)@RPEJwUdoy;m_my{yULWYI%{oJgL;@*RT-Mn%aVj*!%>Wds!*2WxK`)aDny>tcoC z1b25UQmnXJfZ}e!id%7~KyjC(6ew+RcXtaAphW{giWe_XT)Oi+`<$6Q=j;AYGMRkI zJCnTmu-3Eg`?_v@wa2>Ro18yhK|*_SHB}GIVKDw`H8@*x6sz<_0$Giv!`C-cr^nRQ zpB;60^C45;itJ3&#u75w%j8)!GZTATvO9?O(-q|67(ZsZUAei>d|#2(S7TJ+~jgIybT zY01}C+N))pUc*vfJ@X>p_Dn4Vzd?>mKlG`kLej3DY~`z(;H(q@3V)n*s#!L#y*<2BZ4Tt z*eAsn=YQ^8DfU@66xYQX z{-}{u7{srk0SW}i|1JE#>N5SGW0tg4iAU{)e)}7h@QvARfxm0vM^E`WNFW1wImk`U%su*PrekpXm(%qi+jM%)r&BH2cLn6G8E4t_L~UUo%S@O zsj??Q_3vr2r*;nQ4p{11r^;}$X|wVCg~0LuoxEz2 zDDNNV?FqD-|8%*f*A8aITfemhQic5xz+>!Cae^)(=PYE~6Ym!ooH2dHMK;);K_Z6l zSjE9x4(S#HK7s&ZYxvlm)&4bP+FeQ~;(_p@OM=0ef#Ec*yzY2Ebz}7-?bSp3iNvXx z6P9>Q?i!5rGRfnR3hIxWHFS;S@m3qfjrATm?CAJ}3G8mvhNF(e1^3{vKLsSPB~n0R}*?rHsohkWWSyIZo=|-DQd9ddc@E+#K-Rh zNo&QigTzzy=;N)Qw!^Ge^sC;QYmr~h;j*zt2f9=x04J?UuCLRxqvWqyM2K-U2RFU* zLnxDF=&Ow@tT?{-Gjkyy$XEx95EnBGS0>Uigp779hI|5UOEshuzf=%z*J!PZkKjup z`@FE?HXJ^N8!p9~l)w}_tgf(!sj20tyq8k7`ABYTze^e5BWYnT_`WKEA~ZCH&ejz} zO&13(N2k7|l%cLcxk09mB2Utw=mr||R3suI3XxV0F z3buKcHkrytS^a)@yae~q9Bwv<`&%5UCS!AoXskT_gu-BjC&mGj^Z{&jKW6<;=A)m! zo$)0Fug$II%W&0kpMLYHDa~}*KvLa>1<-TaF`1dtU%)ZRy#;YZ96FxXY@q(v^i(>p zfjRaDzo;7GE%0FZ=sS|x{fT#(=pU{>w%AGi<(jKgXkVx#=AnYzaWNy~F8}>1|2z1S z`Cs$}Qs8Z0A+$B?R~;tZnPyp8cZ68{QD}#ZGh}ccV+yjcVj`XD`$i`n?Q?~ir1N3y z3S}m3dOFRuPKBjx!vUsVmOAnK(Fsw40`!&Lu}yq=b%cf5&OhlAdnt8T&lwKwD}OjL zkqoN?{Suf`gTM*DCUFB|DQk;pPOD3l8}Y1oX!Z4eCp_y^`UNCk@v{!TfkFtKA4Y{z z&YQ);S71gH9uwg$JC*!3s`3fr!Be9=K^SuQU~^`mVh$`J6B>tu);m%&$=U&O70h7b z+`~coiqej#*SqDrPwsRmBuU=y5NjYNajxgxZI@@NjXI)3KYMdif;P9?1HbYz6$;r+j|Ej6Y8WLq(6j!4-Su72>Ti^2H=^NLJWU|WrD z@8RWNe^MSUsbZY_KkWwtUxK016$a@aa%^hEY4L$C6cwnC2FlQMxw-{B>T1Tui*V=-j$4y2N$oFTa(>f`EPf^X~$YP=53aQX|IT>Fwx+E zcHr`k_NXL_&TnDTHzO;0(@&DVKdWR|RW?P>QPia3%f{j~izqP@(utxZfMrIc^ai?G+#AY-flF2{ZOU>^7P^glQ0T@#oG7F%nHL_tpIAuB!PG-7#)2 zKT#PH;rWl(@un0c48r(?f9{`8gihWpQ+tlBS~vFO5S!7${&xX#Pli3h{oOy5XuHO= zVLq6Oe8Gv~@}2P6aCjxb(@TAhRF>v`AgMQlR~`VJMfl9}e{hha_87W-3BEYrNcX;@ z&Uv?a;=pNfogea9wB0;D3Kg85J|>Rih@%R}U{nUM>{(N#@ZXe6CH10#+O7RG)hu{g9=HfWgp zA8eg)1@c%0%0*LK8-{72 z=e@|?`lg{oc)@`R`YV9^*yznGQzM_fE_Cij?n->EiEEWT>b!voM(BZRO7AZS~Rzidb3SCtDlIyR>x@VjV|-%zf4 zzm-qaE?_r%^HaOS55<{;S*Q6A598~ii*%hYkE+Sz`>lr5lHvUB$HFu&kCxN|xr4_h zc0a8e3p=o*%oV$WsoNjOcp7PosV<|Y+8kD%>m|rWdrnu% zQb6K)a`H0=7Q{mp3*BlkO~#k<&}T@l((`Pe=v>^y37xnfpmT|i`06dpO_kOhw07OA zh@FUBi4QMo*-p(`F)tV{-`6dmw)oc!cLpLQhuBckWeBtF{autzFBTu-L5#I~A?32A z)~qULjq>m5d9}_f!;aQ{8kc@`w1U6=hNG?0FruxBwpeiH9uqwPDr~q1IR;2uFo}yu0LAw z%L+@8l~#|pa=y>RX*QarDx9*(*pc9v;0^w8y&eX@?4@8xdNT{)wt`#WDuv93JJNV~?YXkS(7$Cig>){`-o zYGC5t)jz69nv<@IbQfAZYmQ&@t~Yo0|3h&dvk5_6!BSVESTG@}uo{lSmT$+i>CNvx z`}BBwF7mT$yJoWWVu3f6lV^udInBDU+vGJT>J-ZEu*i;z(_(A?RBZjGPrbz7)Qby` z#ev%!uM^_dM}Ar9mPYTCVJ9MkSD=$HE;R#;R>ssW2{+z2Hcb#VrAaBA?C0wjA!jCxGvWXwz}ovd|7ise zT04GcH->cN%L9yJXaiHseUYLL-m+NUXs$Uwb(2*xLGgRiblQ z$QR48*6>wO1WXX$oLyeJsC*yE8`9zwyn;a*z;s&!4EklS$!$1A=X~o z$INRBnOiM}8eFDW+^pgz?2^kbvb~yW`MkZQf_noP@3eE#-MP!=Qf_&=zE%q($jA(5 zOMeQ-ABH1bS#@l#dR}%dh9lQjiRV*c8M)F8(Np&RzZ;q)og*(B6h^!asAl~fDXLa@ z$*D9(bX@GZ#h0&uiLx1PXLM0J?k(Myl14NdBOeVWEQd^tD_2v*?q?R~Oj+tbwhjw` zzgTi-oxK8{3wBaP1ljVO(sTu2C5#S^v>%Ur{@}J#HDnKB!Yv-o?zKTtrjW3ym%(u~ zd@T#u66>8??MNx^;@vZEr3u}02Klfjak1%D4#+{1c$){CT%pAjlEJ^1qweD=$(>>6 zts`x{6^{PS9Mm;SZO3*hKj+B#M-rzq8?^7M@d`?pK+L#s6+de=#h4T4d}v6vmYB55?}r$8%~ddCkgj^=Ry^ z@`63@uk3?n@~Al8ChM=ZENRR~^9kB5tg37$5`=cr1F2(n=afj$l@|5i@>w_rHlIioVfhoymu9P)KanUBP>*;rQzb6YpWgk(25Cq-Q#=Z zgC#;bFH6Km>^&#B5MJ>D!VER5v5fM)cBSM?fLXI$H-{K4y* z|4>5aBmN|zB7-uOhexGN7Ge*7Hj4gU$X*%ZYabTx#(|H`b7I;pA6|PevZU?TfmYuB zLYC$n>c_xac7@2iJcl8I9H5KW;(Vl`M?5MR`(L(Y95{o_wjhBMbzScEzBE=Nj|7-c zohH`{Y|5;FX=-iIoY@JtO|QeIx1hvnL_n58J4A2&D* zmV87uIWqpALI-k4Gup&gk;=Pn&RnYafg)zcv=z6>aACt`@*he|vIqfcPIT$K+9e6Q zt2xVeJbBCdzN`76e<;76&HtgOj~!_)P)ydbU1OlST5~tq`D2_qm*ITE$$)4I0dRhip;+mB4 z$8hwyEDYI_D_{5megv!ikx~Vm54&iZo@Hl|UP_92RkPW5=QkKt&s^}Ae1aiee%EOs zYG0YHUvT_jj?hyors>M_M>I$((w_{3;jzjdBx07RBwsN#I7R?p;;43h?E0mFL#kUl zDC)7d%23hWR3vW{abpKTwCJ-|rVCNPUZ z^8&v<2?u+OQP;B86=Q>mMF0cLRuz3jq`D5$V8sb3e7TY%+Pev@JsMf25x>gurR0pa zV7QJ-D`aOZ?HgADUY;{d)nu_L2^r+8t?y_uvw6zug4m(=jb zkR8S~ITJT1dujOBr&Nu*STh5l>O2bsasW#v0*-SgVtkLu9W@iW3k}DmUoF)eEA0#( zhM`gc0CJHicTiOV5N)hJW+D zyEpewUunhko#^Qw8waEuXQU?@WhW9D~knjv+AV$4c#1O(yfrps2`Z0_Ib>^Jt_8DPO z8E)cH)(&urrOzNHbG-zRwB}xry+ifOTNvo<_(I6#*kS-9fM(dsNjYNP&A)ID0Q35d zgj_pxzt1gNZ^WNF9NiL&#S&+9ZQaM?ii+kzJp*h%Zn?>+&cMcGY0pXO#!vCe2C*(& zE}yx6A2}fVL|hTbl+A!7c0{z_+1U_bymMgL7?;@guIbaz98-?(uSD2mcp~K}o@kh@ z)O!j3I4vZC%k24o>~O=m+UeZ4nWUqeC1*;R``Xhj?_0p^M>t3YCo04ez(g`m=UHwt zfS2ZoH$y8=_#u?1m&+Z$C1FFNs;!YqtIs2qp~XI`UV&KCQL}-shG;Lv z>lgcr&gT7!t#XgfXRoz&>0vvZ{l)Lz+3CE3q{VGx%z6u)rJFfU|4;;?`X%04;yYm^ ztGu$+Td@+^kig^iU$kvDeP6xumPx0?%G`$0d{LSpEVxP5)}Lefj9JU-yO=+wm!aD# zf+jcYcbtc16Q7-s$VKIERBpiauyU4r2ND=hI%dRO zdB9XznPFI`HaHNK-f&#&1w|KEsxZPz10NEr&Y%0sVn?m``4rNOV>$`u8dx{9Rv6Sc z7)Hf-;P~?=qb`Al#}$q|`Gdv20^3dcPeN6Up)@pvs{Y5kDN63$Y)oHv?3{PEtEw;- zyWc(3G^p70lIFaJXv&Wc#6?$x6uoC(%1{(*@pkyokU!OgmKc|sG=?ZiRA!aqjkGu5 zM?y}PUi?7++y5o{y~{%ZJ?Wo?BRKG)vZii&Zfu*^G)}^ZBIrQz5ZBRum|g$W;6ggW zNL*Ynyi47*X0D0Ty`ZYe8?MzvTE(1G-K%-HTEeN6KF^)6K`DsVXa02y&Or}Nm9u~B z+FjV@4AgNK^|n^*a$ZH75U(ad*ff$Ir?j?D?pb)0kJOvej|g?dgr#HnhG1L-PEE|P zZjCM+4Ru}2mv9{eq1zgnCojjW^OB9LBeZL6*lN_Tqo|^1+l2iGLs0`5AM552=c~#V z{2GuD95(jctuCSgzF$|*W{axC6)e$UG>hP^CZjg?h5p-z_dlSUshQ??#0M%=SEee} zi$XqpRI34%#0Gf;649?G@XDG|YYHM59fc5zBq2g;bpe!|J{L`vF|9uw6}sa3rC*`_ zBKI`gOnT3_hId^4as0!ZaD`%Z3fCZE{4^uho9`B%wJKc_e`tvr;yH^CVj)hiO*>s} z#?z^AQHy}mF6O1RTi>?pXyBu#QoSlCyw5_3f+M8aFMBLZD$JHSp9U(~5`;{Urn`0V z0_Wwm;`%lj4pi-2LH~@Nng#vFR_y975Ex_QaI7)>%df#NwT!8(NO{0RJDs10JF?QQ zVr{!L`J`?a!^@nM-tjxlJBNmhQmBE17?{D-SHi1Q&fLk0YjU^4efk*dwyxK|&ATyT z>X&$-nLAr5l=il%{g0+i!*qhcuh=13nU?H;bJB|-zK$Y<#FDAK{rK5%K_X0TrzS_d zHl__Bd=Lx9(g__9Y0M(t;pm;~5L+ZDSS6QrIW;S5)ZUfUH5NS|+pdBqo~M^s8aagD zk4Ig>!Av#-${I(J7VQ+XWxdzh0m1Nrwe#K2^{ct|g1J>>Mn)=X%clH~Wo-B_;zi={ zuGNig;QNJEfAo$CR;(13L;7Cq@LV8nA0Q4(DSg3P@WZCp)m-GMzY~X!Sn-_Yqzd^& zS+#%8R3v7@d)1Z$KbhjErNY>sQu_S8+e6LpR9PI`D%=&Ao7gEaqCDrQMD3~);|Ncm0g#G9aX7s`PS*ue`aS zF0&%j$az=4I77y2Cd8HXXrdGxxWC%ATqH*xV#S~G+Ug&|ax-rh293=<=rTk{z8gSS zUS16Y+3is^b!_hgbNuQDXT6>Ymm$f)zLM5~4ua3{BEw@99zb$uWJV1 zvlHd}wGH;p4YieP#!X;O%MZET?1TYAS+|+PP^IiKJ37~Ah70nQs?4%>jFVsMf#u(; zzbr}RYg|D1NI(4$Si+53G_}{V#n3d3ib`Co5yQHTJwHZfW^kD)yNueH7JERs3Ku+j z`c!YZI=k|n$}^Q*ievjV?-A*remK8V7V|Siu*CY04+qU$jycedoqXTCcx_?#ITWIR z2Q_yGEwvO_8L>;di->#>#Jug}x#dn>7&e8Ttt~l``Q)(2Nxo9(5m|(CQlJ>_x@!4+ z%v4a~q0wN}jBTjLkE-%Wlq{ltY7dEC(;7}1aM{e8#feBL5ar4?suMhQ0O#S`SUkN^ znk_#Ns)(j{Q%wsf+&D)zCf{FcdsC?x@D>P1%db%zW#EX1g>TPW|DB4Ln>4`yz$GhG zrbx!R$^smva&*G#WNPYCFGTq`%zBjcJImX2V@h6(y-yJFaYcKWy>r+x#@_YiS-!C> zIB~_Bp!w*0-C&((*M_-fZzdHMNle-K9>M+Yk#uJ6dyOWVS!P!BW(!a(hbIUtL|;mj zc(*$jo%Tvac>X}4F|~1G&!1W&zU07COf4(Y%DK~v`@=5BkndQ~gq8mAPWk@9)&(Tg z!&u-R=S$lbz>7}T3JO#JFKN`YYs2cPea9}i9eb;QYcxeHJvXJZD_vSFT>__Lr)rkn zjfSY{W~dHiaH)LP7M}86Rua}Oa^-5(dUV~p&%Ik~wrx`1KCa#d(?B?U`P{tVUq*%w zjlSBrH%^ZJloZ31JzxR=m`?Ic5U?1q@W4OFrwy6B=lf#j+gv;<|L@sY{5tG+& zj}RjsV@9DizO(5bjn(?(>g}g+{*}9vlTRVlI6`;4o_oYN!>{IfJ?D&plOdI$cHGQy z3m7kiTQ9!rS$EhCzsnn;=x%r8LE-A~M%S{sc?Hjde|ea+I>%;0MJ=S0!dCNLo>9W! zN*M>=a_HRZ0R-Ay32J)T6vC9&YJ2oOGS=RrwL13mYZH=*=S#|`j`);dPdj6}oV}ER z+<_DLgq;tWwdG=1uE$RCYf!etxUb1z!~GIAP|mODSP&ia#}%z-_6K zv=ycDPD9jy%vFDklODxMYFuaG>3x4B01Q?qo*x!7dF3_X5nNOD(TK|~eb|ayBjEkQ zm5koJlETm;R8o`Knt@nFUn*PaUgr;1eWTYkSP{bs^kqYONoC+$Jce zK5oe50PMKN=Ygnyl%r)pQVF|(V?5i3YfB$z%iZ;I?_Ot5>^PmtJf&bW&v8 z(>Rhqx~P_cHfVE)DGrTO{UEP&SrtxW;~pwK;>f{3g*Vs%p0pQl@L`R!=@j_(S0RY& zsuI3u;T~6 z{cr9TZOPu@PgQhcQXdj-Q_b}{d>Le&XwTV5O3mB!8FZJ* zBAcKvI1I!f&&sMUa)0h{DT#-8HeDa&Lo)*V00pQ$>> zW=^xC7Jt9J#7~|a_NW;*KMIJGnLJo`_{OgC=EnsdwTlF}GLBy^T1jp-TE4A=!nx16 zdUEoC)PwI?e#At>hjK;w760UjdW*WysQ0l%q$b6&Gd3(<2Sg53N+R2PY`Jl2{OLUI z5PUo5_ul9ovKv&Qjh-&9l=lQC8${XZ-K5@F$U z0QGl|Py$65Sa@)=L8QtSA#m7*ECOtxd6UeJkn(<6W0;nPJENgTGnDH>b0gXWb6fWW z&BZv-BElU6X&b10zDz}%>Mz-s?|ZCY?ZaRYDz})wPpmQO_r+ym<#;6r z@TIhnMJ^+5cJmGc!4-mf)~|f=5ym`~4?rC|Iq;QpG{*ZiueB~68m&9pl;(vhL#6#5 zSfp95ppc5PESexdSXdSSsO}2%0H!KY^>o`dUP>edt_&-uzewcVb*XC7sFv61ow3Q} zo>4HNUraO7nC{QxvoJbYZ2`D)?PRyn*@8wQ@O7zO+drf_b%7`Gwp3F~Kd37KfTS~~ zR6zEL6-4mz&N+M zMH^tQd=7kUpV0UmGqY;Ll>z+xe608_Gb0ny;{-V-{1f0hulNte`)n;K?Fm^tt(AR1 zJX!ydebjvToCa;5*S338E(%!wp3jL5-tsUt=Zf(iJ6Vtiz|M(>ApcMZt(C(`rFCsHxH1wX)uA~UdFxZn>(A|O*0*{lChzX0Y?Q1M2JZRZ5dsh(w%3{J26}aR={)38<4o5<&BJ+c!FiqB! zDpnok^4!BzsJy3E;Rfw33sh}jxBf5h)`ck9Cv4@fwR*8Db=pRACVf$^3>KNp#!5Z8 zpD023 zPQXO#^HHyemng3%Z{wOW&y78o=}CGUD#${nTm%4nN&RxDtscns9dN#N4QeA88L!=S zG^@*97w_U!QGHM(Bs!iL(X^#4vdw$3E|(a-WeW^11I;%$=!1k7S?F>)QrE;EFq<&8 zYj&{&4cZx@Cf}@V*6lGG+@Y~~^W`6wndqA)0?4hodP1E#kDdPbwO;j9Mq^)xnDL&AvVbYS5`ZTbG!BNTU<>EQPm&u6 zHiJ8S_zGoyh>)yCsa;2ne2F7^U<=S}&W_A3{R3ZDxac(v(d8O-pDj^4wL0=Je|LVp zxQnmSw!j$eU1?KnXOF4RdorOX$|!c0DtdZ5eR6CGs|{^3%*bp5Eov+)cN)9WiBlif zX5t)S)1WAG66MCTMJ|81rVr}%zNM>a^Jys1RyO56O1zZ6LpZhxb|>!Gf0mi2cp?2Q z;Set&icx@?p2E`;y|2|p7amKH$m1a~kZ!6plv@XGbehfoUh^TB4OUZEvG7(4;(ke% zwt>hJ{Cu8!G&#LAzTQe+tF2Hd%W_x2IyhT39_#f{!)Tr~x%-QPjqTfx49jnTUHqT* z-F^`+p53mBgh_fHn|x#$@3wtkgR8iPn;Js$Ek1D`kPtz285CX6_%LpAy5|C%=G%7N zq(7#6ni-ux`0LGAc(`CyC$$Je`HVC&&OuvE(yH5 z+gSB#S>&j9SS7tT-Ssq5P< zM?#LSNzeaQRznCY;yy=5iE3R~#QO?4aX=jWTPeskpO)1h>B_ zK)G@|nh39_)RUixVyCF4Ck6*7Ht-}P#$`mO;+DqFQr6FY*88do=2h~A>Onc-1o)-xF+f0|DVC|Ja z`ZVV9T?s#^Z~(gaHs39eoaVn%QKX;f*YKm!GCNOK+oCwG1E?{}C}FxmZ-kC5&-le~ z+pbF^T#r9rI|?ldo_tx=vKZ*Cc`p&B&|wtNV)*N!nz*@|TAvvwozNDa!D~yDF!iV; z1YvL2CKK$jO(`ZQey_p&MFOLt9|juH1k$2@F~6T3v_)+IfqLFaMmV`wf8h2^4v6sy zESR*lIyO>$kv^(BW>*{~P@82ouDC#Ckq@z)g|j?yS;TrDOuvFb`j~cqdn9)0vquiu zVNThM_b`|mF$DY|ry;X96_z>hiq6Iw+>W3!JdBwBqqPo*FTBcRZ((5;e+R zNsowT$9G$kcpn%&?-Nhz9E!Zt zVY-+}6Zri%(pkLZ4XOhj0Vm=c4^~$=1dfK_>QPQXLQccj4M~%_pKgTVUs0^K1>#h{ zs1FcpkOZ%b~Wky@B zQqsYsVBE`xrgbV=WeXv0;ZNgsRY8Siw`@`kM0<;y(G7|&zs^R5YVO48(%D8Vd7KS% zxg(LSCQ^!C@ahx?Q>)%Z zE4(}sqEnnr`X08Mpd-BII=k3b3mhu1dh)L?u1xB&s$1P}+9-++-9O#Ys?445NqU^P z9`q!2v_>8bz4-1NQt_l}kJjVauy##y@O#iJfRfxL;=PA-URPgis2^pnV$Ba&L8xqZ z>=7)v0tr^PAf8sT%(U+*=Dq$9Qt4i)Cu0y6@nvEjc536G*F8D~VdL*<5tPRKL%n0` zqs-$npd$Q&9~r=r8a@lbg-YNTZPL~C+=xYyzJ8YFaQtND8li~`R&QuLzn@1MX6Gtd z45QIZw9kg@3z%z4yK`1TO1-0!HOWO!>=_(8O&xe#BAJIMoHcZ>tRw94C@@s9?iX$& z&e^PS0;_NvzRW*nE{R@>q1lw~DfjusO};@DVl4XtNQ*FAB0%t^#qix%W|BL z8y!6D?{~akJefH;x;JS-ToubT z$M;zctn$)oZ~mr&LWY=wM?cadEej8gOKs!^%a`^ZPN$iCK;(T9EpO$4Qp`9g6k7n3 zF$fVAQsjehgxNCEdIcK*@d^55h2ipL#|C~ z+Aj-t@&>AwGwOG*8CFBMDs3(wKA?O9b3)n9w_UPO{A zVo+@yk-HscePIB}o0EfTVX6)R8kbk@$FWymPozqf-;Ho$=PsEaB1A^~@`z_Fn2qGo zq!c<~VGYw=G$Q6zKAsj&Kp)dq9xXiIlc{?BWA%&`iw4G0;^G)wz;&Z$-CVT;kp9hK zAbwsnViA|c60a@WWmkKARo1T*52lV4^nBu@is7EgdRE}ot2&Ox$o#i}GN>>b3*-PWf-V^6s(ckgOz5rU-7^@zm;5gvraJE&&NtJ1p z^OR?2;LURRfCFBzw%h!dfkN9Y6;$3(m@j@hmB~{SU=qLE3VD-4vj3s{e;A;((&GB5 zWZ4}1jj<}%Xq!tuEB1| z+yS}`B~oMyZE!jJ{e%?5<~6QQc17Ugw*SZ>Lx|FNELGY&8WJLLK%vPLwYYU2|KWh# zR%%YWRg`6>)>?QT#9mO(vY6q?2~`k`kRsRw1jp5b5yBI|onE<5ty8v_l*iW+5*CJO zeop@J5HutiHbX#w6G?_8CPqVMNdAkEq@M>Cr9AK*S)A-@izITT)WbE-?|dhyKk0Ix@*GEMX0d?)bcAYaj^Pn1Hi!;nkD zO%v59R+qUg0fYFMQ^UU4=|*)%+N3oGaQ~3=QA_VSZfgc}4;naWXE}sVrpRY^YDLi! zcvWi9Mf%f%5!BE19RP#BtvU>oV6~~Bgbe?JG?_x%oXs2wD?&dbsYi1xoDXW#kOf<{b2_kY zKTr+7$n^TQjVP04T(;$-XF4Zhn4HIVB^$0_ z;-Pzglk@H(HNfR(vj|n|a!1DBw=2)P8yJS}xh7kVlBoBl7R(?8IrusaCgf!Vljy?d z+>OEGnxmYRe7_Cz2pVsnAcBi#Ek|upaCH$XPbYJoew0FsM3uqI58AKL1GuuL3=u&( zbaPyT0NtYL%Td9g1`7g1OIO2~x4I?iZe>Ot0F}^WUW!$S5TBM*Q#cDLOL6K{J6JJZYemND#G45A=^7zTENhEI#a%?ycZLohx zYfxz%yNet(Rd&LI90@$LGh?dNG%q0q2<}Ol6{edC>w8v0#Ib@ghkc))9E_Fl0KG5# zrpX0gu#rRK!W{{XzqK|+^))~ymn>ENPVvaPPF-==#Sdy6genD?-{RGwhGuV4QMwg- zFzEN`>&l2;5C~;@=MRkgOC9evx=i@AhVgy&L!`Fm;l`t}W)NWY_bv991~6d%2Kh!m zGrU_@u^J_>#;1iZ^0u(UIX|5=8!j5il}Z8!n3f(Qhbd~}kP1@u0Ds3?^FPn-tl4^)V9#9FQ2kV06kl#L3;5T6}>gL@3d zgws3y%|o~}d{~3)FzkvJ;2#lA+8od8>1K~sWVteWnhP#gekviRf3TNccA=;L^$tQ= zQ#xKmw|r6QMF>5Uy!-4@vr}i<5#k6svdUS$|Df->O2ho11EMUiW&lQ;aJfDi#rPXa z&iy)hh+yjFy32vnu+9_@iLReDk(Va2cF@Q>j`b}fh)08mmxPLy(#prPBm(j|?Dx(o zkF9uKXH`!>> z=k2yn-}l0d7h`?K<~q(u?pQpeV6)%AfD;pmzsXA1b#87a)mlAGsahPreD1o}!g_!h zJd*g?RTJ;LTluHla@%EuEkp1VH4)sAD!P>`XQhneZDQmj0xsnCxli_4!p59#<% z9X20tANU_KSNu7c$=`V}d_!c{*R~igx{PF2mPoMUo7Bpc=pUx(3Td1EokC9Zqj|Iu zqoCTrOS;{Hx$VEF#O7FBPK??7Ym8qjTnd0yZB@gg1jA2XTyGRiJpO*fnG&joL}A>6TfUMWbp>tAFbDI) z0;3Vv0Ksf-gVGH}j=yNjC21AbaCu&)P6WHqtf8r9F8p_3m8~xHxTY$3HNWY7;2IUR z2vv%aB%dE3-8CjS^Q0hmHnU!7^og<92-E309a~f_+%OT|PCI%EUle-L&9y#*%D1=$ zee?B_e6-O`2rBZ0?_KbK8e8jRa<8M(YT+mXS|-`-6G+Gy-5@Gv** zu5p*%?c}d2%KXl1)=RLtxwKY%SUMj|E*+`vcp&U%TZ&A>Q1I{BJ_NUWHLX*SyMlILR+$AF^L|OO*{K()W)!naZ2G*TA0{c<|NkLw4#qi70za3&LYW z%vCBK<~Fr3BE+{@@7irrPhr3MklFa zxkX?Irz1tJ*LuyM@)E@0fnSab@hDhoM!Z#-Q749I+SI_TmFk^53?A=~#gX!j8I8y` z`LX-V)+BkveN;2~%N`+r!CBiFZ^^HWZM%mIFI));aC+(lKy5<3X^Oh}5A+Y&IZ(=Z zGEw)sOAHSw#VEsh?Ps51Vb^5KC$Gqy7oNf{ZPoJ>m26ks4xu#KA4*BgY6wo(o{xW+ z9pdy>++~W$w;l!(Gm;2lyf8_w>%GmnfxD;pjhXtc=i7NK4Q(o#Ikdc1-+sr;^;AUqk%F>9|#1T@~kTcS!DrcRwu0kG_7<@O=xl7x&ehAhPX!M@}X_ zwQ#w5qRbCo)UgyMj*f3nhq#LEI!JkFTMR73Wb0+iQK#Oo8n!vuYJN$P%!^N2oSQhF zzD;uj`!(|Y-Kc)ZtvpPR7oido4`4sB7^~@j? zZ|0}Kxz@kx$%=}4AgOPVZ_LgqT?jEAfO3?|9uQMZ+ZH{Xz_3XMv35M=u0ILpTKD6o zO?rvR)LJ*QQuWTYo4qaHIEI@cl9NO>5G|I#xZ3(jE^*qiH=C(jNyl8N$Eqeb(fhh{npa1{EYtQ(R?P1ZQJ zI^h;X%ISD<=X!EupiafvVq{=FV=NP2a82g&nE}P|cd`Xa0QYSYM5@v!Kcs7~?}v}G z_D-vYh<^R_XdOqph3}EBbfROgv|`PdsKq)5C$^}>sN(l>1i*&Ak52}!xcKM=SzE%O z+Jd8!w~Hu%j~oJ@K=?NL6-x>fz`ef};4m5Rfa?4I;yAd3obc&DW){1+j#+{W&U6O0 z_C!vAi}&djjfRS-E_V`AE@gA>Y$#Oov5p5d#tWbYgP`PWV1teAe3uF)(f|aA{=9>% z+}PUf*y)*i-2QAH_e$d*#@k1iv_ zl%l5<5w1M$V7h|WkAXGU=aFnAb0l~NVf0jCfSo_a7)8&_;_2GPj&Ui}5kCDYDV6r| zo7Y_eDA@OOO@^!0)GBWY`bmgWwEov3)rWM=OsRH{{Y+t&K}TU$jK;s5BT5t0LA&K( zenYs;658WP9#<=d+=ZmRtLD?3EkO#KgNTJuOX-PD`o-P-GmE3w^+h$o!L1o!CfN1o zfl7?Fct8nem{)u$_;98E$0Ws;nEPB=WTTir$qBHI>=}vV7H!S5{E?TgtKrP@=*5%X zxC|^cz{)QrujmXe^A|@19&uweWO=`Ac*z^SuTCfp;NjtQ{RIZh0dcg_&_+MHIEKXw zhM+9KEE zdK;E{(a}2APD*zd^Y1R}%%p=-B$STxK`&Vc2UCg2Xix5;%&-ug*GyH}Qjdl=3u3g|w^i%gKBtlFpyF88!Azd2`b zu*SmSvD`j=mflm;uYV}q5B4Dx->x6Rs*dOeOmsS`EG4h+c2i_U))qXR#O{>1rSRvk z#-v(rkjLsteo5i0}8zP9)*}dnoCmjXP zh53X(rO=@^Qg~uwYSlCAP+y#2ssV$pM!TCPrg%tjSAOXn#FXo+Re@4m-K6RKU3LFn z8^b4)KV5s~lj-iGk%cX>Hj>sLz_HfG^|AQRxw;q;Dk1rbSSh zuZ)yyf7e*XFjrL)3Dsyu!|HPxVG+1-@U&@FI1G7QT+bb|R*Gz)IVSZeH?R9ddx{M2jo@8E#mk80?lEuqCMS z4v;k7FGn**f0kNJT?(nW(;Iv#U)Gp{4h7OD-}6Ucs9Z#3Ow(h~0wR9VgNFp(XubEQ zyjgY@5K-8CIu0u5Sw&7?wnG{&r>^&DxB!BI+22#r7ypTXx6)=^XGqCO6^&u1?|M)L3JCfua~%HXiKnF7MnMH_XY%EKFTuG85( z`mFb)*k`*x)&LgXtr*vf`UXT_3qBFwr$QZ1=?{_y#P;jSoa2h2^u-o!(X0AhZ&--G zMiIM!*_VXSg>iOFZ=>OZ(^(GpI8?a%*ZUo0o6~&k9iQSAacWuTtW^Oa>C)%Z6ErYf zqFmsv#uIa2fQhV;ZN4f+X0XSak;$M*RR34tb+`ZK_n>SSHl0r z-GG+Jp2v++ug%AqV;+x;HBru4){(fG&Dt+Sn0!O9>Ou^8z+g%H+ORb29B081TT^7do$;{|c>9t>skWHW`tS)*@E2*rKpjut>_7>Mt zT9oAsEVN&gd97eYqISe5K>s#RlWH)telaC5bCANJSo+dUPArv^LV(ukc`FEfK!D!A z@FsKB$``4ek}Ywasaj+FyJ;z#S@)`kaA(wJICV%;#(%o(2(T-MBzw}ChETiNOV23;{K4ItB+oC2 z6y$B0M^JufsT*J6X70EpCtI}o*qS*fRcgbf^txN$ag_qk|B{W(@nZkc1bqml^Ipn- zLz%=j)S$S_k-n3sEN>(l=-^0LAA@7`)s0m{_S5(wZZ1t!iZdM6+n0i4xw{6^K#QE- z6A$((AV zX=rgMR?UVwR&pG^eHYAx)*^tq0RCjlkYb8Pqr%*{+Z&d}|2j~#y(qEPUYP2K>2?WD zyVeqf%&9nN6k{6A#CDB`r+$fc+ttw;82*bwx^;Os2iJZ>sr)>P%bn%@?oV)B>=4u&oS>i%{*DfN^OhbE|#hD=I1zwvkOK<}n1b zBkmau?fbP+TQtsS_qPlWP0d;7UK$zkukyiyL(;fOnLF0oX-|(+vYK`K1576~AJxXG zy^P&gL8R3OQ)vYH4Gov@yb3W{PriBDGM{!zZ(`oPLzdc3FB0q z^?ta8-rUS)Al8wi#Mey#B7i6pTkcL;Rq2D)Wq(V%u*CW|*P^7Or4wODwQ!6)&0M81 zgDp!7Ff;-eAkVT+^s&h!!0vXY7nHym1z8TtB_(w6IYI2d0i1D+taW!cr=d~jQdG>;#Wlhas*%OtI*Rl9-~?H1oASlrqhjUP|* z36Gdcmj)H;2$?kO*|4y?8RctVL~zmVpGpP3R*M19G-LERP+ChKZcBM+MVXA#nITM% zwTg?C+j%T7PCo7}7Q!{l0x?GeT~|#Q0G%S0Jq&9DC$e24bI0^d4q{`B6w(9*)26*- zX=^b&e+@l$-mO`CkDA%%7Zv>xWP&seV}&E>3hqmjD3zK#NwJO6((yxJ^`C`xf}bc zyBAiN8}Y=1X^=)-(2IQ)kM4z_^}e1?F=783pE1`O=)P1Qwa2AK`0bCjheHb&RU>b* z#7W}{fBDWn;nU+q)yW;ZF-w6}7RrzoQq#~IC5cXN3F#cIQTx*>6$YaMW_CCl&%}3) zE%~?C+dDqfm_2l)6(*h@G__|AHDCcL?{*r#1?=H%Wn^-(F~(BZ7RFnkJs6##uFtpi z02p;}CYd<4l>4xMsiD=w*VM~3+GcFFY?ESvD>Js7Ck(8|xT=Zhoh5G$RPzy%_I*n4 z64-A&-4}TDkq9HO&%TtPQ4$c%*PYO@_-tFBFj-#%>H0|6{9O_JCzFG*B{NWEoRV`* zdwAF76r7_h+v=XZ-jik&4_44BNXKkE1^Qw>N=^WJ+m7+>VM8}eo6jBMZUYA z8B}+872-|Bk-qnN>pn&1gU`*h{N<`|E#1`0qa2x%k7G+<1sVvq%ZBTnp`=a(Svybp zB8#}7;UDc|C7zNBmb|zmE$4kGMc<7`QF~p0r*zDgoZTjEsJAlpKq--s6zv&6G{Z0ifEn-B_8o#V_Q>PA= zDj0fjUXkqL;Zr+H%%Pm}{1x)***HCu@sNS==YaiWER)?Aua|w9S*wMqnBDa};bs=y zZ=@1=fV!l-AK99ZmmZ$cU`gJ(9|VR~mX|xeBYebr$M~*4Bm-6?p>B*j%H&0Gk>wk{ zK=Q;C>mYf!RypG@L2392?VJ?IO?2_CAD<1x^vT_szd2>J+we!GQAQ5wbfK;S!3SIw z-@?>3n&xQ->B2726rGVS?%iI2MKNY87omsiM!b6swpq%Vg}AY=V*0@|1?}C4vGjNk;e=v&x-wj5}gz9D)syi_oCGX3OU+>rsZq?U@U zw`xcgi{!6jP%QF{7H3&(@3qjghUcK)LU~KdHR9IB(;!f3p9uJwR#jeC=`3&*dLw`F zs(H+qp|D-KoF$9wV8n_2SW(TDOqE3YD`6~W|IK=W34|2V)}NhE*2MDei~i)@B2xv# zg2{DyJizKxcar=yXL!Ubtl~tN7_IUmfzQ~;oG^}?__Ws5-vm=fnPfdibU0+o%F|0v>8ES5YXMnrqd0U@i0yaKIiEnF_+#^znNch%W-87HRRKHH z=C?=5|2;6BmIz6Y-@evvyN{IebDdG`Pr)0(Mqj1ypq%{-c#Z+d3oi^|q_dQS=v?xg zJ&raVFJ1?=sL8StIQj2S5Bnc~(9z`f>daCGh^QJz4POV^Dtv@6B%f$>!2H^SHZX zgULH+BrM_AFkVV&dNLX+B59SA}gU3&Aby4()U&yG$;~@CmS5}s8Sb2iHfWcSwdMtKX zuSgqqbiG?54q0#0!+6Gpr(uWeV22ZTi`?)v|D1}I$(_S>Pc}9bty&Te%KZGey{Z%k z$J8Uq!bQ`r|K-PgGWnaCHt%OMs`z(fx{}FCMG8R9`jkm-dgXc`7Z$S$9-j{RDl83C zogJx-z3eb?Kjm%jIbAU_i?{DJdNkI4(P!4A)3NL*Ew9;MVH8h#{cK9d66YYx{Ox-TNpF2?s2)m~OAmtZSI?&p%z3>owsI13(-;RF15I)`k|35qA zB)I1Pp-_ggpFYRhJ7qWRCrCiLj*b4Iz+Mm~u0Be=OjbX%8;~>d_$)vC?Y9w*tNydy z;5C|ll1d7C4hfCwIF-dCa>w8bZtPgHEKfd_ZIzL?1y{x0moTy4+%E|G?8Y`FUWy8j zlevjgWxpqRncjLFTY(-X5CS$tYN>5dBaY6A5KkNd?u&t0PkmhzVE}ToCwtSwx$1xk z{#8BcD~z-`)xTlZ3L(vC$JhOJl$n3=*EZAW5wUB=ub-^$;!T-zSD+cC8>o?NTlptL zZzD1&ulP-P0jD2uPjU4Y>wJC*aqQo%g*SD5>v*Bqk>o?$c_N@7JU^Ih52pe=@7!*P zJi5>Ni_+(aQG1P5?IM2e{}k9lxUOd&6K z+lAq`^l^|@Ei{Wy={sDc-JXcaR_~7zQWY(DE-0D2MqM7eQE-j0JUO}z9+f0@$vg(8 z@2~}=w%ee){9nI3rA*BS2V$cFKY!??x1j3HftOZNC5M#!BTv0Lt8}`&O1tv>4WG44-`$>_rTb@ZsB-p)7|~$v zRb2@c*tj)EJk?Gpa)o)jg!tNna}CiJXA}^SKr>Am!ivBhLX8I?i*>5g0OV3d8=6WU zsFgp)?c}}`?XczeoA){#HxKtebfH&3qWH{LaglL3d<@n@(x8uFtLuZ)+TXc-1%3(> z%tWEH9S*p+ebMNQ*Lhb+f_4K_4-UpSsyh(R=4_9ejvU$eU&ppYex7v2g{rcXhOktd^zd5#I)BkVd^{W@e;} zdp@wUD!2NWil_U>G4VW@m*;jb-nqR1i4ey~{2S8{-46%=CPdiKVg~VmyCj%+`Twh% zl=M(uQTP4LfsY|SJ46Gh4%lk>=gqb=7PB?DTDc8*R42Z0roW22m!Le5IFJ*8I_$PY zod(TO$#8=nH#K@s?rj5!4-Xm?oYt^#}VW#E%{prw~_Yx4qKQ+_YS z(M%C_Y>)Du9X1(diK^9^`3VOuZB6DXiu<+>o7OmNqv6Bfr(CfYe4rPZJ?B)#-LV_) z`ZE&-RM~I+O!XTC;Rcbz9>y7zdHf1R0M;E6vA8J@?4?^vxSvR8!w=il&8PE@Q{rdhdpGF=0#CQ6i{|CYY>35IN?~y$`{l+KE?aOO$3vVdP(mC{ z_gT_}CS(4-x)8EKU zZ(@Y-;Og!75utXWN*c9qnehw}Rh>IJe~#>nWN-bQuo_oWI}PDsKkmW=|N2nh15)A7 zoY^hiZD`uzsg$hcu=iOeHE|2gzJRqEH+cD*xfCjv9KY+won%|xdZFBHTDRyU*D6Pt zMV+x}_z}Fd&TPgnMz`GiKDumS;$D!yq8gXkbX4QTY#```gITOH=fJtv(;4aXU+sQJ zJm@bQFHpjam*cH*gXD^7&SFUp`DPAIB?H{Gs&gjgXT$hN&*104gQj~-sMGJphv1Kx z@4aw)jqyjBK8sq3-vw=ziNq-~gyWmTd0I}q< zL4_{gEq58S;Vd5!wCMi{S`r$>nG%`%eT5aq6KLRm?~mTs)m)lvsl;KQRG02x)?!{@ z%>1avRjw7Q&NbyE=y%W?kL`eI&cIl3D&5HK$&aNHu<5SC?G@vG{esHVu%O{^_4=@u z4civ>dOHJGNZvHnH3@K-m@<8e+`ofqcUSSt?C*6&^`)*&92rKJ#yaabmM?#y!?8GR zk>YBoSx8ieVvh$sshmTORG`hJ+L{r6|K2E{?58t@Uc5LrYA;-U{ZnHN``oq$XaqV%}N{Z(jo{bjlcM{>_e9rDB`(y~IDL?!qiP!uHLeb)>0&0{reb8Yr`qxmS*&p z%;+zM-h(a62V(8rp-Lm$-na#+6CQ3|;+3L3IKL0=4ZI8^^#}7yHRU+Ll!}^By5p9+ z!nmh*Jx-xveJ6qMIyMd);@3_aK(u)*ySoi#6^4eqRQ0gnSM`Wm9#jGlAxtfQ`ACu= z^C`HCN<7J(U>elyFZ#BzMtR~hjhvchq-=ZrL(rsuEyWALp}}W0gZy;9SQ+dM>2ddv zX7bAom9;$P)lxmRjM7P`R;=G~v5Gv68OzZH;kfEDp_2z)j1jWkjVCu%v|II@&!E zffaVV-Z85$al1TPb8c5rSqmp?CwYk!h(Z7gBzc%MA){eqr*Io@KcBk?kbdmaqzo0V zPcCPzQPWNZdP>UdU!!LS~srYN(MUHns9Q!YZ6;oDx8GGprwVxIdDa-vRQM#Te(MIq7U z43v6u9^+<0&3NW$$}I14@x5|kjHHW{@0*1`xz=*z*iU*=%d%z{S8wXk)X&>dP4Z^sB@vRQnS&@EozE(qzmtO{`{}kL( z%<`kVsu|#N=#LH$C;Qw|9Qfx{>RgtVuh;6OPWl>ogysUO%NwIIap-+eN5uNnkIx6( zq#gYRV)1el-gnMEI>f$z%fQExSsGGYOkr;yT~XSA&0a7O7hrhdKa|1&JUch{Uu&vs zBHrRO7R}V6O=b;Ri)X_;O!_taMt&lm6F0(XNX?8M@#OJ|x!?Ij*y}A0JJB%@dj01m zt6CGmdSCB%i_Q2ghAzQuUul4tnq1awN*(WRsWFebeLw`xTY5zp_MBj@eGXGU1J0Os zqniT@?Dy&IjQDbuA&s?^B@wJgs4?TfhV|r;z_;S&UlvBiX!GDq#T0L?rHl#7#X43T z*wk=XD`AR}jA`Dq(^7(Vd8Y+ZY%}GnZ_c*qaUrShTQ4;5xu{9$b;pvXgKd&h!KC9} zAe^i1h&nc(H#v(N`82klsXOX+QYvwX?`*%$d9F1+Vl@z3Y2Vq>!-hw$w)=+&Y}(vp zamSV$dPO(Bw|ioHWfAysEF6kFY@}AP;5IS@+^#mmIZg;)bjI_oMK9j3bvm20i1+0d zR^=chn%mnO+iBN9ILSRI{x+iW_GsKjdhgJvo{JcME;=zp`}d|skN)`680^>5x$QRf zm`UVCQP07&GtQdnW+e}`WgE8CABy1M#PWYJLOQt5FVhtmFE2NNu~WI@U=+#e7w7WMr!th&?;V&*h4h(VL~ut=`nFlLF8I#P&-!ui85C znn9)aT-XusKn$DP<|g*ffagDyo<>m6I)|*R<8|W;T^fMq^D$k(js#~!0p>$Tx6|1N zZKHm^wfA9f#`~lC7QKF4YpNx>gr^}Gh*9i^kKpMFq<=iSvPVyG#nSw>*C%$I-Rdo6 zOw~QAh0~{0mrXp=GDIqPtmor6 zK|arfT;b)=mBw!jc>>@Ol#f4oce_^-w7Bn&8=g9^L!@IKiNDsk`JgAF8nSR>H3GuY z?UsYFG)D;97FUrM6T)q7d;E^?y^pmE?$3WqCTESWZg&_S-r!0BJS_rKIw;b zLQPUyc8e@1_AY}%5rXZ`ECgQ*G6`4p9|?uAbQf)hft$S(_%S2X0aBt$qaGW1OZ;#N zgy)T~Wc&~^W(fQdAB7efbubl?MuPWl(7OU&;lsW;0~*~hTy-93<8^;3TKjahk#G#9 z7;LCDzM|}glSukwkP_I?$$7=J1%Y;Y6R~yi|%t< zBV;it4H$$MnV7^AWn1WBtaZ3+g<|-w2US({KR`IIce-$ z)4zQ?mM_BATVs29jZJ+nJRQ_C4u_Gqw!1E^fS~0rHNKwtTb2?Dz(Kb5(Nr>RCUKNl zbgjVry|~znG4W&BCBKPVOy2V@CI3q5=O$4fUE=L;<_!88VHcY9X)q#_1|Wd4X9@?@F6=do5AxIM zy!+~L`ly4`B}l)|7|mZWDRIx>+O zDk|zBaigbB^$>pvHbmz4w?SIdF-Pc+pAF2Y6Y`9FNh)8Ac)V^CmFnwV6 zBy*ASuU6Y@#RxubPzjX{=G!@z5w>30QwP?O7fg8>wFLA1t6s}%zSGG^(htstnk^rR z1c?pChlgK9vVLT0$)tlxkG07R+=bM13Bu;M`43&pfN9o8UGWL~h`iiB&3G@E{Bzkb z?91+TC#K4x@Fh=3BFIYiA4(_)@6h1*DrR&)4e9TANi=VI3xKKU*{-!P$K2%O0rp!& zwc!VUV!!O`6L!UF4mWbKIetB5a$wHqM2pKXC7o8l5_CP;7P@X-F6ashUx-ON;c^9t zu+w8!;%Z)7lM)hMBE?BM)6Uub5UV10Y=kfSY9)IEVoit1&p}Q>7&fh=x({O|5->2_ z@nzn5^pWz)W6sYQ1UbA3Wv*vKH#Jud3p}!@!OFkSAU@EzuiUKtyRi|RiqpsK08LqJ z%J|$vUM~)W@5v^MVt1dIY1Cyb{>b)yXyFur(L3*Tr5(Sm`k3MWRxjFKTBjhS?604# z&>MRF!247Xk7SR=Zb~qVINvwga)zp!uHMAm;-wCu9xI`fxzzCkj{cY)cZ4ZdU1Lt8 z{IZVkJN;-tC3r;ujcDQn;4nr79;n0MRum-I^tyR+kZL-am=UW@aN)Wd!WN86L!*_( zL`lb}tRe)vbun&Ght&LNY%`I^&Zs8$9fn9vQ^(6@r{P#bUs56||t4;ok+0&8WKh!SKC*PWB(;YcqKI9Cu zr>J+RnQJDZ^{~lD#B-#2{XfOT|Id#u7h&frJHvnGc3gGvbT*-f7$NK0*{qHDvErxs zGE6NPadE)gE6M{5{eF$D?kU&3pVAuLo>571bMKhZyo(n>%_4%GM+~cWUJ2eAnyfe& zOg>zPn3}?l?^?Kjp9JS~gZN^nhYcM#5hR@8-(YT$Tvz);ywSbNKJ9DeR!ZycGd&-+ zxk{?*gaRLuT!CPJ?)`Q!gscToN|iIZSczCXD&Jn2$XjXSWmCOQ;pVjLud4) zm1qW8xtnZiZ`|f*HFRW*pKRKj&rBv(7MhTlujw=V_KV(rF5RwGc5yuY~mie-I5^z&=o*)$F`&S zV5Cp}yK7(Odw=|4cn6*j+5ydh9J})xruv52x}nuWVC_w{>xO*8nPEX1%Ro&@3j@iK zIDW?2%H%rrLICG^yNII>(hrWfH}lc2C=^13{xnZ~VQi*@{WM&F>(3P!F$h~Nn0;KX z8FSU>>R#a(0Sn#M8_>A(Drqr;WttB~!Pv@ks`ZnH+2IP1U{A{(UdLeGpWv ziI~;&aR`%5Te9D47ec)K`7D@sLeWtRtV8R3YaWbQ~K&6tfh^MzIO<3p3L@i&w*X`-()krF@ z`v}#9XiW%xiXm=d7BqztlMt=aj1xxFG$Z7-gOpegApvs2C99yE!`6F*X+7H`P3Ufw z`=)}Q^x4d(T5=X;%#iph3xh=fDlD4=o1nk7r*le5&gWQ^t*3Ek$$0}~t2r%p@7$QM zO>SifK9didPpv|+xiY|DSS<4Kp8$32rcxg-< zFMq^|VncspeQ)(;QqF(*!t!x_X7w=)BXV?rRpUn{yh(D3^vq~{&AdA=nB$xW4XVMJ z-Ga{FT#2K~LdM$J-(kH(yU;DVAw^r-yi9iLoPUS}yPONDcl(FNzWy9{r+A=@E~m{s znW1#v;xBr&ZhULG-O^zMSyeGxn4)fKZlzV_Y-CUz;1*r_SbH^;U*^Rlj0~v&F9M=Q zmfiOE90PZS71tk_Vb;73Z%-TlP;T5u1qiJjPxR<%NMAoz)BRY|vBO8K^)Q`oY47`yb=HsB zAx%$#W~TbZM=#S}a0U=pXjM7XsZz2q3lZz`8mb>+UCKPkK28YbeD5m4y>@={d%yXb zrxh&|&csW-(P08wVKa(hWWw=6HDV=FWut8boRpHUcVw)KTot@xa5SE6d_MTM-InDhas(x*!A5LL=0uNz;|$F}R)s%soZxue!n z2$C2c?dj)-3uKzgcp)EjC1%5>7g8s?czdEO-*n`t=kR;56(_d5aoHoYeS(@gh(`gH z40V|acQeTzhWds+K>hk9Z~U2CJ8(30hiH?=SDb?9{{BHTK*myEBE zZ8ro&E|ek9IF++9F7*HmX`W@Rxa^P44R`>1X%O_*_;QUpHQ1tjO57|?tG@cGRM^)a%tD0ccRk|4OrwAQjmz&^=J<|dlKwL|)lJyGWFKv?mh%sP{S-IesL+`P=(na&*;xV@1IZ%2GQDuBw zS;&d<>@D=UvbsHon*kICd3kB(FhGPT;uLL|&S!*L5rS z=CWK`Az$b@$S#EUb1sZsPRDFoq#Sym2d7)K9u3A}5sQu1pAG^!1R--!CKe|3ATNrP z^L+l|?Yybe(m#`sCi)72)O3={2n*vs=2;}9Dj2YvN2U7BXfDI?W2!R6TI3L2JjcqZ zD$lDy)82`kpCkT*FhEYx3%AHb{fUYDNt11?^!NI9ed^9CDEO@j#YO)p5ev6mwlLBX z?V`*kuGEv3{5D&eQwzjZHmws&~DEuv4SKe-pNl{Nuun}rN;c+-F6=|E9 zt-kGpn@_r?sX14+2AEb6(#QQj7oN=FgIY%}vV^VqcAl)2`d<;gjsU>q3Xw38v?`LI z8jppAo0gV^G_LfmpZqoSw?e*nWT=OoPd~bF|5bhY4XG^hn2w|K@mY1lYvpQC;N@Bp z#x$SI6Be*B@@C;f<{OD=s8S%G(R!`;!fcAm}%m(K)>F6td;bdvbyQYEhyEs>I zd!J!Ag^la6Oj7J*#qJjGZ-`gUF|f>Zvp_$#d!ctBtnIIvw^m4n;$71*Q%WUlypbB$ z;(PXLAlEziZbRjQhB^h~Z}96?NL;!g#~ouH@*rt~KF$@L@7542x*OuyDbD80$wS)R z`ycHIYlt8f1QW~V3FSf0V-W&}Kd^U%7CYGRD{=j~g`6A&6F~;Hy;J2dAzL!+m`h$Z zHI(pZA}Yc`*fdO2v1R4?9+`6WL4!_R6MiudF|WA$hl1X%h?*72CN&J(ubSM>C}~hY z$gz%uYCTEaYw=Hp=KkuB`bw{J^(+|_^1=7_(#g>{%?Gcsx*nnZX^s45;l;Jb&TL$} zMl*2c#qv1@%#^7lxDEGNdnfSh#R^$+41Pm_3-<+7n0tR_AZ;a>u9|B`?9rgh_3A<0 zzb@-WeIP#xJjY@4DhNhp4W3Ap++RP}CUE?^ayNbRW9;=uImL#b=FsMcBTt*-7Z962 zZwV*1Y=d6PD5Bdk@tKteO1UlD+iY}l#jcewf{p8zOi3W`0r(EhFrSskx5p-e!W&qg z@_aVV?PfDB?b+VNF|s{_W|h@j5#f69w5$)B|2ZzXh9Un@it)k=sapx-+IHt2O(z>?5|Uco3~-11EtZ+HQEM-@+X|*4@=cBV ziKL(`$*!*f`|5h!m!>RVAI^L?aOPrju&{s004Ez?8yB!J2PnRpB^jrG2m6%;&F-6# z)9XJsdPz^uF`PacE>W6iKadh@Hx1xGGO$@5p&{U|kjvzO%+)26IF$ibeWUd8N_BK( zO+pKa>(X!w(yJ8^&7C#4y@j^Kwh~LF5hs|M(eIbKPBgeg%s60TeUV@G4 zoHhwwb>J)WU;UGEYQp`80-@SjhI=GO?HNpt2~%Ym_%(VzC%#j6VE`Xjo3II4FGjCZ z@u!!3!dS$&zSLp#sLgwBO=+9SOK^US3jh zQi?Vl3Bkybc77GY8wKGJp|+J}P3~Nd0pxDx?LU?F{DC(2gz;P9MXm?b2iRN^z)y)p zy96pAbSqhKjV?wJ(!x&;BjxhSvCoiQPQw&c zw|>@Vf>kE>Qq}xgKy+g;*I%Jo`#Z7Y=^G`7j+belBNCR5EIszMY?&GO->e9Ws|}N; z12RKCq+)uV`;47QV;QWLnE&O~Ch;qe{FZ0w-Lda0X0IQeoHJjjn@ytWQdZ-=7eHCx zF^C@5C_L&Fb8(hrhn2bpG;t6FX+xzv^xOt>zV_Be;!diM=X@C(L1pmnpGvrJ=7X}g zS@PY`haG=5s_kHY*~gWQSMxTPC&+W6sJtbKeKGb~s!y}W^83p#a82UqLEXrte<)Mb zF5`b0F51~$*JkJ^8k9IKeO>sc=YbV!X zqBzqWp5Hn(1>G#H|XQGSRT3>%TqjvZ+Gb=g0ll;B|L<(vUX&9-PGo;$5jS9&A{Q zW4?CgbE+L-u&bN?675(W_U`UUFGUPT1220O5heHvkq^n<6B4ar!=8L$4o6nNO|84^ zeH&Wv6Siyxk3?}o^u*72fwL!Te$>C+dgu#hc1$yC^y-sh&=MCmOc-AgIq&y|4=u)n z3ckG?bx3FJcAFm6dhB}lU1sTHsH3Y}(t#s=$wT%iGtlbu6*S*Qj|s)j0^W{_Dn}j- zFt%YW-1iTi+)VM$XwK&mk*+g6s!Pak?5#MA>_pR$2PYjWUYrUlCe!ohm2@;kQj<+IZ1c;P?Wh@;BpgcnMdBhrq9rN;K*`nARFoiBPIfgTL@ zDtOKb*5G1jlQg3S8Yg9=j+Q|72qg_|;THi646YwyjVE7bo(-sbrGvW!fzRt5LX`Ch z7FUa)55z9n*bC|-#WI)+ogBKi+s_9qq{_993DOZ>vQBX8(BgcV5zD^r>slF~_(Xdr z$^+T~qj2+2YHi2Bpdp8$LVaf(G+gm3=;ms}*qZc#ztHibQ*G9>fg!eq5$VutZVtPv zY<42yRjrB_opw}5STxRK!6Z^xmejO;}2tdIh&S7K0< z7zdV22L_0dVAHQ$u(OkX81R1Y=6f zG)0csT)MzDgi2FXsQAfk*t_AR!-Qs50y96a9q2*Lf&q02`aYru@BY<^5@?j{bN9#^ zb+`E_drHRmXRSd6?+G~lbjkaQq8eQy)8}gidW83f_slhSsebmtbet;z77+?!JVuD+ zJ@bi;m;Cg)<&eQ{Qi7YYh#^1)fSI@w?RC@<23~tFcXChnZS32?+g8D-bv@^Xp5@+< zY{+2q-u;;)fkSOn`t-t8ph2ntF*@3)vcUyJ&0Z=yi@VlGq?y>raRKppWj!17}y%MoVqykS0_bmG+ybmAd0 z&i`TUtfJZsyEaW}p;(Jsad$876n7^$1Z#ny#a)X#G(p?q?!i3}B!%KGMT-PVDK4FS z|D4RMIh-$tSt~h6@~*tk-uHc79?k*Lv|URy*U;eP-sU_mcxz=zJ*Y;6XYS6h(VQ+- zDKFg_XsA^+*@|Q~e#S#*H^)jN|D&(Apz*hVa%=3MKXRFx)|~D0xG5Y^9?+*Hrnsm6 z`X^6@&&im97gq<2a1eW4>#w$q8kHOxh)@9X1ncsMlVs~5;Kl9MF}>s zj!3**f&zpDMFfo|t0f%=Wr;%h9wIjmD%taeeH^g$n_Jeta)Dilhy=50f3h-NX(U_I z=*!k$yVGo2#4Zi3x=pNz<#kAmH|FgDZsB2R^LzBvBzg==K@3%aVd`qaBd<}V)}jnrKGUkGo^*I)*=hcxbj zI`ld~x9>o^M?1Bv6XS;m*2bM7sSagyUn^sTBb@|^uKHir8W1%_+3N94;v+)+s!VxO z+g)dBp`nNXLrv(-aK>JoUnf_B>Kh9{jt@98M)PfkC#Wn>EI-spEIAf6hFQHek57s) ztu%8nX|}IrOz6$$(I_+VArO9K?%li6X(6vWNNRKXyb7LT^4sDMa$$1eOh`d2VfUD7 z-Pvmee`IkdvLJ_=akHsE*0c2AQxVpcZ4B%}L$B9N+USKO&9OoL<2eGC%g|>L3!3$|ZfJILc6ud8Tb`jq(-op|NG2Q4-c`(8)IPGu8|~Lm zMh_B|8u)HhAvLX2K>2&1uguQ!JUR=~jf&5S{|Ig|IRtD-)ePXROjs(71mix(#IX(I zmb*O&)`LmDq?#i(JaszGuE`X*B?Hux(duuS2gD?-aNC4A5`Dm`09fO41WW!y6L9$--~Z5>UANya zmfu315mw_OEo$M^FR)C^wWVwHw{hd`AM)OKaK#3~E&hv;2-I86>r6$vt5u(ULJe1vkJxHqll@|ACi)A?#9DY-KbW$woU zPpjo-i^xI!;eiW8Bam4@>H!s}K9~3_dOrD1=)4hH+C8ZA(^OLHjo1wMcAr95+eY=A ze(r0P%+SF3Qq04vG{nPM!J<2V=B=AxRcy-JG8wV#q)af8)IjBwb84d(wGZJDkYf&h zD=DfFW4KUl?z%M-%}h^Lnw*q{6$kH6QdCq_fhjt#mUYsi1Rm8ga{tfyXR?A^|n7bnQcqwr@ypWrMN|fPA$=&r-%#)1Za4g zxBDmne~fp&{6nJ#`5G(Zzusg1eYxjiyEHnGmh_2`1s4mF3JIqTd%wt+9jw;m87jSI zdg3fZY98}#ZCL%+l(nU<1K=*ELYFtD)-sD}9!T@@zQdwFZL@N=GPNRsgtM&Gd4i;r z0}G?lj{5)nq^N>+yvTp2yJK6g=fF&r^&?@!j{9G>#@m}58LTdcxYD0~;LF&=+B?D| zhg?wcgM|&0VXrc>%~WJDbd|9)gf}8PT|?q8at%n|UZ~EL5-NNk%M!}yhj}1sd&R|V zb57t$oJM)<^`|880sEz}asWqs{B@Y0RLPe}|FBmx@(aW!uEtFp{L_E{O3LnwFMIZpb>fQuRH%Zz#}SFa@EETF^9&ybAI=vuhweM-?Il1FvY#bI$Wrpk_{OkAy>L7 z+k(}_^)QXk z=J?Ifja&LHewav#CrLP)Pz;Ht9TOGCa*|Efm<0&H+KwH?sEdJH2W_H|oXjn$kq!4l zv-^kk8FX;66u36E603I>l{NN&h{+KzBMO!iVewEpRft@#YOURR7+&1+#UajVkIgoR zQ1DBIvP=uT5MjmBN~VY`DmP)9QnjTA@XR}rHdgyzgc_|&rkouNwQ~;=I$Y+IARqE< zVM7(vJ~fH<9^dZwO3qXv0JgE%*0SpRF88(ZvN{v=xrHfUE>Fo7NqD1|Enn4OTp`Kt z*D-=@XjagE!pdM@=)zWcr^nmozlOVY+h4}WFflG6#6tu>;|r5b2e^j{75igDfj-a4 zyk+F?8z8b1zQr#}BK|N63k#F0i4_rNhd2+oR4v+Vrh@UD&;EUyVQ>(W9PjG>$#gAA= zknP#BMnn$X4VQP<3+%r(f26IWw#D>yO71H@oxyc1+A$qvM$)(gO?VqRdggz%tdU`O zI&n+ejLvzRJXs@ZuG0zQ(M{rr`jD^Cy=Z!`z$%cG5v>Wx%K^(&Hw66~QLb z_`tyzXhBme&j=Cep3F)t+ijY&SYC9{6YT`!USQUAl$eA&xt)5 zP;Da^^p5-~?N5p7s2;T1U8lKW4)&YDf%{NOs45<+{=CqvB}v1U3)%Rg!kVsV4@C`_ zc7jch((2dfj1`!}+;a$3R-caU=97Xo(WAhHHj@K|YyQ%W>VlLfxf~@^Gxhe5XRaui zsXTQiKv!tqmPiSXqV>XqOZx;VRR^tByNri%KaAdSSdXVwACdgvvq>NqoHeO<1#6=L zMk%mGGF%Q5OL~*H%~BP8wCCC5t?2PtcZwAQ>n)I5zC*`lii-dPKE0>aDP(Rvq8oS_ zN0~ajd9iU?FDNt-dEcvt@4>|LM=kSL02 zoHaFhmXt=p>dl?CUO`3Cci(e7Mv9tN_xWmiw|KM@J6w)JadQgkSR5y7$XRpSMNl7) zirc+*>-Q{!lrNVsCGOaFKeB4WsGkw7n}&30VyV_Q)B+iNm;E(Xo0)d{z66~k`$4Uk ze9YA^a2;(gpEatY=8&wMCP9wscubu=i8drG3p6NClt%zQ@RTagJ9rl~x9XoLu5nP{ z$i4Q(QTjnC@UJlo^L%FJsi%SiDCZlu7c^#M_|@h%f_b+|vfj;M?~2i^dC0upo#Q<` zo)2hlzq|FkO}9>$OGl5ihEXBCZMyR!FLFL)DBW$Pj>k=hDgxD;CnUqf*)j31@n!Pf zV58@syN)w3hCbEueOzpdAKepWUHSIVkzI`~+&isdsa#{C;o3P-l9+Ind@U44|U5V}5BVv{)4)LNA>(n)ytyLCF!?fBaM+)}nA6{y#>IUSA+xr)E8OBV`6CQ!kq1h~A_ z9l`~l`;O2hSI=7~iY)xB{4^;u-tZPo_ERm;+@d4&9rdK{suWLaZX4H%8>!->l(>F7 zcj59%uPn;3(yqOFZD{Ui{y79%8xzpTj7X+W`BMy>SfY&(j6KK8yz>Lgq2e2$wG^3B ztb8lhTDI5XfL(Q5#;o&&L9GP)VFv*@Q~@$2O#4;j3mb7%aC`BBs78j0Bg0p))HGpf z!G7Jj*643G_Ge!LUL|`^A!2j_l&?pgWb?Nl`Svw3udAAo_}bk4tgEj!82Eb<$uyzfeHizb`sqAFIuxQrEQOX z8SsZ@b~Im|o{aqzvEJ8iOZvVoB;K~CyH}7mC2?4Mn$tf%szymR+Mk4V_k#hwA!bTN zAam4xm9XRFl>}sy+GcVm4#2LIIGrK9YL-8kTBi1-X3IYd*%NitW_%I8?<)fE3!Q-e zJXhBE$mDP7XguWQlWsz5IT{*AOBSaYV`QSL)%s%(QK#m$6A9Vt*w#!k2)XD8KaXX= zVd}DW-EG1F)Y#>iUscW>^EA-WvWF{NjS=(_^ z9YR&tL7aB^v2H?}?Fky8UrJqsV7R+1i|sWg`c!8O%@-4fkr%Xo_gtBe((vH!5hK0Y zIGA>wH}SijL$_=K85@#Zj1MeDWdjy}x6f14h^U8;K{)eZ4?TffkB$k(8@@^k-WTat ztB}f1BR4_679(r_N)q}wh`J19J}3Ekh}%k2-asEqd5JNmNLM@jocP1+`ry;2&!P^7 zPr2q%gO)(}mi9mw{kM;>V72k%FU)-bBsBqBm`tC%12_wOEMK)|uRe9#Irdr$XZGQY zY*VrwUpDOAukw2n|NWs+$P_CeI2^?F608;c+Ni~&L#o|AOIV2NQ=px8MK_LvM%7ze zE}w6y9)m}fI2!RaaVTTUO425dn*_8$w9V=ofjlwZ8Y`5UTw9Ipq|gL{A-RL&HF=~5 zE5m_nkW*;yU#xUkXb;@am1n34%H;ghFXc@k+q3W8I`z)HUJ32`mW+L~rnMG@BX6^C zNwC^hk8Ge6AxB;0BcZ-afao7r&G-*>=Z=9qMBM=qJ>|HU6oC z9Ul)kks)JQ+^vx@_Fj2r|IiMIvm`EvxSAcFA@7PzLn0Lv_NmV~Z3CJ77LaSV?+sJF z_aZK+tQmD$AQIp^oR1RiEUG!?6b>benO7#5y=139z`Db3dp_>C!n0j%+Op0EU(v*0 ztTuP#irp0xo{%%>Y0MGGevC@&vcUnG>DBcmaGz{48E?>9ucPhJ?N`C{K|!fG2I@o= z&%Vt^oHO+BKH87Em!qNYJ5-XE+dRa1t3Z)a2&5a{;f#T}|Ijo~9UwYhx5m zd@DkM_Fh*l!GVzVXRV<;4|`;s1`9V|h0pu_0IVc)aY?+I`Elj>FX>8o#(K#$^ndCq z`JZNeiRePyWC7%O;H@um-!-!$wd5W>$$aKU0p&7LaFr*n4Jl{|rz;EweVy9~_ zPwfoIm^+B$f+0m6wY*Oed%SC+!RNNR+ggsPe-DKXtSj*c@Z^KX)U-DBtilX;++s-e?0@>9Wq&@V`Tf{5HJQf<=HHCjU79tQgvl*%%jDT# z*L;ZoZH{nib&euOF<-|tVxLtdeqPikl=UhWwHI&o%(*5-4L`!!>y_1C+Z3-^KvV!H ztgT>jrU6eOrh^}AtDn4eH68yD88S7@;Tp!&9m3F=RjN{J1Ah z;b+Nw4JGh?u=5!qD?C5sTRX+RRzVjG3xyq2K|Hv8SS@_{hnMDgui%NJpg`v9#+Wbm z4=D;s4_HX!FN#QAxV9cY8Zl|^ zSm#l5pP;#i$Jr|7Nyu9LIfe_#CsKJ$hr|T>U!y6Rv|k?O&^7d!+YR0s2E^9TL?*nK->mo%rM6*1I2^&A^6BsIXyQyygV%Qy8RSQhAWjd2mrC~gS?_yG)60@#WmZ5&Esb8ZIr9HufoQ7B zU^)J87Kp}Yj-ARrhBRnyt8-2Mbw?Vm{)jjeV-YIN1Nk4#tY_D9_McexY7mZdt#SI3 zZPKJA_;RhOy+~*FBgCG5qCptOwEjY&!bau|<;VsnTWpR0U0qF6WTsL|$dTWNtEdhL z-$$Wtp_VbfD5Q|ok&4mO&?#jAs61xFkDj9Chb1>qT|9Tc;%(2xBmE>$E-ZjF>9-!z zMtPtjjIwA330{5qd%fXeaCB-+!H7^;wft6fveLv>^}$y>1rw;~x`3SjYP48yY7{uX zpyi$Gf!08=8iBalpe7bMuy@syxb!B#)a?~?vZ!jkB1Z5>6R`~| zI*C!TEw8EOa2^pOA>)Xq9dw_K(zS`xGLbyqtEjdI)W$v75r6qEUwPE}J#q%OUPuTo zBvjRwaZ=F~qh3cd(+pvd@$v7J0kR$X5Kb9=G}Y<=zr(e;0(5 z?jrQ|@@d9q*RU;8Q?escn$YqB@nQznVF8+=lR~rqKT84s@5>+B9xOn32l2tP?Tz=! z)T`q6<-JwwnV5mP%aS7cOZ)^xRAMvEBa&krKqI>>MtfFlozChD2GXIq+p=goEr$VhTsH?HcS16D*TwgtpGulO?2 zI0Xu}&=N5u(-2!}@KCn0MAi=IIN!AX~jJmzntY6AR2 z$G911FTTD%>=hjhptIRhp>uLWCPDR@h5Xn}S8*KbyGO<8ih0FO4P<3KGbyF=@XGln z-Cix-i{pq%u}Dw>(@db&O1U4=SemBE82i6akZjFZ6A&(lG02u}GuC$bVXTo>rJK8% z!J(cDoY+h=A85-8Yf^Ccoa60N8{XaCYz2{%9OI8Wj`Y55sL2LE-pclr=&+OcpJMP6_N5WhBbYKzk!B;6z%i*qN zs7o8E<*@G}AS*4ON|!qI{l_UOO>8erJ*fxZ_-)lg+jf#qdW`@tbXaIwgE`ZY;V0{v z2qz}^^Lr9CECk_0)?{L1_sDtF$={(Dw(9v`DHcR-}itFMS|Q@miTZu^~4 zaKw+-1@3;pqwBfnYs$LP+GwqvgFUJ^I8=kPMQ>M+LLQNSU=)|u=W{~Zn=jFGu`_)e zk#+cl>_^Q){~n-3L=WE>CB;;JR4f#nbVcA1=CCp}bO|B;;2rWSN_i8*k`N^40<~^Z zT`gV|2Yoc*I3^9p+_kUW_`W)R3ox2>VYay9CYSxdleXh-?1|25lm|g>?$I&qw~=8Z z^Oj!^d9#)ze8$eMAt4}^Eql&+@5r1tyC0M`C2HBxa5W;tmskmISG5u`@=5!YyX5Og zA*}z+M5Sj}cb15DnAl438F1;9HNRw+@76<~lh69_jFmLiM-IU!uOa^NfL{2rbN}6I z-Pt!*@k{{h?>^@Ym@!)IRDInceHRdk+uB-7aWn7)M*MNY9)ScSG4S zy8sq0(M+67$aMQehgR)P+?vkXO}Se*LNL0CJ)v=4gH22LD8({U5!D|#&?uFnK-L-X{Tp*+9o+1$;t{F-&uY6+E7DXc@e)z zG(@78u0zaU+olZ|MVeA?22x#)&J)?L@1x;k@0N z!J^!I(Y{b*rNc5Y;IqaX_$(R(h!m&^sNtGwulL^vk@R7t6_6K)bG#TlOhoh@6o*2Bf9Ow;BY^{uW9Ds@l3yU{eq6b0O znkM#Hl{hTy?AK-@3ahc0I8rcKLxmwX7la*QiGmz|e6d&U-aF3g(8aL*0!P5Z##6Vyf8>vg9FHAOIapVEZGr3yl8obHs6y1cnSeKY^!!h~130HK_2GSN zjyKmMqwqcWv)eKd&HL^Ad5ok)Q!e&|dFJ*vKbi1~^m~lvh-QvT2M}668^rT&Nlrm0 zB;Ovbrc>dw0lj6i>1iT~cw|}uNm&}qFTaq~U`oDSpX$qo*0?_8iu!`YT+K<*5SgxZ z-81%C3Wd;Sq`7==lj+m;D0V71*}hA3yiKa|v(gb&$ntTJTAyLb^X>lj_CfI6ycwq~5C7fu>G?7WA&U};hbl`7HohPg0XMNG^Zt!f#JEqx> zj7q#Cv}z;wAUYb zmP9@m6x|h9>J@5jyt5(V@z;-Vdq0+3G`Tg1MwNBgM>t16yzZby*}}04b14F2a0qE5 zv{I%L_(gM}c2_KAf!nRBNNGb7e>%_Z4K>}VGmG?<$znugBQZ^JOQBkK6O~_>`?E=t z&*c~vHD>Qk+J|}K-CGp(UU(4r_JBZ;2tat!5EdS_!_tG)O_A_T!XKmc)?});A`{$M zj$ZyP6(&irPYr`r_FK%3LpYeS+N}0k8F&${_{YYQG^sGVW1#0-mziQU2CG)*BhpHo zXAv0Tc#2qYFx2uEwdQ$q^8en4{Qo`E$Tz$&@x*>E*(~f5#EYDG7R=%kQp>D!*iK)( zi%$QwR90Y+34F6JXpOs8>kYft<`U|g-genpKNnaSMxiEU!a{3IQw7dZe=?{XN~a6k z;F)l_@7Y@DI&5{)N_vox*h<2{FhwLIb^U#xX5d?9E!z{12LyY2fkq*@@4=I(@xh&0 z%yp=Bm||Z#7orR3>z4G(AQ~C5B)2?aM3h z6jg+TgkYf;LN$F@Gd+GDj+TV@Jq6u(giopoh&$nPy1wzFI;Z{6Lyi2 z!zE=|dU6AB#bYxrPxgz=Spqi;O7Mhc6tVmHc`qiV~9{NkI#vBz!e=H`yu z=f$rfmPrMfQ01b+7iskt+y_Vq*c0X{K+_SKB+Ag?ZQdAsz}I@HwfYKYeV=PMHApQd z#NzKKs#i6caW^?>pOpH!1MgC5^Q+@gghirbj;1j)cv0Un|58RFD>~D%0OIM9Ee>+; zL!Q><&Lg`z8e%=uu6cKJP}IqGdvJ9N-q~hlWGnD-R%xHyeHy;vLTN2ikN=^iga)K; z(EF^Eri{Ab^|-Q<#U#bl{g_qq$V{gIM`VC+Ec{refaw%Z&4l+yUGDusMeNU#zF_u@$jh4cxO8w1YB&z_WRg6K6p5W303BGsZJo=7t&nS=36%++@rB!% zcUb$X4DmRpm#IdGCOkC7VzbzYu zdbNMP{-ilv{s&bu`c$iy)b)p*+^p7S26MbZo*;LHV64a|8|#5RhR;0cRht`#TV(kz zk!1RG%=(upbuo-}Uk+YawvVUcCP{(?ljC;!219=Vq#Er*zTA7#FoFMuw_Whv0zQ4b zo4VLpJkqLfafta__;qJhYVGg5Mu>igQj6acZE@}Ts&gw}xuq9;6W+pTZOU|U*Yu(8 z$IWg^dvyb@X7Q(+36`#ZXzxZ0)V~Yf7L1=$0ov1_97@Qx9EuMr5YY*-4*5{PH#JS< zdS&uznC{4=7;8&_c9sV0G_(1 ze3;O}UdySBXHr)ntfkui#Dch4Pjh1_d?0%4_v&BJhO=fZGBCK zopEz(gyOmUsCBm;u4OCgV)Pg@k1MbDf?6n!LbS|33SF3Ii+nq1+I*~Mf+Li4`C`b= z9*@OnOKG%hfwKPd)x+8h@B;xt!ov~A4Q#%15@}~>NcmME<%e`?#gGO8DTL9Ti~N4yuW9dKP_5iiVMat;Kb!Dxxx@Uo+#g@0I?JTh9^&`8kerDmI6m@ zoVafFb6yFUZ2m_&_3erREG1Cp7d_EtkaL;XV;1Z{@pbOP>q z*1VQt@AL<&tw4Q!kt*V|va}0DO1&x1Nqo3->dedj#yw&Nyx6R|wSNC^$%#?9-^mUk zUtTFC`2unVTZk;C^{d;-WG1JD(*#(A@KgK=7cYb)oj{-=d^)r0AnDBERoq{zq-K|b zV_D$F*Q%;7jO})9u%dtRSY#n0qmQ~qE<{PT@qX=ikp588Nq~8&V{pLH$Ji~fYNAjv zC=}~oanRAfW_l&B@X%_M3EQlYkF1G&+56GCh7lYvRikWvfhqKx`XNab20LGe-88MA zWMhx6mKd8=Pc^H`e`)vejZ_nymH`Iwcksu@r9*zE3kW@|cMVf$RKvE}7s^h6D<}@H z#QX`w!=73Z4;(jTo#G#G6_HNQDI?_Om3yvt4h;VmmJ| z_cb=FcKnK*kj`%%1A}ErUF;ToEbVBwZzs@Yx}3;3zH4}XVE1Ffoz852UU4X%lCkgy zm-tR06LKGjBR1`O7E2Q|VcWD^HI!cMP{;fuFoe5Fj=;q zDL+MjsqI32hrbMGECX2OPQS0@5>uid+Dccc@;xBx4A!$Au6>Je++Wr1$!BHZFso|K zdDZB|f>|M#1O?Dgu7?D@thrbG$je1hE#B%bAuhb@MfJ{^!KA^+Y*9Zz&q=2$aGv=^ zNoCk)5<+6`8u}PHP6nIezGjbv<;4e2XdA6~EA(mKa;4?iJW6wGd^dZ$ly8@U41GA* zW5GTPstNkMq6@a#`BbjszrEhn9it~MwXp1rv5@Rh9K<49oK?G6xyW=f8f9&2kaJlx zF~8wyIn?Oqa!rfR*X)1tMKB%9#tRtMol;Yj^`+5fF>wVsJMr z+=MxaC=Gp|ifPO_?J+Qg;3;n>71|C7VG!I?k}imF(qqb4InWp~(%7YyGmUM$8w+6a z%$YfN)O0u37ua#!sdzK1{aHw`Wq3GdA-T(U=FBLaL~$`P)yak{_BsA;u+i+AK%)nx zR8OgTB2U3uk6^QzBbG}Omt83b;gM7+2Itv}U0gg4f@=eT~jwq$Gkd&M;T$`P9!-EO;|wTHPY7wv+*D!y6}uEm#&`H~%PWvSb8 zk9p1VghM-<(O)&55vj$b7?%!F@ys7OUQe!;CHWK)G9R%hB)nf)PMEUviB^=OSbgKs z7(_l#QJdo}{8vLWNSBu2-8d{~d&*B%%6d@lcqn`Qh~lDG3c2&m-Af)iB>(wUSbCz7Zph}$YBvedey@ce9fKvywoioTHvY>p53se@*tvvbE^> zt}9+z?HJ;BPO36E5T~VK#ryoSf5s0#^V(}oomo7;R=;`plyDcmuNkk ztQi>LgIa@U*at>kk|P7RRu~n97e*4bYh?rW9s)XfkURw)*RM4=V#b8wVj*4n=QipE z&clT2@za`G+ve(D(-Gk4Iaio5@)!H74b-q*raq+}Sqr5Mj#VgO-1d-9?Ojp#=okQY z&XGAUzpc`z=b~sZCQ^$dqhNGr>*Dj@aT5|~FlomHZ5=0RNsmNS%X3&08O=>d3leO{ z5$I`3OXqS$Y|CoMu2C8+Kk>nAu4^sY_m?`wm`%E4_{fc3Fjl`1A>~H9GI_}faAixi zW2vS0e$$3jz;hhjAoFuu+*qc{E3r%+f77@r=fkN<6IfYCt_7U2Z>#|@14h{rme=ma zuDVS#ly_FZRaR!rdK`$QQ0+RJo3dh>57#FJ+1P*&M7;S!U$P>2-({R)4$IfM!&g5s zwL?RMkw&e!2*F9S1uI+oTo%uhrj?3F$mbq?RNg88Uy~sJGiy`5bOEwSAg0AWmGJiB zyyM0GNpk1Thg)I`7+}v!`pr%)Qh%rh4N;*$jz&buD%Z4(PkSaA#N=Z-zCbxidfRHt zS5EpYMSt7%E@3#47(mVy|M53thhTVi6hm-4c%;~|_?eFX#u%uRuUsDqR3J9)=PLeI zYfAsg^AO+WZK3YFBSKMP=GgS)0n{38tumrEywOg)J*54CcNtE?ksK^no5LOYBlj@( z>l|)eTrH7zzd-5TryJn!*L=V4cbvOCvXdJ-c;ot{v&!PJ+HVfND1Kh&($$f_q2P$J z56{yn@cS=^=H4#8>dY1-rBQe^GOcw$xh4lNp*6*kM3gt|U`TvCs_p6@=IYp3$UJ0z zK0LhZb-Tvv#2filyWCu`a#U(&e;|vup_Q4}x+4k?d(SJ3`qJyOpW`XI@RFU4RaC z-bbDIdq31zJ6Y-cwv--D^QsP>9TUQwUdmVuzxXfNhUZwz1zYoX@Zx5FS5qWLDi z?I^zOr0GkJA9odM5MQpb3U5CAfqMp*@?Kyn6fb(xJQjwxgXqudSjhv<+S~c|!@bp_ zh@aY{Qo{TXiXe}d-))boVod`s^%VdPu&L*Sh$;A8>#HbZrJHe|4|ZV3&SN6G0DZfN zRIqsb88Pgf0fVj$NlaY%bu|%#>H?wBc~c)Hq(l?V zFD7j7h~fanV&tO4cv=mK9v~2 ziB7HYvQX5-d+=@s^$qRQHtDa=W`!&yh0Jq&{??*mCE=So&s&NZkbf!gd=!q*S}7By zi{AurhjPXQ8X3im-%VR8w0;s{NBk#}i$F|0Tu5}doWU2ucs2tN0(7kKh+R>K=ma{emQdX70jM%VaAA*U@+C_LXMJ1F_5&NURF zeRP;S8YZW$$QYV25IQI`jRYV{k`SK96x(bjAYsjA>-!`}uTTlUWwUy5DRNmtvHkq( zI#kx&@ngmoS|A5riI5OW-Kky3j`MB-)C2e7%#*KTQl=#1J=xvr&A(HSSDTQCyE{ahqh)X zlzBeeJ3b#Uw$*VH4}W{mY=e~=O5bW#G=ZR zV3E(;urWZ$%S+LRwM&hHDey+oGL+y^hW!bCN`=e6&9;vd3GSc@P95!aB%~b%KWgHV z668&|8Z1+E=G{fn04FzHYMpoi>|Er(WXQ?QX5!*b+O>iR(Woy=NayG=o|ABF;~oj zBs_0^;)TiXUK8KYl<8FEx4nyw`7h{*FII99%&uOt{L5fXKXke<%=VNGDi^vo-#=cY zrj8?;7vK+$%Cn_Vb@e}4!PF1j%+%+Xbe6_g!kf{uAOCQt_HzLd4V$n%aHz zo@_y|pakE^qb9Pv7O%x&|C7L__aP@n^Sy35va+?f&Bok!-{f7kzA0)msf_LGb#%Y= z<+455t9dd*?5kf3Syim^bCKPC^khLYH5FUB`JXy-D3UXMbvYn%HWfj4(23BS7D&mGr0S(Wr#;2fic#}lA0crZuGoVZs6 zHg<|G@UdU?be{@do}+)N$~MhIr$(z$FjSOQ-Da>mXC7nNP1=^UYq|({I3fgjZaU3xw7cZq8z*46!m15(`M-ps=ecy+{3SEXsUb$rEqB@{E~Sq64nf zhMePl!^W^7LKO`%jFMN8&%l^gZufoZYh;3;w`TN~=>t<0B@95p5tfpnUqESWJ9wDF zL9uu|Z7okhl-993eBD=J@C4_Vv3qH&>&sc@`xXhGY?UT)_MN!n#k2JN=L{XBO8#p; zRP71I0`vsF0<9?_!?-Nh+vdV6_AF!k(fIKc2jH|g^V^dY<+DXHm!p)5dz)HCPM}?i z9NKG@)3~_8Ztsh!TSTdJSK#!HOfy6J(>$<;8~D1Uw2f>G4N|9B1b}NdzkEXZOLiT7 zJFNs-6W9EmZ@KdyE%aJ_s~F(U1uBaUwgwDNXe>gno%re73E5-%3Er_<`y7~l!m~^s zZ=GpQ88>ELV!I14wm5` zQx8vHOL5oM2kk4XGoxXT8>)EF$AdHZbS?U(dyiltEq;!69^Yhs;1wQ@Pd8IPj1@$` zT?p0@KocI?w#$G}o+(%6kGxF(L-D#KnuP$vymnKmaZ}#PybEv*lK8BxTr8}=8&S( zWqFx1OmhqS#dkje9LskUgNDY{uSXqjQbs-mj=M3g9g2aqIWN|NeRBZ?Gn7Xnhv99__dU=^t?y-@JJv zZc_&ZXL{QO^kaAPB!lQk-90k2^XUBwr# z%qj&uRQsa|Elgoo9F!4pP6i&gRCd6p0vWkKY#C>kV}ALeWYFgfQFjyR@I(EqMWv`) zF*I}6hA>^pbP{ZMkSjT?REDdgFIsJK2dt$!7(wx|L99$?PWa=ue9R!- zQKk>b0UU9)vIU7r=VrGs$0L5Cw~xNIbVl^L%KG(HDfB_wU3nMI7DLD&Q|grab;w#g zv{#mpOfWN9!Oh&?M6>HpdzGe1YgOjiTJ(z^PhugAhZQT{;Ty)RX5bH>6OKxaapOD1 zLIn&@DKm4DMo>m1D`m;2I>f2hc09?3NeEJp)n(SqS^#Rh@rlio5q$tDPuCpB#W)868X$C1FubN>j@OZ zc6-X#+2XLs)FJ0!(H6F# zgTqKa<)dOV^~(8hH`byF%t}Z&)Joq&=b+*m?HLwH(p2f+|N5=SV!kY4sOS@2pWOt2 zL^@j#AA6ni$)kqBij0z?FbFHI6#G3)RnF(*-B%q}hc{3DvyYoSvWF<2+tIj0*HQP$ zh6ais6!Q5fcEJ{-rgR+S!1+f=fa^7OnEvE%c}A!rui|4gGb7Z=N@6+BVbuWSxNNpJ zo9`oO^p3@~CfW2df>S;iM=6mO^9?R>A**8mBc#to>Q8p6uQ>=P;W?l4r*|?eO#drw zuk7MwL6`UWF-jeWkauSDwNJ%|3U&ya;UMd^%5vze774eBx4%g$S!cpMxBQ zuoOJ}|DlzCL8B+<@g@Bj7Z(qh+Bk#Se6tH@Ke%M{5$zCR#edZzs53gS$G4<1!?J)W z{UK=Aun8lKU9Mp}=n)YCNg2L(Nz^qTKBbo1sj94P%nJNf>1^#~pZ^ez=Pks{|BgUF zh*=MQJB->Y^u=<0jxe=mTJa$`lSL{SVB5-Nc_RG@6|ohmRqIc;m2IP>l0K{+kR}c) zj}HIzY<+K_9nxEMsn4nFoziVEr_9I%fk3up10aiby4wHH>UhbYV#dP`ejUwMbQfd{ z?O*Nh=*Wyi0{;S@OSAmy^fdg;LbpZiWyvJKuVlfr?a$Ct?BC}VT9nd&60NI&b zD8n3f=U#c=ab)+HPcsLvmJYtCOtMaK7F-bu+8FmEvuakFA5C*E)*S>I`y5eG;J!Z> zI^_`cav}f{anbb@$PV2Xd%7-$X1JPiKhet$8l7lreI?>+N4ROMjNX62-1Fb3kH$Qx zSf2<-6-rG!$a7JJ(h`iz@&6P`$2T&-s6uIf1AdBPzq$-icyVbpa{p)lb0HjcZ^JkK z51mAU^j!&sl=Liuz_O59lTfUTd1{#NqR7rVc)j)SuRvbQKEG}Q_;j64BTyv{68FFL zW8VKGp0izHGrhVW4#4%Wi}LSm+wDugZ~%16=QWeFr{k^G7@G*7gX-6Sok0JlDg>3a z&FCSOV;N=+W(IVi6b$9$HukdSqe36M(kN{fLUF#-GMVF&Qq&#o%N%tKrx^dCwa|UO z<*}w4qTNLF?Ez_Kk7cJ)tt&-(r*p_>0zaj?UU<(MT5~x3CgZ;naox2rPnpT~BiEs` z0Qd<^- zm*I1*$}F^%`omghFSvm@Kc+t}I5ZNAab81-cNV@k+aDX6{C#K`O^J@4TC-tKS8OQW zYb~NlQC0`NxiHD-j@)E9>vo)7?EpTJ!_#(i=cZIgC7KnxuvKJWLpa?p1<6in}`$ z2_B%h1S{I21&T{=&fJIla?Z@1Ip<9F)1Jvo_DuHg`(0~&R)HZv;!JV`uM&G=-Rbjd zEv{C9u|U`x8#%>hFk5F`APgGqXxyl668tc}I4naa1}n&0=4p2`YjRk@YpqU2EloB? zep?61eZ!AT@D`A>zu#waZ~iQGbbL_xP&2Uv*%QPzV{?TpaG2~ZFQrW`jmJJTI|C?y zR~#rg>{-Ca7w!MknG1xm<%)i9_|I=M&ol1mFW$;;i!R9+J6k-sH?b_u-X>86k0&vI zsZuY;)O6q^eye38M+aUjlZ?r(Zzw7?qrS)l+;G)c(CIhHl z`}J$-@^3uN0L07{vn9-a*3}UAt(W#8j?cl}P_=xX-1Hmy--`{szg z{0{IZ!x1~nkYy8AWJN1($~6)Ou`n<>Qn(Eb?4!L1_K01t!SQa!?f#YBCQJtZP%{XP zU}67=&m7pi7%PlN%*1iZBtx`7#Pg6)|+x{s~}MF_6ZHPJ~ElsBkTzPu(A z(yE_vXg5vbXt@{0T@|_4QAgW-V0*u&CuXCVpY0EOjoy*uXS#o54001_I%W{3p z!-r4iX@COIb2!vMOH?#3P5btjR65t4NCfZpKxm&)JZ+gxN+k*i9Q*Y*P^_8zpuy#| z{8!zLu)c6*l+>^$oNp%!AG`U+f%1&v(`)+h)gKgjG+a9nlffqYd zGVHB^(e)c54W}3LMGaQ#G@|3F8}8_0gGQwOJ*3h7%UcmP4cd;DoG5VB5s)hXkPeXt z%2+Tm6dZDHG+o5`t`t~pigHeGlWj1}>npNU(;@(GLGJ#bOO0noKM9+e5xyA_h!?W$ zO!HO16J$pVKqntF-S-^*_8gK5GhP4G6mW!>1BaUtpN}s0DI6cV)_>C^GPEoUci$<} z*TDJ_YonO`yOye|{r<7|qC58hk}sYf2HW%&_K38=EiS5AUfoh8=4+`3{mfD z-?EEn(F5P2&(^d`2IOqEikv%OJXmT7!{Vo%I}9g3nE4a))^Oz@S@=(xN6J*BA&15$ z)%?c!nNJ}z{7IPZrp_bpuANAHf6@8xzWzExTNqC6ufOxCsNrNpx=|Fv))dngO+81% zxtE6AawU8$S*`jY$~kOAX)I;e|f+1YzvoY`w|;z@LhJ(SDRs zt9U5I-%saya2Av10t`K{D=Qv2LYLSelj`t68T`)95 z|8#{tU5*;Mn6Rzy`~|%Hdfeinr3;B+ukFfg9dWrYm^z)>6Pkkra`53HlMZ zr7>NF!o_URzUZ%aWFdpAJoDX055gPkmeRFkqbf_fan0FfH8E*PU%%-B4~+o)A-T2t zARDk=YWkMM)XOQ?eE@EV%l?)A7cq2%!zV)bV{}E5LroF<0@3Q~02((ofGN+c+VuD+ ztKW*J*tCy0j)Lj4KCMY)QR`bik<)_{^06yy)ZRBfAbBmp{Kvg?$L*iLr%fCPmvcE( zAesj4s7$C<0}Fwd5BZrIy#5(^kdG8pCC;s}z?;q`Eb`P`V>Ni=mS2}MV?jgiWs-gQ zk@OGaGH}xnFqM+=%O&In4n}7vF>g~Z&6leUki0K`1FDv z(y=2M-R`*WV|n?x*h-4X55U?v;`#TtBW!P z*WH>3YU~`_1SxBnt*c|1*^582Dt|TO3y=b^a@Wjj6ecIMlbN}kwXElaFxXeixNHQm z>Oq{eYIx4hQP}?~*tueG%r}Ktll#Ax{11pz{}?8X(9ql(Mc@A>5w0K~*JKp^yFv}eVB^RoPJ zTXVfw7Dp>SOGLYe=UIuCXxx=cE~|LQ@4Cp8g^SuN>jPolbR zsznyf-gAAbmuUv`C=fFhhzT2rCAmZakQqQu4^Lk#wq&wFM|)TQiPGLU7ZvihR3KPF zM3E#7XQINAl#38A1Q2>r6Pwh)w9PI~HzNWOtV=>wwA}$A5?D;Tj6xZ{v#;$>davQ% z{vqYynRun0n^7W;zwvGDhty2@`N6E6ibjNJ%;h7gf$`?D_28^VcB0%gU@|d>DAu!E ztPkWWY=b&1iAAbZP4sJ?7W-b#yMPE;wxU={xo5>c?^$Sl5k1*S!rtrazgi4)H(&q+ zNArZXveB@JZC_q6qM!>Q>ean1Ury3K>dq5*6$Pi`2uVc4i?;kORp$`w1 z966-t*a9&G`^KCqzh@D*tfJHWhva>_{fH>n zzJY88IyGgEuZ;QOplVa&iGT#-)VU1pqB~y}GhMSJtl^JZJpuX3e43G3uN}UxWs*49J?X>gcjW?H7bU|(w)NWV5Fh(9+S1q6gX&dOMOwVq1eOi#7Ccezxj)t1&f9}wl_mBoqZ5H-?n=(fRT+W`8<kZwmZU)`!<8T={6X2ij=J7jLro0e;PW%A(aX8zoxxpRU>o)0H zI6m)#wRmi6`3Kbg7hC@ujZtd6J9%AFQPIi4fSyWw|K_StTBg;zAf+lf>`C>~#kje2 zV0M$CiKzxRm%~QSM$P-2>C=Kq*1~4zEd5WTJz$)x84S`d;JXpTxqo7Ujf6sS3Jp|5 zt=G?5bExiI!@y0!RXheByG?Ii=YD_Yij{d;*)zi(?__)C>loAbCQ4;liRBjvv#3f= z)U@{A!g0|P7o`C?@l5C8zl+T>`2>{{gB5Dl@iwhRGusJF01>9%|6aAb?(C;u((=@2 z=aC;sjlOed;by$dd%Bb72_OpBvQZ?1LcJFBWf)hU!xz_3G!wL|@j4$AanNS?xhzYAUd zTUWD*|mU zbmFKHyG$Chv7<{plcGzh+m-j<>057=vN2%Vv=2!L=0sc8l@_4(=(VWPlx5yu&rT4|t~VxkPS@td5Zb_IbyrHC zG45rRnFJ!Q+44duY3~elyxiG;8E^deOw^g&ZDHrR(U<1&#^s68&e^q3<^RIa=h!f< z4Q&V)z6)|GO}o?fJq!jGdzOj(nQIZDZCdZJGcnVzDQ{Okb8@aSBWW~_Q&OU> zZC@-wsou1y!DRQuh?UP>89uEI#vd|v_LVq`gJ+YVn}G(YPqrXS#7Sj(Y0)dW;VDrX zcuqRh#;7`D&VbpitG8yu*w=Ihow&8!>`mS!aOl!;cPdMwTLm&D8?RI|_fxqTQ3@&M z$P(NnXvJwe^23j*7rQ~O5~H+_>Q;nniJzdcAuh2t%@WAGKz+pt)5DW)Nl1K4i;JuC zQQYd7?q*<6w=w^t@E&*9Z*37553a_x_~Ol=cjM!en?L$$e;HrS%&g^7^>hRt2u`iv zv1C;7ZibZ}|H;IQs{@^2muh5e9@DeYtq-4&`GlUf5Vn4kh?qWnR?F?tF@~==Z|p%ro=pk88g$ee{hj$ErBIk2giI?8A$GI zZr$9i@omXFcz1ka&uhohvXi0U+jApNl-n02AzvtWWoC+6Ck+|Ng|+Am5i8K>5gZ_-DWS??int(aiFjo2u&9}w++^*?dmrz! z>9(d@FW_61w6^e4KfKl@0rHsL#&oy6lSZYiH(+BRNi2$gQ(W%HMsA?*`I*$;gkbon znP#t&=3wro7)Du&v&Wv8xBFKX8V_#&IH-V~0HI1TG=8sedBsk$A+f2DO^ckepeM=f zqpP8Mt8rKtw?hI^i+WS5=!dJf!zk2x!KTIsTuNdjG&se=n z4ys191g~huoyqoPprwqTM%R;{vwt?naT()%-mtWqvUOjhElY#@sowx{nrm{s5ecdq zKD!YH#-6x6svWSTVosU5iOFo}C)nRFvuV6@cnj_B{U6~ZJ}9+^qlG4&J-N7FE6?6H zHa1ug8#q;6t)Jeoq}wa0g5#6WT1tEuT<^b&XbHctu+iotx`g~kH=0jr4p=@CXn9l- zflY}9Z6M$~L*U1#bq;BWymGtjC*v=sJ$vD(s6QSQdkTHMbr++%7P9q{P;u zj$a^?&?u>yCI>IKOVY2PtJ}xG$jz_Ke^l9n;sTVH$O;|w8qLEsnR*ye}eT8?kz4He4q+OL;*pYGMC>a@12W)$=4MNx&h<6=KWv#o*=%k(e7#2hWR zH|7TT%x($7EJ7i0)6VC!-7hliQGN2fK<0;wjmPJhWD}aP0^#%1(GHxv)%!qA zd#^mvZI=DiNG>KcRP^fk9@HOUlus~O>nH~BA%59=I@zX_^8jgY!v|xwyXM%5+|a zV%`y3mjK`2gFw^YEVpT2m(UvOB71M669JUbz72mKx>#19Z5Ogjt5e`kee10yWMkPY zct#4W4(pYt9Oyhu?;MO?5)VSC&jVu}uDv~}!+myrEg~!I_5-Xjp`UB&7&=}AW^u`~ zTPGq|h&&pNd8c|iw#GK8%{V@fgRiMS@-7Qi2xP-^v4xtJMGweWZuQH!msd^d?Lwso zF)71Rm+gyWY&u5Il#U->8a_WK#jtn-#GGa-teEExf4(U`v1>MdJSqEmY##5L!9OZX zsXPdgOnSVM=xxE->Zw5E%G}*nVU6fau&YUn=WeoyH;J7(5ZWQbZFJ1Rs@KRf{LvIT zeQvgf%NOCXEKoUyt)@gV>#EewQZkjrvfR~~iXKrjH7teiV3v}<&522k#OCaxxjlv*iI8Ub5ed)mBo-%k zfZ8`)#g~;AS)xXal%fR&ty9+b@NS;8mvhX4oDzq5jl%WXuKx0m+VshtIloNA9#K6& z3t|Q#28JeoQb166usYi$~g8VG`Ed)w|SHi|m|=UtJPU2C8^yP%qjk2>Sw1}wLt zF@R&KQ7i$D{fRT9?MI&7WD=JKoYQJEe49P#YCGD^ay$gN@c;Ow8`!h^XlcBz_u18Sl!-}mA%HML7DqjDRgZ)xlYVvX*C8@;@UGpm z><%zcuZjO*mg1p^t0gdEpsirCocQMB+y}g}N)!J2c#6;<>-TD(j7C`G67r$SYvoM^ zH5nskiMh$62Yfv4u>tMJ*dV)XGtJss>9R3qpj(NmK5cy332nJpo-3E#VTT-E;!j-BhZRF`t#th z{he$s_T}w3=x(DvY21)4r|oa1j_Nl3xD1+%j2q;bm_vJe-{dWOFVk(S8y^s&Z5bux z#^Oc$MD$A8#^{c03H}t^12FlLJ0xQJo2sumc61{(iWt|h`WuW)5!eOFxOQ zibDJi-aK79uO$)(9HrYtAEN#Sq%)?l=f;YOF8y6%avj^3xb`>;d*TB3NyO6=Kibf( z{)MY6-0~)=uG-+=UlFnpvY<}U*$PF&SC8xg4^F<5q>oP!b6*y&Qyr$&8Ef0LoS4I4 zdytUkgda6=XVvNmq^>A+)2p8S1o8eMZAw5_d7ti8*aYf=&axSEt7th?d1H#=MXUIp z=iBvl^oc|+ak-e_D%5~ngtXd5K6N?RGOcqR+<|&DyCZby}-4 zR9i)-s&*V@m`jm+e4SK5%wWW63WOl)?1H?e ztAmeUwPf@k}h(4Dyw;9qoaFZpaEFDVNTDSahO+ldQuU+hq#HhvCQW?oB~V5^HO-77SP z{2c{Oj7TCl@xF?dmCKRk)e_wyESq`SzOzF{c0Iwrv&XCZ9?ZGF+McK9#gtU$95R?s zupSNfF;$3t4tjiNgtAx)m%YgbEpcJ*fHfs&VSM(v#&tW zZNbXHLOEoPq8jm)pojK!u=m_?gf{Z5nJ#|8$w5GXLhLYz%rhov5^yQ=F)vBmK2oP& z;(h-BNhY%6d|@TXhxI!y*)6%3x^t4_Z%B{IAN*;2K%W?+i4lms-3|}Im%tzFRN}%{ z?pN`UQlhk&05vL|oJyz7Xzz#WYG6gm0X_JYSSN(ZzWv`A=gR+oF4?Z9E+g+9r9yLt z4sNg3tVV!iNvsoM=`M{%q5}0mo3U=LCoIbrTP>u-snfDn*~X1`d)FqMyxTUP?(Ar| z&B~`xdtw?HT*(=?4_*AbQt6L$9}R6ST`}Xv7ObXX&%IakwNvwK-R9t(hmegjr@xt| zF$(MJuuejwNKRh8n|`i3{x*Y}b28c1)Wy*=)y=%H+g0cVWQJUXjJV`v)c~3EUEt}c zE`*uuHK(?c0Z2X{TvdP-&z8=3-&3f3d5G38KIDe&9qF~FsNb(LWpt?XkH z=3{`NaSxVrY>cl4^_d2~bX8hk$gqv;415BPJBsE@6D(gAcgJpP5SJMyO>=w-Nkw%7x4bxmG-H6@Dqx2(=k&8#iY z0J6iS^{x^4ny<5Ku+Rk0T4J+6hMN1CMRqXg*E>|Afr#>JOf~FxpJQJ5ib(w&Q1WPI z{><3i(E`t=1QL6a8akRqWH_)3A~^E&tcq!ovblCN^$3o%!}WLckku+mT_o z)E3Ln^Vy3Qc^Eu3OTiV1j$n@Epf|$EMFOW(v#HOXpyk_P+S9wbOhNstF8+bCoJr0$ zC)i3c_;^??sTr>9F@bERR*atxEkS{`<%XLil3rdDrU%S^(BfWdef^;U{neLk6rEEN% zh!rR`4ac`jb1pr0Sy|e6*DPB^T4)wI3fy04a-nM^Exh%|YJPw0*lkgN6Lhc}be%SI zX1CAHnkg>kte_ju_^R7()#k3$Mrz_G4dvbJ7?wA?d!h=dOv{{DTZcWX`EHHg^d)NI zO(&K3c9tc7u1cq_y6@AxaA32fMzg`uVE#<*urcRI5e6xgUJsDEhtYAKc>b;4uPn>+ zUk3O&kSj155~IFpqYdS(yTNbytj2hIflOzer*&E}{lJ6%6lB+?SWSR|}hq0z|9k&`v@F8nE3XvVb% zy-#LI9s{kRxnXsD*mKXg9#U7E&ckUv5LL`tPxHb!*J(5Y!|@`M9VY42E_s=JtgkE; z#`c@OrRxc-Q9S@zMw)B5;;Ah+0~nhrA>Kk0;gy~Mk>ZpI(g@hRWV8dq9V7lp#BgUI zT}kd@-LGuFvf7?eg8yXPobc>QiPIY423d3TFu=?1y;VtnpRqxaSdgdGTw@*^-Ro&jKWKbUJu$GHROpgMGr@J7#&dj1McQ|;4SODuytLCb~J5fw0N;(OPuFWXNHoX^rhu45#!xJMEMoMga7PP^ zmzF=jpsqZ9?E+7nOH+m>mP^}{&PEqMq6%{K%}`ft%csPj5-2wv8I56vkXgTd$#AXD z=K*kAH`~*n58}7Kj*9GIckg0rF*%*%rGJ0MY~aSXd3^k`%4H1_3*m9i$IBnp76`3K znQGxTgn&Z+Gg%mcr)Mm9jlKh?|BWN6r?eqnllKVak7vm~r|HYGJ|^?w%jjoH5M*ts z)NE^p-U%_13*gv{ldQE7EI3qsyW?B7Y<>PO81=&b%=)?QKFUh44ad=Ch0&iI9sRxV zPMkGHkwZSEm_p6Su*YLH$>QQv!RidrjdEkg(qcJp zz+@tgcPw?Y9R|)kM!&BATm1we*=MmcymF`sGt^^60niTNpWoyFp`P_YQ(Z=(rijke zn=XyMsLXfLX=`*6{8O%@P95#oiFdEG3QYU{UoL|FE0d^!|XZ?swGtgG2>(^E8( zFz!;{&z=GVm|QnaNiFf_S8Qp-F-TFEVB(r|4i*7b)9scao z_}EL8@B#O8t3XF&Odc*n{oA(zL~14D6h{p(Pv7D_i;;q#@C&KGUI?ktOB9DkXZGUd z>>T;%8p-yU>e)j!c@_>k3-cYqMp` z1}f4?kQ<-%DJ!5heu_{vyp>at_v2<2E8J8p7o2_P8g!BV#cVUlaK5->L)+oU(5W2; zo%`~j&?&KOOuf>WzV1C!B`uZGkFeiKt55z(Y9>zx4qW+0jtQgcppn6}*zm~4Z-3te z&^)Fi6`u#mT9*sSRBzt?Lwf7hEBw>^rmo=R^Tb3T5=_BNt<)2SkC*jTS^VkkA5Q=S zipbfgtA~8)?J*I)!pVivITb5NO)^PYP#kIiB@ov`kC0{-22*aCrS!A12Hjq_M{17e z51viUjOi(30VnhKKsK3}A_SM`CJCt|gS0Kz4Xh5qFzLC9_B1O;)7iEE z!4rF!mrSuV`+rm_$8n!sc2+1}z8PDjiK4Ky5fp)&JF~q^nZR`4=&xlrl&> z0j5HuGFtAXd9`w@ne{R$<9HS?)UrQt|8b>y4pNNJEEVkDH|8XPu&EjJ-Y6l&@7e`_ zH;bPBc0~5$)V8bZbfea~1|Im{&iD@MQA22#XyEH_a%^2|@iz7*A6I3Y^3`a{Y$fEY zpl|;5?JN3YU#8Q09lZ8s>oNNG)?Z_^R1T$!mblW{!@)5v2H`YX8)KW}IYR^lQ!7^d zKwEW;EV0Nd2zcO1(L7cA0wBI{dxl&VSFfU(St}(wh2s*-|JFA5O=>RX2|(Z$HueB~ zy7}X=9g`4DwJ!n)`RyaH8c|~DyOlA{>5IC>s`u{bZhTTaBcp~Z zkQRnP#VvU{W@3avuYIJ3W0u&!{@*UDkN3YUcB1s|jp#jgJ@OJ8HpDm&c{E`a%4xXv zqRjQE2A07;4t0^&Wx+ipp4AoUK2qW)Fm$A}r-U$9lhzZ}+*SjEHmp#Bm}KuKMOX>L zF%+MT33?GHiPHNIiOA{s9}-{J6k4n9&gZTqqIVsPt67{4pyLIKSjtXYhISoMSyf`3ZnWEy2@ihX8B{@MzGC`OzK}d+eW5Qsg|5Mw;|Mt!L zeiho}slC%(k45LrZ(eMc)6Upr9LEBwLOCQrf)p5{y_lF-K>T^(iaZ`5O?_3COn)x5 zcq~d)*^#@R7cXXqsilmydZ+{vqeS+w3UsZw%5G^h*v+{O)kqQ=Kx^@Nop zr521ZA8T>EYsJT_rqb`0qw*6iQNg>|6S1A5o?ai}BH` zMC4RJllvq>puWsV-%{lNemKgsV}$=rG<N6Fm@Bu?!p&xj>C z@>-C&z|rB4ohaoKHpbzYg;#Uzj6%Z@!7DVL2U}N@lE^vN9oHQg0H5Cc!$(6i9uw?y z!n=>KL?%^5L45;q{ycO5PuGEafM{T~#I>7iLTq_GU8Z^Ydl5BqyJ-8drPW3OB*FDs zZks-Qe08pDJw;q*MxP+#tL)gzE(z*Dy-v=k24CIx`Zs}^FhW^t-4SyC2? z`?13oLG-*e=Px5|?uC*~nU|R^>+g-o;tjGkzh}g0Jt~FHcf9>ib(ok#PT?(>s%>a< z{I8IsaoLz}s6euu@x?UG1xU0VycBm*&qH*~1*GIQBak1XDK}7u z7ph%u%^OV5C2#k9B6sjOqRlU*R3zrnmyGPvY-8(S{Yj|^P2QM%PQX!hj`{N-F)4xL z194~{1p#vI>}za}A*bSpCmw|4k=|HW{jwB`ys$+RiffdMH>^Xic}4i~!>*g-`J+=a zXMRxIU#n(;0a267EyBOWV%a9BCdo~KnO1$)XU5YW%)hC5#k%%6`U06BoaPtovdN`?W)3v8uHuL}dQ>c5JDGMkBt%9+AL6Mw5QX zM{9q=dXxB5(Z?C!JJmj2D)(14A#C8d8U|%w{&L|_nxVsu6<{ywY;Ok;h0N(mS`Fji zbv0k!RP77;q6d5ct~4K33ERXTuOqXD+m157!^U?HH+E~FlEUTP9Nnx#RCuUBruSm4 z&0CZ=?aB`=v-!yky?4qG2A??xw@LwOfT5+Wq!zk1q5Hd9DuaKVH9>#<_K56w~iS%c?d10?w*h zNBqY~&K>RTJXFvw^HlFPJ>7|@Yja#Z_&xlh{<{9Kq@OgU6 za;*3&!nS>2KAX({oe}|@lNjoocrr^oVNpJaY`INpJAP+P#I~6gW6Wm$qSJ>1%hWgOZNo}aL4chQ%vElB-1V5I2;mt;r0)F(CA5UBV?W3Ry_ha{p z@Ih2SQx_MDg?!|fQtEiF1L-w%3cfBtp76Ud?AR@<-*=Qba1+h;grIMBaE`GWk2d-* zZRyIxlqL(ZM#j$hM&SfeG*fcu_5!pWe=0*mOwIS*v3VPq=HjVuhQ1L+G6^MPy0@YyggBWb-PF-eN*Xk(@_yHxQeb$o^=Y{&v^r8rulM2;KqAy-OTe{#-XW={h!<)YtMi-4QPx_m0n$wzuMqTXI*hLKR=0)2Ua3b2E0G z{#DAm49q`pxj`@XBHgEtZ~&=Sw!rhE9$M5c6YF zaQq?!JVSMr?d@G&rEj`__eFsWa!2^ZRM&2(cBu)8Ct(!M(oC&b840li8J6CM zJKwtbf5U!Y@VE$sLqFRJ3MvRn#*zSmN3V{XUi^MMC0Osxx>R^X z3X9LMtBik})eG|oqegYVOH6|C{Rvl9e6b^xN?hY@bEK@>OM#rkS+8nIY2}Q~gSDBE z2vLNY?U9O;!*Z+x$T*H_LjuEJlJA{A{zH;EkccY!^}4lPbCLY&_UG^8w!@j^KL&`ML2@rGA#zdnGc;~|L8T-ZPq{u7OL0SyDNrHnhOMY2^;ip@BuXXA=D z$UprLDXqMlSSA>Qa*9hbq|&7E2bnQe4$&{9(49n=Xw+G$A_l#Rh=H>yQUBO-W6j}6 zWl5q=v}Loi>Ubo1>8%#ig%!dv6pZmd@&NL)PuIqQ-am)82kg0ClyD2|7g`JV>7b3w zxB<9>Dog+x#5w72ft?xO^b_cCVu%*@(^YDW#4tZIkSC;;4~Aq-#m%fzOaLMNHA*z^ zPGs%TnU=Ja%y=sFY6&_}6?1?am62HQ&3WnHU_&B7* zm3X{R&RYa`#biRiMS1Nfr}#mhH{DITT-q;djs728w0L$j?6K(6shDMa#G_Frr^XqZS{OV7s#|RK0;ttK_JW6S&(>ffR z>7O~<%zZB44mjH-6IO2G+zm5MLz^?T8N)*(7-qO_V7jAeOAh3))J#_ zMN{|L$UW0F-*<0U?sA8Y34_}g9`>V$m0#Lc zPVu|q#%w`NP}r>)$EiIZWn@XOJw2^qI=J&Tq$sp0mGsYwZfq^(0o-+Wo)nH;pm_Ed}$rha@V}9&bC+fA`78?Hd%aT6i+(6 z*&VrPaRYCipD0;@sSdTMKY|zkFE|hWUn_%QZ|Gh@=7Ch_bjA0N8k2hzAGb|};`l{l z=?0cknmiemi5cIo;tu%{u@_-HEd0Uwe(U#k_fq+0)9f26Np5mS5+nM7`D%2pc;C4ic9CBX+qj*Fz17;3BUMs?O^)1Cs`Vq8u3K(!gSZW>1rCTxWspDw8u^9iE({ zYr!)1tI=A*Q(>rvxUDG^6F#ibO$^&Wjy~gheaMOf#FdX^3*On+*DG>9mH0inG*16x zmJgnU#~;%jxs^j!lF^s}C^JI_2I@yh(R2x-P&Q#Y&f#w*mfc8{Ck8NW43)OO|*s4c?BBFS%J-KxghA z;MfxGFxhW6CQT6CxK&3^jvWA51!|^En7+~DU^_o+oL>e_5`t|n{;WVrA>b5y(=Tmq}Yut(#s42{6Xq!5ao za#GbLvK)$q3pYM>a+y!xBkIJ-@K+uxZ7ub!fn|c#ziKR1SHW`h)$@h2KUFNE(23Wy zX|kR=CBC`3K*1@cS)#{h7n1^+ik%#+gd;U6nxSA7T6EtO_ID{so80(Gy?N>{nmrm= zeN7D`dm-jkuE+U?@xXfzg8}?{t)7_F(^xTrgU~Th(R#4dnvqX)W55=`_$u0;Ki3Z~ zB(QoKZcO8kXUL(#lS9c6r3fWSL4|#8S_vV97&>?>nOk128PgtbPdG}>LC!R*b5<&g z(NvR+iyUjQLLBBu1Y6Z|2T^W3{%n5{E~_m+b4a`M79s3*UwI$ybGTfyU|YRtBqv>B zSvUf2_%9M1#PWl7{GF%B7q9kUCO4DIixekDM@YFs`-6}juei(y191;Ro_I{QM1&R4 zIGv|tHWz66duyy-Z|@!PMlAx zfjSm0o~S;0zy2z-7Bk#%g;$W%WHULDXj)SncUs34-%ipMn=Ysyxx!}dHA>owMNy?B0a$??+OzQHL&Xh$)tDuh6TFR6@2gQ{m`^0Lu))e zGLm)$Fe4W*t`7;`2{t{YpzeC-P(8-AE03;L@~uej{^SqZK>^&$FByuFF;ggY(qNM# z39vZ@{05x3eS9>ST;mQ>t=4Qx>=;iSC|TnG0YlL} z(g|Grb99J0$w+ZNxtaCLY`F5YJ4=XF$9vt->NZ!WeEUr8k=bPL!p~@)ER{n#s@T9Mbd z;bJA{Y|Pd7P;BomQU5mUeD=W&V(a3ekJ8urdInCyqwtnV0}JlT@^4q9I}FBq6z zmBJY#)Xkl+8sOr+dDfI%@!-LCwQN!&K-OOqdg8gRqiCr3`7KRQawirLHYWZw{E%+H zWRRfsx+UR^*6E)0w(PjwgR^eSHcW4TB5*)Rv3y{VUK?Dm8iS)#sCyMPu|X%c>5JEp z8T_*?eQ>M7xbYJ=I7J(Ti>&xKC4_v|Pm}9)MZ^F?JagQC zNS~d}#-=DYEHOLi$ZcIY0|Msb3A+WKd>BNB^t#n^>TBpfUT;svgd3Xl(v_Px9kkZZeQ;)@;As8x zhKq47}w*crLmR$b70U*0Rc(v3u3B+KX8UXn~tV*;;V?>c++_xB++K46$ zCIEDN95yg3KrW>(67g!*)2AQFe8s5L0-&~`GNg^Kb7Q2);Spsg=TUx$^IyF>j4-a9iz-(dynT5@O9*>ti zF60M0v42RL{XeUhJQ1vvN)LRQR0ckG!@X4gJACLJe*ge0ywfiR1CeL*s5oe7wsH>z zplXB{ooBMqzHok4&49(=i^o7!4y4sKR*Md_?Ay4HW51)q35azE>Vp|Vo$Hj<8Cex; zJ@kg(Fs_w1p4}zZgiMLl>^AG~9lIM;Fpy$uwsBWZr8N@%!SkSrc~35=VBF7aC?G}q zBwq*^$@>zCz5C_&pd|tFONkW5KctDG6MzijQ&lj#-E@M;Mwn~uH@Uv_U=b@A>j#le~eC#!yQlhqb3(m7sC;LX=`B9vnl z@Lo!2W-1NphhV8^DnIg%Xpo6R+A}@;)K;_`uO?F6r$4Cta%fJ9&OF0I88dBp=tAL9 z+H1#uvj+ZrPYAR;GG7aLFT`g|q{p`!P;Ze*5-|yy4i_Hk;nr9}TWD4DLO62I{#SpZ z{|D|@zMB5|p41C(w`dOx?Wox#(je9SQ_FZRnWSu&Ss)--a@q!i29?dDLZefQ@ZDqv z|DX2GE2^n&U*iFh?gpeoAP|aRXaQ-`R1lCVy|)m8Qi618A}DC+ARPg>6s7kPdI`Nr ziwRw-Qlv?5Cuf|ObI-VAzudF$lh137xyJmhIp+GWIsV`Gk)`@z#kVZ^CoZK1;Ke~g zYrBo*KP-?k>I$!1eR@qu+c`st{vcvq$ai?4^RoRCcm-gXQ>-5xYtoCW3NI}xt9giZ z#}l2J2)3;2J!0xyH{s)YOc~}2MI`|vUV97#EP2RzFBUi!IEdka3d!u{cSMa~MMAwK zMc6WDw24!Oc~dm~p_UlJSaMla(yP<$w#jYmv{&Fz08w07`U|~31|Y!ff!C-QdsC7) z0pI56!Y6N3Qq!u6KQw#7yWEuMmns}z8!wHx2@kt$d4x50Idui_VD6t;XuoI*%>{#H zH8UY`q@fcz3`VR8J3bzVvT`27Q6}+uuE1f$ghlDi$6YspLa*aF%nGg10F;!jBboIpD)hdb z1qiJMsypJ;B|<};PR~R4)1-jq8@);X5(lf^Z+qvoEOMqGd}qXzlvGxcEzbrWkGLkM zWaU-u&Jv;)G6OiIptTg4xnHU$1%tAmQvmeHGJrD%4+?ATBxrztmhsfe+efl{ z4+#~Xhtz@l5jp%sCJ@!WGBJc&f5V=o);<*Il-_5a!4)&R<&c|TBZ$f| z=V$VpcC;iaH1gRJxe2$&jw_a48F zhN_%;yZdIgp9t9)|Otx{izMvsD_ouRvH zal2O!{W8$4;Wk_xeWTfe&o-45)vs_9QaM8qQ}>_72N~xzF`$$)Xdhssvxct#IChOo z&^3a9F1(`*!c+y)z?+ z3`UlIb_j8s#Yb72fLyhi+7-LJ8_%@D$~6MB4kT)xFv=<29hy)4T#Jt-}?ejZwVLIS$vatt;dPWOKEmE zaxzFX=hRVlq=ce4agOu@Wff^h1T&ND4~XsAiFC`(J}DXO((8S+eC^&eXF6s+@3jr- zY-)*uVO~NRmJqS0-u97X{TBWYr&PjmmGDyCyG2r%^Oof$uICGee|Wm-bUZOX;WP2N z&m-JY-K2&jcY@9_G!`FEMu$~6A?P7wCoh4sXDKwO_GO_9x-DSXhoX$Cr#kE02<|UW zF6@>cSNznkVW=xemt;?yKGy!T@`xhi0Mis}2(xVh+9oy$}HZAx0EbXA;Y z3N44lpo*}oUeX&M2nIRB6oN}nIZFKXikkLdII5SL*LxLCN@Oay&+)}$xUKR9uOI6L*$f0~wBU;=&WmfK!(`GvM zWm*4^0(5bdnd3hHI0u&XCMj&VRFaOSjRBb4%ucW)yQcJJHgWxH<#YD4;R9B#B73jt z(@_n+AZ|Kq5=cT%0(YpMdb}3qoW^R2Bc^8&dQc&gF8M<*H?GXQ#+z~?4A2(ZMhYfT zff0-a2<>0dKL2$&&c6+)cXHAEa@I6uL0Xjtl-g~+v7Ps#+*H{=k>$_~gL?LW57>jj z=x(!h?9GP;v(5ES^)5*#A9fawQY4ul6`8RJ5d9HUyMbPlAOi7^EiI^pgs=>YXNLwu zTn}|TZT%!%EC!liN|`v)Zo*uI>=!Lz1Nw8kDz>(O1@+TvMcakC;i-|$BF*lTn~7Uz zHJ>&F5l^e}52%eD=9;kr*KiPKUriN_dmMNKYSZgHHigD#@hR*`N>n)Zv(cMUX8n3P3z&shtp@@OrTT{_4>XA<9eH;x6V{qBxeGCL@9l` zY|+!!_jXtBW*`yrY1I~K{pH9N^Qe9WKIaLlRKrJVQ~*;U*_bgdaeX!3hoYBBfi_ow z!03`Iz)-{$;QX>-j&tVGu&aiJjs4@gM&!4cZb8ZNmOAyx;??{rp{BRaUz54T+W9LU z;6o2oMuT<_~nT|NEHSrO-6txgIL%x|fqwU4eCS#Xo);thqD>SvaTLHF+XB`hPT7b-bAkMGV-coNbM+~NyX z@}m)xpJGS!PJQZukN5{lvCCjp1KeH1OVgLxX~|u|kZ&M4+Y9Th5M|lzt)87jZ{c6N zJx8rpj52H4b)TwEH0x~YYIr<0ElVQpW9H@5F8!gH-x6vWq3Y~=$b{?kgCJJQu#G92myH~cJx(C94~kyg z_Zd3~vS6iHZ;%3OdtS$V1!{Tn6#Xbf?!^vBzZjXR*x^H9DaTna`kkju$~7F93X;;j zCg>$F1GzE@VyTsuXaf$t6Y8+s$s!~8T5}JeM#w%vT#%3*j!H`-WQW83Yy^>8XNjux zo$Q{{shBD*(+#;;3iVR2=R_kVh^Kd*SRHc--Gfj-pJM1oDz=6#x6b)gQKJ%T=<^$Y z-mmQ7cM#3e1i#x{(pdF{G!SaW+zq%Y*cJ6GQSKoVCa zAK!aH8@?v5%C4ySz4hO4t{U zW~vKU0DH17sU4vn*KA%l4Q7&yB(pdN=Oldx?oGjag5vu3XyrS}R!JRGIjct7uK*P* z?<=wzb^T7PUe$Il{uDfxXedtF`ytT@>zs+*DAM~ibYTZ%zNoDz4m%5zEn8S023D6Ht%!aM&tGrQRLZn3q-Aiz5f+QmFW zrfG0|yd}EH*Ik7!XcH`$AefdWm{$ESSD&(0JL z_9AOkq`84c-hIS$?J(L8vU}s0VC7acaUNMEHC-upJ6te>SD!OI zca^(`_DcjN_Q^9~zu1kT7U{!aK4qGU3VZ|J2^4jTm<`*DS=}>|57%_vDy9@%v9jSq`!rU$$>)XLhD6CQ{|X%P`O3EVjqW)b z1jCp+&cph)GEbJNB`uhweTE~9{cUm$-F?ly&!`W0t+jupU4-A?A~Go_ZyBYJ!*a-7 z^GS(0JX|TM)%4XnZv@3*WKGgo11asUD=>u$Xvd&_l_KiKYVwKQiE(5il;Oc%+rZkn znu>G@iw%aEB>B>3uH~;d9E@-1Il#v5biJ}sy@Q*_q81$frVqx=57xZ4JT&BO2FlfC#KeYBE~=4t(z&Fcb`49s6{`qr&k#Nc@N z)4zHW*dG>TDiDsjJ@kP*?C=rP6=WXOkib^>DOuia>BhJYYt7*>XYJQ%sIo$4RTy2F z^`iCwm^FPLux+h~RJ4zM*14g9uh6Brc+waXJGiN6S znyHm3bc(9J5;&4t$* zvazVQ*>jTV%Sx14WWAOS?Rb$MWtqz%)Zl#ggbf|tp>g3sUf}NF0r_&ihF@A*x~lz- zQFujEg$@0RLcfnWXFc`gUFN5>Bkhs;i6(ZKs6-WIwN;p7wF=5%x^aiBsUxCrb7r`! z8jIEn=t#}oD)s&Zhe(^xIUrD3Z(-tJjO6EkoO>Y z-@Hv-mA%>4WUMibJF}J_GAl74bo-e(T4JEz4xZ>O18v6)b=}Nf8Nvd+xosJ=+Es?O zjg&-!u{r+13x{e~098a;x>Mc?#i@3A)46Wh9(59RRdH-P_HzaV62%(Zc+qzNexT$Y z!lJ_bqU!ksGQeYtpxG5?&wgg_&S=`Ju6R-NPt7iZn0%F>*%e$mTD)~$V=(K-e*$`H z-FZB6J$>dxPUAF+amGisDoXCVfD=0_)4kDng9+ZpI;jbIA}S-l)?m0S?ndM+$G2qz zFH>dGN#Qz@oPviTVvk%yS<-?&WN9v}P$_1T3~|G2hW@Q={#z6o|8sn6r+J%K+hrrm z5&={mO9l2e>Wn6C@Xv&sUUs;IL7bjsGNyIp^BUs~3q0z-=Lv`fjV=VsKc7LaNRve{ zHanZR!zbNbEFz5LS-K{-lF|IT)?}5?v$$Cn z)+*^-7N4*GLUB(~lL;+A_h+WcY9U`>&={$fQ3pJGmSkFsB^3H{=~J2f?3qcx5>#r3 z(0Sa|_fl6olbM+Zbl7N9aPLE7~ z40Lxw12qG$TIB~Da$}fp(G&CarR^}MNYCN>7bK?3p169gI4J?w4+N%$7z&Ew_@hG| zWQZ45x%h6;VX4qQ>(Z1;Zvum|X#7v8d>jMbAPh^MxicD{EWOhjW1M;!+i=~r9Jj7F zWeU5+Ec|J)mEFZ6?A??Fh$^ZNN^f?;J5EztNe_OwT>}+yrvt>(Q@`z(W9SQ9pZwdu zFaP=Oomv~t1Im5Z#;yRs&7ju$mN%_qm#$ITt!gitPXkmM4!_Iq_9)nAPu-cyQoza4 ztha{LD$Y;0T8*!_3U>2 +#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/thirdparty/QuadriFlow/src/adjacent-matrix.cpp b/thirdparty/QuadriFlow/src/adjacent-matrix.cpp new file mode 100755 index 00000000..e20ffb05 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/src/adjacent-matrix.hpp b/thirdparty/QuadriFlow/src/adjacent-matrix.hpp new file mode 100755 index 00000000..e3eb2e12 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/src/compare-key.hpp b/thirdparty/QuadriFlow/src/compare-key.hpp new file mode 100755 index 00000000..df9109d6 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/src/config.hpp b/thirdparty/QuadriFlow/src/config.hpp new file mode 100755 index 00000000..63b7b542 --- /dev/null +++ b/thirdparty/QuadriFlow/src/config.hpp @@ -0,0 +1,44 @@ +#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 + +// The following make_unique is to fix CXX14 in CXX11 +#include +namespace std { +template +std::unique_ptr make_unique(Args&&... args) +{ + return std::unique_ptr(new T(std::forward(args)...)); +} +} + +#endif diff --git a/thirdparty/QuadriFlow/src/dedge.cpp b/thirdparty/QuadriFlow/src/dedge.cpp new file mode 100755 index 00000000..b030e20d --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/src/dedge.hpp b/thirdparty/QuadriFlow/src/dedge.hpp new file mode 100755 index 00000000..e8ee372f --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/src/disajoint-tree.hpp b/thirdparty/QuadriFlow/src/disajoint-tree.hpp new file mode 100755 index 00000000..1822b83a --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/src/dset.hpp b/thirdparty/QuadriFlow/src/dset.hpp new file mode 100755 index 00000000..f8e6f6da --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/src/flow.hpp b/thirdparty/QuadriFlow/src/flow.hpp new file mode 100755 index 00000000..ab4a01cb --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/src/hierarchy.cpp b/thirdparty/QuadriFlow/src/hierarchy.cpp new file mode 100755 index 00000000..c333256a --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/src/hierarchy.hpp b/thirdparty/QuadriFlow/src/hierarchy.hpp new file mode 100755 index 00000000..8403038d --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/src/loader.cpp b/thirdparty/QuadriFlow/src/loader.cpp new file mode 100755 index 00000000..aa27066e --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/src/localsat.cpp b/thirdparty/QuadriFlow/src/localsat.cpp new file mode 100755 index 00000000..1ab66517 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/src/localsat.hpp b/thirdparty/QuadriFlow/src/localsat.hpp new file mode 100755 index 00000000..af952320 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/src/main.cpp b/thirdparty/QuadriFlow/src/main.cpp new file mode 100755 index 00000000..18bc4063 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/src/merge-vertex.cpp b/thirdparty/QuadriFlow/src/merge-vertex.cpp new file mode 100755 index 00000000..4c7b0a2b --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/src/merge-vertex.hpp b/thirdparty/QuadriFlow/src/merge-vertex.hpp new file mode 100755 index 00000000..8bcea3d8 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/src/optimizer.cpp b/thirdparty/QuadriFlow/src/optimizer.cpp new file mode 100755 index 00000000..1c59ad0f --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/src/optimizer.hpp b/thirdparty/QuadriFlow/src/optimizer.hpp new file mode 100755 index 00000000..ad6fa720 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/src/parametrizer-flip.cpp b/thirdparty/QuadriFlow/src/parametrizer-flip.cpp new file mode 100755 index 00000000..67b6ebbb --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/src/parametrizer-int.cpp b/thirdparty/QuadriFlow/src/parametrizer-int.cpp new file mode 100755 index 00000000..08fa36c1 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/src/parametrizer-mesh.cpp b/thirdparty/QuadriFlow/src/parametrizer-mesh.cpp new file mode 100755 index 00000000..19effe92 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/src/parametrizer-scale.cpp b/thirdparty/QuadriFlow/src/parametrizer-scale.cpp new file mode 100755 index 00000000..bbd901d0 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/src/parametrizer-sing.cpp b/thirdparty/QuadriFlow/src/parametrizer-sing.cpp new file mode 100755 index 00000000..2d600e3c --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/src/parametrizer.cpp b/thirdparty/QuadriFlow/src/parametrizer.cpp new file mode 100755 index 00000000..b8538356 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/src/parametrizer.hpp b/thirdparty/QuadriFlow/src/parametrizer.hpp new file mode 100755 index 00000000..1f4a02be --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/src/post-solver.cpp b/thirdparty/QuadriFlow/src/post-solver.cpp new file mode 100755 index 00000000..6027ddd2 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/src/post-solver.hpp b/thirdparty/QuadriFlow/src/post-solver.hpp new file mode 100755 index 00000000..546245d8 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/src/serialize.hpp b/thirdparty/QuadriFlow/src/serialize.hpp new file mode 100755 index 00000000..3e670e02 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/src/subdivide.cpp b/thirdparty/QuadriFlow/src/subdivide.cpp new file mode 100755 index 00000000..c408bbc6 --- /dev/null +++ b/thirdparty/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/thirdparty/QuadriFlow/src/subdivide.hpp b/thirdparty/QuadriFlow/src/subdivide.hpp new file mode 100755 index 00000000..a93c58ac --- /dev/null +++ b/thirdparty/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 diff --git a/thirdparty/simpleuv/thirdparty/eigen/Eigen/src/Core/Functors.h b/thirdparty/simpleuv/thirdparty/eigen/Eigen/src/Core/Functors.h index 5a1b2f28..0d668169 100644 --- a/thirdparty/simpleuv/thirdparty/eigen/Eigen/src/Core/Functors.h +++ b/thirdparty/simpleuv/thirdparty/eigen/Eigen/src/Core/Functors.h @@ -321,6 +321,24 @@ struct functor_traits > PacketAccess = packet_traits::HasNegate }; }; +// Add for QuadriFlow +/** \internal + * \brief Template functor to compute the signum of a scalar + * \sa class CwiseUnaryOp, Cwise::sign() + */ +template::IsComplex!=0) > struct scalar_sign_op; +template +struct scalar_sign_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_sign_op) + EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a) const + { + return Scalar( (a>Scalar(0)) - (a + //EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const { return internal::psign(a); } +}; + /** \internal * \brief Template functor to compute the absolute value of a scalar * diff --git a/thirdparty/simpleuv/thirdparty/eigen/Eigen/src/plugins/ArrayCwiseUnaryOps.h b/thirdparty/simpleuv/thirdparty/eigen/Eigen/src/plugins/ArrayCwiseUnaryOps.h index 1c3ed3fc..c10774e3 100644 --- a/thirdparty/simpleuv/thirdparty/eigen/Eigen/src/plugins/ArrayCwiseUnaryOps.h +++ b/thirdparty/simpleuv/thirdparty/eigen/Eigen/src/plugins/ArrayCwiseUnaryOps.h @@ -1,4 +1,9 @@ - +// Add for QuadriFlow +EIGEN_STRONG_INLINE const CwiseUnaryOp, const Derived> +sign() const +{ + return derived(); +} /** \returns an expression of the coefficient-wise absolute value of \c *this *