Trait Driver

Source
pub trait Driver
where Self: DriverExt,
{ // Required method fn solve(self) -> Result<(Self::Algo, Step), DriverError> where Self: Sized; // Provided methods fn test() where Self: Sized { ... } fn try_on_step<F, E>(self, f: F) -> TryForEachDriver<Self, F> where F: FnMut(&mut Self::Algo, &Step) -> Result<(), E>, E: Error + Sync + Send + 'static, Self: Sized { ... } fn on_step<F>(self, f: F) -> ForEachDriver<Self, F> where Self: Sized, F: FnMut(&mut Self::Algo, &Step) { ... } fn converge_when<F>(self, pred: F) -> ConvergedWhenDriver<Self, F> where Self: Sized, F: FnMut(&mut Self::Algo, &Step) -> bool { ... } fn fail_if<F>(self, pred: F) -> FailIfDriver<Self, F> where Self: Sized, F: FnMut(&mut Self::Algo, &Step) -> bool { ... } fn show_progress_bar_after(self, after: Duration) -> ProgressBarDriver<Self> where Self: Sized { ... } fn into_boxed(self) -> Box<dyn Driver<Algo = Self::Algo>> where Self: Sized + 'static { ... } }
Expand description

The executor that controls an algorithm’s iteration, and early stopping.

Drivers are created by factory methods: fixed_iters, fail_after_iters, with_timeout

The Driver consumes the algorithm during factory construction, but mutably lends it back during iteration in on_step and converge_when, and finally returns the algorithm back to the caller after solving.

Required Methods§

Source

fn solve(self) -> Result<(Self::Algo, Step), DriverError>
where Self: Sized,

Runs the algorithm, until failure, iteration exhaustion, or convergence.

In cases of success, the algo in its final state and the final iteration step is returned.

By convention, the algo variable in its final state is named solved, and will offer accessors to retrieve the solution or best approximation to the solution.

§Example

let (solved, _step) = fixed_iters(my_algo, 1000)
    .on_step(|_algo, step| println!("{step:?}"))
    .solve()?;

assert_approx_eq!(solved.x(),  &vec![1.5, 2.0] );

Provided Methods§

Source

fn test()
where Self: Sized,

Source

fn try_on_step<F, E>(self, f: F) -> TryForEachDriver<Self, F>
where F: FnMut(&mut Self::Algo, &Step) -> Result<(), E>, E: Error + Sync + Send + 'static, Self: Sized,

Invoked after each iteration, allowing printing or debugging of the iteration step. Can be used to capture details of the iteration. See Self::try_on_step.

Source

fn on_step<F>(self, f: F) -> ForEachDriver<Self, F>
where Self: Sized, F: FnMut(&mut Self::Algo, &Step),

Invoked after each iteration, allowing printing or debugging of the iteration Step. Any errors encountered by the underlying algorithm will terminate the solving, and Self::solve will return the error.

Can be used to capture details of the iteration, or update hyperparameters on the algorithm for adaptive learning.

Source

fn converge_when<F>(self, pred: F) -> ConvergedWhenDriver<Self, F>
where Self: Sized, F: FnMut(&mut Self::Algo, &Step) -> bool,

Used for early stopping.

Common convergence predicates are step size below a small epsilon, or residuals being below near zero. Some specific convergence criteria are best handled by using metrics within this callback.

Source

fn fail_if<F>(self, pred: F) -> FailIfDriver<Self, F>
where Self: Sized, F: FnMut(&mut Self::Algo, &Step) -> bool,

Decide when to abandon iteration with Self::solve returning DriverError::FailIfPredicate.

Convergence predicates are tested first.

Common failure predicates are residuals growing in size after an initial set of iterations, or user cancelation - implemented perhaps by the closure predicate checking the value of an AtomicBool.

Source

fn show_progress_bar_after(self, after: Duration) -> ProgressBarDriver<Self>
where Self: Sized,

Display a progress bar to the terminal after the algo has been running for this duration.

Use Duration::MAX to disable the progress bar, and Duration::ZERO to display it immediately. The progress bar will refresh at most every 50ms.

The progress bar will not display if either:

  • stdout is not a terminal (perhaps redirected to a ulility or file)
  • the environment variable NO_COLOR is set
  • the elapsed time never reaches the duration set by this function
§Example
let solution = fixed_iters(my_algo, 1000)
    // show a progress bar if the algo is slow to execute
    .show_progress_bar_after(Duration::from_millis(250))  
    .solve()?;
Source

fn into_boxed(self) -> Box<dyn Driver<Algo = Self::Algo>>
where Self: Sized + 'static,

Convenience method for when you want to dynamically type.

§Examples

The following wont compile as the if/then arms have different types…

let driver = if log_enabled {
    fixed_iters(my_algo, 100).on_step(|_, step| println!("{step:?}"))
} else {
    fixed_iters(my_algo, 100)
};

Boxing a dyn trait gets around this…

let log_enabled = true;
let driver = if log_enabled {
    fixed_iters(my_algo, 100).on_step(|_, step| println!("{step:?}")).into_boxed()
} else {
    fixed_iters(my_algo, 100).into_boxed()
};
// driver is type Box<dyn Driver>
let (my_algo, _step) = driver.show_progress_bar_after(Duration::ZERO).solve()?;

Implementors§

Source§

impl<S, T> Driver for T
where T: DriverExt<Algo = S>, S: Algo,