Crate stepwise

Source
Expand description

Latest version Documentation License MSRV

§Overview

The stepwise crate is a zero-dependency helper library for writing iterative algorithms.
It supports both numeric techniques—such as gradient descent, fixed-point iteration, Newton–Raphson—and non-numeric stepwise processes, like line-by-line file parsing or tree search.

With stepwise, you can:

  • Use the Driver executor in a functional, iterator-like style to configure:
    • iteration limits, timeouts, convergence criteria,
    • logging, and
    • terminal progress bars.
  • Control early stopping using metrics that compute moving averages, absolute/relative differences, invocation counts, or detect stalled solvers.
  • Use included mini linear algebra functions for computing norms and distances.
  • Collect structured data using samplers for ML training, convergence analysis, or plotting.
  • Benchmark your own solvers on a suite of problems, and compare them with the built-in algorithms.

driver | algorithms | metrics | linear algebra functions | samplers | problems


§Example 1

use stepwise::{Driver as _, fixed_iters, assert_approx_eq}; 
use stepwise::algos::GradientDescent;

let sphere_gradient = |x: &[f64]| vec![2.0 * x[0], 2.0 * x[1]];
let learning_rate = 0.1;
let initial_guess = vec![5.5, 6.5];

let algo = GradientDescent::new(learning_rate, initial_guess, sphere_gradient);

let (solved, step) = fixed_iters(algo, 1000).solve().expect("solving failed!");

assert_approx_eq!(solved.x(), &[0.0, 0.0]);

§Example 2

use std::time::Duration;
use stepwise::prelude::*;

let gd = algos::GradientDescent::new(0.01, vec![1.0, 2.0], problems::sphere_grad);

let mut avg_of_norm = metrics::Ema::with_window(10);

let (solved, step) = fail_after_iters(gd, 10_000)
    .converge_when(|algo, _step| avg_of_norm.observe(algo.gradient.norm_l2()) < 1e-10)
    .show_progress_bar_after(Duration::from_millis(20))
    .on_step(|algo, _step| algo.learning_rate *= 0.9999)
    .solve()
    .expect("solving failed!");

assert_approx_eq!(solved.x(), &[0.0, 0.0]);
assert_eq!(step.iteration(), 1301);

In Example 2 (above):

  • Early stopping is used to terminate the algorithm
  • An exponential moving average of gradient’s l2-norm is used to test it is near zero.
  • A progress bar is also printed in the terminal if algorithm runs for more than 20ms.
  • The stepwise prelude is used to import both the metrics and the linear algebra trait
  • A decaying learning rate is applied after each step.

§Creating an Algorithm

Callers will typically interact with your algorithm through the Driver trait.
However, to integrate with stepwise, you must implement the core Algo trait for your algorithm.

This involves defining a single method:

  • step(): returns a tuple of:
    • a ControlFlow, indicating whether iteration should continue or stop
    • a Result, capturing any error that may occur during a step

This design separates control flow from failure, supporting fallible solvers with clean early-stopping logic.

Note: accessor methods like x() (for current state) are not part of the trait, but are expected in usable solvers, in order to retrieve the solution after or during iteration.

use std::{error::Error, ops::ControlFlow};

pub trait Algo {
    type Error: Send + Sync + Error + 'static;

    fn step(&mut self) -> (ControlFlow<()>, Result<(), Self::Error>);

    // <default methods omitted>
}

Modules§

algos
A collection of sample algorithms
metrics
Metrics collect maximums, averages etc, for use as convergence criteria.
prelude
Use stepwise::prelude::* for a ‘no fuss’ include everything approach.
problems
Sample problems for testing optimization, along with their gradient functions
samplers
Samplers are containers for sampling data or convergence trajectories; or recording epochs/iterations for later tabulation, plotting or analysis.

Macros§

assert_approx_eq
Assert that two values are approximately equal.
assert_approx_ne
Assert that two values are comparable, but approximately not-equal.
log_trace

Structs§

Step
A small struct that holds iteration count, elapsed time etc for each algorithm step. The elapsed time is calculated on first call or on Clone.

Enums§

DriverError
FileFormat
Used internally by algorithms to determine whether they can support writing a checkpoint file of the designated type.
RecoveryFile
Determines recovery behaviour for Driver::recovery.

Traits§

Algo
Algorithms implement this trait to work with the library.
Driver
An executor for the algorithm controlling max iterations, execution time, convergence criteria, and callbacks.
VectorExt
Basic linear algebra functions.

Functions§

central_difference_gradient
Calculate the gradient of a function using central differences.
fail_after_iters
Constructs a Driver that will fail once a certain number of iterations is reached.
fixed_iters
Constructs a Driver with a fixed number of iterations
format_duration
Formats a duration in the form 05h-02m-07s-045ms
with_timeout
Constructs a Driver that will fail after an elased duration.

Type Aliases§

BoxedDriver
BoxedError
DynDriver