PandA-2024.02
network_flow.cpp
Go to the documentation of this file.
1 /*
2  *
3  * _/_/_/ _/_/ _/ _/ _/_/_/ _/_/
4  * _/ _/ _/ _/ _/_/ _/ _/ _/ _/ _/
5  * _/_/_/ _/_/_/_/ _/ _/_/ _/ _/ _/_/_/_/
6  * _/ _/ _/ _/ _/ _/ _/ _/ _/
7  * _/ _/ _/ _/ _/ _/_/_/ _/ _/
8  *
9  * ***********************************************
10  * PandA Project
11  * URL: http://panda.dei.polimi.it
12  * Politecnico di Milano - DEIB
13  * System Architectures Group
14  * ***********************************************
15  * Copyright (C) 2004-2024 Politecnico di Milano
16  *
17  * This file is part of the PandA framework.
18  *
19  * The PandA framework is free software; you can redistribute it and/or modify
20  * it under the terms of the GNU General Public License as published by
21  * the Free Software Foundation; either version 3 of the License, or
22  * (at your option) any later version.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License
30  * along with this program. If not, see <http://www.gnu.org/licenses/>.
31  *
32  */
45 #include "network_flow.hpp"
46 #include "Parameter.hpp"
47 #include "dbgPrintHelper.hpp"
48 
49 #define initial_value 10000000
50 #pragma GCC diagnostic push
51 #pragma GCC diagnostic error "-Weffc++"
52 
53 network_flow::network_flow(int _debug_level)
54  : network_flow_graph(0),
55  p_nf_vertex_description(boost::get(nf_vertex_description_t(), network_flow_graph)),
56  p_nf_balance(boost::get(nf_balance_t(), network_flow_graph)),
57  p_nf_imbalance(boost::get(nf_imbalance_t(), network_flow_graph)),
58  p_nf_potential(boost::get(nf_potential_t(), network_flow_graph)),
59  p_nf_distance(boost::get(nf_distance_t(), network_flow_graph)),
60  p_nf_index(boost::get(nf_index_t(), network_flow_graph)),
61  p_nf_name(boost::get(nf_name_t(), network_flow_graph)),
62  p_nf_edge_description(boost::get(nf_edge_description_t(), network_flow_graph)),
63  p_nf_pseudo_flow(boost::get(nf_pseudo_flow_t(), network_flow_graph)),
64  p_nf_residual_capacity(boost::get(nf_residual_capacity_t(), network_flow_graph)),
65  p_nf_reduced_cost(boost::get(nf_reduced_cost_t(), network_flow_graph)),
66  p_nf_flow(boost::get(nf_flow_t(), network_flow_graph)),
67  p_nf_capacity(boost::get(nf_capacity_t(), network_flow_graph)),
68  p_nf_cost(boost::get(nf_cost_t(), network_flow_graph)),
69  inserted_edges(),
70  debug_level(_debug_level)
71 {
72 }
73 
75 {
76  network_flow_graph_type::vertex_iterator vi, vi_end;
77  network_flow_graph_type::edge_iterator ei, ei_end;
78 
81 
82  CustomOrderedSet<vertex_pair>::iterator inserted_edges_iterator;
83 
84  if(boost::num_vertices(network_flow_graph) == 0)
85  {
86  return false;
87  }
88 
89  /*creation and initialization of the residual network*/
90  // distance = inf, potential = 0, e(i) = b(i), E:={i:e(i)>0} D:={i:e(i)<0}
91  E.clear();
92  D.clear();
93  // std::cerr << "number of vertices into the flow graph = " << boost::num_vertices(network_flow_graph) << std::endl;
94  for(boost::tie(vi, vi_end) = boost::vertices(network_flow_graph); vi != vi_end; vi++)
95  {
97  p_nf_potential[*vi] = 0;
98  p_nf_imbalance[*vi] = p_nf_balance[*vi];
99  // filling E and D sets
100  if(p_nf_imbalance[*vi] > 0)
101  {
102  E.insert(*vi);
103  }
104  if(p_nf_imbalance[*vi] < 0)
105  {
106  D.insert(*vi);
107  }
108  }
109  // flow_ij = 0, pseudo_flow_ij = 0, rcij = cij, ruij = uij
110  inserted_edges.clear();
111  for(boost::tie(ei, ei_end) = boost::edges(network_flow_graph); ei != ei_end; ei++)
112  {
113  p_nf_flow[*ei] = 0;
114  p_nf_pseudo_flow[*ei] = 0;
115  p_nf_reduced_cost[*ei] = p_nf_cost[*ei];
117 
118  inserted_edges.insert(
119  std::make_pair(boost::target(*ei, network_flow_graph), boost::source(*ei, network_flow_graph)));
120  }
121 
123  {
124  print_graph();
125  }
126 
127  // from (i,j) adding (j,i), cji = -cij, ruji = 0, flow_ji = 0, pseudo_flow_ji = 0, rcji = cji, uji = 0
128  for(inserted_edges_iterator = inserted_edges.begin(); inserted_edges_iterator != inserted_edges.end();
129  ++inserted_edges_iterator)
130  {
131  network_flow_graph_type::edge_descriptor original, reverse;
132  vertex_pair vertices;
133  vertices = *inserted_edges_iterator;
134  original = (boost::edge(vertices.second, vertices.first, network_flow_graph)).first;
135  reverse = (boost::add_edge(vertices.first, vertices.second, network_flow_graph)).first;
136  p_nf_cost[reverse] = -p_nf_cost[original];
137  p_nf_residual_capacity[reverse] = 0;
138  p_nf_flow[reverse] = 0;
139  p_nf_pseudo_flow[reverse] = 0;
140  p_nf_reduced_cost[reverse] = p_nf_cost[reverse];
141  p_nf_capacity[reverse] = 0;
142  }
143  /*---------------------------------------------------------------------------*/
144 
145  int i = 1; // maintains iterations number
146 
147  while(!E.empty())
148  {
149  std::vector<network_flow_graph_type::edge_descriptor> P;
150  std::vector<network_flow_graph_type::edge_descriptor>::iterator P_iterator;
151 
152  /*selection of K and I vertices*/
153  network_flow_graph_type::vertex_descriptor k, I;
154 
155  k = *(E.begin());
156  for(EDi = E.begin(); EDi != E.end(); ++EDi)
157  {
158  if(p_nf_balance[*EDi] > p_nf_balance[k])
159  {
160  k = *EDi;
161  }
162  }
163 
164  I = *(D.begin());
165  for(EDi = D.begin(); EDi != D.end(); ++EDi)
166  {
167  if(p_nf_balance[*EDi] < p_nf_balance[k])
168  {
169  I = *EDi;
170  }
171  }
172  /*---------------------------------------------------------------------------*/
173 
174  PRINT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "network_flow: K and I vertices selected ");
175 
176  /*shortest path distances computation and shortest path identification*/
178  if(P.empty())
179  {
180  clear_results();
181  return false;
182  }
183  /*---------------------------------------------------------------------------*/
184 
186  "network_flow: shortest path distances computed and shortest path identificated");
187 
188  /*update node potentials*/
189  for(boost::tie(vi, vi_end) = boost::vertices(network_flow_graph); vi != vi_end; vi++)
190  {
191  p_nf_potential[*vi] = p_nf_potential[*vi] - p_nf_distance[*vi];
192  }
193  /*---------------------------------------------------------------------------*/
194 
195  PRINT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "network_flow: node potentials updated");
196 
197  /*update reduced costs*/
198  for(boost::tie(ei, ei_end) = boost::edges(network_flow_graph); ei != ei_end; ei++)
199  {
200  p_nf_reduced_cost[*ei] = p_nf_cost[*ei] - p_nf_potential[boost::source(*ei, network_flow_graph)] +
202  }
203  /*---------------------------------------------------------------------------*/
204 
205  PRINT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "network_flow: reduced costs updated");
206 
207  /*sigma computation*/
208  // sigma = min{e(k),-e(I),min{rij: (i,j) in P}}
209  double sigma;
210 
211  sigma = initial_value;
212 
213  for(P_iterator = P.begin(); P_iterator != P.end(); ++P_iterator)
214  { // min{rij: (i,j) in P}
215  if(p_nf_residual_capacity[*P_iterator] < sigma)
216  {
217  sigma = p_nf_residual_capacity[*P_iterator];
218  }
219  }
220  if(p_nf_imbalance[k] < sigma)
221  {
222  sigma = p_nf_imbalance[k];
223  }
224 
225  if((-p_nf_imbalance[I]) < sigma)
226  {
227  sigma = p_nf_imbalance[I];
228  }
229  /*---------------------------------------------------------------------------*/
230 
231  PRINT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "network_flow: sigma computated");
232 
233  /*augment sigma units of pseudo flow along the path P, updating flows, residual capacity and imbalance*/
234  for(P_iterator = P.begin(); P_iterator != P.end(); ++P_iterator)
235  {
236  network_flow_graph_type::vertex_descriptor source, target;
237  network_flow_graph_type::out_edge_iterator oei, oei_end;
238 
239  source = boost::source(*P_iterator, network_flow_graph);
240  target = boost::target(*P_iterator, network_flow_graph);
241 
242  p_nf_pseudo_flow[*P_iterator] += sigma; // pseudo flow update
243 
244  network_flow_graph_type::edge_descriptor ed;
245  ed = boost::edge(target, source, network_flow_graph).first;
246 
247  if(inserted_edges.find(std::make_pair(source, target)) == inserted_edges.end())
248  {
249  // original edge
250  p_nf_flow[*P_iterator] = p_nf_pseudo_flow[*P_iterator] - p_nf_pseudo_flow[ed]; // flow update
251  p_nf_residual_capacity[*P_iterator] =
252  p_nf_capacity[*P_iterator] - p_nf_flow[*P_iterator]; // residual capacity update
253  p_nf_residual_capacity[ed] = p_nf_flow[*P_iterator]; // residual capacity update
254  }
255  else
256  {
257  // reversal edge
258  p_nf_flow[ed] = p_nf_pseudo_flow[ed] - p_nf_pseudo_flow[*P_iterator]; // flow update
259  p_nf_residual_capacity[ed] = p_nf_capacity[ed] - p_nf_flow[ed]; // residual capacity update
260  p_nf_residual_capacity[*P_iterator] = p_nf_flow[ed]; // residual capacity update
261  }
262  }
263 
264  for(boost::tie(vi, vi_end) = boost::vertices(network_flow_graph); vi != vi_end; vi++)
265  {
266  update_vertex_imbalance(*vi); // residual network update
267  }
268  /*---------------------------------------------------------------------------*/
269 
271  "network_flow: updated path P, updated flows, residual capacity and imbalance");
272 
273  /*Update E and D sets*/
274  E.clear();
275  D.clear();
276  for(boost::tie(vi, vi_end) = boost::vertices(network_flow_graph); vi != vi_end; vi++)
277  {
278  if(p_nf_imbalance[*vi] > 0)
279  {
280  E.insert(*vi);
281  }
282  if(p_nf_imbalance[*vi] < 0)
283  {
284  D.insert(*vi);
285  }
286  }
287  /*---------------------------------------------------------------------------*/
288 
289  PRINT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "network_flow: E and D sets updated");
290 
292  {
293  std::string file_name;
294  file_name = "network_flow_graph_" + I2S(i) + ".dot";
295  print_graph(file_name.data());
296  }
297 
298  i++;
299  }
300 
301  /*Removing reversal edges*/
302  while(!inserted_edges.empty())
303  {
304  vertex_pair edge;
305  edge = *inserted_edges.begin();
306  boost::remove_edge(edge.first, edge.second, network_flow_graph);
307  inserted_edges.erase(inserted_edges.begin());
308  }
309  /*---------------------------------------------------------------------------*/
310 
312  {
313  print_graph("network_flow_min_cost_flow.dot");
314  }
315 
316  return true;
317 }
318 
319 void network_flow::generic_label_correcting_algorithm(network_flow_graph_type::vertex_descriptor source,
320  network_flow_graph_type::vertex_descriptor target,
321  std::vector<network_flow_graph_type::edge_descriptor>* P)
322 {
323  /*initialization step*/
324  size_t n = boost::num_vertices(network_flow_graph);
325  std::map<network_flow_graph_type::vertex_descriptor, network_flow_graph_type::vertex_descriptor> predecessors;
326  network_flow_graph_type::vertex_iterator vi, vi_end;
327  for(boost::tie(vi, vi_end) = boost::vertices(network_flow_graph); vi != vi_end; vi++)
328  {
330  predecessors[*vi] = n;
331  }
332  p_nf_distance[source] = 0;
333  predecessors[source] = source;
334  /*---------------------------------------------------------------------------*/
335 
336  /*distances computation, predecessors computation and vertex distance labelling*/
337  network_flow_graph_type::edge_iterator ei, ei_end;
338  bool condition_satisfied = true;
339  while(condition_satisfied)
340  {
341  condition_satisfied = false;
342  for(boost::tie(ei, ei_end) = boost::edges(network_flow_graph); ei != ei_end; ei++)
343  {
344  network_flow_graph_type::vertex_descriptor source_, target_;
345  source_ = boost::source(*ei, network_flow_graph);
346  target_ = boost::target(*ei, network_flow_graph);
347  if(p_nf_distance[source_] != initial_value)
348  {
349  if((p_nf_distance[target_] > p_nf_distance[source_] + p_nf_reduced_cost[*ei]) &&
350  p_nf_residual_capacity[*ei] > 0)
351  {
352  p_nf_distance[target_] = p_nf_distance[source_] + p_nf_reduced_cost[*ei];
353  predecessors[target_] = source_;
354  network_flow_graph_type::vertex_descriptor pred;
355  pred = source_;
356  while(pred != source)
357  {
358  if(pred == target_)
359  {
360  P->clear();
361  return;
362  }
363  pred = predecessors[pred];
364  }
365  condition_satisfied = true;
366  }
367  }
368  }
369  }
370  /*---------------------------------------------------------------------------*/
371 
372  /*shortest path identification*/
373  network_flow_graph_type::vertex_descriptor current_vertex, dest;
374  P->clear();
375  current_vertex = target;
376 
377  while(current_vertex != source)
378  {
379  bool exist;
380  dest = current_vertex;
381  current_vertex = predecessors[current_vertex];
382  if(current_vertex == n)
383  {
384  P->clear();
385  return;
386  }
387  network_flow_graph_type::edge_descriptor ed;
388  tie(ed, exist) = boost::edge(current_vertex, dest, network_flow_graph);
389  P->push_back(ed);
390  }
391  /*---------------------------------------------------------------------------*/
392 }
393 
394 void network_flow::update_vertex_imbalance(network_flow_graph_type::vertex_descriptor vd)
395 {
396  network_flow_graph_type::out_edge_iterator oei, oei_end;
397  network_flow_graph_type::in_edge_iterator iei, iei_end;
398 
399  double outflow, inflow;
400 
401  inflow = 0;
402  outflow = 0;
403 
404  // outflow
405  for(boost::tie(oei, oei_end) = boost::out_edges(vd, network_flow_graph); oei != oei_end; oei++)
406  {
407  outflow += p_nf_pseudo_flow[*oei];
408  }
409 
410  // inflow
411  for(boost::tie(iei, iei_end) = boost::in_edges(vd, network_flow_graph); iei != iei_end; iei++)
412  {
413  inflow += p_nf_pseudo_flow[*iei];
414  }
415 
416  p_nf_imbalance[vd] = p_nf_balance[vd] + inflow - outflow;
417 }
418 
420 {
421  /*Removing reversal edges*/
422  while(!inserted_edges.empty())
423  {
424  vertex_pair edge;
425  edge = *inserted_edges.begin();
426  boost::remove_edge(edge.first, edge.second, network_flow_graph);
427  inserted_edges.erase(inserted_edges.begin());
428  }
429  /*---------------------------------------------------------------------------*/
430 
431  /*Cleaning network_flow_graph vertices*/
432  network_flow_graph_type::vertex_iterator vi, vi_end;
433  for(boost::tie(vi, vi_end) = boost::vertices(network_flow_graph); vi != vi_end; vi++)
434  {
435  p_nf_vertex_description[*vi] = "";
436  p_nf_imbalance[*vi] = 0;
437  p_nf_potential[*vi] = 0;
439  }
440  /*---------------------------------------------------------------------------*/
441 
442  /*Cleaning network_flow_graph edges*/
443  network_flow_graph_type::edge_iterator ei, ei_end;
444  for(boost::tie(ei, ei_end) = boost::edges(network_flow_graph); ei != ei_end; ei++)
445  {
446  p_nf_edge_description[*ei] = "";
447  p_nf_pseudo_flow[*ei] = 0;
448  p_nf_residual_capacity[*ei] = 0;
449  p_nf_reduced_cost[*ei] = p_nf_cost[*ei];
450  p_nf_flow[*ei] = 0;
451  }
452  /*---------------------------------------------------------------------------*/
453 }
454 
455 bool network_flow::print_graph(const char* file_name)
456 {
457  network_flow_graph_type::vertex_iterator vi, vi_end;
458  network_flow_graph_type::edge_iterator ei, ei_end;
459 
460  for(boost::tie(vi, vi_end) = boost::vertices(network_flow_graph); vi != vi_end; vi++)
461  {
463  }
464 
465  for(boost::tie(ei, ei_end) = boost::edges(network_flow_graph); ei != ei_end; ei++)
466  {
468  }
469 
470  std::ofstream dot_file(file_name);
471  if(!dot_file)
472  {
473  return false;
474  }
475  boost::write_graphviz(dot_file, network_flow_graph, make_label_writer(p_nf_vertex_description),
476  make_label_writer(p_nf_edge_description));
477  dot_file.close();
478  return true;
479 }
480 
481 std::string network_flow::get_vertex_description(network_flow_graph_type::vertex_descriptor vd)
482 {
483  std::string description;
484 
485  description = "name: " + p_nf_name[vd] + "\\nindex: " + I2S(p_nf_index[vd]) +
486  "\\ndistance: " + I2S(p_nf_distance[vd]) + "\\npotential: " + I2S(p_nf_potential[vd]) +
487  "\\nimbalance: " + I2S(p_nf_imbalance[vd]) + "\\nbalance: " + I2S(p_nf_balance[vd]);
488 
489  return description;
490 }
491 
492 std::string network_flow::get_edge_description(network_flow_graph_type::edge_descriptor ed)
493 {
494  std::string description;
495 
496  description = "cost: " + I2S(p_nf_cost[ed]) + "\\ncapacity: " + I2S(p_nf_capacity[ed]) +
497  "\\nflow: " + I2S(p_nf_flow[ed]) + "\\nreduced cost: " + I2S(p_nf_reduced_cost[ed]) +
498  "\\nresidual capacity: " + I2S(p_nf_residual_capacity[ed]) +
499  "\\npseudo flow: " + I2S(p_nf_pseudo_flow[ed]);
500 
501  return description;
502 }
503 #pragma GCC diagnostic pop
#define DEBUG_LEVEL_VERY_PEDANTIC
extremely verbose debugging print is performed.
pmap_nf_index_t p_nf_index
File containing functions and utilities to support the printing of debug messagges.
#define PRINT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
#define DEBUG_LEVEL_PEDANTIC
very verbose debugging print is performed.
This algorithm is to find coloring of a graph Algorithm: Let G = (V,E) be a graph with vertices v_1...
string target
Definition: lenet_tvm.py:16
#define initial_value
pmap_nf_flow_t p_nf_flow
pmap_nf_imbalance_t p_nf_imbalance
pmap_nf_edge_description_t p_nf_edge_description
Edge maps variables.
std::string get_vertex_description(network_flow_graph_type::vertex_descriptor vd)
Generates the description string of the vertex vd.
std::string get_edge_description(network_flow_graph_type::edge_descriptor ed)
Generates the description string of the edge ed.
bool successive_shortest_path_algorithm()
Computes the solution for the min cost flow problem with successive shortest path algorithm...
network_flow_graph_type network_flow_graph
Network flow graph pointer.
network_flow(int _debug_level)
Constructor of the class.
unsigned edges[4545]
Definition: graph.h:25
pmap_nf_potential_t p_nf_potential
pmap_nf_pseudo_flow_t p_nf_pseudo_flow
const size_t P
Definition: helm.c:5
void update_vertex_imbalance(network_flow_graph_type::vertex_descriptor vd)
Updates the vertex imbalance.
std::set< Key, Compare, Alloc > OrderedSetStd
Definition: custom_set.hpp:59
static const uint32_t k[]
Definition: sha-256.c:22
void generic_label_correcting_algorithm(network_flow_graph_type::vertex_descriptor source, network_flow_graph_type::vertex_descriptor target, std::vector< network_flow_graph_type::edge_descriptor > *P)
Implements the generic label correcting algorithm for vertex distances labelling. ...
#define D
Definition: generate.c:16
pmap_nf_residual_capacity_t p_nf_residual_capacity
pmap_nf_vertex_description_t p_nf_vertex_description
Vertex maps variables.
#define I2S(number)
pmap_nf_cost_t p_nf_cost
int original[DIMENSION_Y][DIMENSION_X]
Definition: boxfilter.h:1
this class is used to manage the command-line or XML options.
pmap_nf_reduced_cost_t p_nf_reduced_cost
bool print_graph(const char *file_name="network_flow.dot")
Prints a textual description of the graph in a .dot file format.
pmap_nf_balance_t p_nf_balance
This class contains a network flow graph representation and min cost flow algorithm.
void clear_results()
Clears results of a previous computation.
pmap_nf_name_t p_nf_name
pmap_nf_capacity_t p_nf_capacity
#define DEBUG_LEVEL_VERBOSE
verbose debugging print is performed.
pmap_nf_distance_t p_nf_distance
std::pair< network_flow_graph_type::vertex_descriptor, network_flow_graph_type::vertex_descriptor > vertex_pair
#define DEBUG_LEVEL_MINIMUM
minimum debugging print is performed.
CustomOrderedSet< vertex_pair > inserted_edges

Generated on Mon Feb 12 2024 13:02:53 for PandA-2024.02 by doxygen 1.8.13