Releases: ERGO-Code/HiGHS
v1.14.0
The highlight of v1.14 is the extension of the HiPO interior point LP
solver to handle convex QPs.
Code changes
Prompted by #2821,
the treatment of Hessian matrix anomalies has been changed. Firstly,
any duplicate entries in the Hessian are now summed.
-
When a square Hessian is read from the
QMATRIXsection of an MPS
file, or passed by a user, any asymmetry results in
Highs::readModelorHighs::passHessianreturning
HighsStatus::kError. Previously HiGHS would use$$(Q+Q^T)/2$$ as
the Hessian. -
A triangular Hessian, whether read from the
QUADOBJsection of an
MPS file, or passed by a user, was previsouly assumed to be given by
only lower triangular entries, with any entries in the upper
triangle being ignored. Now, any entries in the upper triangle of
the Hessian are accepted, being added to any corresponding entries
in the lower triangle. If there are entries in the upper triangle,
their number is logged in a warning message, which also states the
number of any summations, andHighs::readModelor
Highs::passHessianwill returnHighsStatus::kWarning.
Prompted by #2849,
console, file and callback logging are now independent, allowing any
combination to be on/off.
Following PR #2854,
HiPO is now capable of solving convex QP problems. Option
solver="qpasm" selects the previous active-set QP solver, while
solver="hipo" or solver="ipm" selects the HiPO solver.
Following PR #2865,
HiGHS performs logging during probing in MIP presolve and checks for
time-out
Following PR #2870,
dedicated time-out during IIS calculation (using HiGHS option
iis_time_limit) has been enabled.
Prompted by #2883,
the function signature for Highs_getInfinity in the C# API has been
corrected.
Prompted by #2887,
addVariable in highspy cannot create names with spaces, illegal
variable or constraint names when writing MPS or LP files no longer
leads to an error return - generic names are created - and the EMS
file facility has been removed.
Following PR #2918,
logging during IIS calculation has been improved.
Following PR #2934,
HiPO uses infinity-norm equilibration of the rows and columns of the
matrix rather than Curtis-Reid scaling.
v1.13.1
Code changes
Following PR #2812,
HiGHS can read LP files with keywords as constraint names.
Following PR #2818, a
potential data race in the HiGHS multithreading system has been fixed
Following PR #2825,
potential conflict with METIS symbols has been eliminated.
Following PR #2832,
potential conflict with AMD and RCM symbols has been eliminated.
Following PR #2834,
there is some minimal documentation of the highspymodelling
language.
Following PR #2837,
the use of the logging callback is independent to the settings of the
output_flag, log_to_console and output_flag options.
Build changes
Following PR #2836,
it is now possible to build a static library with HiPO, without the
requirement for blas to be specified at compile time.
Following PR #2839,
files like README.md and LICENSE.txt are installed in the proper location.
v1.13.0
Code changes
The HiPO release exposed various issues flagged up via GitHub and email.
- Fix some overflows when computing statistics of analyse phase.
- Free memory used for normal equations, if augmented system is preferred.
- Fix bug in supernode amalgamation.
- Print the BLAS library used in the HiGHS header, so it is visible when using HiPO without logging.
- Add the ability to use AMD and RCM rather than Metis
- Use 64-bit integers
- Fixed the time limit
Following PR #2623,
singleton column stuffing added to MIP presolve - see Gamrath et al.,
Progress in presolving for mixed integer
programming. Math. Prog. Comp. 7, 367–398 (2015).
Following user PR
#2625, callback data
structs are named, allowing them to be forward-declared data types if
a callback needs to be declared in a public header
Following PR #2626,
IPX is used by default when switching to IPM after simplex reaches
iteration limit in HighsLpRelaxation::run
Following user PR
#2628, #include <functional> has been added in highs/mip/HighsGFkSolve.h and
highs/mip/HighsNodeQueue.h to avoid compilation failures for some
compilers.
Prompted by #2633,
the constraint matrix is passed by reference (rather than value) for
each constraint when writing a LP file.
Following PR #2639,
the dominated columns reduction is speeded up for models with many
columns.
Prompted by #2643,
primal simplex is avoided when the unscaled LP problem has primal
infeasibilities but is dual feasible.
Following PR #2644,
the irreducible infeasibility system detection facility has been
refactored and is much more robust. Rather than have
HighsOption::iis_strategy be one from an enum of "strategy
scenarios" it is now a bit map
- 0 => "light strategy", which is always performed when
Highs::getIisis called. - 1 => From dual ray, which is currently unavailable.
- 2 => From the whole LP (solving an elasticity LP repeatedly (fixing positive elastic variables at zero) until no more elastic variables are positive, and using the fixed elastic variables to determine a set of infeasible rows, for which there is a corresponding set of columns with nonzeros in those rows that form an infeasibility set (IS).
- 4 => Attempt to reduce the IS to an IIS.
- 8 => Prioritize low numbers of columns (rather than low numbers of rows) when reducing the IS.
Hence, by just setting the 2-bit, an IS is formed reliably, and at not great expense (for an LP).
Prompted by #2653,
the very rare report of spurious primal infeasibilities in the optimal
solution of MIPs with large bounds on variables or constraints is
eliminated.
Prompted by #2655,
#2766 and
#2744,
changeRowsBounds has been added to highspy.
Following PR #2671,
implications gathered by the MIP solver are applied when performing a
bound change.
Prompted by #2676,
the getIis method in highspy is now correct.
Following PR #2678, an
option mip_allow_cut_separation_at_nodes (default true) has been
added for models where time is spent on separating cuts at branching
nodes is a considerable fraction of the solution time.
Prompted by #2681,
Highs_getPresolvedColName and Highs_getPresolvedRowName have been
added to the C API.
Following PR #2695,
HPresolve::enumerateSolutions enumerates all solutions to pure
binary constraints with up to 8 variables. This is run before probing
to avoid (expensive) probing on binary variables that could be
fixed.
Prompted by #2696,
the simplex solver sets dual values of basic variables to zero,
translating this numerical error measure to nonzero residuals in the
dual equations.
Prompted by #2705, a
presolved MIP can be passed from C if it contains implied integers.
Following user PR
#2713, scalar
entries of the HighsLp class are not used after the corresponding
instance undergoes std::move in highs/mip/HighsLpRelaxation.cpp.
Prompted by #2721, examples
of using solution in Python examples have been improved.
Following user PR
#2747, save_value is
initialised wen a HighsSimplexBadBasisChangeRecord is created.
Following PR #2761,
presolve now checks if all binary variables (from a constraint) form a
clique.
Following PR #2762,
the vector is passed by reference rather than value to freeVector in
highs/ipm/hipo/auxiliary/Auxiliary.h.
Following PR #2768,
the HiPO wrapper no longer makes an unnecessary copy of the LP.
Prompted by #2769,
now initialising sense in struct Model of LP file reader
Compiler warnings have been fixed
All unguarded printf statements have been removed.
Build changes
Added Python 3.14 wheels.
Added a CMake option BUILD_OPENBLAS for Windows and Linux, when HIPO is ON and BUILD_OPENBLAS is ON, OpenBLAS is downloaded and built as a subproject. The default value is OFF.
Update rules_cuda for the bazel build.
Filereader is now in highs/ rather than extern/.
Metis, AMD and RCM are now in extern/. Metis is no longer an external dependency.
Binaries are now available. Standard HiGHS binaries are MIT-licensed and HiGHS with HiPO are Apache-licensed.
Licensing
Code not written for HiGHS is now maintained in the /extern
directory, and THIRD_PARTY_NOTICES.md contains a statement of the
licenses of all such external code, some of which are permissive
non-MIT licenses.
When HiGHS is built from code, the conditions of the non-MIT licenses
are such that the resulting binaries and executable remain MIT
licensed. However, since the interior point solver HiPO makes use of
some of this external code, we believe that the MIT license is lost
when users link to our precompiled binaries. Hence there are binaries
without HiPO (MIT license), and with HiPO (Apache 2.0 license).
We believe that this is a conservative stance, and we are taking
expert advice that may allow us to relax this distinction.
v1.12.0
Code changes
HiPO is out! Our new factorisation-based interior point solver, developed by Filippo Zanetti, is officially integrated in HiGHS! HiPO is multi-threaded and will improve the performance on many large instances. Metis and BLAS are required for HiPO. In this version, HiPO will be available when HiGHS is built from source with CMake. It can be accessed from C++, C and will also be available when HiGHS is called from JuMP. In a future release, HiPO will be available from Python, C# and more.
Forcing column reduction now checks the bound on the column dual rather than whether the dual row activity is zero fixing #2409
Now handling correctly the case where an infeasible MIP has a feasible relaxation, so no ray is computed fixing #2415
Fixed minor bug exposed by #2441 in Highs::setSolution() for a sparse user solution when the moidel is empty, and only clearing the dual data before solving with modified objective in Highs::multiobjectiveSolve() so that user-supplied solution is not cleared.
The irreducible infeasibility system (IIS) facility now detects infeasibility due to bounds on constraint activity values (implied by variable bounds) being incompatible with constraint bounds. A kIisStrategyLight mode for the iis_strategy option has been introduced so that only infeasibility due to incompatible variable/constraint bounds and constraint activity values is checked for. The LP corresponding to any known IIS is now formed and held as a data member of the HighsIis class. It can be obtained as a const reference using Highs::getIisLp(), and written to a file using Highs::writeIisModel(const std::string& filename = "")
Prompted by #2463, the HiGHS solution and basis files now match data to any column and row names in the model, only assuming that the data are aligned with column and row indices if there are no names in the model. This requires a new version (v2) of the HiGHS basis file. Basis files from v1 are still read, but deprecated. Now, when writing out a model, basis or solution, column and row names are added to the model - previously they were created temporarily and inconsistentyly on the fly. If the model has existing names, then distinctive names are created to replace any blank names, but names with spaces or duplicate names yield an error status return.
Refactored strong branching to minimize duplicated code
Only for LPs is there a choice of solver. Previously, when setting the solver option to anything other than "choose", any incumbent model was solved as an LP, using that LP solver. This has caused confusiuon for users, and is unnecessary now that there is the solve_relaxation option. Now, if the incumbent model is a QP or MIP, it is solved as such (unless solve_relaxation is true for a MIP), and the value of the solver option only determines what solver is used to solve an LP. If the value of solver is "choose", then HiGHS will use what it expects to be the best solver for the problem; if value of solver is "ipm", then HiGHS will use what it expects to be the better IPM solver (of HiPO and IPX) for the problem; if value of solver is "hipo", then HiGHS will use the HiPO IPM solver (if available in the build); if value of solver is "ipx", then HiGHS will use the IPX IPM solver; if value of solver is "pdlp", then HiGHS will use the PDLP first-order solver. The option mip_lp_solver has been introduced to define which LP solver is used when solving LPs in the MIP solver for which an advanced basis is not known - typically the "root node" LP. Note that The PDLP solver cannot be used to solve such LPs, since it does not yield a basic solution. If an interior point solver fails to obtain a basic solution, the simplex solver will then be used. The option mip_ipm_solver has been introduced to define which IPM solver is used when solving LPs in the MIP solver for which IPM is mandatory - typically the analytic centre calculation. When LPs are to be solved by an IPM solver, the HiPO solver is used (if available in the build) unless IPX has been specified explicitly.
As per #2487, trivial heuristics now run before feasibility jump (FJ), and FJ will use any existing incumbent. FJ will clip any finite variable values in the incumbent to lower and upper bounds, and falls back to the existing logic (lower bound if finite, else upper bound if finite, else 0) for any infinite values in the incumbent.
Prompted by #2460, the options user_objective_scale and user_bound_scale apply uniform (power-of-two) scaling to the objective and bounds of a model, and now respect the following restrictions
- For a MIP, column bounds cannot be scaled, so the scaling is achieved by scaling the cost and constraint matrix column
- For a QP, Hessian entries must be scaled down (up) when bounds are scaled up (down) so that all terms in the objective are scaled by a constant.
Formerly the options user_cost_scale and user_bound_scale allowed uniform (power-of-two) scaling to the costs and bounds of an LP. The option user_cost_scale is now replaced by user_objective_scale.
After HiGHS determines and logs the coefficient ranges and warns about extreme values, it recommends values of user_objective_scale and user_bound_scale if
- All the objective coefficients (bound values) are smaller than the "excessively small constant"
kExcessivelySmallObjectiveCoefficient(kExcessivelySmallBoundValue) - both of which are 1e-4 - suggesting that they are scaled up so that the largest value becomes (just over) the excessively small constant. Since the smallest value can be arbitrarily small, scaling so that this becomes (just over) the small constant is inadvisable, as the largest value could then be scaled up to an extremely large value. - All the objective coefficients (bound values) are larger than the "excessively large constant"
kExcessivelyLargeObjectiveCoefficient(kExcessivelyLargeBoundValue) - both of which are 1e6 - suggesting that they are scaled down so that the largest value becomes (just over) the excessively large constant.
The recommended objective scaling is determined with respect to the recommended bound scaling
Users can obtain the recommended values of user_objective_scale and user_bound_scale by calling Highs::getObjectiveBoundScaling
The irreducible infeasibility system (IIS) facility now detects infeasibility due to bounds on constraint activity values being incompatible with constraint bounds. A kIisStrategyLight mode for the iis_strategy option has been introduced so that only infeasibility due to incompatible variable/constraint bounds and constraint activity values is checked for. The model corresponding to any known IIS is now formed and held as a data member of the HighsIis class. The HighsIis class is available via highspy, and its data members are available via the C API.
Prompted by #2463, when HiGHS writes out a solution or basis for a model without column or row names, it creates names. This avoids a mis-match between the ordering of variables when such a model is written out as a .lp file, and then this and a solution or a basis is read in.
Prompted by #2528, the logging for the HiGHS interior point method (IPM) solvers and PDLP solver has been standardised, and logging has been added to the IPM solver during time-consuming computational phases.
Prompted by #2557, Highs::getFixedLp has been added so that, after solving a MIP, the LP with discrete variables fixed at their optimal values can be formed, allowing it to be passed to HiGHS and solved as an LP.
Prompted by #2581, the QP example in call_highs_from_csharp.cs has been corrected
Prompted by #2582, the C API constants are declared static const to prevent multiple definition linker errors
Build changes
The Bazel build now supports building with Cuda with an optional parameter cupdlp_gpu.
v1.11.0
Build changes
Replace command line parsing library with Cpp11 #2211
CMake updates #2286, the root of the HiGHS source files is now highs/, rather than src/
Add missing include to zstr needed for gcc v15 and clang v19 #2313
Updates for intel llvm compiler on linux #2257
Build directory for Windows MSVC now Release/bin replacing bin/Release #2376
Code changes
Fixed incorrect assertion in HighsMipSolver::solutionFeasible() (fixing #2204)
As part of #2251 cuPDLP-C will start from the incumbent solution in HiGHS. For a model that has been changed, the user must supply a starting solution via a call to Highs::setSolution
getColIntegrality now returns HighsVarType::kContinuous when model_.lp_.integrality_ is empty (fixing #2261)
Now ensuring that when solving a scaled LP with useful but unvalidated basis, it does not lose its scaling after validation, since the scaling factors will be applied to the solution (fixing #2267)
By setting non-empty values of options read_solution_file, read_basis_file, write_model_file (with extension .lp or .mps), write_solution_file, solution_file, write_basis_file, these files will be read or written when calling Highs::run(). Hence options previously only available via the command line interface can be use (for example) by modelling languages that only call Highs::run() (fixing #2269).
Bug #2273 fixed
Added the feasibility jump heuristic as per #1423. This is on by default, but using the option mip_heuristic_run_feasibility_jump=false switches it off.
ZI rounding and shifting MIP primal heuristics have been added (see #2287). They are off by default, but can be activated by setting the options mip_heuristic_run_zi_round and mip_heuristic_run_shifting to be true. Options mip_heuristic_run_rins, mip_heuristic_run_rens and mip_heuristic_run_root_reduced_cost to run the RINS, RENS and rootReducedCost heuristics have been added. These are true by default, but setting them to be false can accelerate the MIP solver on easy problems.
Added Highs_changeRowsBoundsByRange to C API, fixing #2296
Corrected docstrings for Highs_getReducedRow, motivated by #2312
LP file reader no longer fails when there is no objective section. Fix is #2316, but this exposes code quality issue #2318
Added a max scale factor (+1024) when scaling up coefficients in preprocessBaseInequality and postprocessCut. Fix is #2337
Corrected the bounds used in when strengthening coefficients in HPresolve::rowPresolve, fixing #1517
Fixed numerical error in highs/mip/HighsCliqueTable.cpp, closing #2320
Fixed bug in highs/mip/HighsFeasibilityJump.cpp, closing #2331
Tightened CMIR cuts, leading to small performance gain, closing #2333
Scaling the tolerance in forcing row reduction to avoid use of rows with small coefficients and bounds, closing #2290
Fixed bug when calculating a coefficient in one of the cuts in separateImpliedBounds in highs/mip/HighsImplications.cpp
Added CSECTION to the exceptions for keywords that are followed by text, and thus cannot be used as names of columns, RHS, ranges, bounds etc.
Introduced the following KKT error measures to HighsInfo: num_relative_primal_infeasibilities; max_relative_primal_infeasibility; num_relative_dual_infeasibilities; max_relative_dual_infeasibility; num_primal_residual_errors; max_primal_residual_error; num_dual_residual_errors; max_dual_residual_error; num_relative_primal_residual_errors; max_relative_primal_residual_error; num_relative_dual_residual_errors; max_relative_dual_residual_error; num_complementarity_violations; max_complementarity_violation; primal_dual_objective_error. The relative values are used to assess whether a solution deemed to be optimal by the first order LP solver cuPDLP-C or interior point solver IPX (without crossover) is truly acceptable. They also enable users to determine whether a solution corresponding to HighsModelStatus::kUnknown is acceptable to them as optimal. Also introduced options complementarity_tolerance used to assess whether the (relative) primal-dual objective error is acceptable, and kkt_tolerance which, if set to a value other than kDefaultKktTolerance = 1e-7 is used as the tolerance for all the KKT error measures. The HiGHS documentation has been updated to reflect the new options and HighsInfo data, and logging messages indicate when KKT error measures are not satisfied, despite the solver considering the LP solution to be optimal.
Added a max scale factor (+1024) when scaling up coefficients in preprocessBaseInequality and postprocessCut. Fix is #2337.
Renamed HighsOptions::pdlp_d_gap_tol to HighsOptions::pdlp_optimality_tolerance for consistency with IPM
Renamed HighsOptions::complementarity_tolerance to HighsOptions::optimality_tolerance for consistency with IPM and PDLP
v1.10.0
Build changes
Added code coverage report
Replaced command line parsing library with CLI11. Removed C++17 reference with cxxopts, which is no longer in HiGHS
Code changes
Any LP offset is communicated to the IPM solver, and used in logging and primal/dual objective calculations.
If there is a valid basis when Highs::run() is called, presolve isn't skipped unless the solver option is "simplex" or "choose" (when simplex will always be chosen if there is an advanced basis).
Added basis solve methods to highspy
Added methods to get primal/dual ray and dual unboundedness direction to highspy
When a presolved LP has model status kUnknown, rather than returning this to the user, it performs postsolve and then uses the basis to solve the original LP
Fixed bug in presolve when pointers stored in HighsMatrixSlice get invalidated when the coefficient matrix is reallocated (e.g. when non-zeros are added in HPresolve::addToMatrix)
Primal and dual residual tolerances - applied following IPM or PDLP solution - now documented as options
Highs::getCols (Highs::getRows) now runs in linear time if the internal constraint matrix is stored column-wise (row-wise). Added ensureColwise/Rowwise to the Highs class, the C API and highspy so that users can set the internal constraint matrix storage orientation
When columns and rows are deleted from the incumbent LP after a basic solution has been found, HiGHS no longer invalidates the basis. Now it maintains the basic and nonbasic status of the remaining variables and constraints. When the model is re-solved, this information is used to construct a starting basis.
Fixed bugs in presolve
When running from the command line, changes to default option values are reported
Added callback to allow users to supply integer feasible solutions to the MIP solver during execution
Bug fix for primal heuristics in the MIP solver
Model status is set appropriately when a solver's claimed optimality doesn't satify the general HiGHS primal/dual feasibilily tolerances. Affects IPM without crossover and PDLP
Command line parsing now done with pure C++11 code
Added command line flags to read basis from and write basis to a file
Bug fixes in records of primal/dual rays
MPS read utility improved. Error logging is now less verbose; inability to handle USERCUTS section is properly logged
Implemented lifting for probing as described by Achterberg et al in Presolve Reductions in Mixed Integer Programming. INFORMS Journal on Computing 32(2):473-506 (2019). Not used by default, but option mip_lifting_for_probing allows it to be used with two levels of modification
Propagated updates from cuPDLP-C
Added GPU support for cuPDLP-C
v1.9.0
Build changes
Python: Source Distribution update, added to PyPI
Code changes
HiGHS now handles multiple linear objectives by either blending using weights, or performing lexicographic optimization: see https://ergo-code.github.io/HiGHS/stable/guide/further/#guide-multi-objective-optimization
Fixed minor bug in bound checking in presolve
Fixed bug in floor(HighsCDouble x) and ceil(HighsCDouble x) when argument is small
Added some sanity checks to Highs::writeLocalModel to prevent segfaults if called directly by a user
v1.8.1
Build changes
Added wheels for Python 3.13
Updated command line options and moved them out of the library and into the executable
Code changes
When primal infeasiblity is detected in presolve, no dual ray is available so, previously, the has_dual_ray parameter of Highs::getDualRay returned false and that was it. Now, if a null pointer is not passed for dual_ray_value, Highs::getDualRay will compute a dual ray - at the cost of solving the feasiblility LP without presolve. The same is now true for Highs::getPrimalRay. Highs::getDualUnboundednessDirection has been introduced to determine the product between the constraint matrix and the dual ray, forcing the calculation of the latter if necessary. Once a dual ray is known for the incumbent model in HiGHS, subsequent calls to Highs::getDualRay and Highs::getDualUnboundednessDirection will be vastly cheaper
The method Highs::getDualObjectiveValue now exitsts to compute the dual objective value, returning HighsStatus::kError if it is not possible.
The method Highs::getStandardFormLp now exists to return the incumbent LP in standard form - overlooking any integrality or Hessian. To determine the sizes of the vectors of data, the method is called without specifying pointers to the data arrays.
Added documentation on the use of presolve when solving an incumbent model, and clarifying the use of the method Highs::presolve.
HiGHS will now read a MIPLIB solution file
Added time limit check to HPresolve::strengthenInequalities
Added getColIntegrality to highspy
Now computing the primal-dual integral, reporting it, and making it available as HighsInfo::primal_dual_integral
Trivial primal heuristics "all zero", "all lower bound", "all upper bound", and "lock point" added to the MIP solver
v1.8.0
Code updates
We believe that the issue of HiGHS "hanging" when run on Windows with threads not equal to 1 has been fixed!
Added int64_t mip_total_lp_iterations to HighsCallbackDataOut and modified accessor function
Highs::writeSolution and Highs::writeBasis now being done via HighsIO logging, so can be redirected to logging callback.
Introduced const double kHighsUndefined as value of undefined values in a user solution. It's equal to kHighsInf
Added Highs::setSolution(const HighsInt num_entries, const HighsInt* index, const double* value); to allow a sparse primal solution to be defined. When a MIP is solved to do this, the value of (new) option mip_max_start_nodes is used for mip_max_nodes to avoid excessive cost
Added options write_presolved_model_to_file and write_presolved_model_file so that presolved model can be written via a command line option
Added Highs::feasibilityRelaxation to solve the problem of minimizing a (possibly weighted) sum of (allowable) infeasibilities in an LP/MIP.
Added Python utility examples/plot_highs_log.py (due to @Thell) to visualise progress of the MIP solver.
Added minimal documentation of solvers and how simplex variants can be run
Methods receiving matrix data where only small values are explicit zeros (so removed internally) are now silent and return HighsStatus::kOk (since internal matrix is exact)
Now multiplying by pre-computed reciprocals rather than performing divisions in loops in simplex solver: LP performance improvement ~2.5%
Primal and dual residuals after IPM and cuPDLP-C are checked, and corrections applied to row solution and column duals
Highs::passModelName added to allow name to be given to the incumbent model
Memory leaks in cuPDLP-C fixed
Bug fixed in MIP presolve
v1.7.2
Build changes
The python wrapper highspy is now available for aarch64 on manylinux
This allows highs to be run through Python on AWS arm64
Bug fix for fortran on macOS
Code changes
The accessor function Highs_getCallbackDataOutItem in the C API means
that pdlp_iteration_count can be moved back to where it was inserted
into the HighsCallbackDataOut struct in v1.7.0, which broke the C
API. This fixes #1812
Some duplicate code has been eliminated from the MIP solver, and
modifications made to eliminate compiler warnings
Declaration of the (deprecated) method char* highsCompilationDate()
has been corrected
Fixed bug when describing integrality status during the human-readable solution write