00001
#include <volume_io/internal_volume_io.h>
00002
#include <bicpl/numerical.h>
00003
#include <bicpl/prog_utils.h>
00004
00005 #define DEFAULT_RATIO 1.0
00006
00007 private Real
evaluate_fit(
00008
int n_parameters,
00009 Real constant_term,
00010 LSQ_TYPE *linear_terms,
00011 LSQ_TYPE *square_terms,
00012
int n_cross_terms[],
00013
int *cross_parms[],
00014 LSQ_TYPE *cross_terms[],
00015 Real parm_values[] )
00016 {
00017
int parm, n;
00018 Real fit, parm_val;
00019
00020 fit = constant_term;
00021
00022 for_less( parm, 0, n_parameters )
00023 {
00024 parm_val = parm_values[parm];
00025 fit += parm_val * ((Real) linear_terms[parm] +
00026 parm_val * (Real) square_terms[parm]);
00027
00028 for_less( n, 0, n_cross_terms[parm] )
00029 fit += parm_val * parm_values[cross_parms[parm][n]] *
00030 (Real) cross_terms[parm][n];
00031 }
00032
00033
return( fit );
00034 }
00035
00036 private void evaluate_fit_derivative(
00037
int n_parameters,
00038 Real constant_term,
00039 LSQ_TYPE *linear_terms,
00040 LSQ_TYPE *square_terms,
00041
int n_cross_terms[],
00042
int *cross_parms[],
00043 LSQ_TYPE *cross_terms[],
00044 Real parm_values[],
00045 Real derivatives[] )
00046 {
00047
int parm, n, neigh_parm, n_terms, *cp;
00048 Real term, parm_val, deriv_p;
00049
LSQ_TYPE *ct;
00050
00051 for_less( parm, 0, n_parameters )
00052 derivatives[parm] = 0.0;
00053
00054 for_less( parm, 0, n_parameters )
00055 {
00056 parm_val = parm_values[parm];
00057
00058 deriv_p = (Real) linear_terms[parm] +
00059 2.0 * parm_val * (Real) square_terms[parm];
00060
00061 ct = cross_terms[parm];
00062 cp = cross_parms[parm];
00063 n_terms = n_cross_terms[parm];
00064 for_less( n, 0, n_terms )
00065 {
00066 neigh_parm = *cp++;
00067 term = (Real) (*ct++);
00068 deriv_p += term * parm_values[neigh_parm];
00069 derivatives[neigh_parm] += term * parm_val;
00070 }
00071 derivatives[parm] += deriv_p;
00072 }
00073 }
00074
00075 private void evaluate_fit_along_line(
00076
int n_parameters,
00077 Real constant_term,
00078 LSQ_TYPE *linear_terms,
00079 LSQ_TYPE *square_terms,
00080
int n_cross_terms[],
00081
int *cross_parms[],
00082 LSQ_TYPE *cross_terms[],
00083 Real parm_values[],
00084 Real negative_gradient[],
00085 Real line_coefs[],
00086 Real *a_ptr,
00087 Real *b_ptr )
00088 {
00089
int parm, n, n_terms, *cp;
00090 Real a, b, line_coef;
00091 Real a_inc;
00092
LSQ_TYPE *ct;
00093
00094 a = 0.0;
00095 b = 0.0;
00096
00097 for_less( parm, 0, n_parameters )
00098 {
00099 line_coef = line_coefs[parm];
00100 a_inc = line_coef * (Real) square_terms[parm];
00101
00102 ct = cross_terms[parm];
00103 cp = cross_parms[parm];
00104 n_terms = n_cross_terms[parm];
00105 for_less( n, 0, n_terms )
00106 a_inc += (Real) (*ct++) * line_coefs[*cp++];
00107
00108 a += line_coef * a_inc;
00109 b += line_coef * (-negative_gradient[parm]);
00110 }
00111
00112 *a_ptr = a;
00113 *b_ptr = b;
00114 }
00115
00116 private void minimize_along_line(
00117
int n_parameters,
00118 Real constant_term,
00119 LSQ_TYPE *linear_terms,
00120 LSQ_TYPE *square_terms,
00121
int n_cross_terms[],
00122
int *cross_parms[],
00123 LSQ_TYPE *cross_terms[],
00124 Real max_step_size,
00125 Real parm_values[],
00126 Real negative_gradient[],
00127 Real line_coefs[] )
00128 {
00129
int parm;
00130 Real a, b, t, step_size;
00131
static Real ratio;
00132
static BOOLEAN first =
TRUE;
00133
00134
if( first )
00135 {
00136 first =
FALSE;
00137
if( getenv(
"LSQ_STEP_RATIO" ) == 0 ||
00138 sscanf( getenv(
"LSQ_STEP_RATIO" ),
"%lf", &ratio ) != 1 )
00139 ratio =
DEFAULT_RATIO;
00140 }
00141
00142
evaluate_fit_along_line( n_parameters, constant_term, linear_terms,
00143 square_terms, n_cross_terms, cross_parms,
00144 cross_terms, parm_values, negative_gradient,
00145 line_coefs, &a, &b );
00146
00147
if( a == 0.0 )
00148
return;
00149
00150 t = ratio * -b / (2.0 * a);
00151
00152
if( max_step_size >= 0.0 )
00153 {
00154 step_size = 0.0;
00155 for_less( parm, 0, n_parameters )
00156 step_size += t * t * line_coefs[parm] * line_coefs[parm];
00157
00158 step_size = sqrt( step_size );
00159
if( step_size > max_step_size )
00160 t *= max_step_size / step_size;
00161 }
00162
00163 for_less( parm, 0, n_parameters )
00164 parm_values[parm] += t * line_coefs[parm];
00165 }
00166
00167 private Real
private_minimize_lsq(
00168
int n_parameters,
00169 Real constant_term,
00170 LSQ_TYPE *linear_terms,
00171 LSQ_TYPE *square_terms,
00172
int n_cross_terms[],
00173
int *cross_parms[],
00174 LSQ_TYPE *cross_terms[],
00175 Real max_step_size,
00176
int n_iters,
00177 Real parm_values[] )
00178 {
00179 Real fit, len, gg, dgg, gam;
00180
int iter, p;
00181
int update_rate;
00182 Real *unit_dir, *g, *h, *xi;
00183 Real last_update_time, current_time;
00184
00185 ALLOC( g, n_parameters );
00186 ALLOC( h, n_parameters );
00187 ALLOC( xi, n_parameters );
00188 ALLOC( unit_dir, n_parameters );
00189
00190 fit =
evaluate_fit( n_parameters, constant_term, linear_terms,
00191 square_terms, n_cross_terms, cross_parms, cross_terms,
00192 parm_values );
00193
00194 print(
"Initial %g\n", fit );
00195 (
void) flush_file( stdout );
00196
00197
evaluate_fit_derivative( n_parameters, constant_term, linear_terms,
00198 square_terms, n_cross_terms,
00199 cross_parms, cross_terms,
00200 parm_values, xi );
00201
00202 for_less( p, 0, n_parameters )
00203 {
00204 g[p] = -xi[p];
00205 h[p] = g[p];
00206 xi[p] = g[p];
00207 }
00208
00209 update_rate = 1;
00210 last_update_time = current_cpu_seconds();
00211
00212 for_less( iter, 0, n_iters )
00213 {
00214 len = 0.0;
00215 for_less( p, 0, n_parameters )
00216 len += xi[p] * xi[p];
00217
00218
if( len != 0.0 )
00219 {
00220 len = sqrt( len );
00221 for_less( p, 0, n_parameters )
00222 unit_dir[p] = xi[p] / len;
00223
00224
minimize_along_line( n_parameters, constant_term, linear_terms,
00225 square_terms, n_cross_terms, cross_parms,
00226 cross_terms,
00227 max_step_size, parm_values, g, unit_dir );
00228 }
00229
00230
if( ((iter+1) % update_rate) == 0 || iter == n_iters - 1 )
00231 {
00232 fit =
evaluate_fit( n_parameters, constant_term, linear_terms,
00233 square_terms, n_cross_terms, cross_parms,
00234 cross_terms, parm_values );
00235
00236 print(
"%d: %g\n", iter+1, fit );
00237 (
void) flush_file( stdout );
00238 current_time = current_cpu_seconds();
00239
if( current_time - last_update_time < 1.0 )
00240 update_rate *= 10;
00241 last_update_time = current_time;
00242 }
00243
00244
evaluate_fit_derivative( n_parameters, constant_term, linear_terms,
00245 square_terms, n_cross_terms,
00246 cross_parms, cross_terms,
00247 parm_values, xi );
00248
00249 gg = 0.0;
00250 dgg = 0.0;
00251 for_less( p, 0, n_parameters )
00252 {
00253 gg += g[p] * g[p];
00254 dgg += (xi[p] + g[p]) * xi[p];
00255
00256
00257
00258 }
00259
00260
if( gg == 0.0 )
00261
break;
00262
00263 gam = dgg / gg;
00264
00265 for_less( p, 0, n_parameters )
00266 {
00267 g[p] = -xi[p];
00268 h[p] = g[p] + gam * h[p];
00269 xi[p] = h[p];
00270 }
00271 }
00272
00273 FREE( g );
00274 FREE( h );
00275 FREE( xi );
00276 FREE( unit_dir );
00277
00278
return( fit );
00279 }