src/glpapi17.c
changeset 1 c445c931472f
equal deleted inserted replaced
-1:000000000000 0:d5d11258d4a5
       
     1 /* glpapi17.c (flow network problems) */
       
     2 
       
     3 /***********************************************************************
       
     4 *  This code is part of GLPK (GNU Linear Programming Kit).
       
     5 *
       
     6 *  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
       
     7 *  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
       
     8 *  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
       
     9 *  E-mail: <mao@gnu.org>.
       
    10 *
       
    11 *  GLPK is free software: you can redistribute it and/or modify it
       
    12 *  under the terms of the GNU General Public License as published by
       
    13 *  the Free Software Foundation, either version 3 of the License, or
       
    14 *  (at your option) any later version.
       
    15 *
       
    16 *  GLPK is distributed in the hope that it will be useful, but WITHOUT
       
    17 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
       
    18 *  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
       
    19 *  License for more details.
       
    20 *
       
    21 *  You should have received a copy of the GNU General Public License
       
    22 *  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
       
    23 ***********************************************************************/
       
    24 
       
    25 #include "glpapi.h"
       
    26 #include "glpnet.h"
       
    27 
       
    28 /***********************************************************************
       
    29 *  NAME
       
    30 *
       
    31 *  glp_mincost_lp - convert minimum cost flow problem to LP
       
    32 *
       
    33 *  SYNOPSIS
       
    34 *
       
    35 *  void glp_mincost_lp(glp_prob *lp, glp_graph *G, int names,
       
    36 *     int v_rhs, int a_low, int a_cap, int a_cost);
       
    37 *
       
    38 *  DESCRIPTION
       
    39 *
       
    40 *  The routine glp_mincost_lp builds an LP problem, which corresponds
       
    41 *  to the minimum cost flow problem on the specified network G. */
       
    42 
       
    43 void glp_mincost_lp(glp_prob *lp, glp_graph *G, int names, int v_rhs,
       
    44       int a_low, int a_cap, int a_cost)
       
    45 {     glp_vertex *v;
       
    46       glp_arc *a;
       
    47       int i, j, type, ind[1+2];
       
    48       double rhs, low, cap, cost, val[1+2];
       
    49       if (!(names == GLP_ON || names == GLP_OFF))
       
    50          xerror("glp_mincost_lp: names = %d; invalid parameter\n",
       
    51             names);
       
    52       if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
       
    53          xerror("glp_mincost_lp: v_rhs = %d; invalid offset\n", v_rhs);
       
    54       if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double))
       
    55          xerror("glp_mincost_lp: a_low = %d; invalid offset\n", a_low);
       
    56       if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
       
    57          xerror("glp_mincost_lp: a_cap = %d; invalid offset\n", a_cap);
       
    58       if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
       
    59          xerror("glp_mincost_lp: a_cost = %d; invalid offset\n", a_cost)
       
    60             ;
       
    61       glp_erase_prob(lp);
       
    62       if (names) glp_set_prob_name(lp, G->name);
       
    63       if (G->nv > 0) glp_add_rows(lp, G->nv);
       
    64       for (i = 1; i <= G->nv; i++)
       
    65       {  v = G->v[i];
       
    66          if (names) glp_set_row_name(lp, i, v->name);
       
    67          if (v_rhs >= 0)
       
    68             memcpy(&rhs, (char *)v->data + v_rhs, sizeof(double));
       
    69          else
       
    70             rhs = 0.0;
       
    71          glp_set_row_bnds(lp, i, GLP_FX, rhs, rhs);
       
    72       }
       
    73       if (G->na > 0) glp_add_cols(lp, G->na);
       
    74       for (i = 1, j = 0; i <= G->nv; i++)
       
    75       {  v = G->v[i];
       
    76          for (a = v->out; a != NULL; a = a->t_next)
       
    77          {  j++;
       
    78             if (names)
       
    79             {  char name[50+1];
       
    80                sprintf(name, "x[%d,%d]", a->tail->i, a->head->i);
       
    81                xassert(strlen(name) < sizeof(name));
       
    82                glp_set_col_name(lp, j, name);
       
    83             }
       
    84             if (a->tail->i != a->head->i)
       
    85             {  ind[1] = a->tail->i, val[1] = +1.0;
       
    86                ind[2] = a->head->i, val[2] = -1.0;
       
    87                glp_set_mat_col(lp, j, 2, ind, val);
       
    88             }
       
    89             if (a_low >= 0)
       
    90                memcpy(&low, (char *)a->data + a_low, sizeof(double));
       
    91             else
       
    92                low = 0.0;
       
    93             if (a_cap >= 0)
       
    94                memcpy(&cap, (char *)a->data + a_cap, sizeof(double));
       
    95             else
       
    96                cap = 1.0;
       
    97             if (cap == DBL_MAX)
       
    98                type = GLP_LO;
       
    99             else if (low != cap)
       
   100                type = GLP_DB;
       
   101             else
       
   102                type = GLP_FX;
       
   103             glp_set_col_bnds(lp, j, type, low, cap);
       
   104             if (a_cost >= 0)
       
   105                memcpy(&cost, (char *)a->data + a_cost, sizeof(double));
       
   106             else
       
   107                cost = 0.0;
       
   108             glp_set_obj_coef(lp, j, cost);
       
   109          }
       
   110       }
       
   111       xassert(j == G->na);
       
   112       return;
       
   113 }
       
   114 
       
   115 /**********************************************************************/
       
   116 
       
   117 int glp_mincost_okalg(glp_graph *G, int v_rhs, int a_low, int a_cap,
       
   118       int a_cost, double *sol, int a_x, int v_pi)
       
   119 {     /* find minimum-cost flow with out-of-kilter algorithm */
       
   120       glp_vertex *v;
       
   121       glp_arc *a;
       
   122       int nv, na, i, k, s, t, *tail, *head, *low, *cap, *cost, *x, *pi,
       
   123          ret;
       
   124       double sum, temp;
       
   125       if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
       
   126          xerror("glp_mincost_okalg: v_rhs = %d; invalid offset\n",
       
   127             v_rhs);
       
   128       if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double))
       
   129          xerror("glp_mincost_okalg: a_low = %d; invalid offset\n",
       
   130             a_low);
       
   131       if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
       
   132          xerror("glp_mincost_okalg: a_cap = %d; invalid offset\n",
       
   133             a_cap);
       
   134       if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
       
   135          xerror("glp_mincost_okalg: a_cost = %d; invalid offset\n",
       
   136             a_cost);
       
   137       if (a_x >= 0 && a_x > G->a_size - (int)sizeof(double))
       
   138          xerror("glp_mincost_okalg: a_x = %d; invalid offset\n", a_x);
       
   139       if (v_pi >= 0 && v_pi > G->v_size - (int)sizeof(double))
       
   140          xerror("glp_mincost_okalg: v_pi = %d; invalid offset\n", v_pi);
       
   141       /* s is artificial source node */
       
   142       s = G->nv + 1;
       
   143       /* t is artificial sink node */
       
   144       t = s + 1;
       
   145       /* nv is the total number of nodes in the resulting network */
       
   146       nv = t;
       
   147       /* na is the total number of arcs in the resulting network */
       
   148       na = G->na + 1;
       
   149       for (i = 1; i <= G->nv; i++)
       
   150       {  v = G->v[i];
       
   151          if (v_rhs >= 0)
       
   152             memcpy(&temp, (char *)v->data + v_rhs, sizeof(double));
       
   153          else
       
   154             temp = 0.0;
       
   155          if (temp != 0.0) na++;
       
   156       }
       
   157       /* allocate working arrays */
       
   158       tail = xcalloc(1+na, sizeof(int));
       
   159       head = xcalloc(1+na, sizeof(int));
       
   160       low = xcalloc(1+na, sizeof(int));
       
   161       cap = xcalloc(1+na, sizeof(int));
       
   162       cost = xcalloc(1+na, sizeof(int));
       
   163       x = xcalloc(1+na, sizeof(int));
       
   164       pi = xcalloc(1+nv, sizeof(int));
       
   165       /* construct the resulting network */
       
   166       k = 0;
       
   167       /* (original arcs) */
       
   168       for (i = 1; i <= G->nv; i++)
       
   169       {  v = G->v[i];
       
   170          for (a = v->out; a != NULL; a = a->t_next)
       
   171          {  k++;
       
   172             tail[k] = a->tail->i;
       
   173             head[k] = a->head->i;
       
   174             if (tail[k] == head[k])
       
   175             {  ret = GLP_EDATA;
       
   176                goto done;
       
   177             }
       
   178             if (a_low >= 0)
       
   179                memcpy(&temp, (char *)a->data + a_low, sizeof(double));
       
   180             else
       
   181                temp = 0.0;
       
   182             if (!(0.0 <= temp && temp <= (double)INT_MAX &&
       
   183                   temp == floor(temp)))
       
   184             {  ret = GLP_EDATA;
       
   185                goto done;
       
   186             }
       
   187             low[k] = (int)temp;
       
   188             if (a_cap >= 0)
       
   189                memcpy(&temp, (char *)a->data + a_cap, sizeof(double));
       
   190             else
       
   191                temp = 1.0;
       
   192             if (!((double)low[k] <= temp && temp <= (double)INT_MAX &&
       
   193                   temp == floor(temp)))
       
   194             {  ret = GLP_EDATA;
       
   195                goto done;
       
   196             }
       
   197             cap[k] = (int)temp;
       
   198             if (a_cost >= 0)
       
   199                memcpy(&temp, (char *)a->data + a_cost, sizeof(double));
       
   200             else
       
   201                temp = 0.0;
       
   202             if (!(fabs(temp) <= (double)INT_MAX && temp == floor(temp)))
       
   203             {  ret = GLP_EDATA;
       
   204                goto done;
       
   205             }
       
   206             cost[k] = (int)temp;
       
   207          }
       
   208       }
       
   209       /* (artificial arcs) */
       
   210       sum = 0.0;
       
   211       for (i = 1; i <= G->nv; i++)
       
   212       {  v = G->v[i];
       
   213          if (v_rhs >= 0)
       
   214             memcpy(&temp, (char *)v->data + v_rhs, sizeof(double));
       
   215          else
       
   216             temp = 0.0;
       
   217          if (!(fabs(temp) <= (double)INT_MAX && temp == floor(temp)))
       
   218          {  ret = GLP_EDATA;
       
   219             goto done;
       
   220          }
       
   221          if (temp > 0.0)
       
   222          {  /* artificial arc from s to original source i */
       
   223             k++;
       
   224             tail[k] = s;
       
   225             head[k] = i;
       
   226             low[k] = cap[k] = (int)(+temp); /* supply */
       
   227             cost[k] = 0;
       
   228             sum += (double)temp;
       
   229          }
       
   230          else if (temp < 0.0)
       
   231          {  /* artificial arc from original sink i to t */
       
   232             k++;
       
   233             tail[k] = i;
       
   234             head[k] = t;
       
   235             low[k] = cap[k] = (int)(-temp); /* demand */
       
   236             cost[k] = 0;
       
   237          }
       
   238       }
       
   239       /* (feedback arc from t to s) */
       
   240       k++;
       
   241       xassert(k == na);
       
   242       tail[k] = t;
       
   243       head[k] = s;
       
   244       if (sum > (double)INT_MAX)
       
   245       {  ret = GLP_EDATA;
       
   246          goto done;
       
   247       }
       
   248       low[k] = cap[k] = (int)sum; /* total supply/demand */
       
   249       cost[k] = 0;
       
   250       /* find minimal-cost circulation in the resulting network */
       
   251       ret = okalg(nv, na, tail, head, low, cap, cost, x, pi);
       
   252       switch (ret)
       
   253       {  case 0:
       
   254             /* optimal circulation found */
       
   255             ret = 0;
       
   256             break;
       
   257          case 1:
       
   258             /* no feasible circulation exists */
       
   259             ret = GLP_ENOPFS;
       
   260             break;
       
   261          case 2:
       
   262             /* integer overflow occured */
       
   263             ret = GLP_ERANGE;
       
   264             goto done;
       
   265          case 3:
       
   266             /* optimality test failed (logic error) */
       
   267             ret = GLP_EFAIL;
       
   268             goto done;
       
   269          default:
       
   270             xassert(ret != ret);
       
   271       }
       
   272       /* store solution components */
       
   273       /* (objective function = the total cost) */
       
   274       if (sol != NULL)
       
   275       {  temp = 0.0;
       
   276          for (k = 1; k <= na; k++)
       
   277             temp += (double)cost[k] * (double)x[k];
       
   278          *sol = temp;
       
   279       }
       
   280       /* (arc flows) */
       
   281       if (a_x >= 0)
       
   282       {  k = 0;
       
   283          for (i = 1; i <= G->nv; i++)
       
   284          {  v = G->v[i];
       
   285             for (a = v->out; a != NULL; a = a->t_next)
       
   286             {  temp = (double)x[++k];
       
   287                memcpy((char *)a->data + a_x, &temp, sizeof(double));
       
   288             }
       
   289          }
       
   290       }
       
   291       /* (node potentials = Lagrange multipliers) */
       
   292       if (v_pi >= 0)
       
   293       {  for (i = 1; i <= G->nv; i++)
       
   294          {  v = G->v[i];
       
   295             temp = - (double)pi[i];
       
   296             memcpy((char *)v->data + v_pi, &temp, sizeof(double));
       
   297          }
       
   298       }
       
   299 done: /* free working arrays */
       
   300       xfree(tail);
       
   301       xfree(head);
       
   302       xfree(low);
       
   303       xfree(cap);
       
   304       xfree(cost);
       
   305       xfree(x);
       
   306       xfree(pi);
       
   307       return ret;
       
   308 }
       
   309 
       
   310 /***********************************************************************
       
   311 *  NAME
       
   312 *
       
   313 *  glp_maxflow_lp - convert maximum flow problem to LP
       
   314 *
       
   315 *  SYNOPSIS
       
   316 *
       
   317 *  void glp_maxflow_lp(glp_prob *lp, glp_graph *G, int names, int s,
       
   318 *     int t, int a_cap);
       
   319 *
       
   320 *  DESCRIPTION
       
   321 *
       
   322 *  The routine glp_maxflow_lp builds an LP problem, which corresponds
       
   323 *  to the maximum flow problem on the specified network G. */
       
   324 
       
   325 void glp_maxflow_lp(glp_prob *lp, glp_graph *G, int names, int s,
       
   326       int t, int a_cap)
       
   327 {     glp_vertex *v;
       
   328       glp_arc *a;
       
   329       int i, j, type, ind[1+2];
       
   330       double cap, val[1+2];
       
   331       if (!(names == GLP_ON || names == GLP_OFF))
       
   332          xerror("glp_maxflow_lp: names = %d; invalid parameter\n",
       
   333             names);
       
   334       if (!(1 <= s && s <= G->nv))
       
   335          xerror("glp_maxflow_lp: s = %d; source node number out of rang"
       
   336             "e\n", s);
       
   337       if (!(1 <= t && t <= G->nv))
       
   338          xerror("glp_maxflow_lp: t = %d: sink node number out of range "
       
   339             "\n", t);
       
   340       if (s == t)
       
   341          xerror("glp_maxflow_lp: s = t = %d; source and sink nodes must"
       
   342             " be distinct\n", s);
       
   343       if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
       
   344          xerror("glp_maxflow_lp: a_cap = %d; invalid offset\n", a_cap);
       
   345       glp_erase_prob(lp);
       
   346       if (names) glp_set_prob_name(lp, G->name);
       
   347       glp_set_obj_dir(lp, GLP_MAX);
       
   348       glp_add_rows(lp, G->nv);
       
   349       for (i = 1; i <= G->nv; i++)
       
   350       {  v = G->v[i];
       
   351          if (names) glp_set_row_name(lp, i, v->name);
       
   352          if (i == s)
       
   353             type = GLP_LO;
       
   354          else if (i == t)
       
   355             type = GLP_UP;
       
   356          else
       
   357             type = GLP_FX;
       
   358          glp_set_row_bnds(lp, i, type, 0.0, 0.0);
       
   359       }
       
   360       if (G->na > 0) glp_add_cols(lp, G->na);
       
   361       for (i = 1, j = 0; i <= G->nv; i++)
       
   362       {  v = G->v[i];
       
   363          for (a = v->out; a != NULL; a = a->t_next)
       
   364          {  j++;
       
   365             if (names)
       
   366             {  char name[50+1];
       
   367                sprintf(name, "x[%d,%d]", a->tail->i, a->head->i);
       
   368                xassert(strlen(name) < sizeof(name));
       
   369                glp_set_col_name(lp, j, name);
       
   370             }
       
   371             if (a->tail->i != a->head->i)
       
   372             {  ind[1] = a->tail->i, val[1] = +1.0;
       
   373                ind[2] = a->head->i, val[2] = -1.0;
       
   374                glp_set_mat_col(lp, j, 2, ind, val);
       
   375             }
       
   376             if (a_cap >= 0)
       
   377                memcpy(&cap, (char *)a->data + a_cap, sizeof(double));
       
   378             else
       
   379                cap = 1.0;
       
   380             if (cap == DBL_MAX)
       
   381                type = GLP_LO;
       
   382             else if (cap != 0.0)
       
   383                type = GLP_DB;
       
   384             else
       
   385                type = GLP_FX;
       
   386             glp_set_col_bnds(lp, j, type, 0.0, cap);
       
   387             if (a->tail->i == s)
       
   388                glp_set_obj_coef(lp, j, +1.0);
       
   389             else if (a->head->i == s)
       
   390                glp_set_obj_coef(lp, j, -1.0);
       
   391          }
       
   392       }
       
   393       xassert(j == G->na);
       
   394       return;
       
   395 }
       
   396 
       
   397 int glp_maxflow_ffalg(glp_graph *G, int s, int t, int a_cap,
       
   398       double *sol, int a_x, int v_cut)
       
   399 {     /* find maximal flow with Ford-Fulkerson algorithm */
       
   400       glp_vertex *v;
       
   401       glp_arc *a;
       
   402       int nv, na, i, k, flag, *tail, *head, *cap, *x, ret;
       
   403       char *cut;
       
   404       double temp;
       
   405       if (!(1 <= s && s <= G->nv))
       
   406          xerror("glp_maxflow_ffalg: s = %d; source node number out of r"
       
   407             "ange\n", s);
       
   408       if (!(1 <= t && t <= G->nv))
       
   409          xerror("glp_maxflow_ffalg: t = %d: sink node number out of ran"
       
   410             "ge\n", t);
       
   411       if (s == t)
       
   412          xerror("glp_maxflow_ffalg: s = t = %d; source and sink nodes m"
       
   413             "ust be distinct\n", s);
       
   414       if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
       
   415          xerror("glp_maxflow_ffalg: a_cap = %d; invalid offset\n",
       
   416             a_cap);
       
   417       if (v_cut >= 0 && v_cut > G->v_size - (int)sizeof(int))
       
   418          xerror("glp_maxflow_ffalg: v_cut = %d; invalid offset\n",
       
   419             v_cut);
       
   420       /* allocate working arrays */
       
   421       nv = G->nv;
       
   422       na = G->na;
       
   423       tail = xcalloc(1+na, sizeof(int));
       
   424       head = xcalloc(1+na, sizeof(int));
       
   425       cap = xcalloc(1+na, sizeof(int));
       
   426       x = xcalloc(1+na, sizeof(int));
       
   427       if (v_cut < 0)
       
   428          cut = NULL;
       
   429       else
       
   430          cut = xcalloc(1+nv, sizeof(char));
       
   431       /* copy the flow network */
       
   432       k = 0;
       
   433       for (i = 1; i <= G->nv; i++)
       
   434       {  v = G->v[i];
       
   435          for (a = v->out; a != NULL; a = a->t_next)
       
   436          {  k++;
       
   437             tail[k] = a->tail->i;
       
   438             head[k] = a->head->i;
       
   439             if (tail[k] == head[k])
       
   440             {  ret = GLP_EDATA;
       
   441                goto done;
       
   442             }
       
   443             if (a_cap >= 0)
       
   444                memcpy(&temp, (char *)a->data + a_cap, sizeof(double));
       
   445             else
       
   446                temp = 1.0;
       
   447             if (!(0.0 <= temp && temp <= (double)INT_MAX &&
       
   448                   temp == floor(temp)))
       
   449             {  ret = GLP_EDATA;
       
   450                goto done;
       
   451             }
       
   452             cap[k] = (int)temp;
       
   453          }
       
   454       }
       
   455       xassert(k == na);
       
   456       /* find maximal flow in the flow network */
       
   457       ffalg(nv, na, tail, head, s, t, cap, x, cut);
       
   458       ret = 0;
       
   459       /* store solution components */
       
   460       /* (objective function = total flow through the network) */
       
   461       if (sol != NULL)
       
   462       {  temp = 0.0;
       
   463          for (k = 1; k <= na; k++)
       
   464          {  if (tail[k] == s)
       
   465                temp += (double)x[k];
       
   466             else if (head[k] == s)
       
   467                temp -= (double)x[k];
       
   468          }
       
   469          *sol = temp;
       
   470       }
       
   471       /* (arc flows) */
       
   472       if (a_x >= 0)
       
   473       {  k = 0;
       
   474          for (i = 1; i <= G->nv; i++)
       
   475          {  v = G->v[i];
       
   476             for (a = v->out; a != NULL; a = a->t_next)
       
   477             {  temp = (double)x[++k];
       
   478                memcpy((char *)a->data + a_x, &temp, sizeof(double));
       
   479             }
       
   480          }
       
   481       }
       
   482       /* (node flags) */
       
   483       if (v_cut >= 0)
       
   484       {  for (i = 1; i <= G->nv; i++)
       
   485          {  v = G->v[i];
       
   486             flag = cut[i];
       
   487             memcpy((char *)v->data + v_cut, &flag, sizeof(int));
       
   488          }
       
   489       }
       
   490 done: /* free working arrays */
       
   491       xfree(tail);
       
   492       xfree(head);
       
   493       xfree(cap);
       
   494       xfree(x);
       
   495       if (cut != NULL) xfree(cut);
       
   496       return ret;
       
   497 }
       
   498 
       
   499 /***********************************************************************
       
   500 *  NAME
       
   501 *
       
   502 *  glp_check_asnprob - check correctness of assignment problem data
       
   503 *
       
   504 *  SYNOPSIS
       
   505 *
       
   506 *  int glp_check_asnprob(glp_graph *G, int v_set);
       
   507 *
       
   508 *  RETURNS
       
   509 *
       
   510 *  If the specified assignment problem data are correct, the routine
       
   511 *  glp_check_asnprob returns zero, otherwise, non-zero. */
       
   512 
       
   513 int glp_check_asnprob(glp_graph *G, int v_set)
       
   514 {     glp_vertex *v;
       
   515       int i, k, ret = 0;
       
   516       if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
       
   517          xerror("glp_check_asnprob: v_set = %d; invalid offset\n",
       
   518             v_set);
       
   519       for (i = 1; i <= G->nv; i++)
       
   520       {  v = G->v[i];
       
   521          if (v_set >= 0)
       
   522          {  memcpy(&k, (char *)v->data + v_set, sizeof(int));
       
   523             if (k == 0)
       
   524             {  if (v->in != NULL)
       
   525                {  ret = 1;
       
   526                   break;
       
   527                }
       
   528             }
       
   529             else if (k == 1)
       
   530             {  if (v->out != NULL)
       
   531                {  ret = 2;
       
   532                   break;
       
   533                }
       
   534             }
       
   535             else
       
   536             {  ret = 3;
       
   537                break;
       
   538             }
       
   539          }
       
   540          else
       
   541          {  if (v->in != NULL && v->out != NULL)
       
   542             {  ret = 4;
       
   543                break;
       
   544             }
       
   545          }
       
   546       }
       
   547       return ret;
       
   548 }
       
   549 
       
   550 /***********************************************************************
       
   551 *  NAME
       
   552 *
       
   553 *  glp_asnprob_lp - convert assignment problem to LP
       
   554 *
       
   555 *  SYNOPSIS
       
   556 *
       
   557 *  int glp_asnprob_lp(glp_prob *P, int form, glp_graph *G, int names,
       
   558 *     int v_set, int a_cost);
       
   559 *
       
   560 *  DESCRIPTION
       
   561 *
       
   562 *  The routine glp_asnprob_lp builds an LP problem, which corresponds
       
   563 *  to the assignment problem on the specified graph G.
       
   564 *
       
   565 *  RETURNS
       
   566 *
       
   567 *  If the LP problem has been successfully built, the routine returns
       
   568 *  zero, otherwise, non-zero. */
       
   569 
       
   570 int glp_asnprob_lp(glp_prob *P, int form, glp_graph *G, int names,
       
   571       int v_set, int a_cost)
       
   572 {     glp_vertex *v;
       
   573       glp_arc *a;
       
   574       int i, j, ret, ind[1+2];
       
   575       double cost, val[1+2];
       
   576       if (!(form == GLP_ASN_MIN || form == GLP_ASN_MAX ||
       
   577             form == GLP_ASN_MMP))
       
   578          xerror("glp_asnprob_lp: form = %d; invalid parameter\n",
       
   579             form);
       
   580       if (!(names == GLP_ON || names == GLP_OFF))
       
   581          xerror("glp_asnprob_lp: names = %d; invalid parameter\n",
       
   582             names);
       
   583       if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
       
   584          xerror("glp_asnprob_lp: v_set = %d; invalid offset\n",
       
   585             v_set);
       
   586       if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
       
   587          xerror("glp_asnprob_lp: a_cost = %d; invalid offset\n",
       
   588             a_cost);
       
   589       ret = glp_check_asnprob(G, v_set);
       
   590       if (ret != 0) goto done;
       
   591       glp_erase_prob(P);
       
   592       if (names) glp_set_prob_name(P, G->name);
       
   593       glp_set_obj_dir(P, form == GLP_ASN_MIN ? GLP_MIN : GLP_MAX);
       
   594       if (G->nv > 0) glp_add_rows(P, G->nv);
       
   595       for (i = 1; i <= G->nv; i++)
       
   596       {  v = G->v[i];
       
   597          if (names) glp_set_row_name(P, i, v->name);
       
   598          glp_set_row_bnds(P, i, form == GLP_ASN_MMP ? GLP_UP : GLP_FX,
       
   599             1.0, 1.0);
       
   600       }
       
   601       if (G->na > 0) glp_add_cols(P, G->na);
       
   602       for (i = 1, j = 0; i <= G->nv; i++)
       
   603       {  v = G->v[i];
       
   604          for (a = v->out; a != NULL; a = a->t_next)
       
   605          {  j++;
       
   606             if (names)
       
   607             {  char name[50+1];
       
   608                sprintf(name, "x[%d,%d]", a->tail->i, a->head->i);
       
   609                xassert(strlen(name) < sizeof(name));
       
   610                glp_set_col_name(P, j, name);
       
   611             }
       
   612             ind[1] = a->tail->i, val[1] = +1.0;
       
   613             ind[2] = a->head->i, val[2] = +1.0;
       
   614             glp_set_mat_col(P, j, 2, ind, val);
       
   615             glp_set_col_bnds(P, j, GLP_DB, 0.0, 1.0);
       
   616             if (a_cost >= 0)
       
   617                memcpy(&cost, (char *)a->data + a_cost, sizeof(double));
       
   618             else
       
   619                cost = 1.0;
       
   620             glp_set_obj_coef(P, j, cost);
       
   621          }
       
   622       }
       
   623       xassert(j == G->na);
       
   624 done: return ret;
       
   625 }
       
   626 
       
   627 /**********************************************************************/
       
   628 
       
   629 int glp_asnprob_okalg(int form, glp_graph *G, int v_set, int a_cost,
       
   630       double *sol, int a_x)
       
   631 {     /* solve assignment problem with out-of-kilter algorithm */
       
   632       glp_vertex *v;
       
   633       glp_arc *a;
       
   634       int nv, na, i, k, *tail, *head, *low, *cap, *cost, *x, *pi, ret;
       
   635       double temp;
       
   636       if (!(form == GLP_ASN_MIN || form == GLP_ASN_MAX ||
       
   637             form == GLP_ASN_MMP))
       
   638          xerror("glp_asnprob_okalg: form = %d; invalid parameter\n",
       
   639             form);
       
   640       if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
       
   641          xerror("glp_asnprob_okalg: v_set = %d; invalid offset\n",
       
   642             v_set);
       
   643       if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
       
   644          xerror("glp_asnprob_okalg: a_cost = %d; invalid offset\n",
       
   645             a_cost);
       
   646       if (a_x >= 0 && a_x > G->a_size - (int)sizeof(int))
       
   647          xerror("glp_asnprob_okalg: a_x = %d; invalid offset\n", a_x);
       
   648       if (glp_check_asnprob(G, v_set))
       
   649          return GLP_EDATA;
       
   650       /* nv is the total number of nodes in the resulting network */
       
   651       nv = G->nv + 1;
       
   652       /* na is the total number of arcs in the resulting network */
       
   653       na = G->na + G->nv;
       
   654       /* allocate working arrays */
       
   655       tail = xcalloc(1+na, sizeof(int));
       
   656       head = xcalloc(1+na, sizeof(int));
       
   657       low = xcalloc(1+na, sizeof(int));
       
   658       cap = xcalloc(1+na, sizeof(int));
       
   659       cost = xcalloc(1+na, sizeof(int));
       
   660       x = xcalloc(1+na, sizeof(int));
       
   661       pi = xcalloc(1+nv, sizeof(int));
       
   662       /* construct the resulting network */
       
   663       k = 0;
       
   664       /* (original arcs) */
       
   665       for (i = 1; i <= G->nv; i++)
       
   666       {  v = G->v[i];
       
   667          for (a = v->out; a != NULL; a = a->t_next)
       
   668          {  k++;
       
   669             tail[k] = a->tail->i;
       
   670             head[k] = a->head->i;
       
   671             low[k] = 0;
       
   672             cap[k] = 1;
       
   673             if (a_cost >= 0)
       
   674                memcpy(&temp, (char *)a->data + a_cost, sizeof(double));
       
   675             else
       
   676                temp = 1.0;
       
   677             if (!(fabs(temp) <= (double)INT_MAX && temp == floor(temp)))
       
   678             {  ret = GLP_EDATA;
       
   679                goto done;
       
   680             }
       
   681             cost[k] = (int)temp;
       
   682             if (form != GLP_ASN_MIN) cost[k] = - cost[k];
       
   683          }
       
   684       }
       
   685       /* (artificial arcs) */
       
   686       for (i = 1; i <= G->nv; i++)
       
   687       {  v = G->v[i];
       
   688          k++;
       
   689          if (v->out == NULL)
       
   690             tail[k] = i, head[k] = nv;
       
   691          else if (v->in == NULL)
       
   692             tail[k] = nv, head[k] = i;
       
   693          else
       
   694             xassert(v != v);
       
   695          low[k] = (form == GLP_ASN_MMP ? 0 : 1);
       
   696          cap[k] = 1;
       
   697          cost[k] = 0;
       
   698       }
       
   699       xassert(k == na);
       
   700       /* find minimal-cost circulation in the resulting network */
       
   701       ret = okalg(nv, na, tail, head, low, cap, cost, x, pi);
       
   702       switch (ret)
       
   703       {  case 0:
       
   704             /* optimal circulation found */
       
   705             ret = 0;
       
   706             break;
       
   707          case 1:
       
   708             /* no feasible circulation exists */
       
   709             ret = GLP_ENOPFS;
       
   710             break;
       
   711          case 2:
       
   712             /* integer overflow occured */
       
   713             ret = GLP_ERANGE;
       
   714             goto done;
       
   715          case 3:
       
   716             /* optimality test failed (logic error) */
       
   717             ret = GLP_EFAIL;
       
   718             goto done;
       
   719          default:
       
   720             xassert(ret != ret);
       
   721       }
       
   722       /* store solution components */
       
   723       /* (objective function = the total cost) */
       
   724       if (sol != NULL)
       
   725       {  temp = 0.0;
       
   726          for (k = 1; k <= na; k++)
       
   727             temp += (double)cost[k] * (double)x[k];
       
   728          if (form != GLP_ASN_MIN) temp = - temp;
       
   729          *sol = temp;
       
   730       }
       
   731       /* (arc flows) */
       
   732       if (a_x >= 0)
       
   733       {  k = 0;
       
   734          for (i = 1; i <= G->nv; i++)
       
   735          {  v = G->v[i];
       
   736             for (a = v->out; a != NULL; a = a->t_next)
       
   737             {  k++;
       
   738                if (ret == 0)
       
   739                   xassert(x[k] == 0 || x[k] == 1);
       
   740                memcpy((char *)a->data + a_x, &x[k], sizeof(int));
       
   741             }
       
   742          }
       
   743       }
       
   744 done: /* free working arrays */
       
   745       xfree(tail);
       
   746       xfree(head);
       
   747       xfree(low);
       
   748       xfree(cap);
       
   749       xfree(cost);
       
   750       xfree(x);
       
   751       xfree(pi);
       
   752       return ret;
       
   753 }
       
   754 
       
   755 /***********************************************************************
       
   756 *  NAME
       
   757 *
       
   758 *  glp_asnprob_hall - find bipartite matching of maximum cardinality
       
   759 *
       
   760 *  SYNOPSIS
       
   761 *
       
   762 *  int glp_asnprob_hall(glp_graph *G, int v_set, int a_x);
       
   763 *
       
   764 *  DESCRIPTION
       
   765 *
       
   766 *  The routine glp_asnprob_hall finds a matching of maximal cardinality
       
   767 *  in the specified bipartite graph G. It uses a version of the Fortran
       
   768 *  routine MC21A developed by I.S.Duff [1], which implements Hall's
       
   769 *  algorithm [2].
       
   770 *
       
   771 *  RETURNS
       
   772 *
       
   773 *  The routine glp_asnprob_hall returns the cardinality of the matching
       
   774 *  found. However, if the specified graph is incorrect (as detected by
       
   775 *  the routine glp_check_asnprob), the routine returns negative value.
       
   776 *
       
   777 *  REFERENCES
       
   778 *
       
   779 *  1. I.S.Duff, Algorithm 575: Permutations for zero-free diagonal, ACM
       
   780 *     Trans. on Math. Softw. 7 (1981), 387-390.
       
   781 *
       
   782 *  2. M.Hall, "An Algorithm for distinct representatives," Amer. Math.
       
   783 *     Monthly 63 (1956), 716-717. */
       
   784 
       
   785 int glp_asnprob_hall(glp_graph *G, int v_set, int a_x)
       
   786 {     glp_vertex *v;
       
   787       glp_arc *a;
       
   788       int card, i, k, loc, n, n1, n2, xij;
       
   789       int *num, *icn, *ip, *lenr, *iperm, *pr, *arp, *cv, *out;
       
   790       if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
       
   791          xerror("glp_asnprob_hall: v_set = %d; invalid offset\n",
       
   792             v_set);
       
   793       if (a_x >= 0 && a_x > G->a_size - (int)sizeof(int))
       
   794          xerror("glp_asnprob_hall: a_x = %d; invalid offset\n", a_x);
       
   795       if (glp_check_asnprob(G, v_set))
       
   796          return -1;
       
   797       /* determine the number of vertices in sets R and S and renumber
       
   798          vertices in S which correspond to columns of the matrix; skip
       
   799          all isolated vertices */
       
   800       num = xcalloc(1+G->nv, sizeof(int));
       
   801       n1 = n2 = 0;
       
   802       for (i = 1; i <= G->nv; i++)
       
   803       {  v = G->v[i];
       
   804          if (v->in == NULL && v->out != NULL)
       
   805             n1++, num[i] = 0; /* vertex in R */
       
   806          else if (v->in != NULL && v->out == NULL)
       
   807             n2++, num[i] = n2; /* vertex in S */
       
   808          else
       
   809          {  xassert(v->in == NULL && v->out == NULL);
       
   810             num[i] = -1; /* isolated vertex */
       
   811          }
       
   812       }
       
   813       /* the matrix must be square, thus, if it has more columns than
       
   814          rows, extra rows will be just empty, and vice versa */
       
   815       n = (n1 >= n2 ? n1 : n2);
       
   816       /* allocate working arrays */
       
   817       icn = xcalloc(1+G->na, sizeof(int));
       
   818       ip = xcalloc(1+n, sizeof(int));
       
   819       lenr = xcalloc(1+n, sizeof(int));
       
   820       iperm = xcalloc(1+n, sizeof(int));
       
   821       pr = xcalloc(1+n, sizeof(int));
       
   822       arp = xcalloc(1+n, sizeof(int));
       
   823       cv = xcalloc(1+n, sizeof(int));
       
   824       out = xcalloc(1+n, sizeof(int));
       
   825       /* build the adjacency matrix of the bipartite graph in row-wise
       
   826          format (rows are vertices in R, columns are vertices in S) */
       
   827       k = 0, loc = 1;
       
   828       for (i = 1; i <= G->nv; i++)
       
   829       {  if (num[i] != 0) continue;
       
   830          /* vertex i in R */
       
   831          ip[++k] = loc;
       
   832          v = G->v[i];
       
   833          for (a = v->out; a != NULL; a = a->t_next)
       
   834          {  xassert(num[a->head->i] != 0);
       
   835             icn[loc++] = num[a->head->i];
       
   836          }
       
   837          lenr[k] = loc - ip[k];
       
   838       }
       
   839       xassert(loc-1 == G->na);
       
   840       /* make all extra rows empty (all extra columns are empty due to
       
   841          the row-wise format used) */
       
   842       for (k++; k <= n; k++)
       
   843          ip[k] = loc, lenr[k] = 0;
       
   844       /* find a row permutation that maximizes the number of non-zeros
       
   845          on the main diagonal */
       
   846       card = mc21a(n, icn, ip, lenr, iperm, pr, arp, cv, out);
       
   847 #if 1 /* 18/II-2010 */
       
   848       /* FIXED: if card = n, arp remains clobbered on exit */
       
   849       for (i = 1; i <= n; i++)
       
   850          arp[i] = 0;
       
   851       for (i = 1; i <= card; i++)
       
   852       {  k = iperm[i];
       
   853          xassert(1 <= k && k <= n);
       
   854          xassert(arp[k] == 0);
       
   855          arp[k] = i;
       
   856       }
       
   857 #endif
       
   858       /* store solution, if necessary */
       
   859       if (a_x < 0) goto skip;
       
   860       k = 0;
       
   861       for (i = 1; i <= G->nv; i++)
       
   862       {  if (num[i] != 0) continue;
       
   863          /* vertex i in R */
       
   864          k++;
       
   865          v = G->v[i];
       
   866          for (a = v->out; a != NULL; a = a->t_next)
       
   867          {  /* arp[k] is the number of matched column or zero */
       
   868             if (arp[k] == num[a->head->i])
       
   869             {  xassert(arp[k] != 0);
       
   870                xij = 1;
       
   871             }
       
   872             else
       
   873                xij = 0;
       
   874             memcpy((char *)a->data + a_x, &xij, sizeof(int));
       
   875          }
       
   876       }
       
   877 skip: /* free working arrays */
       
   878       xfree(num);
       
   879       xfree(icn);
       
   880       xfree(ip);
       
   881       xfree(lenr);
       
   882       xfree(iperm);
       
   883       xfree(pr);
       
   884       xfree(arp);
       
   885       xfree(cv);
       
   886       xfree(out);
       
   887       return card;
       
   888 }
       
   889 
       
   890 /***********************************************************************
       
   891 *  NAME
       
   892 *
       
   893 *  glp_cpp - solve critical path problem
       
   894 *
       
   895 *  SYNOPSIS
       
   896 *
       
   897 *  double glp_cpp(glp_graph *G, int v_t, int v_es, int v_ls);
       
   898 *
       
   899 *  DESCRIPTION
       
   900 *
       
   901 *  The routine glp_cpp solves the critical path problem represented in
       
   902 *  the form of the project network.
       
   903 *
       
   904 *  The parameter G is a pointer to the graph object, which specifies
       
   905 *  the project network. This graph must be acyclic. Multiple arcs are
       
   906 *  allowed being considered as single arcs.
       
   907 *
       
   908 *  The parameter v_t specifies an offset of the field of type double
       
   909 *  in the vertex data block, which contains time t[i] >= 0 needed to
       
   910 *  perform corresponding job j. If v_t < 0, it is assumed that t[i] = 1
       
   911 *  for all jobs.
       
   912 *
       
   913 *  The parameter v_es specifies an offset of the field of type double
       
   914 *  in the vertex data block, to which the routine stores earliest start
       
   915 *  time for corresponding job. If v_es < 0, this time is not stored.
       
   916 *
       
   917 *  The parameter v_ls specifies an offset of the field of type double
       
   918 *  in the vertex data block, to which the routine stores latest start
       
   919 *  time for corresponding job. If v_ls < 0, this time is not stored.
       
   920 *
       
   921 *  RETURNS
       
   922 *
       
   923 *  The routine glp_cpp returns the minimal project duration, that is,
       
   924 *  minimal time needed to perform all jobs in the project. */
       
   925 
       
   926 static void sorting(glp_graph *G, int list[]);
       
   927 
       
   928 double glp_cpp(glp_graph *G, int v_t, int v_es, int v_ls)
       
   929 {     glp_vertex *v;
       
   930       glp_arc *a;
       
   931       int i, j, k, nv, *list;
       
   932       double temp, total, *t, *es, *ls;
       
   933       if (v_t >= 0 && v_t > G->v_size - (int)sizeof(double))
       
   934          xerror("glp_cpp: v_t = %d; invalid offset\n", v_t);
       
   935       if (v_es >= 0 && v_es > G->v_size - (int)sizeof(double))
       
   936          xerror("glp_cpp: v_es = %d; invalid offset\n", v_es);
       
   937       if (v_ls >= 0 && v_ls > G->v_size - (int)sizeof(double))
       
   938          xerror("glp_cpp: v_ls = %d; invalid offset\n", v_ls);
       
   939       nv = G->nv;
       
   940       if (nv == 0)
       
   941       {  total = 0.0;
       
   942          goto done;
       
   943       }
       
   944       /* allocate working arrays */
       
   945       t = xcalloc(1+nv, sizeof(double));
       
   946       es = xcalloc(1+nv, sizeof(double));
       
   947       ls = xcalloc(1+nv, sizeof(double));
       
   948       list = xcalloc(1+nv, sizeof(int));
       
   949       /* retrieve job times */
       
   950       for (i = 1; i <= nv; i++)
       
   951       {  v = G->v[i];
       
   952          if (v_t >= 0)
       
   953          {  memcpy(&t[i], (char *)v->data + v_t, sizeof(double));
       
   954             if (t[i] < 0.0)
       
   955                xerror("glp_cpp: t[%d] = %g; invalid time\n", i, t[i]);
       
   956          }
       
   957          else
       
   958             t[i] = 1.0;
       
   959       }
       
   960       /* perform topological sorting to determine the list of nodes
       
   961          (jobs) such that if list[k] = i and list[kk] = j and there
       
   962          exists arc (i->j), then k < kk */
       
   963       sorting(G, list);
       
   964       /* FORWARD PASS */
       
   965       /* determine earliest start times */
       
   966       for (k = 1; k <= nv; k++)
       
   967       {  j = list[k];
       
   968          es[j] = 0.0;
       
   969          for (a = G->v[j]->in; a != NULL; a = a->h_next)
       
   970          {  i = a->tail->i;
       
   971             /* there exists arc (i->j) in the project network */
       
   972             temp = es[i] + t[i];
       
   973             if (es[j] < temp) es[j] = temp;
       
   974          }
       
   975       }
       
   976       /* determine the minimal project duration */
       
   977       total = 0.0;
       
   978       for (i = 1; i <= nv; i++)
       
   979       {  temp = es[i] + t[i];
       
   980          if (total < temp) total = temp;
       
   981       }
       
   982       /* BACKWARD PASS */
       
   983       /* determine latest start times */
       
   984       for (k = nv; k >= 1; k--)
       
   985       {  i = list[k];
       
   986          ls[i] = total - t[i];
       
   987          for (a = G->v[i]->out; a != NULL; a = a->t_next)
       
   988          {  j = a->head->i;
       
   989             /* there exists arc (i->j) in the project network */
       
   990             temp = ls[j] - t[i];
       
   991             if (ls[i] > temp) ls[i] = temp;
       
   992          }
       
   993          /* avoid possible round-off errors */
       
   994          if (ls[i] < es[i]) ls[i] = es[i];
       
   995       }
       
   996       /* store results, if necessary */
       
   997       if (v_es >= 0)
       
   998       {  for (i = 1; i <= nv; i++)
       
   999          {  v = G->v[i];
       
  1000             memcpy((char *)v->data + v_es, &es[i], sizeof(double));
       
  1001          }
       
  1002       }
       
  1003       if (v_ls >= 0)
       
  1004       {  for (i = 1; i <= nv; i++)
       
  1005          {  v = G->v[i];
       
  1006             memcpy((char *)v->data + v_ls, &ls[i], sizeof(double));
       
  1007          }
       
  1008       }
       
  1009       /* free working arrays */
       
  1010       xfree(t);
       
  1011       xfree(es);
       
  1012       xfree(ls);
       
  1013       xfree(list);
       
  1014 done: return total;
       
  1015 }
       
  1016 
       
  1017 static void sorting(glp_graph *G, int list[])
       
  1018 {     /* perform topological sorting to determine the list of nodes
       
  1019          (jobs) such that if list[k] = i and list[kk] = j and there
       
  1020          exists arc (i->j), then k < kk */
       
  1021       int i, k, nv, v_size, *num;
       
  1022       void **save;
       
  1023       nv = G->nv;
       
  1024       v_size = G->v_size;
       
  1025       save = xcalloc(1+nv, sizeof(void *));
       
  1026       num = xcalloc(1+nv, sizeof(int));
       
  1027       G->v_size = sizeof(int);
       
  1028       for (i = 1; i <= nv; i++)
       
  1029       {  save[i] = G->v[i]->data;
       
  1030          G->v[i]->data = &num[i];
       
  1031          list[i] = 0;
       
  1032       }
       
  1033       if (glp_top_sort(G, 0) != 0)
       
  1034          xerror("glp_cpp: project network is not acyclic\n");
       
  1035       G->v_size = v_size;
       
  1036       for (i = 1; i <= nv; i++)
       
  1037       {  G->v[i]->data = save[i];
       
  1038          k = num[i];
       
  1039          xassert(1 <= k && k <= nv);
       
  1040          xassert(list[k] == 0);
       
  1041          list[k] = i;
       
  1042       }
       
  1043       xfree(save);
       
  1044       xfree(num);
       
  1045       return;
       
  1046 }
       
  1047 
       
  1048 /* eof */