LocalSolver logo
is now
Hexaly logo

We're excited to share that we are moving forward. We're leaving behind the LocalSolver brand and transitioning to our new identity: Hexaly. This represents a leap forward in our mission to enable every organization to make better decisions faster when faced with operational and strategic challenges.


Hosaki Function¶

Note

This problem can be resolved 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.

Principles learned¶

  • Create an external function

  • Enable the surrogate modeling on an external function

  • Set an evaluation limit to the function

Problem¶

../_images/hosaki_blackbox.svg

Hosaki function is defined by

\[f(x) = (1 - 8x_1 + 7x_1^2 - \frac{7}{3} x_1^3 + \frac{1}{4} x_1^4)x_2^2 e^{-x_2}\]

This is a box-constrained problem.

For more details, see: hosaki_function.html

Download the example


Program¶

The objective function is defined by an external function. It receives the argument values via the LSExternalArgumentValues, and returns the value of the function at this point.

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 external function, an O_Call expression is created. This expression is then minimized.

To use the surrogate modeling feature, the method enableSurrogateModeling available on the LSExternalContext of the function is called. This method returns the LSSurrogateParameters, on which the maximum number of calls to the function can be set, as the function is usually computationally expensive.

Execution:
hexaly hosaki.hxm [evaluationLimit=] [solFileName=]
use io;

/* External function */
function hosaki(x1, x2) {
    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\python
python hosaki.py
Execution (Linux)
export PYTHONPATH=/opt/hexaly_13_0/bin/python
python 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.lib
hosaki
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.dll
Hosaki
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.jar
java -cp %HX_HOME%\bin\hexaly.jar;. Hosaki
Compilation / Execution (Linux)
javac Hosaki.java -cp /opt/hexaly_13_0/bin/hexaly.jar
java -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);
        }
    }
}