Main Page | Modules | Data Structures | File List | Data Fields | Globals | Related Pages

amoeba.c

Go to the documentation of this file.
00001 /* ---------------------------------------------------------------------------- 00002 @COPYRIGHT : 00003 Copyright 1993,1994,1995 David MacDonald, 00004 McConnell Brain Imaging Centre, 00005 Montreal Neurological Institute, McGill University. 00006 Permission to use, copy, modify, and distribute this 00007 software and its documentation for any purpose and without 00008 fee is hereby granted, provided that the above copyright 00009 notice appear in all copies. The author and McGill University 00010 make no representations about the suitability of this 00011 software for any purpose. It is provided "as is" without 00012 express or implied warranty. 00013 ---------------------------------------------------------------------------- */ 00014 00015 #include <volume_io/internal_volume_io.h> 00016 #include <bicpl/numerical.h> 00017 00018 #ifndef lint 00019 static char rcsid[] = "$Header: /software/source//libraries/bicpl/Numerical/amoeba.c,v 1.14 2000/02/06 15:30:39 stever Exp $"; 00020 #endif 00021 00022 #define FLIP_RATIO 1.0 00023 #define CONTRACT_RATIO 0.5 00024 #define STRETCH_RATIO 2.0 00025 00026 /* ----------------------------- MNI Header ----------------------------------- 00027 @NAME : get_function_value 00028 @INPUT : amoeba 00029 parameters 00030 @OUTPUT : 00031 @RETURNS : function value 00032 @DESCRIPTION: Evaluates the function being minimized by amoeba, by calling 00033 the user function. 00034 @METHOD : 00035 @GLOBALS : 00036 @CALLS : 00037 @CREATED : 1993 David MacDonald 00038 @MODIFIED : 00039 ---------------------------------------------------------------------------- */ 00040 00041 private Real get_function_value( 00042 amoeba_struct *amoeba, 00043 float parameters[] ) 00044 { 00045 return( (*amoeba->function) ( amoeba->function_data, parameters ) ); 00046 } 00047 00048 /* ----------------------------- MNI Header ----------------------------------- 00049 @NAME : initialize_amoeba 00050 @INPUT : n_parameters 00051 initial_parameters 00052 parameter_deltas 00053 function 00054 function_data 00055 tolerance 00056 @OUTPUT : amoeba 00057 @RETURNS : 00058 @DESCRIPTION: Initializes the amoeba structure to minimize the function. 00059 @METHOD : 00060 @GLOBALS : 00061 @CALLS : 00062 @CREATED : 1993 David MacDonald 00063 @MODIFIED : 00064 ---------------------------------------------------------------------------- */ 00065 00066 public void initialize_amoeba( 00067 amoeba_struct *amoeba, 00068 int n_parameters, 00069 Real initial_parameters[], 00070 Real parameter_deltas[], 00071 amoeba_function function, 00072 void *function_data, 00073 Real tolerance ) 00074 { 00075 int i, j; 00076 00077 amoeba->n_parameters = n_parameters; 00078 amoeba->function = function; 00079 amoeba->function_data = function_data; 00080 amoeba->tolerance = tolerance; 00081 amoeba->n_steps_no_improvement = 0; 00082 ALLOC2D( amoeba->parameters, n_parameters+1, n_parameters ); 00083 ALLOC( amoeba->values, n_parameters+1 ); 00084 00085 ALLOC( amoeba->sum, n_parameters ); 00086 00087 for_less( j, 0, n_parameters ) 00088 amoeba->sum[j] = 0.0; 00089 00090 for_less( i, 0, n_parameters+1 ) 00091 { 00092 for_less( j, 0, n_parameters ) 00093 { 00094 amoeba->parameters[i][j] = (float) initial_parameters[j]; 00095 if( i > 0 && j == i - 1 ) 00096 amoeba->parameters[i][j] = (float) parameter_deltas[j]; 00097 amoeba->sum[j] += (Real) amoeba->parameters[i][j]; 00098 } 00099 00100 amoeba->values[i] = get_function_value( amoeba, amoeba->parameters[i] ); 00101 } 00102 } 00103 00104 /* ----------------------------- MNI Header ----------------------------------- 00105 @NAME : get_amoeba_parameters 00106 @INPUT : amoeba 00107 @OUTPUT : parameters 00108 @RETURNS : function value 00109 @DESCRIPTION: Passes back the current position of the amoeba (best value), 00110 and returns the function value at that point. 00111 @METHOD : 00112 @GLOBALS : 00113 @CALLS : 00114 @CREATED : 1993 David MacDonald 00115 @MODIFIED : 00116 ---------------------------------------------------------------------------- */ 00117 00118 public Real get_amoeba_parameters( 00119 amoeba_struct *amoeba, 00120 Real parameters[] ) 00121 { 00122 int i, j, low; 00123 00124 low = 0; 00125 for_less( i, 1, amoeba->n_parameters+1 ) 00126 { 00127 if( amoeba->values[i] < amoeba->values[low] ) 00128 low = i; 00129 } 00130 00131 for_less( j, 0, amoeba->n_parameters ) 00132 parameters[j] = (Real) amoeba->parameters[low][j]; 00133 00134 return( amoeba->values[low] ); 00135 } 00136 00137 /* ----------------------------- MNI Header ----------------------------------- 00138 @NAME : terminate_amoeba 00139 @INPUT : amoeba 00140 @OUTPUT : 00141 @RETURNS : 00142 @DESCRIPTION: Frees the amoeba. 00143 @METHOD : 00144 @GLOBALS : 00145 @CALLS : 00146 @CREATED : 1993 David MacDonald 00147 @MODIFIED : 00148 ---------------------------------------------------------------------------- */ 00149 00150 public void terminate_amoeba( 00151 amoeba_struct *amoeba ) 00152 { 00153 FREE2D( amoeba->parameters ); 00154 FREE( amoeba->values ); 00155 FREE( amoeba->sum ); 00156 } 00157 00158 /* ----------------------------- MNI Header ----------------------------------- 00159 @NAME : try_amoeba 00160 @INPUT : amoeba 00161 sum 00162 high 00163 fac 00164 @OUTPUT : 00165 @RETURNS : value 00166 @DESCRIPTION: Does a modification to the high vertex of the amoeba and 00167 returns the value of the new point. If the new point is 00168 better (smaller value), it replaces the high vertex of the 00169 amoeba. 00170 @METHOD : 00171 @GLOBALS : 00172 @CALLS : 00173 @CREATED : 1993 David MacDonald 00174 @MODIFIED : 00175 ---------------------------------------------------------------------------- */ 00176 00177 private Real try_amoeba( 00178 amoeba_struct *amoeba, 00179 Real sum[], 00180 int high, 00181 Real fac ) 00182 { 00183 int j; 00184 Real y_try, fac1, fac2; 00185 float *parameters; 00186 00187 ALLOC( parameters, amoeba->n_parameters ); 00188 00189 fac1 = (1.0 - fac) / (Real) amoeba->n_parameters; 00190 fac2 = fac - fac1; 00191 00192 for_less( j, 0, amoeba->n_parameters ) 00193 parameters[j] = (float) (sum[j] * fac1 + 00194 (Real) amoeba->parameters[high][j] * fac2); 00195 00196 y_try = get_function_value( amoeba, parameters ); 00197 00198 if( y_try < amoeba->values[high] ) 00199 { 00200 amoeba->values[high] = y_try; 00201 for_less( j, 0, amoeba->n_parameters ) 00202 { 00203 sum[j] += (Real) parameters[j] - (Real) amoeba->parameters[high][j]; 00204 amoeba->parameters[high][j] = parameters[j]; 00205 } 00206 } 00207 00208 FREE( parameters ); 00209 00210 return( y_try ); 00211 } 00212 00213 #define N_STEPS_NO_IMPROVEMENT 20 00214 00215 /* ----------------------------- MNI Header ----------------------------------- 00216 @NAME : perform_amoeba 00217 @INPUT : amoeba 00218 @OUTPUT : 00219 @RETURNS : TRUE if numerically significant improvement 00220 @DESCRIPTION: Performs one iteration of an amoeba, returning true if a 00221 numerically significant improvement has been found recently. 00222 Even if it returns FALSE, you can keep calling this function, 00223 since it may be contracting with no improvement, but will 00224 eventually shrink small enough to get an improvment. 00225 @METHOD : 00226 @GLOBALS : 00227 @CALLS : 00228 @CREATED : 1993 David MacDonald 00229 @MODIFIED : 00230 ---------------------------------------------------------------------------- */ 00231 00232 public BOOLEAN perform_amoeba( 00233 amoeba_struct *amoeba ) 00234 { 00235 int i, j, low, high, next_high; 00236 Real y_try, y_save; 00237 BOOLEAN improvement_found; 00238 00239 improvement_found = TRUE; 00240 00241 if( amoeba->values[0] > amoeba->values[1] ) 00242 { 00243 high = 0; 00244 next_high = 1; 00245 } 00246 else 00247 { 00248 high = 1; 00249 next_high = 0; 00250 } 00251 00252 low = next_high; 00253 00254 for_less( i, 2, amoeba->n_parameters+1 ) 00255 { 00256 if( amoeba->values[i] < amoeba->values[low] ) 00257 low = i; 00258 else if( amoeba->values[i] > amoeba->values[high] ) 00259 { 00260 next_high = high; 00261 high = i; 00262 } 00263 else if( amoeba->values[i] > amoeba->values[next_high] ) 00264 next_high = i; 00265 } 00266 00267 if( numerically_close( amoeba->values[low], amoeba->values[high], 00268 amoeba->tolerance ) ) 00269 { 00270 ++amoeba->n_steps_no_improvement; 00271 if( amoeba->n_steps_no_improvement == N_STEPS_NO_IMPROVEMENT ) 00272 improvement_found = FALSE; 00273 } 00274 else 00275 amoeba->n_steps_no_improvement = 0; 00276 00277 y_try = try_amoeba( amoeba, amoeba->sum, high, -FLIP_RATIO ); 00278 00279 if( y_try <= amoeba->values[low] ) 00280 y_try = try_amoeba( amoeba, amoeba->sum, high, STRETCH_RATIO ); 00281 else if( y_try >= amoeba->values[next_high] ) 00282 { 00283 y_save = amoeba->values[high]; 00284 y_try = try_amoeba( amoeba, amoeba->sum, high, CONTRACT_RATIO ); 00285 00286 if( y_try >= y_save ) 00287 { 00288 for_less( i, 0, amoeba->n_parameters+1 ) 00289 { 00290 if( i != low ) 00291 { 00292 for_less( j, 0, amoeba->n_parameters ) 00293 { 00294 amoeba->parameters[i][j] = (amoeba->parameters[i][j] + 00295 amoeba->parameters[low][j]) / 2.0f; 00296 } 00297 00298 amoeba->values[i] = get_function_value( amoeba, 00299 amoeba->parameters[i] ); 00300 } 00301 } 00302 00303 for_less( j, 0, amoeba->n_parameters ) 00304 { 00305 amoeba->sum[j] = 0.0; 00306 for_less( i, 0, amoeba->n_parameters+1 ) 00307 amoeba->sum[j] += (Real) amoeba->parameters[i][j]; 00308 } 00309 } 00310 } 00311 00312 return( improvement_found ); 00313 }

Generated on Wed Jul 28 09:10:56 2004 for BICPL by doxygen 1.3.7