pub struct NlTnlp { /* private fields */ }Implementations§
Source§impl NlTnlp
impl NlTnlp
Sourcepub fn new(prob: NlProblem) -> NlTnlp
pub fn new(prob: NlProblem) -> NlTnlp
Build the TNLP, panicking if AMPL external-function resolution fails.
Kept for the many infallible call sites (CLI, tests) that operate on
.nl models known to need no external libraries. Surfaces that can be
handed an arbitrary user model — notably the Python read_nl binding —
must call Self::try_new instead so a missing $AMPLFUNC library
becomes a catchable error rather than an uncatchable panic across the
pyo3 boundary.
Sourcepub fn try_new(prob: NlProblem) -> Result<NlTnlp, String>
pub fn try_new(prob: NlProblem) -> Result<NlTnlp, String>
Build the TNLP, returning an error (instead of panicking) when AMPL
imported functions named by the model can’t be resolved — e.g.
$AMPLFUNC is unset, a named library is missing/unloadable, or a
referenced function id isn’t registered by any loaded library.
Sourcepub fn try_new_with_quadratic(
prob: NlProblem,
use_quadratic: bool,
) -> Result<NlTnlp, String>
pub fn try_new_with_quadratic( prob: NlProblem, use_quadratic: bool, ) -> Result<NlTnlp, String>
Self::try_new with the constant-structure fast path (gh #588, Q4)
explicitly on or off.
The env var try_new reads is process-global, which is exactly wrong
for the differential test that has to build the same model both ways
and compare the derivatives — so the knob is a parameter here and the
env var only chooses its default.
pub fn final_x(&self) -> Option<&[f64]>
pub fn final_obj(&self) -> f64
Sourcepub fn final_lambda(&self) -> Option<&[f64]>
pub fn final_lambda(&self) -> Option<&[f64]>
Converged constraint multipliers from the last solve, in original
.nl row order. None before a solve finishes. See
Self::final_x for the primal counterpart.
Sourcepub fn final_bound_multipliers(&self) -> Option<(&[f64], &[f64])>
pub fn final_bound_multipliers(&self) -> Option<(&[f64], &[f64])>
Converged lower / upper bound multipliers from the last solve, in
original .nl variable order and Ipopt’s internal convention (both
>= 0). None before a solve finishes.
Sourcepub fn problem(&self) -> &NlProblem
pub fn problem(&self) -> &NlProblem
The parsed problem this TNLP evaluates (bounds, starting point,
names, suffixes). Read-only; per-instance overrides go through
Self::variant.
Sourcepub fn enable_curvature_scaling(&mut self) -> bool
pub fn enable_curvature_scaling(&mut self) -> bool
Opt this model in to curvature-based scaling (gh #703): compute
the per-variable and per-row factors of
crate::nl_scaling::curvature_scaling and serve them from
TNLP::get_scaling_parameters, so nlp_scaling_method reaches
them through the channel it already has for user factors.
Returns false when the model is not one the scheme is defined for
— some row or the objective is not degree ≤ 2, so no constant Qᵢ
exists. The caller must surface that as an error rather than solving
unscaled: an accepted scaling option that is then quietly not applied
is exactly the gh #483 failure.
Costs one pass over every stored Hessian entry plus RUIZ_SWEEPS
passes over the magnitude surrogates, and nothing at all for a solve
that never calls it.
Sourcepub fn curvature_scaling_enabled(&self) -> bool
pub fn curvature_scaling_enabled(&self) -> bool
Whether Self::enable_curvature_scaling has been called and
succeeded.
Sourcepub fn curvature_scaling_read_curvature(&self) -> bool
pub fn curvature_scaling_read_curvature(&self) -> bool
Whether the enabled curvature scaling actually read any curvature —
see crate::nl_scaling::CurvatureScaling::quadratic. false when
scaling is not enabled, and false for a degree-≤2 model whose every
Q is empty (an LP), where the scheme degenerates to plain Ruiz
equilibration of [A b].
Sourcepub fn quadratic_row(&self, i: usize) -> bool
pub fn quadratic_row(&self, i: usize) -> bool
Is constraint row i evaluated from a constant quadratic form
rather than from an AD tape (gh #588, Q4)?
Structural, so it answers before any evaluation. Exposed for the
differential test, which has to know which models exercise the fast
path at all, and for POUNCE_DBG_TAPE_STATS.
Sourcepub fn quadratic_objective(&self) -> bool
pub fn quadratic_objective(&self) -> bool
As Self::quadratic_row, for the objective.
Sourcepub fn problem_mut(&mut self) -> &mut NlProblem
pub fn problem_mut(&mut self) -> &mut NlProblem
Mutable access to that same problem, for a caller that owns this TNLP outright.
The tapes were built from the expressions in Self::problem and
are not rebuilt, so editing an expression here does not change
what this TNLP evaluates. It exists for teardown: the Python
binding takes the expression trees out through here so a deeply
nested one is dropped on a stack chosen for it rather than
recursively on whatever thread collected the object (pounce#472).
Sourcepub fn hessian_vector_product(
&mut self,
x: &[f64],
v: &[f64],
obj_factor: f64,
lambda: Option<&[f64]>,
out: &mut [f64],
) -> Result<(), String>
pub fn hessian_vector_product( &mut self, x: &[f64], v: &[f64], obj_factor: f64, lambda: Option<&[f64]>, out: &mut [f64], ) -> Result<(), String>
Hessian-vector product of the Lagrangian:
out = (obj_factor·∇²f(x) + Σ_i λ_i·∇²g_i(x)) · v.
This is the matrix-free counterpart of eval_h. eval_h runs one
Tape::hessian_directional pass per color and then decodes the
compressed columns into the sparse lower triangle; here the seed is
the caller’s v directly, so it is a single forward-over-reverse
pass per tape — O(tape ops), independent of n and of the coloring’s
chromatic number. That is what makes it usable on models where
materializing ∇²L is impractical (issue #469): a Newton–Krylov /
truncated-CG step only ever needs ∇²L · v.
Sign convention matches eval_h and the rest of this evaluator: a
maximize model’s objective is negated so the returned operator is
the one that minimizing solves. lambda is None for the objective
block alone.
out is overwritten (not accumulated into). Errors on any length
mismatch rather than panicking, since the Python binding hands this
arbitrary user arrays.
Sourcepub fn hessian_vector_products(
&mut self,
x: &[f64],
v: &[f64],
k: usize,
obj_factor: f64,
lambda: Option<&[f64]>,
out: &mut [f64],
) -> Result<(), String>
pub fn hessian_vector_products( &mut self, x: &[f64], v: &[f64], k: usize, obj_factor: f64, lambda: Option<&[f64]>, out: &mut [f64], ) -> Result<(), String>
Block form of Self::hessian_vector_product: k directions at
once, out[:, c] = ∇²L · v[:, c].
v and out are n × k in column-major order — direction c
occupies v[c*n .. (c+1)*n]. out is overwritten.
Worth having as its own entry point rather than a loop over the
single-vector call: the forward sweep depends only on x, so a block
runs it once per tape and reuses vals across all k directions,
where k separate calls would redo it k times. Only the
forward-tangent + reverse-over-tangent passes are per-direction. That
is the shape a block-Krylov solve, a directional-derivative probe, or
a densify-the-Hessian loop wants.
An all-zero direction is skipped, so passing a sparse block whose
columns are mostly empty costs only the columns that carry signal.
(The sparsity that dominates is the model’s own: each tape touches
only its own variables, and hessian_directional is O(tape ops), not
O(n).)
Sourcepub fn variant(&self, v: &NlVariation) -> Result<NlTnlp, String>
pub fn variant(&self, v: &NlVariation) -> Result<NlTnlp, String>
Clone this TNLP with per-instance overrides applied — the
“one structure, many bound / starting-point variations” case of
batched NLP solving (pounce#126). The AD tapes, sparsity, and
coloring are reused via Clone (they depend only on the model
structure, which a variation cannot change); only the values in
prob.x0 / prob.x_l / prob.x_u / prob.g_l / prob.g_u
are replaced. Any stale final_x from a previous solve of
self is cleared on the clone.
Errors when an override’s length does not match the model
(n for x0/x_l/x_u, m for g_l/g_u).
Sourcepub fn variants(&self, vs: &[NlVariation]) -> Result<Vec<NlTnlp>, String>
pub fn variants(&self, vs: &[NlVariation]) -> Result<Vec<NlTnlp>, String>
Build one NlTnlp per variation, sharing this instance’s
structure (see Self::variant). Returns instances in input
order; errors on the first length-mismatched variation.
Trait Implementations§
Source§impl ExpressionProvider for NlTnlp
impl ExpressionProvider for NlTnlp
Source§fn constraint_expression(&self, i: usize) -> Option<FbbtTape>
fn constraint_expression(&self, i: usize) -> Option<FbbtTape>
Per-.nl-row constraint expression tape, with the linear
part folded in. Returns None for constraints that contribute
neither a nonlinear expression nor any linear coefficients
(so FBBT skips them — there’s nothing to tighten).
Source§fn variable_name(&self, i: usize) -> Option<&str>
fn variable_name(&self, i: usize) -> Option<&str>
Variable name from the sibling .col file, if one was loaded.
Index is original .nl column order.
Source§fn constraint_name(&self, i: usize) -> Option<&str>
fn constraint_name(&self, i: usize) -> Option<&str>
Constraint name from the sibling .row file, if one was loaded.
Index is original .nl row order.
Source§fn objective_expression(&self) -> Option<FbbtTape>
fn objective_expression(&self) -> Option<FbbtTape>
Self::constraint_expression; FBBT does not use the
objective today, but a future OBBT-style pass might.Source§impl TNLP for NlTnlp
impl TNLP for NlTnlp
Source§fn get_scaling_parameters(&mut self, req: ScalingRequest<'_>) -> bool
fn get_scaling_parameters(&mut self, req: ScalingRequest<'_>) -> bool
Hand the .nl file’s scaling_factor suffixes to the engine’s
nlp_scaling_method=user-scaling pathway — the AMPL/ASL channel
Ipopt reads in AmplTNLP::GetScalingParameters, and the one a
Pyomo Suffix(direction=Suffix.EXPORT) named scaling_factor
writes into. Before gh#483 nothing implemented this callback for
.nl input, so a tagged model reached the solver with the option
accepted and no scaling applied, silently.
Returns false (engine falls back to no scaling) when the file
declares no scaling_factor suffix at all — the same “user
supplied nothing” answer as the default TNLP impl.
AMPL suffix vectors default to 0 for components the model did
not tag, and 0 is not a usable scale factor. A zero entry is
therefore read as “not tagged” and becomes 1.0, which is what
“unlisted components are unscaled” means. Per-variable factors
are passed straight through: OrigIpoptNlp does not model them
and refuses the solve with a message rather than dropping them.
Source§fn get_var_con_metadata(
&mut self,
var: &mut MetaData,
con: &mut MetaData,
) -> bool
fn get_var_con_metadata( &mut self, var: &mut MetaData, con: &mut MetaData, ) -> bool
Publish the .col / .row names (captured at load time) under the
conventional idx_names metadata key, in original .nl order. The
adapter permutes these into split space (see
OrigIpoptNlp::split_space_names) so the debugger can report a
near-singular Jacobian row as the mass_balance equation rather
than “row 3” — the model-vs-index gap Lee et al. (2024,
https://doi.org/10.69997/sct.147875) flag for equation-oriented
model debugging. Declines (returns false) when the model shipped no
name files so callers fall back to index labels.
Source§fn get_nlp_info(&mut self) -> Option<NlpInfo>
fn get_nlp_info(&mut self) -> Option<NlpInfo>
Source§fn get_bounds_info(&mut self, b: BoundsInfo<'_>) -> bool
fn get_bounds_info(&mut self, b: BoundsInfo<'_>) -> bool
Source§fn get_starting_point(&mut self, sp: StartingPoint<'_>) -> bool
fn get_starting_point(&mut self, sp: StartingPoint<'_>) -> bool
Source§fn eval_grad_f(&mut self, x: &[f64], _new_x: bool, grad: &mut [f64]) -> bool
fn eval_grad_f(&mut self, x: &[f64], _new_x: bool, grad: &mut [f64]) -> bool
x into grad_f.Source§fn eval_g(&mut self, x: &[f64], _new_x: bool, g: &mut [f64]) -> bool
fn eval_g(&mut self, x: &[f64], _new_x: bool, g: &mut [f64]) -> bool
g(x).Source§fn eval_jac_g(
&mut self,
x: Option<&[f64]>,
_new_x: bool,
mode: SparsityRequest<'_>,
) -> bool
fn eval_jac_g( &mut self, x: Option<&[f64]>, _new_x: bool, mode: SparsityRequest<'_>, ) -> bool
g. Sparsity vs. values selected by
mode. x and new_x are unused on the structure call.Source§fn eval_h(
&mut self,
x: Option<&[f64]>,
_new_x: bool,
obj_factor: f64,
lambda: Option<&[f64]>,
_new_lambda: bool,
mode: SparsityRequest<'_>,
) -> bool
fn eval_h( &mut self, x: Option<&[f64]>, _new_x: bool, obj_factor: f64, lambda: Option<&[f64]>, _new_lambda: bool, mode: SparsityRequest<'_>, ) -> bool
Source§fn finalize_solution(&mut self, sol: Solution<'_>, _d: &IpoptData, _q: &IpoptCq)
fn finalize_solution(&mut self, sol: Solution<'_>, _d: &IpoptData, _q: &IpoptCq)
Source§fn get_constraints_linearity(&mut self, types: &mut [Linearity]) -> bool
fn get_constraints_linearity(&mut self, types: &mut [Linearity]) -> bool
nlp_scaling_method=equilibration-based.Source§fn get_variables_linearity(&mut self, types: &mut [Linearity]) -> bool
fn get_variables_linearity(&mut self, types: &mut [Linearity]) -> bool
Source§fn get_objective_variables_linearity(&mut self, types: &mut [Linearity]) -> bool
fn get_objective_variables_linearity(&mut self, types: &mut [Linearity]) -> bool
NonLinear iff the objective’s nonlinear part depends on the
variable; a variable that enters the objective only linearly (or
not at all) is Linear even when it is nonlinear in a
constraint. Consumed by presolve’s Phase-0 objective-coupling
guard, which must not mistake constraint-only nonlinearity for
objective coupling. Default: declines (slice untouched).Source§fn get_number_of_nonlinear_variables(&mut self) -> i32
fn get_number_of_nonlinear_variables(&mut self) -> i32
Source§fn get_list_of_nonlinear_variables(
&mut self,
pos_nonlin_vars: &mut [i32],
) -> bool
fn get_list_of_nonlinear_variables( &mut self, pos_nonlin_vars: &mut [i32], ) -> bool
Self::get_nlp_info.Source§fn derivative_proofs(&mut self) -> DerivativeProofs
fn derivative_proofs(&mut self) -> DerivativeProofs
Source§fn intermediate_callback(
&mut self,
_stats: IterStats,
_ip_data: &IpoptData,
_ip_cq: &IpoptCq,
) -> bool
fn intermediate_callback( &mut self, _stats: IterStats, _ip_data: &IpoptData, _ip_cq: &IpoptCq, ) -> bool
User_Requested_Stop.Source§fn finalize_metadata(&mut self, _var: &MetaData, _con: &MetaData)
fn finalize_metadata(&mut self, _var: &MetaData, _con: &MetaData)
Self::finalize_solution. Default does nothing.Source§fn is_presolve_wrapper(&self) -> bool
fn is_presolve_wrapper(&self) -> bool
Source§fn scaling_factors(&self) -> Option<Vec<f64>>
fn scaling_factors(&self) -> Option<Vec<f64>>
finalize_solution payload
see scaled coordinates and need these to undo the substitution.
A transparent decorator should forward the inner answer.Source§fn presolve_infeasibility_proof(&self) -> Option<InfeasibilityProof>
fn presolve_infeasibility_proof(&self) -> Option<InfeasibilityProof>
None (the default) means “not proved” — which is not the same as
“feasible”. Read moreAuto Trait Implementations§
impl Freeze for NlTnlp
impl RefUnwindSafe for NlTnlp
impl Send for NlTnlp
impl Sync for NlTnlp
impl Unpin for NlTnlp
impl UnsafeUnpin for NlTnlp
impl UnwindSafe for NlTnlp
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T, U> Imply<T> for U
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more