Results#

Solve Results#

Unified solver result for Cvxium: a SolveResult built from concern-scoped parts.

A solver’s result carries fields whose applicability depends on two independent things: the problem (a feasibility problem has no objective value; an unconstrained problem has no Lagrange multipliers) and the solver (the barrier method has inner centering steps that the primal-dual method lacks). Rather than encode that two-dimensional fact in a one-dimensional inheritance chain, which forces sentinel values into the data and isinstance checks into every caller, SolveResult is a single concrete type assembled by composition:

  • the always-present spine (solution, status, message, solver, n_iterations);

  • problem-shape parts (objective, duals), present exactly when the problem has that structure, so their absence itself carries the information a sentinel would;

  • a single solver-method part (diagnostics), whose concrete type names the solver that ran;

  • optional certificate and phase1 parts.

Convenience accessors (objective_value, equality_multipliers, and so on) delegate into the parts and raise a specific error when the concern is absent, so the common path stays flat. TwoBlockSolveResult adds x- and y-block views for saddle-point solves.

The module depends only on NumPy, matplotlib, and the standard library; it imports no other Cvxium module, so it can be used anywhere without risking an import cycle. (matplotlib backs the diagnostics plotting methods and, under lazy imports, is not loaded until a plot method is first called.) Every container is frozen (a result is a value, not a workspace) with eq=False, because the fields include NumPy arrays and nested parts with no clean value equality or hash; compare fields explicitly instead. Each container supports a to_dict/from_dict round trip, and SolveResult adds serialize/deserialize for JSON.

class cvxium.problems.result.SolveStatus(*values)[source]#

Bases: Enum

Outcome of a solve.

The members are:

  • OPTIMAL: the duality gap is within tolerance;

  • ACCEPTABLE: the gap is within the soft tolerance;

  • FEASIBLE: a feasibility solve found a feasible point;

  • MAX_ITERATIONS: an optimization stopped at a best-effort iterate;

  • INFEASIBLE: certified infeasible, or no feasible point was found (ProblemMarginallyFeasibleError carries this status without claiming a certificate);

  • UNBOUNDED: certified unbounded.

The centering step still reports the integer codes 0, 1, and 2 internally; _legacy_solve_status in optimization maps them to OPTIMAL, ACCEPTABLE, and MAX_ITERATIONS.

class cvxium.problems.result.SolverDiagnostics[source]#

Bases: object

Solver-method part of a result; the concrete subclass names the solver.

The base carries no fields; each solver’s subclass exposes its own per-iteration trajectories as typed tuples. The subclasses are BarrierDiagnostics, SaddleBarrierDiagnostics, PrimalDualDiagnostics and HsdDiagnostics.

iteration_count()[source]#

Return the number of iterations performed, comparable within one solver.

The unit differs by method (Newton steps for the barrier method, outer iterations for the primal-dual and homogeneous self-dual methods), but within one solver it is an honest measure of work, which is what a performance guard needs.

Returns:

n – The iteration count; 0 in the base, meaning the solver does not report one.

Return type:

int

to_dict()[source]#

Serialize to a JSON-ready dict tagged with the concrete type.

Returns:

d – A dict whose "__type__" entry names the diagnostics class.

Return type:

dict[str, Any]

static from_dict(d)[source]#

Reconstruct the tagged diagnostics subclass from to_dict output.

Dispatches on the "__type__" tag. The barrier step trajectories (inner_btls_steps, inner_quadratic_from) and the primal-dual step_sizes are optional in the payload and default to empty.

Parameters:

d (dict[str, Any]) – A dict produced by some diagnostics class’s to_dict.

Returns:

diagnostics – An instance of the tagged class.

Return type:

SolverDiagnostics

Raises:
  • ValueError – When the tag names no known diagnostics class.

  • KeyError – When a required entry is missing.

class cvxium.problems.result.BarrierDiagnostics(duality_gaps=(), inner_nits=(), inner_suboptimalities=(), inner_btls_steps=(), inner_quadratic_from=())[source]#

Bases: SolverDiagnostics

