Solving Your First Hexaly Model¶
The best way to discover Hexaly Optimizer is to use the built-in modeling language. It provides many mathematical operators and can be used both for programming and modeling: in the same Hexaly Modeler program it is possible to manipulate data structures as in any imperative language and define the optimization model. As a result, models written with Hexaly Modeler are concise and readable.
For more more details, see Hexaly Modeler’s complete documentation.
Hexaly Optimizer is implemented in C++ language. Nevertheless, object-oriented APIs are provided for Python, allowing a full integration of Hexaly Optimizer in your Python business applications. Hexaly Optimizer’s APIs are lightweight, with only a few classes to manipulate. Note that Hexaly Optimizer is a model-and-run math programming solver: having instantiated the model, no additional code has to be written in order to run the solver.
Note
Once you have installed Hexaly Optimizer on your computer, the recommended way to link Hexaly Optimizer to your Python installation is to type the following command in a command prompt or in the prompt of your Python environment (Anaconda for instance):
pip install hexaly
Note that it only configures the integration of Hexaly Optimizer in Python. It is not a substitute for a proper installation of Hexaly Optimizer with a Hexaly Optimizer license. This command must be executed each time you install a new version of Hexaly Optimizer.
In this section, we show you how to model and solve your first problem: the optimization of the shape of a bucket. With a limited surface of material (S=π), we try to build a bucket that holds the largest volume.
This small example is more precisely described in our optimal bucket code template. The main goal of this page is to show how to write and launch a model.
Writing the model¶
Below is a program which models this nonlinear problem (see optimal bucket).
// Copyright (c) Hexaly. Permission is hereby granted to use, copy,
// and modify this code for applications developed with Hexaly.
use io;
/* Declare the optimization model */
function model() {
PI = 3.14159265359;
// Numerical decisions
R <- float(0, 1);
r <- float(0, 1);
h <- float(0, 1);
// Surface must not exceed the surface of the plain disc
surface <- PI * pow(r, 2) + PI * (R + r) * sqrt(pow(R - r, 2) + pow(h, 2));
constraint surface <= PI;
// Maximize the volume
volume <- PI * h / 3 * (pow(R, 2) + R * r + pow(r, 2));
maximize volume;
}
/* Parametrize the solver */
function param() {
if (hxTimeLimit == nil) hxTimeLimit = 2;
}
/* Write the solution in a file with the following format:
* - surface and volume of the bucket
* - values of R, r and h */
function output() {
if (solFileName == nil) return;
local solFile = io.openWrite(solFileName);
solFile.println(surface.value, " ", volume.value);
solFile.println(R.value, " ", r.value, " ", h.value);
}
All the expressions in the model are declared using left arrows <-. Decision
variables are introduced using the built-in float() function (or also
bool(), int(), set(), list(), interval). Intermediate
expressions can be built upon these decision variables by using other operators
or functions. For example, in the model above: power (pow), square root
(sqrt), less than or equal to (<=). Many other mathematical operators
are available, allowing you to model and solve highly nonlinear combinatorial
optimization problems. The keywords constraint or maximize are used for
tagging expressions as constrained or maximized.
# Copyright (c) Hexaly. Permission is hereby granted to use, copy,
# and modify this code for applications developed with Hexaly.
import hexaly.optimizer
import sys
with hexaly.optimizer.HexalyOptimizer() as optimizer:
PI = 3.14159265359
#
# Declare the optimization model
#
m = optimizer.model
# Numerical decisions
R = m.float(0, 1)
r = m.float(0, 1)
h = m.float(0, 1)
# Surface must not exceed the surface of the plain disc
surface = PI * r ** 2 + PI * (R + r) * m.sqrt((R - r) ** 2 + h ** 2)
m.constraint(surface <= PI)
# Maximize the volume
volume = PI * h / 3 * (R ** 2 + R * r + r ** 2)
m.maximize(volume)
m.close()
#
# Parametrize the optimizer
#
if len(sys.argv) >= 3:
optimizer.param.time_limit = int(sys.argv[2])
else:
optimizer.param.time_limit = 2
optimizer.solve()
#
# Write the solution in a file with the following format:
# - surface and volume of the bucket
# - values of R, r and h
#
if len(sys.argv) >= 2:
with open(sys.argv[1], 'w') as f:
f.write("%f %f\n" % (surface.value, volume.value))
f.write("%f %f %f\n" % (R.value, r.value, h.value))
After creating the Hexaly Optimizer environment with HexalyOptimizer(),
all the decision variables of the model are declared with the float()
function (or also bool(), int(), set(), list(), interval()).
Intermediate expressions can be built upon these decision variables by using
other operators or functions. For example, in the model above: power (pow),
square root (sqrt), less than or equal to (<=). Many other mathematical
operators are available, allowing you to model and solve highly nonlinear
combinatorial optimization problems. The methods constraint or
maximize are used for tagging expressions as constrained or maximized.
// Copyright (c) Hexaly. Permission is hereby granted to use, copy,
// and modify this code for applications developed with Hexaly.
#include "optimizer/hexalyoptimizer.h"
#include <fstream>
#include <iostream>
#include <vector>
using namespace hexaly;
using namespace std;
class OptimalBucket {
public:
// Hexaly Optimizer
HexalyOptimizer optimizer;
// Hexaly Program variables
HxExpression R;
HxExpression r;
HxExpression h;
HxExpression surface;
HxExpression volume;
void solve(int limit) {
hxdouble PI = 3.14159265359;
// Declare the optimization model
HxModel model = optimizer.getModel();
// Numerical decisions
R = model.floatVar(0.0, 1.0);
r = model.floatVar(0.0, 1.0);
h = model.floatVar(0.0, 1.0);
// Surface must not exceed the surface of the plain disc
surface = PI * model.pow(r, 2) + PI * (R + r) * model.sqrt(model.pow(R - r, 2) + model.pow(h, 2));
model.constraint(model.leq(surface, PI));
// Maximize the volume
volume = PI * h / 3 * (model.pow(R, 2) + R * r + model.pow(r, 2));
model.maximize(volume);
model.close();
// Parametrize the optimizer
optimizer.getParam().setTimeLimit(limit);
optimizer.solve();
}
/* Write the solution in a file with the following format:
* - surface and volume of the bucket
* - values of R, r and h */
void writeSolution(const string& fileName) {
ofstream outfile;
outfile.exceptions(ofstream::failbit | ofstream::badbit);
outfile.open(fileName.c_str());
outfile << surface.getDoubleValue() << " " << volume.getDoubleValue() << endl;
outfile << R.getDoubleValue() << " " << r.getDoubleValue() << " " << h.getDoubleValue() << endl;
}
};
int main(int argc, char** argv) {
const char* solFile = argc > 1 ? argv[1] : NULL;
const char* strTimeLimit = argc > 2 ? argv[2] : "2";
try {
OptimalBucket model;
model.solve(atoi(strTimeLimit));
if (solFile != NULL)
model.writeSolution(solFile);
return 0;
} catch (const exception& e) {
cerr << "An error occurred:" << e.what() << endl;
return 1;
}
}
After creating the Hexaly Optimizer environment with HexalyOptimizer(),
all the decision variables of the model are declared with the floatVar()
function (or also boolVar(), intVar(), setVar(), listVar(),
intervalVar()). Intermediate expressions can be built upon these decision
variables by using other operators or functions. For example, in the model
above: power (pow), square root (sqrt), less than or equal to (leq).
Many other mathematical operators are available, allowing you to model and solve
highly nonlinear combinatorial optimization problems. The methods
constraint or maximize are used for tagging expressions as constrained
or maximized.
// Copyright (c) Hexaly. Permission is hereby granted to use, copy,
// and modify this code for applications developed with Hexaly.
using System;
using System.IO;
using Hexaly.Optimizer;
public class OptimalBucket : IDisposable
{
// Hexaly Optimizer
HexalyOptimizer optimizer;
// Hexaly Program variables
HxExpression R;
HxExpression r;
HxExpression h;
HxExpression surface;
HxExpression volume;
public OptimalBucket()
{
optimizer = new HexalyOptimizer();
}
public void Dispose()
{
if (optimizer != null)
optimizer.Dispose();
}
public void Solve(int limit)
{
// Declare the optimization model
HxModel model = optimizer.GetModel();
// Numerical decisions
R = model.Float(0, 1);
r = model.Float(0, 1);
h = model.Float(0, 1);
// Surface must not exceed the surface of the plain disc
surface =
Math.PI * model.Pow(r, 2)
+ Math.PI * (R + r) * model.Sqrt(model.Pow(R - r, 2) + model.Pow(h, 2));
model.AddConstraint(surface <= Math.PI);
// Maximize the volume
volume = Math.PI * h / 3 * (model.Pow(R, 2) + R * r + model.Pow(r, 2));
model.Maximize(volume);
model.Close();
// Parametrize the optimizer
optimizer.GetParam().SetTimeLimit(limit);
optimizer.Solve();
}
// Write the solution in a file with the following format:
// - surface and volume of the bucket
// - values of R, r and h
public void WriteSolution(string fileName)
{
using (StreamWriter output = new StreamWriter(fileName))
{
output.WriteLine(surface.GetDoubleValue() + " " + volume.GetDoubleValue());
output.WriteLine(
R.GetDoubleValue() + " " + r.GetDoubleValue() + " " + h.GetDoubleValue()
);
}
}
public static void Main(string[] args)
{
string outputFile = args.Length > 0 ? args[0] : null;
string strTimeLimit = args.Length > 1 ? args[1] : "2";
using (OptimalBucket model = new OptimalBucket())
{
model.Solve(int.Parse(strTimeLimit));
if (outputFile != null)
model.WriteSolution(outputFile);
}
}
}
After creating the Hexaly Optimizer environment with HexalyOptimizer(),
all the decision variables of the model are declared with the Float()
function (or also Bool(), Int(), Set(), List(), Interval()).
Intermediate expressions can be built upon these decision variables by using
other operators or functions. For example, in the model above: power (Pow),
square root (Sqrt), less than or equal to (<=). Many other mathematical
operators are available, allowing you to model and solve highly nonlinear
combinatorial optimization problems. The methods Constraint or
Maximize are used for tagging expressions as constrained or maximized.
// Copyright (c) Hexaly. Permission is hereby granted to use, copy,
// and modify this code for applications developed with Hexaly.
import java.io.*;
import com.hexaly.optimizer.*;
public class OptimalBucket {
private static final double PI = 3.14159265359;
// Hexaly Optimizer
private final HexalyOptimizer optimizer;
// Hexaly Program variables
private HxExpression R;
private HxExpression r;
private HxExpression h;
private HxExpression surface;
private HxExpression volume;
private OptimalBucket(HexalyOptimizer optimizer) {
this.optimizer = optimizer;
}
private void solve(int limit) {
// Declare the optimization model
HxModel model = optimizer.getModel();
HxExpression piConst = model.createConstant(PI);
// Numerical decisions
R = model.floatVar(0, 1);
r = model.floatVar(0, 1);
h = model.floatVar(0, 1);
// surface = PI*r^2 + PI*(R+r)*sqrt((R - r)^2 + h^2)
HxExpression s1 = model.prod(piConst, r, r);
HxExpression s2 = model.pow(model.sub(R, r), 2);
HxExpression s3 = model.pow(h, 2);
HxExpression s4 = model.sqrt(model.sum(s2, s3));
HxExpression s5 = model.sum(R, r);
HxExpression s6 = model.prod(piConst, s5, s4);
surface = model.sum(s1, s6);
// Surface must not exceed the surface of the plain disc
model.addConstraint(model.leq(surface, PI));
HxExpression v1 = model.pow(R, 2);
HxExpression v2 = model.prod(R, r);
HxExpression v3 = model.pow(r, 2);
// volume = PI*h/3*(R^2 + R*r + r^2)
volume = model.prod(piConst, model.div(h, 3), model.sum(v1, v2, v3));
// Maximize the volume
model.maximize(volume);
model.close();
// Parametrize the optimizer
optimizer.getParam().setTimeLimit(limit);
optimizer.solve();
}
/* Write the solution in a file with the following format:
* - surface and volume of the bucket
* - values of R, r and h */
private void writeSolution(String fileName) throws IOException {
try (PrintWriter output = new PrintWriter(fileName)) {
output.println(surface.getDoubleValue() + " " + volume.getDoubleValue());
output.println(R.getDoubleValue() + " " + r.getDoubleValue() + " " + h.getDoubleValue());
}
}
public static void main(String[] args) {
String outputFile = args.length > 0 ? args[0] : null;
String strTimeLimit = args.length > 1 ? args[1] : "2";
try (HexalyOptimizer optimizer = new HexalyOptimizer()) {
OptimalBucket model = new OptimalBucket(optimizer);
model.solve(Integer.parseInt(strTimeLimit));
if (outputFile != null) {
model.writeSolution(outputFile);
}
} catch (Exception ex) {
System.err.println(ex);
ex.printStackTrace();
System.exit(1);
}
}
}
After creating the Hexaly Optimizer environment HexalyOptimizer(),
all the decision variables of the model are declared with the floatVar()
function (or also boolVar(), intVar(), setVar(), listVar(),
intervalVar()). Intermediate expressions can be built upon these decision
variables by using other operators or functions. For example, in the model
above: power (pow), square root (sqrt), less than or equal to (leq).
Many other mathematical operators are available, allowing you to model and
solve highly nonlinear combinatorial optimization problems. The methods
constraint or maximize are used for tagging expressions as constrained
or maximized.
Compiling and running the program¶
To solve this model, call Hexaly Optimizer with the HXM file as argument.
On Windows:
hexaly %HX_HOME%\examples\optimal_bucket\optimal_bucket.hxm
Note that on Windows, in a PowerShell window you would use the following line:
hexaly $env:HX_HOME\examples\optimal_bucket\optimal_bucket.hxm
On Linux or Mac OS the command line looks like this:
hexaly /opt/hexaly_15_0/examples/optimal_bucket/optimal_bucket.hxm
A Python distribution must be installed on your computer. Hexaly Optimizer is compatible with Python >= 3.8.
On any system, if you applied the recommended pip install procedure
described above, your Python program is directly launched with:
python optimal_bucket.py
On Windows, the above program is compiled and launched using the following lines in Visual Studio Command Prompt x64:
cl /EHsc optimal_bucket.cpp -I%HX_HOME%\include /link %HX_HOME%\bin\hexaly150.lib
optimal_bucket
Note that on Windows, in a PowerShell window you would use the following lines:
cl /EHsc optimal_bucket.cpp -I"$env:HX_HOME\include" /link "$env:HX_HOME\bin\hexaly150.lib"
optimal_bucket
On Linux, the same program is compiled and launched using the following lines:
g++ optimal_bucket.cpp -I/opt/hexaly_15_0/include -lhexaly150 -lpthread -o optimal_bucket
./optimal_bucket
On MacOS, you can use the following lines:
clang++ optimal_bucket.cpp -std=c++11 -I/opt/hexaly_15_0/include -lhexaly150 -lpthread -o optimal_bucket
./optimal_bucket
On Windows, the above program is compiled and launched using the following lines in Visual Studio Command Prompt x64. Note that if you use directly Visual Studio IDE for building your program, you must specify the Platform target x64, in the Properties of your Visual Studio project.
copy %HX_HOME%\bin\Hexaly.NET.dll .
csc OptimalBucket.cs /reference:Hexaly.NET.dll
OptimalBucket
For compiling, Java Development Kit 8.0 (or superior) must be installed on your computer. On Windows, the above program is compiled and launched using the following lines:
javac OptimalBucket.java -cp %HX_HOME%\bin\hexaly.jar
java -cp %HX_HOME%\bin\hexaly.jar;. -Djava.library.path=%HX_HOME%\bin\ OptimalBucket
Note that on Windows, in a PowerShell window you would use the following lines:
javac OptimalBucket.java -cp $env:HX_HOME\bin\hexaly.jar
java "-Djava.library.path=$env:HX_HOME\bin\" -cp "$env:HX_HOME\bin\hexaly.jar;." OptimalBucket
On Linux or Mac OS, the above program is compiled and launched using the following lines:
javac OptimalBucket.java -cp /opt/hexaly_15_0/bin/hexaly.jar
java -cp /opt/hexaly_15_0/bin/hexaly.jar:. -Djava.library.path=/opt/hexaly_15_0/bin/ OptimalBucket
Then, the following trace will appear in your console:
Model: expressions = 26, decisions = 3, constraints = 1, objectives = 1
Param: time limit = 2 sec, no iteration limit
[objective direction ]: maximize
[ 0 sec, 0 itr]: 0
[ optimality gap ]: 100%
[ 0 sec, 42898 itr]: 0.68709
[ optimality gap ]: < 0.01%
42898 iterations performed in 0 seconds
Optimal solution:
obj = 0.68709
gap = < 0.01%
bounds = 0.687189
If no time limit is set, the search will continue until optimality is proven
(Optimal solution message) or until you force the stop of the program by
pressing Ctrl+C. The trace in console starts with the key figures of the
model: number of expressions, decisions, constraints, and objectives.
Once the search is finished, the total number of iterations and the elapsed time
are displayed, as well as the status and the value of the best solution
found. The solution status can be Inconsistent, Infeasible,
Feasible, or Optimal.
If you have trouble compiling or launching the program, please have a look at the Installation & Licensing instructions. We invite users willing to go further with APIs to consult the API Reference: