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