|
Packit |
67cb25 |
typedef struct
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_function_fdf fdf_linear;
|
|
Packit |
67cb25 |
gsl_multimin_function_fdf *fdf;
|
|
Packit |
67cb25 |
/* fixed values */
|
|
Packit |
67cb25 |
const gsl_vector *x;
|
|
Packit |
67cb25 |
const gsl_vector *g;
|
|
Packit |
67cb25 |
const gsl_vector *p;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* cached values, for x(alpha) = x + alpha * p */
|
|
Packit |
67cb25 |
double f_alpha;
|
|
Packit |
67cb25 |
double df_alpha;
|
|
Packit |
67cb25 |
gsl_vector *x_alpha;
|
|
Packit |
67cb25 |
gsl_vector *g_alpha;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* cache "keys" */
|
|
Packit |
67cb25 |
double f_cache_key;
|
|
Packit |
67cb25 |
double df_cache_key;
|
|
Packit |
67cb25 |
double x_cache_key;
|
|
Packit |
67cb25 |
double g_cache_key;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
wrapper_t;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static void
|
|
Packit |
67cb25 |
moveto (double alpha, wrapper_t * w)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (alpha == w->x_cache_key) /* using previously cached position */
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
return;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* set x_alpha = x + alpha * p */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_vector_memcpy (w->x_alpha, w->x);
|
|
Packit |
67cb25 |
gsl_blas_daxpy (alpha, w->p, w->x_alpha);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
w->x_cache_key = alpha;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static double
|
|
Packit |
67cb25 |
slope (wrapper_t * w) /* compute gradient . direction */
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double df;
|
|
Packit |
67cb25 |
gsl_blas_ddot (w->g_alpha, w->p, &df);
|
|
Packit |
67cb25 |
return df;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static double
|
|
Packit |
67cb25 |
wrap_f (double alpha, void *params)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
wrapper_t *w = (wrapper_t *) params;
|
|
Packit |
67cb25 |
if (alpha == w->f_cache_key) /* using previously cached f(alpha) */
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
return w->f_alpha;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
moveto (alpha, w);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
w->f_alpha = GSL_MULTIMIN_FN_EVAL_F (w->fdf, w->x_alpha);
|
|
Packit |
67cb25 |
w->f_cache_key = alpha;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return w->f_alpha;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static double
|
|
Packit |
67cb25 |
wrap_df (double alpha, void *params)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
wrapper_t *w = (wrapper_t *) params;
|
|
Packit |
67cb25 |
if (alpha == w->df_cache_key) /* using previously cached df(alpha) */
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
return w->df_alpha;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
moveto (alpha, w);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (alpha != w->g_cache_key)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_MULTIMIN_FN_EVAL_DF (w->fdf, w->x_alpha, w->g_alpha);
|
|
Packit |
67cb25 |
w->g_cache_key = alpha;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
w->df_alpha = slope (w);
|
|
Packit |
67cb25 |
w->df_cache_key = alpha;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return w->df_alpha;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static void
|
|
Packit |
67cb25 |
wrap_fdf (double alpha, void *params, double *f, double *df)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
wrapper_t *w = (wrapper_t *) params;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Check for previously cached values */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (alpha == w->f_cache_key && alpha == w->df_cache_key)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
*f = w->f_alpha;
|
|
Packit |
67cb25 |
*df = w->df_alpha;
|
|
Packit |
67cb25 |
return;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (alpha == w->f_cache_key || alpha == w->df_cache_key)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
*f = wrap_f (alpha, params);
|
|
Packit |
67cb25 |
*df = wrap_df (alpha, params);
|
|
Packit |
67cb25 |
return;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
moveto (alpha, w);
|
|
Packit |
67cb25 |
GSL_MULTIMIN_FN_EVAL_F_DF (w->fdf, w->x_alpha, &w->f_alpha, w->g_alpha);
|
|
Packit |
67cb25 |
w->f_cache_key = alpha;
|
|
Packit |
67cb25 |
w->g_cache_key = alpha;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
w->df_alpha = slope (w);
|
|
Packit |
67cb25 |
w->df_cache_key = alpha;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
*f = w->f_alpha;
|
|
Packit |
67cb25 |
*df = w->df_alpha;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static void
|
|
Packit |
67cb25 |
prepare_wrapper (wrapper_t * w, gsl_multimin_function_fdf * fdf,
|
|
Packit |
67cb25 |
const gsl_vector * x, double f, const gsl_vector *g,
|
|
Packit |
67cb25 |
const gsl_vector * p,
|
|
Packit |
67cb25 |
gsl_vector * x_alpha, gsl_vector *g_alpha)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
w->fdf_linear.f = &wrap_f;
|
|
Packit |
67cb25 |
w->fdf_linear.df = &wrap_df;
|
|
Packit |
67cb25 |
w->fdf_linear.fdf = &wrap_fdf;
|
|
Packit |
67cb25 |
w->fdf_linear.params = (void *)w; /* pointer to "self" */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
w->fdf = fdf;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
w->x = x;
|
|
Packit |
67cb25 |
w->g = g;
|
|
Packit |
67cb25 |
w->p = p;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
w->x_alpha = x_alpha;
|
|
Packit |
67cb25 |
w->g_alpha = g_alpha;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_vector_memcpy(w->x_alpha, w->x);
|
|
Packit |
67cb25 |
w->x_cache_key = 0.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
w->f_alpha = f;
|
|
Packit |
67cb25 |
w->f_cache_key = 0.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_vector_memcpy(w->g_alpha, w->g);
|
|
Packit |
67cb25 |
w->g_cache_key = 0.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
w->df_alpha = slope(w);
|
|
Packit |
67cb25 |
w->df_cache_key = 0.0;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static void
|
|
Packit |
67cb25 |
update_position (wrapper_t * w, double alpha, gsl_vector *x, double *f, gsl_vector *g)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* ensure that everything is fully cached */
|
|
Packit |
67cb25 |
{ double f_alpha, df_alpha; wrap_fdf (alpha, w, &f_alpha, &df_alpha); } ;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
*f = w->f_alpha;
|
|
Packit |
67cb25 |
gsl_vector_memcpy(x, w->x_alpha);
|
|
Packit |
67cb25 |
gsl_vector_memcpy(g, w->g_alpha);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static void
|
|
Packit |
67cb25 |
change_direction (wrapper_t * w)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* Convert the cache values from the end of the current minimisation
|
|
Packit |
67cb25 |
to those needed for the start of the next minimisation, alpha=0 */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* The new x_alpha for alpha=0 is the current position */
|
|
Packit |
67cb25 |
gsl_vector_memcpy (w->x_alpha, w->x);
|
|
Packit |
67cb25 |
w->x_cache_key = 0.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* The function value does not change */
|
|
Packit |
67cb25 |
w->f_cache_key = 0.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* The new g_alpha for alpha=0 is the current gradient at the endpoint */
|
|
Packit |
67cb25 |
gsl_vector_memcpy (w->g_alpha, w->g);
|
|
Packit |
67cb25 |
w->g_cache_key = 0.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Calculate the slope along the new direction vector, p */
|
|
Packit |
67cb25 |
w->df_alpha = slope (w);
|
|
Packit |
67cb25 |
w->df_cache_key = 0.0;
|
|
Packit |
67cb25 |
}
|