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.

Retrieving solution status and values

Status of the solution

A feasible solution is an assignment of values to decisions variables such that:

  • all constraints are satisfied,
  • no objective has undefined value. Undefined values can occur when performing illegal mathematical operations (square root of negative number for instance) or accessing outside of the bounds of an array.

Note that some values can be undefined in a feasible solution, provided that all objectives have valid values. For instance a conditional expression x>0 ? srqt(x) : sqrt(-x) always has one of its branches undefined, but its output is always valid.

At the end of the search, the status of the solution can be one of the following:

  • INCONSISTENT if the solver was able to prove that no feasible solution can be found
  • INFEASIBLE if no feasible solution has been found yet
  • FEASIBLE if a feasible solution has been computed
  • OPTIMAL if a feasible solution has been found whose optimality has been proven. (objective value within 0.01% of computed bound for each objective)

This status can be retrieved at any time after the model has been closed.

// you must include ls module at the beginning of your lsp file
use ls;

// it allows you to access to the current solution, for instance in the output() function
function output() {

    println("Status is :"+ls.current.solution.status);

    // you can also compare the status to its possible values
    if (ls.current.solution.status == ls.status.INCONSISTENT) ...
    else if (ls.current.solution.status == ls.status.INFEASIBLE) ...
    else if (ls.current.solution.status == ls.status.FEASIBLE) ...
    else if (ls.current.solution.status == ls.status.OPTIMAL) ...
}
with localsolver.LocalSolver() as ls:

    ...

    print('Status is ' + ls.solution.status)
    # you can also compare the status to its possible values
    if (ls.solution.status == LSSolutionStatus.INCONSISTENT) :
        ...
    elif (ls.solution.status == LSSolutionStatus.INFEASIBLE) :
        ...
    elif (ls.solution.status == LSSolutionStatus.FEASIBLE) :
        ...
    elif (ls.solution.status == LSSolutionStatus.OPTIMAL) :
        ...
// with ls an object of type LocalSolver

cout << "Status is :" << ls.getSolution().getStatus() << endl;

// you can also compare the status to its possible values
if (ls.getSolution().getStatus() == SS_INCONSISTENT) ...
else if (ls.getSolution().getStatus() == SS_INFEASIBLE) ...
else if (ls.getSolution().getStatus() == SS_FEASIBLE) ...
else if (ls.getSolution().getStatus() == SS_OPTIMAL) ...
// with ls an object of type LocalSolver

println("Status is :"+ls.GetSolution().GetStatus());

// you can also compare the status to its possible values
if (ls.GetSolution().GetStatus() == SolutionStatus.Inconsistent) ...
else if (ls.GetSolution().GetStatus() == SolutionStatus.Infeasible) ...
else if (ls.GetSolution().GetStatus() == SolutionStatus.Feasible) ...
else if (ls.GetSolution().GetStatus() == SolutionStatus.Optimal) ...
// with ls an object of type LocalSolver

println("Status is :"+ls.getSolution().getStatus());

// you can also compare the status to its possible values
if (ls.getSolution().getStatus() == SolutionStatus.Inconsistent) ...
else if (ls.getSolution().getStatus() == SolutionStatus.Infeasible) ...
else if (ls.getSolution().getStatus() == SolutionStatus.Feasible) ...
else if (ls.getSolution().getStatus() == SolutionStatus.Optimal) ...

Values of numeric variables and expressions

