Skip to content

Active development environment: you may notice changes or incomplete features.

JAOT

Analyzing Results

Every solve persists an execution, and the execution page is where you read the result. It is built around one principle: lead with facts that are exact for your solution, and label everything that is approximate.

In the Model Workspace, the results drawer that opens after a solve shows a compact summary — status, objective, how many variables were assigned — and a View full results link to the execution page described here.

The structured solution

A solved assignment or routing model used to read as a wall of assign_v3_o107 = 1 rows. The execution page now recovers the index structure those flat names came from and leads with a grouped view: one block per variable family, sub-grouped by the first index — assignv3 → the members chosen for it.

  • Non-zero only is on by default: the grouped view shows the decisions (binary members that are on show just their label; anything else shows its value).
  • The Table toggle switches to the full flat table, including per-variable sensitivity columns.
  • Variables with no recoverable structure render flat in an "Other variables" bucket — nothing regresses for continuous or custom-named models.
  • On very large solutions the grouped view renders a bounded prefix (500 values) with a Show all opt-in, so the page stays responsive.

Structure recovery is server-side and honest: a model compiled from a JModel source carries its real index sets, authoritatively. For flat or imported models, JAOT parses the conventional name_1_2 numeric-suffix pattern only — anything ambiguous is left flat rather than guessed.

The solve summary

The Solve summary card states how the model solved, honestly:

  • "Proven optimal at the root node — no branching" — the presolver and cuts closed the problem immediately.
  • "Optimal proven after N nodes" — real branch-and-bound work happened.
  • "Time limit reached — best solution has gap X%" — you got the incumbent, not a proof.

Below the headline: the objective value, the final gap, node and iteration counts, and wall-clock solve time. (This card replaced a live convergence chart that was empirically a flat line for real models — solvers find the incumbent almost immediately and spend the rest of the run proving optimality, so a curve suggested progress that wasn't the story.)

Exact analysis

The Analysis section is computed on demand from the solution x* and the problem data — not from the LP relaxation — so every figure is exact for the integer solution and solver-agnostic:

  • Binding constraints — "12 of 439 constraints are binding at the optimum (no slack)", with the tightest constraints listed first: activity, operator, and right-hand side per row.
  • Utilization — per ≤-constraint, activity as a percentage of its right-hand side, so "capacity is at 97%" is one glance.
  • Objective contributions — which terms c·x* actually drive the objective, as a ranked bar list.

Very large models degrade gracefully: the analysis is bounded (the most informative rows lead, a truncation note appears) rather than slow.

The classic LP-relaxation shadow prices are still available, demoted into a collapsed section underneath and deduplicated ("47 constraints · shadow price 1.0" instead of 47 identical rows). For a MIP they are duals of a different, easier problem — directional at best — which is exactly why they no longer lead the page. See Understanding Your Solution for how to read them, and for the plain-language AI explanation of the result.

The variables chart

The Visualization tab charts variable magnitudes. When every non-zero variable has the same value — the normal case for a binary assignment solution, where a bar chart of identical bars carries zero information — it collapses to an aggregate ("N variables at 1, M at zero") with a Show chart anyway override.

API

Everything on the page is available programmatically:

GET /api/v2/models/executions/{execution_id}
GET /api/v2/models/executions/{execution_id}/exact-analysis

The first returns the persisted execution (solution variables include the recovered family and index_tuple); the second computes the exact analysis on demand — binding constraints, slack/utilization, and objective contributions.