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 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 ? sqrt(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.

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

    println("Status is " + lsSolution.status);

    // you can also compare the status to its possible values
    if (lsSolution.status == "INCONSISTENT") ...
    else if (lsSolution.status == "INFEASIBLE") ...
    else if (lsSolution.status == "FEASIBLE") ...
    else if (lsSolution.status == "OPTIMAL") ...
}
# with ls an object of type LocalSolver

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

std::cout << "Status is " << ls.getSolution().getStatus() << std::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

Console.Writeline("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

System.out.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), isUndefined (LSP/Java/C++) or IsUndefined (C#).

function output() {
    // with x an ls expression
    if (x.isUndefined()) throw "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";
std::cout << "x is boolean ? "<< (x.isBool() ? "YES" : "NO") << std::endl;
// same method to retrieve int and bool values
std::cout << "value of x is "<< (x.isDouble() ? x.getDoubleValue() : x.getIntValue() << std::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 and array 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.

Before retrieving the value of the expression, the user can check its type using the necessary methods available on LSExpression objects. 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();
std::cout << "Collection values = " << coll.toString() << std::endl;
std::cout << "Collection size = " << coll.count() << std::endl;
// note that indexing starts at 0 and that the values of a set
// are given in increasing order
std::cout << "Collection 8th value = " << coll[7] << std::endl;

// with myarray an array expression
LSArray arrayvals = myarray.getArrayValue();
std::cout << "Array value = " << arrayvals.toString() << std::endl;
std::cout << "Array size = " << arrayvals.count() << std::endl;
std::cout << "Array 8th value is double = " << arrayvals.isDouble(7) << std::endl;
std::cout << "Array 8th value = " << arrayvals[7] << std::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.get(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));

Values of interval variables and expressions

The value of an interval decision variable or a range expression is an interval characterized by a start value, an end value, and a size.

Before retrieving the value of the expression, the user can check its type using the necessary methods available on LSExpression objects. The values of these expressions are of type LSInterval.

These types can be printed directly (the output is formatted with points e.g. 5…10) or the user can retrieve its charateristics (start, end, size) one by one.

function output() {
    // with myinterval an interval or range expression
    local inter = myinterval.value;
    println("Interval = " + inter);
    println("Interval size = " + inter.count());
    println("Interval start = " + inter.start);
    println("Interval end = " + inter.end);
}
# with myinterval an interval or range expression
inter = myinterval.value
print("Interval value = " + inter)
print("Interval size = " + inter.count())
print("Interval start = " + inter.start())
print("Interval end = " + inter.end())
// with myinterval an interval or range expression
LSInterval inter = myinterval.getIntervalValue();
std::cout << "Interval value = " << inter.toString() << std::endl;
std::cout << "Interval size = " << inter.count() << std::endl;
std::cout << "Interval start = " << inter.start() << std::endl;
std::cout << "Interval end = " << inter.end() << std::endl;
// with myinterval an interval or range expression
LSInterval inter = myinterval.GetIntervalValue();
Console.Writeline("Interval value = " + inter);
Console.Writeline("Interval size = " + inter.Count());
Console.Writeline("Interval start = " + inter.Start());
Console.Writeline("Interval end = " + inter.End());
// with myinterval an interval or range expression
LSInterval inter = myinterval.getIntervalValue();
System.out.println("Interval value = " + inter);
System.out.println("Interval size = " + inter.count());
System.out.println("Interval start = " + inter.start());
System.out.println("Interval end = " + inter.end());