Subversion Repositories wimsdev

Rev

Rev 8177 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
10 reyssat 1
/*    Copyright (C) 1998-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis
2
 *
3
 *  This program is free software; you can redistribute it and/or modify
4
 *  it under the terms of the GNU General Public License as published by
5
 *  the Free Software Foundation; either version 2 of the License, or
6
 *  (at your option) any later version.
7
 *
8
 *  This program is distributed in the hope that it will be useful,
9
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 *  GNU General Public License for more details.
12
 *
13
 *  You should have received a copy of the GNU General Public License
14
 *  along with this program; if not, write to the Free Software
15
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16
 */
17
 
18
 /* Finds the shortest paths linking given points. */
19
 
7676 bpr 20
/* fast algorithm is not ready. */
10 reyssat 21
 
7676 bpr 22
#define MAX_POINTS 32 /* cannot exceed number of bits in long */
23
#define MAX_DIM 10 /* dimension limit */
24
#define MAX_SHORT 20 /* limit of registered shortest paths */
10 reyssat 25
 
8177 bpr 26
 
10 reyssat 27
#include <stdio.h>
28
#include <stdlib.h>
29
#include <string.h>
30
#include <math.h>
31
#include <ctype.h>
8177 bpr 32
#include "../config.h"
10 reyssat 33
 
34
int  pointcnt,dimension,first,last,count,shortcnt;
7676 bpr 35
/* style = 0: loop to the start
36
 *    1: arbitrary open path
37
 *    2: open path with fixed start
38
 *    3: open path with fixed end
39
 *    4: open path with fixed start and end */
10 reyssat 40
int style=0;
7676 bpr 41
int fast=0; /* fast algo if 1, no rigor */
10 reyssat 42
int optimize=0;
43
char *input;
44
double dist[MAX_POINTS][MAX_POINTS];
45
double ds[MAX_POINTS];
46
double coord[MAX_POINTS][MAX_DIM];
47
double shortest;
48
double tolerance; /* to compensate floating rounding error in comparison */
7676 bpr 49
double distmin; /* minimum of distance between two points */
10 reyssat 50
double firstlast; /* distance between first and last */
51
int shpath[MAX_SHORT][MAX_POINTS];
52
int chain[MAX_POINTS];
53
 
7676 bpr 54
/* reverse a subchain */
10 reyssat 55
void reverse(int i, int j)
56
{
12248 bpr 57
  int k,t;
58
  for(k=0;k<(j-i+1)/2;k++) {
59
    t=chain[i+k]; chain[i+k]=chain[j-k];
60
    chain[j-k]=t;
61
  }
10 reyssat 62
}
63
 
7676 bpr 64
/* move point i to position j */
10 reyssat 65
void reinsert(int i, int j)
66
{
12248 bpr 67
  int t;
68
  t=chain[i];
69
  if(j>i) {
70
    j--;
71
    memmove(chain+i,chain+i+1,(j-i)*sizeof(chain[0]));
72
    chain[j]=t;
73
  }
74
  else {
75
    memmove(chain+j+1,chain+j,(i-j)*sizeof(chain[0]));
76
    chain[j]=t;
77
  }
10 reyssat 78
}
79
 
80
int _fcalc(void)
81
{
12248 bpr 82
  int modif;
83
  int i,j;
7676 bpr 84
 
12248 bpr 85
  modif=0;
7676 bpr 86
/* four-configuration optimize */
12248 bpr 87
  for(i=1;i<pointcnt-2;i++) {
88
    for(j=i+1;j<pointcnt-1;j++) {
89
        if(dist[chain[i-1]][chain[i]]+dist[chain[j]][chain[j+1]]
90
           >dist[chain[i-1]][chain[j]]+dist[chain[i]][chain[j+1]]
91
           +tolerance) {
92
          reverse(i,j); modif=1;
93
        }
10 reyssat 94
    }
12248 bpr 95
  }
7676 bpr 96
/* Point relink */
12248 bpr 97
  for(i=1;i<pointcnt-1;i++) {
98
    double dd;
99
    int th;
100
    th=chain[i];
101
    dd=dist[chain[i-1]][th]+dist[th][chain[i+1]]
102
      -dist[chain[i-1]][chain[i+1]];
103
    for(j=0;j<pointcnt-1;j++) {
104
      if(j==i || j==i-1) continue;
105
      if(dd>dist[chain[j]][th]+dist[chain[j+1]][th]
106
           -dist[chain[j]][chain[j+1]]+tolerance) {
107
        reinsert(i,j+1); modif=1;
7676 bpr 108
      }
10 reyssat 109
    }
12248 bpr 110
  }
111
  for(i=0;i<pointcnt;i++) shpath[shortcnt][i]=chain[i];
112
  shortcnt+=modif; return modif;
10 reyssat 113
}
114
 