Numeric variables and expressions are expressions of the mathematical model whose value is a boolean and integer of a floating point number. Three methods are available on expressions to identify these expressions : isBool(), isInt() and isDouble() (or in Python is_bool, is_int and is_double and in C# IsBool(), IsInt() and IsDouble()).

As mentioned above, an expression can have an undefined value, what can be detected with function is_undefined (Python) (or isUndefined in LSP/Java/C++ and IsUndefined in C#).

function output() {
    // with x an ls expression
    if (x.isUndefined()) error("X was expected to have a valid value");
    println("x is boolean" ? +(x.isBool() ? "YES": "NO");
    println("value of x is "+x.value);
}
# with x an object of type LSExpression
if x.is_undefined():
    raise Exception('X was expected to have a valid value')
print(' x is boolean ? '+ ('YES' if x.is_bool() else 'NO'))
print(' value of x is '+x.value)
// with x an object of type LSExpression
if (x.isUndefined()) throw "X was expected to have a valid value";
cout << "x is boolean ? "<< (x.isBool() ? "YES": "NO") << endl;
// same method to retrieve int and bool values
cout << "value of x is "<< (x.isDouble()? x.getDoubleValue() : x.getIntValue() << endl;
// with x an object of type LSExpression
if (x.IsUndefined()) throw new Exception("X was expected to have a valid value");
 Console.Writeline("x is boolean ? " + (x.isBool() ? "YES": "NO"));
 // same method to retrieve int and bool values
 Console.Writeline("value of x is "+ (x.IsDouble()? x.GetDoubleValue() : x.GetIntValue());
// with x an object of type LSExpression
 if (x.isUndefined()) throw new Exception("X was expected to have a valid value");
 System.out.println("x is boolean ? " + (x.isBool() ? "YES": "NO"));
 // same method to retrieve int and bool values
 System.out.println("value of x is "+ (x.isDouble()? x.getDoubleValue() : x.getIntValue());

Values of collection variables and expressions

Some expressions of a LocalSolver model do not take numeric values. For instance the value of a set or a list is a collection of integers. Similarly the value of an array expression is an array of values.

Generally, collections or arrays are clearly identified by the user. If needed the necessary methods are available on LSExpression objects to check this value type. The values of these expressions are of type LSCollection (for set and list) or LSArray (for arrays).

These types can be printed directly (the output is formatted with brackets e.g. [4, 8, 7, 2]) or the user can retrieve its values one by one.

function output() {
    // with mycoll a set or list expression
    local coll = mycoll.value;
    println("Collection values = "+coll);
    println("Collection size = "+coll.count);
    // note that indexing starts at 0 and that the values of a set
    // are given in increasing order
    println("Collection 8th value = "+coll[7]);

    // with myarray an array expression
    local arrayvals = myarray.value;
    println("Array value = "+arrayvals);
    println("Array size = "+arrayvals.count);
    println("Array 8th value = "+ arrayvals[7]));
}
# with mycoll a set or list expression
coll = mycoll.value
print('Collection values = ',coll)
print('Collection size = ',coll.count())
# note that indexing starts at 0 and that the values of a set
# are given in increasing order
print('Collection 8th value = ', coll[7])

# with myarray an array expression
arrayvals = myarray.value
print('Array value = ', arrayvals)
print('Array size = ', arrayvals.count())
print('Array 8th value is double = ', arrayvals.is_double(7))
print('Array 8th value = ', arrayvals[7])
// with mycoll a set or list expression
LSCollection coll = mycoll.getCollectionValue();
cout << Collection values = " << coll.toString() << endl;
cout << "Collection size = " <<coll.count() << endl;
// note that indexing starts at 0 and that the values of a set
// are given in increasing order
cout << "Collection 8th value = " << coll[7] << endl;

// with myarray an array expression
LSArray arrayvals = myarray.getArrayValue();
cout << "Array value = " << arrayvals.toString() << endl;
cout << "Array size = " << arrayvals.count() << endl;
cout << "Array 8th value is double = " << arrayvals.isDouble(7) << endl;
cout << "Array 8th value = " << arrayvals[7] << endl;
// with mycoll a set or list expression
LSCollection coll = mycoll.GetCollectionValue();
Console.Writeline("Collection values = " + coll);
Console.Writeline("Collection size = " +coll.Count());
// note that indexing starts at 0 and that the values of a set
// are given in increasing order
Console.Writeline("Collection 8th value = " + coll[7]);

// with myarray an array expression
LSArray arrayvals = myarray.GetArrayValue();
Console.Writeline("Array value = " + arrayvals);
Console.Writeline("Array size = " + arrayvals.Count());
Console.Writeline("Array 8th value is double = " + arrayvals.IsDouble(7));
Console.Writeline("Array 8th value = " + arrayvals[7]);
// with mycoll a set or list expression
LSCollection coll = mycoll.getCollectionValue();
System.out.println("Collection values = " + coll);
System.out.println("Collection size = " +coll.count());
// note that indexing starts at 0 and that the values of a set
// are given in increasing order
System.out.println("Collection 8th value = " + coll.getValue(7));

LSArray arrayvals = arr.getArrayValue();
System.out.println("Array value = " + arrayvals);
System.out.println("Array size = " + arrayvals.count());
System.out.println("Array 8th value is double = " + arrayvals.isDouble(7));
System.out.println("Array 8th value = " + arrayvals.getDoubleValue(7));