Skip to content

Add compute_control_result: the control together with the solver status - #117

Open
baggepinnen wants to merge 1 commit into
darnstrom:mainfrom
baggepinnen:feat/compute-control-result
Open

baggepinnen wants to merge 1 commit into
darnstrom:mainfrom
baggepinnen:feat/compute-control-result

Conversation

@baggepinnen

Copy link
Copy Markdown
Contributor

Closes #115, following the entry point suggested there.

result = compute_control_result(mpc, x; r, d, uprev, p)
result.control      # the control action (the solver's last iterate on failure)
result.exitflag     # >0 success, <0 failure
result.status       # the flag as a Symbol, e.g. :Optimal, :Soft_Optimal, :Primal_Infeasible
result.solver_info  # DAQP's info (iterations, solve time, ...)
  • MPCResult{I} is a plain struct (parametric on the info type so it stays type-stable);
    compute_control_result performs exactly the same solve and uprev bookkeeping as
    compute_control, which now delegates to it (check = true/false behave as before).
  • Implemented for MPC; ExplicitMPC's tree evaluation has no solver status, so it is left out —
    happy to add a trivially-:Optimal method if you prefer symmetry.
  • Docstrings, a paragraph in manual/simple.md, and a testset (feasible: same control as
    compute_control on a fresh controller, :Optimal, info populated; infeasible hard output
    bound: exitflag < 1, :Primal_Infeasible, no throw, while compute_control still asserts).

One observation from writing the tests, possibly worth its own issue: after an infeasible solve,
subsequent solve calls on the same mpc.opt_model return exitflag = 1 with NaN control —
the Julia-side DAQP workspace is not reset after a failure (the generated C resets it every call).
The tests therefore use a fresh controller per assertion. That behaviour makes the status all the
more important to surface: the second call reports :Optimal while returning NaN.

Full test suite passes locally (Julia 1.12.7).

🤖 Generated with Claude Code

https://claude.ai/code/session_01LNTSoj8uSmNpSqpRTor8di

compute_control asserts on the exit flag and returns only the control, so a caller that must
not throw (a simulation loop, a controller embedded in a larger model) has no public way to
know whether the QP was actually solved (darnstrom#115). compute_control_result performs the same
solve and returns a type-stable MPCResult carrying control, exitflag, status (the flag as a
Symbol) and solver_info; compute_control now delegates to it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LNTSoj8uSmNpSqpRTor8di
@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.59%. Comparing base (92ecae7) to head (68e79fe).
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #117      +/-   ##
==========================================
+ Coverage   89.57%   89.59%   +0.01%     
==========================================
  Files          15       15              
  Lines        2389     2393       +4     
==========================================
+ Hits         2140     2144       +4     
  Misses        249      249              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Getting the solver status of compute_control without asserting

2 participants