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 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 
21 /* SYMPHONY include files */
22 /*__BEGIN_EXPERIMENTAL_SECTION__*/
23 #include "sym_master.h"
24 /*___END_EXPERIMENTAL_SECTION___*/
25 #include "sym_macros.h"
26 #include "sym_constants.h"
27 #include "sym_proccomm.h"
28 #include "sym_dg_params.h"
29 #include "sym_master_u.h"
30 
31 /* CNRP include files */
32 #include "cnrp_const.h"
33 #include "cnrp_types.h"
34 #include "cnrp_io.h"
35 #include "compute_cost.h"
36 #include "cnrp_master_functions.h"
37 #include "cnrp_dg_functions.h"
38 #include "cnrp_macros.h"
39 #include "small_graph.h"
40 #include "network.h"
41 #ifdef COMPILE_IN_TM
42 #ifdef COMPILE_IN_LP
43 #include "cnrp_lp.h"
44 #ifdef COMPILE_IN_CG
45 #include "cnrp_cg.h"
46 #endif
47 #ifdef COMPILE_IN_CP
48 #include "cnrp_cp.h"
49 #endif
50 #endif
51 #endif
52 
53 /*===========================================================================*/
54 
55 /*===========================================================================*\
56  * This file contains the user-written functions for the master process.
57 \*===========================================================================*/
58 
user_usage(void)59 void user_usage(void){
60          printf("master [ -HEP ] [ -S file ] [ -F file ] [ -B rule ]\n"
61 		"[ -V sel ] [ -K closest ] [ -N routes ] [ -C capacity ]\n"
62 		"[ -D level ] [ -M ] [ -X toggle ] [ -Y toggle ] \n"
63 		"[ -Z toggle ] [-G tau] \n"
64 		"\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n"
65 		"\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\n",
66 		"-H: help",
67 		"-E: use sparse edge set",
68 		"-D level: verbosity level for displaying LP solutions",
69 		"-P type: specify problem type",
70 		"-S file: load sparse graph from 'file'",
71 		"-F file: problem data is in 'file'",
72 		"-B i: which candidates to check in strong branching",
73 		"-V i: how to construct the base set of variables",
74 		"-K k: use 'k' closest edges to build sparse graph",
75 		"-N n: use 'n' routes",
76 		"-M  : use min cut subroutine",
77 		"-C c: use capacity 'c'",
78 		"-X t: toggles generation of X cuts",
79 		"-Y t: toggles generation of capacity cuts",
80 		"-Z t: toggles generation of tight capacity cuts",
81 		"-G t: set tau to 't'");
82 }
83 
84 /*===========================================================================*\
85  * Initialize user-defined data structures. In this case, I store all
86  * problem-specific data such as the location of the customers, edge costs,
87  * etc. in this data-structure.
88 \*===========================================================================*/
89 
user_initialize(void ** user)90 int user_initialize(void **user)
91 {
92    cnrp_problem *cnrp = (cnrp_problem *) calloc(1, sizeof(cnrp_problem));
93 
94    *user = cnrp;
95 
96    return(USER_SUCCESS);
97 }
98 
99 /*===========================================================================*/
100 
101 /*===========================================================================*\
102  * In this function, I set up the user parameters. The first step is to cast
103  * the void pointer in order to access my data. In the readparams() function,
104  * I read in parameters from the parameter file given on the command line.
105 \*===========================================================================*/
106 
user_readparams(void * user,char * filename,int argc,char ** argv)107 int user_readparams(void *user, char *filename, int argc, char **argv)
108 {
109    cnrp_problem *cnrp = (cnrp_problem *)user;
110    /*__BEGIN_EXPERIMENTAL_SECTION__*/
111 #if 0
112    p->par.lp_par.problem_type = INTEGER_PROBLEM;
113    strcpy(p->par.dg_par.source_path, "/home/tkr/BlackBox/DrawGraph/IGD_1.0/");
114 #endif
115    /*___END_EXPERIMENTAL_SECTION___*/
116 
117    cnrp_readparams(cnrp, filename, argc, argv);
118 
119    return(USER_SUCCESS);
120 }
121 
122 /*===========================================================================*/
123 
124 /*===========================================================================*\
125  * After I've read in the parameters, I can now read in the data file, whose
126  * name was given in the parameter file. This file contains instance data.
127 \*===========================================================================*/
128 
user_io(void * user)129 int user_io(void *user)
130 {
131    cnrp_problem *cnrp = (cnrp_problem *)user;
132 
133    cnrp_io(cnrp, cnrp->par.infile);
134 
135    if (cnrp->par.use_small_graph == LOAD_SMALL_GRAPH){
136       read_small_graph(cnrp);
137    }
138 
139    if (!cnrp->numroutes && cnrp->par.prob_type == VRP){
140       printf("\nError: Number of trucks not specified or computed "
141 	     "for VRP\n\n");
142       exit(1);
143    }
144 
145    if (cnrp->numroutes > 1){
146       printf("NUMBER OF TRUCKS: \t%i\n", cnrp->numroutes);
147       printf("TIGHTNESS: \t\t%.2f\n",
148 	     cnrp->demand[0]/(cnrp->capacity*(double)cnrp->numroutes));
149    }
150 
151    /* Selects the cheapest edges adjacent to each node for the base set */
152 
153    if (cnrp->par.use_small_graph == SAVE_SMALL_GRAPH){
154       if (!cnrp->g) make_small_graph(cnrp, 0);
155       save_small_graph(cnrp);
156    }else if (!cnrp->g){
157       make_small_graph(cnrp, 0);
158    }
159 
160    return(USER_SUCCESS);
161 }
162 
163 /*===========================================================================*/
164 
165 /*===========================================================================*\
166  * Here is where the heuristics are performed and an upper bound is calculated.
167  * An upper bound can also be specified in the parameter file. The
168  * other thing I do in this routine is build up a graph of the
169  * cheapest k edges adjacent to the each node plus any edges chosen
170  * during the heuristics to comprise my base set later.
171 \*===========================================================================*/
172 
user_start_heurs(void * user,double * ub,double * ub_estimate)173 int user_start_heurs(void *user, double *ub, double *ub_estimate)
174 {
175    cnrp_problem *cnrp = (cnrp_problem *)user;
176 
177    if (*ub > 0){
178       cnrp->cur_tour->cost = (int) (*ub);
179    }else{
180       cnrp->cur_tour->cost = MAXINT;
181    }
182 
183    cnrp->cur_tour->numroutes = cnrp->numroutes;
184 
185    if (cnrp->par.use_small_graph == LOAD_SMALL_GRAPH){
186       if (*ub <= 0 && cnrp->cur_tour->cost > 0)
187 	 *ub = (int)(cnrp->cur_tour->cost);
188       cnrp->numroutes = cnrp->cur_tour->numroutes;
189    }
190 
191 #if 0
192    if(cnrp->par.prob_tpye == BPP)
193       *ub = 1;
194 #endif
195 
196    if (*ub > 0 && !(cnrp->par.prob_type == BPP))
197       printf("INITIAL UPPER BOUND: \t%i\n\n", (int)(*ub));
198    else if (!(cnrp->par.prob_type == BPP))
199       printf("INITIAL UPPER BOUND: \tNone\n\n");
200    else
201       printf("\n\n");
202 
203    return(USER_SUCCESS);
204 }
205 
206 /*===========================================================================*/
207 
208 /*===========================================================================*\
209  * If graph drawing will be use, the user must initialize the drawing
210  * window here.
211 \*===========================================================================*/
212 
user_init_draw_graph(void * user,int dg_id)213 int user_init_draw_graph(void *user, int dg_id)
214 {
215 #ifndef WIN32   /* FIXME : None of this works in Windows */
216    cnrp_problem *cnrp = (cnrp_problem *)user;
217    int s_bufid;
218 
219    if (!(cnrp->posx && cnrp->posy)) return(USER_SUCCESS);
220    if ( (cnrp->dg_id = dg_id) ){
221       int i, zero = 0, eight = 0x08;
222       char node_place[MAX_NAME_LENGTH] = {"node_placement"};
223       char weight[5];
224       int *posx = cnrp->posx, *posy = cnrp->posy;
225       int minx=MAXINT, miny=MAXINT, maxx=-MAXINT, maxy=-MAXINT, xx, yy;
226       int width = 1000, height = 700;
227 #if 0
228       int width=p->par.dg_par.canvas_width, height=p->par.dg_par.canvas_height;
229 #endif
230       double mult;
231 
232       for (i = cnrp->vertnum - 1; i >= 0; i--){
233 	 if (posx[i] < minx) minx = posx[i];
234 	 if (posx[i] > maxx) maxx = posx[i];
235 	 if (posy[i] < miny) miny = posy[i];
236 	 if (posy[i] > maxy) maxy = posy[i];
237       }
238       xx = maxx - minx;
239       yy = maxy - miny;
240       mult = (int) MIN((width - 20.0)/xx, (height-20.0)/yy);
241       width = (int) (xx * mult + 30);
242       height = (int) (yy * mult + 30);
243       for (i = cnrp->vertnum-1; i >= 0; i--){
244 	 posx[i] = (int) ((posx[i] - minx) * mult + 10);
245 	 posy[i] = (int) ((maxy - posy[i]) * mult + 10);
246       }
247 
248       init_window(dg_id, node_place, width, height);
249       /* Now pack the placement of the nodes of the graph */
250       s_bufid = init_send(DataInPlace);
251       send_str(node_place);
252       send_int_array(&cnrp->vertnum, 1);
253       for (i = 0; i < cnrp->vertnum; i++){
254 	 send_int_array(&i, 1);
255 	 send_int_array(posx + i, 1);
256 	 send_int_array(posy + i, 1);
257 	 send_int_array(&eight, 1);
258 	 sprintf(weight, "%i", (int)(cnrp->demand[i]));
259 	 send_str(weight);
260       }
261       /* No edges are passed to the default graph */
262       send_int_array(&zero, 1);
263       send_msg(dg_id, CTOI_SET_GRAPH);
264       freebuf(s_bufid);
265 
266       display_graph(dg_id, node_place);
267    }
268 #endif
269 
270    return(USER_SUCCESS);
271 }
272 
273 /*===========================================================================*/
274 
275 /*===========================================================================*\
276  * In this routine, I build the initial edge set for the root. There are
277  * several things going on here. First, there is a user-defined parameter
278  * defining whether or not to just go ahead and add all variables to the
279  * problem up front (cnrp->par.add_all_edges). Currently, this seems to be the
280  * best option since the problems are small anyway. Further, I am doing some
281  * preprocessing here by eliminating edges for which the sum of the demands of
282  * their endpoints is greater than the capacity since these edges cannot
283  * be in any feasible solution.
284  *
285  * Notice that there are several options programmed for which set
286  * of edges should be in the base set. The
287  * base constraints are just the degree constraints from the IP
288  * formulation. These do not have to be specified explicitly, just the
289  * number of them given.
290 \*===========================================================================*/
291 
user_initialize_root_node(void * user,int * basevarnum,int ** basevars,int * basecutnum,int * extravarnum,int ** extravars,char * obj_sense,double * obj_offset,char *** colnames,int * colgen_strat)292 int user_initialize_root_node(void *user, int *basevarnum, int **basevars,
293 			      int *basecutnum, int *extravarnum,
294 			      int **extravars, char *obj_sense,
295 			      double *obj_offset, char ***colnames,
296 			      int *colgen_strat)
297 {
298    cnrp_problem *cnrp = (cnrp_problem *)user;
299 
300    *basevarnum = cnrp->basevarnum;
301    *basevars = cnrp->basevars;
302    *extravarnum = cnrp->extravarnum;
303    *extravars = cnrp->extravars;
304    *basecutnum = cnrp->basecutnum;
305 
306    if (!cnrp->par.colgen_strat[0]){
307       if (cnrp->par.add_all_edges ||
308 	  cnrp->par.base_variable_selection == SOME_ARE_BASE){
309 	 colgen_strat[0]=(FATHOM__DO_NOT_GENERATE_COLS__DISCARD |
310 			  BEFORE_BRANCH__DO_NOT_GENERATE_COLS);
311       }else{
312 	 colgen_strat[0] = (FATHOM__DO_NOT_GENERATE_COLS__SEND  |
313 			    BEFORE_BRANCH__DO_NOT_GENERATE_COLS);
314       }
315    }else{
316       colgen_strat[0] = cnrp->par.colgen_strat[0];
317    }
318    if (!cnrp->par.colgen_strat[1]){
319       if (cnrp->par.add_all_edges ||
320 	  cnrp->par.base_variable_selection == SOME_ARE_BASE){
321 	 colgen_strat[1]=(FATHOM__DO_NOT_GENERATE_COLS__DISCARD |
322 			  BEFORE_BRANCH__DO_NOT_GENERATE_COLS);
323       }else{
324 	 colgen_strat[1] = (FATHOM__GENERATE_COLS__RESOLVE  |
325 			    BEFORE_BRANCH__DO_NOT_GENERATE_COLS);
326       }
327    }else{
328       colgen_strat[1] = cnrp->par.colgen_strat[1];
329    }
330 
331    return(USER_SUCCESS);
332 }
333 
334 /*===========================================================================*/
335 
336 /*===========================================================================*\
337  * In my case, a feasible solution is specified most compactly by
338  * essentially a permutation of the customers along with routes numbers,
339  * specifying the order of the customers on their routes. This is just
340  * sent as a character array which then gets cast to an array of
341  * structures, one for each customers specifying the route number and
342  * the next customer on the route.
343 \*===========================================================================*/
344 
user_receive_feasible_solution(void * user,int msgtag,double cost,int numvars,int * indices,double * values)345 int user_receive_feasible_solution(void *user, int msgtag, double cost,
346 				   int numvars, int *indices, double *values)
347 {
348    cnrp_problem *cnrp = (cnrp_problem *)user;
349 
350    if (cnrp->par.prob_type == TSP || cnrp->par.prob_type == VRP ||
351        cnrp->par.prob_type == BPP)
352       receive_char_array((char *)cnrp->cur_tour->tour,
353 			 cnrp->vertnum*sizeof(_node));
354    else
355       receive_int_array(cnrp->cur_sol_tree, cnrp->vertnum);
356 
357    return(USER_SUCCESS);
358 }
359 
360 /*===========================================================================*/
361 
362 /*===========================================================================*\
363  * Here, we send the necessary data to the LP process. Notice that
364  * there are two cases to deal with. If the LP or the TM are running
365  * as separate processes, then we have to send the data by
366  * message-passing. Otherwise, we can allocate the user-defined LP data
367  * structure here and simply copy the necessary information. This is the
368  * only place the user has to sorry about this distinction between
369  * configurations.
370 \*===========================================================================*/
371 
user_send_lp_data(void * user,void ** user_lp)372 int user_send_lp_data(void *user, void **user_lp)
373 {
374    cnrp_problem *cnrp = (cnrp_problem *)user;
375 
376 #if defined(COMPILE_IN_TM) && defined(COMPILE_IN_LP)
377    /* This is the case when we are copying data directly because
378       the LP is not running separately. This code should be virtually
379       identical to that of user_receive_lp_data() in the LP process.*/
380 
381    cnrp_spec *cnrp_lp = (cnrp_spec *) calloc(1, sizeof(cnrp_spec));
382    int zero_varnum = cnrp->zero_varnum;
383    int *zero_vars = cnrp->zero_vars;
384    int vertnum, i, j, k, l;
385 
386    *user_lp = (void *)cnrp_lp;
387 
388    cnrp_lp->par = cnrp->lp_par;
389    cnrp_lp->window = cnrp->dg_id;
390    cnrp_lp->numroutes = cnrp->numroutes;
391    vertnum = cnrp_lp->vertnum = cnrp->vertnum;
392    cnrp_lp->edges = cnrp->edges;
393    cnrp_lp->demand = cnrp->demand;
394    cnrp_lp->capacity = cnrp->capacity;
395    cnrp_lp->costs = cnrp->dist.cost;
396    cnrp_lp->utopia_fixed = cnrp->utopia_fixed;
397    cnrp_lp->utopia_variable = cnrp->utopia_variable;
398    cnrp_lp->variable_cost = cnrp_lp->fixed_cost = MAXDOUBLE;
399    cnrp_lp->ub = cnrp->ub;
400 
401    if (cnrp->par.prob_type == VRP || cnrp->par.prob_type == TSP ||
402        cnrp->par.prob_type == BPP){
403       cnrp_lp->cur_sol = (_node *) calloc (cnrp->vertnum, sizeof(_node));
404    }else{
405       cnrp_lp->cur_sol_tree = (int *) calloc (cnrp->vertnum - 1, ISIZE);
406    }
407 /*__BEGIN_EXPERIMENTAL_SECTION__*/
408    if (cnrp_lp->window){
409       copy_node_set(cnrp_lp->window, TRUE, (char *)"Weighted solution");
410       copy_node_set(cnrp_lp->window, TRUE, (char *)"Flow solution");
411    }
412 /*___END_EXPERIMENTAL_SECTION___*/
413 
414 #else
415    /* Here, we send that data using message passing and the rest is
416       done in user_receive_lp_data() in the LP process */
417 
418    send_char_array((char *)(&cnrp->lp_par), sizeof(cnrp_lp_params));
419    send_int_array(&cnrp->dg_id, 1);
420    send_int_array(&cnrp->numroutes, 1);
421    send_int_array(&cnrp->vertnum, 1);
422    send_dbl_array(cnrp->demand, cnrp->vertnum);
423    send_dbl_array(&cnrp->capacity, 1);
424    send_int_array(cnrp->dist.cost, cnrp->edgenum);
425    send_int_array(&cnrp->zero_varnum, 1);
426    if (cnrp->zero_varnum){
427       send_int_array(cnrp->zero_vars, cnrp->zero_varnum);
428    }
429    send_dbl_array(&cnrp->utopia_fixed, 1);
430    send_dbl_array(&cnrp->utopia_variable, 1);
431    send_dbl_array(&cnrp->ub, 1);
432 #endif
433 
434    return(USER_SUCCESS);
435 }
436 
437 /*===========================================================================*/
438 
439 /*===========================================================================*\
440  * Here, we send the necessary data to the CG process. Notice that
441  * there are two cases to deal with. If the CG, LP, or the TM are running
442  * as separate processes, then we have to send the data by
443  * message-passing. Otherwise, we can allocate the user-defined LP data
444  * structure here and simply copy the necessary information. This is the
445  * only place the user has to sorry about this distinction between
446  * configurations.
447 \*===========================================================================*/
448 
user_send_cg_data(void * user,void ** user_cg)449 int user_send_cg_data(void *user, void **user_cg)
450 {
451    cnrp_problem *cnrp = (cnrp_problem *)user;
452 
453 #if defined(COMPILE_IN_TM) && defined(COMPILE_IN_LP) && defined (COMPILE_IN_CG)
454    /* This is is the case when we are copying data directly because
455       the CG is not running separately. This code should be virtually
456       identical to that of user_receive_cg_data() in the CG process.*/
457 
458    cg_cnrp_spec *cnrp_cg = (cg_cnrp_spec *) malloc (sizeof(cg_cnrp_spec));
459    int edgenum, vertnum, i, j, k;
460 
461    *user_cg = (void *)cnrp_cg;
462 
463    cnrp_cg->par = cnrp->cg_par;
464    cnrp_cg->numroutes = cnrp->numroutes;
465    vertnum = cnrp_cg->vertnum = cnrp->vertnum;
466    cnrp_cg->demand = cnrp->demand;
467    cnrp_cg->capacity = cnrp->capacity;
468    cnrp_cg->dg_id = cnrp->dg_id;
469 
470    edgenum = cnrp->vertnum*(cnrp->vertnum-1)/2;
471 
472    cnrp_cg->in_set = (char *) calloc(cnrp->vertnum, sizeof(char));
473    cnrp_cg->ref = (int *) malloc(cnrp->vertnum*sizeof(int));
474    cnrp_cg->new_demand = (double *) malloc(cnrp->vertnum*sizeof(double));
475    cnrp_cg->cut_val = (double *) calloc(cnrp->vertnum, sizeof(double));
476    cnrp_cg->cut_list = (char *) malloc(((cnrp->vertnum >> DELETE_POWER)+1)*
477 				   (cnrp->cg_par.max_num_cuts_in_shrink + 1)*
478 				   sizeof(char));
479 
480    cnrp_cg->edges = (int *) calloc (2*edgenum, sizeof(int));
481 
482    /*create the edge list (we assume a complete graph)*/
483    for (i = 1, k = 0; i < vertnum; i++){
484       for (j = 0; j < i; j++){
485 	 cnrp_cg->edges[2*k] = j;
486 	 cnrp_cg->edges[2*k+1] = i;
487 	 k++;
488       }
489    }
490 
491 #ifdef CHECK_CUT_VALIDITY
492    if ((cnrp_cg->feas_sol_size = cnrp->feas_sol_size)){
493       cnrp_cg->feas_sol = cnrp->feas_sol;
494    }
495 #endif
496 #else
497    /* Here, we send that data using message passing and the rest is
498       done in user_receive_cg_data() in the CG process */
499 
500    send_char_array((char *)&cnrp->cg_par, sizeof(cnrp_cg_params));
501    send_int_array(&cnrp->dg_id, 1);
502    send_int_array(&cnrp->numroutes, 1);
503    send_int_array(&cnrp->vertnum, 1);
504    send_dbl_array(cnrp->demand, cnrp->vertnum);
505    send_dbl_array(&cnrp->capacity, 1);
506 #ifdef CHECK_CUT_VALIDITY
507    send_int_array(&cnrp->feas_sol_size, 1);
508    if (cnrp->feas_sol_size){
509       send_int_array(cnrp->feas_sol, cnrp->feas_sol_size);
510    }
511 #endif
512 #endif
513 
514    return(USER_SUCCESS);
515 }
516 
517 /*===========================================================================*/
518 
519 /*===========================================================================*\
520  * Here, we send the necessary data to the CP process. Notice that
521  * there are two cases to deal with. If the CP, LP, or the TM are running
522  * as separate processes, then we have to send the data by
523  * message-passing. Otherwise, we can allocate the user-defined LP data
524  * structure here and simply copy the necessary information. This is the
525  * only place the user has to sorry about this distinction between
526  * configurations.
527 \*===========================================================================*/
528 
user_send_cp_data(void * user,void ** user_cp)529 int user_send_cp_data(void *user, void **user_cp)
530 {
531    cnrp_problem *cnrp = (cnrp_problem *)user;
532 
533 #if defined(COMPILE_IN_TM) && defined(COMPILE_IN_LP) && defined (COMPILE_IN_CP)
534    /* This is is the case when we are copying data directly because
535       the LP is not running separately. This code should be virtually
536       identical to that of user_receive_cp_data() in the CP process.*/
537 
538    cnrp_spec_cp *cnrp_cp = (cnrp_spec_cp *) malloc (sizeof(cnrp_spec_cp));
539    int i, j, k;
540 
541    cnrp_cp->par = cnrp->cp_par;
542    cnrp_cp->vertnum = cnrp->vertnum;
543    cnrp_cp->capacity = cnrp->capacity;
544    cnrp_cp->demand = (double *) malloc(cnrp->vertnum * DSIZE);
545    memcpy((char *)cnrp_cp->demand, (char *) cnrp->demand, cnrp->vertnum * DSIZE);
546 
547    *user_cp = (void *)cnrp_cp;
548 
549    cnrp_cp->edgenum =
550       cnrp_cp->vertnum*(cnrp_cp->vertnum-1)/2 + cnrp_cp->vertnum-1;
551    cnrp_cp->edges = (int *) calloc ((int)2*cnrp_cp->edgenum, sizeof(int));
552 
553    /* create the edge list (we assume a complete graph) */
554    for (i = 1, k = 0; i < cnrp_cp->vertnum; i++){
555       for (j = 0; j < i; j++){
556 	 cnrp_cp->edges[2*k] = j;
557 	 cnrp_cp->edges[2*k+1] = i;
558 	 k++;
559       }
560    }
561 
562    /* now add the duplicate copies of the depot edges to allow for
563       routes with one customer */
564    for (i = 1; i < cnrp_cp->vertnum; i++){
565       cnrp_cp->edges[2*k] = 0;
566       cnrp_cp->edges[2*k+1] = i;
567       k++;
568    }
569 #else
570    /* Here, we send that data using message passing and the rest is
571       done in user_receive_cp_data() in the CP process */
572 
573    send_int_array(&cnrp->vertnum, 1);
574    send_dbl_array(&cnrp->capacity, 1);
575    send_dbl_array(cnrp->demand, cnrp->vertnum);
576 
577 #endif
578 
579    return(USER_SUCCESS);
580 }
581 
582 /*__BEGIN_EXPERIMENTAL_SECTION__*/
583 /*===========================================================================*/
584 
user_send_sp_data(void * user)585 int user_send_sp_data(void *user)
586 {
587    return(USER_SUCCESS);
588 }
589 
590 /*___END_EXPERIMENTAL_SECTION___*/
591 /*===========================================================================*/
592 
593 /*===========================================================================*\
594  * Generally, this function is not needed but you might find some use
595  * for it. Someone did :).
596 \*===========================================================================*/
597 
user_process_own_messages(void * user,int msgtag)598 int user_process_own_messages(void *user, int msgtag)
599 {
600    return(USER_DEFAULT);
601 }
602 
603 /*===========================================================================*/
604 
605 /*===========================================================================*\
606  * This is the user's chance to display the solution in whatever
607  * manner desired. In my case, I can display a text version, which is
608  * just a list of the customers on each route, or use the interactive
609  * Graph Drawing application to graphically display the solution.
610 \*===========================================================================*/
611 
user_display_solution(void * user,double lpetol,int varnum,int * indices,double * values,double objval)612 int user_display_solution(void *user, double lpetol, int varnum, int *indices,
613 			  double *values, double objval)
614 {
615    cnrp_problem *cnrp = (cnrp_problem *)user;
616    _node *tour = cnrp->cur_tour->tour;
617    int *tree = cnrp->cur_sol_tree, node, prev_node;
618    int cur_vert = 0, prev_vert = 0, cur_route, i, count;
619    elist *cur_route_start = NULL;
620    edge *edge_data;
621    vertex *verts;
622    double fixed_cost = 0.0, variable_cost = 0.0;
623    int window = cnrp->dg_id;
624    int vertnum = cnrp->vertnum, v0, v1;
625    int total_edgenum =  vertnum*(vertnum-1)/2;
626    network *n;
627 
628    /* FIXME: This is UGLY! */
629 #if (defined(MULTI_CRITERIA) && defined(FIND_NONDOMINATED_SOLUTIONS)) && \
630    (defined(COMPILE_IN_TM) && defined(COMPILE_IN_LP)) && 0
631 
632    problem *p = get_problem_ptr(FALSE);
633    cnrp_spec *cnrp_lp = (cnrp_spec *) p->tm->lpp[0]->user;
634 
635    cnrp->fixed_cost = cnrp_lp->fixed_cost;
636    cnrp->variable_cost = cnrp_lp->variable_cost;
637 
638    tour = cnrp_lp->cur_sol;
639    tree = cnrp_lp->cur_sol_tree;
640    printf("\nSolution Found:\n");
641 #ifdef ADD_FLOW_VARS
642    printf("Solution Fixed Cost: %.1f\n", cnrp->fixed_cost);
643    printf("Solution Variable Cost: %.1f\n", cnrp->variable_cost);
644 #else
645    printf("Solution Cost: %.0f\n", fixed_cost);
646 #endif
647 #else
648    printf("\nSolution Found:\n");
649 #endif
650 
651 #if 0
652    if (tour){
653       node = tour[0].next;
654       if (tour[0].route == 1)
655 	 printf("\n0 ");
656       while (node != 0){
657 	 if (tour[prev_node].route != tour[node].route){
658 	    printf("\nRoute #%i: ", tour[node].route);
659 	    count = 0;
660 	 }
661 	 printf("%i ", node);
662 	 count++;
663 	 if (count > 15){
664 	    printf("\n");
665 	    count = 0;
666 	 }
667 	 prev_node = node;
668 	 node = tour[node].next;
669       }
670       printf("\n\n");
671 
672       if (window){
673 	 char name[MAX_NAME_LENGTH] = {"feas_solution"};
674 	 disp_vrp_tour(window, TRUE, name, tour, cnrp->vertnum,
675 			cnrp->numroutes, CTOI_WAIT_FOR_CLICK_AND_REPORT);
676       }
677       return(USER_SUCCESS);
678    }
679 
680    if (tree){
681       printf("Edge List:\n");
682       for (i = 0; i < vertnum - 1; i++){
683 	 BOTH_ENDS(tree[i], &v0, &v1);
684 	 printf("%i %i\n", v1, v0);
685       }
686       printf("\n\n");
687 
688       if (window){
689 	 char name[MAX_NAME_LENGTH] = {"feas_solution"};
690 	 copy_node_set(window, TRUE, name);
691 	 draw_edge_set_from_userind(window, name, vertnum - 1, tree);
692 	 display_graph(window, name);
693 	 wait_for_click(window, name, CTOI_WAIT_FOR_CLICK_NO_REPORT);
694       }
695       return(USER_SUCCESS);
696    }
697 #endif
698 
699    /*Otherwise, construct the solution from scratch*/
700 
701 #ifdef ADD_FLOW_VARS
702    n = create_flow_net(indices, values, varnum, lpetol, cnrp->edges,
703 		       cnrp->demand, vertnum);
704 #else
705    n = create_net(indices, values, varnum, lpetol, cnrp->edges, cnrp->demand,
706 		  vertnum);
707 #endif
708 
709    for (i = 0; i < n->edgenum; i++){
710       if (n->edges[i].weight > 1 - lpetol){
711 	 fixed_cost += cnrp->dist.cost[INDEX(n->edges[i].v0, n->edges[i].v1)];
712       }
713 #ifdef ADD_FLOW_VARS
714       variable_cost += (n->edges[i].flow1+n->edges[i].flow2)*
715 	 cnrp->dist.cost[INDEX(n->edges[i].v0, n->edges[i].v1)];
716 #endif
717    }
718    cnrp->fixed_cost = fixed_cost;
719    cnrp->variable_cost = variable_cost;
720 #if defined(ADD_FLOW_VARS) && defined(MULTI_CRITERIA)
721    printf("Solution Fixed Cost: %.1f\n", fixed_cost);
722    printf("Solution Variable Cost: %.1f\n", variable_cost);
723 #else
724    printf("Solution Cost: %.0f\n", fixed_cost);
725 #endif
726 
727    if (cnrp->par.prob_type == TSP || cnrp->par.prob_type == VRP ||
728        cnrp->par.prob_type == BPP){
729 
730       verts = n->verts;
731 
732      /*construct the tour corresponding to this solution vector*/
733       for (cur_route_start = verts[0].first, cur_route = 1,
734 	      edge_data = cur_route_start->data; cur_route <= cnrp->numroutes;
735 	   cur_route++){
736 	 edge_data = cur_route_start->data;
737 	 edge_data->scanned = TRUE;
738 	 cur_vert = edge_data->v1;
739 	 tour[prev_vert].next = cur_vert;
740 	 tour[cur_vert].route = cur_route;
741 	 prev_vert = 0;
742 	 while (cur_vert){
743 	    if (verts[cur_vert].first->other_end != prev_vert){
744 	       prev_vert = cur_vert;
745 	       edge_data = verts[cur_vert].first->data;
746 	       cur_vert = verts[cur_vert].first->other_end;
747 	    }
748 	    else{
749 	       prev_vert = cur_vert;
750 	       edge_data = verts[cur_vert].last->data; /*This statement
751 							 could possibly
752 							 be taken out to speed
753 							 things up a bit*/
754 	       cur_vert = verts[cur_vert].last->other_end;
755 	    }
756 	    tour[prev_vert].next = cur_vert;
757 	    tour[cur_vert].route = cur_route;
758 	 }
759 	 edge_data->scanned = TRUE;
760 
761 	 while (cur_route_start->data->scanned){
762 	    if (!(cur_route_start = cur_route_start->next_edge)) break;
763 	 }
764       }
765 
766       /* Display the solution */
767 
768       cur_vert = tour[0].next;
769 
770       if (tour[0].route == 1)
771 	 printf("\n0 ");
772       while (cur_vert != 0){
773 	 if (tour[prev_vert].route != tour[cur_vert].route){
774 	    printf("\nRoute #%i: ", tour[cur_vert].route);
775 	    count = 0;
776 	 }
777 	 printf("%i ", cur_vert);
778 	 count++;
779 	 if (count > 15){
780 	    printf("\n");
781 	    count = 0;
782 	 }
783 	 prev_vert = cur_vert;
784 	 cur_vert = tour[cur_vert].next;
785       }
786       printf("\n");
787    }else{
788 
789       for (i = 0; i < n->edgenum; i++){
790 	 cnrp->cur_sol_tree[i] = INDEX(n->edges[i].v0, n->edges[i].v1);
791       }
792 
793       /* Display the solution */
794 
795       for (i = 0; i < n->edgenum; i++){
796 	 printf("%i %i\n", n->edges[i].v0, n->edges[i].v1);
797       }
798       printf("\n");
799    }
800    free_net(n);
801 
802    return(USER_SUCCESS);
803 }
804 
805 /*===========================================================================*/
806 
807 /*===========================================================================*\
808  * This is a debugging feature which might
809  * allow you to find out why a known feasible solution is being cut off.
810 \*===========================================================================*/
811 
user_send_feas_sol(void * user,int * feas_sol_size,int ** feas_sol)812 int user_send_feas_sol(void *user, int *feas_sol_size, int **feas_sol)
813 {
814 #ifdef TRACE_PATH
815    cnrp_problem *cnrp = (cnrp_problem *)user;
816 
817    *feas_sol_size = cnrp->feas_sol_size;
818    *feas_sol = cnrp->feas_sol;
819 #endif
820    return(USER_SUCCESS);
821 }
822 
823 /*===========================================================================*/
824 
825 /*===========================================================================*\
826  * This function frees everything.
827 \*===========================================================================*/
828 
user_free_master(void ** user)829 int user_free_master(void **user)
830 {
831    cnrp_problem *cnrp = (cnrp_problem *)(*user);
832 
833    if (cnrp->cur_tour){
834       FREE(cnrp->cur_tour->tour);
835       FREE(cnrp->cur_tour->route_info);
836       FREE(cnrp->cur_tour);
837    }
838    FREE(cnrp->cur_sol_tree);
839    FREE(cnrp->posy);
840    FREE(cnrp->posx);
841    FREE(cnrp->dist.coordx);
842    FREE(cnrp->dist.coordy);
843    FREE(cnrp->dist.coordz);
844    FREE(cnrp->dist.cost);
845    FREE(cnrp->edges);
846    FREE(cnrp->demand);
847    if (cnrp->g){
848       FREE(cnrp->g->edges);
849       FREE(cnrp->g);
850    }
851 #ifdef CHECK_CUT_VALIDITY
852    FREE(cnrp->feas_sol);
853 #endif
854    FREE(cnrp->zero_vars);
855    FREE(cnrp);
856 
857    return(USER_SUCCESS);
858 }
859 /*===========================================================================*/
860 
861 /*===========================================================================*\
862  * This function is used to lift the user created cuts during warm starting *
863 \*===========================================================================*/
864 
user_ws_update_cuts(void * user,int * size,char ** coef,double * rhs,char * sense,char type,int new_col_num,int change_type)865 int user_ws_update_cuts (void *user, int *size, char **coef, double * rhs,
866 			 char *sense, char type, int new_col_num,
867 			 int change_type)
868 {
869    return(USER_DEFAULT);
870 }
871 
872 /*===========================================================================*/
873 
874 
875 
876 
877 
878 
879 
880