Warnings

Hexaly Optimizer provides warnings to help identify potential issues in the solver configuration or the model. This section explains how to enable or disable warnings and interpret their messages.

Enabling and disabling warnings

Parameter HxParam.warningLevel controls the warning computation behavior with three possible levels:

  • 0: Disable warning computation.
  • 1: Automatic behavior (default) - warnings related to the solver configuration are displayed, but modeling warnings are not computed.
  • 2: Compute all warnings, including modeling warnings.

For example, the following code enables the computation of all warnings:

hxWarningLevel = 2;
optimizer.param.warning_level = 2
optimizer.getParam().setWarningLevel(2);
optimizer.GetParam().SetWarningLevel(2);
optimizer.getParam().setWarningLevel(2);

Solver configuration warnings

Warnings are raised when the solver configuration is set in such a way that it may not perform as expected:

  • The number of threads is set below the recommended minimum, which may cause a significant loss in performance.
  • Warnings related to phases:
    • Phase p has a time or iteration limit, whereas the previous phase has none. Limits on p and any successive phases will never be applied.
    • Phase p has an optimized objective of higher priority than the previous phase. It is recommended that phase objectives progress monotonically.
    • Several phases focus on the same objective, which means they are equivalent to a single phase with cumulated duration.
    • One or several objectives are not used in any phase and will therefore be discarded.
  • An advanced parameter was set that does not exist.

Modeling warnings

Modeling warnings aim at assisting users in the detection of modeling errors. They are raised when a constraint or objective cannot be proven to be well-defined. They often indicate the presence of implicit constraints, which the user might not have expected.

For a solution to be valid, each objective and each constraint must be assigned a well-defined value. For example, an objective assigned the square root of a negative number x would result in an invalid solution. This also applies if the objective is a sum including such an undefined value. Consequently, when the term sqrt(x) appears in the objective function, it implicitly requires x to be nonnegative. Similarly, a term a[x] can be undefined if x is out of the bounds of the array a, which implicitly restricts the domain of x. Such implicit requirements can make the problem infeasible or can dramatically restrict the set of feasible solutions.

However, if this undefined square root has no impact on constraints and objectives, then the model remains perfectly valid. For instance, the following objective is perfectly legitimate:

minimize x >= 0 ? sqrt(x) : sqrt(-x);
model.minimize(model.iif(x >= 0, model.sqrt(x), model.sqrt(-x)))
model.minimize(model.iif(x >= 0, model.sqrt(x), model.sqrt(0 - x)));
model.Minimize(model.If(x >= 0, model.Sqrt(x), model.Sqrt(0 - x)));
model.minimize(model.iif(model.geq(x, 0), model.sqrt(x), model.sqrt(model.sub(0, x))));

Indeed, in this case, the objective value is always well-defined, even when one branch of the conditional statement is undefined.

Hexaly performs an in-depth analysis of the model to determine whether all objectives and constraints are guaranteed to be well-defined. Note that in order to keep this analysis as fast as possible, it is not exhaustive and false positive and false negative results are possible. In other words, a warning can be issued even though the model constraints and conditions are defined such that the “Not a Number” error will never occur (false positive). Conversely, the absence of warnings does not guarantee that the model is correct (false negative). However, checking the part of the model mentioned in the warning is highly recommended.

As mentioned above, the main possible causes of undefined values are forbidden arithmetic operations (0/0, sqrt(-1), log(0), etc.), and array overflows. It is important to understand that these mistakes will not throw errors during the resolution of the model, it will merely discard a (possibly large) part of the solution space.

For instance, in our Capacitated Vehicle Routing Problem (CVRP) code template, we need to compute the distance traveled by each truck to write the objective function (total traveled distance). Each truck is modeled using a list decision variable representing the sequence of customers it visits. If we write sequence the list decision variable representing the customers visited by truck k, and c the number of customers visited by truck k (count(sequence)), then the distance traveled by truck k is the sum of

  • the sum of distances from one customer to the next
  • if the truck is used, the distance from the depot to the first customer and from the last customer back to the depot

The latter term is written:

(c > 0 ? (distDepot[sequence[0]] + distDepot[sequence[c - 1]]) : 0)
model.iif(c > 0, dist_depot[sequence[0]] + dist_depot[sequence[c - 1]], 0)
model.iif(c > 0, distDepot[sequence[0]] + distDepot[sequence[c - 1]], 0)
model.If(c > 0, distDepot[sequence[0]] + distDepot[sequence[c - 1]], 0)
model.iif(model.gt(c, 0), model.sum(model.at(distDepot, model.at(sequence, 0)),
        model.at(distDepot, model.at(sequence, model.sub(c, 1)))), 0)

Without the if safeguard, the only valid solutions would be solutions where all lists are non-empty. This would lead to unexpected behavior: the solver would only produce solutions using all the trucks, even though much better solutions using only a fraction of the trucks may exist for certain low-demand instances.

When modeling warnings are enabled, the following warning is issued and the user can easily identify the problem:

Warning: A risk of "Not a Number" error on objective (expression #13522): sum#13522
was identified. Please make sure that this expression will always be well-defined.
The probable cause is expression #2271: at(list#0(512), 0).

This warning clearly identifies that at least one list is accessed at index 0 with a risk of overflow (with no guarantee that the list is non-empty).