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.

This page is for an old version of Hexaly Optimizer. We recommend that you update your version and read the documentation for the latest stable release.

Mathematical modeling features

Decision variables

LocalSolver makes a clear distinction between decision variables and intermediate expressions. A decision variable is a variable that cannot be deduced or computed from other variables or expressions. The question to ask when you use LocalSolver is What are the most atomic decisions I want to take?

This aspect can be a bit disturbing compared to other optimization techniques such as linear programming or constraint programming but it is really important for the performance of the underlying algorithms. For example, in a knapsack problem, the only decisions are the boolean variables x[i] equal to 1 if the object i is in the bag or 0 otherwise. On the opposite, the total weight of elements in the bag, defined as sum[i in 0..nbItems-1](values[i] * x[i]) is a typical intermediate expression: its value can be deduced from decision variables.

There are five kinds of decisions in LocalSolver: booleans, floating quantities, integer quantities, set variables and list variables.

Boolean decisions

Boolean decisions can take two values 0 or 1. They are declared using the built-in function bool() that returns a new binary decision. Booleans enables you to model any problem where a binary decision is involved (such as the knapsack problem). Most of combinatorial optimization problems (assignment, allocation, packing, covering, partitioning, routing, scheduling, etc.) can be simply expressed as pure 0-1 models.

To have an idea of what it is possible with boolean decisions, have a look at our Example tour.

Floating-point decisions

Floating-point decisions are used to model continuous quantitative decisions taking values in a given range. They are declared using the built-in function float(a,b) that returns a floating-point decision with range [a,b]. The largest range of a floating-point decision is defined by the IEEE 754 double-precision floating-point format, which is roughly [-10^307, 10^307].

Integer decisions

In a similar way, integer decisions are used to model integer quantitative decisions taking values in a given range. They are declared using the built-in function int(a,b) that returns an integer decision with range [a,b]. The largest range of an integer decision is [-2^63+1, 2^63-1], which is roughly [-10^18, 10^18].

Set and list decisions

Set and list decisions allow defining decision variables whose value is a collection of integers within a domain [0, n-1] where n is the unique operand of the operator. See our documentation on collection variables for details.

Constraints

A constraint is a kind of tag put on an expression that enforces it to be true (equal to 1). In LocalSolver, any variable or intermediate expression that has a boolean value (0, 1) can be constrained. Thus, ‘’all’’ expressions involving relational operators (<, <=, >, >=, ==, !=) but also logical and (&&), or (||), xor or immediate if (iif) can be constrained without limitation on the type of the problem. In particular, LocalSolver is not limited to linear constraints but can also handle highly-nonlinear models.

To tag an expression as a constraint in the modeler, simply prefix it by the keyword constraint.

// These two formulations are equivalent
constraint knapsackWeight <= 102;
weightCst <- knaspackWeight <= 102;
constraint weightCst;
# These two formulations are equivalent
model.constraint(knapsackWeight <= 102)
weightCst = knaspackWeight <= 102
model.constraint(weightCst)
// These two formulations are equivalent
model.constraint(knapsackWeight <= 102);
weightCst = knaspackWeight <= 102;
model.constraint(weightCst);
// These two formulations are equivalent
model.Constraint(knapsackWeight <= 102);
weightCst = knaspackWeight <= 102;
model.Constraint(weightCst);
// These two formulations are equivalent
model.constraint(knapsackWeight <= 102);
weightCst = model.leq(knaspackWeight, 102);
model.constraint(weightCst);

A good practice in operations research is to only model as constraints requirements that are strictly necessary. If a requirement may be violated in some exceptional cases then it is better modeled as a primary objectives in order to be “softly” satisfied (goal programming). LocalSolver offers a feature making this easy to do: lexicographic objectives.

Objectives

At least one objective must be defined using the keyword minimize or maximize. Any expression can be used as objective. If several objectives are defined, they are interpreted as a lexicographic objective function. The lexicographic ordering is induced by the order in which objectives are declared. In this way, expressions frequently encoutered in math programming models like:

maximize 10000 revenues - 100 resources + desiderata;

in order to first maximize revenues, then minimize resources, and ultimately maximize desiderata can be avoided. Indeed, you can directly write