Barrier-method trajectories, one entry per outer (barrier-parameter) step.

Entry i of inner_nits, inner_suboptimalities, inner_btls_steps and inner_quadratic_from describes the inner Newton centering performed during outer step i.

Together, inner_btls_steps and inner_quadratic_from answer a question the other trajectories cannot: whether the solver takes full Newton steps once it is entitled to. Past the quadratic-convergence threshold, backtracking accepts the unit step (Boyd and Vandenberghe, 2004, section 9.5.3), so a step below 1 there means a step cap is binding when it should not be, a defect that costs iterations silently and otherwise shows up only as a slow solver. steps_past_quadratic_convergence extracts those steps.

Fields:
  • duality_gaps (tuple[float, …]) – Duality gap after each outer step.

  • inner_nits (tuple[int, …]) – Number of Newton iterations in each centering step.

  • inner_suboptimalities (tuple[tuple[float, …], …]) – Per centering step, the suboptimality estimate λ^2 / 2 (λ the Newton decrement) at each Newton iteration.

  • inner_btls_steps (tuple[tuple[float, …], …]) – Per centering step, the accepted backtracking step length of each Newton iteration.

  • inner_quadratic_from (tuple[int | None, …]) – Per centering step, the 0-based index into that step’s inner_btls_steps entry of the first step taken after the suboptimality fell below the quadratic-convergence threshold; None when it never did.

References

Boyd, Stephen and Vandenberghe, Lieven, Convex Optimization, Cambridge University Press, 2004.

iteration_count()[source]#

Return the total number of Newton iterations across all centering steps.

Returns:

n – The sum of inner_nits.

Return type:

int

steps_past_quadratic_convergence()[source]#

Return every accepted step length taken in the quadratic phase.

The hook for regression tests, which assert that these are all 1: a solver in the quadratic phase that is not taking unit steps has a cap binding somewhere, and the iterations it costs are invisible in any aggregate the result otherwise exposes.

Returns:

steps – The steps from each centering step’s inner_quadratic_from index onward, concatenated over the outer steps. Empty when no outer step reached the quadratic phase, which callers should treat as no evidence rather than as a pass.

Return type:

tuple[float, …]

to_dict()[source]#

Serialize the barrier trajectories to a JSON-ready dict.

Returns:

d – The fields as lists, tagged "BarrierDiagnostics".

Return type:

dict[str, Any]

plot_convergence(ax=None)[source]#

Plot the duality gap per outer step on a log scale.

Draws a step function (stairs), since the barrier duality gap is a discrete value sampled once per outer centering step. PrimalDualDiagnostics and HsdDiagnostics track per-iteration trajectories and draw ordinary line plots instead.

Parameters:

ax (Axes | None) – Axes to draw on; None creates a new figure.

Returns:

ax – The axes drawn on.

Return type:

Axes

plot_newton_convergence(it, ax=None)[source]#

Plot the inner Newton suboptimality for one outer (centering) step.

Parameters:
  • it (int) – The outer step to plot, 1-indexed.

  • ax (Axes | None) – Axes to draw on; None creates a new figure.

Returns:

ax – The axes drawn on.

Return type:

Axes

Raises:

ValueError – When inner_nits and inner_suboptimalities differ in length, when no trajectories were recorded, or when it is outside 1 to the number of outer steps.

class cvxium.problems.result.SaddleBarrierDiagnostics(duality_gaps=(), inner_nits=(), inner_suboptimalities=(), inner_btls_steps=(), inner_quadratic_from=(), upper_bounds=(), lower_bounds=(), certified_upper_bounds=(), certified_lower_bounds=())[source]#

Bases: BarrierDiagnostics

Barrier trajectories for a two-block saddle solve, with saddle-value brackets.

Extends BarrierDiagnostics with a closed-form bracket on the saddle value V, recorded once per outer step:

lower_bounds[i] ≤ V ≤ upper_bounds[i].

The two-block objective ζ is concave in the x-block and convex in the y-block (the negated x-block Hessian is positive definite), so a joint stationary point solves

max_x min_y ζ(x, y).

