We test curvature of the Lagrangian, rather than the objective alone. Assume , and are near the point being tested. Use , unrestricted equality multipliers, nonnegative inequality multipliers, and row Jacobians. The KKT reference owns the active/strong/weak definitions; the constraint-qualification reference owns feasible paths and tangent versus linearized cones. This page develops the second-order proofs and computational tests used in Lecture 21.
# This code cell installs packages on Colab
import sys
if "google.colab" in sys.modules:
!wget "https://raw.githubusercontent.com/ndcbe/optimization/main/notebooks/helper.py"
import helper
helper.easy_install()
else:
sys.path.insert(0, "../")
import helper
helper.set_plotting_style()Helpful Cones¶
Linearized and critical directions¶
On open , use C maps , , . At a feasible KKT point , write for active inequality indices, split into (positive multiplier) and (zero multiplier) for the chosen KKT vector. Combined active labels are tagged and ; equality 1 and inequality 1 are different constraints. With derivatives evaluated at the point,
At a KKT point, . Indeed stationarity gives . Each term is nonnegative; equality to zero forces wherever . Weakly active inequalities retain their one-sided restrictions. Biegler (2010), p. 79; Nocedal and Wright (2006), (12.53), p. 330.
Under LICQ, equals the tangent cone, including zero and arbitrary scales. Unit limiting directions are its unit section, as explained in the qualification reference. Neither nor need be a linear subspace.

Subspaces that bracket the critical cone¶

For , , , the origin has . The panels then show a quadrant (), a ray (), just zero (), and a line (). Holding more independent rows at equality makes a smaller subspace.
is contained in . Under LICQ the column counts are and ; without full row rank use . A nonempty weak set adds independent rows under LICQ, but strict complementarity makes the two row sets identical. Their null spaces coincide; separately computed bases need not be numerically identical.
Second Order Necessary Conditions¶
Complete necessary-condition proof¶
For data, a local minimum satisfying LICQ has unique KKT multipliers and obeys
This is Biegler’s Theorem 4.17, p. 80 (apply the errata), and Nocedal–Wright’s Theorem 12.5, p. 332.
Complete proof. Fix . LICQ and the feasible-path construction give with and each active inequality exactly . A strongly active inequality has zero directional derivative; weakly active and inactive constraints have zero multiplier. Thus exactly. Stationarity eliminates the linear Taylor term, so
A negative quadratic coefficient dominates the remainder for sufficiently small positive and contradicts local minimality. This establishes the nonnegative curvature test.

The path correction is ; the second-order Taylor remainder is . They are different quantities. The vanishing first derivative is what permits the displacement correction to leave the quadratic coefficient unchanged.
Second Order Sufficient Conditions¶
Complete sufficient-condition proof¶
For data at a KKT point, suppose
Then is a strict local minimum. LICQ is not required for this sufficient test. Biegler, Theorem 4.18, pp. 81–82; Nocedal–Wright, Theorem 12.6, pp. 333–334.
Complete contradiction proof. If strict local minimality fails, choose distinct feasible with . Put and . Compactness of the unit sphere gives a subsequence with . Constraint expansions give without any CQ. Dividing the objective difference by gives ; stationarity gives , hence .
At every feasible point because , and . Also . The stationary second-order expansion therefore yields
a contradiction. This proof includes directions approaching the critical cone, rather than assuming a direction limit for every original sequence.

Does SOSC imply SONC? At a fixed multiplier vector, strict positivity implies nonnegativity on that same cone. But the necessary-condition theorem additionally assumes LICQ, whereas the sufficient-condition theorem does not. Do not transfer that hypothesis from one theorem to the other. In a degenerate problem different KKT vectors can give different Hessians and critical-cone descriptions; the fixed-vector sufficient test remains meaningful.
In Biegler’s second proof case, all positive-multiplier terms contribute to the first-order Lagrangian/objective difference. Keeping only one chosen negative contribution supports an inequality, not an equality unless the other terms vanish. The argument above keeps the full sum and avoids that omission.
Reduced Hessian¶
A basis for a linear null space¶
For a full-row-rank with , a null-space basis has full column rank and . Every vector in is uniquely . When , the null space is and has zero columns; a curvature condition over its nonzero vectors is vacuous.
This is the row-oriented version of Biegler’s Definition 4.19, p. 82. If rows are dependent, the correct dimension is , obtained with a rank-revealing factorization or SVD. Pivoting detects the dependence; it does not make dependent rows independent. An arbitrary critical cone cannot be represented by with unrestricted : that image is a subspace.
Complete QR construction and a small worked example¶
For independent rows, factor , where is orthogonal and is nonsingular upper triangular. Since ,
and has independent columns, so it spans the null space. An economic QR can omit this complement; request the complete factorization. Biegler (4.58), p. 82; Nocedal–Wright (12.74), p. 337.
For , choose
Check , and . The two constraint planes intersect in the line spanned by .

