The source code and dockerfile for the GSW2024 AI Lab.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

170 lines
5.9 KiB

2 months ago
  1. /* maxflow.c */
  2. /* Written by Andrew Makhorin <mao@gnu.org>, October 2015. */
  3. #include <math.h>
  4. #include <glpk.h>
  5. #include "maxflow.h"
  6. #include "misc.h"
  7. /***********************************************************************
  8. * NAME
  9. *
  10. * max_flow - find max flow in undirected capacitated network
  11. *
  12. * SYNOPSIS
  13. *
  14. * #include "maxflow.h"
  15. * int max_flow(int nn, int ne, const int beg[], const int end[],
  16. * const int cap[], int s, int t, int x[]);
  17. *
  18. * DESCRIPTION
  19. *
  20. * This routine finds max flow in a given undirected network.
  21. *
  22. * The undirected capacitated network is specified by the parameters
  23. * nn, ne, beg, end, and cap. The parameter nn specifies the number of
  24. * vertices (nodes), nn >= 2, and the parameter ne specifies the number
  25. * of edges, ne >= 0. The network edges are specified by triplets
  26. * (beg[k], end[k], cap[k]) for k = 1, ..., ne, where beg[k] < end[k]
  27. * are numbers of the first and second nodes of k-th edge, and
  28. * cap[k] > 0 is a capacity of k-th edge. Loops and multiple edges are
  29. * not allowed.
  30. *
  31. * The parameter s is the number of a source node, and the parameter t
  32. * is the number of a sink node, s != t.
  33. *
  34. * On exit the routine computes elementary flows thru edges and stores
  35. * their values to locations x[1], ..., x[ne]. Positive value of x[k]
  36. * means that the elementary flow goes from node beg[k] to node end[k],
  37. * and negative value means that the flow goes in opposite direction.
  38. *
  39. * RETURNS
  40. *
  41. * The routine returns the total maximum flow through the network. */
  42. int max_flow(int nn, int ne, const int beg[/*1+ne*/],
  43. const int end[/*1+ne*/], const int cap[/*1+ne*/], int s, int t,
  44. int x[/*1+ne*/])
  45. { int k;
  46. /* sanity checks */
  47. xassert(nn >= 2);
  48. xassert(ne >= 0);
  49. xassert(1 <= s && s <= nn);
  50. xassert(1 <= t && t <= nn);
  51. xassert(s != t);
  52. for (k = 1; k <= ne; k++)
  53. { xassert(1 <= beg[k] && beg[k] < end[k] && end[k] <= nn);
  54. xassert(cap[k] > 0);
  55. }
  56. /* find max flow */
  57. return max_flow_lp(nn, ne, beg, end, cap, s, t, x);
  58. }
  59. /***********************************************************************
  60. * NAME
  61. *
  62. * max_flow_lp - find max flow with simplex method
  63. *
  64. * SYNOPSIS
  65. *
  66. * #include "maxflow.h"
  67. * int max_flow_lp(int nn, int ne, const int beg[], const int end[],
  68. * const int cap[], int s, int t, int x[]);
  69. *
  70. * DESCRIPTION
  71. *
  72. * This routine finds max flow in a given undirected network with the
  73. * simplex method.
  74. *
  75. * Parameters of this routine have the same meaning as for the routine
  76. * max_flow (see above).
  77. *
  78. * RETURNS
  79. *
  80. * The routine returns the total maximum flow through the network. */
  81. int max_flow_lp(int nn, int ne, const int beg[/*1+ne*/],
  82. const int end[/*1+ne*/], const int cap[/*1+ne*/], int s, int t,
  83. int x[/*1+ne*/])
  84. { glp_prob *lp;
  85. glp_smcp smcp;
  86. int i, k, nz, flow, *rn, *cn;
  87. double temp, *aa;
  88. /* create LP problem instance */
  89. lp = glp_create_prob();
  90. /* create LP rows; i-th row is the conservation condition of the
  91. * flow at i-th node, i = 1, ..., nn */
  92. glp_add_rows(lp, nn);
  93. for (i = 1; i <= nn; i++)
  94. glp_set_row_bnds(lp, i, GLP_FX, 0.0, 0.0);
  95. /* create LP columns; k-th column is the elementary flow thru
  96. * k-th edge, k = 1, ..., ne; the last column with the number
  97. * ne+1 is the total flow through the network, which goes along
  98. * a dummy feedback edge from the sink to the source */
  99. glp_add_cols(lp, ne+1);
  100. for (k = 1; k <= ne; k++)
  101. { xassert(cap[k] > 0);
  102. glp_set_col_bnds(lp, k, GLP_DB, -cap[k], +cap[k]);
  103. }
  104. glp_set_col_bnds(lp, ne+1, GLP_FR, 0.0, 0.0);
  105. /* build the constraint matrix; structurally this matrix is the
  106. * incidence matrix of the network, so each its column (including
  107. * the last column for the dummy edge) has exactly two non-zero
  108. * entries */
  109. rn = xalloc(1+2*(ne+1), sizeof(int));
  110. cn = xalloc(1+2*(ne+1), sizeof(int));
  111. aa = xalloc(1+2*(ne+1), sizeof(double));
  112. nz = 0;
  113. for (k = 1; k <= ne; k++)
  114. { /* x[k] > 0 means the elementary flow thru k-th edge goes from
  115. * node beg[k] to node end[k] */
  116. nz++, rn[nz] = beg[k], cn[nz] = k, aa[nz] = -1.0;
  117. nz++, rn[nz] = end[k], cn[nz] = k, aa[nz] = +1.0;
  118. }
  119. /* total flow thru the network goes from the sink to the source
  120. * along the dummy feedback edge */
  121. nz++, rn[nz] = t, cn[nz] = ne+1, aa[nz] = -1.0;
  122. nz++, rn[nz] = s, cn[nz] = ne+1, aa[nz] = +1.0;
  123. /* check the number of non-zero entries */
  124. xassert(nz == 2*(ne+1));
  125. /* load the constraint matrix into the LP problem object */
  126. glp_load_matrix(lp, nz, rn, cn, aa);
  127. xfree(rn);
  128. xfree(cn);
  129. xfree(aa);
  130. /* objective function is the total flow through the network to
  131. * be maximized */
  132. glp_set_obj_dir(lp, GLP_MAX);
  133. glp_set_obj_coef(lp, ne + 1, 1.0);
  134. /* solve LP instance with the (primal) simplex method */
  135. glp_term_out(0);
  136. glp_adv_basis(lp, 0);
  137. glp_term_out(1);
  138. glp_init_smcp(&smcp);
  139. smcp.msg_lev = GLP_MSG_ON;
  140. smcp.out_dly = 5000;
  141. xassert(glp_simplex(lp, &smcp) == 0);
  142. xassert(glp_get_status(lp) == GLP_OPT);
  143. /* obtain optimal elementary flows thru edges of the network */
  144. /* (note that the constraint matrix is unimodular and the data
  145. * are integral, so all elementary flows in basic solution should
  146. * also be integral) */
  147. for (k = 1; k <= ne; k++)
  148. { temp = glp_get_col_prim(lp, k);
  149. x[k] = (int)floor(temp + .5);
  150. xassert(fabs(x[k] - temp) <= 1e-6);
  151. }
  152. /* obtain the maximum flow thru the original network which is the
  153. * flow thru the dummy feedback edge */
  154. temp = glp_get_col_prim(lp, ne+1);
  155. flow = (int)floor(temp + .5);
  156. xassert(fabs(flow - temp) <= 1e-6);
  157. /* delete LP problem instance */
  158. glp_delete_prob(lp);
  159. /* return to the calling program */
  160. return flow;
  161. }
  162. /* eof */