1 #include <math.h>
2 #include <stdlib.h>
3
4 #include "qsortucb.h"
5 #include "BB_constants.h"
6 #include "sym_timemeas.h"
7 #include "sym_messages.h"
8 #include "decomp.h"
9 #include "decomp_user.h"
10 #include "compute_cost.h"
11 #include "network.h"
12 #include "decomp_types.h"
13 #include "sym_dg_params.h"
14 #include "vrp_sym_dg.h"
15 #include "vrp_macros.h"
16 #include "vrp_const.h"
17 #include "ind_sort.h"
18
int_compar(const void * int1,const void * int2)19 int int_compar(const void *int1, const void *int2)
20 {
21 return((*((int *)int1)) - (*((int *)int2)));
22 }
23
24 /*===========================================================================*/
25
user_generate_new_cols(cg_prob * p)26 dcmp_col_set *user_generate_new_cols(cg_prob *p)
27 {
28 cg_vrp_spec *vrp = (cg_vrp_spec *)(p->user);
29 int size = vrp->vertnum+vrp->numroutes-1;
30 dcmp_col_set *cols = (dcmp_col_set *) calloc (1, sizeof(dcmp_col_set));
31 int *intour;
32 int *tour;
33 edge **stack;
34 vertex *verts;
35 elist *cur_edge;
36 int position = 0;
37 int numroutes = vrp->numroutes;
38
39 cols->lb = (double *) calloc (COL_BLOCK_SIZE, sizeof(double));
40 cols->ub = (double *) calloc (COL_BLOCK_SIZE, sizeof(double));
41 cols->obj = (double *) calloc (COL_BLOCK_SIZE, sizeof(double));
42 cols->matbeg = (int *) calloc (COL_BLOCK_SIZE+1, sizeof(int));
43 cols->matind = (int *) calloc (size*COL_BLOCK_SIZE, sizeof(int));
44 cols->matval = (double *) calloc (size*COL_BLOCK_SIZE, sizeof(double));
45 cols->num_cols = 0;
46 cols->max_cols = COL_BLOCK_SIZE;
47 cols->nzcnt = 0;
48 cols->max_nzcnt = size*COL_BLOCK_SIZE;
49
50 intour = (int *) calloc (vrp->vertnum, sizeof(int));
51 tour = (int *) calloc (size+1, sizeof(int));
52
53 if (!vrp->n){
54 ind_sort(p->cur_sol.xind, p->cur_sol.xval, p->cur_sol.xlength);
55 vrp->n = createnet(p->cur_sol.xind, p->cur_sol.xval, p->cur_sol.xlength,
56 p->cur_sol.lpetol, vrp->edges, vrp->demand,
57 vrp->vertnum);
58 }
59
60 verts = vrp->n->verts;
61
62 cur_edge = verts[0].first;
63 stack=(edge **) malloc(verts[0].degree*sizeof(edge *));
64
65 p->dcmp_data.timeout = time(NULL);
66
67 while(cur_edge &&cur_edge->data->weight == 2){
68 intour[cur_edge->other_end]++;
69 tour[intour[0]++] = cur_edge->other_end+numroutes;
70 tour[cur_edge->other_end+numroutes]=intour[0];
71 cur_edge->data->deleted = TRUE;
72 stack[position++]=cur_edge->data;
73 cur_edge = cur_edge->next_edge;
74 }
75 if (cur_edge){
76 bfm(p, 0, intour, tour, cols, stack, position);
77 }else{
78 add_tour_to_col_set(p, tour, vrp, cols);
79 }
80
81 FREE(tour);
82 FREE(intour);
83 FREE(stack);
84
85 return(cols);
86 }
87
88 /*===========================================================================*/
89
bfm(cg_prob * p,int cur_node,int * intour,int * tour,dcmp_col_set * cols,edge ** stack,int position)90 char bfm(cg_prob *p, int cur_node, int *intour, int *tour, dcmp_col_set *cols,
91 edge **stack, int position)
92 {
93 cg_vrp_spec *vrp = (cg_vrp_spec *)(p->user);
94 int numroutes = vrp->numroutes, vertnum = vrp->vertnum;
95 vertex *verts = vrp->n->verts;
96 int i;
97 int count=0;
98 elist *cur_edge;
99
100 if (cur_node == 0 && intour[0] == numroutes){
101 for (i = 0; i < vertnum; i++){
102 if (intour[i] == FALSE)
103 break;
104 }
105 if (i < vertnum){
106 return(TRUE);
107 }
108 add_tour_to_col_set(p, tour, vrp, cols);
109 if (time(NULL) - p->dcmp_data.timeout > p->par.decomp_timeout ||
110 cols->num_cols == p->par.decomp_max_col_num_per_iter){
111 return(FALSE);
112 }else{
113 return(TRUE);
114 }
115 }
116
117 intour[cur_node]++;
118
119 if ( cur_node ){
120 for (cur_edge = verts[cur_node].first; cur_edge;
121 cur_edge = cur_edge->next_edge){
122 if (cur_edge->data->weight == 1){
123 if (cur_edge->other_end && !intour[cur_edge->other_end]){
124 tour[cur_node+numroutes] = cur_edge->other_end+numroutes;
125 if (time(NULL) - p->dcmp_data.timeout > p->par.decomp_timeout ||
126 !bfm(p, cur_edge->other_end, intour, tour, cols, stack,
127 position)){
128 return(FALSE);
129 }else{
130 intour[cur_node]--;
131 return(TRUE);
132 }
133 }
134 }else{
135 break;
136 }
137 }
138
139 for (cur_edge = verts[cur_node].first; cur_edge;
140 cur_edge = cur_edge->next_edge){
141 if (!(cur_edge->other_end?
142 intour[cur_edge->other_end] : cur_edge->data->deleted)){
143 tour[cur_node+numroutes] = cur_edge->other_end?
144 cur_edge->other_end+numroutes:intour[0];
145 if (time(NULL) - p->dcmp_data.timeout > p->par.decomp_timeout ||
146 !bfm(p, cur_edge->other_end, intour, tour, cols, stack,
147 position))
148 return(FALSE);
149 }
150 }
151 }else{
152 for (cur_edge = verts[cur_node].first; cur_edge;
153 cur_edge = cur_edge->next_edge)
154 if (!(intour[cur_edge->other_end]) && !(cur_edge->data->deleted)){
155 tour[intour[0]-1] = cur_edge->other_end+numroutes;
156 if (!vrp->par.allow_one_routes_in_bfm)
157 cur_edge->data->deleted = TRUE;
158 if (time(NULL) - p->dcmp_data.timeout > p->par.decomp_timeout ||
159 !bfm(p, cur_edge->other_end, intour, tour, cols, stack,
160 position))
161 return(FALSE);
162 cur_edge->data->deleted = TRUE;
163 stack[position++]=cur_edge->data;
164 count++;
165 }
166 for ( i=0;i<count; i++){
167 (stack[--position])->deleted = FALSE;
168 }
169 }
170 intour[cur_node]--;
171 return(TRUE);
172
173 }
174
175 /*===========================================================================*/
176
add_tour_to_col_set(cg_prob * p,int * tour,cg_vrp_spec * vrp,dcmp_col_set * cols)177 void add_tour_to_col_set(cg_prob *p, int *tour, cg_vrp_spec *vrp,
178 dcmp_col_set *cols)
179 {
180 int *coef = cols->matind+cols->nzcnt;
181 int size = vrp->vertnum+vrp->numroutes-1, k;
182 int cur_node, next_node;
183 double cost, *unbdd_row = p->dcmp_data.unbdd_row;
184 int dunbr = p->dcmp_data.dunbr;
185 double gamma = unbdd_row[p->dcmp_data.lp_data->m-1];
186 double etol = p->cur_sol.lpetol;
187 int numroutes = vrp->numroutes;
188 char name[100];
189
190 if (cols->num_cols == cols->max_cols){
191 cols->max_cols += COL_BLOCK_SIZE;
192 cols->lb = (double *) realloc ((char *)cols->lb,
193 (cols->max_cols)*sizeof(double));
194 cols->ub = (double *) realloc ((char *)cols->ub,
195 (cols->max_cols)*sizeof(double));
196 cols->obj = (double *) realloc ((char *)cols->obj,
197 (cols->max_cols)*sizeof(double));
198 cols->matbeg = (int *) realloc ((char *)cols->matbeg,
199 (cols->max_cols+1)*sizeof(int));
200 }
201 if (cols->nzcnt + size > cols->max_nzcnt){
202 cols->max_nzcnt += size*COL_BLOCK_SIZE;
203 cols->matind = (int *) realloc ((char *)cols->matind,
204 cols->max_nzcnt*sizeof(int));
205 cols->matval = (double *) realloc ((char *)cols->matval,
206 cols->max_nzcnt*sizeof(double));
207 }
208
209 coef = cols->matind + cols->nzcnt;
210
211 coef[0] = INDEX(0, tour[0]-numroutes);
212 cost = dunbr ? unbdd_row[coef[0]]:0;
213 for (cur_node = tour[0], next_node = tour[cur_node], k = 1;;
214 cur_node = next_node, next_node = tour[cur_node]){
215 if (next_node == numroutes){
216 coef[k] = INDEX(0, (cur_node-numroutes));
217 cost += dunbr ? unbdd_row[coef[k]] : 0;
218 break;
219 }
220 coef[k] = INDEX((cur_node>numroutes?cur_node-numroutes:0),
221 (next_node>numroutes?next_node-numroutes:0));
222 cost += dunbr ? unbdd_row[coef[k]] : 0;
223 k++;
224 }
225
226 if (vrp->dg_id && p->par.verbosity > 4){
227 sprintf(name, "Partial Decomp Tour (%i,%i,%i,%i)",
228 p->cur_sol.xlevel, p->cur_sol.xiter_num, p->cur_sol.xiter_num,
229 cols->num_cols);
230 display_part_tour(vrp->dg_id, TRUE, name, tour, numroutes,
231 CTOI_WAIT_FOR_CLICK_AND_REPORT);
232 }
233
234 if (dunbr && cost + gamma >= -etol)
235 return;
236
237 qsort ((char *)coef, size, sizeof(int), int_compar);
238
239 cols->nzcnt += size;
240 cols->matbeg[cols->num_cols+1] = cols->matbeg[cols->num_cols]+size;
241 cols->num_cols++;
242 }
243
244 /*===========================================================================*/
245
user_unpack_col(cg_prob * p,col_data * col,int * nzcnt,int * matind)246 void user_unpack_col(cg_prob *p, col_data *col, int *nzcnt, int *matind)
247 {
248 memcpy ((char *) matind, col->coef, col->size);
249 }
250
251 /*===========================================================================*/
252
user_display_col(cg_prob * p,col_data * col)253 void user_display_col(cg_prob *p, col_data *col)
254 {
255 int nzcnt = col->size/(sizeof(int));
256 cg_vrp_spec *vrp = (cg_vrp_spec *)p->user;
257 int i, *origind = (int *) calloc ((int)nzcnt, sizeof(int));
258 double *x = (double *) calloc ((int)nzcnt, sizeof(double));
259
260 for (i=0; i<nzcnt; i++){
261 origind[i] = (int)(((int *)col->coef)[i]);
262 x[i] = 1;
263 }
264
265 draw_weighted_edge_set(vrp->dg_id, (char *)"Decomp Column", nzcnt, origind,
266 x, p->cur_sol.lpetol);
267 }
268
269 /*===========================================================================*/
270
user_check_col(cg_prob * p,int * colind,double * colval,int collen)271 int user_check_col(cg_prob *p, int *colind, double *colval, int collen)
272 {
273 cg_vrp_spec *vrp = (cg_vrp_spec *)p->user;
274 int capacity = vrp->capacity, *demand = vrp->demand;
275 int weight, num_cuts = 0;
276 int cut_size = (vrp->vertnum >> DELETE_POWER) +1;
277 network *n;
278 elist *cur_route_start;
279 vertex *verts;
280 int cur_route, cur_vert, prev_vert, cust_num;
281 edge *edge_data;
282 cut_data *new_cut;
283
284 n = createnet(colind, colval, collen-1, p->cur_sol.lpetol,
285 vrp->edges, vrp->demand, vrp->vertnum);
286
287 verts = n->verts;
288 new_cut = (cut_data *) calloc (1, sizeof(cut_data));
289 new_cut->size = cut_size;
290 /*new_cut->level = p->cur_sol.xlevel;*/
291
292 for (cur_route_start = verts[0].first, cur_route = 0,
293 edge_data = cur_route_start->data; cur_route < vrp->numroutes;
294 cur_route++){
295 edge_data = cur_route_start->data;
296 edge_data->scanned = TRUE;
297 cur_vert = edge_data->v1;
298 prev_vert = weight = cust_num = 0;
299
300 new_cut->coef = (char *) calloc (cut_size, sizeof(char));
301
302 while (cur_vert){
303 /*keep tracing around the route and whenever the addition
304 of the next customer causes a violation, impose the
305 constraint induced
306 by the set of customers seen so far on the route*/
307 new_cut->coef[cur_vert >> DELETE_POWER] |=
308 (1 << (cur_vert & DELETE_AND));
309 cust_num++;
310 if ((weight += demand[cur_vert]) > capacity){
311 new_cut->type = (cust_num < vrp->vertnum/2 ?
312 SUBTOUR_ELIM_SIDE:SUBTOUR_ELIM_ACROSS);
313 new_cut->rhs = (new_cut->type ==SUBTOUR_ELIM_SIDE ?
314 RHS(cust_num, weight, capacity):
315 2*BINS(weight, capacity));
316 if (check_cut(p, vrp, new_cut))
317 num_cuts += cg_send_cut(new_cut);
318 }
319 if (verts[cur_vert].first->other_end != prev_vert){
320 prev_vert = cur_vert;
321 edge_data = verts[cur_vert].first->data;
322 cur_vert = verts[cur_vert].first->other_end;
323 }
324 else{
325 prev_vert = cur_vert;
326 edge_data = verts[cur_vert].last->data; /*This statement could
327 possibly be taken out to
328 speed things up a bit*/
329 cur_vert = verts[cur_vert].last->other_end;
330 }
331 }
332 edge_data->scanned = TRUE;
333
334 free ((char *) new_cut->coef);
335
336 while (cur_route_start->data->scanned){/*find the next edge leading out
337 of the depot which has not yet
338 been traversed to start the next
339 route*/
340 if (!(cur_route_start = cur_route_start->next_edge)) break;
341 }
342 }
343 for (cur_route_start = verts[0].first; cur_route_start;
344 cur_route_start = cur_route_start->next_edge)
345 cur_route_start->data->scanned = FALSE;
346
347 free_net(n);
348 FREE(new_cut);
349
350 return(num_cuts);
351 }
352
353 /*===========================================================================*/
354
check_cut(cg_prob * p,cg_vrp_spec * vrp,cut_data * cut)355 char check_cut(cg_prob *p, cg_vrp_spec *vrp, cut_data *cut)
356 {
357 network *n = vrp->n;
358 char *coef;
359 int v0, v1;
360 vertex *verts;
361 int vertnum;
362 double lhs = 0;
363 elist *cur_edge;
364 int i;
365
366 verts = n->verts;
367 vertnum = n->vertnum;
368
369 /*----------------------------------------------------------------------*\
370 | Here the cut is "unpacked" and checked for violation. Each cut is |
371 | stored as compactly as possible. The subtour elimination constraints |
372 | are stored as a vector of bits indicating which side of the cut each |
373 | node is on. If the cut is violated, it is sent back to the lp. |
374 | Otherwise, "touches" is incremented. "Touches" is a measure of the |
375 | effectiveness of a cut and indicates how long it has been since a |
376 | cut was useful |
377 \*----------------------------------------------------------------------*/
378 switch (cut->type){
379
380 case SUBTOUR_ELIM_SIDE:
381 coef = cut->coef;
382 for (lhs = 0, v0 = 0; v0<vertnum; v0++){
383 if (!(coef[v0 >> DELETE_POWER] & (1 << (v0 & DELETE_AND))))
384 continue;
385 for(cur_edge = verts[v0].first;cur_edge;cur_edge=cur_edge->next_edge){
386 v1 = cur_edge->other_end;
387 if (coef[v1 >> DELETE_POWER] & (1 << (v1 & DELETE_AND)))
388 lhs += cur_edge->data->weight;
389 }
390 }
391 return (lhs/2 > (double)(cut->rhs)+p->cur_sol.lpetol);
392
393 case SUBTOUR_ELIM_ACROSS:
394 coef = cut->coef;
395 for (lhs = 0, i = 0; i<p->cur_sol.xlength; i++){
396 v0 = vrp->edges[p->cur_sol.xind[i] << 1];
397 v1 = vrp->edges[(p->cur_sol.xind[i] << 1) + 1];
398 if ((coef[v0 >> DELETE_POWER] >> (v0 & DELETE_AND) & 1) ^
399 (coef[v1 >> DELETE_POWER] >> (v1 & DELETE_AND) & 1))
400 lhs += p->cur_sol.xval[i];
401 }
402 return (lhs < (double)(cut->rhs)-p->cur_sol.lpetol);
403
404 default:
405 printf("Cut types not recognized! \n\n");
406 return(FALSE);
407 }
408
409 return(FALSE);
410 }
411
412 /*========================================================================*/
413
user_pack_col(int * colind,int collen,col_data * col)414 void user_pack_col(int *colind, int collen, col_data *col)
415 {
416 col->size = collen*sizeof(int);
417 col->coef = (char *) calloc (col->size, sizeof(char));
418 memcpy(col->coef, colind, col->size);
419 }
420
421 /*========================================================================*/
422
user_free_decomp_data_structures(cg_prob * p,void ** user)423 void user_free_decomp_data_structures(cg_prob *p, void **user)
424 {
425 cg_vrp_spec *vrp = (cg_vrp_spec *)(*user);
426
427 free_net(vrp->n);
428
429 vrp->n = NULL;
430 }
431
432 /*===========================================================================*/
433
user_set_rhs(int varnum,double * rhs,int length,int * ind,double * val,void * user)434 char user_set_rhs(int varnum, double *rhs, int length, int *ind,
435 double *val, void *user)
436 {
437 return(FALSE);
438 }
439
440
441
442
443
444
445
446
447
448