/*************************************/ /* Utility subroutines for Argon 2.0 */ /*************************************/ #include "utils.h" /* return pseudo random number on (0,1) */ double frandom() { return ((random()+0.5)/pow(2.,31.)); } /* end frandom() */ /* generate n normal variables and store in x[] */ void randnorm (int n, double x[]) { int i; double s1, s2; for (i=0; inext != NULL) && strncmp(p->next->token, token, MAX_TOKEN_SIZE-1); p = p->next ); if ( p->next == NULL ) { /* look for free space */ for (q=mempool+1; qtoken)==(char)0 ) { p->next = q; q->next = NULL; strncpy (q->token, token, MAX_TOKEN_SIZE-1); q->init_time = TIME; return(TIME); } printf("**error watch(): mempool %d records all used up.\n", MAX_RECORD-1); return(-1.); } else { printf("**error watch(): token name \"%s\" already used.\n", token); return(-1.); } /* return the time elapsed in seconds */ case 1: for ( p = mempool; (p->next != NULL) && strncmp(p->next->token, token, MAX_TOKEN_SIZE-1); p = p->next); if ( p->next == NULL ) { printf("**error watch(): token name \"%s\" not found.\n", token); return(-1.); } else return (TIME - p->next->init_time); /* return the time elapsed in seconds */ /* and refresh the watch's startpoint */ case 2: for ( p = mempool; (p->next != NULL) && strncmp(p->next->token, token, MAX_TOKEN_SIZE-1); p = p->next); if ( p->next == NULL ) { printf("**error watch(): token name \"%s\" not found.\n", token); return(-1.); } else { cc = p->next->init_time; p->next->init_time = TIME; return (TIME - cc); } /* destroy the record and free resources */ case 3: for ( p = mempool; (p->next != NULL) && strncmp(p->next->token, token, MAX_TOKEN_SIZE-1); p = p->next); if ( p->next == NULL ) { printf("**error watch(): token name \"%s\" not found.\n", token); return(-1.); } else { cc = p->next->init_time; *(p->next->token) = (char)0; p->next = p->next->next; return (TIME - cc); } default: printf("**error watch(): 0:init 1:check 2:refresh 3:destroy.\n"); return(-1.); } } /* end watch() */ #undef TIME #undef MAX_RECORD #undef MAX_TOKEN_SIZE char *earth_time (double seconds) { const struct time_unit { char *name; double scale; } earthman[] = { {"s", 1}, {"min", 60}, {"hr", 60}, {"day", 24}, {"month", 30}, {"year", 365} }; static char time[128], *p; int i, max=sizeof(earthman)/sizeof(struct time_unit); double scale; int denom; seconds /= earthman[0].scale; for (scale=1,i=1; i0; i--) { denom = floor(seconds/scale); if (denom>0) { sprintf(p, "%d %s, ", denom, earthman[i].name); while((*p)!=(char)0) p++; } seconds -= denom*scale; scale /= earthman[i].scale; } sprintf(p, "%.3f %s", seconds, earthman[0].name); return(time); } /* earth_time() */ void matran(double A[3][3], double B[3][3]) { B[0][0] = A[0][0]; B[0][1] = A[1][0]; B[0][2] = A[2][0]; B[1][0] = A[0][1]; B[1][1] = A[1][1]; B[1][2] = A[2][1]; B[2][0] = A[0][2]; B[2][1] = A[1][2]; B[2][2] = A[2][2]; return; } /* end matran() */ void matadd(double A[3][3], double B[3][3], double C[3][3]) { C[0][0] = A[0][0] + B[0][0]; C[0][1] = A[0][1] + B[0][1]; C[0][2] = A[0][2] + B[0][2]; C[1][0] = A[1][0] + B[1][0]; C[1][1] = A[1][1] + B[1][1]; C[1][2] = A[1][2] + B[1][2]; C[2][0] = A[2][0] + B[2][0]; C[2][1] = A[2][1] + B[2][1]; C[2][2] = A[2][2] + B[2][2]; return; } /* end matadd() */ void matsub(double A[3][3], double B[3][3], double C[3][3]) { C[0][0] = A[0][0] - B[0][0]; C[0][1] = A[0][1] - B[0][1]; C[0][2] = A[0][2] - B[0][2]; C[1][0] = A[1][0] - B[1][0]; C[1][1] = A[1][1] - B[1][1]; C[1][2] = A[1][2] - B[1][2]; C[2][0] = A[2][0] - B[2][0]; C[2][1] = A[2][1] - B[2][1]; C[2][2] = A[2][2] - B[2][2]; return; } /* end matsub() */ void matmul(double A[3][3], double B[3][3], double C[3][3]) { C[0][0] = A[0][0]*B[0][0] + A[0][1]*B[1][0] + A[0][2]*B[2][0]; C[0][1] = A[0][0]*B[0][1] + A[0][1]*B[1][1] + A[0][2]*B[2][1]; C[0][2] = A[0][0]*B[0][2] + A[0][1]*B[1][2] + A[0][2]*B[2][2]; C[1][0] = A[1][0]*B[0][0] + A[1][1]*B[1][0] + A[1][2]*B[2][0]; C[1][1] = A[1][0]*B[0][1] + A[1][1]*B[1][1] + A[1][2]*B[2][1]; C[1][2] = A[1][0]*B[0][2] + A[1][1]*B[1][2] + A[1][2]*B[2][2]; C[2][0] = A[2][0]*B[0][0] + A[2][1]*B[1][0] + A[2][2]*B[2][0]; C[2][1] = A[2][0]*B[0][1] + A[2][1]*B[1][1] + A[2][2]*B[2][1]; C[2][2] = A[2][0]*B[0][2] + A[2][1]*B[1][2] + A[2][2]*B[2][2]; return; } /* end matmul() */ double matinv(double A[3][3], double B[3][3]) { double D11,D22,D33,D12,D21,D13,D31,D32,D23,determinant; D11=A[1][1]*A[2][2]-A[1][2]*A[2][1]; D22=A[2][2]*A[0][0]-A[2][0]*A[0][2]; D33=A[0][0]*A[1][1]-A[0][1]*A[1][0]; D12=A[1][2]*A[2][0]-A[1][0]*A[2][2]; D23=A[2][0]*A[0][1]-A[2][1]*A[0][0]; D31=A[0][1]*A[1][2]-A[0][2]*A[1][1]; D13=A[1][0]*A[2][1]-A[2][0]*A[1][1]; D21=A[2][1]*A[0][2]-A[0][1]*A[2][2]; D32=A[0][2]*A[1][0]-A[1][2]*A[0][0]; determinant=A[0][0]*D11+A[0][1]*D12+A[0][2]*D13; B[0][0]=D11/determinant; B[1][1]=D22/determinant; B[2][2]=D33/determinant; B[0][1]=D21/determinant; B[1][2]=D32/determinant; B[2][0]=D13/determinant; B[1][0]=D12/determinant; B[2][1]=D23/determinant; B[0][2]=D31/determinant; return (determinant); } /* end matinv() */ /******************************************/ /* Diagonalize 3x3 real symmetric matrix: */ /* A = Q^T * diag(eigval) * Q, eigval[i] */ /* will be stored in descending order, */ /* Q[i][] forming a right-handed system. */ /******************************************/ #define DIAG3_TINY (1E-12) char *diag3 (double A[3][3], double eigval[3], double Q[3][3]) { static char info[32]; int i; double a, b, c, d, e, module, angle; info[0] = (char) 0; if ( (fabs(A[0][1]-A[1][0]) > DIAG3_TINY) || (fabs(A[0][2]-A[2][0]) > DIAG3_TINY) || (fabs(A[1][2]-A[2][1]) > DIAG3_TINY) ) { strcpy (info, "matrix is not symmetric."); return (info); } else { A[0][1] = (A[0][1]+A[1][0])/2.; A[1][0] = A[0][1]; A[0][2] = (A[0][2]+A[2][0])/2.; A[2][0] = A[0][2]; A[1][2] = (A[1][2]+A[2][1])/2.; A[2][1] = A[1][2]; } /* solve x^3 + a*x^2 + b*x + c = 0: */ a = -A[0][0]-A[1][1]-A[2][2]; b = A[0][0]*A[1][1]+A[0][0]*A[2][2]+A[1][1]*A[2][2]- A[0][1]*A[0][1]-A[0][2]*A[0][2]-A[1][2]*A[1][2]; c = A[0][0]*A[1][2]*A[1][2]+A[1][1]*A[0][2]*A[0][2]+ A[2][2]*A[0][1]*A[0][1]-A[0][0]*A[1][1]*A[2][2]; d = 36*a*b-108*c-8*a*a*a; e = 12*b*b*b-3*b*b*a*a-54*a*b*c+81*c*c+12*a*a*a*c; if (e > DIAG3_TINY) { strcpy (info, "imaginary eigenvalues."); return (info); } else e = 12*sqrt(fabs(e)); module = sqrt(d*d+e*e); angle = (fabs(module)= eigval[1] >= eigval[2] */ if (eigval[0]=1;i--) { if (arr[i] <= a) break; arr[i+1]=arr[i]; idx[i+1]=idx[i]; } arr[i+1]=a; idx[i+1]=b; } if (!jstack) return; ir=istack[jstack]; l=istack[jstack-1]; jstack -= 2; } else { k=(l+ir) >> 1; SWAP(arr[k],arr[l+1]) SWAPi(idx[k],idx[l+1]) if (arr[l+1] > arr[ir]) { SWAP(arr[l+1],arr[ir]) SWAPi(idx[l+1],idx[ir]) } if (arr[l] > arr[ir]) { SWAP(arr[l],arr[ir]) SWAPi(idx[l],idx[ir]) } if (arr[l+1] > arr[l]) { SWAP(arr[l+1],arr[l]) SWAPi(idx[l+1],idx[l]) } i=l+1; j=ir; a=arr[l]; b=idx[l]; for (;;) { do i++; while (arr[i] < a); do j--; while (arr[j] > a); if (j < i) break; SWAP(arr[i],arr[j]) SWAPi(idx[i],idx[j]) } arr[l]=arr[j]; arr[j]=a; idx[l]=idx[j]; idx[j]=b; jstack += 2; if (jstack > NSTACK) { printf ("NSTACK too small in sort2."); exit(1); } if (ir-i+1 >= j-l) { istack[jstack]=ir; istack[jstack-1]=i; ir=j-1; } else { istack[jstack]=j-1; istack[jstack-1]=l; l=i; } } } } #undef M #undef NSTACK #undef SWAP #undef SWAPi #ifdef QUICKSORT_TEST #define K 6 void main() { double a[K] = {0.1, -0.2, 3.6, 1.8, 9.9, -21.}, c[K]; int idx[K], i; for (i=0; inext != NULL) && strncmp(p->next->token, token, MAX_SCHEDULE_TOKEN_SIZE-1); p = p->next ); if ( p->next != NULL ) { printf("add_schedule(): token name \"%s\" already used.\n", token); exit(1); } /* look for free pointer space in schpool[] */ for (q=schpool+1; qtoken) == '\0') { p->next = q; q->next = NULL; strncpy (q->token, token, MAX_SCHEDULE_TOKEN_SIZE-1); q->token[MAX_SCHEDULE_TOKEN_SIZE-1] = '\0'; j = 0; /* total number of control points */ pair_start = 1; /* at the start of a control record */ for (c=buf; (*c=='\t')||(*c==' '); c++); for (; (j='0')&&(*c<='9')) || (*c=='-') || (*c=='+') ) { if ( pair_start ) /* no control time is given */ tmp[0][j] = SCHEDULE_NONSENSE; tmp[1][j] = atof(c); /* control values */ pair_start = 1; /* end of this pair */ j++; } else if ( ((*c=='T') || (*c=='t')) && pair_start ) { /* explicit control time */ tmp[0][j] = atof(c+1); pair_start = 0; /* wait for value input */ } else if ( ((*c=='F') || (*c=='f')) && pair_start ) { /* fractional control time */ tmp[0][j] = tmin + (tmax-tmin)*atof(c+1); pair_start = 0; } else { printf ("add_schedule: cannot parse substring " "\"%s\".\n", c); exit(1); } } if (j >= MAX_SCHEDULE_N) { printf("add_schedule: out of temporary storage" " MAX_SCHEDULE_N = %d\n" "for \"%s\".\n", MAX_SCHEDULE_N, buf); exit(1); } q->n = j; q->s = malloc(2*j*sizeof(double)); if (tmp[0][0] == SCHEDULE_NONSENSE) tmp[0][0] = tmin; if (tmp[0][j-1] == SCHEDULE_NONSENSE) tmp[0][j-1] = tmax; for (i=1; inontrivial=i=0; is[2*i] = tmp[0][i]; q->s[2*i+1] = tmp[1][o[i]]; q->nontrivial = q->nontrivial || (fabs(q->s[2*i+1]-q->s[1]) > SCHEDULE_TINY); } return (q); } printf("add_schedule(): schpool %d pointer slots all used up.\n", MAX_SCHEDULES-1); exit(1); return(NULL); } /* return add_schedule() */ double schedule (char token[], double t) { int i; struct schedule_list *q; for ( q = schpool; (q->next != NULL) && strncmp(q->next->token, token, MAX_SCHEDULE_TOKEN_SIZE-1); q = q->next ); if (q->next == NULL) { printf("schedule: token name \"%s\" not found.\n", token); exit (1); } q = q->next; if ( !(q->nontrivial) ) return (q->s[1]); if (t <= q->s[0]) return (q->s[1]); if (t >= q->s[2*q->n-2]) return (q->s[2*q->n-1]); for (i=0; in-1; i++) if ( (t >= q->s[2*i]) && (t < q->s[2*i+2]) ) break; if ( fabs(q->s[2*i] - q->s[2*i+2]) < SCHEDULE_TINY ) return( (q->s[2*i+1] + q->s[2*i+3]) / 2 ); else return (q->s[2*i+1] + (q->s[2*i+3] - q->s[2*i+1]) * (t - q->s[2*i]) / (q->s[2*i+2] - q->s[2*i])); } /* end schedule() */ /* See if the control value remains constant during period */ /* [t1,t2]: if it does, then return the upper and lower */ /* bounds which contain [t1,t2]; otherwise return NULL. */ double *calm_period (char token[], double t1, double t2) { int i, j, k; struct schedule_list *q; double ti, tf; static double bound[2]; for ( q = schpool; (q->next != NULL) && strncmp(q->next->token, token, MAX_SCHEDULE_TOKEN_SIZE-1); q = q->next ); if ( q->next == NULL ) { printf("schedule: token name \"%s\" not found.\n", token); exit (1); } q = q->next; ti = (t1 < t2)? t1:t2; tf = (t1 < t2)? t2:t1; for (i=0; in; i++) if (fabs(ti - q->s[2*i]) < SCHEDULE_TINY) break; else if (ti < q->s[2*i]) if (i==0) break; else {i--; break;} if (ti < q->s[2*0]) bound[0] = ti; else /* search left for lower bounds */ for (k=i; k>=0; k--) if (fabs(q->s[2*k+1]-q->s[2*i+1])s[2*k]; for (j=q->n-1; j>=0; j--) if (fabs(tf - q->s[2*j]) < SCHEDULE_TINY) break; else if (tf > q->s[2*j]) if (j==q->n-1) break; else {j++; break;} if (tf > q->s[2*(q->n-1)]) bound[1] = tf; else /* search right for upper bounds */ for (k=j; kn; k++) if (fabs(q->s[2*k+1]-q->s[2*j+1])s[2*k]; for (; is[2*i+1]-q->s[2*j+1]) > SCHEDULE_TINY)) return(NULL); return(bound); } /* end calm_period() */ void cancel_schedule (char token[]) { struct schedule_list *q; for ( q = schpool; (q->next != NULL) && strncmp(q->next->token, token, MAX_SCHEDULE_TOKEN_SIZE-1); q = q->next ); if ( q->next == NULL ) { printf("schedule: token name \"%s\" not found.\n", token); exit (1); } free (q->next->s); q->next->n = 0; *(q->next->token) = '\0'; q->next = q->next->next; return; } /* end cancel_schedule() */ void cancel_all_schedules() { struct schedule_list *q; for ( q=schpool; q->next != NULL; ) { free (q->next->s); q->next->n = 0; *(q->next->token) = '\0'; q->next = q->next->next; } return; } /* end cancel_all_schedules() */ #ifdef SCHEDULE_TEST void main() { struct schedule_list *a = add_schedule ("a", " F0.1 10 20 t0.9 30 ", 0, 1); struct schedule_list *b = add_schedule ("b", " F0.1 10 F0.11 20 t0.9 15 ", 0, 1); struct schedule_list *c; printf ("%d %f %f %f %f %f %f\n", a->n, a->s[0], a->s[1], a->s[2], a->s[3], a->s[4], a->s[5]); printf ("%d %f %f %f %f %f %f\n", b->n, b->s[0], b->s[1], b->s[2], b->s[3], b->s[4], b->s[5]); printf ("%f %f %f\n", schedule("a", -0.1), schedule("a", 0.2), schedule("a", 0.7)); cancel_schedule ("a"); printf ("%f %f %f %f\n", schedule("b", -0.1), schedule("b", 0.2), schedule("b", 1.7), schedule("b", 0.103) ); cancel_all_schedules(); c = add_schedule ("c", " F0.1 10 10 10 10 10 F0.9 10 F0.95 20 ", 0, 1); printf ("c = %d %d %d\n", calm_period("c", -10, 1.5), calm_period("c", 0.4, 0.5), calm_period("c", 0.4, 0.9)); } #endif /* Without changing idx[2*min] and idx[2*max], solve */ /* the memory conflict at idx[2*i+1], idx[2*i+2]. */ void make_space (int idx[], int list[], int i, int min, int max) { int j, k, a, left_shift; if (idx[2*i+1] < idx[2*i+2]) return; else if (idx[2*i+1] > idx[2*i+2]) { printf ("make_space: detects overflow at i=%d and i+1.\n", i); exit(1); } /* look for left free space */ for (j=i; (j>min)&&(idx[2*j]==idx[2*j-1]); j--); /* look for right free space */ for (k=i+1; (kmin) && (kmin) && (k>=max) ) left_shift = 1; else if ( (j<=min) && (kidx[2*i+2]; a--) list[a] = list[a-1]; for (a=2*k+1; a>=2*i+2; a--) idx[a]++; } return; } /* end make_space() */ void safe_append (int idx[], int list[], int value, int i, int min, int max) { make_space (idx, list, i, min, max); list[idx[2*i+1]++] = value; return; } /* end safe_append() */