Commit e273f515 authored by Davis King's avatar Davis King

Added find_min_global() overloads.

parent 3284f575
This diff is collapsed.
...@@ -53,7 +53,7 @@ namespace dlib ...@@ -53,7 +53,7 @@ namespace dlib
/*! /*!
WHAT THIS OBJECT REPRESENTS WHAT THIS OBJECT REPRESENTS
This is a simple typed integer class used to strongly type the "max number This is a simple typed integer class used to strongly type the "max number
of function calls" argument to find_max_global(). of function calls" argument to find_max_global() and find_min_global().
!*/ !*/
...@@ -136,6 +136,21 @@ namespace dlib ...@@ -136,6 +136,21 @@ namespace dlib
optimizer. optimizer.
!*/ !*/
template <
typename funct
>
std::pair<size_t,function_evaluation> find_min_global (
std::vector<funct>& functions,
const std::vector<function_spec>& specs,
const max_function_calls num,
const std::chrono::nanoseconds max_runtime = FOREVER,
double solver_epsilon = 0
);
/*!
This function is identical to the find_max_global() defined immediately above,
except that we perform minimization rather than maximization.
!*/
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < template <
...@@ -204,9 +219,26 @@ namespace dlib ...@@ -204,9 +219,26 @@ namespace dlib
optimizer. optimizer.
!*/ !*/
template <
typename funct
>
function_evaluation find_min_global (
funct f,
const matrix<double,0,1>& bound1,
const matrix<double,0,1>& bound2,
const std::vector<bool>& is_integer_variable,
const max_function_calls num,
const std::chrono::nanoseconds max_runtime = FOREVER,
double solver_epsilon = 0
);
/*!
This function is identical to the find_max_global() defined immediately above,
except that we perform minimization rather than maximization.
!*/
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
// The following functions are just convenient overloads for calling the above defined // The following functions are just convenient overloads for calling the above defined
// find_max_global() routines. // find_max_global() and find_min_global() routines.
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < template <
...@@ -224,6 +256,21 @@ namespace dlib ...@@ -224,6 +256,21 @@ namespace dlib
return find_max_global(std::move(f), bound1, bound2, std::vector<bool>(bound1.size(),false), num, FOREVER, solver_epsilon); return find_max_global(std::move(f), bound1, bound2, std::vector<bool>(bound1.size(),false), num, FOREVER, solver_epsilon);
} }
template <
typename funct
>
function_evaluation find_min_global (
funct f,
const matrix<double,0,1>& bound1,
const matrix<double,0,1>& bound2,
const std::vector<bool>& is_integer_variable,
const max_function_calls num,
double solver_epsilon
)
{
return find_min_global(std::move(f), bound1, bound2, std::vector<bool>(bound1.size(),false), num, FOREVER, solver_epsilon);
}
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < template <
...@@ -241,6 +288,21 @@ namespace dlib ...@@ -241,6 +288,21 @@ namespace dlib
return find_max_global(std::move(f), bound1, bound2, std::vector<bool>(bound1.size(),false), num, max_runtime, solver_epsilon); return find_max_global(std::move(f), bound1, bound2, std::vector<bool>(bound1.size(),false), num, max_runtime, solver_epsilon);
} }
template <
typename funct
>
function_evaluation find_min_global (
funct f,
const matrix<double,0,1>& bound1,
const matrix<double,0,1>& bound2,
const max_function_calls num,
const std::chrono::nanoseconds max_runtime = FOREVER,
double solver_epsilon = 0
)
{
return find_min_global(std::move(f), bound1, bound2, std::vector<bool>(bound1.size(),false), num, max_runtime, solver_epsilon);
}
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < template <
...@@ -257,6 +319,20 @@ namespace dlib ...@@ -257,6 +319,20 @@ namespace dlib
return find_max_global(std::move(f), bound1, bound2, std::vector<bool>(bound1.size(),false), num, FOREVER, solver_epsilon); return find_max_global(std::move(f), bound1, bound2, std::vector<bool>(bound1.size(),false), num, FOREVER, solver_epsilon);
} }
template <
typename funct
>
function_evaluation find_min_global (
funct f,
const matrix<double,0,1>& bound1,
const matrix<double,0,1>& bound2,
const max_function_calls num,
double solver_epsilon
)
{
return find_min_global(std::move(f), bound1, bound2, std::vector<bool>(bound1.size(),false), num, FOREVER, solver_epsilon);
}
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < template <
...@@ -274,6 +350,21 @@ namespace dlib ...@@ -274,6 +350,21 @@ namespace dlib
return find_max_global(std::move(f), matrix<double,0,1>({bound1}), matrix<double,0,1>({bound2}), num, max_runtime, solver_epsilon); return find_max_global(std::move(f), matrix<double,0,1>({bound1}), matrix<double,0,1>({bound2}), num, max_runtime, solver_epsilon);
} }
template <
typename funct
>
function_evaluation find_min_global (
funct f,
const double bound1,
const double bound2,
const max_function_calls num,
const std::chrono::nanoseconds max_runtime = FOREVER,
double solver_epsilon = 0
)
{
return find_min_global(std::move(f), matrix<double,0,1>({bound1}), matrix<double,0,1>({bound2}), num, max_runtime, solver_epsilon);
}
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < template <
...@@ -290,6 +381,20 @@ namespace dlib ...@@ -290,6 +381,20 @@ namespace dlib
return find_max_global(std::move(f), matrix<double,0,1>({bound1}), matrix<double,0,1>({bound2}), num, FOREVER, solver_epsilon); return find_max_global(std::move(f), matrix<double,0,1>({bound1}), matrix<double,0,1>({bound2}), num, FOREVER, solver_epsilon);
} }
template <
typename funct
>
function_evaluation find_min_global (
funct f,
const double bound1,
const double bound2,
const max_function_calls num,
double solver_epsilon
)
{
return find_min_global(std::move(f), matrix<double,0,1>({bound1}), matrix<double,0,1>({bound2}), num, FOREVER, solver_epsilon);
}
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < template <
...@@ -306,6 +411,20 @@ namespace dlib ...@@ -306,6 +411,20 @@ namespace dlib
return find_max_global(std::move(f), bound1, bound2, max_function_calls(), max_runtime, solver_epsilon); return find_max_global(std::move(f), bound1, bound2, max_function_calls(), max_runtime, solver_epsilon);
} }
template <
typename funct
>
function_evaluation find_min_global (
funct f,
const matrix<double,0,1>& bound1,
const matrix<double,0,1>& bound2,
const std::chrono::nanoseconds max_runtime,
double solver_epsilon = 0
)
{
return find_min_global(std::move(f), bound1, bound2, max_function_calls(), max_runtime, solver_epsilon);
}
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < template <
...@@ -322,6 +441,20 @@ namespace dlib ...@@ -322,6 +441,20 @@ namespace dlib
return find_max_global(std::move(f), bound1, bound2, max_function_calls(), max_runtime, solver_epsilon); return find_max_global(std::move(f), bound1, bound2, max_function_calls(), max_runtime, solver_epsilon);
} }
template <
typename funct
>
function_evaluation find_min_global (
funct f,
const double bound1,
const double bound2,
const std::chrono::nanoseconds max_runtime,
double solver_epsilon = 0
)
{
return find_min_global(std::move(f), bound1, bound2, max_function_calls(), max_runtime, solver_epsilon);
}
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < template <
...@@ -339,6 +472,21 @@ namespace dlib ...@@ -339,6 +472,21 @@ namespace dlib
return find_max_global(std::move(f), bound1, bound2, is_integer_variable, max_function_calls(), max_runtime, solver_epsilon); return find_max_global(std::move(f), bound1, bound2, is_integer_variable, max_function_calls(), max_runtime, solver_epsilon);
} }
template <
typename funct
>
function_evaluation find_min_global (
funct f,
const matrix<double,0,1>& bound1,
const matrix<double,0,1>& bound2,
const std::vector<bool>& is_integer_variable,
const std::chrono::nanoseconds max_runtime,
double solver_epsilon = 0
)
{
return find_min_global(std::move(f), bound1, bound2, is_integer_variable, max_function_calls(), max_runtime, solver_epsilon);
}
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
} }
......
...@@ -213,6 +213,66 @@ namespace ...@@ -213,6 +213,66 @@ namespace
DLIB_TEST_MSG(std::abs(result.y - 21.9210397) < 0.0001, std::abs(result.y - 21.9210397)); DLIB_TEST_MSG(std::abs(result.y - 21.9210397) < 0.0001, std::abs(result.y - 21.9210397));
} }
// ----------------------------------------------------------------------------------------
void test_find_min_global(
)
{
print_spinner();
auto rosen = [](const matrix<double,0,1>& x) { return +1*( 100*std::pow(x(1) - x(0)*x(0),2.0) + std::pow(1 - x(0),2)); };
auto result = find_min_global(rosen, {0, 0}, {2, 2}, max_function_calls(100), 0);
matrix<double,0,1> true_x = {1,1};
dlog << LINFO << "rosen: " << trans(result.x);
DLIB_TEST_MSG(min(abs(true_x-result.x)) < 1e-5, min(abs(true_x-result.x)));
print_spinner();
result = find_min_global(rosen, {0, 0}, {2, 2}, max_function_calls(100));
dlog << LINFO << "rosen: " << trans(result.x);
DLIB_TEST_MSG(min(abs(true_x-result.x)) < 1e-5, min(abs(true_x-result.x)));
print_spinner();
result = find_min_global(rosen, {0, 0}, {2, 2}, std::chrono::seconds(5));
dlog << LINFO << "rosen: " << trans(result.x);
DLIB_TEST_MSG(min(abs(true_x-result.x)) < 1e-5, min(abs(true_x-result.x)));
print_spinner();
result = find_min_global(rosen, {0, 0}, {2, 2}, {false,false}, max_function_calls(100));
dlog << LINFO << "rosen: " << trans(result.x);
DLIB_TEST_MSG(min(abs(true_x-result.x)) < 1e-5, min(abs(true_x-result.x)));
print_spinner();
result = find_min_global(rosen, {0, 0}, {0.9, 0.9}, {false,false}, max_function_calls(100));
true_x = {0.9, 0.81};
dlog << LINFO << "rosen, bounded at 0.9: " << trans(result.x);
DLIB_TEST_MSG(min(abs(true_x-result.x)) < 1e-5, min(abs(true_x-result.x)));
print_spinner();
result = find_min_global([](double x){ return std::pow(x-2,2.0); }, -10, 10, max_function_calls(10), 0);
dlog << LINFO << "(x-2)^2: " << trans(result.x);
DLIB_TEST(result.x.size()==1);
DLIB_TEST(std::abs(result.x - 2) < 1e-9);
print_spinner();
result = find_min_global([](double x){ return std::pow(x-2,2.0); }, -10, 1, max_function_calls(10));
dlog << LINFO << "(x-2)^2, bound at 1: " << trans(result.x);
DLIB_TEST(result.x.size()==1);
DLIB_TEST(std::abs(result.x - 1) < 1e-9);
print_spinner();
result = find_min_global([](double x){ return std::pow(x-2,2.0); }, -10, 1, std::chrono::seconds(2));
dlog << LINFO << "(x-2)^2, bound at 1: " << trans(result.x);
DLIB_TEST(result.x.size()==1);
DLIB_TEST(std::abs(result.x - 1) < 1e-9);
print_spinner();
result = find_min_global([](double a, double b){ return complex_holder_table(a,b);},
{-10, -10}, {10, 10}, max_function_calls(300), 0);
dlog << LINFO << "complex_holder_table y: "<< result.y;
DLIB_TEST_MSG(std::abs(result.y + 21.9210397) < 0.0001, std::abs(result.y + 21.9210397));
}
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
...@@ -233,6 +293,7 @@ namespace ...@@ -233,6 +293,7 @@ namespace
test_upper_bound_function(0.0, 1e-1); test_upper_bound_function(0.0, 1e-1);
test_global_function_search(); test_global_function_search();
test_find_max_global(); test_find_max_global();
test_find_min_global();
} }
} a; } a;
......
...@@ -263,14 +263,14 @@ int main() try ...@@ -263,14 +263,14 @@ int main() try
// Finally, let's try the find_max_global() routine. Like find_min_bobyqa(), // Finally, let's try the find_min_global() routine. Like find_min_bobyqa(),
// this technique is specially designed to optimize a function in the absence // this technique is specially designed to minimize a function in the absence
// of derivative information. However, it is also designed to handle // of derivative information. However, it is also designed to handle
// functions with many local optima. Where BOBYQA would get stuck at the // functions with many local optima. Where BOBYQA would get stuck at the
// nearest local optima, find_max_global() won't. find_max_global() uses a // nearest local optima, find_min_global() won't. find_min_global() uses a
// global optimization method based on a combination of non-parametric global // global optimization method based on a combination of non-parametric global
// function modeling and BOBYQA style quadratic trust region modeling to // function modeling and BOBYQA style quadratic trust region modeling to
// efficiently find a global maximizer. It usually does a good job with a // efficiently find a global minimizer. It usually does a good job with a
// relatively small number of calls to the function being optimized. // relatively small number of calls to the function being optimized.
// //
// You also don't have to give it a starting point or set any parameters, // You also don't have to give it a starting point or set any parameters,
...@@ -296,20 +296,20 @@ int main() try ...@@ -296,20 +296,20 @@ int main() try
} }
// Holder table function tilted towards 10,10 and with additional // Holder table function tilted towards 10,10 and with additional
// high frequency terms to add more local optima. // high frequency terms to add more local optima.
return std::abs(sin(x0)*cos(x1)*exp(std::abs(1-std::sqrt(x0*x0+x1*x1)/pi))) -(x0+x1)/10 - sin(x0*10)*cos(x1*10); return -( std::abs(sin(x0)*cos(x1)*exp(std::abs(1-std::sqrt(x0*x0+x1*x1)/pi))) -(x0+x1)/10 - sin(x0*10)*cos(x1*10));
}; };
// To optimize this difficult function all we need to do is call // To optimize this difficult function all we need to do is call
// find_max_global() // find_min_global()
auto result = find_max_global(complex_holder_table, auto result = find_min_global(complex_holder_table,
{-10,-10}, // lower bounds {-10,-10}, // lower bounds
{10,10}, // upper bounds {10,10}, // upper bounds
max_function_calls(300)); max_function_calls(300));
cout.precision(9); cout.precision(9);
// These cout statements will show that find_max_global() found the // These cout statements will show that find_min_global() found the
// globally optimal solution to 9 digits of precision: // globally optimal solution to 9 digits of precision:
cout << "complex holder table function solution y (should be 21.9210397): " << result.y << endl; cout << "complex holder table function solution y (should be -21.9210397): " << result.y << endl;
cout << "complex holder table function solution x:\n" << result.x << endl; cout << "complex holder table function solution x:\n" << result.x << endl;
} }
catch (std::exception& e) catch (std::exception& e)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment