Examples and Tests¶
API¶
The OptimLib API follows a relatively simple convention, with most algorithms called using the following syntax:
algorithm_id(<initial/final values>, <objective function>, <objective function data>);
The function inputs, in order, are:
A writable vector of initial values to define the starting point of the algorithm, where, in the event of successful completion of the algorithm, the initial values will be overwritten by the latest candidate solution vector.
The
objective function
is a user-defined function to be minimized, or zeroed-out in the case of root finding methods.The final input is optional; it is any object that contains additional parameters necessary to evaluate the objective function.
For example, the BFGS algorithm is called using
bfgs(ColVec_t& init_out_vals, std::function<double (const ColVec_t& vals_inp, ColVec_t* grad_out, void* opt_data)> opt_objfn, void* opt_data);
Example¶
The code below uses Differential Evolution to search for the minimum of the Ackley function, a well-known test function with many local minima.
#define OPTIM_ENABLE_EIGEN_WRAPPERS
#include "optim.hpp"
#define OPTIM_PI 3.14159265358979
double
ackley_fn(const Eigen::VectorXd& vals_inp, Eigen::VectorXd* grad_out, void* opt_data)
{
const double x = vals_inp(0);
const double y = vals_inp(1);
const double obj_val = 20 + std::exp(1) - 20 * std::exp(-0.2 * std::sqrt(0.5 * (x * x + y * y))) - std::exp( 0.5 * (std::cos(2 * OPTIM_PI * x) + std::cos(2 * OPTIM_PI * y)) );
return obj_val;
}
int main()
{
Eigen::VectorXd x = 2.0 * Eigen::VectorXd::Ones(2); // initial values: (2,2)
bool success = optim::de(x, ackley_fn, nullptr);
if (success) {
std::cout << "de: Ackley test completed successfully." << std::endl;
} else {
std::cout << "de: Ackley test completed unsuccessfully." << std::endl;
}
std::cout << "de: solution to Ackley test:\n" << x << std::endl;
return 0;
}
On x86-based computers, this example can be compiled using:
g++ -Wall -std=c++14 -O3 -march=native -ffp-contract=fast -I/path/to/eigen -I/path/to/optim/include optim_de_ex.cpp -o optim_de_ex.out -L/path/to/optim/lib -loptim
The Armadillo-based version of this example:
#define OPTIM_ENABLE_ARMA_WRAPPERS
#include "optim.hpp"
// Ackley function
double ackley_fn(const arma::vec& vals_inp, arma::vec* grad_out, void* opt_data)
{
const double x = vals_inp(0);
const double y = vals_inp(1);
const double pi = arma::datum::pi;
double obj_val = -20*std::exp( -0.2*std::sqrt(0.5*(x*x + y*y)) ) - std::exp( 0.5*(std::cos(2*pi*x) + std::cos(2*pi*y)) ) + 22.718282L;
//
return obj_val;
}
int main()
{
// initial values:
arma::vec x = arma::ones(2,1) + 1.0; // (2,2)
//
std::chrono::time_point<std::chrono::system_clock> start = std::chrono::system_clock::now();
bool success = optim::de(x,ackley_fn,nullptr);
std::chrono::time_point<std::chrono::system_clock> end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = end-start;
if (success) {
std::cout << "de: Ackley test completed successfully.\n"
<< "elapsed time: " << elapsed_seconds.count() << "s\n";
} else {
std::cout << "de: Ackley test completed unsuccessfully." << std::endl;
}
arma::cout << "\nde: solution to Ackley test:\n" << x << arma::endl;
return 0;
}
On x86-based computers, compile using:
g++ -Wall -std=c++11 -O3 -march=native -ffp-contract=fast -I/path/to/armadillo -I/path/to/optim/include optim_de_ex.cpp -o optim_de_ex.out -L/path/to/optim/lib -loptim
Test suite¶
You can build the test suite as follows:
# compile tests
cd ./tests
./setup
cd ./unconstrained
./configure -l eigen
make
./bfgs.test