Hosaki Function
Problem
The Hosaki function is defined by the equation:
This is a box-constrained problem. Variables x1 and x2, respectively, have domains [0, 5] and [0, 6]. The goal of the problem is to find the minimum of this function. For more details, see hosaki_function.html.
Principles learned
- Create an external function
- Enable surrogate modeling on an external function
- Set an evaluation limit to the function
This problem can be solved without the surrogate modeling 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 surrogate modeling on a simple and computationally inexpensive problem.
Program
The Hexaly model for the Hosaki Function Problem uses two float decision variables: x1 and x2. The domains of these variables are [0, 5] and [0, 6], respectively.
The problem does not have any constraints but only an objective function to minimize. The objective function is defined by an external function. It receives the argument values (x1 and x2) via the HxExternalArgumentValues
, and returns the value of the function at this point. To compute the value returned by the external function, an O_Call
expression is created. This expression is then minimized.
To use the surrogate modeling feature, the enableSurrogateModeling
method available on the HxExternalContext
of the function is called. This method returns the HxSurrogateParameters
, on which the maximum number of calls to the function can be set. As the function is usually computationally expensive in practice, it is very useful to limit the search to a reasonable time.
- Execution
-
hexaly hosaki.hxm [evaluationLimit=] [solFileName=]
use io;
/* External function */
function hosaki(args) {
local x1 = args[0];
local x2 = args[1];
return (1 - 8*x1 + 7*pow(x1, 2) - 7*pow(x1, 3)/3 + pow(x1, 4)/4) * pow(x2, 2)
* exp(-x2);
}
/* Declare the optimization model */
function model() {
// Numerical decisions
x1 <- float(0, 5);
x2 <- float(0, 6);
// Create and call the function
f <- doubleExternalFunction(hosaki);
funcCall <- call(f, x1, x2);
// Enable surrogate modeling
surrogateParams = f.context.enableSurrogateModeling();
// Minimize function call
minimize(funcCall);
}
/* Parameterize the solver */
function param() {
if (evaluationLimit == nil) surrogateParams.evaluationLimit = 30;
else surrogateParams.evaluationLimit = evaluationLimit;
}
/* Write the solution in a file */
function output() {
if (solFileName != nil) {
local solFile = io.openWrite(solFileName);
solFile.println("obj=", funcCall.value);
solFile.println("x1=", x1.value);
solFile.println("x2=", x2.value);
}
}
- Execution (Windows)
-
set PYTHONPATH=%HX_HOME%\bin\pythonpython hosaki.py
- Execution (Linux)
-
export PYTHONPATH=/opt/hexaly_13_0/bin/pythonpython hosaki.py
import hexaly.optimizer
import sys
import math
#
# External 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 hexaly.optimizer.HexalyOptimizer() as optimizer:
#
# Declare the optimization model
#
model = optimizer.model
# Numerical decisions
x1 = model.float(0, 5)
x2 = model.float(0, 6)
# Create and call the function
f = model.create_double_external_function(hosaki_function)
func_call = model.call(f, x1, x2)
# Enable surrogate modeling
surrogate_params = f.external_context.enable_surrogate_modeling()
# Minimize function call
model.minimize(func_call)
model.close()
# Parameterize the optimizer
surrogate_params.evaluation_limit = evaluation_limit
optimizer.solve()
# Write the solution in a file
if output_file is not None:
with open(output_file, 'w') as f:
f.write("obj=%f\n" % func_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%HX_HOME%\include /link %HX_HOME%\bin\hexaly130.libhosaki
- Compilation / Execution (Linux)
-
g++ hosaki.cpp -I/opt/hexaly_13_0/include -lhexaly130 -lpthread -o hosaki
./hosaki
#include "optimizer/hexalyoptimizer.h"
#include <cmath>
#include <fstream>
#include <iostream>
using namespace hexaly;
using namespace std;
/* External function */
class HosakiFunction : public HxExternalFunction<hxdouble> {
hxdouble call(const HxExternalArgumentValues& argumentValues) override {
hxdouble x1 = argumentValues.getDoubleValue(0);
hxdouble x2 = argumentValues.getDoubleValue(1);
return (1 - 8 * x1 + 7 * pow(x1, 2) - 7 * pow(x1, 3) / 3 + pow(x1, 4) / 4) * pow(x2, 2) * exp(-x2);
}
};
class Hosaki {
public:
// Hexaly Optimizer
HexalyOptimizer optimizer;
// Hexaly Program variables
HxExpression x1;
HxExpression x2;
HxExpression funcCall;
void solve(int evaluationLimit) {
// Declare the optimization model
HxModel model = optimizer.getModel();
// Numerical decisions
x1 = model.floatVar(0, 5);
x2 = model.floatVar(0, 6);
// Create and call the function
HosakiFunction funcClass;
HxExpression func = model.createExternalFunction(&funcClass);
funcCall = model.call(func, x1, x2);
// Enable surrogate modeling
HxExternalContext context = func.getExternalContext();
HxSurrogateParameters surrogateParams = context.enableSurrogateModeling();
// Minimize function call
model.minimize(funcCall);
model.close();
// Parameterize the optimizer
surrogateParams.setEvaluationLimit(evaluationLimit);
optimizer.solve();
}
/* Write 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=" << funcCall.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 %HX_HOME%\bin\Hexaly.NET.dll .csc Hosaki.cs /reference:Hexaly.NET.dllHosaki
using System;
using System.IO;
using Hexaly.Optimizer;
public class Hosaki : IDisposable
{
/* External function */
public class HosakiFunction
{
public double Call(HxExternalArgumentValues argumentValues)
{
double x1 = argumentValues.GetDoubleValue(0);
double x2 = argumentValues.GetDoubleValue(1);
return (1 - 8 * x1 + 7 * Math.Pow(x1, 2) - 7 * Math.Pow(x1, 3) / 3 + Math.Pow(x1, 4) / 4)
* Math.Pow(x2, 2)
* Math.Exp(-x2);
}
}
// Hexaly Optimizer
private HexalyOptimizer optimizer;
// Hexaly Program variables
private HxExpression x1;
private HxExpression x2;
private HxExpression funcCall;
public Hosaki()
{
optimizer = new HexalyOptimizer();
}
public void Dispose()
{
if (optimizer != null)
optimizer.Dispose();
}
public void Solve(int evaluationLimit)
{
// Declare the optimization model
HxModel model = optimizer.GetModel();
// Numerical decisions
x1 = model.Float(0, 5);
x2 = model.Float(0, 6);
// Create and call the function
HosakiFunction hosakiFunction = new HosakiFunction();
HxDoubleExternalFunction func = new HxDoubleExternalFunction(hosakiFunction.Call);
HxExpression funcExpr = model.DoubleExternalFunction(func);
funcCall = model.Call(funcExpr, x1, x2);
// Enable surrogate modeling
HxExternalContext context = funcExpr.GetExternalContext();
HxSurrogateParameters surrogateParams = context.EnableSurrogateModeling();
// Minimize function call
model.Minimize(funcCall);
model.Close();
// Parameterize the optimizer
surrogateParams.SetEvaluationLimit(evaluationLimit);
optimizer.Solve();
}
/* Write the solution in a file */
public void WriteSolution(string fileName)
{
using (StreamWriter output = new StreamWriter(fileName))
{
output.WriteLine("obj=" + funcCall.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 %HX_HOME%\bin\hexaly.jarjava -cp %HX_HOME%\bin\hexaly.jar;. Hosaki
- Compilation / Execution (Linux)
-
javac Hosaki.java -cp /opt/hexaly_13_0/bin/hexaly.jarjava -cp /opt/hexaly_13_0/bin/hexaly.jar:. Hosaki
import java.io.*;
import java.lang.Math;
import com.hexaly.optimizer.*;
public class Hosaki {
/* External function */
private static class HosakiFunction implements HxDoubleExternalFunction {
@Override
public double call(HxExternalArgumentValues argumentValues) {
double x1 = argumentValues.getDoubleValue(0);
double x2 = argumentValues.getDoubleValue(1);
return (1 - 8 * x1 + 7 * Math.pow(x1, 2) - 7 * Math.pow(x1, 3) / 3 + Math.pow(x1, 4) / 4) * Math.pow(x2, 2) * Math.exp(-x2);
}
}
// Hexaly Optimizer
private final HexalyOptimizer optimizer;
// Hexaly Program variables
private HxExpression x1;
private HxExpression x2;
private HxExpression funcCall;
private Hosaki(HexalyOptimizer optimizer) {
this.optimizer = optimizer;
}
private void solve(int evaluationLimit) {
// Declare the optimization model
HxModel model = optimizer.getModel();
// Numerical decisions
x1 = model.floatVar(0, 5);
x2 = model.floatVar(0, 6);
// Create and call the function
HosakiFunction function = new HosakiFunction();
HxExpression func = model.doubleExternalFunction(function);
funcCall = model.call(func, x1, x2);
// Enable surrogate modeling
HxExternalContext context = func.getExternalContext();
HxSurrogateParameters surrogateParams = context.enableSurrogateModeling();
// Minimize function call
model.minimize(funcCall);
model.close();
// Parameterize the optimizer
surrogateParams.setEvaluationLimit(evaluationLimit);
optimizer.solve();
}
/* Write the solution in a file */
private void writeSolution(String fileName) throws IOException {
try (PrintWriter output = new PrintWriter(fileName)) {
output.println("obj=" + funcCall.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 (HexalyOptimizer optimizer = new HexalyOptimizer()) {
Hosaki model = new Hosaki(optimizer);
model.solve(Integer.parseInt(strEvaluationLimit));
if (outputFile != null) {
model.writeSolution(outputFile);
}
} catch (Exception ex) {
System.err.println(ex);
ex.printStackTrace();
System.exit(1);
}
}
}