Hosaki Function¶
Note
This problem can be resolved without the black-box functionality (see branin function). Indeed, this functionality is useful when the objective function is computationally expensive. The purpose of this example is only to illustrate the use of a black-box function on a simple and computationally inexpensive problem.
Principles learned¶
- Create a black-box function
- Call a black-box function
- Set the evaluation limit for the black-box function
Problem¶
Hosaki function is defined by
This is a box-constrained problem.
For more details, see: hosaki_function.html
Download the exampleProgram¶
The objective function is defined by a black-box function. It receives the argument values via the
LSBlackBoxArgumentValues
, and returns the value of the function at this
point.
The model is quite similar to a LocalSolver model without a black-box function.
Two floating decision variables x1
and x2
are declared. The domains of
these variables are respectively [0,5]
and [0,6]
. To calculate the value
returned by the black-box function, an O_Call
expression is created. This
expression is then minimized.
As a black-box function is usually computationally expensive, the maximum number
of calls to the function can be set with the LSBlackBoxContext
.
- Execution (Windows)
- set PYTHONPATH=%LS_HOME%\bin\pythonpython hosaki.py
- Execution (Linux)
- export PYTHONPATH=/opt/localsolver_10_5/bin/pythonpython hosaki.py
########## hosaki.py ##########
import localsolver
import sys
import math
# Black-box function
def hosaki_function(argument_values):
x1 = argument_values[0]
x2 = argument_values[1]
return ((1 - 8 * x1 + 7 * pow(x1, 2) - 7 * pow(x1, 3) / 3 + pow(x1, 4) / 4) * pow(x2, 2)
* math.exp(-x2))
def main(evaluation_limit, output_file):
with localsolver.LocalSolver() as ls:
# Declares the optimization model
model = ls.model
# Numerical decisions
x1 = model.float(0, 5)
x2 = model.float(0, 6)
# Creates and calls blackbox function
f = model.create_double_blackbox_function(hosaki_function)
bb_call = model.call(f, x1, x2)
# Minimizes function call
model.minimize(bb_call)
model.close()
# Parameterizes the solver
f.blackbox_context.evaluation_limit = evaluation_limit
ls.solve()
# Writes the solution in a file
if output_file is not None:
with open(output_file, 'w') as f:
f.write("obj=%f\n" % bb_call.value)
f.write("x1=%f\n" % x1.value)
f.write("x2=%f\n" % x2.value)
if __name__ == '__main__':
output_file = sys.argv[1] if len(sys.argv) > 1 else None
evaluation_limit = int(sys.argv[2]) if len(sys.argv) > 2 else 30
main(evaluation_limit, output_file)
- Compilation / Execution (Windows)
- cl /EHsc hosaki.cpp -I%LS_HOME%\include /link %LS_HOME%\bin\localsolver105.libhosaki
- Compilation / Execution (Linux)
- g++ hosaki.cpp -I/opt/localsolver_10_5/include -llocalsolver105 -lpthread -o hosakihosaki
//********* hosaki.cpp *********
#include <iostream>
#include <fstream>
#include <cmath>
#include "localsolver.h"
using namespace localsolver;
using namespace std;
/* Black-box function */
class HosakiFunction : public LSBlackBoxFunction<lsdouble> {
lsdouble call(const LSBlackBoxArgumentValues& argumentValues) override {
lsdouble x1 = argumentValues.getDoubleValue(0);
lsdouble x2 = argumentValues.getDoubleValue(1);
return (1 - 8*x1 + 7*x1*x1 - 7*pow(x1, 3)/3 + pow(x1, 4)/4) * x2*x2
* exp(-x2);
}
};
class Hosaki {
public:
// Solver
LocalSolver localsolver;
// LS Program variables
LSExpression x1;
LSExpression x2;
LSExpression bbCall;
void solve(int evaluationLimit) {
// Declares the optimization model
LSModel model = localsolver.getModel();
// Numerical decisions
x1 = model.floatVar(0, 5);
x2 = model.floatVar(0, 6);
// Creates and calls blackbox function
HosakiFunction bbFuncClass;
LSExpression bbFunc = model.createBlackBoxFunction(&bbFuncClass);
bbCall = model.call(bbFunc, x1, x2);
// Minimizes function call
model.minimize(bbCall);
model.close();
// Parameterizes the solver
LSBlackBoxContext context = bbFunc.getBlackBoxContext();
context.setEvaluationLimit(evaluationLimit);
localsolver.solve();
}
// Writes the solution in a file
void writeSolution(const string& fileName) {
ofstream outfile;
outfile.exceptions(ofstream::failbit | ofstream::badbit);
outfile.open(fileName.c_str());
outfile << "obj=" << bbCall.getDoubleValue() << endl;
outfile << "x1=" << x1.getDoubleValue() << endl;
outfile << "x2=" << x2.getDoubleValue() << endl;
}
};
int main(int argc, char** argv) {
const char* solFile = argc > 1 ? argv[1] : NULL;
const char* strEvaluationLimit = argc > 2 ? argv[2] : "30";
try {
Hosaki model;
model.solve(atoi(strEvaluationLimit));
if (solFile != NULL) model.writeSolution(solFile);
} catch (const exception& e) {
cerr << "An error occurred: " << e.what() << endl;
return 1;
}
return 0;
}
- Compilation / Execution (Windows)
- copy %LS_HOME%\bin\localsolvernet.dll .csc Hosaki.cs /reference:localsolvernet.dllHosaki
/********** Hosaki.cs **********/
using System;
using System.IO;
using localsolver;
public class Hosaki : IDisposable
{
/* Black-box function */
public class HosakiFunction {
public double Call(LSBlackBoxArgumentValues argumentValues) {
double x1 = argumentValues.GetDoubleValue(0);
double x2 = argumentValues.GetDoubleValue(1);
return (1 - 8*x1 + 7*x1*x1 - 7*Math.Pow(x1, 3)/3 + Math.Pow(x1, 4)/4) * x2*x2
* Math.Exp(-x2);
}
}
// Solver
private LocalSolver localsolver;
// LS Program variables
private LSExpression x1;
private LSExpression x2;
private LSExpression bbCall;
public Hosaki()
{
localsolver = new LocalSolver();
}
public void Dispose()
{
if (localsolver != null)
localsolver.Dispose();
}
public void Solve(int evaluationLimit)
{
// Declares the optimization model
LSModel model = localsolver.GetModel();
// Numerical decisions
x1 = model.Float(0, 5);
x2 = model.Float(0, 6);
// Creates and calls blackbox function
HosakiFunction func = new HosakiFunction();
LSDoubleBlackBoxFunction bbFunc = new LSDoubleBlackBoxFunction(func.Call);
LSExpression bbFuncExpr = model.DoubleBlackBoxFunction(bbFunc);
bbCall = model.Call(bbFuncExpr, x1, x2);
// Minimizes function call
model.Minimize(bbCall);
model.Close();
// Parameterizes the solver
LSBlackBoxContext context = bbFuncExpr.GetBlackBoxContext();
context.SetEvaluationLimit(evaluationLimit);
localsolver.Solve();
}
// Writes the solution in a file
public void WriteSolution(string fileName)
{
using (StreamWriter output = new StreamWriter(fileName))
{
output.WriteLine("obj=" + bbCall.GetDoubleValue());
output.WriteLine("x1=" + x1.GetDoubleValue());
output.WriteLine("x2=" + x2.GetDoubleValue());
}
}
public static void Main(string[] args)
{
string outputFile = args.Length > 0 ? args[0] : null;
string strEvaluationLimit = args.Length > 1 ? args[1] : "30";
using (Hosaki model = new Hosaki())
{
model.Solve(int.Parse(strEvaluationLimit));
if (outputFile != null)
model.WriteSolution(outputFile);
}
}
}
- Compilation / Execution (Windows)
- javac Hosaki.java -cp %LS_HOME%\bin\localsolver.jarjava -cp %LS_HOME%\bin\localsolver.jar;. Hosaki
- Compilation / Execution (Linux)
- javac Hosaki.java -cp /opt/localsolver_10_5/bin/localsolver.jarjava -cp /opt/localsolver_10_5/bin/localsolver.jar:. Hosaki
/********** Hosaki.java **********/
import java.io.*;
import java.lang.Math;
import localsolver.*;
public class Hosaki {
/* Black-box function */
private static class HosakiFunction implements LSDoubleBlackBoxFunction {
@Override
public double call(LSBlackBoxArgumentValues argumentValues) {
double x1 = argumentValues.getDoubleValue(0);
double x2 = argumentValues.getDoubleValue(1);
return (1 - 8*x1 + 7*x1*x1 - 7*Math.pow(x1, 3)/3 + Math.pow(x1, 4)/4)
* x2*x2 * Math.exp(-x2);
}
}
// Solver
private final LocalSolver localsolver;
// LS Program variables
private LSExpression x1;
private LSExpression x2;
private LSExpression bbCall;
private Hosaki(LocalSolver localsolver) {
this.localsolver = localsolver;
}
// Declares the optimization model
private void solve(int evaluationLimit) {
LSModel model = localsolver.getModel();
// Numerical decisions
x1 = model.floatVar(0, 5);
x2 = model.floatVar(0, 6);
// Creates and calls blackbox function
HosakiFunction function = new HosakiFunction();
LSExpression bbFunc = model.doubleBlackBoxFunction(function);
bbCall = model.call(bbFunc, x1, x2);
// Minimizes function call
model.minimize(bbCall);
model.close();
// Parameterizes the solver
LSBlackBoxContext context = bbFunc.getBlackBoxContext();
context.setEvaluationLimit(evaluationLimit);
localsolver.solve();
}
// Writes the solution in a file
private void writeSolution(String fileName) throws IOException {
try (PrintWriter output = new PrintWriter(fileName)) {
output.println("obj=" + bbCall.getDoubleValue());
output.println("x1=" + x1.getDoubleValue());
output.println("x2=" + x2.getDoubleValue());
}
}
public static void main(String[] args) {
String outputFile = args.length > 0 ? args[0] : null;
String strEvaluationLimit = args.length > 1 ? args[1] : "30";
try (LocalSolver localsolver = new LocalSolver()) {
Hosaki model = new Hosaki(localsolver);
model.solve(Integer.parseInt(strEvaluationLimit));
if (outputFile != null) {
model.writeSolution(outputFile);
}
} catch (Exception ex) {
System.err.println(ex);
ex.printStackTrace();
System.exit(1);
}
}
}