int main(void) { double *vect1,*vect2,*vect3; wn_gpmake("general_free"); wn_make_vect(&vect1,LEN); wn_make_vect(&vect2,LEN); wn_make_vect(&vect3,LEN); wn_random_vect(vect1,LEN); wn_print_vect(vect1,LEN); wn_copy_vect(vect2,vect1,LEN); wn_print_vect(vect1,LEN); wn_random_vect(vect2,LEN); printf("v1.v2 = %lf\n",wn_dot_vects(vect1,vect2,LEN)); printf("v1.v1 = %lf\n",wn_dot_vects(vect1,vect1,LEN)); printf("norm2(v1) = %lf\n",wn_norm2_vect(vect1,LEN)); printf("norm(v1) = %lf\n",wn_norm_vect(vect1,LEN)); printf("corr(v1,v2)) = %lf\n", wn_dot_vects(vect1,vect2,LEN)/ (wn_norm_vect(vect1,LEN)*wn_norm_vect(vect2,LEN))); wn_free_vect(vect1,LEN); wn_gpfree(); return(0); }
void wn_cdn_set_solution ( wn_cdn_context_type c, double vect[] ) { wn_copy_vect(c->current_vect,vect,c->num_vars); }
/******************************************************************** 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_cdn_compute_func_call_vect ( wn_cdn_context_type c, double *search_direction, double x ) { wn_copy_vect(c->func_call_vect,c->current_vect,c->num_vars); wn_add_scaled_vect(c->func_call_vect,search_direction,x,c->num_vars); }
void wn_cdn_get_solution ( wn_cdn_context_type c, int *pcode, double *pob, double vect[] ) { *pcode = c->code; *pob = c->ob; wn_copy_vect(vect,c->current_vect,c->num_vars); }
local double line_function(double x) { double ret; if(last_line_function_x_valid) { if(x == last_line_function_x) { return(last_line_function_ret); } } wn_copy_vect(save_vect,buffer_vect,num_vars); wn_add_scaled_vect(save_vect,save_direction,x,num_vars); if(wn_conj_direction_debug >= WN_CONJ_DIR_DBG_ALL) { printf("function call %d at ",num_func_calls); wn_print_vect(save_vect,num_vars); } ++num_func_calls; ret = wn_clip_f((*save_pfunction)(save_vect)); if(wn_conj_direction_debug >= WN_CONJ_DIR_DBG_ALL) { printf("function value is %lg\n",ret); fflush(stdout); } last_line_function_x_valid = TRUE; last_line_function_x = x; last_line_function_ret = ret; return(ret); }
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 line_minimize ( double vect[], double direction[], double *pval_min, double *psave_x0, double *psave_a, double (*pfunction)(double vect[]) ) { double ax,bx,cx,x0,fa,fb,fc,fx0; double a,b; double old_x0,old_a; int code; if(wn_conj_direction_debug >= WN_CONJ_DIR_DBG_LINESEARCH) { printf("start line minimize.\n"); } last_line_function_x_valid = FALSE; wn_copy_vect(buffer_vect,vect,num_vars); save_vect = vect; save_direction = direction; save_pfunction = pfunction; old_x0 = *psave_x0; old_a = *psave_a; bx = 0.0; fb = *pval_min; if(wn_conj_direction_debug >= WN_CONJ_DIR_DBG_ALL) { printf("First point at %lg, function value = %lg\n", bx, fb); } if(old_x0 == 0.0) { old_x0 = 1.0; } ax = old_x0*wn_random_double_between(0.9,1.1); if(wn_conj_direction_debug >= WN_CONJ_DIR_DBG_ALL) { printf("Second point at %lg (old_x0 = %lg)\n", ax, old_x0); } fa = line_function(ax); if(!(old_a > 0.0)) { goto simple_parabola_fit; } /* the curvature along a search direction is constant for a quadratic function, therefore, try to use the curvature from the last search */ fit_parabola_2pa(&code,&x0,&b,old_a,ax,fa,bx,fb); if( (code != WN_SUCCESS) || (!(wn_abs(x0)<MAX_EXPAND*wn_abs(old_x0)) && (*psave_x0 != 0.0)) || too_close(x0, ax) || too_close(x0, bx) || !is_valid_number(x0) || !is_valid_number(ax) || !is_valid_number(bx) ) { goto simple_parabola_fit; } cx = x0; if(wn_conj_direction_debug >= WN_CONJ_DIR_DBG_ALL) { printf("Third point at %lg\n", cx); } fc = line_function(cx); wn_fit_parabola_3p(&code,&a,&x0,&b,ax,fa,bx,fb,cx,fc); if((code != WN_SUCCESS)||(!(a > 0.0))|| (!(wn_abs(x0)<MAX_EXPAND*wn_abs(old_x0))&&(*psave_x0 != 0.0))) { goto full_linesearch; } if(!(b < fb)) { if(wn_conj_direction_debug >= WN_CONJ_DIR_DBG_ALL) { printf("Doing slow line search (parabola fit returned suspect min value).\n"); } goto full_linesearch; } if((!(fc < fb))||(!(fc < fa))) { /* evaluate one more point */ goto evaluate_x0; } /* is it economical to evaluate one more point? */ if((fb-b) <= 1.5*(fb-fc)) { /* do not evaluate one more point */ wn_swap(fb,fc,double); wn_swap(bx,cx,double); goto finish; } else { /* evaluate one more point */ goto evaluate_x0; } simple_parabola_fit: if(fa < fb) { cx = 2.0*ax*wn_random_double_between(0.8,1.2); } else { cx = -1.0*ax*wn_random_double_between(0.8,1.2); } fc = line_function(cx); wn_fit_parabola_3p(&code,&a,&x0,&b,ax,fa,bx,fb,cx,fc); if((code != WN_SUCCESS)||(!(a > 0.0))|| (!(wn_abs(x0)<MAX_EXPAND*wn_abs(old_x0))&&(*psave_x0 != 0.0))) { if(wn_conj_direction_debug >= WN_CONJ_DIR_DBG_ALL) { printf("Parabola fit failed. Switching to slow line search mode.\n"); } goto full_linesearch; } evaluate_x0: fx0 = line_function(x0); if(!(fx0 <= fb)) { if(wn_conj_direction_debug >= WN_CONJ_DIR_DBG_ALL) { printf("Doing a slow line search because f(x0) is too large (x0 = %lg).\n", x0); } goto full_linesearch; } fb = fx0; bx = x0; if(!(fa <= fc)) { wn_swap(fa,fc,double); wn_swap(ax,cx,double); } if(!(fb <= fa)) { wn_swap(fb,fa,double); wn_swap(bx,ax,double); } goto finish; full_linesearch: ; /* printf("now.\n"); */ do { if(ax == bx) { if(wn_random_bit()) { ax += wn_random_double_between(-1.0,1.0); fa = line_function(ax); } else { bx += wn_random_double_between(-1.0,1.0); fb = line_function(bx); } } if(ax == cx) { if(wn_random_bit()) { ax += wn_random_double_between(-1.0,1.0); fa = line_function(ax); } else { cx += wn_random_double_between(-1.0,1.0); fc = line_function(cx); } } if(bx == cx) { if(wn_random_bit()) { bx += wn_random_double_between(-1.0,1.0); fb = line_function(bx); } else { cx += wn_random_double_between(-1.0,1.0); fc = line_function(cx); } } } while((ax == bx)||(ax == cx)||(bx == cx)); wn_minimize_1d_raw(&code,&fa,&fb,&fc,&ax,&bx,&cx,fb,&line_function,1,20); /* printf("l = %lf\n",bx); */ finish: ; /* if(show_linesearch) { printf("ax=%lg,bx=%lg,cx=%lg,old_x0=%lg\n",ax,bx,cx,old_x0); } */ wn_copy_vect(vect,buffer_vect,num_vars); /* compute *psave_x0 */ if(wn_abs(bx) < MIN_CONTRACT*wn_abs(old_x0)) { if(bx < 0.0) { *psave_x0 = -MIN_CONTRACT*wn_abs(old_x0); } else { *psave_x0 = MIN_CONTRACT*wn_abs(old_x0); } } else { *psave_x0 = bx; } /* compute *psave_a */ wn_fit_parabola_3p(&code,&a,&x0,&b,ax,fa,bx,fb,cx,fc); if((code != WN_SUCCESS)||(!(a > 0.0))) { *psave_a = 0.0; } else { *psave_a = a; } if(*pval_min == fb) { if(wn_conj_direction_debug >= WN_CONJ_DIR_DBG_LINESEARCH) { printf("finish line minimize.\n"); fflush(stdout); } return; /* do not move if no improvement */ } wn_add_scaled_vect(vect,direction,bx,num_vars); *pval_min = fb; if(wn_conj_direction_debug >= WN_CONJ_DIR_DBG_LINESEARCH) { printf("finish line minimize.\n"); fflush(stdout); } }
local void line_minimize ( wn_cdn_context_type c, wn_cdn_srchdir_type search_direction, double *px_width_sum ) { double *search_direction_vect; double poly[3],poly_total_noise[3]; double xopt,fopt,dfopt,fopt_noise,dfopt_noise; double x_width; double x0,x1,x2,f0,f1,f2,df0,df1,df2, f0_noise,f1_noise,f2_noise,df0_noise,df1_noise,df2_noise; int code; double a; double diff_noise; printf("line minimize: coord = %d\n", search_direction->coord); printf(" x_width = %lg\n",search_direction->x_width); x_width = search_direction->x_width; find_taylor_poly(c,poly,poly_total_noise,search_direction,0.0); if(poly_total_noise[1] == 0.0) { search_direction->ratio_df1_noise = WN_FHUGE; } else { search_direction->ratio_df1_noise = wn_abs(poly[1])/poly_total_noise[1]; } printf(" x_width = %lg\n",search_direction->x_width); printf("poly=\n"); wn_print_vect(poly,3); printf("poly_total_noise=\n"); wn_print_vect(poly_total_noise,3); /* try to find min using slope and curvature - this should work most of the time */ if(poly[2] >= 2.0*poly_total_noise[2]) { xopt = -0.5*poly[1]/poly[2]; printf(" xopt = %lg\n",xopt); if((-x_width < xopt)&&(xopt < x_width)) { printf("slope-curvature method successful!!!!!!\n"); fopt = wn_eval_poly(xopt,poly,3); goto finish; } else { printf("slope-curvature method failed because xopt too far out\n"); x0 = xopt; } } else { printf("slope-curvature method failed because non-positive curvature\n"); x0 = search_direction->x0; if(x0 == 0.0) { x0 = search_direction->x_width; } if(poly[1] < 0.0) { x0 = wn_abs(x0); } else if(poly[1] > 0.0) { x0 = -wn_abs(x0); } } if((-search_direction->x_width < x0)&&(x0 < search_direction->x_width)) { if(x0 < 0.0) { x0 = -search_direction->x_width; } else { wn_assert(x0 >= 0.0); x0 = search_direction->x_width; } } /* try secant method using slopes */ secant: ; printf("trying secant method....\n"); x1 = 0.0; f1 = poly[0]; df1 = poly[1]; f1_noise = poly_total_noise[0]; df1_noise = poly_total_noise[1]; find_taylor_poly(c,poly,poly_total_noise,search_direction,x0); f0 = poly[0]; df0 = poly[1]; f0_noise = poly_total_noise[0]; df0_noise = poly_total_noise[1]; printf("x0 = %lg\n",x0); printf("poly=\n"); wn_print_vect(poly,3); printf("poly_total_noise=\n"); wn_print_vect(poly_total_noise,3); wn_fit_parabola_2d(&code,&a,&xopt,x0,df0,x1,df1); printf("code = %d,a = %lg, xopt = %lg\n",code,a,xopt); if((code != WN_SUCCESS)||(!(a > 0.0))|| (!(wn_abs(xopt)<MAX_EXPAND*wn_abs(x0)))) { printf("secant method failed because parabola fit failed.\n"); goto full_linesearch; } find_taylor_poly(c,poly,poly_total_noise,search_direction,xopt); fopt = poly[0]; dfopt = poly[1]; fopt_noise = poly_total_noise[0]; dfopt_noise = poly_total_noise[1]; printf("xopt = %lg\n",xopt); printf("poly=\n"); wn_print_vect(poly,3); printf("poly_total_noise=\n"); wn_print_vect(poly_total_noise,3); diff_noise = sqrt(wn_square(f1_noise)+wn_square(fopt_noise)); if((fopt-f1) > 2.0*diff_noise) { printf("secant method failed because f increased too much\n"); goto full_linesearch; } if(!(wn_abs(dfopt) <= wn_abs(df1))) { printf("secant method failed because df increased\n"); goto full_linesearch; } printf("secant method successful!!!!!!\n"); goto finish; /* full linesearch: search out, or in by 2x steps*/ full_linesearch: ; if(wn_abs(df1) <= 2.0*df1_noise) { xopt = x1; fopt = f1; dfopt = df1; printf("full linesearch failed because slope indistinguishable from 0\n"); goto finish; } if(df1 < 0.0) { wn_assert(x0 > 0.0); } else if(df1 > 0.0) { wn_assert(x0 < 0.0); } else { wn_assert_notreached(); } printf("df1 = %lg,df0 = %lg\n",df1,df0); if(wn_sign(df1) == wn_sign(df0)) { printf("searching outward....\n"); /* search outward until slopes differ */ while(wn_sign(df1) == wn_sign(df0)) { xopt = x0; fopt = f0; dfopt = df0; x0 *= 2.0; find_taylor_poly(c,poly,poly_total_noise,search_direction,x0); f0 = poly[0]; df0 = poly[1]; printf("xopt=%lg,fopt=%lg,dfopt=%lg,x0=%lg,f0=%lg,df0=%lg,x1=%lg,f1=%lg,df1=%lg\n", xopt,fopt,dfopt,x0,f0,df0,x1,f1,df1); } } else if(wn_sign(df1) == -wn_sign(df0)) { xopt = x0; fopt = f0; dfopt = df0; printf("searching inward....\n"); while(wn_sign(dfopt) == -wn_sign(df1)) { xopt *= 0.5; find_taylor_poly(c,poly,poly_total_noise,search_direction,xopt); fopt = poly[0]; dfopt = poly[1]; printf("xopt=%lg,fopt=%lg,dfopt=%lg,x1=%lg,f1=%lg,df1=%lg\n", xopt,fopt,dfopt,x1,f1,df1); } } else { wn_assert_notreached(); } finish: ; compute_search_direction_vect(c,&search_direction_vect,search_direction); wn_cdn_compute_func_call_vect(c,search_direction_vect,xopt); wn_copy_vect(c->current_vect,c->func_call_vect,c->num_vars); retire_search_direction_vect(c,&search_direction_vect,search_direction); if(xopt != 0.0) { (*px_width_sum) += wn_abs(xopt)/search_direction->x_width; } c->ob = fopt; printf("finish: xopt = %lg, fopt = %lg\n",xopt,fopt); }
void wn_cdn_optimize ( wn_cdn_context_type c, int num_func_calls ) { int i,j,iteration; double *old_vect,*coord_direction; wn_cdn_srchdir_type new_search_direction; double old_ob; double x_width_sum; wn_gppush(c->current_group); c->force_optimize_stop_flag = FALSE; if(num_func_calls >= WN_IHUGE) { c->max_num_func_calls = WN_IHUGE; } else { c->max_num_func_calls = c->num_func_calls + num_func_calls; } if(c->code == WN_CDN_NOT_STARTED) { c->code = WN_SUBOPTIMAL; c->ob = wn_clip_f((*(c->pfunction))(c->current_vect,c->num_func_calls)); ++(c->num_func_calls); } for(iteration=0;;++iteration) { /* if(wn_cdn_debug >= WN_CDN_DBG_PASSES) */ { printf("iteration = %d ********************************\n",iteration); printf("num_func_calls = %d\n",c->num_func_calls); printf("ob = %lg\n",c->ob); printf("vect = \n"); wn_print_vect(c->current_vect,c->num_vars); fflush(stdout); } /* (void)getchar(); */ old_ob = c->ob; wn_copy_vect(c->old_vect,c->current_vect, c->num_vars); x_width_sum = 0.0; /* minimize along acceleration search directions */ if(wn_cdn_debug >= WN_CDN_DBG_LINESEARCH) { printf("start acceleration line minimizations ------------------\n"); } for(i=0;i<c->num_search_directions;++i) { if(wn_cdn_debug >= WN_CDN_DBG_LINESEARCH) { printf("acceleration line search %d\n",i); } line_minimize(c,(c->search_direction_array)[i],&x_width_sum); if( ( (c->max_num_func_calls < WN_IHUGE) && (c->num_func_calls > c->max_num_func_calls) ) || c->force_optimize_stop_flag ) { c->code = WN_SUBOPTIMAL; goto finish; } } /* minimize along coordinate directions */ if(wn_cdn_debug >= WN_CDN_DBG_LINESEARCH) { printf("start coordinate line minimizations ------------------\n"); } for(i=0;i<c->num_vars;++i) { if(wn_cdn_debug >= WN_CDN_DBG_LINESEARCH) { printf("coord line search %d\n",i); } line_minimize(c,(c->coord_search_direction_array)[i],&x_width_sum); if( ( (c->max_num_func_calls < WN_IHUGE) && (c->num_func_calls > c->max_num_func_calls) ) || c->force_optimize_stop_flag ) { c->code = WN_SUBOPTIMAL; goto finish; } } recompute_num_line_samples(c); if(!vects_equal(c->current_vect,c->old_vect,c->num_vars)) { /* compute new acceleration search direction */ if(c->num_search_directions < c->max_num_search_directions) { make_search_direction(c,&new_search_direction,FALSE,-1); for(i=c->num_search_directions;i>0;--i) { (c->search_direction_array)[i] = (c->search_direction_array)[i-1]; } (c->search_direction_array)[0] = new_search_direction; ++(c->num_search_directions); } else { new_search_direction = (c->search_direction_array)[(c->max_num_search_directions) - 1]; reset_search_direction(c,new_search_direction); for(i=c->max_num_search_directions-1;i>0;--i) { (c->search_direction_array)[i] = (c->search_direction_array)[i-1]; } (c->search_direction_array)[0] = new_search_direction; } for(j=0;j<c->num_vars;++j) { (new_search_direction->dir_vect)[j] = (c->current_vect)[j] - (c->old_vect)[j]; } new_search_direction->x0 = 1.0; new_search_direction->x_width = 1.0/x_width_sum; new_search_direction->max_x_width = 100.0*new_search_direction->x_width; } } finish: ; c->force_optimize_stop_flag = FALSE; wn_gppop(); }
EXTERN void wn_conj_gradient_method ( int *pcode, double *pval_min, double vect[], int len, double (*pfunction)(double vect[]), void (*pgradient)(double grad[],double vect[]), int max_iterations ) { int iteration,no_move_count; int stable_satisfy_count; double norm2_g,norm2_last_g,g_dot_last_g,val,last_val,beta, jump_len,last_jump_len,alpha; double *g,*last_g,*direction; bool function_free_method,last_was_function_free_method; bool first_parabolic_fit_succeeded; double computed_g_dot_dlast; old_group = wn_curgp(); wn_gpmake("no_free"); wn_force_optimize_stop_flag = FALSE; wn_make_vect(&buffer_vect,len); wn_make_vect(&g,len); wn_make_vect(&last_g,len); wn_make_vect(&direction,len); function_free_method = FALSE; stable_satisfy_count = 0; last_was_function_free_method = FALSE; jump_len = 1.0; no_move_count = 0; beta = 0.0; wn_gppush(old_group); val = (*pfunction)(vect); (*pgradient)(g,vect); wn_copy_vect(direction,g,len); norm2_g = wn_norm2_vect(g,len); for(iteration=0;;++iteration) { last_dy1 = dy1; last_jump_len = jump_len; wn_swap(last_g,g,double *); /* move g to last g */ norm2_last_g = norm2_g; if(function_free_method) { double x2; double g0_dot_d0,g1s_dot_d0,dot_diff; dy1 = wn_dot_vects(direction,last_g,len); last_jump_len = -wn_sign(dy1)*wn_abs(last_jump_len); x2 = last_jump_len; /* printf("last_jump_len = %lg\n",last_jump_len); */ wn_add_vect_and_scaled_vect(buffer_vect,vect,direction,last_jump_len,len); (*pgradient)(g,buffer_vect); /* g0_dot_d0 = wn_dot_vects(last_g,direction,len); */ g0_dot_d0 = dy1; g1s_dot_d0 = wn_dot_vects(g,direction,len); dot_diff = g0_dot_d0-g1s_dot_d0; if(!(dot_diff > 0.0)) /* not upward facing parabola */ { stable_satisfy_count = 0; goto function_based_method; } alpha = g0_dot_d0/dot_diff; /* printf("alpha = %lg\n",alpha); */ if(!(((1.0-10000.0) < alpha)&&(alpha < (1.0+10000.0)))) { stable_satisfy_count = 0; goto function_based_method; } jump_len = alpha*last_jump_len; /* g[j] = alpha*g[j] + (1.0-alpha)*last_g[j]; */ wn_scale_vect(g,alpha,len); wn_add_scaled_vect(g,last_g,1.0-alpha,len); g_dot_last_g = wn_dot_vects(g,last_g,len); if(beta != 0.0) { computed_g_dot_dlast = -g_dot_last_g/beta; /* printf("computed_g_dot_dlast=%lg,last_dy1=%lg\n", computed_g_dot_dlast,last_dy1); */ if(!(wn_abs(computed_g_dot_dlast) < 0.4*wn_abs(last_dy1))) { stable_satisfy_count = 0; goto function_based_method; } } wn_add_scaled_vect(vect,direction,alpha*last_jump_len,len); if( wn_force_optimize_stop_flag || ((max_iterations < WN_IHUGE)&&(iteration >= max_iterations)) ) { wn_force_optimize_stop_flag = FALSE; wn_gppop(); wn_gpfree(); val = (*pfunction)(vect); *pval_min = val; *pcode = WN_SUBOPTIMAL; return; } } else /* function based method */ { function_based_method: if(last_was_function_free_method) { /* set so that next iteration will succeed */ val = (*pfunction)(vect); } function_free_method = FALSE; if(norm2_last_g == 0.0) /* unlikely */ { wn_gppop(); wn_gpfree(); *pval_min = val; *pcode = WN_SUCCESS; return; } last_val = val; line_minimize(pcode,&first_parabolic_fit_succeeded,&val,&jump_len, vect, direction,last_val,last_g,last_jump_len,len,pfunction); if(*pcode != WN_SUCCESS) { wn_gppop(); wn_gpfree(); *pval_min = val; return; } if( wn_force_optimize_stop_flag || ((max_iterations < WN_IHUGE)&&(iteration >= max_iterations)) ) { wn_force_optimize_stop_flag = FALSE; wn_gppop(); wn_gpfree(); *pval_min = val; *pcode = WN_SUBOPTIMAL; return; } wn_assert(val <= last_val); if(val == last_val) { if(no_move_count >= 2) { wn_gppop(); wn_gpfree(); *pval_min = val; *pcode = WN_SUCCESS; return; } else { ++no_move_count; jump_len = last_jump_len; } } else { no_move_count = 0; } (*pgradient)(g,vect); g_dot_last_g = wn_dot_vects(g,last_g,len); if((!first_parabolic_fit_succeeded)||(last_jump_len == 0.0)) { stable_satisfy_count = 0; goto no_function_method_test_fail; } alpha = jump_len/last_jump_len; if(!(((1.0-3000.0) < alpha)&&(alpha < (1.0+3000.0)))) { stable_satisfy_count = 0; goto no_function_method_test_fail; } if(beta != 0.0) { computed_g_dot_dlast = -g_dot_last_g/beta; /* printf("computed_g_dot_dlast=%lg,last_dy1=%lg\n", computed_g_dot_dlast,last_dy1); */ if(!(wn_abs(computed_g_dot_dlast) < 0.2*wn_abs(last_dy1))) { stable_satisfy_count = 0; goto no_function_method_test_fail; } } ++stable_satisfy_count; if(stable_satisfy_count > 3) { function_free_method = TRUE; } no_function_method_test_fail: ; } norm2_g = wn_norm2_vect(g,len); /* g_dot_last_g = wn_dot_vects(g,last_g,len); */ beta = (norm2_g - g_dot_last_g)/norm2_last_g; wn_add_vect_and_scaled_vect(direction,g,direction,beta,len); /* printf("norm(g) = %lg\n",wn_norm_vect(g,len)); printf("ob = %lg,beta = %lg,numerator=%lg,denom=%lg,norm2(direction)=%lg\n", val,beta,numerator,norm2_last_g,wn_norm2(direction)); printf("iteration = %d,ob = %lg\n",iteration,val); */ last_was_function_free_method = function_free_method; } }
local void line_minimize ( int *pcode, bool *pfirst_parabolic_fit_succeeded, double *pval, double *pjump_len, double vect[], double direction[], double last_val, double last_g[], double last_jump_len, int len, double (*pfunction)(double vect[]) ) { double a,x0,y0,b,x1,y1,x2,y2; int code; *pcode = WN_SUCCESS; x1 = 0.0; y1 = last_val; dy1 = wn_dot_vects(direction,last_g,len); if(last_jump_len == 0.0) { last_jump_len = 1.0; } last_jump_len = -wn_sign(dy1)*wn_abs(last_jump_len); x2 = last_jump_len; eval_function(&y2,vect,direction,x2,len,pfunction); wn_fit_parabola_2pd(&code,&a,&x0,&b,x1,y1,dy1,x2,y2); /* look for excuses to say that parabolic fit is no good */ if(code != WN_SUCCESS) { /* printf("parabola fit failed - probably a line.\n"); */ x0 = x2+GOLDEN_RATIO*x2; /* project outward */ eval_function(&y0,vect,direction,x0,len,pfunction); goto parabolic_fit_failed; } if(!(a > 0)) { /* printf("downward facing parabola.\n"); */ x0 = x2+GOLDEN_RATIO*x2; /* project outward */ eval_function(&y0,vect,direction,x0,len,pfunction); goto parabolic_fit_failed; } if(!(wn_abs(x0) < 10000.0*wn_abs(x2))) { /* printf("x0 too far out.\n"); */ x0 = 10000.0*x2; /* project outward */ eval_function(&y0,vect,direction,x0,len,pfunction); goto parabolic_fit_failed; } if(!(wn_abs(x0) > (1.0/10000.0)*wn_abs(x2))) { /* printf("x0 too far in.\n"); */ x0 = (1.0/10000.0)*x2; /* project inward */ eval_function(&y0,vect,direction,x0,len,pfunction); goto parabolic_fit_failed; } if(!(b < y1)) /* no improvement expected,weird form for Nan problems */ { /* printf("no improvement expected.\n"); */ x0 = GOLDEN_SECTION*x2; eval_function(&y0,vect,direction,x0,len,pfunction); goto parabolic_fit_failed; } eval_function(&y0,vect,direction,x0,len,pfunction); if(parabola_fit_improvement_wrong(y1,y0,b,0.25)) { /* printf("poor parabola fit detected.\n"); */ goto parabolic_fit_failed; } /* parabolic fit succeeded */ if(y0 > y1) { x0 = x1; y0 = y1; } *pval = y0; *pjump_len = x0; wn_copy_vect(vect,buffer_vect,len); *pfirst_parabolic_fit_succeeded = TRUE; /* *pfirst_parabolic_fit_succeeded = !parabola_fit_improvement_wrong(y1,y0,b,0.25); */ return; parabolic_fit_failed: *pfirst_parabolic_fit_succeeded = FALSE; save_vect = vect; save_direction = direction; save_len = len; save_pfunction = pfunction; wn_minimize_1d_raw(pcode,&y1,&y0,&y2,&x1,&x0,&x2,y1,(simple_eval_function), 3,20); if(!((*pcode == WN_SUCCESS)||(*pcode == WN_SUBOPTIMAL))) { return; } *pcode = WN_SUCCESS; if(y0 <= last_val) { *pval = y0; *pjump_len = x0; wn_add_scaled_vect(vect,direction,x0,len); } else { *pval = last_val; *pjump_len = 0.0; } return; }