On the barrier central path, the two frozen-block best-response duals have a closed form (central-path duality applied per block). With the barrier parameter t, the per-block inequality counts m_x (the x-block, a maximization) and m_y (the y-block, a minimization), and the achieved saddle value

v = ζ(x, y),

the bounds are

L = v - m_y / t ≤ V,   U = v + m_x / t ≥ V.

The y-block, the inner minimization (min_y ζ(x_bar, y) ≤ V), sets the lower bound, and the x-block, the outer maximization (max_x ζ(x, y_bar) ≥ V), sets the upper bound. So upper_bounds[i] - lower_bounds[i] equals duality_gaps[i], the surrogate gap (m_x + m_y) / t. The bracket is exact on the central path and approximate, to the inner centering tolerance, off it, the same caveat the surrogate gap carries.

The optional certified bounds give a guaranteed bracket that holds off the central path too. Each is obtained by minimizing the frozen-block Lagrangian again with a warm-started mini-Newton solve and subtracting δ^2, the squared Newton decrement. Inside the self-concordant region (Boyd and Vandenberghe, 2004, Eq. 9.50) this correction yields a guaranteed bound, so

certified_lower_bounds[i] ≤ V ≤ certified_upper_bounds[i]

holds unconditionally. When a block’s minimization leaves the self-concordant region where the correction is valid, the entry is -inf (lower) or inf (upper), a conservative deferral rather than an unsound bound.

The fields of BarrierDiagnostics are inherited; the new fields are below.

Fields:
  • upper_bounds (tuple[float, …]) – Closed-form upper bound U on the saddle value after each outer step.

  • lower_bounds (tuple[float, …]) – Closed-form lower bound L on the saddle value after each outer step.

  • certified_upper_bounds (tuple[float, …]) – Guaranteed upper bound after each outer step, inf where deferred; empty when the certified dual was not evaluated.

  • certified_lower_bounds (tuple[float, …]) – Guaranteed lower bound after each outer step, -inf where deferred; empty when the certified dual was not evaluated.

References

Boyd, Stephen and Vandenberghe, Lieven, Convex Optimization, Cambridge University Press, 2004.

to_dict()[source]#

Serialize the saddle trajectories and value brackets to a JSON-ready dict.

The certified bounds may contain ±inf deferrals. json.dumps encodes them as Infinity and -Infinity under its default allow_nan=True, and json.loads reads them back.

Returns:

d – The fields as lists, tagged "SaddleBarrierDiagnostics".

Return type:

dict[str, Any]

plot_bounds(ax=None)[source]#

Plot the upper and lower bounds on the saddle value against the outer step.

Each bound is sampled once per outer centering step, so the two curves are drawn as step functions closing on the saddle value, with the bracket between them shaded. plot_convergence shows the same information as a single gap curve on a log scale. When present, the certified bracket is overlaid as dashed curves, with the ±inf deferrals masked out so that only steps with a guaranteed bound are drawn.

Parameters:

ax (Axes | None) – Axes to draw on; None creates a new figure.

Returns:

ax – The axes drawn on.

Return type:

Axes

Raises:

ValueError – When upper_bounds and lower_bounds differ in length, when no bounds were recorded, or when certified bounds are present but do not match that length.

class cvxium.problems.result.PrimalDualDiagnostics(surrogate_gaps=(), primal_residual_norms=(), dual_residual_norms=(), step_sizes=())[source]#

Bases: SolverDiagnostics

Primal-dual trajectories, one entry per outer iteration.

Fields:
  • surrogate_gaps (tuple[float, …]) – Surrogate duality gap η̂ = -f^T λ at each iteration.

  • primal_residual_norms (tuple[float, …]) – Euclidean norm of the primal residual r_pri at each iteration.

  • dual_residual_norms (tuple[float, …]) – Euclidean norm of the dual residual r_dual at each iteration.

  • step_sizes (tuple[float, …]) – Step length taken at each iteration.

iteration_count()[source]#

Return the number of outer primal-dual iterations.

Returns:

n – The length of surrogate_gaps.

Return type:

int

late_step_sizes(fraction=0.25)[source]#

