/******************************************************************** Fit traditional cubic to 2 points (x,y) and derivatives Cubic is of the form y = c3*x^3 + c2*x^2 + c1*x + c0 Return c3, c2, c1, c0 ********************************************************************/ void wn_fit_cubic_2p2d ( int *pcode, double coef[4], double x1,double y1,double dy1, double x2,double y2,double dy2 ) { double c[4]; double m,b; double xform[2]; double accum[5],next_accum[5]; int i,j; *pcode = WN_SUCCESS; if(x1 == x2) { *pcode = WN_SINGULAR; return; } /* compute mapping from x space to -1 +1 space */ m = 2.0/(x2-x1); b = 1.0 - m*x2; dy1 /= m; dy2 /= m; /* compute coefs assuming x1==-1,x2==1 */ c[2] = (1.0/4.0)*(dy2-dy1); c[0] = (1.0/2.0)*(y2+y1) - c[2]; c[3] = (1.0/2.0)*(y1+dy1 + c[2] - c[0]); c[1] = dy2 - 3.0*c[3] - 2.0*c[2]; /* use mapping to transform cubic */ wn_zero_vect(coef,4); wn_zero_vect(accum,4); accum[0] = 1.0; xform[0] = b; xform[1] = m; for(i=0;i<4;++i) { for(j=0;j<=i;++j) { coef[j] += c[i]*accum[j]; } wn_mult_polys(next_accum,accum,i+1,xform,2); wn_copy_vect(accum,next_accum,i+2); } *pcode = WN_SUCCESS; }
void wn_mult_polys(double out[],double in1[],int len1,double in2[],int len2) { int i1,i2; wn_zero_vect(out,len1+len2-1); for(i1=0;i1<len1;++i1) for(i2=0;i2<len2;++i2) { out[i1+i2] += in1[i1]*in2[i2]; } }
local void reset_search_direction ( wn_cdn_context_type c, wn_cdn_srchdir_type search_direction ) { if(search_direction->dir_vect != NULL) { wn_zero_vect(search_direction->dir_vect,c->num_vars); } search_direction->x_min = -WN_FHUGE; search_direction->x_max = WN_FHUGE; search_direction->x0 = 0.0; search_direction->curvature = 0.0; search_direction->x_width = 0.0; search_direction->max_x_width = WN_FHUGE; }
EXTERN void wn_conj_direction_method ( int *pcode, double *pval_min, double vect[], double initial_coord_x0s[], int passed_num_vars, double (*pfunction)(double vect[]), int max_func_calls ) { int i,j,iteration; double *old_vect,*coord_direction; double *new_search_direction; double old_val_min; wn_memgp conj_dir_memgp; wn_gpmake("no_free"); force_optimize_stop_flag = FALSE; num_vars = passed_num_vars; max_num_search_directions = num_vars; wn_make_vect(&buffer_vect,num_vars); search_directions = (double **)wn_zalloc( max_num_search_directions*sizeof(double *)); wn_make_vect(&old_vect,num_vars); wn_make_vect(&coord_direction,num_vars); wn_make_vect(&coord_x0s,num_vars); wn_make_vect(&search_direction_x0s,max_num_search_directions); wn_make_vect(&coord_as,num_vars); wn_make_vect(&search_direction_as,max_num_search_directions); if(initial_coord_x0s == NULL) { wn_zero_vect(coord_x0s,num_vars); } else { wn_copy_vect(coord_x0s,initial_coord_x0s,num_vars); } wn_zero_vect(search_direction_x0s,max_num_search_directions); wn_zero_vect(coord_as,num_vars); wn_zero_vect(search_direction_as,max_num_search_directions); /* name and pop the memory group we created */ conj_dir_memgp = wn_curgp(); wn_gppop(); sqrt_tolerance = sqrt(wn_machine_tolerance()); num_search_directions = 0; num_func_calls = 0; last_line_function_x_valid = FALSE; *pval_min = wn_clip_f((*pfunction)(vect)); ++num_func_calls; for(iteration=0;;++iteration) { if(wn_conj_direction_debug >= WN_CONJ_DIR_DBG_PASSES) { printf("iteration = %d ********************************\n",iteration); printf("ob = %lg\n",*pval_min); fflush(stdout); } /* (void)getchar(); */ old_val_min = *pval_min; wn_copy_vect(old_vect,vect,num_vars); /* minimize along acceleration search directions */ if(wn_conj_direction_debug >= WN_CONJ_DIR_DBG_LINESEARCH) { printf("start acceleration line minimizations ------------------\n"); } for(i=0;i<num_search_directions;++i) { if(wn_conj_direction_debug >= WN_CONJ_DIR_DBG_LINESEARCH) { printf("acceleration line search %d\n",i); } line_minimize(vect,search_directions[i],pval_min, &(search_direction_x0s[i]),&(search_direction_as[i]), pfunction); if( ((max_func_calls < WN_IHUGE)&&(num_func_calls > max_func_calls)) || force_optimize_stop_flag ) { *pcode = WN_SUBOPTIMAL; goto finish; } } /* minimize along coordinate directions */ if(wn_conj_direction_debug >= WN_CONJ_DIR_DBG_LINESEARCH) { printf("start coordinate line minimizations ------------------\n"); } for(i=0;i<num_vars;++i) { if(wn_conj_direction_debug >= WN_CONJ_DIR_DBG_LINESEARCH) { printf("coord line search %d\n",i); } coord_direction[i] = 1.0; line_minimize(vect,coord_direction,pval_min, &(coord_x0s[i]),&(coord_as[i]), pfunction); coord_direction[i] = 0.0; if( ((max_func_calls < WN_IHUGE)&&(num_func_calls > max_func_calls)) || force_optimize_stop_flag ) { *pcode = WN_SUBOPTIMAL; goto finish; } } if(*pval_min >= old_val_min) { wn_assert(*pval_min == old_val_min); *pcode = WN_SUCCESS; break; } /* compute new acceleration search direction */ if(num_search_directions < max_num_search_directions) { wn_gppush(conj_dir_memgp); wn_make_vect(&new_search_direction,num_vars); wn_gppop(); for(i=num_search_directions;i>0;--i) { search_directions[i] = search_directions[i-1]; search_direction_x0s[i] = search_direction_x0s[i-1]; search_direction_as[i] = search_direction_as[i-1]; } search_directions[0] = new_search_direction; search_direction_x0s[0] = 1.0; search_direction_as[0] = 0.0; ++num_search_directions; } else { new_search_direction = search_directions[max_num_search_directions-1]; for(i=max_num_search_directions-1;i>0;--i) { search_directions[i] = search_directions[i-1]; search_direction_x0s[i] = search_direction_x0s[i-1]; search_direction_as[i] = search_direction_as[i-1]; } search_directions[0] = new_search_direction; search_direction_x0s[0] = 1.0; search_direction_as[0] = 0.0; } for(j=0;j<num_vars;++j) { new_search_direction[j] = vect[j] - old_vect[j]; } } finish: ; force_optimize_stop_flag = FALSE; last_line_function_x_valid = FALSE; wn_gppush(conj_dir_memgp); wn_gpfree(); }
local void mat_test_big_simplex() { double val,objective,*solution_vect,*objective_vect,*right_side,**mat; int vars,eqs; int len_i,len_j,code,i,j; wn_gpmake("no_free"); /* temp memory group */ vars = LEN; eqs = LEN; len_i = eqs; len_j = vars+eqs; wn_make_mat(&mat,len_i,len_j); wn_make_vect(&solution_vect,len_j); wn_make_vect(&objective_vect,len_j); wn_make_vect(&right_side,len_i); for(j=0;j<len_j;++j) { val = wn_normal_distribution(); /* if(val < 0.0) { val = -val; } */ objective_vect[j] = val; /* objective_vect[j] = 1.0; */ } for(i=0;i<len_i;++i) { val = wn_normal_distribution(); if(val < 0.0) { val = -val; } right_side[i] = val; } for(i=0;i<len_i;++i) { wn_zero_vect(mat[i],len_j); for(j=0;j<vars;++j) { val = wn_normal_distribution(); if(val < 0.0) { val = -val; } mat[i][j] = val; } mat[i][vars+i] = 1; } wn_simplex_method(&code,&objective,NULL,solution_vect, objective_vect,mat,right_side, len_i,len_j); wn_assert(WN_SUCCESS == code); wn_gpfree(); } /* mat_test_big_simplex */
local void mat_test_gramm_schmidt(void) { double **mat, **mat_orig; int ilen, jlen, code; /* ilen rows, jlen columns */ int a, b; double *sum_vect, mul, mul2; int trial; for (trial = 0; trial < 1000; ++trial) { wn_gpmake("no_free"); /* temp memory group */ jlen = (unsigned) wn_random_int() % 20 + 1; ilen = (unsigned) wn_random_int() % jlen + 1; wn_make_mat(&mat_orig, ilen, jlen); wn_random_mat(mat_orig, ilen, jlen); wn_make_mat(&mat, ilen, jlen); for (a = 0; a < ilen; ++a) { for (b = 0; b < jlen; ++b) { mat[a][b] = mat_orig[a][b]; } } wn_gramm_schmidt(&code, mat, ilen, jlen); wn_assert(WN_SUCCESS == code); /* first ilen vects should be orthogonal */ for (a = 0; a < ilen; ++a) { for (b = a+1; b < ilen; ++b) { wn_assert(LO_ALMOST_EQUAL(0.0, wn_dot_vects(mat[a], mat[b], jlen))); } } /* let's make the gramm_schmidt be unit vectors, to be simple */ for (a = 0; a < ilen; ++a) { mul2 = wn_dot_vects(mat[a], mat[a], jlen); mul = 1/sqrt(mul2); for (b = 0; b < jlen; ++b) { mat[a][b] *= mul; } wn_assert(LO_ALMOST_EQUAL(1.0, wn_dot_vects(mat[a], mat[a], jlen))); } /* check again orthogonality */ for (a = 0; a < ilen; ++a) { for (b = a+1; b < ilen; ++b) { wn_assert(LO_ALMOST_EQUAL(0.0, wn_dot_vects(mat[a], mat[b], jlen))); } } /* make a vector in the space spanned by the original vectors */ wn_make_vect(&sum_vect, jlen); wn_zero_vect(sum_vect, jlen); for (a = 0; a < ilen; ++a) { wn_add_scaled_vect(sum_vect, mat_orig[a], wn_flat_distribution(), /**/ jlen); } /* OK, sum_vect is reached from the original matrix of vectors */ /* can we reach it from mat? */ for (a = 0; a < ilen; ++a) { mul = wn_dot_vects(sum_vect, mat[a], jlen); wn_add_scaled_vect(sum_vect, mat[a], -mul, jlen); } wn_assert(LO_ALMOST_EQUAL(0.0, wn_dot_vects(sum_vect, sum_vect, jlen))); wn_gpfree(); } /* for trial */ } /* mat_test_gramm_schmidt */
local void gradient(double grad[],double v[]) { double diff,conductance_sum; int i; wn_sll el; wn_sparse_matrix_entry entry; printf("gradient. count = %d\n",count); ++count; wn_zero_vect(grad,len); for(i=0;i<len;++i) { if(stimulus_type_vect[i] != voltage) { if(stimulus_type_vect[i] == current) { /* currents at each node must sum to drive current */ diff = stimulus_vect[i]; } else { /* currents at each node must sum to zero */ diff = 0.0; } conductance_sum = 0.0; for(el=(conductance_graph->i_lists)[i];el!=NULL;el=el->next) { entry = (wn_sparse_matrix_entry)(el->contents); conductance_sum += entry->value; } diff -= v[i]*conductance_sum; for(el=(conductance_graph->i_lists)[i];el!=NULL;el=el->next) { entry = (wn_sparse_matrix_entry)(el->contents); if(stimulus_type_vect[entry->j] == voltage) { diff += stimulus_vect[entry->j]*entry->value; } else { diff += v[entry->j]*entry->value; } } grad[i] += 2.0*diff*(-conductance_sum); for(el=(conductance_graph->i_lists)[i];el!=NULL;el=el->next) { entry = (wn_sparse_matrix_entry)(el->contents); if(stimulus_type_vect[entry->j] != voltage) { grad[entry->j] += 2.0*diff*entry->value; } } } } }
void wn_make_vect(double **pvect,int len) { *pvect = (double *)wn_alloc(len*sizeof(double)); wn_zero_vect(*pvect,len); }