map01bf@255
|
1 /*
|
map01bf@255
|
2 emd.c
|
map01bf@255
|
3
|
map01bf@255
|
4 Last update: 3/14/98
|
map01bf@255
|
5
|
map01bf@255
|
6 An implementation of the Earth Movers Distance.
|
map01bf@255
|
7 Based of the solution for the Transportation problem as described in
|
map01bf@255
|
8 "Introduction to Mathematical Programming" by F. S. Hillier and
|
map01bf@255
|
9 G. J. Lieberman, McGraw-Hill, 1990.
|
map01bf@255
|
10
|
map01bf@255
|
11 Copyright (C) 1998 Yossi Rubner
|
map01bf@255
|
12 Computer Science Department, Stanford University
|
map01bf@255
|
13 E-Mail: rubner@cs.stanford.edu URL: http://vision.stanford.edu/~rubner
|
map01bf@255
|
14 */
|
map01bf@255
|
15
|
map01bf@255
|
16 #include <stdio.h>
|
map01bf@255
|
17 #include <stdlib.h>
|
map01bf@255
|
18 #include <math.h>
|
map01bf@255
|
19
|
map01bf@255
|
20 #include "emd.h"
|
map01bf@255
|
21
|
map01bf@255
|
22 #define DEBUG_LEVEL 0
|
map01bf@255
|
23 /*
|
map01bf@255
|
24 DEBUG_LEVEL:
|
map01bf@255
|
25 0 = NO MESSAGES
|
map01bf@255
|
26 1 = PRINT THE NUMBER OF ITERATIONS AND THE FINAL RESULT
|
map01bf@255
|
27 2 = PRINT THE RESULT AFTER EVERY ITERATION
|
map01bf@255
|
28 3 = PRINT ALSO THE FLOW AFTER EVERY ITERATION
|
map01bf@255
|
29 4 = PRINT A LOT OF INFORMATION (PROBABLY USEFUL ONLY FOR THE AUTHOR)
|
map01bf@255
|
30 */
|
map01bf@255
|
31
|
map01bf@255
|
32
|
map01bf@255
|
33 #define MAX_SIG_SIZE1 (MAX_SIG_SIZE+1) /* FOR THE POSIBLE DUMMY FEATURE */
|
map01bf@255
|
34
|
map01bf@255
|
35 /* NEW TYPES DEFINITION */
|
map01bf@255
|
36
|
map01bf@255
|
37 /* node1_t IS USED FOR SINGLE-LINKED LISTS */
|
map01bf@255
|
38 typedef struct node1_t {
|
map01bf@255
|
39 int i;
|
map01bf@255
|
40 double val;
|
map01bf@255
|
41 struct node1_t *Next;
|
map01bf@255
|
42 } node1_t;
|
map01bf@255
|
43
|
map01bf@255
|
44 /* node1_t IS USED FOR DOUBLE-LINKED LISTS */
|
map01bf@255
|
45 typedef struct node2_t {
|
map01bf@255
|
46 int i, j;
|
map01bf@255
|
47 double val;
|
map01bf@255
|
48 struct node2_t *NextC; /* NEXT COLUMN */
|
map01bf@255
|
49 struct node2_t *NextR; /* NEXT ROW */
|
map01bf@255
|
50 } node2_t;
|
map01bf@255
|
51
|
map01bf@255
|
52
|
map01bf@255
|
53
|
map01bf@255
|
54 /* GLOBAL VARIABLE DECLARATION */
|
map01bf@255
|
55 static int _n1, _n2; /* SIGNATURES SIZES */
|
map01bf@255
|
56 static float _C[MAX_SIG_SIZE1][MAX_SIG_SIZE1];/* THE COST MATRIX */
|
map01bf@255
|
57 static node2_t _X[MAX_SIG_SIZE1*2]; /* THE BASIC VARIABLES VECTOR */
|
map01bf@255
|
58 /* VARIABLES TO HANDLE _X EFFICIENTLY */
|
map01bf@255
|
59 static node2_t *_EndX, *_EnterX;
|
map01bf@255
|
60 static char _IsX[MAX_SIG_SIZE1][MAX_SIG_SIZE1];
|
map01bf@255
|
61 static node2_t *_RowsX[MAX_SIG_SIZE1], *_ColsX[MAX_SIG_SIZE1];
|
map01bf@255
|
62 static double _maxW;
|
map01bf@255
|
63 static float _maxC;
|
map01bf@255
|
64
|
map01bf@255
|
65 /* DECLARATION OF FUNCTIONS */
|
map01bf@255
|
66 static float init(signature_t *Signature1, signature_t *Signature2,
|
map01bf@255
|
67 float (*Dist)(feature_t *, feature_t *));
|
map01bf@255
|
68 static void findBasicVariables(node1_t *U, node1_t *V);
|
map01bf@255
|
69 static int isOptimal(node1_t *U, node1_t *V);
|
map01bf@255
|
70 static int findLoop(node2_t **Loop);
|
map01bf@255
|
71 static void newSol();
|
map01bf@255
|
72 static void russel(double *S, double *D);
|
map01bf@255
|
73 static void addBasicVariable(int minI, int minJ, double *S, double *D,
|
map01bf@255
|
74 node1_t *PrevUMinI, node1_t *PrevVMinJ,
|
map01bf@255
|
75 node1_t *UHead);
|
map01bf@255
|
76 #if DEBUG_LEVEL > 0
|
map01bf@255
|
77 static void printSolution();
|
map01bf@255
|
78 #endif
|
map01bf@255
|
79
|
map01bf@255
|
80
|
map01bf@255
|
81 /******************************************************************************
|
map01bf@255
|
82 float emd(signature_t *Signature1, signature_t *Signature2,
|
map01bf@255
|
83 float (*Dist)(feature_t *, feature_t *), flow_t *Flow, int *FlowSize)
|
map01bf@255
|
84
|
map01bf@255
|
85 where
|
map01bf@255
|
86
|
map01bf@255
|
87 Signature1, Signature2 Pointers to signatures that their distance we want
|
map01bf@255
|
88 to compute.
|
map01bf@255
|
89 Dist Pointer to the ground distance. i.e. the function that computes
|
map01bf@255
|
90 the distance between two features.
|
map01bf@255
|
91 Flow (Optional) Pointer to a vector of flow_t (defined in emd.h)
|
map01bf@255
|
92 where the resulting flow will be stored. Flow must have n1+n2-1
|
map01bf@255
|
93 elements, where n1 and n2 are the sizes of the two signatures
|
map01bf@255
|
94 respectively.
|
map01bf@255
|
95 If NULL, the flow is not returned.
|
map01bf@255
|
96 FlowSize (Optional) Pointer to an integer where the number of elements in
|
map01bf@255
|
97 Flow will be stored
|
map01bf@255
|
98
|
map01bf@255
|
99 ******************************************************************************/
|
map01bf@255
|
100
|
map01bf@255
|
101 float emd(signature_t *Signature1, signature_t *Signature2,
|
map01bf@255
|
102 float (*Dist)(feature_t *, feature_t *),
|
map01bf@255
|
103 flow_t *Flow, int *FlowSize)
|
map01bf@255
|
104 {
|
map01bf@255
|
105 int itr;
|
map01bf@255
|
106 double totalCost;
|
map01bf@255
|
107 float w;
|
map01bf@255
|
108 node2_t *XP;
|
map01bf@255
|
109 flow_t *FlowP;
|
map01bf@255
|
110 node1_t U[MAX_SIG_SIZE1], V[MAX_SIG_SIZE1];
|
map01bf@255
|
111
|
map01bf@255
|
112 w = init(Signature1, Signature2, Dist);
|
map01bf@255
|
113
|
map01bf@255
|
114 #if DEBUG_LEVEL > 1
|
map01bf@255
|
115 printf("\nINITIAL SOLUTION:\n");
|
map01bf@255
|
116 printSolution();
|
map01bf@255
|
117 #endif
|
map01bf@255
|
118
|
map01bf@255
|
119 if (_n1 > 1 && _n2 > 1) /* IF _n1 = 1 OR _n2 = 1 THEN WE ARE DONE */
|
map01bf@255
|
120 {
|
map01bf@255
|
121 for (itr = 1; itr < MAX_ITERATIONS; itr++)
|
map01bf@255
|
122 {
|
map01bf@255
|
123 /* FIND BASIC VARIABLES */
|
map01bf@255
|
124 findBasicVariables(U, V);
|
map01bf@255
|
125
|
map01bf@255
|
126 /* CHECK FOR OPTIMALITY */
|
map01bf@255
|
127 if (isOptimal(U, V))
|
map01bf@255
|
128 break;
|
map01bf@255
|
129
|
map01bf@255
|
130 /* IMPROVE SOLUTION */
|
map01bf@255
|
131 newSol();
|
map01bf@255
|
132
|
map01bf@255
|
133 #if DEBUG_LEVEL > 1
|
map01bf@255
|
134 printf("\nITERATION # %d \n", itr);
|
map01bf@255
|
135 printSolution();
|
map01bf@255
|
136 #endif
|
map01bf@255
|
137 }
|
map01bf@255
|
138
|
map01bf@255
|
139 if (itr == MAX_ITERATIONS)
|
map01bf@255
|
140 fprintf(stderr, "emd: Maximum number of iterations has been reached (%d)\n",
|
map01bf@255
|
141 MAX_ITERATIONS);
|
map01bf@255
|
142 }
|
map01bf@255
|
143
|
map01bf@255
|
144 /* COMPUTE THE TOTAL FLOW */
|
map01bf@255
|
145 totalCost = 0;
|
map01bf@255
|
146 if (Flow != NULL)
|
map01bf@255
|
147 FlowP = Flow;
|
map01bf@255
|
148 for(XP=_X; XP < _EndX; XP++)
|
map01bf@255
|
149 {
|
map01bf@255
|
150 if (XP == _EnterX) /* _EnterX IS THE EMPTY SLOT */
|
map01bf@255
|
151 continue;
|
map01bf@255
|
152 if (XP->i == Signature1->n || XP->j == Signature2->n) /* DUMMY FEATURE */
|
map01bf@255
|
153 continue;
|
map01bf@255
|
154
|
map01bf@255
|
155 if (XP->val == 0) /* ZERO FLOW */
|
map01bf@255
|
156 continue;
|
map01bf@255
|
157
|
map01bf@255
|
158 totalCost += (double)XP->val * _C[XP->i][XP->j];
|
map01bf@255
|
159 if (Flow != NULL)
|
map01bf@255
|
160 {
|
map01bf@255
|
161 FlowP->from = XP->i;
|
map01bf@255
|
162 FlowP->to = XP->j;
|
map01bf@255
|
163 FlowP->amount = XP->val;
|
map01bf@255
|
164 FlowP++;
|
map01bf@255
|
165 }
|
map01bf@255
|
166 }
|
map01bf@255
|
167 if (Flow != NULL)
|
map01bf@255
|
168 *FlowSize = FlowP-Flow;
|
map01bf@255
|
169
|
map01bf@255
|
170 #if DEBUG_LEVEL > 0
|
map01bf@255
|
171 printf("\n*** OPTIMAL SOLUTION (%d ITERATIONS): %f ***\n", itr, totalCost);
|
map01bf@255
|
172 #endif
|
map01bf@255
|
173
|
map01bf@255
|
174 /* RETURN THE NORMALIZED COST == EMD */
|
map01bf@255
|
175 return (float)(totalCost / w);
|
map01bf@255
|
176 }
|
map01bf@255
|
177
|
map01bf@255
|
178
|
map01bf@255
|
179
|
map01bf@255
|
180
|
map01bf@255
|
181
|
map01bf@255
|
182 /**********************
|
map01bf@255
|
183 init
|
map01bf@255
|
184 **********************/
|
map01bf@255
|
185 static float init(signature_t *Signature1, signature_t *Signature2,
|
map01bf@255
|
186 float (*Dist)(feature_t *, feature_t *))
|
map01bf@255
|
187 {
|
map01bf@255
|
188 int i, j;
|
map01bf@255
|
189 double sSum, dSum, diff;
|
map01bf@255
|
190 feature_t *P1, *P2;
|
map01bf@255
|
191 double S[MAX_SIG_SIZE1], D[MAX_SIG_SIZE1];
|
map01bf@255
|
192
|
map01bf@255
|
193 _n1 = Signature1->n;
|
map01bf@255
|
194 _n2 = Signature2->n;
|
map01bf@255
|
195
|
map01bf@255
|
196 if (_n1 > MAX_SIG_SIZE || _n2 > MAX_SIG_SIZE)
|
map01bf@255
|
197 {
|
map01bf@255
|
198 fprintf(stderr, "emd: Signature size is limited to %d\n", MAX_SIG_SIZE);
|
map01bf@255
|
199 exit(1);
|
map01bf@255
|
200 }
|
map01bf@255
|
201
|
map01bf@255
|
202 /* COMPUTE THE DISTANCE MATRIX */
|
map01bf@255
|
203 _maxC = 0;
|
map01bf@255
|
204 for(i=0, P1=Signature1->Features; i < _n1; i++, P1++)
|
map01bf@255
|
205 for(j=0, P2=Signature2->Features; j < _n2; j++, P2++)
|
map01bf@255
|
206 {
|
map01bf@255
|
207 _C[i][j] = Dist(P1, P2);
|
map01bf@255
|
208 if (_C[i][j] > _maxC)
|
map01bf@255
|
209 _maxC = _C[i][j];
|
map01bf@255
|
210 }
|
map01bf@255
|
211
|
map01bf@255
|
212 /* SUM UP THE SUPPLY AND DEMAND */
|
map01bf@255
|
213 sSum = 0.0;
|
map01bf@255
|
214 for(i=0; i < _n1; i++)
|
map01bf@255
|
215 {
|
map01bf@255
|
216 S[i] = Signature1->Weights[i];
|
map01bf@255
|
217 sSum += Signature1->Weights[i];
|
map01bf@255
|
218 _RowsX[i] = NULL;
|
map01bf@255
|
219 }
|
map01bf@255
|
220 dSum = 0.0;
|
map01bf@255
|
221 for(j=0; j < _n2; j++)
|
map01bf@255
|
222 {
|
map01bf@255
|
223 D[j] = Signature2->Weights[j];
|
map01bf@255
|
224 dSum += Signature2->Weights[j];
|
map01bf@255
|
225 _ColsX[j] = NULL;
|
map01bf@255
|
226 }
|
map01bf@255
|
227
|
map01bf@255
|
228 /* IF SUPPLY DIFFERENT THAN THE DEMAND, ADD A ZERO-COST DUMMY CLUSTER */
|
map01bf@255
|
229 diff = sSum - dSum;
|
map01bf@255
|
230 if (fabs(diff) >= EPSILON * sSum)
|
map01bf@255
|
231 {
|
map01bf@255
|
232 if (diff < 0.0)
|
map01bf@255
|
233 {
|
map01bf@255
|
234 for (j=0; j < _n2; j++)
|
map01bf@255
|
235 _C[_n1][j] = 0;
|
map01bf@255
|
236 S[_n1] = -diff;
|
map01bf@255
|
237 _RowsX[_n1] = NULL;
|
map01bf@255
|
238 _n1++;
|
map01bf@255
|
239 }
|
map01bf@255
|
240 else
|
map01bf@255
|
241 {
|
map01bf@255
|
242 for (i=0; i < _n1; i++)
|
map01bf@255
|
243 _C[i][_n2] = 0;
|
map01bf@255
|
244 D[_n2] = diff;
|
map01bf@255
|
245 _ColsX[_n2] = NULL;
|
map01bf@255
|
246 _n2++;
|
map01bf@255
|
247 }
|
map01bf@255
|
248 }
|
map01bf@255
|
249
|
map01bf@255
|
250 /* INITIALIZE THE BASIC VARIABLE STRUCTURES */
|
map01bf@255
|
251 for (i=0; i < _n1; i++)
|
map01bf@255
|
252 for (j=0; j < _n2; j++)
|
map01bf@255
|
253 _IsX[i][j] = 0;
|
map01bf@255
|
254 _EndX = _X;
|
map01bf@255
|
255
|
map01bf@255
|
256 _maxW = sSum > dSum ? sSum : dSum;
|
map01bf@255
|
257
|
map01bf@255
|
258 /* FIND INITIAL SOLUTION */
|
map01bf@255
|
259 russel(S, D);
|
map01bf@255
|
260
|
map01bf@255
|
261 _EnterX = _EndX++; /* AN EMPTY SLOT (ONLY _n1+_n2-1 BASIC VARIABLES) */
|
map01bf@255
|
262
|
map01bf@255
|
263 return sSum > dSum ? dSum : sSum;
|
map01bf@255
|
264 }
|
map01bf@255
|
265
|
map01bf@255
|
266
|
map01bf@255
|
267 /**********************
|
map01bf@255
|
268 findBasicVariables
|
map01bf@255
|
269 **********************/
|
map01bf@255
|
270 static void findBasicVariables(node1_t *U, node1_t *V)
|
map01bf@255
|
271 {
|
map01bf@255
|
272 int i, j, found;
|
map01bf@255
|
273 int UfoundNum, VfoundNum;
|
map01bf@255
|
274 node1_t u0Head, u1Head, *CurU, *PrevU;
|
map01bf@255
|
275 node1_t v0Head, v1Head, *CurV, *PrevV;
|
map01bf@255
|
276
|
map01bf@255
|
277 /* INITIALIZE THE ROWS LIST (U) AND THE COLUMNS LIST (V) */
|
map01bf@255
|
278 u0Head.Next = CurU = U;
|
map01bf@255
|
279 for (i=0; i < _n1; i++)
|
map01bf@255
|
280 {
|
map01bf@255
|
281 CurU->i = i;
|
map01bf@255
|
282 CurU->Next = CurU+1;
|
map01bf@255
|
283 CurU++;
|
map01bf@255
|
284 }
|
map01bf@255
|
285 (--CurU)->Next = NULL;
|
map01bf@255
|
286 u1Head.Next = NULL;
|
map01bf@255
|
287
|
map01bf@255
|
288 CurV = V+1;
|
map01bf@255
|
289 v0Head.Next = _n2 > 1 ? V+1 : NULL;
|
map01bf@255
|
290 for (j=1; j < _n2; j++)
|
map01bf@255
|
291 {
|
map01bf@255
|
292 CurV->i = j;
|
map01bf@255
|
293 CurV->Next = CurV+1;
|
map01bf@255
|
294 CurV++;
|
map01bf@255
|
295 }
|
map01bf@255
|
296 (--CurV)->Next = NULL;
|
map01bf@255
|
297 v1Head.Next = NULL;
|
map01bf@255
|
298
|
map01bf@255
|
299 /* THERE ARE _n1+_n2 VARIABLES BUT ONLY _n1+_n2-1 INDEPENDENT EQUATIONS,
|
map01bf@255
|
300 SO SET V[0]=0 */
|
map01bf@255
|
301 V[0].i = 0;
|
map01bf@255
|
302 V[0].val = 0;
|
map01bf@255
|
303 v1Head.Next = V;
|
map01bf@255
|
304 v1Head.Next->Next = NULL;
|
map01bf@255
|
305
|
map01bf@255
|
306 /* LOOP UNTIL ALL VARIABLES ARE FOUND */
|
map01bf@255
|
307 UfoundNum=VfoundNum=0;
|
map01bf@255
|
308 while (UfoundNum < _n1 || VfoundNum < _n2)
|
map01bf@255
|
309 {
|
map01bf@255
|
310
|
map01bf@255
|
311 #if DEBUG_LEVEL > 3
|
map01bf@255
|
312 printf("UfoundNum=%d/%d,VfoundNum=%d/%d\n",UfoundNum,_n1,VfoundNum,_n2);
|
map01bf@255
|
313 printf("U0=");
|
map01bf@255
|
314 for(CurU = u0Head.Next; CurU != NULL; CurU = CurU->Next)
|
map01bf@255
|
315 printf("[%d]",CurU-U);
|
map01bf@255
|
316 printf("\n");
|
map01bf@255
|
317 printf("U1=");
|
map01bf@255
|
318 for(CurU = u1Head.Next; CurU != NULL; CurU = CurU->Next)
|
map01bf@255
|
319 printf("[%d]",CurU-U);
|
map01bf@255
|
320 printf("\n");
|
map01bf@255
|
321 printf("V0=");
|
map01bf@255
|
322 for(CurV = v0Head.Next; CurV != NULL; CurV = CurV->Next)
|
map01bf@255
|
323 printf("[%d]",CurV-V);
|
map01bf@255
|
324 printf("\n");
|
map01bf@255
|
325 printf("V1=");
|
map01bf@255
|
326 for(CurV = v1Head.Next; CurV != NULL; CurV = CurV->Next)
|
map01bf@255
|
327 printf("[%d]",CurV-V);
|
map01bf@255
|
328 printf("\n\n");
|
map01bf@255
|
329 #endif
|
map01bf@255
|
330
|
map01bf@255
|
331 found = 0;
|
map01bf@255
|
332 if (VfoundNum < _n2)
|
map01bf@255
|
333 {
|
map01bf@255
|
334 /* LOOP OVER ALL MARKED COLUMNS */
|
map01bf@255
|
335 PrevV = &v1Head;
|
map01bf@255
|
336 for (CurV=v1Head.Next; CurV != NULL; CurV=CurV->Next)
|
map01bf@255
|
337 {
|
map01bf@255
|
338 j = CurV->i;
|
map01bf@255
|
339 /* FIND THE VARIABLES IN COLUMN j */
|
map01bf@255
|
340 PrevU = &u0Head;
|
map01bf@255
|
341 for (CurU=u0Head.Next; CurU != NULL; CurU=CurU->Next)
|
map01bf@255
|
342 {
|
map01bf@255
|
343 i = CurU->i;
|
map01bf@255
|
344 if (_IsX[i][j])
|
map01bf@255
|
345 {
|
map01bf@255
|
346 /* COMPUTE U[i] */
|
map01bf@255
|
347 CurU->val = _C[i][j] - CurV->val;
|
map01bf@255
|
348 /* ...AND ADD IT TO THE MARKED LIST */
|
map01bf@255
|
349 PrevU->Next = CurU->Next;
|
map01bf@255
|
350 CurU->Next = u1Head.Next != NULL ? u1Head.Next : NULL;
|
map01bf@255
|
351 u1Head.Next = CurU;
|
map01bf@255
|
352 CurU = PrevU;
|
map01bf@255
|
353 }
|
map01bf@255
|
354 else
|
map01bf@255
|
355 PrevU = CurU;
|
map01bf@255
|
356 }
|
map01bf@255
|
357 PrevV->Next = CurV->Next;
|
map01bf@255
|
358 VfoundNum++;
|
map01bf@255
|
359 found = 1;
|
map01bf@255
|
360 }
|
map01bf@255
|
361 }
|
map01bf@255
|
362 if (UfoundNum < _n1)
|
map01bf@255
|
363 {
|
map01bf@255
|
364 /* LOOP OVER ALL MARKED ROWS */
|
map01bf@255
|
365 PrevU = &u1Head;
|
map01bf@255
|
366 for (CurU=u1Head.Next; CurU != NULL; CurU=CurU->Next)
|
map01bf@255
|
367 {
|
map01bf@255
|
368 i = CurU->i;
|
map01bf@255
|
369 /* FIND THE VARIABLES IN ROWS i */
|
map01bf@255
|
370 PrevV = &v0Head;
|
map01bf@255
|
371 for (CurV=v0Head.Next; CurV != NULL; CurV=CurV->Next)
|
map01bf@255
|
372 {
|
map01bf@255
|
373 j = CurV->i;
|
map01bf@255
|
374 if (_IsX[i][j])
|
map01bf@255
|
375 {
|
map01bf@255
|
376 /* COMPUTE V[j] */
|
map01bf@255
|
377 CurV->val = _C[i][j] - CurU->val;
|
map01bf@255
|
378 /* ...AND ADD IT TO THE MARKED LIST */
|
map01bf@255
|
379 PrevV->Next = CurV->Next;
|
map01bf@255
|
380 CurV->Next = v1Head.Next != NULL ? v1Head.Next: NULL;
|
map01bf@255
|
381 v1Head.Next = CurV;
|
map01bf@255
|
382 CurV = PrevV;
|
map01bf@255
|
383 }
|
map01bf@255
|
384 else
|
map01bf@255
|
385 PrevV = CurV;
|
map01bf@255
|
386 }
|
map01bf@255
|
387 PrevU->Next = CurU->Next;
|
map01bf@255
|
388 UfoundNum++;
|
map01bf@255
|
389 found = 1;
|
map01bf@255
|
390 }
|
map01bf@255
|
391 }
|
map01bf@255
|
392 if (! found)
|
map01bf@255
|
393 {
|
map01bf@255
|
394 fprintf(stderr, "emd: Unexpected error in findBasicVariables!\n");
|
map01bf@255
|
395 fprintf(stderr, "This typically happens when the EPSILON defined in\n");
|
map01bf@255
|
396 fprintf(stderr, "emd.h is not right for the scale of the problem.\n");
|
map01bf@255
|
397 exit(1);
|
map01bf@255
|
398 }
|
map01bf@255
|
399 }
|
map01bf@255
|
400 }
|
map01bf@255
|
401
|
map01bf@255
|
402
|
map01bf@255
|
403
|
map01bf@255
|
404
|
map01bf@255
|
405 /**********************
|
map01bf@255
|
406 isOptimal
|
map01bf@255
|
407 **********************/
|
map01bf@255
|
408 static int isOptimal(node1_t *U, node1_t *V)
|
map01bf@255
|
409 {
|
map01bf@255
|
410 double delta, deltaMin;
|
map01bf@255
|
411 int i, j, minI, minJ;
|
map01bf@255
|
412
|
map01bf@255
|
413 /* FIND THE MINIMAL Cij-Ui-Vj OVER ALL i,j */
|
map01bf@255
|
414 deltaMin = INFINITY;
|
map01bf@255
|
415 for(i=0; i < _n1; i++)
|
map01bf@255
|
416 for(j=0; j < _n2; j++)
|
map01bf@255
|
417 if (! _IsX[i][j])
|
map01bf@255
|
418 {
|
map01bf@255
|
419 delta = _C[i][j] - U[i].val - V[j].val;
|
map01bf@255
|
420 if (deltaMin > delta)
|
map01bf@255
|
421 {
|
map01bf@255
|
422 deltaMin = delta;
|
map01bf@255
|
423 minI = i;
|
map01bf@255
|
424 minJ = j;
|
map01bf@255
|
425 }
|
map01bf@255
|
426 }
|
map01bf@255
|
427
|
map01bf@255
|
428 #if DEBUG_LEVEL > 3
|
map01bf@255
|
429 printf("deltaMin=%f\n", deltaMin);
|
map01bf@255
|
430 #endif
|
map01bf@255
|
431
|
map01bf@255
|
432 if (deltaMin == INFINITY)
|
map01bf@255
|
433 {
|
map01bf@255
|
434 fprintf(stderr, "emd: Unexpected error in isOptimal.\n");
|
map01bf@255
|
435 exit(0);
|
map01bf@255
|
436 }
|
map01bf@255
|
437
|
map01bf@255
|
438 _EnterX->i = minI;
|
map01bf@255
|
439 _EnterX->j = minJ;
|
map01bf@255
|
440
|
map01bf@255
|
441 /* IF NO NEGATIVE deltaMin, WE FOUND THE OPTIMAL SOLUTION */
|
map01bf@255
|
442 return deltaMin >= -EPSILON * _maxC;
|
map01bf@255
|
443
|
map01bf@255
|
444 /*
|
map01bf@255
|
445 return deltaMin >= -EPSILON;
|
map01bf@255
|
446 */
|
map01bf@255
|
447 }
|
map01bf@255
|
448
|
map01bf@255
|
449
|
map01bf@255
|
450 /**********************
|
map01bf@255
|
451 newSol
|
map01bf@255
|
452 **********************/
|
map01bf@255
|
453 static void newSol()
|
map01bf@255
|
454 {
|
map01bf@255
|
455 int i, j, k;
|
map01bf@255
|
456 double xMin;
|
map01bf@255
|
457 int steps;
|
map01bf@255
|
458 node2_t *Loop[2*MAX_SIG_SIZE1], *CurX, *LeaveX;
|
map01bf@255
|
459
|
map01bf@255
|
460 #if DEBUG_LEVEL > 3
|
map01bf@255
|
461 printf("EnterX = (%d,%d)\n", _EnterX->i, _EnterX->j);
|
map01bf@255
|
462 #endif
|
map01bf@255
|
463
|
map01bf@255
|
464 /* ENTER THE NEW BASIC VARIABLE */
|
map01bf@255
|
465 i = _EnterX->i;
|
map01bf@255
|
466 j = _EnterX->j;
|
map01bf@255
|
467 _IsX[i][j] = 1;
|
map01bf@255
|
468 _EnterX->NextC = _RowsX[i];
|
map01bf@255
|
469 _EnterX->NextR = _ColsX[j];
|
map01bf@255
|
470 _EnterX->val = 0;
|
map01bf@255
|
471 _RowsX[i] = _EnterX;
|
map01bf@255
|
472 _ColsX[j] = _EnterX;
|
map01bf@255
|
473
|
map01bf@255
|
474 /* FIND A CHAIN REACTION */
|
map01bf@255
|
475 steps = findLoop(Loop);
|
map01bf@255
|
476
|
map01bf@255
|
477 /* FIND THE LARGEST VALUE IN THE LOOP */
|
map01bf@255
|
478 xMin = INFINITY;
|
map01bf@255
|
479 for (k=1; k < steps; k+=2)
|
map01bf@255
|
480 {
|
map01bf@255
|
481 if (Loop[k]->val < xMin)
|
map01bf@255
|
482 {
|
map01bf@255
|
483 LeaveX = Loop[k];
|
map01bf@255
|
484 xMin = Loop[k]->val;
|
map01bf@255
|
485 }
|
map01bf@255
|
486 }
|
map01bf@255
|
487
|
map01bf@255
|
488 /* UPDATE THE LOOP */
|
map01bf@255
|
489 for (k=0; k < steps; k+=2)
|
map01bf@255
|
490 {
|
map01bf@255
|
491 Loop[k]->val += xMin;
|
map01bf@255
|
492 Loop[k+1]->val -= xMin;
|
map01bf@255
|
493 }
|
map01bf@255
|
494
|
map01bf@255
|
495 #if DEBUG_LEVEL > 3
|
map01bf@255
|
496 printf("LeaveX = (%d,%d)\n", LeaveX->i, LeaveX->j);
|
map01bf@255
|
497 #endif
|
map01bf@255
|
498
|
map01bf@255
|
499 /* REMOVE THE LEAVING BASIC VARIABLE */
|
map01bf@255
|
500 i = LeaveX->i;
|
map01bf@255
|
501 j = LeaveX->j;
|
map01bf@255
|
502 _IsX[i][j] = 0;
|
map01bf@255
|
503 if (_RowsX[i] == LeaveX)
|
map01bf@255
|
504 _RowsX[i] = LeaveX->NextC;
|
map01bf@255
|
505 else
|
map01bf@255
|
506 for (CurX=_RowsX[i]; CurX != NULL; CurX = CurX->NextC)
|
map01bf@255
|
507 if (CurX->NextC == LeaveX)
|
map01bf@255
|
508 {
|
map01bf@255
|
509 CurX->NextC = CurX->NextC->NextC;
|
map01bf@255
|
510 break;
|
map01bf@255
|
511 }
|
map01bf@255
|
512 if (_ColsX[j] == LeaveX)
|
map01bf@255
|
513 _ColsX[j] = LeaveX->NextR;
|
map01bf@255
|
514 else
|
map01bf@255
|
515 for (CurX=_ColsX[j]; CurX != NULL; CurX = CurX->NextR)
|
map01bf@255
|
516 if (CurX->NextR == LeaveX)
|
map01bf@255
|
517 {
|
map01bf@255
|
518 CurX->NextR = CurX->NextR->NextR;
|
map01bf@255
|
519 break;
|
map01bf@255
|
520 }
|
map01bf@255
|
521
|
map01bf@255
|
522 /* SET _EnterX TO BE THE NEW EMPTY SLOT */
|
map01bf@255
|
523 _EnterX = LeaveX;
|
map01bf@255
|
524 }
|
map01bf@255
|
525
|
map01bf@255
|
526
|
map01bf@255
|
527
|
map01bf@255
|
528 /**********************
|
map01bf@255
|
529 findLoop
|
map01bf@255
|
530 **********************/
|
map01bf@255
|
531 static int findLoop(node2_t **Loop)
|
map01bf@255
|
532 {
|
map01bf@255
|
533 int i, steps;
|
map01bf@255
|
534 node2_t **CurX, *NewX;
|
map01bf@255
|
535 char IsUsed[2*MAX_SIG_SIZE1];
|
map01bf@255
|
536
|
map01bf@255
|
537 for (i=0; i < _n1+_n2; i++)
|
map01bf@255
|
538 IsUsed[i] = 0;
|
map01bf@255
|
539
|
map01bf@255
|
540 CurX = Loop;
|
map01bf@255
|
541 NewX = *CurX = _EnterX;
|
map01bf@255
|
542 IsUsed[_EnterX-_X] = 1;
|
map01bf@255
|
543 steps = 1;
|
map01bf@255
|
544
|
map01bf@255
|
545 do
|
map01bf@255
|
546 {
|
map01bf@255
|
547 if (steps%2 == 1)
|
map01bf@255
|
548 {
|
map01bf@255
|
549 /* FIND AN UNUSED X IN THE ROW */
|
map01bf@255
|
550 NewX = _RowsX[NewX->i];
|
map01bf@255
|
551 while (NewX != NULL && IsUsed[NewX-_X])
|
map01bf@255
|
552 NewX = NewX->NextC;
|
map01bf@255
|
553 }
|
map01bf@255
|
554 else
|
map01bf@255
|
555 {
|
map01bf@255
|
556 /* FIND AN UNUSED X IN THE COLUMN, OR THE ENTERING X */
|
map01bf@255
|
557 NewX = _ColsX[NewX->j];
|
map01bf@255
|
558 while (NewX != NULL && IsUsed[NewX-_X] && NewX != _EnterX)
|
map01bf@255
|
559 NewX = NewX->NextR;
|
map01bf@255
|
560 if (NewX == _EnterX)
|
map01bf@255
|
561 break;
|
map01bf@255
|
562 }
|
map01bf@255
|
563
|
map01bf@255
|
564 if (NewX != NULL) /* FOUND THE NEXT X */
|
map01bf@255
|
565 {
|
map01bf@255
|
566 /* ADD X TO THE LOOP */
|
map01bf@255
|
567 *++CurX = NewX;
|
map01bf@255
|
568 IsUsed[NewX-_X] = 1;
|
map01bf@255
|
569 steps++;
|
map01bf@255
|
570 #if DEBUG_LEVEL > 3
|
map01bf@255
|
571 printf("steps=%d, NewX=(%d,%d)\n", steps, NewX->i, NewX->j);
|
map01bf@255
|
572 #endif
|
map01bf@255
|
573 }
|
map01bf@255
|
574 else /* DIDN'T FIND THE NEXT X */
|
map01bf@255
|
575 {
|
map01bf@255
|
576 /* BACKTRACK */
|
map01bf@255
|
577 do
|
map01bf@255
|
578 {
|
map01bf@255
|
579 NewX = *CurX;
|
map01bf@255
|
580 do
|
map01bf@255
|
581 {
|
map01bf@255
|
582 if (steps%2 == 1)
|
map01bf@255
|
583 NewX = NewX->NextR;
|
map01bf@255
|
584 else
|
map01bf@255
|
585 NewX = NewX->NextC;
|
map01bf@255
|
586 } while (NewX != NULL && IsUsed[NewX-_X]);
|
map01bf@255
|
587
|
map01bf@255
|
588 if (NewX == NULL)
|
map01bf@255
|
589 {
|
map01bf@255
|
590 IsUsed[*CurX-_X] = 0;
|
map01bf@255
|
591 CurX--;
|
map01bf@255
|
592 steps--;
|
map01bf@255
|
593 }
|
map01bf@255
|
594 } while (NewX == NULL && CurX >= Loop);
|
map01bf@255
|
595
|
map01bf@255
|
596 #if DEBUG_LEVEL > 3
|
map01bf@255
|
597 printf("BACKTRACKING TO: steps=%d, NewX=(%d,%d)\n",
|
map01bf@255
|
598 steps, NewX->i, NewX->j);
|
map01bf@255
|
599 #endif
|
map01bf@255
|
600 IsUsed[*CurX-_X] = 0;
|
map01bf@255
|
601 *CurX = NewX;
|
map01bf@255
|
602 IsUsed[NewX-_X] = 1;
|
map01bf@255
|
603 }
|
map01bf@255
|
604 } while(CurX >= Loop);
|
map01bf@255
|
605
|
map01bf@255
|
606 if (CurX == Loop)
|
map01bf@255
|
607 {
|
map01bf@255
|
608 fprintf(stderr, "emd: Unexpected error in findLoop!\n");
|
map01bf@255
|
609 exit(1);
|
map01bf@255
|
610 }
|
map01bf@255
|
611 #if DEBUG_LEVEL > 3
|
map01bf@255
|
612 printf("FOUND LOOP:\n");
|
map01bf@255
|
613 for (i=0; i < steps; i++)
|
map01bf@255
|
614 printf("%d: (%d,%d)\n", i, Loop[i]->i, Loop[i]->j);
|
map01bf@255
|
615 #endif
|
map01bf@255
|
616
|
map01bf@255
|
617 return steps;
|
map01bf@255
|
618 }
|
map01bf@255
|
619
|
map01bf@255
|
620
|
map01bf@255
|
621
|
map01bf@255
|
622 /**********************
|
map01bf@255
|
623 russel
|
map01bf@255
|
624 **********************/
|
map01bf@255
|
625 static void russel(double *S, double *D)
|
map01bf@255
|
626 {
|
map01bf@255
|
627 int i, j, found, minI, minJ;
|
map01bf@255
|
628 double deltaMin, oldVal, diff;
|
map01bf@255
|
629 double Delta[MAX_SIG_SIZE1][MAX_SIG_SIZE1];
|
map01bf@255
|
630 node1_t Ur[MAX_SIG_SIZE1], Vr[MAX_SIG_SIZE1];
|
map01bf@255
|
631 node1_t uHead, *CurU, *PrevU;
|
map01bf@255
|
632 node1_t vHead, *CurV, *PrevV;
|
map01bf@255
|
633 node1_t *PrevUMinI, *PrevVMinJ, *Remember;
|
map01bf@255
|
634
|
map01bf@255
|
635 /* INITIALIZE THE ROWS LIST (Ur), AND THE COLUMNS LIST (Vr) */
|
map01bf@255
|
636 uHead.Next = CurU = Ur;
|
map01bf@255
|
637 for (i=0; i < _n1; i++)
|
map01bf@255
|
638 {
|
map01bf@255
|
639 CurU->i = i;
|
map01bf@255
|
640 CurU->val = -INFINITY;
|
map01bf@255
|
641 CurU->Next = CurU+1;
|
map01bf@255
|
642 CurU++;
|
map01bf@255
|
643 }
|
map01bf@255
|
644 (--CurU)->Next = NULL;
|
map01bf@255
|
645
|
map01bf@255
|
646 vHead.Next = CurV = Vr;
|
map01bf@255
|
647 for (j=0; j < _n2; j++)
|
map01bf@255
|
648 {
|
map01bf@255
|
649 CurV->i = j;
|
map01bf@255
|
650 CurV->val = -INFINITY;
|
map01bf@255
|
651 CurV->Next = CurV+1;
|
map01bf@255
|
652 CurV++;
|
map01bf@255
|
653 }
|
map01bf@255
|
654 (--CurV)->Next = NULL;
|
map01bf@255
|
655
|
map01bf@255
|
656 /* FIND THE MAXIMUM ROW AND COLUMN VALUES (Ur[i] AND Vr[j]) */
|
map01bf@255
|
657 for(i=0; i < _n1 ; i++)
|
map01bf@255
|
658 for(j=0; j < _n2 ; j++)
|
map01bf@255
|
659 {
|
map01bf@255
|
660 float v;
|
map01bf@255
|
661 v = _C[i][j];
|
map01bf@255
|
662 if (Ur[i].val <= v)
|
map01bf@255
|
663 Ur[i].val = v;
|
map01bf@255
|
664 if (Vr[j].val <= v)
|
map01bf@255
|
665 Vr[j].val = v;
|
map01bf@255
|
666 }
|
map01bf@255
|
667
|
map01bf@255
|
668 /* COMPUTE THE Delta MATRIX */
|
map01bf@255
|
669 for(i=0; i < _n1 ; i++)
|
map01bf@255
|
670 for(j=0; j < _n2 ; j++)
|
map01bf@255
|
671 Delta[i][j] = _C[i][j] - Ur[i].val - Vr[j].val;
|
map01bf@255
|
672
|
map01bf@255
|
673 /* FIND THE BASIC VARIABLES */
|
map01bf@255
|
674 do
|
map01bf@255
|
675 {
|
map01bf@255
|
676 #if DEBUG_LEVEL > 3
|
map01bf@255
|
677 printf("Ur=");
|
map01bf@255
|
678 for(CurU = uHead.Next; CurU != NULL; CurU = CurU->Next)
|
map01bf@255
|
679 printf("[%d]",CurU-Ur);
|
map01bf@255
|
680 printf("\n");
|
map01bf@255
|
681 printf("Vr=");
|
map01bf@255
|
682 for(CurV = vHead.Next; CurV != NULL; CurV = CurV->Next)
|
map01bf@255
|
683 printf("[%d]",CurV-Vr);
|
map01bf@255
|
684 printf("\n");
|
map01bf@255
|
685 printf("\n\n");
|
map01bf@255
|
686 #endif
|
map01bf@255
|
687
|
map01bf@255
|
688 /* FIND THE SMALLEST Delta[i][j] */
|
map01bf@255
|
689 found = 0;
|
map01bf@255
|
690 deltaMin = INFINITY;
|
map01bf@255
|
691 PrevU = &uHead;
|
map01bf@255
|
692 for (CurU=uHead.Next; CurU != NULL; CurU=CurU->Next)
|
map01bf@255
|
693 {
|
map01bf@255
|
694 int i;
|
map01bf@255
|
695 i = CurU->i;
|
map01bf@255
|
696 PrevV = &vHead;
|
map01bf@255
|
697 for (CurV=vHead.Next; CurV != NULL; CurV=CurV->Next)
|
map01bf@255
|
698 {
|
map01bf@255
|
699 int j;
|
map01bf@255
|
700 j = CurV->i;
|
map01bf@255
|
701 if (deltaMin > Delta[i][j])
|
map01bf@255
|
702 {
|
map01bf@255
|
703 deltaMin = Delta[i][j];
|
map01bf@255
|
704 minI = i;
|
map01bf@255
|
705 minJ = j;
|
map01bf@255
|
706 PrevUMinI = PrevU;
|
map01bf@255
|
707 PrevVMinJ = PrevV;
|
map01bf@255
|
708 found = 1;
|
map01bf@255
|
709 }
|
map01bf@255
|
710 PrevV = CurV;
|
map01bf@255
|
711 }
|
map01bf@255
|
712 PrevU = CurU;
|
map01bf@255
|
713 }
|
map01bf@255
|
714
|
map01bf@255
|
715 if (! found)
|
map01bf@255
|
716 break;
|
map01bf@255
|
717
|
map01bf@255
|
718 /* ADD X[minI][minJ] TO THE BASIS, AND ADJUST SUPPLIES AND COST */
|
map01bf@255
|
719 Remember = PrevUMinI->Next;
|
map01bf@255
|
720 addBasicVariable(minI, minJ, S, D, PrevUMinI, PrevVMinJ, &uHead);
|
map01bf@255
|
721
|
map01bf@255
|
722 /* UPDATE THE NECESSARY Delta[][] */
|
map01bf@255
|
723 if (Remember == PrevUMinI->Next) /* LINE minI WAS DELETED */
|
map01bf@255
|
724 {
|
map01bf@255
|
725 for (CurV=vHead.Next; CurV != NULL; CurV=CurV->Next)
|
map01bf@255
|
726 {
|
map01bf@255
|
727 int j;
|
map01bf@255
|
728 j = CurV->i;
|
map01bf@255
|
729 if (CurV->val == _C[minI][j]) /* COLUMN j NEEDS UPDATING */
|
map01bf@255
|
730 {
|
map01bf@255
|
731 /* FIND THE NEW MAXIMUM VALUE IN THE COLUMN */
|
map01bf@255
|
732 oldVal = CurV->val;
|
map01bf@255
|
733 CurV->val = -INFINITY;
|
map01bf@255
|
734 for (CurU=uHead.Next; CurU != NULL; CurU=CurU->Next)
|
map01bf@255
|
735 {
|
map01bf@255
|
736 int i;
|
map01bf@255
|
737 i = CurU->i;
|
map01bf@255
|
738 if (CurV->val <= _C[i][j])
|
map01bf@255
|
739 CurV->val = _C[i][j];
|
map01bf@255
|
740 }
|
map01bf@255
|
741
|
map01bf@255
|
742 /* IF NEEDED, ADJUST THE RELEVANT Delta[*][j] */
|
map01bf@255
|
743 diff = oldVal - CurV->val;
|
map01bf@255
|
744 if (fabs(diff) < EPSILON * _maxC)
|
map01bf@255
|
745 for (CurU=uHead.Next; CurU != NULL; CurU=CurU->Next)
|
map01bf@255
|
746 Delta[CurU->i][j] += diff;
|
map01bf@255
|
747 }
|
map01bf@255
|
748 }
|
map01bf@255
|
749 }
|
map01bf@255
|
750 else /* COLUMN minJ WAS DELETED */
|
map01bf@255
|
751 {
|
map01bf@255
|
752 for (CurU=uHead.Next; CurU != NULL; CurU=CurU->Next)
|
map01bf@255
|
753 {
|
map01bf@255
|
754 int i;
|
map01bf@255
|
755 i = CurU->i;
|
map01bf@255
|
756 if (CurU->val == _C[i][minJ]) /* ROW i NEEDS UPDATING */
|
map01bf@255
|
757 {
|
map01bf@255
|
758 /* FIND THE NEW MAXIMUM VALUE IN THE ROW */
|
map01bf@255
|
759 oldVal = CurU->val;
|
map01bf@255
|
760 CurU->val = -INFINITY;
|
map01bf@255
|
761 for (CurV=vHead.Next; CurV != NULL; CurV=CurV->Next)
|
map01bf@255
|
762 {
|
map01bf@255
|
763 int j;
|
map01bf@255
|
764 j = CurV->i;
|
map01bf@255
|
765 if(CurU->val <= _C[i][j])
|
map01bf@255
|
766 CurU->val = _C[i][j];
|
map01bf@255
|
767 }
|
map01bf@255
|
768
|
map01bf@255
|
769 /* If NEEDED, ADJUST THE RELEVANT Delta[i][*] */
|
map01bf@255
|
770 diff = oldVal - CurU->val;
|
map01bf@255
|
771 if (fabs(diff) < EPSILON * _maxC)
|
map01bf@255
|
772 for (CurV=vHead.Next; CurV != NULL; CurV=CurV->Next)
|
map01bf@255
|
773 Delta[i][CurV->i] += diff;
|
map01bf@255
|
774 }
|
map01bf@255
|
775 }
|
map01bf@255
|
776 }
|
map01bf@255
|
777 } while (uHead.Next != NULL || vHead.Next != NULL);
|
map01bf@255
|
778 }
|
map01bf@255
|
779
|
map01bf@255
|
780
|
map01bf@255
|
781
|
map01bf@255
|
782
|
map01bf@255
|
783 /**********************
|
map01bf@255
|
784 addBasicVariable
|
map01bf@255
|
785 **********************/
|
map01bf@255
|
786 static void addBasicVariable(int minI, int minJ, double *S, double *D,
|
map01bf@255
|
787 node1_t *PrevUMinI, node1_t *PrevVMinJ,
|
map01bf@255
|
788 node1_t *UHead)
|
map01bf@255
|
789 {
|
map01bf@255
|
790 double T;
|
map01bf@255
|
791
|
map01bf@255
|
792 if (fabs(S[minI]-D[minJ]) <= EPSILON * _maxW) /* DEGENERATE CASE */
|
map01bf@255
|
793 {
|
map01bf@255
|
794 T = S[minI];
|
map01bf@255
|
795 S[minI] = 0;
|
map01bf@255
|
796 D[minJ] -= T;
|
map01bf@255
|
797 }
|
map01bf@255
|
798 else if (S[minI] < D[minJ]) /* SUPPLY EXHAUSTED */
|
map01bf@255
|
799 {
|
map01bf@255
|
800 T = S[minI];
|
map01bf@255
|
801 S[minI] = 0;
|
map01bf@255
|
802 D[minJ] -= T;
|
map01bf@255
|
803 }
|
map01bf@255
|
804 else /* DEMAND EXHAUSTED */
|
map01bf@255
|
805 {
|
map01bf@255
|
806 T = D[minJ];
|
map01bf@255
|
807 D[minJ] = 0;
|
map01bf@255
|
808 S[minI] -= T;
|
map01bf@255
|
809 }
|
map01bf@255
|
810
|
map01bf@255
|
811 /* X(minI,minJ) IS A BASIC VARIABLE */
|
map01bf@255
|
812 _IsX[minI][minJ] = 1;
|
map01bf@255
|
813
|
map01bf@255
|
814 _EndX->val = T;
|
map01bf@255
|
815 _EndX->i = minI;
|
map01bf@255
|
816 _EndX->j = minJ;
|
map01bf@255
|
817 _EndX->NextC = _RowsX[minI];
|
map01bf@255
|
818 _EndX->NextR = _ColsX[minJ];
|
map01bf@255
|
819 _RowsX[minI] = _EndX;
|
map01bf@255
|
820 _ColsX[minJ] = _EndX;
|
map01bf@255
|
821 _EndX++;
|
map01bf@255
|
822
|
map01bf@255
|
823 /* DELETE SUPPLY ROW ONLY IF THE EMPTY, AND IF NOT LAST ROW */
|
map01bf@255
|
824 if (S[minI] == 0 && UHead->Next->Next != NULL)
|
map01bf@255
|
825 PrevUMinI->Next = PrevUMinI->Next->Next; /* REMOVE ROW FROM LIST */
|
map01bf@255
|
826 else
|
map01bf@255
|
827 PrevVMinJ->Next = PrevVMinJ->Next->Next; /* REMOVE COLUMN FROM LIST */
|
map01bf@255
|
828 }
|
map01bf@255
|
829
|
map01bf@255
|
830
|
map01bf@255
|
831
|
map01bf@255
|
832
|
map01bf@255
|
833
|
map01bf@255
|
834 /**********************
|
map01bf@255
|
835 printSolution
|
map01bf@255
|
836 **********************/
|
map01bf@255
|
837 static void printSolution()
|
map01bf@255
|
838 {
|
map01bf@255
|
839 node2_t *P;
|
map01bf@255
|
840 double totalCost;
|
map01bf@255
|
841
|
map01bf@255
|
842 totalCost = 0;
|
map01bf@255
|
843
|
map01bf@255
|
844 #if DEBUG_LEVEL > 2
|
map01bf@255
|
845 printf("SIG1\tSIG2\tFLOW\tCOST\n");
|
map01bf@255
|
846 #endif
|
map01bf@255
|
847 for(P=_X; P < _EndX; P++)
|
map01bf@255
|
848 if (P != _EnterX && _IsX[P->i][P->j])
|
map01bf@255
|
849 {
|
map01bf@255
|
850 #if DEBUG_LEVEL > 2
|
map01bf@255
|
851 printf("%d\t%d\t%f\t%f\n", P->i, P->j, P->val, _C[P->i][P->j]);
|
map01bf@255
|
852 #endif
|
map01bf@255
|
853 totalCost += (double)P->val * _C[P->i][P->j];
|
map01bf@255
|
854 }
|
map01bf@255
|
855
|
map01bf@255
|
856 printf("COST = %f\n", totalCost);
|
map01bf@255
|
857 }
|
map01bf@255
|
858
|
map01bf@255
|
859
|