bool AbstractLinAlgPack::max_inequ_viol( const AbstractLinAlgPack::Vector &v ,const AbstractLinAlgPack::Vector &vL ,const AbstractLinAlgPack::Vector &vU ,AbstractLinAlgPack::size_type *max_viol_i ,AbstractLinAlgPack::value_type *max_viol ,AbstractLinAlgPack::value_type *v_i ,int *bnd_type ,AbstractLinAlgPack::value_type *vLU_i ) { RTOpPack::RTOpC op; TEST_FOR_EXCEPT(0!=RTOp_ROp_max_inequ_viol_construct(&op.op())); Teuchos::RCP<RTOpPack::ReductTarget> reduct_obj = op.reduct_obj_create(); const int num_vecs = 3; const Vector* vecs[num_vecs] = { &v, &vL, &vU }; apply_op( op, num_vecs, vecs, 0, NULL ,&*reduct_obj ); const RTOp_ROp_max_inequ_viol_reduct_obj_t ro = RTOp_ROp_max_inequ_viol_val(op(*reduct_obj)); *max_viol_i = ro.max_viol_i; *max_viol = ro.max_viol; *v_i = ro.v_i; *bnd_type = ro.bnd_type; *vLU_i = ro.vLU_i; return *max_viol_i > 0.0; }
AbstractLinAlgPack::value_type AbstractLinAlgPack::sum( const Vector& v_rhs ) { sum_op.reduct_obj_reinit(&*sum_targ); const Vector* vecs[1] = { &v_rhs }; apply_op(sum_op,1,vecs,0,NULL,&*sum_targ); return RTOp_ROp_sum_val(sum_op(*sum_targ)); }
AbstractLinAlgPack::value_type AbstractLinAlgPack::dot( const Vector& v_rhs1, const Vector& v_rhs2 ) { dot_prod_op.reduct_obj_reinit(&*dot_prod_targ); const Vector* vecs[2] = { &v_rhs1, &v_rhs2 }; apply_op(dot_prod_op,2,vecs,0,NULL,&*dot_prod_targ); return RTOp_ROp_dot_prod_val(dot_prod_op(*dot_prod_targ)); }
void AbstractLinAlgPack::Vp_S( VectorMutable* v_lhs, const value_type& alpha ) { #ifdef TEUCHOS_DEBUG TEST_FOR_EXCEPTION(v_lhs==NULL,std::logic_error,"Vp_S(...), Error!"); #endif TEST_FOR_EXCEPT(0!=RTOp_TOp_add_scalar_set_alpha(alpha,&add_scalar_op.op())); VectorMutable* targ_vecs[1] = { v_lhs }; apply_op(add_scalar_op,0,NULL,1,targ_vecs,NULL); }
AbstractLinAlgPack::value_type AbstractLinAlgPack::max_element( const Vector& v ) { RTOpPack::RTOpC op; TEST_FOR_EXCEPT(0!=RTOp_ROp_max_construct(&op.op())); Teuchos::RCP<RTOpPack::ReductTarget> reduct_obj = op.reduct_obj_create(); const Vector* vecs[1] = { &v }; apply_op(op,1,vecs,0,NULL,&*reduct_obj); return RTOp_ROp_max_val(op(*reduct_obj)); }
void AbstractLinAlgPack::sign( const Vector &v ,VectorMutable *z ) { RTOpPack::RTOpC op; TEST_FOR_EXCEPT( !( 0==RTOp_TOp_sign_construct(&op.op()) ) ); const Vector* vecs[1] = { &v }; VectorMutable* targ_vecs[1] = { z }; apply_op(op,1,vecs,1,targ_vecs,NULL); }
void AbstractLinAlgPack::Vp_StV( VectorMutable* v_lhs, const value_type& alpha, const Vector& v_rhs) { #ifdef TEUCHOS_DEBUG TEST_FOR_EXCEPTION(v_lhs==NULL,std::logic_error,"Vp_StV(...), Error!"); #endif TEST_FOR_EXCEPT(0!=RTOp_TOp_axpy_set_alpha( alpha, &axpy_op.op() )); const Vector* vecs[1] = { &v_rhs }; VectorMutable* targ_vecs[1] = { v_lhs }; apply_op(axpy_op,1,vecs,1,targ_vecs,NULL); }
void AbstractLinAlgPack::random_vector( value_type l, value_type u, VectorMutable* v ) { #ifdef TEUCHOS_DEBUG TEST_FOR_EXCEPTION(v==NULL,std::logic_error,"Vt_S(...), Error"); #endif //TEST_FOR_EXCEPT(0!=RTOp_TOp_random_vector_set_bounds( l, u, &random_vector_op.op() )); random_vector_op.set_bounds(l,u); VectorMutable* targ_vecs[1] = { v }; apply_op(random_vector_op,0,NULL,1,targ_vecs,NULL); }
void AbstractLinAlgPack::inv_of_difference( const value_type alpha ,const Vector &v0 ,const Vector &v1 ,VectorMutable *z ) { TEST_FOR_EXCEPT(0!=RTOp_TOp_inv_of_difference_init( alpha, &inv_of_difference_op.op())); const Vector* vecs[2] = { &v0, &v1 }; VectorMutable* targ_vecs[1] = { z }; apply_op(inv_of_difference_op,2,vecs,1,targ_vecs,NULL); }
void AbstractLinAlgPack::force_in_bounds( const Vector& xl, const Vector& xu ,VectorMutable* x ) { #ifdef TEUCHOS_DEBUG TEST_FOR_EXCEPTION(x==NULL,std::logic_error,"force_in_bounds(...), Error"); #endif const Vector* vecs[2] = { &xl, &xu }; VectorMutable* targ_vecs[1] = { x }; apply_op(force_in_bounds_op,2,vecs,1,targ_vecs,NULL); }
void AbstractLinAlgPack::ele_wise_prod( const value_type& alpha, const Vector& v_rhs1, const Vector& v_rhs2 , VectorMutable* v_lhs ) { #ifdef TEUCHOS_DEBUG TEST_FOR_EXCEPTION(v_lhs==NULL,std::logic_error,"ele_wise_prod(...), Error"); #endif TEST_FOR_EXCEPT(0!=RTOp_TOp_ele_wise_prod_set_alpha(alpha,&ele_wise_prod_op.op())); const Vector* vecs[2] = { &v_rhs1, &v_rhs2 }; VectorMutable* targ_vecs[1] = { v_lhs }; apply_op(ele_wise_prod_op,2,vecs,1,targ_vecs,NULL); }
void AbstractLinAlgPack::force_in_bounds_buffer( const value_type rel_push, const value_type abs_push, const Vector& xl, const Vector& xu, VectorMutable* x ) { TEST_FOR_EXCEPT(0!=RTOp_TOp_force_in_bounds_buffer_init( rel_push, abs_push, &force_in_bounds_buffer_op.op())); const Vector* vecs[2] = { &xl, &xu }; VectorMutable* targ_vecs[1] = { x }; apply_op(force_in_bounds_buffer_op,2,vecs,1,targ_vecs,NULL); }
void AbstractLinAlgPack::Vt_S( VectorMutable* v_lhs, const value_type& alpha ) { #ifdef TEUCHOS_DEBUG TEST_FOR_EXCEPTION(v_lhs==NULL,std::logic_error,"Vt_S(...), Error!"); #endif if( alpha == 0.0 ) { *v_lhs = 0.0; } else if( alpha != 1.0 ) { TEST_FOR_EXCEPT(0!=RTOp_TOp_scale_vector_set_alpha( alpha, &scale_vector_op.op() )); VectorMutable* targ_vecs[1] = { v_lhs }; apply_op(scale_vector_op,0,NULL,1,targ_vecs,NULL); } }
AbstractLinAlgPack::value_type AbstractLinAlgPack::max_rel_step( const Vector& x, const Vector& d ) { const int num_vecs = 2; const Vector* vecs[num_vecs] = { &x, &d }; max_rel_step_op.reduct_obj_reinit(&*max_rel_step_targ); apply_op( max_rel_step_op, num_vecs, vecs, 0, NULL ,&*max_rel_step_targ ); return RTOp_ROp_max_rel_step_val(max_rel_step_op(*max_rel_step_targ)); }
void AbstractLinAlgPack::max_abs_ele( const Vector& v, value_type* max_v_j, index_type* max_j ) { TEST_FOR_EXCEPT( !( max_v_j && max_j ) ); RTOpPack::RTOpC op; TEST_FOR_EXCEPT(0!=RTOp_ROp_max_abs_ele_construct(&op.op())); Teuchos::RCP<RTOpPack::ReductTarget> reduct_obj = op.reduct_obj_create(); const Vector* vecs[1] = { &v }; apply_op(op,1,vecs,0,NULL,&*reduct_obj); RTOp_value_index_type val = RTOp_ROp_max_abs_ele_val(op(*reduct_obj)); *max_v_j = val.value; *max_j = val.index; }
AbstractLinAlgPack::size_type AbstractLinAlgPack:: num_bounded( const Vector& xl, const Vector& xu ,value_type inf_bound ) { TEST_FOR_EXCEPT(0!=RTOp_ROp_num_bounded_set_inf_bnd( inf_bound, &num_bounded_op.op() )); num_bounded_op.reduct_obj_reinit(&*num_bounded_targ); const int num_vecs = 2; const Vector* vecs[num_vecs] = { &xl, &xu }; apply_op( num_bounded_op, num_vecs, vecs, 0, NULL ,&*num_bounded_targ ); return RTOp_ROp_num_bounded_val(num_bounded_op(*num_bounded_targ)); }
AbstractLinAlgPack::value_type AbstractLinAlgPack::fraction_to_zero_boundary( const value_type tau, const Vector& x, const Vector& d ) { TEST_FOR_EXCEPT(0!=RTOp_ROp_fraction_to_zero_boundary_init( tau, &fraction_to_zero_boundary_op.op() )); fraction_to_zero_boundary_op.reduct_obj_reinit(&*fraction_to_zero_boundary_targ); const int num_vecs = 2; const Vector* vecs[num_vecs] = { &x, &d }; apply_op( fraction_to_zero_boundary_op, num_vecs, vecs, 0, NULL ,&*fraction_to_zero_boundary_targ ); return RTOp_ROp_fraction_to_zero_boundary_val(fraction_to_zero_boundary_op(*fraction_to_zero_boundary_targ)); }
AbstractLinAlgPack::value_type AbstractLinAlgPack::combined_nu_comp_err_upper( const Vector &v ,const Vector &x ,const Vector &xu ) { combined_nu_comp_err_upper_op.reduct_obj_reinit(&*combined_nu_comp_err_upper_targ); const int num_vecs = 3; const Vector* vecs[num_vecs] = {&v, &xu, &x}; apply_op( combined_nu_comp_err_upper_op, num_vecs, vecs, 0, NULL ,&*combined_nu_comp_err_upper_targ ); return RTOp_ROp_combined_nu_comp_err_one_only_val(combined_nu_comp_err_upper_op(*combined_nu_comp_err_upper_targ)); }
AbstractLinAlgPack::value_type AbstractLinAlgPack::log_bound_barrier( const Vector &x ,const Vector &xl ,const Vector &xu ) { log_bound_barrier_op.reduct_obj_reinit(&*log_bound_barrier_targ); const int num_vecs = 3; const Vector* vecs[num_vecs] = { &x, &xl, &xu }; apply_op( log_bound_barrier_op, num_vecs, vecs, 0, NULL ,&*log_bound_barrier_targ ); return RTOp_ROp_log_bound_barrier_val(log_bound_barrier_op(*log_bound_barrier_targ)); }
/* evaluate all possible (according to order of precedence) operators */ static void eval_stack (void) { /* uses globals par[], op[], val[] */ /* # of operators >= 2 and prev. op-level >= current op-level ? */ while ((op.idx > par.opx[par.idx]) && get_level (-1) >= get_level (0)) { /* shorten value stacks by one */ /* + calculate resulting value */ op.idx -= 1; val.idx -= 1; val.buf[val.idx] = apply_op(op.buf[op.idx], val.buf[val.idx], val.buf[val.idx + 1]); /* pull the just used operator out of the stack */ op.buf[op.idx] = op.buf[op.idx + 1]; } }
std::pair<AbstractLinAlgPack::value_type,AbstractLinAlgPack::value_type> AbstractLinAlgPack::max_near_feas_step( const Vector& x, const Vector& d ,const Vector& xl, const Vector& xu ,value_type max_bnd_viol ) { const int num_vecs = 4; const Vector* vecs[num_vecs] = { &xl, &x, &d, &xu }; TEST_FOR_EXCEPT(0!=RTOp_ROp_max_near_feas_step_set_beta( max_bnd_viol, &max_near_feas_step_op.op() )); max_near_feas_step_op.reduct_obj_reinit(&*max_near_feas_step_targ); apply_op( max_near_feas_step_op, num_vecs, vecs, 0, NULL ,&*max_near_feas_step_targ ); RTOp_ROp_max_near_feas_step_reduct_obj_t u = RTOp_ROp_max_near_feas_step_val(max_near_feas_step_op(*max_near_feas_step_targ));; return std::pair<value_type,value_type>(u.alpha_pos,u.alpha_neg); }
AbstractLinAlgPack::value_type AbstractLinAlgPack::IP_comp_err_with_mu( const value_type mu ,const value_type inf_bound ,const Vector &x ,const Vector &xl ,const Vector &xu ,const Vector &vl ,const Vector &vu ) { TEST_FOR_EXCEPT(0!=RTOp_ROp_comp_err_with_mu_init(mu, inf_bound, &comp_err_with_mu_op.op())); comp_err_with_mu_op.reduct_obj_reinit(&*comp_err_with_mu_targ); const int num_vecs = 5; const Vector* vecs[num_vecs] = {&x, &xl, &xu, &vl, &vu}; apply_op( comp_err_with_mu_op, num_vecs, vecs, 0, NULL ,&*comp_err_with_mu_targ ); return RTOp_ROp_comp_err_with_mu_val(comp_err_with_mu_op(*comp_err_with_mu_targ)); }
//------------------------------------------------------------------------------------------------------------------------------ void BiCGStab(level_type * level, int x_id, int R_id, double a, double b, double desired_reduction_in_norm){ // Algorithm 7.7 in Iterative Methods for Sparse Linear Systems(Yousef Saad) // uses "right" preconditioning... AD^{-1}(Dx) = b ... AD^{-1}y = b ... solve for y, then solve for x = D^{-1}y int r0_id = VECTORS_RESERVED+0; int r_id = VECTORS_RESERVED+1; int p_id = VECTORS_RESERVED+2; int s_id = VECTORS_RESERVED+3; int Ap_id = VECTORS_RESERVED+4; int As_id = VECTORS_RESERVED+5; int jMax=200; int j=0; int BiCGStabFailed = 0; int BiCGStabConverged = 0; residual(level,r0_id,x_id,R_id,a,b); // r0[] = R_id[] - A(x_id) scale_vector(level,r_id,1.0,r0_id); // r[] = r0[] scale_vector(level,p_id,1.0,r0_id); // p[] = r0[] double r_dot_r0 = dot(level,r_id,r0_id); // r_dot_r0 = dot(r,r0) double norm_of_r0 = norm(level,r_id); // the norm of the initial residual... if(r_dot_r0 == 0.0){BiCGStabConverged=1;} // entered BiCGStab with exact solution if(norm_of_r0 == 0.0){BiCGStabConverged=1;} // entered BiCGStab with exact solution while( (j<jMax) && (!BiCGStabFailed) && (!BiCGStabConverged) ){ // while(not done){ j++;level->Krylov_iterations++; // #ifdef KRYLOV_DIAGONAL_PRECONDITION // mul_vectors(level,VECTOR_TEMP,1.0,VECTOR_DINV,p_id); // temp[] = Dinv[]*p[] apply_op(level,Ap_id,VECTOR_TEMP,a,b); // Ap = AD^{-1}(p) #else // apply_op(level,Ap_id,p_id,a,b); // Ap = A(p) #endif // double Ap_dot_r0 = dot(level,Ap_id,r0_id); // Ap_dot_r0 = dot(Ap,r0) if(Ap_dot_r0 == 0.0){BiCGStabFailed=1;break;} // pivot breakdown ??? double alpha = r_dot_r0 / Ap_dot_r0; // alpha = r_dot_r0 / Ap_dot_r0 if(isinf(alpha)){BiCGStabFailed=2;break;} // pivot breakdown ??? add_vectors(level,x_id,1.0,x_id, alpha, p_id); // x_id[] = x_id[] + alpha*p[] add_vectors(level,s_id,1.0,r_id,-alpha,Ap_id); // s[] = r[] - alpha*Ap[] (intermediate residual?) double norm_of_s = norm(level,s_id); // FIX - redundant?? norm of intermediate residual //if(level->my_rank==0)printf("norm(s)/norm(r0) = %e\n",norm_of_s/norm_of_r0); if(norm_of_s == 0.0){BiCGStabConverged=1;break;} // FIX - redundant?? if As_dot_As==0, then As must be 0 which implies s==0 if(norm_of_s < desired_reduction_in_norm*norm_of_r0){BiCGStabConverged=1;break;} #ifdef KRYLOV_DIAGONAL_PRECONDITION // mul_vectors(level,VECTOR_TEMP,1.0,VECTOR_DINV,s_id); // temp[] = Dinv[]*s[] apply_op(level,As_id,VECTOR_TEMP,a,b); // As = AD^{-1}(s) #else // apply_op(level,As_id,s_id,a,b); // As = A(s) #endif // double As_dot_As = dot(level,As_id,As_id); // As_dot_As = dot(As,As) double As_dot_s = dot(level,As_id, s_id); // As_dot_s = dot(As, s) if(As_dot_As == 0.0){BiCGStabConverged=1;break;} // converged ? double omega = As_dot_s / As_dot_As; // omega = As_dot_s / As_dot_As if(omega == 0.0){BiCGStabFailed=3;break;} // stabilization breakdown ??? if(isinf(omega)){BiCGStabFailed=4;break;} // stabilization breakdown ??? add_vectors(level,x_id,1.0,x_id, omega, s_id); // x_id[] = x_id[] + omega*s[] add_vectors(level,r_id,1.0,s_id,-omega,As_id); // r[] = s[] - omega*As[] (recursively computed / updated residual) double norm_of_r = norm(level,r_id); // norm of recursively computed residual (good enough??) //if(level->my_rank==0)printf("norm(r)/norm(r0) = %e\n",norm_of_r/norm_of_r0); if(norm_of_r == 0.0){BiCGStabConverged=1;break;} // if(norm_of_r < desired_reduction_in_norm*norm_of_r0){BiCGStabConverged=1;break;} #ifdef __DEBUG // residual(level,VECTOR_TEMP,x_id,R_id,a,b); // double norm_of_residual = norm(level,VECTOR_TEMP); // if(level->my_rank==0)fprintf(stdout,"j=%8d, norm=%12.6e, norm_inital=%12.6e, reduction=%e\n",j,norm_of_residual,norm_of_r0,norm_of_residual/norm_of_r0); // #endif // double r_dot_r0_new = dot(level,r_id,r0_id); // r_dot_r0_new = dot(r,r0) if(r_dot_r0_new == 0.0){BiCGStabFailed=5;break;} // Lanczos breakdown ??? double beta = (r_dot_r0_new/r_dot_r0) * (alpha/omega); // beta = (r_dot_r0_new/r_dot_r0) * (alpha/omega) if(isinf(beta)){BiCGStabFailed=6;break;} // ??? add_vectors(level,VECTOR_TEMP,1.0,p_id,-omega, Ap_id); // VECTOR_TEMP = (p[]-omega*Ap[]) add_vectors(level, p_id,1.0,r_id, beta,VECTOR_TEMP); // p[] = r[] + beta*(p[]-omega*Ap[]) r_dot_r0 = r_dot_r0_new; // r_dot_r0 = r_dot_r0_new (save old r_dot_r0) } // } #ifdef KRYLOV_DIAGONAL_PRECONDITION // mul_vectors(level,x_id,1.0,VECTOR_DINV,x_id); // x_id[] = Dinv[]*x_id[] // i.e. x = D^{-1}x' #endif // #ifdef __DEBUG if(BiCGStabFailed)if(level->my_rank==0)fprintf(stderr,"BiCGStab Failed... error = %d\n",BiCGStabFailed); #endif }
long double evaluate(string_t* expr) { int i, length; double result, a, b; char as_string[2] = "\0"; char top, op, unused; stack values, ops; string_t formatted; init_string(&formatted, ""); format_expression_string(expr, &formatted); stack_new(&values, sizeof(double)); stack_new(&ops, sizeof(char)); length = strlen(formatted.string); for(i = 0; i < length; i++) { /* Current token is a whitespace, skip it */ if (formatted.string[i] == ' ') continue; /* Current token is a number, push it to stack for numbers */ if((formatted.string[i] >= '0' && formatted.string[i] <= '9') || (formatted.string[i] == '.')) { string_t buf; init_string(&buf, ""); /* There may be more than one digits in number */ while((i < length) && (((formatted.string[i] >= '0') && (formatted.string[i] <= '9')) || (formatted.string[i] == '.'))) { as_string[0] = formatted.string[i++]; append(&buf, as_string); } result = atof(buf.string); stack_push(&values, &result); } else if(formatted.string[i] == '(') { /* Current token is an opening brace, push it to 'ops' */ as_string[0] = formatted.string[i]; stack_push(&ops, as_string); } else if(formatted.string[i] == ')') { /* Closing brace encountered, solve entire brace */ while(TRUE) { stack_peek(&ops, &top); if(top == '(') break; stack_pop(&values, &a); stack_pop(&values, &b); stack_pop(&ops, &op); result = apply_op(op, a, b); stack_push(&values, &result); } stack_pop(&ops, &unused); /* pop ( */ } else if(is_operator(formatted.string[i])) { /* While top of 'ops' has same or greater precedence to current token, which is an operator. Apply operator on top of 'ops' to top two elements in values stack */ while(TRUE) { top = '('; if(!stack_empty(&ops)) stack_peek(&ops, &top); if(stack_empty(&ops) || !has_precedence(formatted.string[i], top)) break; stack_pop(&values, &a); stack_pop(&values, &b); stack_pop(&ops, &op); result = apply_op(op, a, b); /* !!!!!!!!!!!!!!!!!!!! if(division_by_zero) { return -255; } */ stack_push(&values, &result); } /* Push current token to 'ops'. */ as_string[0] = formatted.string[i]; stack_push(&ops, as_string); } } /* Entire expression has been parsed at this point, apply remaining ops to remaining values */ while(!stack_empty(&ops)) { stack_pop(&values, &a); stack_pop(&values, &b); stack_pop(&ops, &op); result = apply_op(op, a, b); stack_push(&values, &result); } /* Top of 'values' contains result, return it */ stack_pop(&values, &result); return result; }
/*- *--------------------------------------------------------------------- * ParseDoSrc -- * Given the name of a source, figure out if it is an attribute * and apply it to the targets if it is. Else decide if there is * some attribute which should be applied *to* the source because * of some special target and apply it if so. Otherwise, make the * source be a child of the targets in the list 'targets' * * Side Effects: * Operator bits may be added to the list of targets or to the source. * The targets may have a new source added to their lists of children. *--------------------------------------------------------------------- */ static void ParseDoSrc( struct growableArray *targets, struct growableArray *sources, int tOp, /* operator (if any) from special targets */ const char *src, /* name of the source to handle */ const char *esrc) { GNode *gn = Targ_FindNodei(src, esrc, TARG_CREATE); if ((gn->special & SPECIAL_SOURCE) != 0) { if (gn->special_op) { Array_FindP(targets, ParseDoOp, gn->special_op); return; } else { assert((gn->special & SPECIAL_MASK) == SPECIAL_WAIT); waiting++; return; } } switch (specType) { case SPECIAL_MAIN: /* * If we have noted the existence of a .MAIN, it means we need * to add the sources of said target to the list of things * to create. Note that this will only be invoked if the user * didn't specify a target on the command line. This is to * allow #ifmake's to succeed, or something... */ Lst_AtEnd(create, gn->name); /* * Add the name to the .TARGETS variable as well, so the user * can employ that, if desired. */ Var_Append(".TARGETS", gn->name); return; case SPECIAL_ORDER: /* * Create proper predecessor/successor links between the * previous source and the current one. */ if (predecessor != NULL) { Lst_AtEnd(&predecessor->successors, gn); Lst_AtEnd(&gn->preds, predecessor); } predecessor = gn; break; default: /* * In the case of a source that was the object of a :: operator, * the attribute is applied to all of its instances (as kept in * the 'cohorts' list of the node) or all the cohorts are linked * to all the targets. */ apply_op(targets, tOp, gn); if ((gn->type & OP_OPMASK) == OP_DOUBLEDEP) { LstNode ln; for (ln=Lst_First(&gn->cohorts); ln != NULL; ln = Lst_Adv(ln)){ apply_op(targets, tOp, (GNode *)Lst_Datum(ln)); } } break; } gn->order = waiting; Array_AtEnd(sources, gn); if (waiting) Array_Find(sources, ParseAddDep, gn); }