Skip to content

Defining and using bounds on parameters

medrimonia edited this page Dec 3, 2016 · 7 revisions

libcmaes supports a safe scheme for constrained optimization. This scheme only supports box-type bounds on the objective function parameters.

The library supports a range of transformations of the objective function parameters, referred to as phenotype / genotype transforms. This mechanism is explained in more detailed in Genotype/Phenotype.

Box-type bounds are part of those transforms but at this stage the following steps are directly applicable to most needs.

Definition of box-type bounds

Define bounds in two arrays of proper dimension:

int dim = 10; // problem dimensions.                                                                          
double sigma = 0.1;
double lbounds[dim],ubounds[dim]; // arrays for lower and upper parameter bounds, respectively                
for (int i=0;i<dim;i++)
  {
    lbounds[i] = -2.0;
    ubounds[i] = 2.0;
  }
std::vector<double> x0(dim,1.0); // beware that x0 is within bounds.     

Pay careful attention that the starting point x0 lies within bounds.

Creation of the genotype transform

GenoPheno<pwqBoundStrategy> gp(lbounds,ubounds,dim); // genotype / phenotype transform associated to bounds. 

The object gp builds and stores special transforms in order to guarantee that optimization remains within bounds.

Parameter settings

Now build the object that holds all hyper-parameters, pass it the GenoPheno object and prepare for optimization to run:

CMAParameters<GenoPheno<pwqBoundStrategy>> cmaparams(dim,&x0.front(),sigma,-1,0,gp); // -1 for automatically \

Running the optimization

Simple call:

CMASolutions cmasols = cmaes<GenoPheno<pwqBoundStrategy>>(fsphere,cmaparams);

Retrieving the best solution

Solutions provided by cmaes are stored in the transformed space, therefore in order to get the parameters, do not forget to use the phenotype transform:

Eigen::VectorXd bestparameters = gp.pheno(cmasols.get_best_seen_candidate().get_x_dvec());

Full example

The following example is available in examples/sample-code-bounds.cc

#include "cmaes.h"
#include <iostream>

using namespace libcmaes;

FitFunc fsphere = [](const double *x, const int N)
{
  double val = 0.0;
  for (int i=0;i<N;i++)
    val += x[i]*x[i];
  return val;
};

int main(int argc, char *argv[])
{
  int dim = 10; // problem dimensions.                                                                          
  double sigma = 0.1;
  double lbounds[dim],ubounds[dim]; // arrays for lower and upper parameter bounds, respectively                
  for (int i=0;i<dim;i++)
    {
      lbounds[i] = -2.0;
      ubounds[i] = 2.0;
    }
  std::vector<double> x0(dim,1.0); // beware that x0 is within bounds.                                          
  GenoPheno<pwqBoundStrategy> gp(lbounds,ubounds,dim); // genotype / phenotype transform associated to bounds.  
  CMAParameters<GenoPheno<pwqBoundStrategy>> cmaparams(x0,sigma,-1,0,gp); // -1 for automatically \
decided lambda, 0 is for random	seeding	of the internal generator.                                              
  cmaparams.set_algo(aCMAES);
  CMASolutions cmasols = cmaes<GenoPheno<pwqBoundStrategy>>(fsphere,cmaparams);
  std::cout << "best solution: ";
  cmasols.print(std::cout,0,gp);
  std::cout << std::endl;
  std::cout << "optimization took " << cmasols.elapsed_time() / 1000.0 << " seconds\n";
  return cmasols.run_status();
}