1 // Copyright (c) 2014  GeometryFactory (France).  All rights reserved.
2 //
3 // This file is part of CGAL (www.cgal.org)
4 //
5 // $URL: https://github.com/CGAL/cgal/blob/v5.3/BGL/include/CGAL/boost/graph/alpha_expansion_graphcut.h $
6 // $Id: alpha_expansion_graphcut.h e893ac1 2020-08-18T10:06:51+02:00 Sébastien Loriot
7 // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
8 //
9 //
10 // Author(s)     : Ilker O. Yaz, Simon Giraudot
11 
12 #ifndef CGAL_BOOST_GRAPH_ALPHA_EXPANSION_GRAPHCUT_H
13 #define CGAL_BOOST_GRAPH_ALPHA_EXPANSION_GRAPHCUT_H
14 
15 #include <CGAL/Iterator_range.h>
16 #include <CGAL/assertions.h>
17 #include <CGAL/property_map.h>
18 #ifdef CGAL_SEGMENTATION_BENCH_GRAPHCUT
19 #include <CGAL/Timer.h>
20 #endif
21 #include <CGAL/IO/trace.h>
22 
23 #include <CGAL/boost/graph/Named_function_parameters.h>
24 #include <CGAL/boost/graph/named_params_helper.h>
25 
26 #include <boost/version.hpp>
27 
28 #include <boost/graph/adjacency_list.hpp>
29 #include <boost/graph/compressed_sparse_row_graph.hpp>
30 
31 #if BOOST_VERSION >= 104400 // at this version kolmogorov_max_flow become depricated.
32 #  include <boost/graph/boykov_kolmogorov_max_flow.hpp>
33 #else
34 #  include <boost/graph/kolmogorov_max_flow.hpp>
35 #endif
36 
37 #include <vector>
38 
39 
40 
41 
42 namespace CGAL
43 {
44 
45 /// \cond SKIP_IN_MANUAL
46 namespace internal
47 {
48 
49 struct Alpha_expansion_old_API_wrapper_graph
50 {
51   typedef std::size_t vertex_descriptor;
52   typedef std::size_t edge_descriptor;
53   typedef boost::directed_tag directed_category;
54   typedef boost::disallow_parallel_edge_tag edge_parallel_category;
55   typedef boost::edge_list_graph_tag traversal_category;
56 
57   typedef boost::counting_iterator<std::size_t> counting_iterator;
58   typedef CGAL::Iterator_range<counting_iterator> counting_range;
59 
60   typedef CGAL::Identity_property_map<std::size_t> Vertex_index_map;
61   typedef CGAL::Pointer_property_map<std::size_t>::type Vertex_label_map;
62 
63   struct Vertex_label_cost_map
64   {
65     typedef std::size_t key_type;
66     typedef std::vector<double> value_type;
67     typedef value_type reference;
68     typedef boost::readable_property_map_tag category;
69 
70     const std::vector<std::vector<double> >* cost_matrix;
71 
Vertex_label_cost_mapAlpha_expansion_old_API_wrapper_graph::Vertex_label_cost_map72     Vertex_label_cost_map (const std::vector<std::vector<double> >* cost_matrix)
73       : cost_matrix (cost_matrix)
74     { }
75 
getAlpha_expansion_old_API_wrapper_graph::Vertex_label_cost_map76     friend reference get (const Vertex_label_cost_map& pmap, key_type idx)
77     {
78       std::vector<double> out;
79       out.reserve (pmap.cost_matrix->size());
80       for (std::size_t i = 0; i < pmap.cost_matrix->size(); ++ i)
81         out.push_back ((*pmap.cost_matrix)[i][idx]);
82       return out;
83     }
84 
85   };
86 
87   typedef CGAL::Pointer_property_map<double>::const_type Edge_cost_map;
88 
89   const std::vector<std::pair<std::size_t, std::size_t> >& edges;
90   const std::vector<double>& edge_costs;
91   const std::vector<std::vector<double> >& cost_matrix;
92   std::vector<std::size_t>& labels;
93 
Alpha_expansion_old_API_wrapper_graphAlpha_expansion_old_API_wrapper_graph94   Alpha_expansion_old_API_wrapper_graph (const std::vector<std::pair<std::size_t, std::size_t> >& edges,
95                                          const std::vector<double>& edge_costs,
96                                          const std::vector<std::vector<double> >& cost_matrix,
97                                          std::vector<std::size_t>& labels)
98     : edges (edges), edge_costs (edge_costs), cost_matrix (cost_matrix), labels (labels)
99   { }
100 
verticesAlpha_expansion_old_API_wrapper_graph101   friend counting_range vertices (const Alpha_expansion_old_API_wrapper_graph& graph)
102   {
103     return CGAL::make_range (boost::counting_iterator<std::size_t>(0),
104                              boost::counting_iterator<std::size_t>(graph.labels.size()));
105   }
106 
num_verticesAlpha_expansion_old_API_wrapper_graph107   friend std::size_t num_vertices (const Alpha_expansion_old_API_wrapper_graph& graph) { return graph.labels.size(); }
108 
edgesAlpha_expansion_old_API_wrapper_graph109   friend counting_range edges (const Alpha_expansion_old_API_wrapper_graph& graph)
110   {
111     return CGAL::make_range (boost::counting_iterator<std::size_t>(0),
112                              boost::counting_iterator<std::size_t>(graph.edges.size()));
113   }
114 
sourceAlpha_expansion_old_API_wrapper_graph115   friend vertex_descriptor source (edge_descriptor ed, const Alpha_expansion_old_API_wrapper_graph& graph)
116   { return graph.edges[ed].first; }
targetAlpha_expansion_old_API_wrapper_graph117   friend vertex_descriptor target (edge_descriptor ed, const Alpha_expansion_old_API_wrapper_graph& graph)
118   { return graph.edges[ed].second; }
119 
vertex_index_mapAlpha_expansion_old_API_wrapper_graph120   Vertex_index_map vertex_index_map() const { return Vertex_index_map(); }
vertex_label_mapAlpha_expansion_old_API_wrapper_graph121   Vertex_label_map vertex_label_map() { return CGAL::make_property_map(labels); }
vertex_label_cost_mapAlpha_expansion_old_API_wrapper_graph122   Vertex_label_cost_map vertex_label_cost_map() const
123   { return Vertex_label_cost_map(&cost_matrix); }
edge_cost_mapAlpha_expansion_old_API_wrapper_graph124   Edge_cost_map edge_cost_map() const { return CGAL::make_property_map(edge_costs); }
125 };
126 
127 ////////////////////////////////////////////////////////////////////////////////////////
128 //   Comments about performance:
129 //
130 // 1) With BGL:
131 //     * Using adjacency_list:
132 //     ** Without pre-allocating vertex-list
133 //       | OutEdgeList | VertexList | Performance |
134 //       |    listS    |   listS    |     25.2    |
135 //       |    vecS     |   listS    |     22.7    |
136 //       |    listS    |   vecS     |     30.7    |
137 //       |    vecS     |   vecS     |     26.1    |
138 //
139 //     ** With pre-allocating vertex-list with max-node size
140 //        (Note: exact number of vertices are not certain at the beginning)
141 //       | OutEdgeList | VertexList | Performance |
142 //       |    listS    |   vecS     |     25.2    |
143 //       |    vecS     |   vecS     |     23.4    |
144 //
145 //     * Didn't try adjacency_matrix since our graph is sparse
146 //     ( Also one can check BGL book, performance section )
147 //
148 //    Decision:
149 //     * Alpha_expansion_graph_cut_boost: use adjacency_list<vecS, listS> without
150 //       pre-allocating vertex-list.
151 //
152 // 2) With Boykov-Kolmogorov MAXFLOW software:
153 //   (http://pub.ist.ac.at/~vnk/software/maxflow-v2.21.src.tar.gz)
154 //                                  | Performance |
155 //                                  |     3.1     |
156 //     * Alpha_expansion_graph_cut_boykov_kolmogorov provides an implementation.
157 //       MAXFLOW does not provide any option for pre-allocation (It is possible with v_3.02 though).
158 //
159 // Typical Benchmark result provided by Ilker
160 //                                 | construction of vertices  |  construction of edges    | graph cut  | Total
161 //   -----------------------------------------------------------------------------------------------------------
162 //   boost with an adjacency list  |         1.53              | 1.51                      |  3.00      | 6.04
163 //   boost with CSR                | 0.11 (gather in a vector) | 0.15 (gather in a vector) |  2.67      | 2.93
164 //   MaxFlow                       |       0.042               | 0.076                     |  1.043     | 1.161
165 //
166 // The main issue for now with CSR is the construction of the opposite edge map that is too costly,
167 // since it is done by exploring all edges to find opposite
168 ////////////////////////////////////////////////////////////////////////////////////////
169 
170 } // namespace internal
171 
172 /**
173  * @brief Implements alpha-expansion graph cut algorithm.
174  *
175  * For representing graph, it uses adjacency_list with OutEdgeList = vecS, VertexList = listS.
176  * Also no pre-allocation is made for vertex-list.
177  */
178 class Alpha_expansion_boost_adjacency_list_impl
179 {
180 private:
181   typedef boost::adjacency_list_traits<boost::vecS, boost::listS, boost::directedS>
182   Adjacency_list_traits;
183 
184   typedef boost::adjacency_list<boost::vecS, boost::listS, boost::directedS,
185           // 4 vertex properties
186           boost::property<boost::vertex_index_t, std::size_t,
187           boost::property<boost::vertex_color_t, boost::default_color_type,
188           boost::property<boost::vertex_distance_t, double,
189           boost::property<boost::vertex_predecessor_t, Adjacency_list_traits::edge_descriptor >
190           > > >,
191           // 3 edge properties
192           boost::property<boost::edge_capacity_t, double,
193           boost::property<boost::edge_residual_capacity_t, double,
194           boost::property<boost::edge_reverse_t, Adjacency_list_traits::edge_descriptor> >
195           > > Graph;
196 
197   typedef boost::graph_traits<Graph> Traits;
198   typedef boost::color_traits<boost::default_color_type> ColorTraits;
199 
200 public:
201 
202   typedef Traits::vertex_descriptor Vertex_descriptor;
203   typedef Traits::vertex_iterator   Vertex_iterator;
204   typedef Traits::edge_descriptor   Edge_descriptor;
205   typedef Traits::edge_iterator     Edge_iterator;
206 
207 private:
208 
209   Graph graph;
210   Vertex_descriptor cluster_source;
211   Vertex_descriptor cluster_sink;
212 
213 public:
214 
clear_graph()215   void clear_graph()
216   {
217     graph.clear();
218     cluster_source = boost::add_vertex(graph);
219     cluster_sink = boost::add_vertex(graph);
220   }
221 
add_vertex()222   Vertex_descriptor add_vertex()
223   {
224     return boost::add_vertex(graph);
225   }
226 
add_tweight(Vertex_descriptor & v,double w1,double w2)227   void add_tweight (Vertex_descriptor& v, double w1, double w2)
228   {
229     add_edge (cluster_source, v, w1, 0);
230     add_edge (v, cluster_sink, w2, 0);
231   }
232 
init_vertices()233   void init_vertices()
234   {
235     // initialize vertex indices, it is necessary since we are using VertexList = listS
236     Vertex_iterator v_begin, v_end;
237     Traits::vertices_size_type index = 0;
238     for(boost::tie(v_begin, v_end) = vertices(graph); v_begin != v_end; ++v_begin) {
239       boost::put(boost::vertex_index, graph, *v_begin, index++);
240     }
241   }
242 
max_flow()243   double max_flow()
244   {
245 #if BOOST_VERSION >= 104400
246     return boost::boykov_kolmogorov_max_flow(graph, cluster_source,
247                                                       cluster_sink);
248 #else
249     return boost::kolmogorov_max_flow(graph, cluster_source, cluster_sink);
250 #endif
251   }
252 
253   template <typename VertexLabelMap, typename InputVertexDescriptor>
update(VertexLabelMap vertex_label_map,const std::vector<Vertex_descriptor> & inserted_vertices,InputVertexDescriptor vd,std::size_t vertex_i,std::size_t alpha)254   void update(VertexLabelMap vertex_label_map,
255               const std::vector<Vertex_descriptor>& inserted_vertices,
256               InputVertexDescriptor vd,
257               std::size_t vertex_i,
258               std::size_t alpha)
259   {
260     boost::default_color_type color = boost::get(boost::vertex_color, graph,
261                                                  inserted_vertices[vertex_i]);
262     if(std::size_t(get (vertex_label_map, vd)) != alpha
263        && color == ColorTraits::white()) //new comers (expansion occurs)
264       put (vertex_label_map, vd,
265            static_cast<typename boost::property_traits<VertexLabelMap>::value_type>(alpha));
266   }
267 
add_edge(Vertex_descriptor & v1,Vertex_descriptor & v2,double w1,double w2)268   void add_edge (Vertex_descriptor& v1, Vertex_descriptor& v2, double w1, double w2)
269   {
270     Edge_descriptor v1_v2, v2_v1;
271     bool v1_v2_added, v2_v1_added;
272 
273     boost::tie(v1_v2, v1_v2_added) = boost::add_edge(v1, v2, graph);
274     boost::tie(v2_v1, v2_v1_added) = boost::add_edge(v2, v1, graph);
275 
276     CGAL_assertion(v1_v2_added && v2_v1_added);
277     //put edge capacities
278     boost::put(boost::edge_reverse, graph, v1_v2, v2_v1);
279     boost::put(boost::edge_reverse, graph, v2_v1, v1_v2);
280 
281     //map reverse edges
282     boost::put(boost::edge_capacity, graph, v1_v2, w1);
283     boost::put(boost::edge_capacity, graph, v2_v1, w2);
284 
285   }
286 };
287 
288 // another implementation using compressed_sparse_row_graph
289 // for now there is a performance problem while setting reverse edges
290 // if that can be solved, it is faster than Alpha_expansion_graph_cut_boost
291 class Alpha_expansion_boost_compressed_sparse_row_impl
292 {
293 private:
294   // CSR only accepts bundled props
295   struct VertexP {
296     boost::default_color_type vertex_color;
297     double vertex_distance_t;
298     // ? do not now there is another way to take it, I think since edge_descriptor does not rely on properties
299     // this should be fine...
300     boost::compressed_sparse_row_graph<boost::directedS>::edge_descriptor
301     vertex_predecessor;
302   };
303 
304   struct EdgeP {
305     double edge_capacity;
306     double edge_residual_capacity;
307     boost::compressed_sparse_row_graph<boost::directedS>::edge_descriptor
308     edge_reverse;
309   };
310 
311   typedef boost::compressed_sparse_row_graph<boost::directedS,
312           VertexP, EdgeP> Graph;
313 
314   typedef boost::graph_traits<Graph> Traits;
315   typedef boost::color_traits<boost::default_color_type> ColorTraits;
316 
317 public:
318 
319   typedef Traits::vertex_descriptor Vertex_descriptor;
320   typedef Traits::vertex_iterator   Vertex_iterator;
321   typedef Traits::edge_descriptor   Edge_descriptor;
322   typedef Traits::edge_iterator     Edge_iterator;
323 
324 private:
325 
326   Graph graph;
327   std::size_t nb_vertices;
328   std::vector<std::pair<std::size_t, std::size_t> > edge_map;
329   std::vector<EdgeP>                edge_map_weights;
330 
331 public:
clear_graph()332   void clear_graph()
333   {
334     nb_vertices = 2;
335     edge_map.clear();
336     edge_map_weights.clear();
337     // edge_map.reserve(labels.size() *
338     //                  8); // there is no way to know exact edge count, it is a heuristic value
339     // edge_map_weights.reserve(labels.size() * 8);
340   }
341 
add_vertex()342   Vertex_descriptor add_vertex()
343   {
344     return (nb_vertices ++);
345   }
346 
add_tweight(Vertex_descriptor & v,double w1,double w2)347   void add_tweight (Vertex_descriptor& v, double w1, double w2)
348   {
349     add_edge (0, v, w1, 0);
350     add_edge (v, 1, w2, 0);
351   }
352 
init_vertices()353   void init_vertices()
354   {
355 #if BOOST_VERSION >= 104000
356     graph = Graph(boost::edges_are_unsorted, edge_map.begin(), edge_map.end(),
357                   edge_map_weights.begin(), nb_vertices);
358 #else
359     graph= Graph(edge_map.begin(), edge_map.end(),
360                  edge_map_weights.begin(), nb_vertices);
361 #endif
362 
363     // PERFORMANCE PROBLEM
364     // need to set reverse edge map, I guess there is no way to do that before creating the graph
365     // since we do not have edge_descs
366     // however from our edge_map, we know that each (2i, 2i + 1) is reverse pairs, how to facilitate that ?
367     // will look it back
368     Graph::edge_iterator ei, ee;
369     for(boost::tie(ei, ee) = boost::edges(graph); ei != ee; ++ei) {
370       Graph::vertex_descriptor v1 = boost::source(*ei, graph);
371       Graph::vertex_descriptor v2 = boost::target(*ei, graph);
372       std::pair<Graph::edge_descriptor, bool> opp_edge = boost::edge(v2, v1, graph);
373 
374       CGAL_assertion(opp_edge.second);
375       graph[opp_edge.first].edge_reverse =
376         *ei; // and edge_reverse of *ei will be (or already have been) set by the opp_edge
377     }
378   }
379 
max_flow()380   double max_flow()
381   {
382 #if BOOST_VERSION >= 104400
383     // since properties are bundled, defaults does not work need to specify them
384     return boost::boykov_kolmogorov_max_flow
385       (graph,
386        boost::get(&EdgeP::edge_capacity, graph),
387        boost::get(&EdgeP::edge_residual_capacity, graph),
388        boost::get(&EdgeP::edge_reverse, graph),
389        boost::get(&VertexP::vertex_predecessor, graph),
390        boost::get(&VertexP::vertex_color, graph),
391        boost::get(&VertexP::vertex_distance_t, graph),
392        boost::get(boost::vertex_index,
393                   graph), // this is not bundled, get it from graph (CRS provides one)
394        0, 1);
395 #else
396     return boost::kolmogorov_max_flow
397        (graph,
398         boost::get(&EdgeP::edge_capacity, graph),
399         boost::get(&EdgeP::edge_residual_capacity, graph),
400         boost::get(&EdgeP::edge_reverse, graph),
401         boost::get(&VertexP::vertex_predecessor, graph),
402         boost::get(&VertexP::vertex_color, graph),
403         boost::get(&VertexP::vertex_distance_t, graph),
404         boost::get(boost::vertex_index,
405                    graph), // this is not bundled, get it from graph
406         0, 1);
407 #endif
408   }
409 
410   template <typename VertexLabelMap, typename InputVertexDescriptor>
update(VertexLabelMap vertex_label_map,const std::vector<Vertex_descriptor> &,InputVertexDescriptor vd,std::size_t vertex_i,std::size_t alpha)411   void update(VertexLabelMap vertex_label_map,
412               const std::vector<Vertex_descriptor>&,
413               InputVertexDescriptor vd,
414               std::size_t vertex_i,
415               std::size_t alpha)
416   {
417     boost::default_color_type color =  graph[vertex_i + 2].vertex_color;
418     if(get(vertex_label_map, vd)!= alpha
419        && color == ColorTraits::white()) //new comers (expansion occurs)
420       put(vertex_label_map, vd, alpha);
421   }
422 
add_edge(Vertex_descriptor v1,Vertex_descriptor v2,double w1,double w2)423   void add_edge(Vertex_descriptor v1, Vertex_descriptor v2, double w1, double w2)
424   {
425     edge_map.push_back(std::make_pair(v1, v2));
426     EdgeP p1;
427     p1.edge_capacity = w1;
428     edge_map_weights.push_back(p1);
429 
430     edge_map.push_back(std::make_pair(v2, v1));
431     EdgeP p2;
432     p2.edge_capacity = w2;
433     edge_map_weights.push_back(p2);
434   }
435 
436 
437 };
438 
439 // tags
440 struct Alpha_expansion_boost_adjacency_list_tag { };
441 struct Alpha_expansion_boost_compressed_sparse_row_tag { };
442 struct Alpha_expansion_MaxFlow_tag { };
443 
444 // forward declaration
445 class Alpha_expansion_MaxFlow_impl;
446 
447 /// \endcond
448 
449 // NOTE: latest performances check (2019-07-22)
450 //
451 // Using a random graph with 50000 vertices, 100000 edges and 30 labels:
452 //
453 // METHOD                 TIMING           MEMORY
454 // Boost Adjacency list   49s              122MiB
455 // Boost CSR              187s             77MiB
456 // MaxFlow                12s              717MiB
457 
458 /**
459    \ingroup PkgBGLPartition
460 
461    regularizes a partition of a graph into `n` labels using the alpha
462    expansion algorithm \cgalCite{Boykov2001FastApproximate}.
463 
464    For a graph \f$(V,E)\f$, this function computes a partition `f`
465    that minimizes the following cost function:
466 
467    \f[
468    \mathrm{C}(f) = \sum_{\{v0,v1\} \in E} C_E(v0,v1) + \sum_{v \in V} C_V(f_v)
469    \f]
470 
471    where \f$C_E(v0,v1)\f$ is the edge cost of assigning a different
472    label to \f$v0\f$ and \f$v1\f$, and \f$C_V(f_v)\f$ is the vertex
473    cost of assigning the label \f$f\f$ to the vertex \f$v\f$.
474 
475    \tparam InputGraph a model of `VertexAndEdgeListGraph`
476 
477    \tparam EdgeCostMap a model of `ReadablePropertyMap` with
478    `boost::graph_traits<InputGraph>::%edge_descriptor` as key and `double`
479    as value
480 
481    \tparam VertexLabelCostMap a model of `ReadablePropertyMap`
482    with `boost::graph_traits<InputGraph>::%vertex_descriptor` as key and
483    `std::vector<double>` as value
484 
485    \tparam VertexLabelMap a model of `ReadWritePropertyMap` with
486    `boost::graph_traits<InputGraph>::%vertex_descriptor` as key and
487    `std::size_t` as value
488 
489    \tparam NamedParameters a sequence of named parameters
490 
491    \param input_graph the input graph.
492 
493    \param edge_cost_map a property map providing the weight of each
494    edge.
495 
496    \param vertex_label_map a property map providing the label of each
497    vertex. This map will be updated by the algorithm with the
498    regularized version of the partition.
499 
500    \param vertex_label_cost_map a property map providing, for each
501    vertex, an `std::vector` containing the cost of this vertex to
502    belong to each label. Each `std::vector` should have the same size
503    `n` (which is the number of labels), each label being indexed from
504    `0` to `n-1`. For example, `get(vertex_label_cost_map,
505    vd)[label_idx]` returns the cost of vertex `vd` to belong to the
506    label `label_idx`.
507 
508    \param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below
509 
510    \cgalNamedParamsBegin
511      \cgalParamNBegin{vertex_index_map}
512        \cgalParamDescription{a property map associating to each vertex of `input_graph` a unique index between `0` and `num_vertices(input_graph) - 1`}
513        \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits<InputGraph>::%vertex_descriptor`
514                       as key type and `std::size_t` as value type}
515        \cgalParamDefault{an automatically indexed internal map}
516        \cgalParamExtra{If this parameter is not passed, internal machinery will create and initialize
517                        a face index property map, either using the internal property map if it exists
518                        or using an external map. The latter might result in  - slightly - worsened performance
519                        in case of non-constant complexity for index access.}
520      \cgalParamNEnd
521 
522      \cgalParamNBegin{implementation_tag}
523        \cgalParamDescription{a tag used to select which implementation of the alpha expansion should be used.
524                              Available implementation tags are:
525                              - `CGAL::Alpha_expansion_boost_adjacency_list`
526                              - `CGAL::Alpha_expansion_boost_compressed_sparse_row_tag`
527                              - `CGAL::Alpha_expansion_MaxFlow_tag`}
528        \cgalParamDefault{`CGAL::Alpha_expansion_boost_adjacency_list`}
529      \cgalParamNEnd
530    \cgalNamedParamsEnd
531 
532    \note The `MaxFlow` implementation is provided by the \ref PkgSurfaceMeshSegmentationRef
533    under GPL license. The header `<CGAL/boost/graph/Alpha_expansion_MaxFlow_tag.h>`
534    must be included if users want to use this implementation.
535 */
536 template <typename InputGraph,
537           typename EdgeCostMap,
538           typename VertexLabelCostMap,
539           typename VertexLabelMap,
540           typename NamedParameters>
alpha_expansion_graphcut(const InputGraph & input_graph,EdgeCostMap edge_cost_map,VertexLabelCostMap vertex_label_cost_map,VertexLabelMap vertex_label_map,const NamedParameters & np)541 double alpha_expansion_graphcut (const InputGraph& input_graph,
542                                  EdgeCostMap edge_cost_map,
543                                  VertexLabelCostMap vertex_label_cost_map,
544                                  VertexLabelMap vertex_label_map,
545                                  const NamedParameters& np)
546 {
547   using parameters::choose_parameter;
548   using parameters::get_parameter;
549 
550   typedef boost::graph_traits<InputGraph> GT;
551   typedef typename GT::edge_descriptor input_edge_descriptor;
552   typedef typename GT::vertex_descriptor input_vertex_descriptor;
553 
554   typedef typename GetInitializedVertexIndexMap<InputGraph, NamedParameters>::type VertexIndexMap;
555   VertexIndexMap vertex_index_map = CGAL::get_initialized_vertex_index_map(input_graph, np);
556 
557   typedef typename GetImplementationTag<NamedParameters>::type Impl_tag;
558 
559   // select implementation
560   typedef typename std::conditional
561     <std::is_same<Impl_tag, Alpha_expansion_boost_adjacency_list_tag>::value,
562      Alpha_expansion_boost_adjacency_list_impl,
563      typename std::conditional
564      <std::is_same<Impl_tag, Alpha_expansion_boost_compressed_sparse_row_tag>::value,
565       Alpha_expansion_boost_compressed_sparse_row_impl,
566       Alpha_expansion_MaxFlow_impl>::type>::type
567     Alpha_expansion;
568 
569   typedef typename Alpha_expansion::Vertex_descriptor Vertex_descriptor;
570 
571   Alpha_expansion alpha_expansion;
572 
573   // TODO: check this hardcoded parameter
574   const double tolerance = 1e-10;
575 
576   double min_cut = (std::numeric_limits<double>::max)();
577 
578 #ifdef CGAL_SEGMENTATION_BENCH_GRAPHCUT
579   double vertex_creation_time, edge_creation_time, cut_time;
580   vertex_creation_time = edge_creation_time = cut_time = 0.0;
581 #endif
582 
583   std::vector<Vertex_descriptor> inserted_vertices;
584   inserted_vertices.resize(num_vertices (input_graph));
585 
586   std::size_t number_of_labels = get(vertex_label_cost_map, *(vertices(input_graph).first)).size();
587 
588   bool success;
589   do {
590     success = false;
591 
592     for (std::size_t alpha = 0; alpha < number_of_labels; ++ alpha)
593     {
594       alpha_expansion.clear_graph();
595 
596 #ifdef CGAL_SEGMENTATION_BENCH_GRAPHCUT
597       Timer timer;
598       timer.start();
599 #endif
600 
601       // For E-Data
602       // add every input vertex as a vertex to the graph, put edges to source & sink vertices
603       for (input_vertex_descriptor vd : CGAL::make_range(vertices(input_graph)))
604       {
605         std::size_t vertex_i = get(vertex_index_map, vd);
606         Vertex_descriptor new_vertex = alpha_expansion.add_vertex();
607         inserted_vertices[vertex_i] = new_vertex;
608         double source_weight = get(vertex_label_cost_map, vd)[alpha];
609         // since it is expansion move, current alpha labeled vertices will be assigned to alpha again,
610         // making sink_weight 'infinity' guarantee this.
611         double sink_weight = (std::size_t(get(vertex_label_map, vd)) == alpha ?
612                               (std::numeric_limits<double>::max)()
613                               : get(vertex_label_cost_map, vd)[get(vertex_label_map, vd)]);
614 
615         alpha_expansion.add_tweight(new_vertex, source_weight, sink_weight);
616       }
617 #ifdef CGAL_SEGMENTATION_BENCH_GRAPHCUT
618       vertex_creation_time += timer.time();
619       timer.reset();
620 #endif
621 
622       // For E-Smooth
623       // add edge between every vertex,
624       for (input_edge_descriptor ed : CGAL::make_range(edges(input_graph)))
625       {
626         input_vertex_descriptor vd1 = source(ed, input_graph);
627         input_vertex_descriptor vd2 = target(ed, input_graph);
628         std::size_t idx1 = get (vertex_index_map, vd1);
629         std::size_t idx2 = get (vertex_index_map, vd2);
630 
631         double weight = get (edge_cost_map, ed);
632 
633         Vertex_descriptor v1 = inserted_vertices[idx1],
634           v2 = inserted_vertices[idx2];
635 
636         std::size_t label_1 = get (vertex_label_map, vd1);
637         std::size_t label_2 = get (vertex_label_map, vd2);
638         if(label_1 == label_2) {
639           if(label_1 != alpha) {
640             alpha_expansion.add_edge(v1, v2, weight, weight);
641           }
642         } else {
643           Vertex_descriptor inbetween = alpha_expansion.add_vertex();
644 
645           double w1 = (label_1 == alpha) ? 0 : weight;
646           double w2 = (label_2 == alpha) ? 0 : weight;
647           alpha_expansion.add_edge(inbetween, v1, w1, w1);
648           alpha_expansion.add_edge(inbetween, v2, w2, w2);
649           alpha_expansion.add_tweight(inbetween, 0., weight);
650         }
651       }
652 #ifdef CGAL_SEGMENTATION_BENCH_GRAPHCUT
653       edge_creation_time += timer.time();
654 #endif
655 
656       alpha_expansion.init_vertices();
657 
658 #ifdef CGAL_SEGMENTATION_BENCH_GRAPHCUT
659       timer.reset();
660 #endif
661 
662       double flow = alpha_expansion.max_flow();
663 
664 #ifdef CGAL_SEGMENTATION_BENCH_GRAPHCUT
665       cut_time += timer.time();
666 #endif
667 
668       if(min_cut - flow <= flow * tolerance) {
669         continue;
670       }
671       min_cut = flow;
672       success = true;
673       //update labeling
674       for (input_vertex_descriptor vd : CGAL::make_range(vertices (input_graph)))
675       {
676         std::size_t vertex_i = get (vertex_index_map, vd);
677         alpha_expansion.update(vertex_label_map, inserted_vertices, vd, vertex_i, alpha);
678       }
679     }
680   } while(success);
681 
682 #ifdef CGAL_SEGMENTATION_BENCH_GRAPHCUT
683   CGAL_TRACE_STREAM << "vertex creation time: " << vertex_creation_time <<
684     std::endl;
685   CGAL_TRACE_STREAM << "edge creation time: " << edge_creation_time << std::endl;
686   CGAL_TRACE_STREAM << "max flow algorithm time: " << cut_time << std::endl;
687 #endif
688 
689   return min_cut;
690 }
691 
692 
693 /// \cond SKIP_IN_MANUAL
694 // variant with default NP
695 template <typename InputGraph,
696           typename EdgeCostMap,
697           typename VertexLabelCostMap,
698           typename VertexLabelMap>
alpha_expansion_graphcut(const InputGraph & input_graph,EdgeCostMap edge_cost_map,VertexLabelCostMap vertex_label_cost_map,VertexLabelMap vertex_label_map)699 double alpha_expansion_graphcut (const InputGraph& input_graph,
700                                  EdgeCostMap edge_cost_map,
701                                  VertexLabelCostMap vertex_label_cost_map,
702                                  VertexLabelMap vertex_label_map)
703 {
704   return alpha_expansion_graphcut (input_graph, edge_cost_map,
705                                    vertex_label_cost_map, vertex_label_map,
706                                    CGAL::parameters::all_default());
707 }
708 
709 // Old API
alpha_expansion_graphcut(const std::vector<std::pair<std::size_t,std::size_t>> & edges,const std::vector<double> & edge_costs,const std::vector<std::vector<double>> & cost_matrix,std::vector<std::size_t> & labels)710 inline double alpha_expansion_graphcut (const std::vector<std::pair<std::size_t, std::size_t> >& edges,
711                                         const std::vector<double>& edge_costs,
712                                         const std::vector<std::vector<double> >& cost_matrix,
713                                         std::vector<std::size_t>& labels)
714 {
715   internal::Alpha_expansion_old_API_wrapper_graph graph (edges, edge_costs, cost_matrix, labels);
716   return alpha_expansion_graphcut(graph,
717                                   graph.edge_cost_map(),
718                                   graph.vertex_label_cost_map(),
719                                   graph.vertex_label_map(),
720                                   CGAL::parameters::vertex_index_map (graph.vertex_index_map()));
721 }
722 
723 template <typename AlphaExpansionImplementationTag>
alpha_expansion_graphcut(const std::vector<std::pair<std::size_t,std::size_t>> & edges,const std::vector<double> & edge_costs,const std::vector<std::vector<double>> & cost_matrix,std::vector<std::size_t> & labels,const AlphaExpansionImplementationTag &)724 double alpha_expansion_graphcut (const std::vector<std::pair<std::size_t, std::size_t> >& edges,
725                                  const std::vector<double>& edge_costs,
726                                  const std::vector<std::vector<double> >& cost_matrix,
727                                  std::vector<std::size_t>& labels,
728                                  const AlphaExpansionImplementationTag&)
729 {
730   internal::Alpha_expansion_old_API_wrapper_graph graph (edges, edge_costs, cost_matrix, labels);
731 
732   return alpha_expansion_graphcut(graph,
733                                   graph.edge_cost_map(),
734                                   graph.vertex_label_cost_map(),
735                                   graph.vertex_label_map(),
736                                   CGAL::parameters::vertex_index_map (graph.vertex_index_map()).
737                                   implementation_tag (AlphaExpansionImplementationTag()));
738 }
739 /// \endcond
740 
741 }//namespace CGAL
742 
743 namespace boost
744 {
745 
746 template <>
747 struct property_map<CGAL::internal::Alpha_expansion_old_API_wrapper_graph, boost::vertex_index_t>
748 {
749   typedef CGAL::internal::Alpha_expansion_old_API_wrapper_graph::Vertex_index_map type;
750   typedef CGAL::internal::Alpha_expansion_old_API_wrapper_graph::Vertex_index_map const_type;
751 };
752 }
753 
754 #endif //CGAL_BOOST_GRAPH_ALPHA_EXPANSION_GRAPHCUT_H
755