Skip to main content

NlTnlp

Struct NlTnlp 

Source
pub struct NlTnlp { /* private fields */ }

Implementations§

Source§

impl NlTnlp

Source

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.

Source

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.

Source

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.

Source

pub fn final_x(&self) -> Option<&[f64]>

Source

pub fn final_obj(&self) -> f64

Source

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.

Source

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.

Source

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.

Source

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.

Source

pub fn curvature_scaling_enabled(&self) -> bool

Whether Self::enable_curvature_scaling has been called and succeeded.

Source

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].

Source

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.

Source

pub fn quadratic_objective(&self) -> bool

As Self::quadratic_row, for the objective.

Source

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).

Source

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.

Source

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).)

Source

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).

Source

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 Clone for NlTnlp

Source§

fn clone(&self) -> NlTnlp

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for NlTnlp

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl ExpressionProvider for NlTnlp

Source§

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>

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>

Constraint name from the sibling .row file, if one was loaded. Index is original .nl row order.

Source§

fn objective_expression(&self) -> Option<FbbtTape>

Expression tape for the objective. Optional in the same sense as Self::constraint_expression; FBBT does not use the objective today, but a future OBBT-style pass might.
Source§

impl TNLP for NlTnlp

Source§

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

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>

Required. Problem dimensions and triplet index style.
Source§

fn get_bounds_info(&mut self, b: BoundsInfo<'_>) -> bool

Required. Variable / constraint bounds.
Source§

fn get_starting_point(&mut self, sp: StartingPoint<'_>) -> bool

Required. Initial primal (and optionally dual) point.
Source§

fn eval_f(&mut self, x: &[f64], _new_x: bool) -> Option<f64>

Required. Objective value at x.
Source§

fn eval_grad_f(&mut self, x: &[f64], _new_x: bool, grad: &mut [f64]) -> bool

Required. Objective gradient at x into grad_f.
Source§

fn eval_g(&mut self, x: &[f64], _new_x: bool, g: &mut [f64]) -> bool

Required. Constraint values g(x).
Source§

fn eval_jac_g( &mut self, x: Option<&[f64]>, _new_x: bool, mode: SparsityRequest<'_>, ) -> bool

Required. Jacobian of 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

Required for exact Hessian, optional for L-BFGS. Hessian of the Lagrangian. Default returns false (signals to %Ipopt that quasi-Newton must be used).
Source§

fn finalize_solution(&mut self, sol: Solution<'_>, _d: &IpoptData, _q: &IpoptCq)

Required. Receives the final iterate after solve.
Source§

fn get_constraints_linearity(&mut self, types: &mut [Linearity]) -> bool

Constraint linearity tags. Used by adaptive-mu’s nlp_scaling_method=equilibration-based.
Source§

fn get_variables_linearity(&mut self, types: &mut [Linearity]) -> bool

Variable linearity tags (used by Bonmin, not by Ipopt).
Source§

fn get_objective_variables_linearity(&mut self, types: &mut [Linearity]) -> bool

Per-variable linearity with respect to the objective only (a pounce extension; upstream has no objective-scoped query). 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

Number of variables that appear nonlinearly. Returning -1 means “treat all as nonlinear” (the Ipopt default).
Source§

fn get_list_of_nonlinear_variables( &mut self, pos_nonlin_vars: &mut [i32], ) -> bool

List of nonlinear variable indices, in the index style returned from Self::get_nlp_info.
Source§

fn derivative_proofs(&mut self) -> DerivativeProofs

What this model can prove about the constancy of its own derivatives (gh #588, phase Q6). Read more
Source§

fn intermediate_callback( &mut self, _stats: IterStats, _ip_data: &IpoptData, _ip_cq: &IpoptCq, ) -> bool

Per-iteration intermediate callback. Returning false requests early termination with User_Requested_Stop.
Source§

fn finalize_metadata(&mut self, _var: &MetaData, _con: &MetaData)

Final metadata pass — called just before Self::finalize_solution. Default does nothing.
Source§

fn is_presolve_wrapper(&self) -> bool

Whether this TNLP is already an explicit generic-presolve wrapper. Read more
Source§

fn scaling_factors(&self) -> Option<Vec<f64>>

The per-variable scaling factors this decorator applies, if it is a scaling wrapper (gh#486). Consumers that read the algorithm’s iterate rather than the 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>

A proof that this problem has no feasible point, if presolve found one. None (the default) means “not proved” — which is not the same as “feasible”. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> ByRef<T> for T

Source§

fn by_ref(&self) -> &T

Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Imply<T> for U
where T: ?Sized, U: ?Sized,

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more