maximize revenues;
minimize resources;
maximize desiderata;
model.maximize(revenues)
model.minimize(resources)
model.maximize(desiderata)
model.maximize(revenues);
model.minimize(resources);
model.maximize(desiderata);
model.Maximize(revenues);
model.Minimize(resources);
model.Maximize(desiderata);
model.maximize(revenues);
model.minimize(resources);
model.maximize(desiderata);

Table of available operators and functions

In the table below, each operator is identified with its name in the LSP language. Note that in Python, C++, C# or Java these names may slightly differ in order to respect coding conventions and reserved keywords of each language:

  • In C++ and Java, decisions are suffixed with “Var” (boolVar, floatVar, intVar, setVar and listVar)
  • in C# all functions start with a capital letter
  Function Description Arguments type Result type Arity Symb
Decisional bool Boolean decision variable with domain {0,1} none bool 0  
float Float decision variable with domain [a, b] 2 doubles double 2  
int Integer decision variable with domain [a, b] 2 integers int 2  
list Ordered collection of integers within a range [0, n - 1] 1 integer collection 1  
set Unordered collection of integers within a range [0, n - 1] 1 integer collection 1  
Arithmetic sum Sum of all operands bool, int, double int, double n >= 0 +
sub Substraction of the first operand by the second one bool, int, double int, double 2 -
prod Product of all operands bool, int, double int, double n >= 0 *
min Minimum of all operands bool, int, double int, double n > 0  
max Maximum of all operands bool, int, double int, double n > 0  
div Division of the first operand by the second one bool, int, double double 2 /
mod Modulo: mod(a, b) = r such that a = q * b + r with q, r integers and r < b. bool, int int 2 %
abs Absolute value: abs(e) = e if e >= 0, and -e otherwise bool, int, double int, double 1  
dist Distance: dist(a, b) = abs(a - b) bool, int, double int, double 2  
sqrt Square root bool, int, double double 1  
cos Cosine bool, int, double double 1  
sin Sine bool, int, double double 1  
tan Tangent bool, int, double double 1  
log Natural logarithm bool, int, double double 1  
exp Exponential function bool, int, double double 1  
pow Power: pow(a, b) is equal to the value of a raised to the power of b. bool, int, double double 2  
ceil Ceil: round to the smallest following integer bool, int, double int 1  
floor Floor: round to the largest previous integer bool, int, double int 1  
round Round to the nearest integer: round(x) = floor(x + 0.5). bool, int, double int 1  
scalar Scalar product between 2 arrays. array int, double 2  
piecewise Piecewise linear function product between 2 arrays. array, int double double 3  
Logical not Not: not(e) = 1 - e. bool bool 1 !
and And: equal to 1 if all operands are 1, and 0 otherwise bool bool n >= 0 &&
or Or: equal to 0 if all operands are 0, and 1 otherwise bool bool n >= 0 ||
xor Exclusive or: equal to 0 if the number of operands with value 1 is even, and 1 otherwise bool bool n >= 0  
Relational eq Equal to: eq(a, b) = 1 if a = b, and 0 otherwise bool, int, double bool 2 ==
neq Not equal to: neq(a, b) = 1 if a != b, and 0 otherwise bool, int, double bool 2 !=
geq Greater than or equal to: geq(a, b) = 1 if a >= b, 0 otherwise bool, int, double bool 2 >=
leq Lower than or equal to leq(a, b) = 1 if a <= b, 0 otherwise bool, int, double bool 2 <=
gt Strictly greater than: gt(a, b) = 1 if a > b, and 0 otherwise. bool, int, double bool 2 >
lt Strictly lower than: lt(a, b) = 1 if a < b, and 0 otherwise. bool, int, double bool 2 <
Conditional iif Ternary operator: iif(a, b, c) = b if a is equal to 1, and c otherwise bool, int, double bool, int, double 3 ?:
array + at T[i] returns the i th value in array T. array, int bool, int, double 2 []
Set related count Returns the number of elements in a collection. collection int 1  
indexOf Returns the index of a value in a collection or -1 if the value is not present. collection, int int 2  
contains Returns 1 if the collection contains the given value or 0 otherwise. collection, int bool 2  
partition Returns true if all the operands form a partition of their common domain. collection bool n > 0  
disjoint Returns true if all the operands are pairwise disjoint. collection bool n > 0  
cover Returns true if all the operands form a cover of their common domain. collection bool n > 0  
Other call Call a function. It can be used to implement your own operator. bool, int, double double n > 0