Statistics
| Revision:

root / trunk / extensions / extGraph / src / org / gvsig / graph / solvers / TspSolverAnnealing.java @ 39203

History | View | Annotate | Download (11 KB)

1
package org.gvsig.graph.solvers;
2

    
3
import java.util.Random;
4

    
5
import org.gvsig.graph.core.GvFlag;
6

    
7
public class TspSolverAnnealing {
8
        static int T_INIT = 100;
9
        static double FINAL_T = 0.1;
10
        static double COOLING = 0.9; /* to lower down T (< 1) */
11

    
12
        
13
        int n;
14
        int[] iorder;
15
        int[] jorder;
16
        float[] b = new float[4];
17
        double[][] odMatrix;
18
        boolean bReturnToOrigin;
19
        int origenTSP, destinoTSP;
20
        int[] vTSP;
21

    
22

    
23

    
24
        /*
25
         * State vars
26
         */
27
        int     verbose = 0;
28
        private GvFlag[] flags  = null;
29
        private boolean bVolverOrigen = false;
30
        private double distTotMin = Double.MAX_VALUE;
31

    
32
        /* float calcula_dist_ordenacion(int v[], int bVolverOrigen)
33
        {
34
                float dist, distTot;
35
                int i;
36

37
                distTot = odMatrix[origenTSP][v[0]]; // Origen al primer punto
38
                for (i = 0; i< numElemTSP-1;i++)
39
                        {
40
                                dist = odMatrix[v[i]][v[i+1]];
41
                    distTot = distTot + dist;
42
                        }
43
                
44
                //  desde y hasta el almacen (distancia al primero y al ?ltimo
45
                if (bVolverOrigen)
46
                        {            
47
                                dist = odMatrix[v[numElemTSP-1]][origenTSP];
48
                    distTot = distTot + dist;
49
                }
50
                        else
51
                        {
52
                                dist = odMatrix[v[numElemTSP-1]][destinoTSP];
53
                                distTot = distTot + dist;
54
                        }
55
                        return distTot;
56
        } */
57

    
58

    
59
        double pathLength()
60
        {
61
                int i; 
62
                double len = 0;
63

    
64
                len = D(origenTSP, iorder[0]);
65
                for (i = 0; i < n-1; i++)
66
                {
67
                        len += D(iorder[i], iorder[i+1]);
68
                }
69

    
70
                if (bReturnToOrigin)
71
                        len += D(iorder[n-1], origenTSP); /* close path */
72
                else
73
                        len += D(iorder[n-1], destinoTSP); /* close path */
74
                return (len);
75
        }
76

    
77
        
78
        int mod(int a, int b) {
79
                int aux = (a % b);
80
                if (aux < 0)
81
                        aux = aux + b;
82
                return aux;
83
        }
84
        
85
        double D(int f, int t) {
86
                return odMatrix[f][t];
87
        }
88

    
89

    
90
        /*
91
         * Local Search Heuristics
92
         *  b-------a        b       a
93
         *  .       .   =>   .\     /.
94
         *  . d...e .        . e...d .  
95
         *  ./     \.        .       .
96
         *  c       f        c-------f
97
         */
98
        double getThreeWayCost (int[] p)
99
        {
100
                int a, b, c, d, e, f;
101
                a = iorder[mod(p[0]-1, n)]; b = iorder[p[0]];
102
                c = iorder[p[1]];   d = iorder[mod(p[1]+1,n)];
103
                e = iorder[p[2]];   f = iorder[mod(p[2]+1,n)];
104
                
105
                // b va a ser el nuevo origen => sumamos su distancia a nuestro origen fijo
106
                double Dant, Dnuevo, Ddiff = 0;
107
                Dant = D(origenTSP, iorder[0]);
108
                Dnuevo = D(origenTSP, b);
109
                Ddiff = Dnuevo - Dant;
110

    
111
                // tambi?n hay que mirar la distancia al destino desde el ?ltimo punto
112
                int fin=n-1;
113
                if (bReturnToOrigin)
114
                {        
115
                        // p[2] va a ser el pr?ximo ?ltimo punto 
116
                        Dant = D(iorder[fin], origenTSP);
117
                        Dnuevo = D(iorder[p[2]], origenTSP);
118
                        Ddiff = Ddiff + Dnuevo - Dant;
119
                }
120
                else
121
                {
122
                        Dant = D(iorder[fin], destinoTSP);
123
                        Dnuevo = D(iorder[p[2]], destinoTSP);
124
                        Ddiff = Ddiff + Dnuevo - Dant;
125
                }
126
                
127

    
128
                return (D(a,d) + D(e,b) + D(c,f) - D(a,b) - D(c,d) - D(e,f) + Ddiff); 
129
                /* add cost between d and e if non symetric TSP */ 
130

    
131
                // A?ADIR DIFERENCIA DE COSTE A LOS NODOS INMOVILES. (ORIGEN Y ?DESTINO?)
132
        }
133

    
134
        void doThreeWay (int[] p)
135
        {
136
                int i, count, m1, m2, m3, a, b, c, d, e, f;
137
                int index;
138
                a = mod(p[0]-1,n); b = p[0];
139
                c = p[1];   d = mod(p[1]+1,n);
140
                e = p[2];   f = mod(p[2]+1,n);        
141
                
142
                m1 = mod(n+c-b,n)+1;  /* num cities from b to c */
143
                m2 = mod(n+a-f,n)+1;  /* num cities from f to a */
144
                m3 = mod(n+e-d,n)+1;  /* num cities from d to e */
145

    
146
                count = 0;
147
                /* [b..c] */
148
                for (i = 0; i < m1; i++)
149
                {
150
                        index = mod(i+b,n);
151
                        jorder[count++] = iorder[index];
152
                }
153

    
154
                /* [f..a] */
155
                for (i = 0; i < m2; i++)
156
                {
157
                        index = mod(i+f,n);
158
                        jorder[count++] = iorder[index];
159
                }
160

    
161
                /* [d..e] */
162
                for (i = 0; i < m3; i++)
163
                {
164
                        index = mod(i+d,n);
165
                        jorder[count++] = iorder[index];
166
                }
167

    
168
                /* copy segment back into iorder */
169
                for (i = 0; i < n; i++) iorder[i] = jorder[i];
170
        }
171

    
172
        /*
173
         *   c..b       c..b
174
         *    \/    =>  |  |
175
         *    /\        |  |
176
         *   a  d       a  d
177
         */
178
        double getReverseCost (int[] p)
179
        {
180
                int a, b, c, d;
181
                a = iorder[mod(p[0]-1,n)]; b = iorder[p[0]];
182
                c = iorder[p[1]];   d = iorder[mod(p[1]+1,n)];
183
                
184
                double Dant = 0, Dnuevo = 0, Ddiff = 0;
185

    
186
                if (p[0]==0 || p[1]==0)
187
                {
188
                        Dant = D(origenTSP,iorder[0]);
189
                        if (p[0]==0)
190
                                Dnuevo = D(origenTSP, c);
191
                        else
192
                                Dnuevo = D(origenTSP, b);
193
                        Ddiff = Dnuevo-Dant;
194
                }
195
                int fin = n-1;
196
                if (bReturnToOrigin) // Miramos la distancia al cero
197
                {                
198
                        // iorder[p[1]] o iorder[p[0]] va a acabar en la ?ltima posici?n
199
                        if (p[0]==fin || p[1] == fin) // tambi?n hay que mirar la distancia al destino desde el ?ltimo punto
200
                        {
201
                                Dant = D(iorder[fin], origenTSP);
202
                                if (p[0]==fin)
203
                                        Dnuevo = D(c,origenTSP);
204
                                else
205
                                        Dnuevo = D(b, origenTSP);
206
                                Ddiff = Ddiff + Dnuevo - Dant;
207

    
208
                        } 
209
                }
210
                else
211
                {
212
                        if (p[0]==fin || p[1] == fin) // tambi?n hay que mirar la distancia al destino desde el ?ltimo punto
213
                        {
214
                                Dant = D(iorder[fin], destinoTSP);
215
                                if (p[0]==fin)
216
                                        Dnuevo = D(c,destinoTSP);
217
                                else
218
                                        Dnuevo = D(b, destinoTSP);
219
                                Ddiff = Ddiff + Dnuevo - Dant;
220

    
221
                        } 
222
                } 
223

    
224
                return (D(d,b) + D(c,a) - D(a,b) - D(c,d) + Ddiff);
225
                /* add cost between c and b if non symetric TSP */ 
226
//         A?ADIR DIFERENCIA DE COSTE A LOS NODOS INMOVILES. (ORIGEN Y ?DESTINO?)
227
        }
228

    
229
        void doReverse(int[] p)
230
        {
231
                int i, nswaps, first, last, tmp;
232

    
233
                /* reverse path b...c */
234
                nswaps = (mod(p[1]-p[0],n)+1)/2;
235
                for (i = 0; i < nswaps; i++)
236
                {
237
                        first = mod(p[0]+i, n);
238
                        last  = mod(p[1]-i, n);
239
                        tmp   = iorder[first];
240
                        
241
                        iorder[first] = iorder[last];
242
                        iorder[last]  = tmp;
243
                }
244
        }
245

    
246
        double annealing()
247
        {
248
                int[] p = new int[3];
249
                int    i=1, j, pathchg;
250
                int    numOnPath, numNotOnPath;
251
                double    pathlen, bestlen;
252
                double energyChange, T;
253
                
254
                /*
255
                 * Set up first eulerian path iorder to be improved by
256
                 * simulated annealing. 
257
                 */
258
                /* bool conEulerian = true;
259
                if (conEulerian)
260
                         findEulerianPath();  */
261

    
262

    
263
                pathlen = pathLength(); // (iorder); 
264
                bestlen = pathlen;
265
                Random rnd = new Random();
266
                
267
                int TRIES_PER_T = 500*n;   
268
                int IMPROVED_PATH_PER_T = 60*n;    
269

    
270
                for (T = T_INIT; T > FINAL_T; T *= COOLING)  /* annealing schedule */
271
                {
272
                        pathchg = 0;
273
                        for (j = 0; j < TRIES_PER_T; j++)
274
                        {
275
                                do {
276
                                        p[0] = rnd.nextInt(n);
277
                                        p[1] = rnd.nextInt(n);
278
                                        if (p[0] == p[1])
279
                                                p[1] = mod(p[0]+1,n); /* non-empty path */
280
                                        numOnPath = mod(p[1]-p[0],n) + 1;
281
                                        numNotOnPath = n - numOnPath;
282
                                } while (numOnPath < 2 || numNotOnPath < 2) ; /* non-empty path */
283
                                
284
                                double rreal = rnd.nextDouble();
285
                                if ((rnd.nextInt() % 2) == 0) /*  threeWay */
286
                                {
287
                                        do {
288
                                                p[2] = mod(rnd.nextInt(numNotOnPath)+p[1]+1,n);
289
                                        } while (p[0] == mod(p[2]+1,n)); /* avoids a non-change */
290
                                        
291
                                        energyChange = getThreeWayCost (p);
292
                                        if ((energyChange < 0) || (rreal < Math.exp(-energyChange/T)))
293
                                        {
294
                                                pathchg++;
295
                                                pathlen += energyChange;
296
                                                doThreeWay (p); 
297
                                        }
298
                                }
299
                                else            /* path Reverse */
300
                                {
301
                                        energyChange = getReverseCost (p);
302
                                        if ((energyChange < 0) || (rreal < Math.exp(-energyChange/T)))
303
                                        {
304
                                                pathchg++;
305
                                                pathlen += energyChange;
306
                                                doReverse(p); 
307
                                        }
308
                                }
309
                                if (pathlen < bestlen)
310
                                {
311
                                        pathlen = pathLength(); // Calculamos la distancia de verdad, por si no interesa
312
                                                                                        // hacer el cambio. pathlen es en realidad una estimaci?n
313
                                        if (pathlen < bestlen)
314
                                        {
315
                                                bestlen = pathlen;
316
                                                for (i=0; i< n; i++)
317
                                                        vTSP[i+1] = iorder[i];
318
                                        }
319
                                }
320
                                if (pathchg > IMPROVED_PATH_PER_T) break; /* finish early */
321
                        }   
322
                        if (pathchg == 0) break;   /* if no change then quit */
323
                }
324
                return bestlen;
325
        }
326

    
327

    
328
        public void setStops(GvFlag[] flags) {
329
                this.flags = flags;
330
        }
331

    
332

    
333
        /**
334
         * This function will use annealing only if numStops >= 6. If numStops < 6, it will
335
         * use direct calculation, ensuring the optimum result.
336
         * @return
337
         */
338
        public GvFlag[] calculate() {
339
                GvFlag[] orderedStops = new GvFlag[flags.length];
340
                int numStops = flags.length;
341
                int numElemTSP;
342
                origenTSP = 0;
343
                destinoTSP = numStops-1;
344
                if (bVolverOrigen )
345
                        numElemTSP = numStops-1;                
346
                else
347
                        numElemTSP = numStops-2;
348

    
349
                n = numElemTSP;
350

    
351
                bReturnToOrigin = bVolverOrigen;
352
                
353
                iorder = new int[n];
354
                jorder = new int[n];
355

    
356

    
357

    
358
                vTSP = new int[numStops];
359
                vTSP[0] = origenTSP;
360
                vTSP[numStops-1] = destinoTSP;
361
                if (numElemTSP > 0)
362
                {                
363
                        // v = new int[numElemTSP];
364
                        for (int i=0; i< numElemTSP; i++)
365
                        {
366
                                iorder[i] = i + 1;
367
                                vTSP[i+1] = i + 1; // v[i];
368
                        }
369

    
370
                } 
371

    
372
                /* identity permutation */
373
                // for (i = 0; i < n; i++) iorder[i] = i+1; 
374

    
375
                double distTotal=0.0;
376
                
377
                if (numElemTSP < 7)
378
                {                
379

    
380
                        distTotMin = calculate_distance(iorder,bVolverOrigen);
381

    
382
                        permut(iorder, numElemTSP, bVolverOrigen);
383
                        
384
                        distTotal = distTotMin ;
385
                }
386
                else
387
                {
388
                        distTotal = annealing();
389
                }
390
                
391
                System.out.println("DistTotal = " + distTotal);
392
                System.out.print("new order = [");
393
                for (int i=0; i < vTSP.length; i++) {
394
                        orderedStops[i] = flags[vTSP[i]];
395
                        System.out.print(vTSP[i] + " ");
396
                }
397
                System.out.println("]");
398
                return orderedStops;
399
        }
400

    
401
        
402
        double calculate_distance(int v[], boolean bVolverOrigen)
403
        {
404
                double dist, distTot;
405
                int i;
406

    
407
                distTot = D(origenTSP, v[0]); // Origen al primer punto
408
                for (i = 0; i< n-1;i++)
409
                        {
410
                    //frmDocMap.Distancia v(i), v(i + 1), dist, tiempo
411
                                dist = D(v[i], v[i+1]);
412
                    distTot = distTot + dist;
413
                        }
414
                
415
                //  desde y hasta el almacen (distancia al primero y al ?ltimo
416
                if (bVolverOrigen)
417
                        {            
418
                                dist = D(v[n-1], origenTSP);
419
                    distTot = distTot + dist;
420
                }
421
                        else
422
                        {
423
                                dist = D(v[n-1], destinoTSP);
424
                                distTot = distTot + dist;
425
                        }
426
                        return distTot;
427
        }
428

    
429
        void exchange(int v[], int p1, int p2)
430
        {
431
          int aux;
432
          aux = v[p1];
433
          v[p1] = v[p2];
434
          v[p2] = aux;
435
        }
436

    
437
         void permut (int v[], int m, boolean bVolverOrigen)
438
        {
439
          int i, j;
440
          double distTot;
441

    
442
          if (m > 0)
443
            for (i = 0; i < m; i++)
444
              {
445
                    exchange(v, i, m-1);
446
                permut (v, m-1, bVolverOrigen);
447
                exchange(v, i, m-1);
448
              }
449
          else
450
          {
451
             // escribir_vector (v);
452
             // Aqu? tenemos el vector que buscamos
453
             // Calculamos su distancia y si es menor que la que tenemos guardada, guardamos el nuevo vector.
454
                  distTot = calculate_distance(v, bVolverOrigen);
455
                        
456
                if (distTot < distTotMin)
457
                        {
458
                    distTotMin = distTot;
459
                    for (j = 0; j< n; j++)
460
                        vTSP[j+1] = v[j];
461
                }
462
                // 'MuestraVector v
463

    
464
          }
465
        }
466

    
467

    
468
        public void setODMatrix(double[][] odMatrix) {
469
                this.odMatrix = odMatrix;
470
        }
471

    
472

    
473
        /**
474
         * @return true if the path is closed => will return to origin.
475
         * @see setReturnToOrigin
476
         */
477
        public boolean isClosed() {
478
                return bReturnToOrigin;
479
        }
480

    
481

    
482
        public void setReturnToOrigin(boolean returnToOrigin) {
483
                bReturnToOrigin = returnToOrigin;
484
        }
485

    
486
}