2025, Nov 26 15:00

Read Variable Levels After a Time Limit in MOSEK Fusion by Accepting a Feasible Solution

Learn how to make MOSEK Fusion return the best feasible solution after a timeout in integer optimization: use acceptedSolutionStatus(Feasible) to read level()

Working with large-scale integer optimization under a time limit is routine, but a common stumbling block appears when you try to retrieve the best solution found so far. In Mosek-Fusion, calling variable levels after a timeout can fail even if a feasible incumbent exists. Here is how to make Fusion return the best feasible solution when the optimizer stops early.

Reproducing the issue

The snippet below sets a strict time limit and then attempts to read the decision variable values. The solve ends due to the time limit, but accessing levels raises an exception.

from mosek.fusion import *
import mosek.fusion.pythonic
import numpy as np
import sys

if __name__ == '__main__':
  mdl = Model()
  matA = np.array(np.random.randint(-1, 2, size=(128, 256)), dtype=np.float64)
  dv = mdl.variable("x_bin", 256, Domain.binary())
  vecb = np.array(np.random.randint(0, 20, size=(128)), dtype=np.float64)
  coeffs = np.random.random(size=256)

  mdl.constraint(matA @ dv <= vecb)
  mdl.objective(ObjectiveSense.Maximize, dv.T @ coeffs)
  mdl.setSolverParam("optimizerMaxTime", 1)
  mdl.setLogHandler(sys.stdout)
  mdl.solve()
  print(dv.level())

When the time limit is hit, Fusion reports a feasible status but not optimal, and the following error appears:

SolutionError: Solution status is Feasible but Optimal is expected. Reason: Accessing integer solution whose problem status is PrimalFeasible.

What’s going on

By default Fusion expects an optimal solution when you request values with methods like level(). After a timeout, the best available result for an integer problem can be merely feasible, not optimal. In that state Fusion refuses to return levels unless you explicitly allow non-optimal solutions to be treated as acceptable for retrieval.

The fix

Tell Fusion that a feasible solution is acceptable for access. The API provides a way to declare which solution statuses you want to accept. The key line is:

mdl.acceptedSolutionStatus(AccSolutionStatus.Feasible)

With this setting, Fusion will let you query values even when the solver stops early with a feasible incumbent.

Corrected example

from mosek.fusion import *
import mosek.fusion.pythonic
import numpy as np
import sys

if __name__ == '__main__':
  mdl = Model()
  matA = np.array(np.random.randint(-1, 2, size=(128, 256)), dtype=np.float64)
  dv = mdl.variable("x_bin", 256, Domain.binary())
  vecb = np.array(np.random.randint(0, 20, size=(128)), dtype=np.float64)
  coeffs = np.random.random(size=256)

  mdl.constraint(matA @ dv <= vecb)
  mdl.objective(ObjectiveSense.Maximize, dv.T @ coeffs)

  mdl.acceptedSolutionStatus(AccSolutionStatus.Feasible)

  mdl.setSolverParam("optimizerMaxTime", 1)
  mdl.setLogHandler(sys.stdout)
  mdl.solve()
  print(dv.level())

The behavior remains the same in terms of modeling and solving. The only change is that Fusion is instructed to accept a feasible solution for value retrieval after the time limit. The approach is documented here: https://docs.mosek.com/latest/pythonfusion/accessing-solution.html#retrieving-solution-values.

Why this matters

Time limits are practical guardrails for integer optimization. When the solver stops on time rather than optimality, the best feasible incumbent may still be valuable. Making Fusion accept a feasible status gives you immediate access to those values, which is particularly useful if you plan to continue working with the same model state or refine it further.

Takeaways

If your solve ends due to a timeout and you need the best feasible solution, instruct Fusion to accept it before calling level(). This keeps your workflow smooth under time budgets and avoids unexpected exceptions when a feasible, non-optimal result is all you need.