1 #include <math.h>
2 #include <memory.h>
3 #include <stdlib.h>
4 
5 #include "BB_constants.h"
6 #include "BB_macros.h"
7 #include "decomp.h"
8 #include "my_decomp.h"
9 #include "vrp_macros.h"
10 #include "vrp_sym_cg.h"
11 #include "vrp_const.h"
12 #include "vrp_common_types.h"
13 #include "sym_proccomm.h"
14 #include "compute_cost.h"
15 #include "decomp_lower_bound.h"
16 #include "vrp_sym_dg.h"
17 #ifdef EXACT_LIFTING
18 #include "util.h"
19 #include "tinytsp.h"
20 #endif
21 
22 typedef struct DBL_NEIGHBOR{ /* a neighbor to a set of nodes */
23    int nbor;    /* the index of the neighbor */
24    int host;    /* the node in the set st. host-nbor edge is the cheapest */
25    double cost;    /* the cost of that cheapest edge */
26 }dbl_neighbor;
27 
28 /*===========================================================================*/
29 
30 #ifdef EXACT_LIFTING
31 
decomp_lower_bound(cg_vrp_spec * vrp,double * edge_costs,int * x,int adjust,int mult)32 double decomp_lower_bound(cg_vrp_spec *vrp, double *edge_costs, int *x,
33 			  int adjust, int mult)
34 {
35    int edgenum = (vrp->vertnum)*(vrp->vertnum-1)/2;
36    int *upper = (int *) calloc(edgenum, ISIZE);
37    int *lower = (int *) calloc(edgenum, ISIZE);
38    int i, j, k, rval;
39    double ub = (double)((MAXINT)/(vrp->vertnum+vrp->numroutes-1)), optval = 0;
40 
41 #ifndef NO_LIFTING
42    double *costs = (double *) calloc(edgenum, DSIZE);
43 
44    /*FIXME: Here, we should check whether the upper bound on the depot edges
45      really are 2.0 or whether they can be taken to be 1.0 */
46    for (i = 1, k = 0; i < vrp->vertnum; i++){
47       for (j = 0; j < i; j++){
48 	 if (edge_costs[k] == ub){
49 	    k++;
50 	 }else if (edge_costs[k] == -100000){
51 	    lower[k] = 1.0;
52 	    upper[k++] = (j == 0 ? 2.0 : 1.0);
53 	 }else{
54 	    upper[k] = (j == 0 ? 2.0 : 1.0);
55 	    costs[k] = edge_costs[k++];
56 	 }
57       }
58    }
59 
60    rval = CCtiny_bnc_msp(vrp->vertnum, edgenum, vrp->edges, costs, 0, lower,
61 			 upper, &ub, CC_TINYTSP_MINIMIZE, &optval, x, 0, 100,
62 			 vrp->numroutes);
63    FREE(upper);
64    FREE(lower);
65    FREE(costs);
66 #else
67 #ifdef COMPILE_IN_CG
68    lp_prob *lp = get_lp_ptr(NULL);
69    LPdata *lp_data2 = lp->lp_data;
70 
71    for (i = 0, k = 0; i < edgenum; i++){
72       if (k >= lp_data2->n || lp_data2->vars[k]->userind > i){
73 	 /*Not in the problem -- upper[i] = lower[i] = 0.0*/
74       }else{
75 	 upper[i] = lp_data2->ub[k];
76 	 lower[i] = lp_data2->lb[k++];
77       }
78    }
79 
80 #else
81 
82    for (i = 1, k = 0; i < vrp->vertnum; i++){
83       for (j = 0; j < i; j++){
84 	 upper[k++] = (j == 0 ? 2.0 : 1.0);
85       }
86    }
87 
88 #endif
89 
90    rval = CCtiny_bnc_msp(vrp->vertnum, edgenum, vrp->edges, edge_costs, 0,
91 			 lower, upper, &ub, CC_TINYTSP_MINIMIZE,
92 			 &optval, x, 0, 100, vrp->numroutes);
93    FREE(upper);
94    FREE(lower);
95 #endif
96 
97    return(rval ? MAXDOUBLE : optval);
98 }
99 
100 /*===========================================================================*/
101 
102 #else
103 
edgecompar(const void * edge1,const void * edge2)104 static int edgecompar(const void *edge1, const void *edge2)
105 {
106    return(((dbl_edge_data *)edge1)->cost-((dbl_edge_data *)edge2)->cost ?
107 	  (((dbl_edge_data *)edge1)->cost-((dbl_edge_data *)edge2)->cost)/
108 	  fabs(((dbl_edge_data *)edge1)->cost-((dbl_edge_data *)edge2)->cost):
109 	  0);
110 }
111 
112 /*===========================================================================*/
113 
decomp_lower_bound(cg_vrp_spec * vrp,double * edge_costs,int * x,int adjust,int mult)114 double decomp_lower_bound(cg_vrp_spec *vrp, double *edge_costs, int *x,
115 			  int adjust, int mult)
116 {
117   int *tree;
118   double bound, tree_cost;
119   int cur_node, vertnum = vrp->vertnum, numroutes = vrp->numroutes, i;
120   dbl_edge_data *depot_costs;
121 
122 
123   /*-------------------------------------------------------------------*\
124   | Calculate a k-degree-centre-tree with penalties lamda               |
125   \*-------------------------------------------------------------------*/
126 
127   tree = (int *) calloc(vertnum, sizeof(int));
128   depot_costs    = (dbl_edge_data *) calloc(vertnum-1, sizeof(dbl_edge_data));
129 
130   tree_cost = decomp_make_k_tree(vrp, edge_costs, tree, numroutes);
131 
132   /*-------------------------------------------------------------------*\
133   | Construct a sorted list of the cheapest edges adjacent to the depot |
134   \*-------------------------------------------------------------------*/
135 
136   for (cur_node = 1; cur_node < vertnum; cur_node++){
137      depot_costs[cur_node-1].cost =
138 	((edge_costs[INDEX(0, cur_node)] == -100000) ?
139 	 0 : edge_costs[INDEX(0, cur_node)]);
140      depot_costs[cur_node-1].v1 = cur_node;
141   }
142 
143   qsort(depot_costs, vertnum-1, sizeof(dbl_edge_data), edgecompar);
144 
145   for (bound = i = 0; i < numroutes; i++)
146      bound += depot_costs[i].cost; /* == -100000) ? 0 : depot_costs[i].cost;*/
147 
148   bound += tree_cost;
149 
150   FREE(tree);
151   FREE(depot_costs);
152 
153   return(bound + 100000.0 * ((double)adjust));
154 }
155 
156 /*--------------------------------------------------------------------------*\
157 | This routine creates a minimum k-degree-centre-tree based on the     |
158 | penalized costs. It first dreates a regular spanning tree and then either  |
159 | forces edges adjacent to the depot either in or out in order to make the   |
160 | degree of the depot correct. Edges are forced in and out by subtracting or |
161 | adding a constant to all the depot edge costs and forming a new minimum    |
162 | spanning tree.                                                             |
163 \*--------------------------------------------------------------------------*/
164 
decomp_make_k_tree(cg_vrp_spec * vrp,double * edge_costs,int * tree,int k)165 double decomp_make_k_tree(cg_vrp_spec *vrp, double *edge_costs, int *tree,
166 			  int k)
167 {
168   int nearnode, size;
169   int host, vertnum = vrp->vertnum, break_node = 0, new_depot_node = 0, i;
170   int depot_degree = 0, cur_node, prev_node, next_node, max_node = 0;
171   int mu = 0, next_mu, last = 0;
172   double cost = 0, max_cost;
173   int *intree = NULL;
174   dbl_neighbor *nbtree = NULL;
175 
176   while (TRUE){
177     intree = (int *) calloc (vertnum, sizeof(int));
178     nbtree = (dbl_neighbor *) calloc (vertnum, sizeof(dbl_neighbor));
179     cost = 0;
180     last = 0;
181     intree[0] = IN_TREE;
182     decomp_insert_edges(vrp, edge_costs, 0, nbtree, intree, &last, mu);
183 
184     /*-----------------------------------------------------------------------*\
185     | Calculate the minimum spanning tree by adding in the nearest node to the|
186     | current tree as long as it does not form a cycle.                       |
187     \*-----------------------------------------------------------------------*/
188 
189     for (size = 1; size < vertnum ; size++){
190       nearnode = decomp_closest(nbtree, intree, &last, &host);
191       intree[nearnode] = IN_TREE;
192       tree[nearnode] = host;
193       cost += edge_costs[INDEX(host, nearnode)];
194       decomp_insert_edges(vrp, edge_costs, nearnode, nbtree, intree, &last,
195 			  mu);
196     }
197 
198     /*----------------------------------------------------------------------*\
199     | Calculate the degree of the depot in the current tree                  |
200     \*----------------------------------------------------------------------*/
201 
202     for (depot_degree = 0, cur_node = 1; cur_node < vertnum; cur_node++){
203       if (!tree[cur_node])
204 	depot_degree++;
205     }
206 
207     /*-----------------------------------------------------------------------*\
208     | If the degree of the depot is as desired, then we are done. If it is too|
209     | small, then we can easily determine the next edge to add adjacent to the|
210     | depot in order to increase the degree of the depot. We add the edge that|
211     | increase the cost of the tree the least by determining which other edge |
212     | in the tree would be forced out. In this case, we don't need to         |
213     | recompute the tree from scratch. We simply make the appropriate switch. |
214     | If the degree is too large, we cannot                                   |
215     | compute the leaving edge so easily. Then we simply raise the cost of all|
216     | edges asjacent to the depot by an amount sufficient to force enough     |
217     | edges out of the solution. In this case, we do have to recompute the    |
218     | tree                                                                    |
219     \*-----------------------------------------------------------------------*/
220 
221     if (depot_degree == k) break;
222 
223     if (depot_degree < k){
224       while (depot_degree < k){
225 	next_mu = MAXINT;
226 	for (i = 1; i<vertnum; i++)
227 	  if (tree[i]){
228 	    max_cost = -MAXINT;
229 	    for (cur_node = i; tree[cur_node]; cur_node = tree[cur_node])
230 	      if ((cost = edge_costs[INDEX(tree[cur_node], cur_node)]) >
231 		  max_cost){
232 		max_cost = cost;
233 		max_node = cur_node;
234 	      }
235 	    if ((cost = edge_costs[INDEX(0, i)] - max_cost) < next_mu){
236 	      next_mu = cost;
237 	      new_depot_node = i;
238 	      break_node = max_node;
239 	    }
240 	  }
241 	for (prev_node = new_depot_node, cur_node = tree[new_depot_node],
242 	     next_node = tree[cur_node]; prev_node != break_node;
243 	     tree[cur_node] = prev_node, prev_node = cur_node,
244 	     cur_node = next_node, next_node = tree[next_node]);
245 
246 	tree[new_depot_node] = 0;
247 
248 	for (depot_degree = 0, cur_node = 1; cur_node < vertnum; cur_node++)
249 	  if (!tree[cur_node])
250 	    depot_degree++;
251 
252       }
253       for (cost = 0, cur_node = 1; cur_node < vertnum; cur_node++)
254 	cost += edge_costs[INDEX(cur_node, tree[cur_node])];
255 
256       break;
257     }
258     else{ /*depot_degree > k*/
259 
260       mu -= MAX(edge_costs[INDEX(0, 1)], 1);
261 
262       if (intree) free((char *) intree);
263       if (nbtree) free((char *) nbtree);
264     }
265   }
266 
267   free ((char *)intree);
268   free ((char *)nbtree);
269   return(cost);
270 }
271 
272 /*===========================================================================*/
273 
decomp_closest(dbl_neighbor * nbtree,int * intree,int * last,int * host)274 int decomp_closest(dbl_neighbor *nbtree, int *intree, int *last, int *host)
275 {
276   int closest_node;
277   int pos, ch;
278   double cost;
279   dbl_neighbor temp;
280 
281   /*-----------------------------------------------------------------------*\
282   | This routine deletes the item from the top of the binary tree where the |
283   | distances are stored and adjusts the tree accordingly                   |
284   \*-----------------------------------------------------------------------*/
285 
286   closest_node = nbtree[1].nbor;
287   *host = nbtree[1].host;
288   (void) memcpy ((char *)&temp, (char *)(nbtree+*last), sizeof(dbl_neighbor));
289   cost = nbtree[*last].cost;
290   --*last;
291   pos = 1;
292   while ((ch=2*pos) < *last){
293     if ((nbtree[ch].cost > nbtree[ch+1].cost)||
294 	((nbtree[ch].cost == nbtree[ch+1].cost) && !nbtree[ch+1].host))
295       ch++;
296     if (cost <= nbtree[ch].cost)
297       break;
298     intree[nbtree[ch].nbor] = pos;
299     (void) memcpy ((char *)(nbtree+pos),
300 		   (char *)(nbtree+ch), sizeof(dbl_neighbor));
301     pos = ch;
302   }
303   if (ch == *last){
304     if (cost > nbtree[ch].cost){
305       intree[nbtree[ch].nbor] = pos;
306       (void) memcpy ((char *)(nbtree+pos),
307 		     (char *)(nbtree+ch), sizeof(dbl_neighbor));
308       pos=ch;
309     }
310   }
311   intree[temp.nbor] = pos;
312   (void) memcpy ((char *)(nbtree+pos), (char *)&temp, sizeof(dbl_neighbor));
313   return(closest_node);
314 }
315 
316 /*===========================================================================*/
317 
decomp_insert_edges(cg_vrp_spec * vrp,double * edge_costs,int new_node,dbl_neighbor * nbtree,int * intree,int * last,int mu)318 void decomp_insert_edges(cg_vrp_spec *vrp, double *edge_costs, int new_node,
319 			 dbl_neighbor *nbtree, int *intree, int *last, int mu)
320 /*--------------------------------------------------------------------------*\
321 |  Scan through the edges incident to 'new_node' - the new node in the set.  |
322 |  If the other end 'i' is in the set, do nothing.                           |
323 |  If the other end is not in nbtree then insert it.                         |
324 |  Otherwise update its distance if necessary:                               |
325 |     If the previous closest point of the set to 'i' is closer then         |
326 |     'new_node' then we don't have to do anything, otherwise update.        |
327 |     (update: the min element is on the top of the tree                     |
328 |              Therefore the insertion and the update parts can be done      |
329 |              with the same code, not like in fi_insert_edges.)             |
330 \*--------------------------------------------------------------------------*/
331 {
332   double cost = 0, prevcost;
333   int pos = 0, ch;
334   int i;
335   int vertnum = vrp->vertnum;
336 
337   for (i=0; i<vertnum; i++){
338     if (intree[i] != IN_TREE){
339       cost = edge_costs[INDEX(new_node, i)] - (i ? 0:mu) - (new_node ? 0:mu);
340       if (intree[i] == NOT_NEIGHBOR){
341 	pos = ++(*last);
342 	prevcost = cost+1;
343       }else{
344 	prevcost = nbtree[pos = intree[i]].cost;
345       }
346       if (prevcost > cost){
347 	while ((ch=pos/2) != 0){
348 	  if ((nbtree[ch].cost < cost)||
349 	      ((nbtree[ch].cost == cost) && !nbtree[ch].host))
350 	    break;
351 	  intree[nbtree[ch].nbor] = pos;
352 	  (void) memcpy ((char *)(nbtree+pos),
353 			 (char *)(nbtree+ch), sizeof(dbl_neighbor));
354 	  pos = ch;
355 	}
356 	nbtree[pos].nbor = i;
357 	nbtree[pos].host = new_node;
358 	nbtree[pos].cost = cost;
359 	intree[i] = pos;
360       }
361     }
362   }
363 }
364 
365 /*--------------------------------------------------------------------------*\
366 | This routine computes the new penaltie for use in computing the lower bound|
367 | The penalties are based on the amount of violation of the degree           |
368 | constraints in the current lower bound.                                    |
369 \*--------------------------------------------------------------------------*/
370 
decomp_new_lamda(cg_vrp_spec * vrp,int upper_bound,int cur_bound,int * lamda,int numroutes,int * tree,dbl_edge_data * cur_edges,int alpha)371 int decomp_new_lamda(cg_vrp_spec *vrp, int upper_bound, int cur_bound,
372 		     int *lamda, int numroutes, int *tree,
373 		     dbl_edge_data *cur_edges, int alpha)
374 {
375   int denom = 0;
376   int cur_node1, cur_node2, vertnum = vrp->vertnum, i;
377   int *degrees;
378 
379   degrees = (int *) calloc (vertnum, sizeof(int));
380 
381   for (cur_node1 = 0; cur_node1 < vertnum; cur_node1++){
382     for (cur_node2 = 0; cur_node2 < vertnum; cur_node2++)
383       if ((cur_node1 != cur_node2) && (tree[cur_node2] == cur_node1))
384 	degrees[cur_node1]++;
385   }
386 
387   for (i = 0; i < numroutes; i++){
388     degrees[cur_edges[i].v0]++;
389     degrees[cur_edges[i].v1]++;
390   }
391 
392   for (cur_node1 = 0; cur_node1 < vertnum; cur_node1++)
393     denom += cur_node1 ? (degrees[cur_node1]-1)*(degrees[cur_node1]-1) :
394       (degrees[cur_node1]-2*numroutes)*(degrees[cur_node1]-2*numroutes);
395 
396   denom = (int) sqrt((double)denom);
397 
398   if (!denom) return(1);
399 
400   for (cur_node1 = 0; cur_node1 < vertnum; cur_node1++)
401     lamda[cur_node1] += (degrees[cur_node1] -
402 				    (cur_node1 ? 1: 2*numroutes));
403 
404   if (degrees) free((char *) degrees);
405 
406   return(0);
407 }
408 
409 #endif
410