1 /* asnokalg.c (solve assignment problem with out-of-kilter alg.) */
2
3 /***********************************************************************
4 * This code is part of GLPK (GNU Linear Programming Kit).
5 * Copyright (C) 2009-2016 Free Software Foundation, Inc.
6 * Written by Andrew Makhorin <mao@gnu.org>.
7 *
8 * GLPK is free software: you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * GLPK is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 * License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with GLPK. If not, see <http://www.gnu.org/licenses/>.
20 ***********************************************************************/
21
22 #include "env.h"
23 #include "glpk.h"
24 #include "okalg.h"
25
glp_asnprob_okalg(int form,glp_graph * G,int v_set,int a_cost,double * sol,int a_x)26 int glp_asnprob_okalg(int form, glp_graph *G, int v_set, int a_cost,
27 double *sol, int a_x)
28 { /* solve assignment problem with out-of-kilter algorithm */
29 glp_vertex *v;
30 glp_arc *a;
31 int nv, na, i, k, *tail, *head, *low, *cap, *cost, *x, *pi, ret;
32 double temp;
33 if (!(form == GLP_ASN_MIN || form == GLP_ASN_MAX ||
34 form == GLP_ASN_MMP))
35 xerror("glp_asnprob_okalg: form = %d; invalid parameter\n",
36 form);
37 if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
38 xerror("glp_asnprob_okalg: v_set = %d; invalid offset\n",
39 v_set);
40 if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
41 xerror("glp_asnprob_okalg: a_cost = %d; invalid offset\n",
42 a_cost);
43 if (a_x >= 0 && a_x > G->a_size - (int)sizeof(int))
44 xerror("glp_asnprob_okalg: a_x = %d; invalid offset\n", a_x);
45 if (glp_check_asnprob(G, v_set))
46 return GLP_EDATA;
47 /* nv is the total number of nodes in the resulting network */
48 nv = G->nv + 1;
49 /* na is the total number of arcs in the resulting network */
50 na = G->na + G->nv;
51 /* allocate working arrays */
52 tail = xcalloc(1+na, sizeof(int));
53 head = xcalloc(1+na, sizeof(int));
54 low = xcalloc(1+na, sizeof(int));
55 cap = xcalloc(1+na, sizeof(int));
56 cost = xcalloc(1+na, sizeof(int));
57 x = xcalloc(1+na, sizeof(int));
58 pi = xcalloc(1+nv, sizeof(int));
59 /* construct the resulting network */
60 k = 0;
61 /* (original arcs) */
62 for (i = 1; i <= G->nv; i++)
63 { v = G->v[i];
64 for (a = v->out; a != NULL; a = a->t_next)
65 { k++;
66 tail[k] = a->tail->i;
67 head[k] = a->head->i;
68 low[k] = 0;
69 cap[k] = 1;
70 if (a_cost >= 0)
71 memcpy(&temp, (char *)a->data + a_cost, sizeof(double));
72 else
73 temp = 1.0;
74 if (!(fabs(temp) <= (double)INT_MAX && temp == floor(temp)))
75 { ret = GLP_EDATA;
76 goto done;
77 }
78 cost[k] = (int)temp;
79 if (form != GLP_ASN_MIN) cost[k] = - cost[k];
80 }
81 }
82 /* (artificial arcs) */
83 for (i = 1; i <= G->nv; i++)
84 { v = G->v[i];
85 k++;
86 if (v->out == NULL)
87 tail[k] = i, head[k] = nv;
88 else if (v->in == NULL)
89 tail[k] = nv, head[k] = i;
90 else
91 xassert(v != v);
92 low[k] = (form == GLP_ASN_MMP ? 0 : 1);
93 cap[k] = 1;
94 cost[k] = 0;
95 }
96 xassert(k == na);
97 /* find minimal-cost circulation in the resulting network */
98 ret = okalg(nv, na, tail, head, low, cap, cost, x, pi);
99 switch (ret)
100 { case 0:
101 /* optimal circulation found */
102 ret = 0;
103 break;
104 case 1:
105 /* no feasible circulation exists */
106 ret = GLP_ENOPFS;
107 break;
108 case 2:
109 /* integer overflow occured */
110 ret = GLP_ERANGE;
111 goto done;
112 case 3:
113 /* optimality test failed (logic error) */
114 ret = GLP_EFAIL;
115 goto done;
116 default:
117 xassert(ret != ret);
118 }
119 /* store solution components */
120 /* (objective function = the total cost) */
121 if (sol != NULL)
122 { temp = 0.0;
123 for (k = 1; k <= na; k++)
124 temp += (double)cost[k] * (double)x[k];
125 if (form != GLP_ASN_MIN) temp = - temp;
126 *sol = temp;
127 }
128 /* (arc flows) */
129 if (a_x >= 0)
130 { k = 0;
131 for (i = 1; i <= G->nv; i++)
132 { v = G->v[i];
133 for (a = v->out; a != NULL; a = a->t_next)
134 { k++;
135 if (ret == 0)
136 xassert(x[k] == 0 || x[k] == 1);
137 memcpy((char *)a->data + a_x, &x[k], sizeof(int));
138 }
139 }
140 }
141 done: /* free working arrays */
142 xfree(tail);
143 xfree(head);
144 xfree(low);
145 xfree(cap);
146 xfree(cost);
147 xfree(x);
148 xfree(pi);
149 return ret;
150 }
151
152 /* eof */
153