Return the step lengths over the last fraction of the solve.

The primal-dual analogue of the barrier method’s quadratic phase. There is no threshold to cross here; the health signal is that the step length approaches 1 as the iterates converge, since a method still taking short steps at the end is being held back by something. Asserting on the tail rather than on a phase flag keeps the claim to what the method actually guarantees.

Parameters:

fraction (float) –

Share of the trajectory to return, in (0, 1]. For n recorded steps the tail has

max(1, floor(n × fraction))

entries. Out-of-range values are rejected rather than clamped, since each has a plausible but wrong answer: 0 or a negative value would floor to a one-element tail, and a value above 1 (such as 25 meant as 25%) would return the whole trajectory.

Returns:

steps – The last entries of step_sizes; empty when no steps were recorded.

Return type:

tuple[float, …]

Raises:

ValueError – When fraction is outside (0, 1].

to_dict()[source]#

Serialize the primal-dual trajectories to a JSON-ready dict.

Returns:

d – The fields as lists, tagged "PrimalDualDiagnostics".

Return type:

dict[str, Any]

plot_convergence(ax=None)[source]#

Plot the surrogate duality gap η̂ = -f^T λ against the iteration.

The primal-dual method does not evaluate a true duality gap at each iteration; it tracks the cheap surrogate gap, and the axis is labeled accordingly. Pass ax to combine with plot_feasibility on a shared figure.

Parameters:

ax (Axes | None) – Axes to draw on; None creates a new figure.

Returns:

ax – The axes drawn on.

Return type:

Axes

plot_feasibility(ax=None)[source]#

Plot the feasibility residual against the iteration.

At each iteration the residual is

r_feas = sqrt(‖r_pri‖^2 + ‖r_dual‖^2),

the primal and dual parts of the KKT residual, excluding the centrality term (Boyd and Vandenberghe, 2004, section 11.7). Pass ax to combine with plot_convergence on a shared figure.

Parameters:

ax (Axes | None) – Axes to draw on; None creates a new figure.

Returns:

ax – The axes drawn on.

Return type:

Axes

Raises:

ValueError – When primal_residual_norms and dual_residual_norms differ in length (raised by zip(..., strict=True)).

References

Boyd, Stephen and Vandenberghe, Lieven, Convex Optimization, Cambridge University Press, 2004.

class cvxium.problems.result.HsdDiagnostics(duality_gaps=(), tau_history=(), kappa_history=())[source]#

Bases: SolverDiagnostics

Homogeneous self-dual trajectories, one entry per outer iteration.

There is no step-length trajectory: the step length is chosen inside the inner cone driver and is not surfaced here. An always-empty field would read as “the solver took no steps” rather than “this solver does not report them”.

Fields:
  • duality_gaps (tuple[float, …]) – Normalized complementarity gap μ of the embedding at each iteration.

  • tau_history (tuple[float, …]) – Homogenizing variable τ at each iteration.

  • kappa_history (tuple[float, …]) – Homogenizing variable κ at each iteration.

iteration_count()[source]#

Return the number of outer homogeneous self-dual iterations.

Returns:

n – The length of duality_gaps.

Return type:

int

to_dict()[source]#

Serialize the homogeneous self-dual trajectories to a JSON-ready dict.

Returns:

d – The fields as lists, tagged "HsdDiagnostics".

Return type:

dict[str, Any]

plot_convergence(ax=None)[source]#

Plot the embedding’s duality gap μ per iteration on a log scale.

Parameters:

ax (Axes | None) – Axes to draw on; None creates a new figure.

Returns:

ax – The axes drawn on.

Return type:

Axes

plot_homogeneity(ax=None)[source]#

Plot the homogenizing variables τ and κ per iteration on a log scale.

In the homogeneous self-dual embedding, τ > 0 at convergence recovers the original optimum, while τ → 0 with κ bounded away from zero certifies infeasibility or unboundedness; τ κ → 0 is the embedding’s complementarity condition. Plotting both makes the termination regime visible at a glance.

The log scale silently omits nonpositive values. The solver terminates before τ or κ underflows to zero, so in practice every stored value is positive and the infeasibility regime stays visible.

