Statistics
| Revision:

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

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
import com.sun.org.apache.xpath.internal.operations.Mod;
8

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

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

    
24

    
25

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

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

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

    
60

    
61
        double pathLength()
62
        {
63
                int i; 
64
                double len = 0;
65

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

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

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

    
91

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

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

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

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

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

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

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

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

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

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

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

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

    
223
                        } 
224
                } 
225

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

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

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

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

    
264

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

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

    
329

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

    
334

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

    
351
                n = numElemTSP;
352

    
353
                bReturnToOrigin = bVolverOrigen;
354
                
355
                iorder = new int[n];
356
                jorder = new int[n];
357

    
358

    
359

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

    
372
                } 
373

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

    
377
                double distTotal=0.0;
378
                
379
                if (numElemTSP < 7)
380
                {                
381

    
382
                        distTotMin = calculate_distance(iorder,bVolverOrigen);
383

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

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

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

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

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

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

    
466
          }
467
        }
468

    
469

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

    
474

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

    
483

    
484
        public void setReturnToOrigin(boolean returnToOrigin) {
485
                bReturnToOrigin = returnToOrigin;
486
        }
487

    
488
}