115
void fastcalc(void)
116
{
12248 bpr 117
  int i,j;
7676 bpr 118
 
12248 bpr 119
  for(i=0;i<pointcnt;i++) chain[i]=i;
120
  shortcnt=1;
121
  for(i=0,j=1;i<10 && j!=0;i++) j=_fcalc();
7676 bpr 122
 
12248 bpr 123
  for(shortest=0,i=0;i<pointcnt-1;i++) shortest+=dist[chain[i]][chain[i+1]];
124
  if(style==0) shortest+=dist[chain[0]][chain[pointcnt-1]];
125
  for(i=0;i<pointcnt;i++) shpath[0][i]=chain[i];
10 reyssat 126
}
127
 
128
void _calc(int level, double dis, long used, int utab[])
129
{
12248 bpr 130
  int current[MAX_POINTS];
131
  double dd,d1,d3,d2,dthis;
132
  int i;
133
  long l;
10 reyssat 134
 
12248 bpr 135
  dd=dis; d1=d2=d3=0;
136
  if(level<pointcnt-2) {
137
    int j,b,prec;
138
    double btab[MAX_POINTS];
139
    if(level>0) prec=utab[level-1]; else prec=0;
140
    if(level>2) {
141
      for(i=0;i<level-2;i++)
142
        btab[i]=dist[utab[i]][prec];
143
      if(level>3) {
144
        d1=ds[level-4]+ds[level-3]+ds[level-2];
145
        d3=dist[utab[level-4]][utab[level-2]]
146
          +ds[level-2]
147
          +dist[prec][utab[level-3]];
148
        d2=dist[utab[level-4]][prec]
149
          +dist[prec][utab[level-3]]
150
          +ds[level-3];
7676 bpr 151
      }
12248 bpr 152
  }
153
  if(level==0 || (level==1 && style==0)) b=last+1; else b=0;
154
  for(i=b,l=(long) 1<<b;i<pointcnt;i++,l<<=1) {
155
    if(used&l) continue;
156
    dthis=dist[prec][i];
157
    if(optimize) {
158
      if(style==0) {
159
        if(level>1 &&
160
             firstlast+dthis>dist[prec][last]+dist[first][i])
161
          continue;
162
        }
163
        else if(level>0) {
7676 bpr 164
/* cut differently */
12248 bpr 165
          if(style==1 && dthis>firstlast) continue;
7676 bpr 166
/* switch with first */
12248 bpr 167
          if((style&1) && level>1 && dist[first][i]<dthis) continue;
7676 bpr 168
/* switch with last */
12248 bpr 169
          if(style<3 && dist[prec][last]<dthis) continue;
170
        }
7676 bpr 171
/* already too long */
12248 bpr 172
        if(level>0 && shortcnt>0 &&
7676 bpr 173
             dthis+dis+distmin*(pointcnt-level-1)>shortest)
12248 bpr 174
          continue;
7676 bpr 175
/* four-config optimize */
12248 bpr 176
        for(j=0;j<=level-3;j++) {
177
          if(ds[j]+dthis>btab[j]+dist[utab[j+1]][i])
178
            goto next;
179
        }
7676 bpr 180
/* five-config optimize */
12248 bpr 181
        if(level>3 &&
7676 bpr 182
             (d1+dthis>d2+dist[utab[level-2]][i] ||
183
            d1+dthis>d3+dist[utab[level-3]][i]))
12248 bpr 184
          continue;
7676 bpr 185
/* try prec elsewhere in the chain */
12248 bpr 186
        if(level>3) {
187
          double dt;
188
          dt=dist[prec][i]+ds[level-2]-dist[utab[level-2]][i];
189
          for(j=0;j<level-3;j++) {
190
              if(dt>dist[prec][utab[j]]+dist[prec][utab[j+1]]-ds[j])
191
                goto next;
7676 bpr 192
          }
12248 bpr 193
        }
7676 bpr 194
      }
12248 bpr 195
      memmove(current,utab,level*sizeof(utab[0]));
196
      current[level]=i;
197
      if(level>0) {dd=dis+dthis; ds[level-1]=dthis;}
198
      else {
199
        first=i; firstlast=dist[first][last];
200
      }
201
      _calc(level+1,dd,used|l,current);
202
      next: ;
203
    }
7676 bpr 204
 
12248 bpr 205
  }
206
  else {
207
    count++;
208
    for(i=0,l=(long) 1;i<pointcnt && used&l; i++,l<<=1);
209
    if(i>=pointcnt) {
210
      printf("ERROR: Internal error.\n"); exit(1);
10 reyssat 211
    }
12248 bpr 212
    utab[pointcnt-2]=i; utab[pointcnt-1]=last;
213
    dis+=dist[utab[pointcnt-3]][i]+dist[i][last];
214
    if(shortest==0 || dis<shortest-tolerance) {
215
      shortest=dis; shortcnt=0;
216
      memmove(shpath[shortcnt++],utab,MAX_POINTS*sizeof(utab[0]));
10 reyssat 217
    }
12248 bpr 218
    else if(dis<shortest+tolerance && shortcnt<MAX_SHORT)
219
      memmove(shpath[shortcnt++],utab,MAX_POINTS*sizeof(utab[0]));
220
  }
10 reyssat 221
}
222
 