Parameters:

ax (Axes | None) – Axes to draw on; None creates a new figure.

Returns:

ax – The axes drawn on.

Return type:

Axes

Raises:

ValueError – When tau_history and kappa_history differ in length.

class cvxium.problems.result.ObjectiveOutcome(value, suboptimality, dual_value=None)[source]#

Bases: object

Objective part of a result, present exactly when the problem had an objective.

Fields:
  • value (float) – Objective value at the solution.

  • suboptimality (float) – Bound on the achieved suboptimality, a nonnegative magnitude.

  • dual_value (float | None) – Value of the Lagrangian dual at the solution, or None when the solver did not compute one.

to_dict()[source]#

Serialize to a JSON-ready dict.

Returns:

d – The three fields.

Return type:

dict[str, Any]

static from_dict(d)[source]#

Reconstruct an outcome from a dict produced by to_dict.

Parameters:

d (dict[str, Any]) – The serialized outcome.

Returns:

outcome – The reconstructed outcome.

Return type:

ObjectiveOutcome

Raises:

KeyError – When an entry is missing.

property duality_gap#

Return the gap between the objective value and its dual bound, if known.

Reported as a magnitude so that it reads the same in both optimization senses: for a minimization value lies above the lower bound dual_value, while for a maximization (see negated) it lies below the upper bound. For a minimization, where weak duality forces value ≥ dual_value, the gap equals value - dual_value.

Returns:

gap – |value - dual_value|, or None when dual_value is None.

Return type:

float | None

negated()[source]#

Return this outcome viewed from the opposite optimization sense.

The solvers only minimize; Problem.maximize(g) has them minimize -g, so value and dual_value describe that minimization. Negating both recovers the maximization view: value becomes g(x_star) and dual_value the corresponding upper bound on g. suboptimality is a nonnegative magnitude and does not depend on the sense, so it carries over unchanged, as does duality_gap.

Returns:

outcome – The outcome with value and dual_value negated.

Return type:

ObjectiveOutcome

class cvxium.problems.result.Duals(equality_multipliers=None, inequality_multipliers=None)[source]#

Bases: object

Lagrange multipliers, each present exactly when the problem had such constraints.

Fields:
  • equality_multipliers (npt.NDArray[np.float64] | None) – Multipliers ν of the equality constraints A x = b, or None.

  • inequality_multipliers (npt.NDArray[np.float64] | None) – Multipliers λ of the inequality constraints, or None.

to_dict()[source]#

Serialize the multipliers to a JSON-ready dict.

Returns:

d – The multipliers as lists, or None where absent.

Return type:

dict[str, Any]

static from_dict(d)[source]#

Reconstruct the multipliers from a dict produced by to_dict.

Parameters:

d (dict[str, Any]) – The serialized multipliers.

Returns:

duals – The reconstructed multipliers.

Return type:

Duals

Raises:

KeyError – When an entry is missing.

class cvxium.problems.result.InfeasibilityCertificate(kind, primal_witness=None, dual_witness=None)[source]#

Bases: object

Witness that a problem is infeasible or unbounded.

Fields:
  • kind (Literal[“infeasible”, “unbounded”]) – What the certificate proves.

  • primal_witness (npt.NDArray[np.float64] | None) – Primal vector supporting the certificate, or None.

  • dual_witness (npt.NDArray[np.float64] | None) – Dual vector supporting the certificate, or None.

to_dict()[source]#

Serialize the certificate to a JSON-ready dict.

Returns:

d – The kind and the witnesses as lists, or None where absent.

Return type:

dict[str, Any]

static from_dict(d)[source]#

Reconstruct a certificate from a dict produced by to_dict.

Parameters:

d (dict[str, Any]) – The serialized certificate.

Returns:

certificate – The reconstructed certificate.

Return type:

InfeasibilityCertificate

Raises:
  • ValueError – When kind is neither "infeasible" nor "unbounded".

  • KeyError – When an entry is missing.

