/**************************** min.c ******************************/ /* A program for computing mininal energy of polygonal knots */ /* Version 2.1 */ /********************** Ying-Qing Wu, 5/95 ***********************/ #include #include #define size 1010 /* max number of vertices */ #define minlambda 0.01 float badrunlimit= 0.05; /* change status if badrun exceed this*runnum */ int add_vtx = 0; /* number of vertices to be added */ int printstyle = 0; /* "1" to print also gradient and edge length */ float turnpoint = -1; char method = 'm'; typedef double vec[3]; typedef vec knt[size]; int runnum, vnum; knt knot, oldknot, vtr, grad, oldgrad; double derivative[size], lenvtr[size], mindistance[size]; double dist[size][size], rate[size][size]; vec minvtr[size][size]; double mindist, maxgrad, maxderiv, enr, enr_vert, enr_edge; vec u, u1, u2; FILE *fp; char infile[20], outfile[20]; /* functions */ double min(int, double *, double *); /* min dist from pt to edge i */ void edgedist(); /* min vector from edge to edge */ void gradient(); /* grad of energy as ftn of vertices*/ void edgevtr(); /* vector from knot[i] to knot[i+1] */ void findderiv(); /* max derivative of gradient */ double energy(); /* energy of the knot */ double vert_energy(); /* vertex energy of the knot */ double edge_energy(); /* edge energy of the knot */ int getfile(); /* input of knot */ void printfile(); /* write result into file */ void add_vertex(); /* add vertices to the knot */ double stdcirc(int); /* compute energies of regular n-gon*/ void help(); /* print help menu */ void run(); /* run the minimizer */ void find_rate(); /* compute position of min vector */ /* vector calculation tools */ double *add(double *, double *, double *); double *subt(double *, double *, double *); double *cross(double *, double *, double *); double *mult(double, double *, double *); double dot(double *, double *); double norm(double *); void assign(double *, double *); int main(int argc, char *argv[]) { char cmd[80], dumb[10], *style[]={"short","long"}; int stdvnum; if (argc>1) strcpy(infile, argv[1]), getfile(); if (argc>2) strcpy(outfile, argv[2]); while (1) { printf ("Enter a command (\"h\" for help): "); gets(cmd); switch (cmd[0]) { case 'h': help(); break; case 'q': exit(0); case 'a': case 'd': if (cmd[0] == 'd') add_vtx = vnum; else if(sscanf(cmd, "%s %d", dumb, &add_vtx)<2) add_vtx = 0; add_vertex(); break; case 's': sscanf(cmd, "%s %d", dumb, &stdvnum); printf(" Min-dist energy: %14.8f\n", stdcirc(stdvnum)); printf(" Edge energy: %14.8f\n", enr_edge); printf(" Vertex energy: %14.8f\n", enr_vert); break; case 'f': sscanf(cmd, "%s %s %s", dumb, infile, outfile); getfile(); break; case 'r': if (sscanf(cmd, "%s %d", dumb, &runnum)==1) runnum = 0; run(); break; case 'p': printstyle = (printstyle == 0) ? 1 : 0; printf(" Set output style to %s print\n",style[printstyle]); break; case 'm': method = (method == 'm') ? 'e' : 'm'; printf(" Set flow method to %c\n", method); break; case 't': sscanf(cmd, "%s %f", dumb, &turnpoint); printf(" Set turning point to %1.2f\n",turnpoint); break; default: printf("Wrong command. Please try again.\n"); break; } } } void help() { printf( "\nChoose one of the following:\n" " file knot1 knot2: set knot1 as input file and knot2 as output file\n" " run n: run the minimizer n times\n" " add n: add n vertices to the knot\n" " double: double the vertices, = add vert_number \n" " std n: compute the energy of a standard n-gon\n" " method: toggle flow method between MD grad and E grad\n" " pstyle: toggle between short (default) and long output\n" " tpoint x: set turning point to x (between 0 and 1)\n" " help: print this help menu\n" " quit: quit min\n" ); } void run() { int i,ctr,badrun; double move, temp, old_enr, badlim, lambda=1; badlim = badrunlimit*runnum; printf(" \n Number of edges: %d\n", vnum); for (badrun = 0, ctr = 0; ctr=old_enr && ctr>1) badrun++; if (badrun>3*badlim && lambda > minlambda) { lambda = 0.9*lambda; badrun = 2*badlim; } temp = (1.0*ctr)/runnum; printf("%-8d %14.8f \n", ctr, enr); findderiv(); for (i=0; i temp)) move = lambda/derivative[i]; else move = lambda/maxderiv; assign(knot[i],add(oldknot[i], mult(move,oldgrad[i],u),u1)); } } printf("%-8d %14.8f\n", ctr, energy()); printfile(); } void add_vertex() { int i, j; if (vnum == 0) { printf("Please specify a knot file.\n"); return; } while (add_vtx > 0) { j = (add_vtx > vnum) ? 0 : vnum - add_vtx; for (i = vnum-j; i > 0; i--) { if (i0 || j m[k]) {a = m[k]; n =k;} if (n==0) {rate[i][j] = s[0]; rate[j][i]=0;} if (n==1) {rate[i][j] = s[1]; rate[j][i]=1;} if (n==2) {rate[i][j] = 0; rate[j][i]=s[2];} if (n==3) {rate[i][j] = 1; rate[j][i]=s[3];} } } } } void edgedist(void) /* calculate rate, dist, and mindist */ { int i,j,k,n; find_rate(); for (i=0; i dist[i][j]) mindistance[n] = dist[i][j]; } } else dist[i][j] = dist[j][i] = 0; if (mindist == 0 || mindist > dist[i][j] && dist[i][j] != 0) mindist = dist[i][j]; } } void gradient(void) /* calculate grad[] */ { double r,t; register double d; vec v; int i,j,k; for (i=0; i< vnum; i++) for (j=0; j<3; j++) oldgrad[i][j] = grad[i][j], grad[i][j] = 0; for (maxgrad = 0, i=0; i0 || j