1 /*===========================================================================*/
2 /* */
3 /* This file is part of a demonstration application for use with the */
4 /* SYMPHONY Branch, Cut, and Price Library. This application is a solver for */
5 /* Capacitated Network Routing Problems. */
6 /* */
7 /* (c) Copyright 2000-2007 Ted Ralphs. All Rights Reserved. */
8 /* */
9 /* This application was developed by Ted Ralphs (ted@lehigh.edu) */
10 /* */
11 /* This software is licensed under the Eclipse Public License. Please see */
12 /* accompanying file for terms. */
13 /* */
14 /*===========================================================================*/
15
16 /* system include files */
17
18 /* SYMPHONY include files */
19 #include "sym_macros.h"
20 #include "sym_constants.h"
21 #include "sym_dg.h"
22
23 /* CNRP include files */
24 #include "cnrp_dg.h"
25 #include "cnrp_const.h"
26 #include "cnrp_macros.h"
27
28 /*===========================================================================*/
29
30 /*===========================================================================*\
31 * This file contains additional user functions for the draw graph process.
32 \*===========================================================================*/
33
34 /*===========================================================================*\
35 * Create the solution graph using adjacency lists
36 \*===========================================================================*/
37
dg_createnet(int vertnum,int length,int * xind,double * xval)38 dg_net_network *dg_createnet(int vertnum, int length, int *xind, double *xval)
39 {
40 dg_net_edge *nedge;
41 dg_net_network *n;
42 dg_net_vertex *verts, *nv;
43 int v[2], i, j;
44 dg_net_elist *adjlist;
45
46 n = (dg_net_network *) calloc(1, sizeof(dg_net_network));
47 n->vertnum = vertnum;
48 n->edgenum = length;
49 n->verts = verts =
50 (dg_net_vertex *) calloc(n->vertnum, sizeof(dg_net_vertex));
51 n->adjlist = adjlist =
52 (dg_net_elist *) malloc(2 * n->edgenum*sizeof(dg_net_elist));
53 n->edges = nedge = (dg_net_edge *) calloc(n->edgenum, sizeof(dg_net_edge));
54
55 /*---- set up orignodenum ------------------------------------------------*/
56 for (i=vertnum-1; i>=0; i--){
57 verts[i].orignodenum = i;
58 }
59
60 /*---- set up the adjacency list -----------------------------------------*/
61 for (i=0; i<length; i++, xval++, xind++){
62 BOTH_ENDS(*xind, &v[1], &v[0]);
63 nedge->head = verts + v[0];
64 nedge->tail = verts + v[1];
65 nedge->weight = *xval;
66 for (j=1; j>=0; j--){
67 nv = verts + v[j];
68 if (!nv->first){
69 nv->first = nv->last = adjlist;
70 }else{
71 nv->last->next_edge = adjlist;
72 nv->last = adjlist;
73 }
74 adjlist->next_edge = NULL;
75 nv->degree++;
76 adjlist->data = nedge;
77 adjlist->other = verts + v[1-j];
78 adjlist++;
79 }
80 nedge++;
81 }
82 return(n);
83 }
84
85 /*===========================================================================*/
86
87 /*===========================================================================*\
88 * Free the network
89 \*===========================================================================*/
90
dg_freenet(dg_net_network * n)91 void dg_freenet(dg_net_network *n)
92 {
93 if (n){
94 FREE(n->adjlist);
95 FREE(n->edges);
96 FREE(n->verts);
97 FREE(n);
98 }
99 }
100
101 /*===========================================================================*/
102
103 /*===========================================================================*\
104 * This function shrinks the chains in the graph
105 \*===========================================================================*/
106
dg_net_shrink_chains(dg_net_network * n)107 void dg_net_shrink_chains(dg_net_network *n)
108 {
109 int vertnum = n->vertnum;
110 dg_net_vertex *verts = n->verts;
111
112 dg_net_vertex *nw, *nv1, *nv, *nu;
113 dg_net_elist *ne;
114 dg_net_edge *dat;
115
116 int i;
117
118 /*------------------------------------------------------------------------*
119 * Here we contract all chains of 1-edges, called 1-paths. We simply
120 * look at all nodes of degree 2 and keep following the 1-path in each
121 * direction from that node until we reach a node that is not of degree 2.
122 *------------------------------------------------------------------------*/
123
124 for (i=0; i<vertnum-1; i++){
125 nv = verts+i;
126 /*-----------check whether we have a degree 2 node-----------*/
127 if (nv->scanned != NOT_SCANNED || nv->degree != 2)
128 continue;
129
130 nv->scanned = SCANNED_SHRUNK;
131
132 /*---------------------------------------------------------------------*
133 * follow the 1-path from i until we hit a node that is not of degree 2
134 * If during this process we come back to nv (i) that means we have a
135 * subtour we can contract into one node.
136 * Also, as we go along we contract all the nodes on the 1-path into i.
137 *---------------------------------------------------------------------*/
138 for (ne = nv->first, nw = ne->other; nw->degree == 2; nw = ne->other){
139 ne->data->deleted = TRUE;
140 if (nv == nw)
141 break;
142 nw->scanned = SCANNED_SHRUNK;
143 nv->snode_size++;
144 nw->snode_next = nv->snode_next;
145 nv->snode_next = nw;
146 ne = (nw->first->data->deleted ? nw->last : nw->first);
147 }
148
149 if (nv == nw){
150 /* in this case we had a subtour and so we don't need to go on*/
151 nv->first = nv->last = NULL;
152 nv->scanned = SCANNED_ALIVE;
153 continue;
154 }
155
156 /* Now nw is not a degree 2 node, but nv->snode_next is the node
157 * in the chain adjacent to nw and so on. The number of nodes
158 * hanging off nv is exactly nv->snode_size (not including nv) */
159 if (nv->snode_size){
160 nv1 = nv->snode_next;
161 if (nv1->first->other != nw){
162 ne = nv1->first;
163 nv1->first = nv1->last;
164 nv1->first->next_edge = ne;
165 nv1->last = ne;
166 ne->next_edge = NULL;
167 }
168 /* Follow the chain back and hang nv to the end */
169 nv1->snode_size = nv->snode_size;
170 for (nu = nv1; nu->snode_next; nu = nu->snode_next);
171 nu->snode_next = nv;
172 nv->snode_next = NULL;
173 nv->snode_size = 0;
174 }else{
175 nv1 = nv;
176 }
177
178 /* Now nw is next to nv1 and nv1->first->other = nw */
179
180 /* Continue to the other end. */
181 for (ne=nv->last, nu=ne->other; nu->degree == 2; nv=nu, nu=ne->other){
182 ne->data->deleted = TRUE;
183 nu->scanned = SCANNED_SHRUNK;
184 nv1->snode_size++;
185 nv->snode_next = nu;
186 ne = (nu->first->data->deleted ? nu->last : nu->first);
187 }
188
189 /* Now nv is the last node in the chain, nu the first not degree
190 * 2 node, (ne goes from nv to nu) the chain hangs off of nv1 in
191 * order, nv1->size is the number of degree 2 nodes in the chain
192 * -1 (nv1 itself).
193 *
194 * Now we update the adjacency lists appropriately. */
195 if (nv1->snode_size){
196 nv1->first->next_edge = nv1->last = ne;
197 ne->next_edge = NULL;
198 dat = ne->data;
199 if (dat->head == nu)
200 dat->tail = nv1;
201 else
202 dat->head = nv1;
203 for (ne=nu->first; ne->data != dat; ne=ne->next_edge);
204 ne->other = nv1;
205 }
206 nv1->scanned = SCANNED_ALIVE;
207 /* Now we are completely done. The whole chain is shrinked
208 * into nv1, nv1 is connected to appropriately to nw and nu. */
209 }
210
211 /* Note that the 'scanned' field is SCANNED_SHRUNK for nodes shrinked into
212 * another node; SCANNED_ALIVE for degree 2 nodes still alive and
213 * NOT_SCANNED for nodes of degree >= 3 */
214 }
215
216 /*===========================================================================*/
217
218 /*===========================================================================*\
219 * This function copies a network into a graph which already contains the
220 * nodes of the graph. Therefore we have to get rid of the shrunk nodes
221 * in the process.
222 \*===========================================================================*/
223
copy_network_into_graph(dg_net_network * n,dg_graph * g)224 void copy_network_into_graph(dg_net_network *n, dg_graph *g)
225 {
226 int i, k, vertnum = n->vertnum, edgenum = n->edgenum;
227 dg_net_vertex *verts = n->verts;
228 dg_net_edge *ne, *nedges = n->edges;
229 dg_node *nod, *gnod, *nodes, *gnodes = g->nodes;
230 dg_edge *ge, *gedges = g->edges;
231
232 for (k = i = 0; i < vertnum; i++)
233 if (verts[i].scanned != SCANNED_SHRUNK)
234 k++;
235
236 nodes = (dg_node *) malloc(k * sizeof(dg_node));
237 for (k = i = 0; i < vertnum; i++){
238 if (verts[i].scanned != SCANNED_SHRUNK){
239 nod = nodes + k++;
240 gnod = gnodes + i;
241 *nod = *gnod;
242 if (verts[i].snode_size){ /* if anything is shrunk into this node */
243 sprintf(nod->weight, "%i", verts[i].snode_size);
244 }else{
245 *nod->weight = 0;
246 }
247 }
248 }
249 FREE(gnodes);
250 g->nodenum = k;
251 g->nodes = nodes;
252
253 for (k = i = 0; i < edgenum; i++)
254 if (! nedges[i].deleted)
255 k++;
256
257 gedges = g->edges = (dg_edge *) malloc(k * sizeof(dg_edge));
258 for (k = i = 0; i < edgenum; i++){
259 if (!(ne=nedges+i)->deleted){
260 ge = gedges + k++;
261 ge->edge_id = INDEX( (ge->tail = ne->tail->orignodenum),
262 (ge->head = ne->head->orignodenum) );
263 ge->deleted = FALSE;
264 if (ne->weight > .99999){
265 strcpy(ge->weight, "1");
266 ge->dash[0] = 0;
267 }else{
268 sprintf(ge->weight, "%.3f", ne->weight);
269 strcpy(ge->dash, "4 3");
270 }
271 }
272 }
273 g->edgenum = k;
274 }
275