/* checks if there is an edge between node1 and node2 */ int is_edge(Network *N,int node1,int node2) { //register int i; return(MatGet(N->mat,node1,node2)); }
/* mA <- mA + alpha*I */ void addId(double alpha, Mat mA) { if (MatDev(mA)) { cuAddId(alpha, MatElems(mA), MatN(mA), MatElemSize(mA)); } else for (int diag = 0; diag < MatN(mA); diag++) { /* This could be marginally sped up using *axpy with a 1xn vector of ones and a stride of n + 1 over the matrix, but it's not worth the trouble. */ MatPut(mA, diag, diag, alpha + MatGet(mA, diag, diag)); } }
/* Computes the sum of the entries on the main diagonal. */ double trace(Mat mA) { double trace; if (MatDev(mA)) { trace = cuTrace(MatElems(mA), MatN(mA), MatElemSize(mA)); } else { trace = 0.; for (int i = 0; i < MatN(mA); i++) { trace += MatGet(mA, i, i); } } return trace; }
/* checks if there is an edge between node1 and node2 if we are at the cross edges s1->t2 or s2->t1 output 1 considers that a switch means switching putting on t2->s1 and t1->s2*/ int is_edge2_dbl(Network *N,int node1,int node2,int s1,int t1,int s2,int t2) { //register int i; if (((node1==s1)&&(node2==t2))||((node1==s2)&&(node2==t1))) return(1); if (((node2==s1)&&(node1==t2))||((node2==s2)&&(node1==t1))) return(1); if (((node1==s1)&&(node2==t1))||((node1==s2)&&(node2==t2))) return(0); if (((node2==s1)&&(node1==t1))||((node2==s2)&&(node1==t2))) return(0); return(MatGet(N->mat,node1,node2)); }
/* perform metropolis iteration exchanging double edges. Output the temperature */ double dbl_metrop_switches(Network **RN,int nover,int nlimit,double init_t,int real_vec13[14],int rand_vec13[14]) { double t=init_t; register int w,k,num_at_t; int s1,t1,s2,t2; int i,j; int sub13[14]; int add13[14]; double E1,E2,dE; int make_change; int tries; //number of tries to find proper pair of edges to exchange int twin_i=-1,twin_j=-1; w=0; if ((w%1000)==0 && GNRL_ST.out_metrop_mat_flag) fprintf(GNRL_ST.mat_metrop_fp,"\nBeginning double switches\n"); k=0,w=0,num_at_t=0; t=init_t; for (i=1;i<14;i++) { sub13[i]=0; add13[i]=0; } E1=energy(real_vec13,rand_vec13); while ((w<nover)&&(E1>GNRL_ST.e_thresh)) { w++; num_at_t++; if ((k>nlimit)||(num_at_t>nlimit)) { num_at_t=0; k=0; t *= TFACTR; // lower temperature } w++; // random edges to choose : until finding a proper pair of edges which can be candidates // should not choose the same edge or the twin one (of the double) // try this for 100 times if not getting good candidate then probably // there is a only one double edge in the netwprk for(i=get_rand((*RN)->e_dbl_num),j=get_rand((*RN)->e_dbl_num),tries=0; ((j==i) || (j==twin_i)) && (tries<100) ;i=get_rand((*RN)->e_dbl_num),j=get_rand((*RN)->e_dbl_num),tries++); //the way out of deadlock if(tries==100 || (*RN)->e_dbl_num==2) break; //this is needed to know if the twin is i-1 or i+1 if(i & 0x1) twin_i=i+1; else twin_i=i-1; if(j & 0x1) twin_j=j+1; else twin_j=j-1; s1=(*RN)->e_arr_dbl[i].s; t1=(*RN)->e_arr_dbl[i].t; s2=(*RN)->e_arr_dbl[j].s; t2=(*RN)->e_arr_dbl[j].t; //check : 1.that there are no crossing edges in the network, // 2.there are no common vertices of these 2 edges //if hasnt passed the check then have to find other pair to switch if (( !( MatGet((*RN)->mat,s1,t2) || MatGet((*RN)->mat,s2,t1) || MatGet((*RN)->mat,t1,s2)|| MatGet((*RN)->mat,t2,s1)) && (s1!=t2) &&(s2!=t1) && (s1!=s2) && (t1!=t2)) ) { // make fill13_dbl - new function fill_13_dbl((*RN),s1,t1,s2,t2,sub13,add13); update(rand_vec13,sub13,add13,1); E2=energy(real_vec13,rand_vec13); dE=E2-E1; // printf("k=%d E=%lf\n",k,E1); make_change=metrop(dE,t); if (make_change) { if(DEBUG_LEVEL==1 && GNRL_ST.out_log_flag) { fprintf(GNRL_ST.log_fp,"switch #%d: (%d %d) (%d %d)\n", k,s1,t1,s2,t2); fprintf(GNRL_ST.log_fp,"i: %d, twin i %d , j: %d twin j : %d\n", i,twin_i,j,twin_j); } if ((w%1000)==0 && GNRL_ST.out_metrop_mat_flag) { fprintf(GNRL_ST.mat_metrop_fp,"%lf\n",E1); printf("success=%d k=%d E1=%lf T=%lf\n",k,w,E1,t); } E1=E2; if ((w%1000)==0 && GNRL_ST.out_metrop_mat_flag) printf("success=%d k=%d E1=%lf T=%lf\n",k,w,E1,t); //make the switch //update edges array (*RN)->e_arr_dbl[i].t=t2; (*RN)->e_arr_dbl[twin_i].s=t2; (*RN)->e_arr_dbl[j].t=t1; (*RN)->e_arr_dbl[twin_j].s=t1; if(DEBUG_LEVEL==1 && GNRL_ST.out_log_flag) { fprintf(GNRL_ST.log_fp,"(%d %d) (%d %d) (%d %d) (%d %d)\n", (*RN)->e_arr_dbl[i].s,(*RN)->e_arr_dbl[i].t, (*RN)->e_arr_dbl[twin_i].s,(*RN)->e_arr_dbl[twin_i].t, (*RN)->e_arr_dbl[j].s,(*RN)->e_arr_dbl[j].t, (*RN)->e_arr_dbl[twin_j].s,(*RN)->e_arr_dbl[twin_j].t ); } //update matrix MatAsgn((*RN)->mat,s1,t1,0); MatAsgn((*RN)->mat,t1,s1,0); MatAsgn((*RN)->mat,s2,t2,0); MatAsgn((*RN)->mat,t2,s2,0); if(DEBUG_LEVEL==1 && GNRL_ST.out_log_flag) dump_network(GNRL_ST.log_fp,(*RN)); MatAsgn((*RN)->mat,s1,t2,1); MatAsgn((*RN)->mat,t2,s1,1); MatAsgn((*RN)->mat,s2,t1,1); MatAsgn((*RN)->mat,t1,s2,1); if(DEBUG_LEVEL==1 && GNRL_ST.out_log_flag) dump_network(GNRL_ST.log_fp,(*RN)); if (DEBUG_LEVEL>1 && GNRL_ST.out_metrop_mat_flag) { fprintf(GNRL_ST.mat_metrop_fp,"%lf %lf ",E1,t); output13(rand_vec13,GNRL_ST.mat_metrop_fp); } k++; } else /* change rand_vec13 back */ { update(rand_vec13,sub13,add13,0); } } } if(GNRL_ST.out_metrop_mat_flag==TRUE){ fprintf(GNRL_ST.mat_metrop_fp,"%lf\n",E1); printf("success=%d k=%d E1=%lf T=%lf\n",k,w,E1,t); } return(t); }
/* perform metropolis iteration exchanging single edges. Output the temperature */ double sin_metrop_switches(Network **RN,int nover,int nlimit,double init_t,int real_vec13[14],int rand_vec13[14]) { double t=init_t; register int w,k,num_at_t; int s1,t1,s2,t2; int i,j,l; int sub13[14]; int add13[14]; double E1,E2,dE; int make_change; if(GNRL_ST.out_metrop_mat_flag==TRUE) printf("\nBeginning single switches\n"); k=0,w=0,num_at_t=0; t=init_t; for (i=1;i<14;i++) { sub13[i]=0; add13[i]=0; } E1=energy(real_vec13,rand_vec13); if ((w%1000)==0 && GNRL_ST.out_metrop_mat_flag) fprintf(GNRL_ST.mat_metrop_fp,"\nEsin :\n"); while ((w<nover)&&(E1>GNRL_ST.e_thresh)) { w++; num_at_t++; if ((k>nlimit)||(num_at_t>nlimit)) { num_at_t=0; k=0; t *= TFACTR; // lower temperature } //get random indexes for edges i=get_rand((*RN)->e_sin_num); while ((j=get_rand((*RN)->e_sin_num)) == i); s1=(*RN)->e_arr_sin[i].s; t1=(*RN)->e_arr_sin[i].t; s2=(*RN)->e_arr_sin[j].s; t2=(*RN)->e_arr_sin[j].t; //check : 1.that there are no crossing edges, // 2.there are no common vertices of these 2 edges //if hasnt passed the check then have to find other pair to switch if ( !(MatGet((*RN)->mat,s1,t2) || MatGet((*RN)->mat,s2,t1)|| MatGet((*RN)->mat,t2,s1) || MatGet((*RN)->mat,t1,s2)) &&(s1!=s2) && (s1!=t2) && (t1!=s2) && (t1!=t2) ) { fill_13((*RN),s1,t1,s2,t2,sub13,add13); update(rand_vec13,sub13,add13,1); E2=energy(real_vec13,rand_vec13); dE=E2-E1; // printf("k=%d E=%lf\n",k,E1); make_change=metrop(dE,t); if (make_change) { if ((w%1000)==0 && GNRL_ST.out_metrop_mat_flag) { fprintf(GNRL_ST.mat_metrop_fp,"%lf\n",E1); printf("success=%d k=%d E1=%lf T=%lf\n",k,w,E1,t); } if(DEBUG_LEVEL>1 && GNRL_ST.out_metrop_mat_flag) { fprintf(GNRL_ST.mat_metrop_fp,"The network :\n\n"); for (l=1;l<=(*RN)->e_sin_num;l++) fprintf(GNRL_ST.mat_metrop_fp,"%d %d %d\n",(*RN)->e_arr_sin[l].t,(*RN)->e_arr_sin[l].s,1); } E1=E2; //make the switch //update edges array (*RN)->e_arr_sin[i].t=t2; (*RN)->e_arr_sin[j].t=t1; //update matrix MatAsgn((*RN)->mat,s1,t1,0); MatAsgn((*RN)->mat,s2,t2,0); MatAsgn((*RN)->mat,s1,t2,1); MatAsgn((*RN)->mat,s2,t1,1); //fprintf(GNRL_ST.mat_metrop_fp,"%lf %lf\n ",E1,t); if(DEBUG_LEVEL>1 && GNRL_ST.out_metrop_mat_flag) { fprintf(GNRL_ST.mat_metrop_fp,"Changed to :\n\n"); for (l=1;l<=(*RN)->e_sin_num;l++) fprintf(GNRL_ST.mat_metrop_fp,"%d %d %d\n",(*RN)->e_arr_sin[l].t,(*RN)->e_arr_sin[l].s,1); fprintf(GNRL_ST.mat_metrop_fp,"rand_vec : \n"); output13(rand_vec13,GNRL_ST.mat_metrop_fp); fprintf(GNRL_ST.mat_metrop_fp,"- : \n"); output13(sub13,GNRL_ST.mat_metrop_fp); fprintf(GNRL_ST.mat_metrop_fp,"+ : \n"); output13(add13,GNRL_ST.mat_metrop_fp); fprintf(GNRL_ST.mat_metrop_fp,"The network :\n\n"); for (l=1;l<=(*RN)->e_sin_num;l++) fprintf(GNRL_ST.mat_metrop_fp,"%d %d %d\n",(*RN)->e_arr_sin[l].t,(*RN)->e_arr_sin[l].s,1); fprintf(GNRL_ST.mat_metrop_fp,"\n\n"); } k++; } else /* change rand_vec13 back */ { update(rand_vec13,sub13,add13,0); } } } if(GNRL_ST.out_metrop_mat_flag==TRUE) { fprintf(GNRL_ST.mat_metrop_fp,"%lf\n",E1); printf("success=%d k=%d E1=%lf T=%lf\n",k,w,E1,t); } return(t); }
int gen_rand_network_metrop(Network **RN_p,int real_vec13[14]) { int rc=RC_OK; int sin_num_of_switchs,dbl_num_of_switchs,num_at_t; //int s2,t1,t2; int i,j,l; int k; // number of succesful switches int w; // total number of switches //int tries; //number of tries to find proper pair of edges to exchange //int twin_i,twin_j; Network *RN; int rand_network_checked=FALSE; Res_tbl met_res_tbl; //int real_vec13[14]; int rand_vec13[14]; //int sub13[14]; //int add13[14]; //double E1,E2,dE; double E1,E2; int snover,dnover; // maximum # of graph changes at any temperature //int nlimit,snlimit,dnlimit; // maximum # of succesful graph changes at any temperature int snlimit,dnlimit; // maximum # of succesful graph changes at any temperature //int make_change; //int numsucc; // how many successful switches already made double t; // the temperature int success; int dispair=0; double dummy; int switches_range; double *switch_ratio_arr; switch_ratio_arr=(double*)calloc(GNRL_ST.rnd_net_num+1,sizeof(double)); sin_num_of_switchs=0; if(G_N->e_sin_num<=1) sin_num_of_switchs=0; else { // num of switches is round(10*(1+rand)*#edges) //num of edges in undirfecetd is actually *2 therefore divided by 2 switches_range=(int)(2*GNRL_ST.r_switch_factor*G_N->e_sin_num); sin_num_of_switchs=(int)switches_range+get_rand((int)switches_range); } if(G_N->e_dbl_num<=1) dbl_num_of_switchs=0; else { // num of switches is round(10*(1+rand)*#edges) //num of edges in undirfecetd is actually *2 therefore divided by 2 switches_range=(int)(2*GNRL_ST.r_switch_factor*G_N->e_dbl_num/2); dbl_num_of_switchs=(int)switches_range+get_rand((int)switches_range); } t=GNRL_ST.t_init; if (GNRL_ST.use_stubs_method==TRUE) { success=0; dispair=0; while ((success==FALSE)&&(dispair<GEN_NETWORK_DISPAIR)) { //printf("trying ron\n"); rc=gen_rand_network_stubs_method(&RN); if(rc==RC_OK) success=TRUE; else success=FALSE; if (success==FALSE) { //printf("dispair - discard\n"); dispair++; } } if (dispair==GEN_NETWORK_DISPAIR) // give up try switch method gen_rand_network_switches_method_conserve_double_edges(&RN,&dummy); else { success=update_network(RN,G_N); if (!success) { printf("Error - degrees don't match\n"); at_exit(-1); } //shuffle_double_edges(RN); if (DEBUG_LEVEL>20 && GNRL_ST.out_log_flag) { fprintf(GNRL_ST.log_fp,"The network :\n\n"); for (l=1;l<=(*RN).edges_num;l++) fprintf(GNRL_ST.log_fp,"%d %d %d\n",(*RN).e_arr[l].t,(*RN).e_arr[l].s,1); } } } else gen_rand_network_switches_method_conserve_double_edges(&RN, &dummy); /**************************************************************/ /**************************************************************/ /**************************************************************/ /* Part II - metropolis algorithm. Perform switches with probability*/ /**************************************************************/ /**************************************************************/ /**************************************************************/ /**************************************************************/ /* metropolis parameters depend on num_of _switches*/ /* otuput real network to _METROP file */ init_res_tbl(&met_res_tbl); list64_init(&met_res_tbl.real); met_motifs_search_real(RN,&met_res_tbl,rand_vec13); list64_free_mem(met_res_tbl.real); E1=energy(real_vec13,rand_vec13); w=0; if(GNRL_ST.out_metrop_mat_flag) { fprintf(GNRL_ST.mat_metrop_fp,"\nreal network\n"); fprintf(GNRL_ST.mat_metrop_fp,"E=%lf T=%lf\n",E1,t); fprintf(GNRL_ST.mat_metrop_fp,"Real triadic census :\n "); output13(real_vec13,GNRL_ST.mat_metrop_fp); fprintf(GNRL_ST.mat_metrop_fp,"random network\n"); fprintf(GNRL_ST.mat_metrop_fp,"%lf,%lf \n",E1,t); fprintf(GNRL_ST.mat_metrop_fp,"Initial random triadic census :\n "); output13(rand_vec13,GNRL_ST.mat_metrop_fp); } /* nover=sin_num_of_switchs*GNRL_ST.iteration_factor; nlimit=nover/10; k=0; num_at_t=0; sin_metrop_switches(&RN,nover,nlimit,GNRL_ST.t_init,real_vec13,rand_vec13); */ if (dbl_num_of_switchs==0) { snover=sin_num_of_switchs*(int)GNRL_ST.iteration_factor; snlimit=snover/10; t=sin_metrop_switches(&RN,snover,snlimit,GNRL_ST.t_init,real_vec13,rand_vec13); } else { dnover=dbl_num_of_switchs*(int)GNRL_ST.iteration_factor/10; dnlimit=dnover/10; if (dnover<10) { dnover=dbl_num_of_switchs; dnlimit=dnover; } t=dbl_metrop_switches(&RN,dnover,dnlimit,GNRL_ST.t_init,real_vec13,rand_vec13); snover=sin_num_of_switchs*(int)GNRL_ST.iteration_factor/10; snlimit=snover/10; k=0; num_at_t=0; t=sin_metrop_switches(&RN,snover,snlimit,t,real_vec13,rand_vec13); if(GNRL_ST.out_metrop_mat_flag) { fprintf(GNRL_ST.mat_metrop_fp,"End E\n"); printf("End E\n"); } for (i=1;i<10;i++) { E2=energy(real_vec13,rand_vec13); if (E2>0) { t=dbl_metrop_switches(&RN,dnover,dnlimit,t,real_vec13,rand_vec13); t=sin_metrop_switches(&RN,snover,snlimit,t,real_vec13,rand_vec13); } } } //check that there are no self edges. If there are any then start again rand_network_checked = TRUE; if(GNRL_ST.calc_self_edges == FALSE){ for(i=1;i<=RN->vertices_num;i++) { if( MatGet(RN->mat,i,i)==1 ) { printf("Self edges still exist building random graph again\n"); rand_network_checked=FALSE; free_network_mem(RN); break; } } } //merge lists to RN->e_arr // j=0; for(i=1;i<=RN->e_dbl_num;i++) { RN->e_arr[++j].s=RN->e_arr_dbl[i].s; RN->e_arr[j].t=RN->e_arr_dbl[i].t; } for(i=1;i<=RN->e_sin_num;i++) { RN->e_arr[++j].s=RN->e_arr_sin[i].s; RN->e_arr[j].t=RN->e_arr_sin[i].t; } if(DEBUG_LEVEL>1 && GNRL_ST.out_metrop_mat_flag) { fprintf(GNRL_ST.mat_metrop_fp,"The network :\n"); for (i=1;i<=RN->edges_num;i++) fprintf(GNRL_ST.mat_metrop_fp,"%d %d %d\n",RN->e_arr[i].t,RN->e_arr[i].s,1); fprintf(GNRL_ST.mat_metrop_fp,"End of network\n"); fprintf(GNRL_ST.mat_metrop_fp,"\n\n"); } if(GNRL_ST.out_metrop_mat_flag) { fprintf(GNRL_ST.mat_metrop_fp,"Real triadic census :\n "); output13(real_vec13,GNRL_ST.mat_metrop_fp); fprintf(GNRL_ST.mat_metrop_fp,"Final random triadic census :\n "); output13(rand_vec13,GNRL_ST.mat_metrop_fp); } *RN_p=RN; return RC_OK; }
static FUNC *ConvertSurface( FUNC *func, OPTIC *optic ) { FUNC *loop ; EXPR *EA0, *separate ; int ea0used, which, rev ; optic->terms[ TERM_MAT ].E = Copy( MatGet() ) ; optic->terms[ TERM_TEMP ].E = Copy( MatGetTemp() ) ; for( loop = func ; loop ; loop = OpticForward( FuncNext(loop) ) ) { which = (int) ( ExprValue( FuncArg( loop, 0 ) ) + 0.49 ) ; if( which < 6 ) break ; EA0 = Copy( FuncArg( loop, 1 ) ) ; ea0used = 0 ; switch( which ) { case 6: /* INDX */ if( FuncArgCount( loop ) == 4 ) { MatPush( EA0, FuncArg( loop, 2 ), FuncIsReversed( loop ) ) ; optic->mutant = 1 ; (optic - 1)->mutant = -1 ; /* kludge-o-rama */ optic->terms[TERM_MUTANT].E = Copy( FuncArg( loop, 3 ) ) ; } else if( FuncArgCount( loop ) == 3 ) { MatPush( EA0, FuncArg( loop, 2 ), FuncIsReversed( loop ) ) ; } else if( FuncArgCount( loop ) == 2 ) { MatPush( EA0, Label( "MatTemperature" ), FuncIsReversed( loop ) ) ; } break ; case 7: /* PARAX */ optic->terms[TERM_FOCLEN].E = EA0 ; optic->function |= FUNCTION_PARAX ; ea0used = 1 ; break ; case 8: /* MIRROR */ optic->function |= FUNCTION_MIRROR ; break ; case 9: /* GRATING */ optic->function |= FUNCTION_GRATING ; optic->terms[TERM_LINES].E = EA0 ; optic->terms[TERM_ORDER].E = Copy( FuncArg( loop, 2 ) ) ; ea0used = 1 ; break ; case 10: /* VIEW */ optic->function |= FUNCTION_VIEW ; break ; case 11: /* STOP */ if( FuncArgCount( loop ) == 1 ) /* EXIT */ optic->function |= FUNCTION_EXIT ; else if( FuncArgCount( loop ) == 7 ) /* STOP */ { int i ; EDAT *S ; if( optic->StopCount == NSTOPS ) { IOerror( IO_ERR, "ConvertSurface", "too many stops" ) ; failed = 1 ; break ; } S = &optic->terms[ TERM_STOPS + 6 * optic->StopCount ] ; for( i = 0 ; i < 6 ; i++ ) S[i].E = Copy( FuncArg( loop, i + 1 ) ) ; optic->StopCount++ ; } break ; case 12: /* PDIST */ if( FuncIsReversed( loop ) ) optic->terms[TERM_PDIST].E = Ecc( EA0, "u-", Garbage() ) ; else optic->terms[TERM_PDIST].E = EA0 ; optic->function |= FUNCTION_PDIST ; ea0used = 1 ; break ; case 13: /* PRINT */ break ; case 14: /* LABEL */ separate = String( " & " ) ; if( optic->terms[ TERM_LABEL ].E ) { optic->terms[ TERM_LABEL ].E = Ecc( optic->terms[ TERM_LABEL ].E, "//", separate ) ; optic->terms[ TERM_LABEL ].E = Ecc( optic->terms[ TERM_LABEL ].E, "//", EA0 ) ; } else optic->terms[ TERM_LABEL ].E = EA0 ; ea0used = 1 ; break ; case 15: /* SURF */ rev = ( FuncIsReversed( loop ) ? -1 : 1 ) ; if( optic->reverse != rev ) { if( !optic->reverse ) optic->reverse = rev ; else { IOerror( IO_ERR, "ConvertSurface", "inconsistent surface reversal on surface #%d", Surface ) ; failed = 1 ; } } if( FuncArgCount( loop ) == 4 ) { optic->surface |= SURFACE_SYMBOLIC ; optic->terms[TERM_Sx].E = Copy( FuncArg( loop, 1 ) ) ; optic->terms[TERM_Sy].E = Copy( FuncArg( loop, 2 ) ) ; optic->terms[TERM_Sf].E = Copy( FuncArg( loop, 3 ) ) ; if( !ExprIsVariable( optic->terms[TERM_Sx].E ) ) IOerror( IO_ERR, "ConvertSurface", "X not a variable" ) ; if( !ExprIsVariable( optic->terms[TERM_Sy].E ) ) IOerror( IO_ERR, "ConvertSurface", "Y not a variable" ) ; break ; } optic->terms[TERM_CURV].E = EA0 ; ea0used = 1 ; if( FuncArgCount( loop ) == 1 ) optic->surface |= SURFACE_FLAT ; else if( FuncArgCount( loop ) == 2 ) optic->surface |= SURFACE_SPHERE ; else if( FuncArgCount( loop ) == 3 ) { optic->surface |= SURFACE_CONIC ; optic->terms[TERM_CONIC].E = Copy( FuncArg( loop, 2 ) ) ; } else /* count = 6 */ { optic->surface |= SURFACE_ASPHERE ; optic->terms[TERM_CONIC].E = Copy( FuncArg( loop, 2 ) ) ; optic->terms[TERM_A4].E = Copy( FuncArg( loop, 3 ) ) ; optic->terms[TERM_A6].E = Copy( FuncArg( loop, 4 ) ) ; optic->terms[TERM_A8].E = Copy( FuncArg( loop, 5 ) ) ; optic->terms[TERM_A10].E = Copy( FuncArg( loop, 6 ) ) ; } break ; case 16: /* TRIX */ rev = ( FuncIsReversed( loop ) ? -1 : 1 ) ; if( optic->reverse != rev ) { if( !optic->reverse ) optic->reverse = rev ; else { IOerror( IO_ERR, "ConvertSurface", "inconsistent surface reversal on surface #%d", Surface ) ; failed = 1 ; } } optic->terms[TERM_Ex].E = EA0 ; optic->terms[TERM_Ey].E = Copy( FuncArg( loop, 2 ) ) ; optic->terms[TERM_Ez].E = Copy( FuncArg( loop, 3 ) ) ; optic->terms[TERM_Eo].E = Copy( FuncArg( loop, 4 ) ) ; optic->surface |= SURFACE_TRIAXIAL ; ea0used = 1 ; break ; case 17: /* MARK */ if( FuncArgCount( loop ) == 2 ) /* surface */ { optic->terms[TERM_MARK].E = EA0 ; ea0used = 1 ; } else if( FuncArgCount( loop ) == 3 ) /* variable */ { if( !ExprIsVariable( FuncArg( loop, 1 ) ) ) { IOerror( OpticBomb, "ConvertSurface", "EXPR not a VARIABLE" ) ; } ExprSetFlags( FuncArg( loop, 1 ), (int) ExprValue( FuncArg( loop, 2 ) ) & VAR_OPTIC ) ; } break ; case 18: /* COAT */ if( optic->terms[ TERM_COATING ].E ) { IOerror( IO_ERR, "ConvertSurface", "multiple coating declarations on surface %d", Surface ) ; failed = 1 ; } else { optic->terms[ TERM_COATING ].E = EA0 ; ea0used = 1 ; } break ; case 19: /* BOUND */ break ; case 20: /* BAFFLE */ optic->function |= FUNCTION_BAFFLE ; break ; case 21: /* MERIT */ break ; case 22: /* APERTURE */ optic->function |= FUNCTION_APERTURE ; if( aperture_set ) { IOerror( IO_ERR, "ConvertSurface", "multiple apertures" ) ; failed = 1 ; } aperture_set = 1 ; break ; case 23: /* PINHOLE */ optic->function |= FUNCTION_PINHOLE ; break ; case 24: /* ORIGIN */ if( origin_set ) { IOerror( IO_WARN, "ConvertSurface", "multiple origins" ) ; /* EVIL HACK!!!! */ /* failed = 1 ; */ } else { optic->function |= FUNCTION_ORIGIN ; origin_set = 1 ; } break ; case 25: /* FRESNEL */ rev = ( FuncIsReversed( loop ) ? -1 : 1 ) ; if( optic->reverse != rev ) { if( !optic->reverse ) optic->reverse = rev ; else { IOerror( IO_ERR, "ConvertSurface", "inconsistent surface reversal on surface #%d", Surface ) ; failed = 1 ; } } optic->surface |= SURFACE_FRESNEL ; optic->terms[TERM_FOCLEN].E = EA0 ; ea0used = 1 ; break ; default: IOerror( OpticBomb, "ConvertSurface", "unexpected surface function on surface #%d", Surface ) ; failed = 1 ; } if( !ea0used ) Free( EA0 ) ; } if( !Compare( optic->terms[ TERM_MAT ].E, MatGet() ) ) optic->function |= FUNCTION_SNELL ; return loop ; }