For numerical work use a stable library factorization, inspect the rank threshold, and check , the rank of , and when an orthonormal basis is intended. Loss of orthogonality does not by itself prove that a full-rank, exactly null basis fails to span the null space. The Math-Primer D3 experiment illustrates orthogonality loss; its economic QR alone does not construct . Watkins (2002), Sections 3.2–3.3, provides the reflector/rotator background.
Reduced Hessian and basis invariance¶
For symmetric and ,
Because is a full-rank basis for , nonzero and nonzero correspond. Thus curvature is positive (semi)definite on this subspace exactly when the reduced Hessian is positive (semi)definite. A different basis , with nonsingular, gives . Definiteness and inertia are invariant; eigenvalue magnitudes generally change. Orthonormal bases make eigenvalue scales easier to interpret.

For , , the origin has , and . Its reduced Hessian is 2, so the origin is a strict constrained minimum despite an indefinite full Hessian.
Let span . Under the necessary theorem’s hypotheses, is a weaker necessary test because it checks fewer directions. At a KKT point, is a stronger sufficient test because it checks more directions than requires. Neither is a general equivalence to the exact cone test.
For example, on , the function has a strict minimum at the origin with zero multipliers. Its critical cone is the nonnegative quadrant. The Hessian has eigenvalues 3 and −1, but for every nonzero critical direction. The whole-space test fails although the exact SOSC holds. Conversely, the all-active null space can be zero and its necessary test vacuous even at a nonminimum. Strict complementarity makes , so the subspace tests become exact. Biegler, pp. 82–83.
Example¶
Example 4.20: a positive one-dimensional reduced Hessian¶
Use the canonical positive-domain log model with . Biegler’s Example 4.20 is on p. 83. Its solution is approximately with , so strict complementarity holds. The corrected Lagrangian Hessian is
The gradient row is and a unit tangent basis is approximately . The reduced Hessian is about 2.42736 using unrounded values; the errata’s 2.4272 uses the rounded printed basis. The printed 1.0331 and Hessian (4.66) need the errata. With the displayed +9 objective, ; the book’s −2.4944 is two lower, consistent with +7. The existing source correction explains the constant without changing the derivatives or minimizer.
The Biegler errata corrects p. 83’s Hessian and reduced-Hessian number. The native calculation below preserves the original rounded NumPy example, followed by the actual Pyomo solve and an analytic derivative/basis check. These are numerical evaluations of a supplied model, not a reason to reuse the uncorrected printed matrix.
Calculation with numpy¶
import numpy as np
# Define the Hessian of the Lagrange function
hessian_L = np.array([[2.3093, 0.4315], [0.4315, 3.2021]])
print(hessian_L)[[2.3093 0.4315]
[0.4315 3.2021]]
# Define the gradient of the constraints
A = np.reshape(np.array([-2.2245, -1.7981]), (2, 1))print(A)[[-2.2245]
[-1.7981]]
Calculate the complete QR factorization.
# Calculate the COMPLETE QR factorization
Q, R = np.linalg.qr(A, mode="complete")print(Q)[[-0.77770385 -0.62863083]
[-0.62863083 0.77770385]]
print(R)[[2.86034331]
[0. ]]
print(Q @ R)[[-2.2245]
[-1.7981]]
The code’s A stacks the single gradient as a column, so A = J_g.T. The second column of the complete lies in , not . Indeed . Since has the right number of independent columns, it is a basis for the tangent line. Now evaluate .
# Calculate the reduced Hessian
print("Reduced Hessian w.r.t. null space of constraints:")
Q[:, 1].T @ hessian_L @ Q[:, 1]Reduced Hessian w.r.t. null space of constraints:
np.float64(2.4273753426093774)Calculate with Pyomo¶
Define and solve the model¶
import pyomo.environ as pyo
m = pyo.ConcreteModel()
# Define variables
m.x1 = pyo.Var(initialize=1)
m.x2 = pyo.Var(initialize=1)
# Define constraints
# Note: changing this to an equality constraint
# changes the reduced_hessian
m.con1 = pyo.Constraint(expr=4 - m.x1 * m.x2 <= 0)
# Define objective
m.obj = pyo.Objective(
expr=m.x1**2
- 4 * m.x1
+ 1.5 * m.x2**2
- 7 * m.x2
+ m.x1 * m.x2
+ 9
- pyo.log(m.x1)
- pyo.log(m.x2)
)
# Obtain dual solutions from first solve and send to warm start
m.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT)
# Specify Ipopt as the solver and solve
opt = pyo.SolverFactory("ipopt")
results = opt.solve(m, tee=True)
assert pyo.check_optimal_termination(results), (
f"Solve failed: status={results.solver.status}, "
f"termination={results.solver.termination_condition}"
)Ipopt 3.13.2:
******************************************************************************
This program contains Ipopt, a library for large-scale nonlinear optimization.
Ipopt is released as open source code under the Eclipse Public License (EPL).
For more information visit http://projects.coin-or.org/Ipopt
This version of Ipopt was compiled from source code available at
https://github.com/IDAES/Ipopt as part of the Institute for the Design of
Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE
Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.
This version of Ipopt was compiled using HSL, a collection of Fortran codes
for large-scale scientific computation. All technical papers, sales and
publicity material resulting from use of the HSL codes within IPOPT must
contain the following acknowledgement:
HSL, a collection of Fortran codes for large-scale scientific
computation. See http://www.hsl.rl.ac.uk.
******************************************************************************
This is Ipopt version 3.13.2, running with linear solver ma27.
Number of nonzeros in equality constraint Jacobian...: 0
Number of nonzeros in inequality constraint Jacobian.: 2
Number of nonzeros in Lagrangian Hessian.............: 3
Total number of variables............................: 2
variables with only lower bounds: 0
variables with lower and upper bounds: 0
variables with only upper bounds: 0
Total number of equality constraints.................: 0
Total number of inequality constraints...............: 1
inequality constraints with only lower bounds: 0
inequality constraints with lower and upper bounds: 0
inequality constraints with only upper bounds: 1
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
0 1.5000000e+00 3.00e+00 2.67e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0
1 -3.3886674e-01 2.05e+00 5.62e+00 -1.0 1.78e+00 - 1.00e+00 2.75e-01f 1
2 -1.1897000e-01 0.00e+00 5.69e-01 -1.0 8.27e-01 - 1.00e+00 1.00e+00f 1
3 -4.7085742e-01 0.00e+00 6.15e-02 -1.7 1.54e-01 - 1.00e+00 1.00e+00h 1
4 -4.9093265e-01 0.00e+00 5.84e-04 -2.5 2.04e-02 - 1.00e+00 1.00e+00h 1
5 -4.9428887e-01 0.00e+00 4.51e-06 -3.8 5.92e-03 - 1.00e+00 1.00e+00h 1
6 -4.9445149e-01 0.00e+00 9.87e-09 -5.7 2.84e-04 - 1.00e+00 1.00e+00h 1
7 -4.9445337e-01 0.00e+00 1.29e-12 -8.6 3.29e-06 - 1.00e+00 1.00e+00h 1
Number of Iterations....: 7
(scaled) (unscaled)
Objective...............: -4.9445336916038984e-01 -4.9445336916038984e-01
Dual infeasibility......: 1.2920775560587572e-12 1.2920775560587572e-12
Constraint violation....: 0.0000000000000000e+00 0.0000000000000000e+00
Complementarity.........: 2.5098574967664487e-09 2.5098574967664487e-09
Overall NLP error.......: 2.5098574967664487e-09 2.5098574967664487e-09
Number of objective function evaluations = 8
Number of objective gradient evaluations = 8
Number of equality constraint evaluations = 0
Number of inequality constraint evaluations = 8
Number of equality constraint Jacobian evaluations = 0
Number of inequality constraint Jacobian evaluations = 8
Number of Lagrangian Hessian evaluations = 7
Total CPU secs in IPOPT (w/o function evaluations) = 0.001
Total CPU secs in NLP function evaluations = 0.000
EXIT: Optimal Solution Found.
Extract the dual variable for the constraint¶
m.dual[m.con1]-0.5684977067847851Actual-point derivative and basis check¶
The model and solve above are unchanged. The following cell differentiates the actual Pyomo expressions and archives one shared basis-comparison figure. It records the point before the later experimental barrier calls solve the model again.
from pyomo.core.expr.calculus.derivatives import differentiate, Modes
variables = [m.x1, m.x2]
x_actual = np.array([pyo.value(v) for v in variables])
u_actual = -float(m.dual[m.con1])
g_expr = m.con1.body
gradient_actual = np.array(differentiate(m.obj.expr, wrt_list=variables))
jac_actual = np.array(differentiate(g_expr, wrt_list=variables)).reshape(1, 2)
lag_expr = m.obj.expr + u_actual * g_expr
lag_gradient = differentiate(lag_expr, wrt_list=variables, mode=Modes.reverse_symbolic)
W_actual = np.array([differentiate(e, wrt_list=variables) for e in lag_gradient])
Q_actual, _ = np.linalg.qr(jac_actual.T, mode="complete")
Z_actual = Q_actual[:, 1:]
bases = np.column_stack([Z_actual[:, 0], [1, -jac_actual[0, 0]/jac_actual[0, 1]],
[-jac_actual[0, 1]/jac_actual[0, 0], 1]])
reduced_values = np.einsum("ij,ik,kj->j", bases, W_actual, bases)
stationarity_actual = gradient_actual + jac_actual.T[:, 0] * u_actual
assert np.all(x_actual > 0) and u_actual > 0
assert np.linalg.norm(stationarity_actual, np.inf) < 1e-6
assert np.linalg.norm(jac_actual @ bases, np.inf) < 1e-12
assert np.all(reduced_values > 0)
print("Actual point:", x_actual, "canonical u:", u_actual)
print("Corrected Lagrangian Hessian:\n", W_actual)
print("Unit QR basis:", Z_actual[:, 0])
print("Reduced Hessians: unit QR, x1 parameter, x2 parameter:", reduced_values)
q_grid = np.linspace(-1, 1, 201)
x1_curve = np.linspace(x_actual[0] - .5, x_actual[0] + .5, 201)
soc_data = {"point": x_actual.tolist(), "objective": float(pyo.value(m.obj)),
"u": u_actual, "J": jac_actual.tolist(), "W": W_actual.tolist(),
"bases": bases.tolist(), "reduced_values": reduced_values.tolist(),
"q": q_grid.tolist(), "quadratic_change": (.5*reduced_values[:,None]*q_grid[None,:]**2).tolist(),
"curve_x1": x1_curve.tolist(), "curve_x2": (4/x1_curve).tolist()}
helper.save_results("soc-log-bases", soc_data, notebook="notebooks/7-dev/Second-Order.ipynb",
source_cells=[("notebooks/7-dev/Second-Order.ipynb", "results:soc-log-model"),
("notebooks/7-dev/Second-Order.ipynb", "results:soc-log-curvature")],
description="Actual +9 log-model point, symbolic Lagrangian derivatives and three tangent parameter scales.",
solver=str(opt), quiet=True)
results = soc_data
Actual point: [1.79811993 2.2245457 ] canonical u: 0.5684977067847851
Corrected Lagrangian Hessian:
[[2.30928773 0.43150229]
[0.43150229 3.20207721]]
Unit QR basis: [-0.62862724 0.77770676]
Reduced Hessians: unit QR, x1 parameter, x2 parameter: [2.42735934 6.14253567 4.01330651]
import matplotlib.pyplot as plt
fig, axes = plt.subplots(1, 2, figsize=(7.5, 3.2))
point = np.asarray(results["point"])
jrow = np.asarray(results["J"])[0]
axes[0].plot(results["curve_x1"], results["curve_x2"], color="#0072B2", linestyle="-", label=r"$x_1x_2=4$")
tangent_x = np.asarray(results["curve_x1"])
axes[0].plot(tangent_x, point[1] - jrow[0]/jrow[1]*(tangent_x-point[0]),
color="0.4", linestyle="--", label="tangent line")
axes[0].scatter(*point, color="black", marker="o", s=45)
axes[0].set(xlabel="$x_1$", ylabel="$x_2$")
axes[0].legend(fontsize=10)
styles = [("unit QR", "#0072B2", "-"), ("x1 parameter", "#D55E00", "--"),
("x2 parameter", "#009E73", ":")]
for values, (label, color, linestyle) in zip(results["quadratic_change"], styles):
axes[1].plot(results["q"], values, color=color, linestyle=linestyle, label=label)
axes[1].set(xlabel="parameter increment q", ylabel="quadratic change")
axes[1].legend(fontsize=10)
fig.tight_layout()
helper.save_figure(fig, "soc-log-bases", quiet=True)

