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