Crate parametric

Crate parametric 

Source
Expand description

A bridge between complex data structures and flat parameter vectors.

The parametric crate solves the “impedance mismatch” between complex, hierarchical models (like neural networks or physics simulations) and optimization algorithms that operate on a simple, flat Vec<f64> of parameters.

It allows you to define your model’s structure once, generically, and then use that single definition to specify parameter search spaces, create runnable instances, and seamlessly update parameters during optimization.

§Getting Started: A Complete Example

Let’s walk through a typical workflow.

use parametric::{Parametric, extract_map_defaults, inject_from_slice};

// Define a model structure with a generic parameter `P`.
// The `Parametric` trait can be derived for any struct whose fields
// are also `Parametric`.
#[derive(Parametric, Debug, PartialEq)]
struct Model<P> {
    weights: Vec<P>,
    bias: P,

    // You can skip fields containing auxiliary data.
    // These fields are moved (not cloned) during `map` operation.
    #[parametric(skip)]
    metadata: String,
}

// 1. Define the search space for the model using a parameter type like `Range`.
let search_space = Model {
    weights: vec![0.0..10.0, -5.0..5.0],
    bias: -1.0..1.0,

    // The auxiliary data is included here.
    metadata: "Example Model v1".to_string(),
};

// 2. Use `extract_map_defaults` to separate the definition into two parts:
//    - A flat `Vec` of parameter specifications (the ranges) for the optimizer.
//    - A runnable model instance with a concrete type (e.g., `f64`) initialized
//      to default values.
let (mut runnable_model, flat_space) = extract_map_defaults::<f64, _>(search_space);

assert_eq!(flat_space, vec![0.0..10.0, -5.0..5.0, -1.0..1.0]);
assert_eq!(
    runnable_model,
    Model {
        weights: vec![0.0, 0.0],
        bias: 0.0,
        metadata: "Example Model v1".to_string()
    }
);

// 3. Inside an optimization loop, an algorithm proposes a new flat vector of parameters.
let new_params = vec![8.5, -2.0, 0.5];

// 4. Use `inject_from_slice` to update the structured model with the new parameters.
//    This is the "injection" step, turning the flat vector back into a structured model.
inject_from_slice(&mut runnable_model, &new_params).unwrap();

assert_eq!(
    runnable_model,
    Model {
        weights: vec![8.5, -2.0],
        bias: 0.5,
        metadata: "Example Model v1".to_string()
    }
);

// Now `runnable_model` can be used to evaluate the cost function.

§The Core Idea

§The Challenge

Optimization algorithms typically require parameters as a flat Vec<f64>, but real-world models have nested, meaningful structures. This forces developers to write tedious and error-prone boilerplate for:

  1. Flattening: Manually converting a structured model into a flat vector.
  2. Injection: Writing the reverse logic to update the model from a flat vector inside the optimization loop.
  3. Maintenance: Meticulously updating both flattening and injection code every time the model’s architecture changes.

§The parametric Solution

This crate automates the mapping between your structured types and a flat representation. The core is the Parametric trait, which provides a generic way to traverse a data structure and apply a function to each of its parameters.

By deriving Parametric on a generic struct like Model<P>, you can instantiate it for different purposes:

  • Model<Range<f64>>: Defines the search space for each parameter.
  • Model<f64>: Creates a runnable instance with concrete values.
  • Model<i32>, Model<bool>, …: Holds any other type you need. This allows you to use the same model definition for discrete parameters, configuration flags, or other metadata, not just floating-point values.

Helper functions like extract_map_defaults and inject_from_slice use the Parametric trait to provide the bridge to the optimizer, eliminating boilerplate, reducing errors, and cleanly decoupling the model’s architecture from its parameterization.

Macros§

impl_arg
Allows this type to be the target of a map operation from any source type, e.g. Parametric::map(|any: T| -> Self { /* ... */ })

Traits§

Parametric
A trait for types whose parameters can be collectively transformed or visited.

Functions§

extract_map_defaults
Separates a parametric structure into a flat vector of its parameters and a new structure containing default values.
fork_map
A low-level utility that maps a parametric structure while extracting a second set of values.
inject_from_iter
Updates the parameters of a model in-place from an iterator.
inject_from_slice
Updates the parameters of a model in-place from a flat slice.

Derive Macros§

Parametric