00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
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 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 
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 
00049 
00050 
00051 
00052 
00053 
00054 
00055 
00056 
00057 
00058 
00059 
00060 
00061 
00062 
00063 
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 
00105 
00106 
00107 
00108 
00109 
00110 
00111 
00112 
00113 
00114 
00115 
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 
00138 
00139 
00140 
00141 
00142 
00143 
00144 
00145 
00146 
00147 
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 
00159 
00160 
00161 
00162 
00163 
00164 
00165 
00166 
00167 
00168 
00169 
00170 
00171 
00172 
00173 
00174 
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 
00216 
00217 
00218 
00219 
00220 
00221 
00222 
00223 
00224 
00225 
00226 
00227 
00228 
00229 
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 }