class cvxium.problems.result.SolveResult(solution, status, message, solver, n_iterations, objective=None, duals=None, diagnostics=None, certificate=None, phase1=None)[source]#

Bases: object

Result of a solve.

The spine fields are always present. objective and duals are present according to the problem’s shape, diagnostics according to the solver, certificate only when the solve certified infeasibility or unboundedness, and phase1 only when a Phase I feasibility solve ran. The accessors (objective_value, dual_value, equality_multipliers, the typed diagnostics views, and so on) raise a specific error when the part they read is absent.

Fields:
  • solution (npt.NDArray[np.float64]) – The final iterate.

  • status (SolveStatus) – Outcome of the solve.

  • message (str) – Human-readable description of the outcome.

  • solver (str) – Name of the solver that ran.

  • n_iterations (int) – Iteration count reported by the solver.

  • objective (ObjectiveOutcome | None) – Objective part; None for a feasibility problem.

  • duals (Duals | None) – Lagrange multipliers; None when the problem had no constraints or the solver did not report them.

  • diagnostics (SolverDiagnostics | None) – Solver-method trajectories, whose type names the solver.

  • certificate (InfeasibilityCertificate | None) – Certificate of infeasibility or unboundedness, when one was found.

  • phase1 (SolveResult | None) – Result of the Phase I feasibility solve, when one ran.

to_dict()[source]#

Serialize to a JSON-ready dict tagged with the concrete type.

The parts (objective, duals, diagnostics, certificate) and the nested phase1 result are serialized in place. Each absent part is kept as None, so its absence, itself information, survives the round trip.

Returns:

d – The serialized result, tagged "SolveResult".

Return type:

dict[str, Any]

static from_dict(d)[source]#

Reconstruct the tagged SolveResult class from to_dict output.

Dispatches on the "__type__" tag to SolveResult or TwoBlockSolveResult, reconstructing each part and the nested phase1 result.

Parameters:

d (dict[str, Any]) – A dict produced by to_dict.

Returns:

result – The reconstructed result, of the tagged class.

Return type:

SolveResult

Raises:
  • ValueError – When the tag names no known result class or status is not a SolveStatus value. Also propagated from the parts’ from_dict methods and from TwoBlockSolveResult validation.

  • KeyError – When a required entry is missing.

serialize()[source]#

Serialize the result to a JSON string.

±inf deferrals in the diagnostics are encoded under json’s default allow_nan=True and round-trip through deserialize.

Returns:

s – The JSON text, indented by 2.

Return type:

str

static deserialize(s)[source]#

Reconstruct a result from serialize output.

Parameters:

s (str) – JSON text produced by serialize.

Returns:

result – The reconstructed result, of the tagged class.

Return type:

SolveResult

Raises:
  • ValueError – Propagated from from_dict; also raised by json.loads for malformed text.

  • KeyError – Propagated from from_dict.

property succeeded#

Check whether the solve reached a usable optimal or feasible point.

Returns:

ok – True when status is OPTIMAL, ACCEPTABLE or FEASIBLE.

Return type:

bool

property barrier_diagnostics#

Return the diagnostics, narrowed to the barrier engine.

A typed view of diagnostics for the caller that reads the barrier convergence trajectories. It raises rather than returning a wrongly typed value, so misuse fails loudly even under python -O. A saddle barrier solve’s diagnostics also qualify.

Returns:

diagnostics – The diagnostics part.

Return type:

BarrierDiagnostics

Raises:

WrongDiagnosticsError – When diagnostics is not a BarrierDiagnostics.

property saddle_barrier_diagnostics#

Return the diagnostics, narrowed to the two-block saddle barrier engine.

A typed view of diagnostics for the caller that reads the saddle value bracket (upper_bounds and lower_bounds). It raises rather than returning a wrongly typed value, so misuse fails loudly.

Returns:

diagnostics – The diagnostics part.

Return type:

SaddleBarrierDiagnostics

Raises:

WrongDiagnosticsError – When diagnostics is not a SaddleBarrierDiagnostics.

property primal_dual_diagnostics#

Return the diagnostics, narrowed to the primal-dual engine.

Returns:

