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