Logging and Tracing#
Traces#
Pluggable sinks for the structured events that Cvxium solvers emit.
A Trace receives the events a solver reports while it runs: the equality solver’s
feasible-point computation, the barrier method’s Phase I outcome, centering steps,
Newton steps, dual evaluations and line searches, the two-block saddle solver’s Newton
steps, and the iterations of the homogeneous self-dual and primal-dual loops. Each event
is one on_* method, a no-op in the base class, so a subclass overrides only the
events it cares about. Solvers read the trace from OptimizationSettings.trace.
Three implementations are provided:
LoggingTrace, the default, writes each event as a log record on thecvxium.optimization,cvxium.linear_programs,cvxium.hsd_solverorcvxium.pd_solverlogger, with structuredcvx_fields thatIterationHandlercollects.ListTracecollects every event as a dict in memory, with no logging configuration.DataFrameTraceadds conversion of those dicts to a pandas DataFrame.
Two want_* methods let a trace tell the solver whether to compute diagnostics that
cost extra work and that only a consumer of the corresponding event needs.
- class cvxium.diagnostics.trace.Trace[source]#
Bases:
objectBase class for solver event traces.
Each
on_*method reports one solver event and does nothing by default; subclass and override the events to collect. The twowant_*methods return False by default, so the solver skips the extra work behindon_btlsand thert_newfield ofon_pd_iteration.LoggingTrace, the default value ofOptimizationSettings.trace, writes each event as a structured record on the appropriatecvxium.*logger, following the logging contract described in Cvxium’s USAGE.md (section 7).- on_feasible_initial_guess()[source]#
Report that the initial guess already satisfies the equality constraints.
Emitted by
EqualitySolverwhen the supplied x0 satisfies A x = b to within 1e-10 in every component, so it is returned unchanged.
- on_svd_done(elapsed_ms)[source]#
Report the time taken to compute an equality-feasible point.
Emitted by
EqualitySolverafter it computes a point satisfying A x = b. For a dense A the time covers the SVD of A and the projection that uses it; for a sparse A, which has no SVD path, the event is reused for the saddle-point projection.- Parameters:
elapsed_ms (float) – Wall-clock time of the computation, in milliseconds: the SVD of A and the projection that follows it, or, for a sparse A, the saddle-point projection, which forms no SVD.
- on_phase1_feasible(solver)[source]#
Report that Phase I returned a point already feasible for this solver.
Emitted by a barrier solver running in feasibility mode when the point from its nested Phase I solver already passes its own feasibility test, so its interior-point loop is skipped.
- Parameters:
solver (str) – Human-readable solver name: the label configured in the solver’s settings, or by default its class name.
- on_ipm_start(solver)[source]#
Report that the outer barrier loop is about to begin.
Emitted after Phase I, by the barrier method and by
StationaritySolver.- Parameters:
solver (str) – Human-readable solver name: the label configured in the solver’s settings, or by default its class name.
- on_centering_start(outer_nit, t)[source]#
Report that a centering step is starting.
Emitted by the barrier method and by
StationaritySolver.
- on_centering_done(outer_nit, elapsed_ms, duality_gap)[source]#
Report that a centering step has finished.
Emitted by the barrier method and by
StationaritySolver, which report different gaps (seeduality_gap). The barrier method’s per-step gap is not monotone, and it inflates when t is large even while the best-bounds certificate holds; the solve’s convergence test and its recorded duality gaps use that certificate instead.- Parameters:
outer_nit (int) – Outer (centering) iteration, 1-indexed.
elapsed_ms (float) – Wall-clock time of the centering step, in milliseconds.
duality_gap (float) – Duality gap at the centered iterate. The barrier method reports the per-step gap objective - dual at the returned iterate;
StationaritySolverreports the surrogate gap n_b / t, where n_b counts its barrier terms (0.0 when there are none).
- on_dual_eval_start(outer_nit)[source]#
Report that the per-centering Lagrange dual evaluation is starting.
The barrier method evaluates the dual once per centering step, itself a small Newton minimization of the Lagrangian (see
on_dual_newton_step); this event andon_dual_eval_donebracket it, so its cost can be compared with the Newton and line-search timings.- Parameters:
outer_nit (int) – Outer (centering) iteration, 1-indexed.
- on_dual_eval_done(outer_nit, elapsed_ms)[source]#
Report that the per-centering Lagrange dual evaluation has finished.
- on_early_stop(outer_nit)[source]#
Report that a solve is stopping before its outer loop runs to completion.
Emitted in three situations: a barrier Phase I solve finds a strictly feasible point; a primal-dual solver minimizing an objective with a feasibility threshold sees the value cross it; or a primal-dual solver’s stall detector stops and returns the best iterate seen. Distinct from
on_converged.- Parameters:
outer_nit (int) – Iteration at which the solve stopped, 1-indexed: the outer (centering) iteration of a barrier solve, or the iteration count of a primal-dual solve.
- on_converged(outer_nit, duality_gap)[source]#
Report that the outer loop met its gap tolerance and is stopping.
In the barrier method (optimization only, not Phase I), emitted when the best-bounds certificate, the best primal objective minus the best dual value seen so far, is within
outer.tolerancebefore the planned number of centering steps is exhausted. Stopping there keeps t out of the ill-conditioned large-t regime.StationaritySolveremits it when its surrogate gap meets its gap tolerance.
- on_ipm_done(solver, elapsed_ms)[source]#
Report that the outer barrier loop has finished.
Emitted by the barrier method and by
StationaritySolver.
- on_newton_step(outer_nit, inner_nit, elapsed_ms, suboptimality, lambda_norm, quadratic_convergence_threshold)[source]#
Report a completed Newton step of a barrier centering step.
Emitted once per inner iteration, after the Newton step is computed and before the line search.
- Parameters:
outer_nit (int) – Outer (centering) iteration, 1-indexed.
inner_nit (int) – Newton iteration within the centering step, 1-indexed.
elapsed_ms (float) – Wall-clock time to compute the Newton step, in milliseconds.
suboptimality (float) – Estimated suboptimality λ^2 / 2 of the iterate for the centering problem, where λ is the Newton decrement.
lambda_norm (float) – The Newton decrement λ at the start of the step.
quadratic_convergence_threshold (bool) – True only on the first inner step of the centering step whose Newton decrement satisfies λ ≤ η, where η = (1 - 2α) / 4 and α is the Armijo parameter: the step at which Newton’s method enters its quadratically convergent phase.
- on_saddle_newton_step(outer_nit, inner_nit, elapsed_ms, residual_norm, lambda_norm)[source]#
Report a completed Newton step of a two-block saddle centering step.
StationaritySolvercenters a coupled two-block saddle problem with an infeasible-start Newton step driven by the residual norm: a cap that keeps the iterate in the domain, then an Armijo backtrack on ‖r‖. It computes no Newton decrement, so this is a separate event fromon_newton_steprather than a reuse with an unused field. Emitted once per accepted step.- Parameters:
outer_nit (int) – Outer (centering) iteration, 1-indexed.
inner_nit (int) – Accepted inner step within the centering, 1-indexed.
elapsed_ms (float) – Wall-clock time of the step, including its line search, in milliseconds.
residual_norm (float) – ‖r(x, y, t, λ)‖_2, the norm of the residual the step drives toward zero, measured at the start of the step.
lambda_norm (float) – ‖λ‖_2, the norm of the equality multiplier after the step; 0.0 when the problem has no
x_equality.
- on_dual_newton_step(inner_nit, elapsed_ms, gradient_norm)[source]#
Report a completed Newton step of a Lagrange dual minimization.
Evaluating the dual means minimizing the Lagrangian over x, which the barrier method does with a few damped Newton steps. During the per-centering dual evaluation these steps fall between
on_dual_eval_startandon_dual_eval_done; other dual evaluations emit them too, as doesStationaritySolverwhen it minimizes a block Lagrangian to certify a bound on the saddle value.- Parameters:
inner_nit (int) – Step within the dual minimization, 1-indexed.
elapsed_ms (float) – Wall-clock time of the step, including its line search, in milliseconds.
gradient_norm (float) – ‖∇_x L‖, the norm of the Lagrangian gradient at the start of the step, the quantity the minimization drives toward zero.
- on_btls(outer_nit, inner_nit, btls_s, improvement, expected_improvement)[source]#
Report a completed backtracking line search.
Called by the barrier method after each line search, but only when
want_btls_detailsreturns True, since filling inimprovementcosts extra barrier-objective evaluations.- Parameters:
outer_nit (int) – Outer (centering) iteration, 1-indexed.
inner_nit (int) – Newton iteration within the centering step, 1-indexed.
btls_s (float) – The accepted step size s.
improvement (float) – Actual decrease of the barrier objective, f_t(x) - f_t(x + s Δx).
expected_improvement (float) – Reference decrease α β λ^2 / (1 + λ), where λ is the Newton decrement and α and β are the Armijo parameters.
- on_hsd_start(solver)[source]#
Report that the homogeneous self-dual loop is about to begin.
Emitted by
HsdSolverbefore its long-step path-following loop.- Parameters:
solver (str) – Human-readable solver name: the label configured in the solver’s settings, or by default its class name.
- on_hsd_iteration(nit, mu, rel_pres, rel_dres, tau, kappa, elapsed_ms)[source]#
Report a completed homogeneous self-dual iteration.
Emitted by
HsdSolverafter each iteration’s Newton step. The residual metrics are those measured at the top of the iteration, before the step, whiletauandkappaare post-step. An iteration that converges, or whose step fails at the cone boundary, ends the loop without emitting this event.- Parameters:
nit (int) – Iteration, 0-indexed within the loop.
mu (float) – Complementarity gap μ at the top of the iteration, before its Newton step.
rel_pres (float) – Relative primal residual ‖r_p‖ / (1 + ‖b‖) at the top of the iteration.
rel_dres (float) – Relative dual residual ‖r_d‖ / (1 + ‖c‖) at the top of the iteration.
tau (float) – Homogenizing variable τ after the step.
kappa (float) – Homogenizing variable κ after the step.
elapsed_ms (float) – Wall-clock time of the iteration, in milliseconds.
- on_hsd_done(solver, nits, status, elapsed_ms)[source]#
Report that the homogeneous self-dual loop has terminated.
- Parameters:
solver (str) – Human-readable solver name: the label configured in the solver’s settings, or by default its class name.
nits (int) – Number of iterations completed, each with one Newton step.
status (int) – Integer status code: 0 converged to the outer tolerance, 1 reached only the soft tolerance, 2 did not converge.
elapsed_ms (float) – Wall-clock time of the whole loop, in milliseconds.
- on_pd_start(solver, num_vars=None, num_ineq=None, tol=None)[source]#
Report that a primal-dual loop is about to begin.
PrimalDualSolver’s inequality-only (Mehrotra predictor-corrector) path and both paths ofPrimalDualStationaritySolversupply the problem dimensions and tolerance;PrimalDualSolver’s equality path does not.- Parameters:
solver (str) – Human-readable solver name: the label configured in the solver’s settings, or by default its class name.
num_vars (int | None) – Number of decision variables, when supplied.
num_ineq (int | None) – Number of inequality constraints, when supplied.
tol (float | None) – Outer convergence tolerance, when supplied.
- on_pd_iteration(nit, eta, dual_norm, pri_norm, residual_norm, t, step, elapsed_ms, sigma=None, rho=None, damping=0.0, cent_norm=None, rt_norm=None, dir_ms=None, rt_new=None)[source]#
Report a completed primal-dual iteration.
Emitted after each accepted step, with the residual metrics measured at the top of the iteration. An iteration that converges or stops breaks before taking a step and emits nothing, so the number of these events equals the number of accepted steps.
Which optional fields are populated depends on the path:
PrimalDualSolver’s inequality-only (Mehrotra predictor-corrector) path supplies all of them,rt_newonly whenwant_pd_step_detailsreturns True.PrimalDualStationaritySolversuppliessigmaonly.PrimalDualSolver’s equality path supplies none, leaving each at its default.
- Parameters:
nit (int) – Iteration, 0-indexed within the loop.
eta (float) – Surrogate duality gap η = -f^T λ at the top of the iteration.
dual_norm (float) – ‖r_dual‖_2, the dual (stationarity) residual norm at the top of the iteration.
pri_norm (float) – ‖A x - b‖_2, the equality residual norm; 0.0 when the problem has no equality constraints.
residual_norm (float) – The proxy sqrt(‖r_dual‖^2 + ‖A x - b‖^2 + η^2), kept for the result history.
t (float) – Surrogate barrier parameter μ m / η, where m counts the inequality constraints and μ is the barrier multiplier. The two-block solver omits μ and reports 0.0 when η ≤ 0.
step (float) – Step length actually taken.
elapsed_ms (float) – Wall-clock time of the iteration, in milliseconds.
sigma (float | None) – Mehrotra centering parameter (in the two-block solver, the mean of its two blocks’ values).
rho (float | None) – Ratio of the actual to the predicted residual reduction;
Nonewhen the step was undamped and the ratio test was skipped.damping (float) – Levenberg damping used for the accepted step.
cent_norm (float | None) – ‖r_cent‖_2, the centrality residual norm.
rt_norm (float | None) – ‖[r_dual; r_cent]‖_2, the KKT residual at barrier parameter t, before the step.
dir_ms (float | None) – Time to compute the search direction, in milliseconds.
rt_new (float | None) – The same KKT residual after the step, at the same t; computed only when
want_pd_step_detailsreturns True, otherwiseNone.
- want_pd_step_details()[source]#
Return whether primal-dual solvers should compute the post-step KKT residual.
Computing
rt_newforon_pd_iterationcosts one extra residual evaluation per iteration, soPrimalDualSolverskips it unless this returns True.LoggingTracereturns True exactly when thecvxium.pd_solverlogger is enabled at DEBUG; collectors that want the field, such asListTrace, return True.- Returns:
want – False here.
- Return type:
- on_pd_damping_engaged(nit, damping, retries)[source]#
Report that Levenberg damping had to grow to find a feasible step.
Emitted by
PrimalDualSolver’s inequality-only path, only on iterations where the damping had to be grown to recover a feasible step: the diagnostic signature of a nearly singular modified Hessian.
- on_pd_done(solver, nits, status, elapsed_ms, reason='', duality_gap=None)[source]#
Report that a primal-dual loop has terminated.
The per-iteration gap is the cheap surrogate η; the true dual is evaluated only once, at termination, and only on the path that reports
duality_gap.- Parameters:
solver (str) – Human-readable solver name: the label configured in the solver’s settings, or by default its class name.
nits (int) – Number of iterations started, including a final one that stopped without taking a step.
status (int) – Integer status code. 0 means converged; the meaning of 1 and 2 depends on the solver. For
PrimalDualSolver, 1 is a stall or the iteration cap, and 2 a feasibility stop or certified infeasibility. ForPrimalDualStationaritySolver, 1 is the iteration cap or another non-converged break, and 2 acceptance at the soft tolerance.elapsed_ms (float) – Wall-clock time of the whole loop, in milliseconds.
reason (str) – Human-readable termination cause; empty when the solver supplies none (as on
PrimalDualSolver’s equality path).duality_gap (float | None) – True duality gap objective - dual, evaluated once at termination. Supplied only by
PrimalDualSolver’s inequality-only path on a normal exit;Noneotherwise.
- want_btls_details()[source]#
Return whether barrier solvers should call
on_btls.Populating
improvementcosts two extraevaluate_barrier_objectivecalls per inner step, so the solver skips them, and theon_btlscall, when this returns False.LoggingTracereturns True exactly when thecvxium.optimizationlogger is enabled at DEBUG.- Returns:
want – False here.
- Return type:
- class cvxium.diagnostics.trace.LoggingTrace[source]#
Bases:
TraceDefault trace, writing each event as a structured
cvxium.*log record.Each record carries a human-readable message and, in
extra, structured fields named with acvx_prefix (always includingcvx_event), the schema thatIterationHandlerand the logging contract in USAGE.md rely on. The per-step events of the barrier and saddle solvers (on_newton_step,on_saddle_newton_step,on_dual_newton_stepandon_btls) log at DEBUG oncvxium.optimization; every other event logs at INFO. Thewant_*methods return True exactly when the logger that would show the extra detail is enabled at DEBUG.- on_feasible_initial_guess()[source]#
Log that the initial guess already satisfies the equality constraints.
Writes an INFO record on
cvxium.linear_programs.
- on_svd_done(elapsed_ms)[source]#
Log the time taken to compute an equality-feasible point.
Writes an INFO record on
cvxium.linear_programs.- Parameters:
elapsed_ms (float) – Wall-clock time of the computation, in milliseconds: the SVD of A and the projection that follows it, or, for a sparse A, the saddle-point projection, which forms no SVD.
- on_phase1_feasible(solver)[source]#
Log that Phase I returned a point already feasible for this solver.
Writes an INFO record on
cvxium.optimization.- Parameters:
solver (str) – Human-readable solver name: the label configured in the solver’s settings, or by default its class name.
- on_ipm_start(solver)[source]#
Log that the outer barrier loop is about to begin.
Writes an INFO record on
cvxium.optimization.- Parameters:
solver (str) – Human-readable solver name: the label configured in the solver’s settings, or by default its class name.
- on_centering_start(outer_nit, t)[source]#
Log that a centering step is starting.
Writes an INFO record on
cvxium.optimization.
- on_centering_done(outer_nit, elapsed_ms, duality_gap)[source]#
Log that a centering step has finished, with its duality gap.
Writes an INFO record on
cvxium.optimization.- Parameters:
outer_nit (int) – Outer (centering) iteration, 1-indexed.
elapsed_ms (float) – Wall-clock time of the centering step, in milliseconds.
duality_gap (float) – Duality gap at the centered iterate. The barrier method reports the per-step gap objective - dual at the returned iterate;
StationaritySolverreports the surrogate gap n_b / t, where n_b counts its barrier terms (0.0 when there are none).
- on_dual_eval_start(outer_nit)[source]#
Log that the per-centering Lagrange dual evaluation is starting.
Writes an INFO record on
cvxium.optimization.- Parameters:
outer_nit (int) – Outer (centering) iteration, 1-indexed.
- on_dual_eval_done(outer_nit, elapsed_ms)[source]#
Log that the per-centering Lagrange dual evaluation has finished.
Writes an INFO record on
cvxium.optimization.
- on_early_stop(outer_nit)[source]#
Log that a solve is stopping before its outer loop runs to completion.
Writes an INFO record on
cvxium.optimization, whichever solver emitted the event.- Parameters:
outer_nit (int) – Iteration at which the solve stopped, 1-indexed: the outer (centering) iteration of a barrier solve, or the iteration count of a primal-dual solve.
- on_converged(outer_nit, duality_gap)[source]#
Log that the outer loop met its gap tolerance and is stopping.
Writes an INFO record on
cvxium.optimization.
- on_ipm_done(solver, elapsed_ms)[source]#
Log that the outer barrier loop has finished.
Writes an INFO record on
cvxium.optimization.
- on_newton_step(outer_nit, inner_nit, elapsed_ms, suboptimality, lambda_norm, quadratic_convergence_threshold)[source]#
Log a completed Newton step of a barrier centering step.
Writes a DEBUG record on
cvxium.optimization. The message shows the decrement and flags the quadratic-convergence step;lambda_normand the flag are not among the structured fields.- Parameters:
outer_nit (int) – Outer (centering) iteration, 1-indexed.
inner_nit (int) – Newton iteration within the centering step, 1-indexed.
elapsed_ms (float) – Wall-clock time to compute the Newton step, in milliseconds.
suboptimality (float) – Estimated suboptimality λ^2 / 2 of the iterate for the centering problem, where λ is the Newton decrement.
lambda_norm (float) – The Newton decrement λ at the start of the step.
quadratic_convergence_threshold (bool) – True only on the first inner step of the centering step whose Newton decrement satisfies λ ≤ η, where η = (1 - 2α) / 4 and α is the Armijo parameter: the step at which Newton’s method enters its quadratically convergent phase.
- on_saddle_newton_step(outer_nit, inner_nit, elapsed_ms, residual_norm, lambda_norm)[source]#
Log a completed Newton step of a two-block saddle centering step.
Writes a DEBUG record on
cvxium.optimization.- Parameters:
outer_nit (int) – Outer (centering) iteration, 1-indexed.
inner_nit (int) – Accepted inner step within the centering, 1-indexed.
elapsed_ms (float) – Wall-clock time of the step, including its line search, in milliseconds.
residual_norm (float) – ‖r(x, y, t, λ)‖_2, the norm of the residual the step drives toward zero, measured at the start of the step.
lambda_norm (float) – ‖λ‖_2, the norm of the equality multiplier after the step; 0.0 when the problem has no
x_equality.
- on_dual_newton_step(inner_nit, elapsed_ms, gradient_norm)[source]#
Log a completed Newton step of a Lagrange dual minimization.
Writes a DEBUG record on
cvxium.optimization.- Parameters:
inner_nit (int) – Step within the dual minimization, 1-indexed.
elapsed_ms (float) – Wall-clock time of the step, including its line search, in milliseconds.
gradient_norm (float) – ‖∇_x L‖, the norm of the Lagrangian gradient at the start of the step, the quantity the minimization drives toward zero.
- on_btls(outer_nit, inner_nit, btls_s, improvement, expected_improvement)[source]#
Log a completed backtracking line search.
Writes a DEBUG record on
cvxium.optimization.- Parameters:
outer_nit (int) – Outer (centering) iteration, 1-indexed.
inner_nit (int) – Newton iteration within the centering step, 1-indexed.
btls_s (float) – The accepted step size s.
improvement (float) – Actual decrease of the barrier objective, f_t(x) - f_t(x + s Δx).
expected_improvement (float) – Reference decrease α β λ^2 / (1 + λ), where λ is the Newton decrement and α and β are the Armijo parameters.
- on_hsd_start(solver)[source]#
Log that the homogeneous self-dual loop is about to begin.
Writes an INFO record on
cvxium.hsd_solver.- Parameters:
solver (str) – Human-readable solver name: the label configured in the solver’s settings, or by default its class name.
- on_hsd_iteration(nit, mu, rel_pres, rel_dres, tau, kappa, elapsed_ms)[source]#
Log a completed homogeneous self-dual iteration.
Writes an INFO record on
cvxium.hsd_solver.tauandkappaappear only in the structured fields, not the message.- Parameters:
nit (int) – Iteration, 0-indexed within the loop.
mu (float) – Complementarity gap μ at the top of the iteration, before its Newton step.
rel_pres (float) – Relative primal residual ‖r_p‖ / (1 + ‖b‖) at the top of the iteration.
rel_dres (float) – Relative dual residual ‖r_d‖ / (1 + ‖c‖) at the top of the iteration.
tau (float) – Homogenizing variable τ after the step.
kappa (float) – Homogenizing variable κ after the step.
elapsed_ms (float) – Wall-clock time of the iteration, in milliseconds.
- on_hsd_done(solver, nits, status, elapsed_ms)[source]#
Log that the homogeneous self-dual loop has terminated.
Writes an INFO record on
cvxium.hsd_solver.- Parameters:
solver (str) – Human-readable solver name: the label configured in the solver’s settings, or by default its class name.
nits (int) – Number of iterations completed, each with one Newton step.
status (int) – Integer status code: 0 converged to the outer tolerance, 1 reached only the soft tolerance, 2 did not converge.
elapsed_ms (float) – Wall-clock time of the whole loop, in milliseconds.
- on_pd_start(solver, num_vars=None, num_ineq=None, tol=None)[source]#
Log that a primal-dual loop is about to begin.
Writes an INFO record on
cvxium.pd_solver; the message shows the dimensions and tolerance when they are supplied.- Parameters:
solver (str) – Human-readable solver name: the label configured in the solver’s settings, or by default its class name.
num_vars (int | None) – Number of decision variables, when supplied.
num_ineq (int | None) – Number of inequality constraints, when supplied.
tol (float | None) – Outer convergence tolerance, when supplied.
- on_pd_iteration(nit, eta, dual_norm, pri_norm, residual_norm, t, step, elapsed_ms, sigma=None, rho=None, damping=0.0, cent_norm=None, rt_norm=None, dir_ms=None, rt_new=None)[source]#
Log a completed primal-dual iteration in one of three formats.
Every format writes INFO records on
cvxium.pd_solver, and the first record of each carries all the arguments as structured fields. The format is chosen by what the caller supplied and by the logger’s level:No
rt_normorcent_norm: one compact line (_log_pd_iter_equality). This coversPrimalDualSolver’s equality path and alsoPrimalDualStationaritySolver, which suppliessigmabut no KKT residual breakdown.rt_normsupplied, logger not enabled at DEBUG: one summary line (_log_pd_iter_mpc_compact).rt_normsupplied, logger enabled at DEBUG: a header line and one line per quantity (_log_pd_iter_mpc_verbose).
The step length is printed in fixed point when it is at least 1e-3, and in scientific notation otherwise.
- Parameters:
nit (int) – Iteration, 0-indexed within the loop.
eta (float) – Surrogate duality gap η = -f^T λ at the top of the iteration.
dual_norm (float) – ‖r_dual‖_2, the dual (stationarity) residual norm at the top of the iteration.
pri_norm (float) – ‖A x - b‖_2, the equality residual norm; 0.0 when the problem has no equality constraints.
residual_norm (float) – The proxy sqrt(‖r_dual‖^2 + ‖A x - b‖^2 + η^2), kept for the result history.
t (float) – Surrogate barrier parameter μ m / η, where m counts the inequality constraints and μ is the barrier multiplier. The two-block solver omits μ and reports 0.0 when η ≤ 0.
step (float) – Step length actually taken.
elapsed_ms (float) – Wall-clock time of the iteration, in milliseconds.
sigma (float | None) – Mehrotra centering parameter (in the two-block solver, the mean of its two blocks’ values).
rho (float | None) – Ratio of the actual to the predicted residual reduction;
Nonewhen the step was undamped and the ratio test was skipped.damping (float) – Levenberg damping used for the accepted step.
cent_norm (float | None) – ‖r_cent‖_2, the centrality residual norm.
rt_norm (float | None) – ‖[r_dual; r_cent]‖_2, the KKT residual at barrier parameter t, before the step.
dir_ms (float | None) – Time to compute the search direction, in milliseconds.
rt_new (float | None) – The same KKT residual after the step, at the same t; computed only when
want_pd_step_detailsreturns True, otherwiseNone.
- want_pd_step_details()[source]#
Return whether the post-step KKT residual would be logged.
- Returns:
want – True exactly when the
cvxium.pd_solverlogger is enabled at DEBUG, the level at whichon_pd_iterationshowsrt_new.- Return type:
- on_pd_damping_engaged(nit, damping, retries)[source]#
Log that Levenberg damping had to grow to find a feasible step.
Writes an INFO record on
cvxium.pd_solver.
- on_pd_done(solver, nits, status, elapsed_ms, reason='', duality_gap=None)[source]#
Log that a primal-dual loop has terminated.
Writes an INFO record on
cvxium.pd_solver; the message appends the true duality gap and the reason when they are supplied.- Parameters:
solver (str) – Human-readable solver name: the label configured in the solver’s settings, or by default its class name.
nits (int) – Number of iterations started, including a final one that stopped without taking a step.
status (int) – Integer status code. 0 means converged; the meaning of 1 and 2 depends on the solver. For
PrimalDualSolver, 1 is a stall or the iteration cap, and 2 a feasibility stop or certified infeasibility. ForPrimalDualStationaritySolver, 1 is the iteration cap or another non-converged break, and 2 acceptance at the soft tolerance.elapsed_ms (float) – Wall-clock time of the whole loop, in milliseconds.
reason (str) – Human-readable termination cause; empty when the solver supplies none (as on
PrimalDualSolver’s equality path).duality_gap (float | None) – True duality gap objective - dual, evaluated once at termination. Supplied only by
PrimalDualSolver’s inequality-only path on a normal exit;Noneotherwise.
- class cvxium.diagnostics.trace.ListTrace[source]#
Bases:
TraceIn-memory trace that collects each event as a dict.
Needs no logging configuration, and records every argument of every hook, a superset of the structured fields that
IterationHandlerextracts fromLoggingTracerecords. Bothwant_*methods return True, so the solver computes the extra diagnostics on every step: two additionalevaluate_barrier_objectivecalls per barrier Newton step (to populateon_btls) and one additional KKT residual evaluation per primal-dual iteration (to populatert_new). That is not free in tight loops; preferLoggingTraceon performance-critical paths.Each row is a dict with an
eventkey naming the hook (its name without theon_prefix), a wall-clocktimein seconds since the epoch, and one key per argument of the hook, named as in the hook’s signature:feasible_initial_guess: no further keys.svd_done:elapsed_ms.phase1_feasible,ipm_start,hsd_start:solver.centering_start:outer_nit,t.centering_done:outer_nit,elapsed_ms,duality_gap.dual_eval_start,early_stop:outer_nit.dual_eval_done:outer_nit,elapsed_ms.converged:outer_nit,duality_gap.ipm_done:solver,elapsed_ms.newton_step:outer_nit,inner_nit,elapsed_ms,suboptimality,lambda_norm,quadratic_convergence_threshold.saddle_newton_step:outer_nit,inner_nit,elapsed_ms,residual_norm,lambda_norm.dual_newton_step:inner_nit,elapsed_ms,gradient_norm.btls:outer_nit,inner_nit,btls_s,improvement,expected_improvement.hsd_iteration:nit,mu,rel_pres,rel_dres,tau,kappa,elapsed_ms.hsd_done:solver,nits,status,elapsed_ms.pd_start:solver,num_vars,num_ineq,tol.pd_iteration:nit,eta,dual_norm,pri_norm,residual_norm,t,step,elapsed_ms,sigma,rho,damping,cent_norm,rt_norm,dir_ms,rt_new.pd_damping_engaged:nit,damping,retries.pd_done:solver,nits,status,elapsed_ms,reason,duality_gap.
Optional arguments the solver did not supply are recorded with their defaults (usually
None).- records()[source]#
Return the accumulated records as a list of dicts.
The outer list is a fresh copy, so appending to or reordering it does not affect the trace. The dicts inside are the objects the trace holds, so mutating one (for example,
trace.records()[0]["event"] = "X") changes the trace’s record too. Treat them as read-only, orcopy.deepcopythe result before mutating it.
- want_btls_details()[source]#
Return True, so that the solver calls
on_btlson every inner step.- Returns:
want – Always True.
- Return type:
- on_feasible_initial_guess()[source]#
Record that the initial guess already satisfies A x = b.
Appends a
feasible_initial_guessrow with no further keys.
- on_svd_done(elapsed_ms)[source]#
Record the time taken to compute an equality-feasible point.
Appends a
svd_donerow carrying each argument under its own name.- Parameters:
elapsed_ms (float) – Wall-clock time of the computation, in milliseconds: the SVD of A and the projection that follows it, or, for a sparse A, the saddle-point projection, which forms no SVD.
- on_phase1_feasible(solver)[source]#
Record that Phase I returned a point feasible for this solver.
Appends a
phase1_feasiblerow carrying each argument under its own name.- Parameters:
solver (str) – Human-readable solver name: the label configured in the solver’s settings, or by default its class name.
- on_ipm_start(solver)[source]#
Record that the outer barrier loop is about to begin.
Appends a
ipm_startrow carrying each argument under its own name.- Parameters:
solver (str) – Human-readable solver name: the label configured in the solver’s settings, or by default its class name.
- on_centering_start(outer_nit, t)[source]#
Record that a centering step is starting.
Appends a
centering_startrow carrying each argument under its own name.
- on_centering_done(outer_nit, elapsed_ms, duality_gap)[source]#
Record that a centering step has finished.
Appends a
centering_donerow carrying each argument under its own name.- Parameters:
outer_nit (int) – Outer (centering) iteration, 1-indexed.
elapsed_ms (float) – Wall-clock time of the centering step, in milliseconds.
duality_gap (float) – Duality gap at the centered iterate. The barrier method reports the per-step gap objective - dual at the returned iterate;
StationaritySolverreports the surrogate gap n_b / t, where n_b counts its barrier terms (0.0 when there are none).
- on_dual_eval_start(outer_nit)[source]#
Record that the per-centering dual evaluation is starting.
Appends a
dual_eval_startrow carrying each argument under its own name.- Parameters:
outer_nit (int) – Outer (centering) iteration, 1-indexed.
- on_dual_eval_done(outer_nit, elapsed_ms)[source]#
Record that the per-centering dual evaluation has finished.
Appends a
dual_eval_donerow carrying each argument under its own name.
- on_early_stop(outer_nit)[source]#
Record that a solve is stopping before its outer loop completes.
Appends a
early_stoprow carrying each argument under its own name.- Parameters:
outer_nit (int) – Iteration at which the solve stopped, 1-indexed: the outer (centering) iteration of a barrier solve, or the iteration count of a primal-dual solve.
- on_converged(outer_nit, duality_gap)[source]#
Record that the outer loop met its gap tolerance.
Appends a
convergedrow carrying each argument under its own name.
- on_ipm_done(solver, elapsed_ms)[source]#
Record that the outer barrier loop has finished.
Appends a
ipm_donerow carrying each argument under its own name.
- on_newton_step(outer_nit, inner_nit, elapsed_ms, suboptimality, lambda_norm, quadratic_convergence_threshold)[source]#
Record a completed Newton step of a barrier centering step.
Appends a
newton_steprow carrying each argument under its own name.- Parameters:
outer_nit (int) – Outer (centering) iteration, 1-indexed.
inner_nit (int) – Newton iteration within the centering step, 1-indexed.
elapsed_ms (float) – Wall-clock time to compute the Newton step, in milliseconds.
suboptimality (float) – Estimated suboptimality λ^2 / 2 of the iterate for the centering problem, where λ is the Newton decrement.
lambda_norm (float) – The Newton decrement λ at the start of the step.
quadratic_convergence_threshold (bool) – True only on the first inner step of the centering step whose Newton decrement satisfies λ ≤ η, where η = (1 - 2α) / 4 and α is the Armijo parameter: the step at which Newton’s method enters its quadratically convergent phase.
- on_saddle_newton_step(outer_nit, inner_nit, elapsed_ms, residual_norm, lambda_norm)[source]#
Record a completed Newton step of a saddle centering step.
Appends a
saddle_newton_steprow carrying each argument under its own name.- Parameters:
outer_nit (int) – Outer (centering) iteration, 1-indexed.
inner_nit (int) – Accepted inner step within the centering, 1-indexed.
elapsed_ms (float) – Wall-clock time of the step, including its line search, in milliseconds.
residual_norm (float) – ‖r(x, y, t, λ)‖_2, the norm of the residual the step drives toward zero, measured at the start of the step.
lambda_norm (float) – ‖λ‖_2, the norm of the equality multiplier after the step; 0.0 when the problem has no
x_equality.
- on_dual_newton_step(inner_nit, elapsed_ms, gradient_norm)[source]#
Record a completed Newton step of a dual minimization.
Appends a
dual_newton_steprow carrying each argument under its own name.- Parameters:
inner_nit (int) – Step within the dual minimization, 1-indexed.
elapsed_ms (float) – Wall-clock time of the step, including its line search, in milliseconds.
gradient_norm (float) – ‖∇_x L‖, the norm of the Lagrangian gradient at the start of the step, the quantity the minimization drives toward zero.
- on_btls(outer_nit, inner_nit, btls_s, improvement, expected_improvement)[source]#
Record a completed backtracking line search.
Appends a
btlsrow carrying each argument under its own name.- Parameters:
outer_nit (int) – Outer (centering) iteration, 1-indexed.
inner_nit (int) – Newton iteration within the centering step, 1-indexed.
btls_s (float) – The accepted step size s.
improvement (float) – Actual decrease of the barrier objective, f_t(x) - f_t(x + s Δx).
expected_improvement (float) – Reference decrease α β λ^2 / (1 + λ), where λ is the Newton decrement and α and β are the Armijo parameters.
- on_hsd_start(solver)[source]#
Record that the homogeneous self-dual loop is about to begin.
Appends a
hsd_startrow carrying each argument under its own name.- Parameters:
solver (str) – Human-readable solver name: the label configured in the solver’s settings, or by default its class name.
- on_hsd_iteration(nit, mu, rel_pres, rel_dres, tau, kappa, elapsed_ms)[source]#
Record a completed homogeneous self-dual iteration.
Appends a
hsd_iterationrow carrying each argument under its own name.- Parameters:
nit (int) – Iteration, 0-indexed within the loop.
mu (float) – Complementarity gap μ at the top of the iteration, before its Newton step.
rel_pres (float) – Relative primal residual ‖r_p‖ / (1 + ‖b‖) at the top of the iteration.
rel_dres (float) – Relative dual residual ‖r_d‖ / (1 + ‖c‖) at the top of the iteration.
tau (float) – Homogenizing variable τ after the step.
kappa (float) – Homogenizing variable κ after the step.
elapsed_ms (float) – Wall-clock time of the iteration, in milliseconds.
- on_hsd_done(solver, nits, status, elapsed_ms)[source]#
Record that the homogeneous self-dual loop has terminated.
Appends a
hsd_donerow carrying each argument under its own name.- Parameters:
solver (str) – Human-readable solver name: the label configured in the solver’s settings, or by default its class name.
nits (int) – Number of iterations completed, each with one Newton step.
status (int) – Integer status code: 0 converged to the outer tolerance, 1 reached only the soft tolerance, 2 did not converge.
elapsed_ms (float) – Wall-clock time of the whole loop, in milliseconds.
- on_pd_start(solver, num_vars=None, num_ineq=None, tol=None)[source]#
Record that a primal-dual loop is about to begin.
Appends a
pd_startrow carrying each argument under its own name.- Parameters:
solver (str) – Human-readable solver name: the label configured in the solver’s settings, or by default its class name.
num_vars (int | None) – Number of decision variables, when supplied.
num_ineq (int | None) – Number of inequality constraints, when supplied.
tol (float | None) – Outer convergence tolerance, when supplied.
- on_pd_iteration(nit, eta, dual_norm, pri_norm, residual_norm, t, step, elapsed_ms, sigma=None, rho=None, damping=0.0, cent_norm=None, rt_norm=None, dir_ms=None, rt_new=None)[source]#
Record a completed primal-dual iteration.
Appends a
pd_iterationrow carrying each argument under its own name.- Parameters:
nit (int) – Iteration, 0-indexed within the loop.
eta (float) – Surrogate duality gap η = -f^T λ at the top of the iteration.
dual_norm (float) – ‖r_dual‖_2, the dual (stationarity) residual norm at the top of the iteration.
pri_norm (float) – ‖A x - b‖_2, the equality residual norm; 0.0 when the problem has no equality constraints.
residual_norm (float) – The proxy sqrt(‖r_dual‖^2 + ‖A x - b‖^2 + η^2), kept for the result history.
t (float) – Surrogate barrier parameter μ m / η, where m counts the inequality constraints and μ is the barrier multiplier. The two-block solver omits μ and reports 0.0 when η ≤ 0.
step (float) – Step length actually taken.
elapsed_ms (float) – Wall-clock time of the iteration, in milliseconds.
sigma (float | None) – Mehrotra centering parameter (in the two-block solver, the mean of its two blocks’ values).
rho (float | None) – Ratio of the actual to the predicted residual reduction;
Nonewhen the step was undamped and the ratio test was skipped.damping (float) – Levenberg damping used for the accepted step.
cent_norm (float | None) – ‖r_cent‖_2, the centrality residual norm.
rt_norm (float | None) – ‖[r_dual; r_cent]‖_2, the KKT residual at barrier parameter t, before the step.
dir_ms (float | None) – Time to compute the search direction, in milliseconds.
rt_new (float | None) – The same KKT residual after the step, at the same t; computed only when
want_pd_step_detailsreturns True, otherwiseNone.
- want_pd_step_details()[source]#
Return True, so that primal-dual solvers compute the post-step residual.
- Returns:
want – Always True.
- Return type:
- on_pd_damping_engaged(nit, damping, retries)[source]#
Record that Levenberg damping had to grow.
Appends a
pd_damping_engagedrow carrying each argument under its own name.
- on_pd_done(solver, nits, status, elapsed_ms, reason='', duality_gap=None)[source]#
Record that a primal-dual loop has terminated.
Appends a
pd_donerow carrying each argument under its own name.- Parameters:
solver (str) – Human-readable solver name: the label configured in the solver’s settings, or by default its class name.
nits (int) – Number of iterations started, including a final one that stopped without taking a step.
status (int) – Integer status code. 0 means converged; the meaning of 1 and 2 depends on the solver. For
PrimalDualSolver, 1 is a stall or the iteration cap, and 2 a feasibility stop or certified infeasibility. ForPrimalDualStationaritySolver, 1 is the iteration cap or another non-converged break, and 2 acceptance at the soft tolerance.elapsed_ms (float) – Wall-clock time of the whole loop, in milliseconds.
reason (str) – Human-readable termination cause; empty when the solver supplies none (as on
PrimalDualSolver’s equality path).duality_gap (float | None) – True duality gap objective - dual, evaluated once at termination. Supplied only by
PrimalDualSolver’s inequality-only path on a normal exit;Noneotherwise.
- class cvxium.diagnostics.trace.DataFrameTrace[source]#
Bases:
ListTraceList trace that converts its records to a pandas DataFrame.
Adds
to_dataframe, which gives one row per event with sparse columns (NaNwhere an event does not carry a field), likeIterationHandler.to_dataframe. pandas is needed only whento_dataframeis called, not at construction.- to_dataframe()[source]#
Convert the accumulated records to a pandas DataFrame.
Requires pandas, which Cvxium does not otherwise depend on; it is imported only here.
- Returns:
df – One row per recorded event. Columns are the union of the keys across records:
timeandeventalways, plus the event fields listed inListTrace, such asouter_nit,inner_nit,elapsed_ms,suboptimality,t,btls_sandsolver. A column with no data for a given event holdsNaNin that row.- Return type:
pd.DataFrame
- Raises:
ImportError – When pandas is not installed.
Logging Handlers#
Logging handlers and log configuration for Cvxium solvers.
Cvxium solvers narrate their progress through the standard logging module, attaching
structured fields (named with a cvx_ prefix) to each record. This module provides
two ways to consume that output. IterationHandler collects the structured fields
into a list of dicts, or a pandas DataFrame, for analysis after a solve.
enable_logging routes one or more logger namespaces to a single file or stderr
handler, replacing the usual handler boilerplate and making repeated calls idempotent.
- class cvxium.diagnostics.handlers.IterationHandler(level=0)[source]#
Bases:
HandlerLogging handler that accumulates per-iteration solver events.
Captures the structured data that Cvxium solvers attach to their log records into a list of dicts, one per record. Each dict holds the record’s creation time and message, plus every recognized
cvx_field present on the record, keyed without the prefix: the event type, the solver, iteration counters, timing, and the numerical diagnostics of that event. Callto_dataframefor a pandas DataFrame (requires pandas), orrecordsfor the raw list of dicts.- Parameters:
level (int) – Threshold passed to
logging.Handler; records below it are ignored.
Examples
Attach before solving, then inspect afterwards:
import logging from cvxium import IterationHandler handler = IterationHandler() logging.getLogger("cvxium").addHandler(handler) logging.getLogger("cvxium").setLevel(logging.DEBUG) solver.solve() df = handler.to_dataframe() # df has columns: time, message, event, outer_nit, inner_nit, elapsed_ms, ...
- emit(record)[source]#
Store one log record as a dict.
The dict holds the record’s creation time (
time) and formatted message (message), plus each field of_CVX_FIELDSthat the record carries with a value other thanNone, keyed without itscvx_prefix. Fields not listed in_CVX_FIELDSare dropped.- Parameters:
record (logging.LogRecord) – The record to store.
- to_dataframe()[source]#
Convert the accumulated records to a pandas DataFrame.
Requires pandas, which Cvxium does not otherwise depend on; it is imported only here.
- Returns:
df – One row per log record. Columns are the union of the keys across records:
timeandmessagealways, plus fields such asevent,solver,outer_nit,inner_nit,elapsed_ms,suboptimality,t,btls_s,improvement, andexpected_improvement. A column with no data for a given event type holdsNaNin that row.- Return type:
pd.DataFrame
- Raises:
ImportError – When pandas is not installed.
- cvxium.diagnostics.handlers.enable_logging(path=None, level=20, namespaces=('cvxium',), mode='w')[source]#
Send one or more logger namespaces to a single handler.
Replaces a dozen lines of handler boilerplate. The part worth centralizing is not the file handler but setting
propagatetoFalseand resetting the handlers: the first stops records from also reaching the root logger (which would duplicate every line in a notebook), and the second makes calling this twice idempotent rather than cumulative.When more than one namespace is passed, sharing one handler across them is the point. They are separate logger trees, so the only thing putting their records in order is that they arrive at the same place: the log is then chronological, and a solver’s iterations sit underneath the line naming the problem being solved.
- Parameters:
path (str | os.PathLike[str] | None) – Log file;
~is expanded.Nonelogs to stderr instead, which suits a terminal but not a notebook.level (int) – Threshold for both the handler and each namespace.
logging.INFOgives the narration;logging.DEBUGadds per-iteration solver detail, which runs to thousands of lines on a large problem. Set unconditionally on every call, unlike theNOTSET-guarded default in__init__.py. That guard exists so a level set before import survives it; here the caller is asking for exactly this level, so a level from an earlier call does not survive a later one that omitslevel.namespaces (Sequence[str]) – Logger names to attach to. Defaults to Cvxium alone; a library built on Cvxium passes its own name alongside the ones it depends on. Repeated names are dropped, keeping the first occurrence. Must not be a bare
str, which satisfiesSequence[str]but would iterate character by character; the function raisesTypeErrorfor one.mode (str) – File mode.
"w"truncates on each call, usually what is wanted when the question is what happened this time;"a"appends. Must be left at"w"whenpathisNone, since stderr has no file mode; any other value raisesValueError.
- Returns:
handler – The attached handler, a
logging.FileHandlerorlogging.StreamHandler, for a caller that wants to remove it again.- Return type:
- Raises:
TypeError – When
namespacesis a barestrrather than a sequence of names.ValueError – When
modeis not"w"whilepathisNone.OSError – Propagated from
logging.FileHandlerwhenpathcannot be opened. It is raised before any logger is touched, so the previous configuration stays intact.
Notes
Each call proceeds in three steps:
Build the new handler, before tearing anything down, so that a bad path leaves the previous configuration in place.
Detach (see
_detach) each namespace that the previous call configured and this call omits. Its handler is shared with namespaces that are in this call and is about to be closed, so leaving it attached would send the namespace’s next record to a closed handler.For each namespace in this call, close and remove every existing handler (including one this module attached earlier, and the placeholder
NullHandlerthat__init__.pyputs oncvxium), setpropagatetoFalse, set the level, and attach the new handler.
Examples
Narration only, to a file:
Cvxium.enable_logging("~/cvxium.log")
Every inner iteration, which runs to thousands of lines:
Cvxium.enable_logging("~/cvxium.log", level=logging.DEBUG)