For this canonical upper inequality, the imported Pyomo suffix is negative and gives the nonnegative canonical multiplier. The analytic stationarity check above verifies the mapping at the actual point. See the KKT suffix reference for other constraint orientations.
The original model comment about changing the inequality to an equality concerns the numerical barrier treatment. At the same point and matching multiplier, the exact active-tangent reduced Hessian is the same; changing a constraint’s role does not by itself change that quadratic form.
Extract the reduced Hessian¶
# Warning: this Pyomo feature is experimental
from pyomo.contrib.interior_point.inverse_reduced_hessian import (
inv_reduced_hessian_barrier,
)
# https://github.com/Pyomo/pyomo/blob/main/pyomo/contrib/interior_point/inverse_reduced_hessian.pyCompute the reduced Hessian with respect to
solve_result, inv_red_hes = inv_reduced_hessian_barrier(
m,
independent_variables=[m.x1], # Warning: these variables cannot be at their bounds
tee=True,
)
print("\nReduced Hessian w.r.t. x1:")
print(np.linalg.inv(inv_red_hes))Ipopt 3.13.2: bound_relax_factor=0
honor_original_bounds=no
******************************************************************************
This program contains Ipopt, a library for large-scale nonlinear optimization.
Ipopt is released as open source code under the Eclipse Public License (EPL).
For more information visit http://projects.coin-or.org/Ipopt
This version of Ipopt was compiled from source code available at
https://github.com/IDAES/Ipopt as part of the Institute for the Design of
Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE
Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.
This version of Ipopt was compiled using HSL, a collection of Fortran codes
for large-scale scientific computation. All technical papers, sales and
publicity material resulting from use of the HSL codes within IPOPT must
contain the following acknowledgement:
HSL, a collection of Fortran codes for large-scale scientific
computation. See http://www.hsl.rl.ac.uk.
******************************************************************************
This is Ipopt version 3.13.2, running with linear solver ma27.
Number of nonzeros in equality constraint Jacobian...: 0
Number of nonzeros in inequality constraint Jacobian.: 2
Number of nonzeros in Lagrangian Hessian.............: 3
Total number of variables............................: 2
variables with only lower bounds: 0
variables with lower and upper bounds: 0
variables with only upper bounds: 0
Total number of equality constraints.................: 0
Total number of inequality constraints...............: 1
inequality constraints with only lower bounds: 0
inequality constraints with lower and upper bounds: 0
inequality constraints with only upper bounds: 1
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
0 -4.9445337e-01 3.56e-08 3.85e-01 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0
1 -4.7328569e-01 0.00e+00 3.92e-04 -1.7 1.17e-02 - 1.00e+00 1.00e+00h 1
2 -4.9381301e-01 0.00e+00 1.46e-04 -3.8 3.57e-02 - 1.00e+00 1.00e+00f 1
3 -4.9445098e-01 0.00e+00 1.74e-07 -5.7 1.06e-03 - 1.00e+00 1.00e+00h 1
4 -4.9445335e-01 0.00e+00 2.15e-12 -8.6 4.10e-06 - 1.00e+00 1.00e+00h 1
Number of Iterations....: 4
(scaled) (unscaled)
Objective...............: -4.9445334641782690e-01 -4.9445334641782690e-01
Dual infeasibility......: 2.1529444893531036e-12 2.1529444893531036e-12
Constraint violation....: 0.0000000000000000e+00 0.0000000000000000e+00
Complementarity.........: 2.5123319576325303e-09 2.5123319576325303e-09
Overall NLP error.......: 2.5123319576325303e-09 2.5123319576325303e-09
Number of objective function evaluations = 5
Number of objective gradient evaluations = 5
Number of equality constraint evaluations = 0
Number of inequality constraint evaluations = 5
Number of equality constraint Jacobian evaluations = 0
Number of inequality constraint Jacobian evaluations = 5
Number of Lagrangian Hessian evaluations = 4
Total CPU secs in IPOPT (w/o function evaluations) = 0.000
Total CPU secs in NLP function evaluations = 0.000
EXIT: Optimal Solution Found.
Reduced Hessian w.r.t. x1:
[[1.99699045]]
Compute the reduced Hessian with respect to
solve_result, inv_red_hes = inv_reduced_hessian_barrier(
m,
independent_variables=[m.x2], # Warning: these variables cannot be at their bounds
tee=True,
)
print("\nReduced Hessian w.r.t. x2:")
print(np.linalg.inv(inv_red_hes))Ipopt 3.13.2: bound_relax_factor=0
honor_original_bounds=no
******************************************************************************
This program contains Ipopt, a library for large-scale nonlinear optimization.
Ipopt is released as open source code under the Eclipse Public License (EPL).
For more information visit http://projects.coin-or.org/Ipopt
This version of Ipopt was compiled from source code available at
https://github.com/IDAES/Ipopt as part of the Institute for the Design of
Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE
Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.
This version of Ipopt was compiled using HSL, a collection of Fortran codes
for large-scale scientific computation. All technical papers, sales and
publicity material resulting from use of the HSL codes within IPOPT must
contain the following acknowledgement:
HSL, a collection of Fortran codes for large-scale scientific
computation. See http://www.hsl.rl.ac.uk.
******************************************************************************
This is Ipopt version 3.13.2, running with linear solver ma27.
Number of nonzeros in equality constraint Jacobian...: 0
Number of nonzeros in inequality constraint Jacobian.: 2
Number of nonzeros in Lagrangian Hessian.............: 3
Total number of variables............................: 2
variables with only lower bounds: 0
variables with lower and upper bounds: 0
variables with only upper bounds: 0
Total number of equality constraints.................: 0
Total number of inequality constraints...............: 1
inequality constraints with only lower bounds: 0
inequality constraints with lower and upper bounds: 0
inequality constraints with only upper bounds: 1
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
0 -4.9445335e-01 0.00e+00 3.85e-01 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0
1 -4.7328569e-01 0.00e+00 3.92e-04 -1.7 1.17e-02 - 1.00e+00 1.00e+00h 1
2 -4.9381301e-01 0.00e+00 1.46e-04 -3.8 3.57e-02 - 1.00e+00 1.00e+00f 1
3 -4.9445098e-01 0.00e+00 1.74e-07 -5.7 1.06e-03 - 1.00e+00 1.00e+00h 1
4 -4.9445335e-01 0.00e+00 2.15e-12 -8.6 4.10e-06 - 1.00e+00 1.00e+00h 1
Number of Iterations....: 4
(scaled) (unscaled)
Objective...............: -4.9445334641782690e-01 -4.9445334641782690e-01
Dual infeasibility......: 2.1529444893531036e-12 2.1529444893531036e-12
Constraint violation....: 0.0000000000000000e+00 0.0000000000000000e+00
Complementarity.........: 2.5123319576325303e-09 2.5123319576325303e-09
Overall NLP error.......: 2.5123319576325303e-09 2.5123319576325303e-09
Number of objective function evaluations = 5
Number of objective gradient evaluations = 5
Number of equality constraint evaluations = 0
Number of inequality constraint evaluations = 5
Number of equality constraint Jacobian evaluations = 0
Number of inequality constraint Jacobian evaluations = 5
Number of Lagrangian Hessian evaluations = 4
Total CPU secs in IPOPT (w/o function evaluations) = 0.000
Total CPU secs in NLP function evaluations = 0.000
EXIT: Optimal Solution Found.
Reduced Hessian w.r.t. x2:
[[2.76904325]]
Coordinate parameters are tangent bases, not coordinate-axis directions¶
At , the tangent basis for parameter is , and for parameter it is . Neither is the coordinate vector or . Each equals a nonzero scalar multiple of the unit QR basis; consequently its reduced Hessian scales by the square of that scalar. Positive definiteness survives, while the three numerical values differ.
The official experimental API documentation and the installed implementation show that inv_reduced_hessian_barrier solves the model again, forms a barrier-subproblem KKT matrix, and extracts an inverse-Hessian block for selected independent variables. At a finite barrier parameter this is not an exact critical-cone certificate. Its selected variables must be away from their bounds. Check solve status, evaluate the actual active-point derivatives, and distinguish coordinate scaling from finite-barrier and roundoff effects when comparing outputs.