diagnostics – The diagnostics part.

Return type:

PrimalDualDiagnostics

Raises:

WrongDiagnosticsError – When diagnostics is not a PrimalDualDiagnostics.

property hsd_diagnostics#

Return the diagnostics, narrowed to the homogeneous self-dual engine.

Returns:

diagnostics – The diagnostics part.

Return type:

HsdDiagnostics

Raises:

WrongDiagnosticsError – When diagnostics is not an HsdDiagnostics.

property objective_value#

Return the objective value at the solution.

Returns:

value – objective.value.

Return type:

float

Raises:

NoObjectiveError – When the result has no objective part (a feasibility solve).

property suboptimality#

Return the achieved suboptimality bound at the solution.

Returns:

suboptimality – objective.suboptimality.

Return type:

float

Raises:

NoObjectiveError – When the result has no objective part (a feasibility solve).

property dual_value#

Return the value of the Lagrangian dual at the solution.

Returns:

dual_value – objective.dual_value.

Return type:

float

Raises:
property equality_multipliers#

Return the Lagrange multipliers of the equality constraints.

Returns:

nu – duals.equality_multipliers.

Return type:

npt.NDArray[np.float64]

Raises:

NoDualsError – When the result has no duals part, or the problem had no equality constraints.

property inequality_multipliers#

Return the Lagrange multipliers of the inequality constraints.

Returns:

lmbda – duals.inequality_multipliers.

Return type:

npt.NDArray[np.float64]

Raises:

NoDualsError – When the result has no duals part, or the problem had no inequality constraints.

class cvxium.problems.result.TwoBlockSolveResult(solution, status, message, solver, n_iterations, objective=None, duals=None, diagnostics=None, certificate=None, phase1=None, x_dimension=0)[source]#

Bases: SolveResult

Result of a solve whose primal splits into an x-block and a y-block.

A saddle-point (two-block stationarity) solve produces two coupled variables, an x-block and a y-block, rather than a single primal vector. This class keeps the spine’s solution as the flat concatenation (x, y), so every generic SolveResult consumer works unchanged, and adds x and y views that split it at x_dimension. Both saddle engines (stationarity_solver and primal_dual_stationarity_solver) return this type; which one ran is recorded in diagnostics, as for ordinary solves. Build one with from_blocks. The fields of SolveResult are inherited; the new field is below.

Fields:

x_dimension (int) – Length of the x-block. Must lie in [0, len(solution)], or construction raises ValueError.

to_dict()[source]#

Serialize to a JSON-ready dict, adding the block split point.

Reuses SolveResult.to_dict and retags the concrete type, so that SolveResult.from_dict routes back to this class.

Returns:

d – The serialized result, tagged "TwoBlockSolveResult", with x_dimension.

Return type:

dict[str, Any]

property x#

Return the x-block of the solution.

Returns:

x – The first x_dimension entries of solution (a view, not a copy).

Return type:

npt.NDArray[np.float64]

property y#

Return the y-block of the solution.

Returns:

y – The entries of solution after the first x_dimension (a view, not a copy).

Return type:

npt.NDArray[np.float64]

classmethod from_blocks(*, x, y, status, message, solver, n_iterations, objective=None, duals=None, diagnostics=None)[source]#

Build a two-block result from its x- and y-blocks.

Concatenates the blocks into the flat solution and records the split point in x_dimension, so that x and y recover them. The certificate and phase1 parts are left None.

Parameters:
  • x (npt.NDArray[np.float64]) – The x-block, converted to float64.

  • y (npt.NDArray[np.float64]) – The y-block, converted to float64.

  • status (SolveStatus) – Outcome of the solve.

  • message (str) – Human-readable description of the outcome.

  • solver (str) – Name of the solver that ran.

  • n_iterations (int) – Iteration count reported by the solver.

  • objective (ObjectiveOutcome | None) – Objective part, or None.

  • duals (Duals | None) – Lagrange multipliers, or None.

  • diagnostics (SolverDiagnostics | None) – Solver-method trajectories, or None.

Returns:

result – The assembled result.

Return type:

TwoBlockSolveResult