pub trait Driverwhere
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§
Sourcefn solve(self) -> Result<(Self::Algo, Step), DriverError>where
Self: Sized,
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§
fn test()where
Self: Sized,
Sourcefn try_on_step<F, E>(self, f: F) -> TryForEachDriver<Self, F>
fn try_on_step<F, E>(self, f: F) -> TryForEachDriver<Self, F>
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
.
Sourcefn on_step<F>(self, f: F) -> ForEachDriver<Self, F>
fn on_step<F>(self, f: F) -> ForEachDriver<Self, F>
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.
Sourcefn converge_when<F>(self, pred: F) -> ConvergedWhenDriver<Self, F>
fn converge_when<F>(self, pred: F) -> ConvergedWhenDriver<Self, F>
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.
Sourcefn fail_if<F>(self, pred: F) -> FailIfDriver<Self, F>
fn fail_if<F>(self, pred: F) -> FailIfDriver<Self, F>
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
.
Sourcefn show_progress_bar_after(self, after: Duration) -> ProgressBarDriver<Self>where
Self: Sized,
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()?;
Sourcefn into_boxed(self) -> Box<dyn Driver<Algo = Self::Algo>>where
Self: Sized + 'static,
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()?;