Skip to main content

InnerExecutor

Struct InnerExecutor 

Source
pub struct InnerExecutor<S, So> { /* private fields */ }
Expand description

Pre-configured inner solver an outer solver drives once per outer iteration.

Owns the configured inner solver, execution controls, and its max_iter budget. The problem is supplied (borrowed) at run time, so the outer solver can pass the &P it receives in next_iter without taking ownership.

Mirrors Executor’s builder API: max_iter and stop_when_factory are chainable. The differences are (a) the problem isn’t owned, and (b) run is reusable: the same InnerExecutor is expected to be invoked many times across the outer’s lifetime.

run_loop_with_control provides the lower-level interface for custom outer solvers.

§Serialization

With serde, the solver and iteration/evaluation/time budgets serialize. Application hooks, deprecated criteria, capability controls (raw budgets and publication validation), and erased target/stall checks cannot be reconstructed and cause a serialization error. They are never silently dropped from an exact checkpoint.

§Composition contracts

Three rules outer solvers must follow when consuming the result of run; see also CONTRIBUTING.md “Solver composition”:

  1. Eval aggregation. The Problem wrapper bumps EvalCounts on every cost/gradient/residual/Jacobian/Hessian call, and the executor mirrors the per-run delta onto the inner state via CountsMirror. What the outer must do depends on which problem the inner sees:

    • Same-problem inner (the outer passes its own &mut Problem<P> to run): the inner’s calls bump the same wrapper as the outer’s, so aggregation happens transparently. No explicit roll-up; the outer state’s CountsMirror impl decides how the counts surface on its State::cost_evals/ GradientState::gradient_evals.
    • Adapter-problem inner (the outer builds a fresh Problem::new(adapter) per outer iter, e.g. the barrier and augmented-Lagrangian methods): after run returns, fold the inner wrapper’s counts back into the outer’s wrapper via EvalCounts::add on Problem::counts_mut. Skipping this fold silently corrupts MaxCostEvals budgets and the public result.cost_evals().

    See the Solver::next_iter contract for the canonical wording.

  2. History resets per run. Each fresh run resets solver convergence, built-in clocks and stall checks, and deprecated criterion history. stop_when_factory creates a fresh custom closure per run. A direct stop_when closure retains its captures across calls.

  3. Failure routing. run returns a full OptimizationResult; classify the reason. Use TerminationReason::is_failure to decide whether to bubble: SolverFailed should bubble via the outer’s mid-iter Option<TerminationReason> return; everything else (MaxIter, *Tolerance, SolverConverged, NumericalNoProgress) is a “clean stop” the outer can consume and continue past. A clean stop does not itself establish convergence or solution accuracy.

Implementations§

Source§

impl<S: State + CountsMirror, So> InnerExecutor<S, So>

Source

pub fn new(solver: So) -> Self

Build an inner executor around solver. Default max_iter is 1000, mirroring Executor::new.

Source

pub fn max_iter(self, n: u64) -> Self

Set the inner-loop iteration budget. Each call to run drives the inner solver up to this many iterations.

Source

pub fn require_evaluated_state(self) -> Self
where S: EvaluatedState,

Validate complete records at publication boundaries.

See RunControl::require_evaluated_state for validation ordering and solver-contract panics. This control cannot be serialized as part of an inner executor.

Source

pub fn max_evaluations(self, kind: EvaluationKind, limit: u64) -> Self

Set a raw category or total-work budget at iteration boundaries.

See RunControl::max_evaluations for accounting, precedence, and serialization limits.

Source

pub fn target_objective<F: Scalar + 'static>(self, target: F) -> Self
where S: ObjectiveIncumbentState<Float = F>,

Stop when an eligible objective-ordered incumbent reaches a finite target.

Replaces target_cost, and vice versa. See RunControl::target_objective.

Source

pub fn no_objective_improvement<F: Scalar + 'static>( self, patience: u64, min_delta: F, ) -> Self
where S: ObjectiveIncumbentState<Float = F>,

Stop after completed iterations without a sufficient objective decrease.

Replaces no_improvement, and vice versa. See RunControl::no_objective_improvement for threshold validation, publication age, and resume behavior.

Source

pub fn max_cost_evals(self, limit: u64) -> Self

Set a cost-evaluation budget, checked after initialization and between iterations.

Source

