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 /* the Vehicle Routing Problem and the Traveling Salesman Problem. */
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 <math.h>
20
21 /* VRP include files */
22 #include "compute_cost.h"
23 #include "vrp_macros.h"
24 #include "vrp_const.h"
25
26 /*===========================================================================*/
27
28 /*===========================================================================*\
29 * This file contains functions for computing costs.
30 \*===========================================================================*/
31
32 /*===========================================================================*\
33 * This function computes the cost of the edge from va to vb
34 \*===========================================================================*/
35
compute_icost(distances * dist,int va,int vb)36 int compute_icost(distances *dist, int va, int vb)
37 {
38 double q1, q2, q3, dx, dy, dz;
39 int cost = 0;
40
41 if (dist->wtype == _GEO){
42 q1 = cos( dist->coordy[va] - dist->coordy[vb] );
43 q2 = cos( dist->coordx[va] - dist->coordx[vb] );
44 q3 = cos( dist->coordx[va] + dist->coordx[vb] );
45 cost = (int) (RRR*acos(0.5*((1.0+q1)*q2-(1.0-q1)*q3))+1.0);
46 }
47 else{
48 dx = dist->coordx[va] - dist->coordx[vb];
49 dy = dist->coordy[va] - dist->coordy[vb];
50 switch (dist->wtype){
51 case _EUC_2D : cost = (int) floor( sqrt( dx*dx + dy*dy ) + 0.5);
52 break;
53 case _EUC_3D : dz = dist->coordz[va] - dist->coordz[vb];
54 cost = (int) floor( sqrt( dx*dx + dy*dy + dz*dz) + 0.5);
55 break;
56 case _MAX_2D : cost = (int) fabs(dx);
57 if (cost < fabs(dy)) cost = (int) fabs(dy);
58 break;
59 case _MAX_3D : dz = dist->coordz[va] - dist->coordz[vb];
60 cost = (int) fabs(dx);
61 if (cost < fabs(dy)) cost = (int) fabs(dy);
62 if (cost < fabs(dz)) cost = (int) fabs(dz);
63 break;
64 case _MAN_2D : cost = (int) floor( abs(dx)+abs(dy)+0.5 );
65 break;
66 case _MAN_3D : dz = dist->coordz[va] - dist->coordz[vb];
67 cost = (int) floor( abs(dx)+abs(dy)+abs(dz)+0.5 );
68 break;
69 case _CEIL_2D : cost = (int)ceil( sqrt( dx*dx + dy*dy ) + 0.5);
70 break;
71 case _ATT : cost = (int)( sqrt( (dx*dx + dy*dy ) / 10 ) + 1);
72 break;
73 }
74 }
75 return( cost );
76 }
77
78 /*===========================================================================*\
79 * This function computes the canonical tour and puts it into the field
80 * p->cur_tour. It adds the nodes to routes in order until capacity is
81 * exceeded, and then it starts a new route,
82 \*===========================================================================*/
83
canonical_tour(distances * dist,best_tours * cur_tour,int vertnum,int capacity,int * demand)84 void canonical_tour(distances *dist, best_tours *cur_tour, int vertnum,
85 int capacity, int *demand)
86 {
87 register int i, j = 1;
88 int weight = 0;
89 _node *tour = cur_tour->tour;
90
91 if (demand[1] > capacity){
92 fprintf(stderr, "Error: weight greater than truck capacity\n");
93 exit(1); /*check whether any of the weights exceed capacity*/
94 }
95
96 tour[0].next = 1;
97 tour[0].route = 0;
98
99 for ( i=1; i < vertnum-1; i++){
100 if (weight + demand[i] <= capacity){
101 weight += demand[i];
102 tour[i].next=i+1; /*keep adding customers to routes until */
103 tour[i].route=j; /*capacity is exceeded*/
104 }
105 else{
106 weight = demand[i]; /*start new route*/
107 if (weight > capacity){
108 fprintf(stderr, "Error: weight greater than truck capacity\n");
109 exit(1);
110 }
111 j++;
112 tour[i].next=i+1;
113 tour[i].route=j;
114 }
115 }
116 if (weight + demand[i] <= capacity){
117 tour[i].next=0;
118 tour[i].route=j; /*add the final customer to the route and */
119 } /* mark the next customer as customer as the*/
120 else{ /*depot or start a new route as necessary */
121 weight = demand[i];
122 if (weight > capacity){
123 fprintf(stderr, "Error: weight greater than truck capacity\n");
124 exit(1);
125 }
126 j++;
127 tour[i].next=0;
128 tour[i].route=j;
129 }
130
131 cur_tour->cost = compute_tour_cost (dist, tour);
132 cur_tour->numroutes = j;
133 }
134
135 /*===========================================================================*\
136 * This function computes the route information pertaining to a given
137 * tour. It just traces out the routes, counting the customers on each
138 * route. When it reaches a new route,
139 * it records the last cutomer on the previous route and the first
140 * customer on the current route, and also the cost of the previous
141 * route. It knows whether it has reached the end of a route by
142 * checking whether the next customer has the same route number as it
143 * does.
144 \*===========================================================================*/
145
route_calc(distances * dist,_node * tour,int numroutes,route_data * route_info,int * demand)146 int route_calc(distances *dist, _node *tour, int numroutes,
147 route_data *route_info, int *demand)
148 {
149 register int cur_node = 0;
150 register int cur_route = 1;
151 int cost = 0;
152
153 for (cur_route = 1; cur_route<=numroutes; cur_route++){
154 cur_node = tour[cur_node].next;
155 route_info[cur_route].numcust++;
156 route_info[cur_route].weight += demand[cur_node];
157 route_info[cur_route].cost = ICOST(dist, 0, cur_node);
158 route_info[cur_route].first = cur_node;
159 while (tour[cur_node].route == tour[tour[cur_node].next].route){
160 route_info[cur_route].cost += ICOST(dist, cur_node, tour[cur_node].next);
161 cur_node = tour[cur_node].next;
162 route_info[cur_route].numcust++;
163 route_info[cur_route].weight += demand[cur_node];
164 }
165 route_info[cur_route].cost += ICOST(dist, 0, cur_node);
166 route_info[cur_route].last = cur_node;
167 cost += route_info[cur_route].cost;
168 }
169 return(cost);
170 }
171
172 /*===========================================================================*\
173 * This function computes the cost of the tour held in
174 * p->cur_tour. At the end of each route, it automatically
175 * adds in the cost of returning to the depot and then
176 * travelling back to the next customer.
177 \*===========================================================================*/
178
compute_tour_cost(distances * dist,_node * tour)179 int compute_tour_cost(distances *dist, _node *tour)
180 {
181 int cost=0;
182 int v0, v1;
183
184 for ( v1 = tour[0].next, cost = ICOST(dist, 0, tour[0].next);;){
185 v1=tour[v0=v1].next;
186 if (tour[v0].route == tour[v1].route)
187 cost += ICOST(dist, v0, v1);
188 else if (v1 == 0){
189 cost += ICOST(dist, 0, v0);
190 break;
191 }
192 else{
193 cost += ICOST(dist, 0, v0);
194 cost += ICOST(dist, 0, v1);
195 }
196 }
197
198 return(cost);
199 }
200
ECOST(double * cost,int v0,int v1,int vertnum)201 double ECOST(double *cost, int v0, int v1, int vertnum)
202 {
203 return((v0 < vertnum && v1 < vertnum) ? (cost[INDEX(v0, v1)]):
204 ((v0 < vertnum && v0 > 0) ? (cost[INDEX(0, v0)]) :
205 ((v1 < vertnum && v1 > 0) ? (cost[INDEX(0, v1)]): DEPOT_PENALTY)));
206 }
207
ICOST(distances * dist,int v0,int v1)208 int ICOST(distances *dist, int v0, int v1)
209 {
210 return(dist->wtype==_EXPLICIT ? dist->cost[INDEX(v0,v1)] :
211 compute_icost(dist,v0,v1));
212 }
213
MCOST(distances * dist,int v0,int v1,int * lamda)214 int MCOST(distances *dist, int v0, int v1, int *lamda)
215 {
216 return(dist->wtype==_EXPLICIT ?
217 dist->cost[INDEX(v0,v1)]+lamda[v0]+lamda[v1] :
218 (compute_icost(dist,v0,v1)+lamda[v0]+lamda[v1]));
219 }
220
TCOST(distances * dist,int v0,int v1,int * lamda,int mu)221 int TCOST(distances *dist, int v0, int v1, int *lamda, int mu)
222 {
223 return(v0 ? MCOST(dist, v0, v1, lamda) : MCOST(dist, v0, v1, lamda) - mu);
224 }
225
226