118 lines
4.1 KiB
C++
118 lines
4.1 KiB
C++
// Copyright (C) 2016 Davis E. King (davis@dlib.net)
|
|
// License: Boost Software License See LICENSE.txt for the full license.
|
|
#ifndef DLIB_fIND_OPTIMAL_PARAMETERS_Hh_
|
|
#define DLIB_fIND_OPTIMAL_PARAMETERS_Hh_
|
|
|
|
#include "../matrix.h"
|
|
#include "find_optimal_parameters_abstract.h"
|
|
#include "optimization_bobyqa.h"
|
|
#include "optimization_line_search.h"
|
|
|
|
namespace dlib
|
|
{
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename funct
|
|
>
|
|
double find_optimal_parameters (
|
|
double initial_search_radius,
|
|
double eps,
|
|
const unsigned int max_f_evals,
|
|
matrix<double,0,1>& x,
|
|
const matrix<double,0,1>& x_lower,
|
|
const matrix<double,0,1>& x_upper,
|
|
const funct& f
|
|
)
|
|
{
|
|
DLIB_CASSERT(x.size() == x_lower.size() && x_lower.size() == x_upper.size() && x.size() > 0,
|
|
"\t double find_optimal_parameters()"
|
|
<< "\n\t x.size(): " << x.size()
|
|
<< "\n\t x_lower.size(): " << x_lower.size()
|
|
<< "\n\t x_upper.size(): " << x_upper.size()
|
|
);
|
|
|
|
// check the requirements. Also split the assert up so that the error message isn't huge.
|
|
DLIB_CASSERT(max_f_evals > 1 && eps > 0 && initial_search_radius > eps,
|
|
"\t double find_optimal_parameters()"
|
|
<< "\n\t Invalid arguments have been given to this function"
|
|
<< "\n\t initial_search_radius: " << initial_search_radius
|
|
<< "\n\t eps: " << eps
|
|
<< "\n\t max_f_evals: " << max_f_evals
|
|
);
|
|
|
|
DLIB_CASSERT( min(x_upper - x_lower) > 0 &&
|
|
min(x - x_lower) >= 0 && min(x_upper - x) >= 0,
|
|
"\t double find_optimal_parameters()"
|
|
<< "\n\t The bounds constraints have to make sense and also contain the starting point."
|
|
<< "\n\t min(x_upper - x_lower): " << min(x_upper - x_lower)
|
|
<< "\n\t min(x - x_lower) >= 0 && min(x_upper - x) >= 0: " << (min(x - x_lower) >= 0 && min(x_upper - x) >= 0)
|
|
);
|
|
|
|
// if the search radius is too big then shrink it so it fits inside the bounds.
|
|
if (initial_search_radius*2 >= min(x_upper-x_lower))
|
|
initial_search_radius = 0.5*min(x_upper-x_lower)*0.99;
|
|
|
|
|
|
double objective_val = std::numeric_limits<double>::infinity();
|
|
size_t num_iter_used = 0;
|
|
if (x.size() == 1)
|
|
{
|
|
// BOBYQA requires x to have at least 2 variables in it. So we can't call it in
|
|
// this case. Instead we call find_min_single_variable().
|
|
matrix<double,0,1> temp(1);
|
|
auto ff = [&](const double& xx)
|
|
{
|
|
temp = xx;
|
|
double obj = f(temp);
|
|
++num_iter_used;
|
|
// keep track of the best x.
|
|
if (obj < objective_val)
|
|
{
|
|
objective_val = obj;
|
|
x = temp;
|
|
}
|
|
return obj;
|
|
};
|
|
try
|
|
{
|
|
double dx = x(0);
|
|
find_min_single_variable(ff, dx, x_lower(0), x_upper(0), eps, max_f_evals, initial_search_radius);
|
|
} catch (optimize_single_variable_failure& )
|
|
{
|
|
}
|
|
}
|
|
else
|
|
{
|
|
auto ff = [&](const matrix<double,0,1>& xx)
|
|
{
|
|
double obj = f(xx);
|
|
++num_iter_used;
|
|
// keep track of the best x.
|
|
if (obj < objective_val)
|
|
{
|
|
objective_val = obj;
|
|
x = xx;
|
|
}
|
|
return obj;
|
|
};
|
|
try
|
|
{
|
|
matrix<double,0,1> start_x = x;
|
|
find_min_bobyqa(ff, start_x, 2*x.size()+1, x_lower, x_upper, initial_search_radius, eps, max_f_evals);
|
|
} catch (bobyqa_failure& )
|
|
{
|
|
}
|
|
}
|
|
|
|
return objective_val;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
}
|
|
|
|
#endif // DLIB_fIND_OPTIMAL_PARAMETERS_Hh_
|
|
|