pub fn max_gradient_evals(self, limit: u64) -> Self
where S: GradientState,

Set a gradient-evaluation budget, checked between iterations.

Source

pub fn max_time(self, limit: Duration) -> Self

Set a time budget starting at the first post-initialization check.

Source

pub fn target_cost<F: Scalar + 'static>(self, target: F) -> Self
where S: State<Float = F>,

Stop when the state’s best cost reaches the finite target.

Source

pub fn no_improvement<F: Scalar + 'static>( self, patience: u64, min_delta: F, ) -> Self
where S: State<Float = F>,

Stop after patience checks without improvement greater than min_delta.

Source

pub fn no_acceptance(self, patience: u64) -> Self
where S: AcceptanceState,

Stop after a positive number of iterations without an accepted move.

Source

pub fn stop_when_factory<M, C>(self, make: M) -> Self
where M: FnMut() -> C + 'static, C: FnMut(&S) -> Option<TerminationReason> + 'static,

Append a factory creating fresh application-stop history for each run.

Source

pub fn terminate_on<C>(self, criterion: C) -> Self
where C: TerminationCriterion<S> + 'static,

👎Deprecated:

configure inner solver convergence or use stop_when_factory; removal scheduled for Basin 2.0

Add a termination criterion to the inner loop. Criteria are checked in insertion order before each inner iteration. See the type-level “Composition contracts” for the statelessness requirement that applies because criteria are reused across run calls.

Source

pub fn stop_when<C>(self, check: C) -> Self
where C: FnMut(&S) -> Option<TerminationReason> + 'static,

Append an application stop whose captures persist across inner runs. Use stop_when_factory for fresh per-run history.

Source

pub fn solver(&self) -> &So

Read-only access to the inner solver. Lets composed outer solvers dispatch on the inner before run, e.g. to build an inner state via InitialState::seed or MemeticInner::seed_scaled. Mutable access goes through run, which already takes &mut self.

Source

pub fn run<P>( &mut self, problem: &mut Problem<P>, state: S, ) -> Result<OptimizationResult<S>, So::Error>
where So: Solver<P, S>,

Drive the inner solver against problem from state, returning the final inner state and termination reason. Reusable: call once per outer iter.

The inner state’s State::cost_evals reflects only per-run work (snapshot-relative against the wrapper count at entry), not cumulative across calls. The wrapper itself accumulates monotonically: for same-problem composition the outer reads its own Problem::counts after run to see total work; for adapter-problem composition the outer builds a fresh inner Problem and folds counts via EvalCounts::add on Problem::counts_mut after run returns.

Internally exactly run_loop_with_control: init is called on every invocation, so the inner solver sees a fresh setup pass each time (e.g. seeding cost/gradient at the new starting point).

Trait Implementations§

Source§

impl<'de, S, So> Deserialize<'de> for InnerExecutor<S, So>
where So: Deserialize<'de>,

Available on crate feature serde only.
Source§

fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl<S, So> Serialize for InnerExecutor<S, So>
where So: Serialize,

Available on crate feature serde only.
Source§

fn serialize<Ser>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error>
where Ser: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

§

impl<S, So> !RefUnwindSafe for InnerExecutor<S, So>

§

impl<S, So> !Send for InnerExecutor<S, So>

§

impl<S, So> !Sync for InnerExecutor<S, So>

§

impl<S, So> !UnwindSafe for InnerExecutor<S, So>

§

impl<S, So> Freeze for InnerExecutor<S, So>
where So: Freeze, RunControl<S>: Freeze,

§

impl<S, So> Unpin for InnerExecutor<S, So>
where So: Unpin, RunControl<S>: Unpin,

§

impl<S, So> UnsafeUnpin for InnerExecutor<S, So>

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> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

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, 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> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<SS, SP> SupersetOf<SS> for SP
where SS: SubsetOf<SP>,

Source§

fn to_subset(&self) -> Option<SS>

The inverse inclusion map: attempts to construct self from the equivalent element of its superset. Read more
Source§

fn is_in_subset(&self) -> bool

Checks if self is actually part of its subset T (and can be converted to it).
Source§

fn to_subset_unchecked(&self) -> SS

Use with care! Same as self.to_subset but without any property checks. Always succeeds.
Source§

fn from_subset(element: &SS) -> SP

The inclusion map: converts self to the equivalent element of its superset.
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