Statistics
| Revision:

svn-gvsig-desktop / trunk / extensions / extGraph / src / org / gvsig / graph / solvers / TspSolverAnnealing.java @ 23215

History | View | Annotate | Download (9.73 KB)

1
package org.gvsig.graph.solvers;
2

    
3
import java.util.Random;
4

    
5
import com.sun.org.apache.xpath.internal.operations.Mod;
6

    
7
public class TspSolverAnnealing {
8
        int n;
9
        int[] iorder;
10
        int[] jorder;
11
        float[] b = new float[4];
12
        double[][] odMatrix;
13
        boolean g_bVolverOrigen;
14
        int origenTSP, destinoTSP;
15
        int[] vTSP;
16

    
17

    
18

    
19
        static int T_INIT = 100;
20
        static double FINAL_T = 0.1;
21
        static double COOLING = 0.9; /* to lower down T (< 1) */
22
        int TRIES_PER_T = 500*n; // TODO: PONER ESTO BIEN.  
23
        int IMPROVED_PATH_PER_T = 60*n;  // TODO: PONER ESTO BIEN.  
24

    
25

    
26
//        static long A[56]= {-1};
27
//        long *rand_fptr = A;
28

    
29
//        #define mod_diff(x,y)   (((x)-(y))&0x7fffffff) 
30
//        private long flipCycle()
31
//        {
32
//                long *ii,*jj;
33
//                for (ii = &A[1], jj = &A[32]; jj <= &A[55]; ii++, jj++)
34
//                *ii= mod_diff (*ii, *jj);
35
//
36
//                for (jj = &A[1]; ii <= &A[55]; ii++, jj++)
37
//                *ii= mod_diff (*ii, *jj);
38
//                rand_fptr = &A[54];
39
//                return A[55];
40
//        }
41

    
42

    
43
//        typedef int Path[3];      /* specify how to change path */
44

    
45
        /*
46
         * State vars
47
         */
48
        int     verbose = 0;
49
//         Point   *cities;
50
//         int     *dist;
51

    
52
//        #define D(x,y) odMatrix[x][y]    //dist[(x)*n+y]                
53
        /* float calcula_dist_ordenacion(int v[], int bVolverOrigen)
54
        {
55
                float dist, distTot;
56
                int i;
57

58
                distTot = odMatrix[origenTSP][v[0]]; // Origen al primer punto
59
                for (i = 0; i< numElemTSP-1;i++)
60
                        {
61
                    //frmDocMap.Distancia v(i), v(i + 1), dist, tiempo
62
                                dist = odMatrix[v[i]][v[i+1]];
63
                    distTot = distTot + dist;
64
                        }
65
                
66
                //  desde y hasta el almacen (distancia al primero y al ?ltimo
67
                // frmDocMap.Distancia idNodoOrigen, v(0), dist, tiempo
68
                if (bVolverOrigen)
69
                        {            
70
                                dist = odMatrix[v[numElemTSP-1]][origenTSP];
71
                    distTot = distTot + dist;
72
                }
73
                        else
74
                        {
75
                                dist = odMatrix[v[numElemTSP-1]][destinoTSP];
76
                                distTot = distTot + dist;
77
                        }
78
                        return distTot;
79
        } */
80

    
81

    
82
        double pathLength()
83
        {
84
                int i; 
85
                double len = 0;
86

    
87
                len = odMatrix[origenTSP][iorder[0]];
88
                for (i = 0; i < n-1; i++)
89
                {
90
                        len += odMatrix[iorder[i]][iorder[i+1]];
91
                }
92

    
93
                if (g_bVolverOrigen)
94
                        len += odMatrix[iorder[n-1]][origenTSP]; /* close path */
95
                else
96
                        len += odMatrix[iorder[n-1]][destinoTSP]; /* close path */
97
                return (len);
98
        }
99

    
100

    
101
        /*
102
         * Prim's approximated TSP tour
103
         * See also [Cristophides'92]
104
         */
105
        // TODO: NO LO USO => Borrar esta funci?n.
106
        void findEulerianPath()
107
        {
108
                int[] mst = new int[n];
109
                int[] arc = new int[n];        
110
                int i, j = 0, k = 0, l, a;
111
                double d, maxd;
112

    
113
                double[] dis = new double[n];
114

    
115
                maxd = Math.sqrt(b[1]-b[0])+ Math.sqrt(b[3]-b[2]);
116
                d    = maxd;
117
                dis[0] = -1;
118
                for (i = 1; i < n; i++)
119
                {
120
                        dis[i] = odMatrix[i][0]; arc[i] = 0;
121
                        if (d > dis[i])
122
                        {
123
                                d = dis[i];
124
                                j = i;
125
                        }
126
                }
127

    
128
                /*
129
                 * O(n^2) Minimum Spanning Trees by Prim and Jarnick 
130
                 * for graphs with adjacency matrix. 
131
                 */
132
                for (a = 0; a < n - 1; a++)
133
                {
134
                        mst[a] = j * n + arc[j]; /* join fragment j with MST */
135
                        dis[j] = -1; 
136
                        d = maxd;
137
                        for (i = 0; i < n; i++)
138
                        {
139
                                if (dis[i] >= 0) /* not connected yet */
140
                                {
141
                                        if (dis[i] > odMatrix[i][j])
142
                                        {
143
                                                dis[i] = odMatrix[i][j];
144
                                                arc[i] = j;
145
                                        }
146
                                        if (d > dis[i])
147
                                        {
148
                                                d = dis[i];
149
                                                k = i;
150
                                        }
151
                                }
152
                        }
153
                        j = k;
154
                }
155

    
156
                /*
157
                 * Preorder Tour of MST
158
                 */
159
//        #define VISITED(x) jorder[x]
160
//        #define NQ(x) arc[l++] = x
161
//        #define DQ()  arc[--l]
162
//        #define EMPTY (l==0)
163
                        
164
                for (i = 0; i < n; i++) jorder[i] = 0;
165
                k = 0; l = 0; d = 0; 
166
                arc[l++] = 0;
167
                while (l != 0)
168
                {
169
                        i = arc[--l];
170
                        if (!(jorder[i] == 0))
171
                        {
172
                                iorder[k++] = i;
173
                                jorder[i]  = 1;                        
174
                                for (j = 0; j < n - 1; j++) /* push all kids of i */
175
                                {
176
                                        if (i == mst[j]%n)
177
                                                arc[l++] = mst[j]/n; 
178
                                }        
179
                        }
180
                }
181
        }
182
        
183
        int mod(int a, int b) {
184
                return (a % b);
185
        }
186
        
187
        double D(int f, int t) {
188
                return odMatrix[f][t];
189
        }
190

    
191

    
192
        /*
193
         * Local Search Heuristics
194
         *  b-------a        b       a
195
         *  .       .   =>   .\     /.
196
         *  . d...e .        . e...d .  
197
         *  ./     \.        .       .
198
         *  c       f        c-------f
199
         */
200
        double getThreeWayCost (int[] p)
201
        {
202
                int a, b, c, d, e, f;
203
                a = iorder[mod(p[0]-1, n)]; b = iorder[p[0]];
204
                c = iorder[p[1]];   d = iorder[mod(p[1]+1,n)];
205
                e = iorder[p[2]];   f = iorder[mod(p[2]+1,n)];
206
                
207
                // b va a ser el nuevo origen => sumamos su distancia a nuestro origen fijo
208
                double Dant, Dnuevo, Ddiff = 0;
209
                Dant = odMatrix[origenTSP][iorder[0]];
210
                Dnuevo = odMatrix[origenTSP][b];
211
                Ddiff = Dnuevo - Dant;
212

    
213
                // tambi?n hay que mirar la distancia al destino desde el ?ltimo punto
214
                int fin=n-1;
215
                if (g_bVolverOrigen)
216
                {        
217
                        // p[2] va a ser el pr?ximo ?ltimo punto 
218
                        Dant = D(iorder[fin], origenTSP);
219
                        Dnuevo = D(iorder[p[2]], origenTSP);
220
                        Ddiff = Ddiff + Dnuevo - Dant;
221
                }
222
                else
223
                {
224
                        Dant = D(iorder[fin], destinoTSP);
225
                        Dnuevo = D(iorder[p[2]], destinoTSP);
226
                        Ddiff = Ddiff + Dnuevo - Dant;
227
                }
228
                
229

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

    
233
                // A?ADIR DIFERENCIA DE COSTE A LOS NODOS INMOVILES. (ORIGEN Y ?DESTINO?)
234
        }
235

    
236
        void doThreeWay (int[] p)
237
        {
238
                int i, count, m1, m2, m3, a, b, c, d, e, f;
239
                int index;
240
                a = mod(p[0]-1,n); b = p[0];
241
                c = p[1];   d = mod(p[1]+1,n);
242
                e = p[2];   f = mod(p[2]+1,n);        
243
                
244
                m1 = mod(n+c-b,n)+1;  /* num cities from b to c */
245
                m2 = mod(n+a-f,n)+1;  /* num cities from f to a */
246
                m3 = mod(n+e-d,n)+1;  /* num cities from d to e */
247

    
248
                count = 0;
249
                /* [b..c] */
250
                for (i = 0; i < m1; i++)
251
                {
252
                        index = mod(i+b,n);
253
                        jorder[count++] = iorder[index];
254
                }
255

    
256
                /* [f..a] */
257
                for (i = 0; i < m2; i++)
258
                {
259
                        index = mod(i+f,n);
260
                        jorder[count++] = iorder[index];
261
                }
262

    
263
                /* [d..e] */
264
                for (i = 0; i < m3; i++)
265
                {
266
                        index = mod(i+d,n);
267
                        jorder[count++] = iorder[index];
268
                }
269

    
270
                /* copy segment back into iorder */
271
                for (i = 0; i < n; i++) iorder[i] = jorder[i];
272
        }
273

    
274
        /*
275
         *   c..b       c..b
276
         *    \/    =>  |  |
277
         *    /\        |  |
278
         *   a  d       a  d
279
         */
280
        double getReverseCost (int[] p)
281
        {
282
                int a, b, c, d;
283
                a = iorder[mod(p[0]-1,n)]; b = iorder[p[0]];
284
                c = iorder[p[1]];   d = iorder[mod(p[1]+1,n)];
285
                
286
                double Dant = 0, Dnuevo = 0, Ddiff = 0;
287

    
288
                if (p[0]==0 || p[1]==0)
289
                {
290
                        Dant = D(origenTSP,iorder[0]);
291
                        if (p[0]==0)
292
                                Dnuevo = D(origenTSP, c);
293
                        else
294
                                Dnuevo = D(origenTSP, b);
295
                        Ddiff = Dnuevo-Dant;
296
                }
297
                int fin = n-1;
298
                if (g_bVolverOrigen) // Miramos la distancia al cero
299
                {                
300
                        // iorder[p[1]] o iorder[p[0]] va a acabar en la ?ltima posici?n
301
                        if (p[0]==fin || p[1] == fin) // tambi?n hay que mirar la distancia al destino desde el ?ltimo punto
302
                        {
303
                                Dant = D(iorder[fin], origenTSP);
304
                                if (p[0]==fin)
305
                                        Dnuevo = D(c,origenTSP);
306
                                else
307
                                        Dnuevo = D(b, origenTSP);
308
                                Ddiff = Ddiff + Dnuevo - Dant;
309

    
310
                        } 
311
                }
312
                else
313
                {
314
                        if (p[0]==fin || p[1] == fin) // tambi?n hay que mirar la distancia al destino desde el ?ltimo punto
315
                        {
316
                                Dant = D(iorder[fin], destinoTSP);
317
                                if (p[0]==fin)
318
                                        Dnuevo = D(c,destinoTSP);
319
                                else
320
                                        Dnuevo = D(b, destinoTSP);
321
                                Ddiff = Ddiff + Dnuevo - Dant;
322

    
323
                        } 
324
                } 
325

    
326
                return (D(d,b) + D(c,a) - D(a,b) - D(c,d) + Ddiff);
327
                /* add cost between c and b if non symetric TSP */ 
328
//         A?ADIR DIFERENCIA DE COSTE A LOS NODOS INMOVILES. (ORIGEN Y ?DESTINO?)
329
        }
330

    
331
        void doReverse(int[] p)
332
        {
333
                int i, nswaps, first, last, tmp;
334

    
335
                /* reverse path b...c */
336
                nswaps = (mod(p[1]-p[0],n)+1)/2;
337
                for (i = 0; i < nswaps; i++)
338
                {
339
                        first = mod(p[0]+i, n);
340
                        last  = mod(p[1]-i, n);
341
                        tmp   = iorder[first];
342
                        
343
                        iorder[first] = iorder[last];
344
                        iorder[last]  = tmp;
345
                }
346
        }
347

    
348
        double annealing()
349
        {
350
                int[] p;
351
                int    i=1, j, pathchg;
352
                int    numOnPath, numNotOnPath;
353
                double    pathlen, bestlen;
354
                double energyChange, T;
355

    
356
                /*
357
                 * Set up first eulerian path iorder to be improved by
358
                 * simulated annealing. 
359
                 */
360
                /* bool conEulerian = true;
361
                if (conEulerian)
362
                         findEulerianPath();  */
363

    
364

    
365
                pathlen = pathLength(); // (iorder); 
366
                bestlen = pathlen;
367
                Random rnd = new Random();
368

    
369
                for (T = T_INIT; T > FINAL_T; T *= COOLING)  /* annealing schedule */
370
                {
371
                        pathchg = 0;
372
                        for (j = 0; j < TRIES_PER_T; j++)
373
                        {
374
                                do {
375
                                        p[0] = rnd.nextInt(n);
376
                                        p[1] = rnd.nextInt(n);
377
                                        if (p[0] == p[1]) p[1] = mod(p[0]+1,n); /* non-empty path */
378
                                        numOnPath = mod(p[1]-p[0],n) + 1;
379
                                        numNotOnPath = n - numOnPath;
380
                                } while (numOnPath < 2 || numNotOnPath < 2) ; /* non-empty path */
381
                                
382
                                
383
                                if ((rnd.nextInt() % 2) == 0) /*  threeWay */
384
                                {
385
                                        do {
386
                                                p[2] = mod(rnd.nextInt(numNotOnPath)+p[1]+1,n);
387
                                        } while (p[0] == mod(p[2]+1,n)); /* avoids a non-change */
388

    
389
                                        energyChange = getThreeWayCost (p);
390
                                        if ((energyChange < 0) || (RREAL < Math.exp(-energyChange/T)))
391
                                        {
392
                                                pathchg++;
393
                                                pathlen += energyChange;
394
                                                doThreeWay (p); 
395
                                        }
396
                                }
397
                                else            /* path Reverse */
398
                                {
399
                                        energyChange = getReverseCost (p);
400
                                        if ((energyChange < 0) || (RREAL < Math.exp(-energyChange/T)))
401
                                        {
402
                                                pathchg++;
403
                                                pathlen += energyChange;
404
                                                doReverse(p); 
405
                                        }
406
                                }
407
                                if (pathlen < bestlen)
408
                                {
409
                                        pathlen = pathLength(); // Calculamos la distancia de verdad, por si no interesa
410
                                                                                        // hacer el cambio. pathlen es en realidad una estimaci?n
411
                                        if (pathlen < bestlen)
412
                                        {
413
                                                bestlen = pathlen;
414
                                                for (i=0; i< n; i++)
415
                                                        vTSP[i+1] = iorder[i];
416
                                        }
417
                                }
418
                                if (pathchg > IMPROVED_PATH_PER_T) break; /* finish early */
419
                        }   
420
                        if (pathchg == 0) break;   /* if no change then quit */
421
                }
422
                return bestlen;
423
        }
424

    
425
}