7676 bpr 223
/* main calculation loops */
10 reyssat 224
void calc(void)
225
{
12248 bpr 226
  int i;
227
  long used;
228
  int utab[MAX_POINTS];
10 reyssat 229
 
12248 bpr 230
  if(fast) {
231
    fastcalc(); return;
232
  }
233
  count=0; shortest=0; shortcnt=0;
234
  memset(utab,0,sizeof(utab));
235
  switch(style) {
236
    case 0: { /* loop to the start */
237
      first=0; utab[0]=0;
238
      for(i=1;i<pointcnt;i++) {
239
        last=i; used=(long) 1<<i; used|=(long) 1;
240
        firstlast=dist[first][last];
241
        _calc(1,firstlast,used,utab);
242
      }
243
      break;
10 reyssat 244
    }
12248 bpr 245
    case 1: { /* arbitrary open path */
246
      for(i=0;i<pointcnt;i++) {
247
        last=i; used=(long) 1<<i;
248
        _calc(0,0,used,utab);
7676 bpr 249
      }
12248 bpr 250
      break;
251
    }
252
    case 2: { /* open path with fixed start */
253
      first=0; utab[0]=0;
254
        for(i=1;i<pointcnt;i++) {
255
          last=i; used=(long) 1|(1<<i);
256
          firstlast=dist[0][last];
7676 bpr 257
          _calc(1,0,used,utab);
12248 bpr 258
        }
259
        break;
10 reyssat 260
    }
12248 bpr 261
    case 3: { /* open path with fixed end */
262
      last=0; used=(long) 1;
263
      _calc(0,0,used,utab);
264
      break;
265
    }
266
    case 4: { /* open path with fixed start and end */
267
      first=0; utab[0]=0;
268
      last=pointcnt-1; used=(long) 1|(1<<last);
269
      firstlast=dist[first][last];
270
      _calc(1,0,used,utab);
271
      break;
272
    }
273
  }
10 reyssat 274
}
275
 
7676 bpr 276
/* Print the result */
10 reyssat 277
void printresult(void)
278
{
12248 bpr 279
  int i,j;
10 reyssat 280
 
12248 bpr 281
  printf("%f %d %d\n",shortest,shortcnt,count);
282
  for(j=0;j<shortcnt;j++) {
283
    for(i=0;i<pointcnt;i++) printf("%d ",shpath[j][i]+1);
284
    printf("\n");
285
  }
10 reyssat 286
}
287
 
7676 bpr 288
/* prepare distance table */
10 reyssat 289
void makedist(void)
290
{
12248 bpr 291
  int i,j,k;
292
  double d;
10 reyssat 293
 
12248 bpr 294
  distmin=-1;
295
  for(i=0;i<pointcnt-1;i++) {
296
    for(j=i+1;j<pointcnt;j++) {
297
      d=0;
298
      for(k=0;k<dimension;k++) {
299
        d+=pow(coord[i][k]-coord[j][k],2);
7676 bpr 300
      }
12248 bpr 301
      d=sqrt(d); dist[i][j]=dist[j][i]=d;
302
      if(distmin<0 || distmin>d) distmin=d;
10 reyssat 303
    }
12248 bpr 304
  }
305
  tolerance=distmin*0.000001;
10 reyssat 306
}
307
 
308
int main(int argc, char *argv[])
309
{
12248 bpr 310
  char *p,*p2,*p3;
311
  int dim;
312
  input=getenv("wims_exec_parm");
7676 bpr 313
/* nothing to do if no problem */
12248 bpr 314
  if(input==NULL || *input==0) return 0;
10 reyssat 315
 
12248 bpr 316
  for(p=input+strlen(input);p>input && isspace(*(p-1));p--);
317
  *p=0; dimension=0;
318
  for(pointcnt=0,p=input;*p!=0 && pointcnt<MAX_POINTS;p=p3) {
319
    p2=strchr(p,'\n');
320
    if(p2==NULL) p3=p+strlen(p);
321
    else {p3=p2+1; *p2=0;}
322
    dim=0;
323
    for(p2=strchr(p,','); p2!=NULL && dim<MAX_DIM;
324
        p=p2+1,dim++,p2=strchr(p,',')) {
325
      *p2=0; coord[pointcnt][dim]=strtod(p,NULL);
10 reyssat 326
    }
12248 bpr 327
    if(dim<MAX_DIM) coord[pointcnt][dim++]=strtod(p,NULL);
328
    if(dim<2) continue; /* bad line */
329
    if(dimension==0) dimension=dim;
330
    pointcnt++;
331
  }
332
  if(pointcnt<3) {
333
    printf("ERROR: Not enough points.\n"); exit(1);
334
  }
335
  p=getenv("w_shortpath_style");
336
  if(p!=NULL) style=atoi(p);
337
  if(style<0 || style>4) style=0;
338
  makedist();
339
  optimize=1; calc();printresult();
10 reyssat 340
/*    optimize=0; calc();printresult();
12248 bpr 341
*/
342
  return 0;
10 reyssat 343
}
344