Skip to main content

optimizer/
lib.rs

1//! A Tree-Parzen Estimator (TPE) library for black-box optimization.
2//!
3//! This library provides an Optuna-like API for hyperparameter optimization
4//! using the Tree-Parzen Estimator algorithm. It supports:
5//!
6//! - Float, integer, and categorical parameter types
7//! - Log-scale and stepped parameter sampling
8//! - Synchronous and async optimization
9//! - Parallel trial evaluation with bounded concurrency
10//! - Serialization for saving/loading study state
11//!
12//! # Quick Start
13//!
14//! ```
15//! use optimizer::{Direction, Study, TpeSampler};
16//!
17//! // Create a study with TPE sampler
18//! let sampler = TpeSampler::builder().seed(42).build();
19//! let study: Study<f64> = Study::with_sampler(Direction::Minimize, sampler);
20//!
21//! // Optimize x^2 for 20 trials
22//! study
23//!     .optimize_with_sampler(20, |trial| {
24//!         let x = trial.suggest_float("x", -10.0, 10.0)?;
25//!         Ok::<_, optimizer::TpeError>(x * x)
26//!     })
27//!     .unwrap();
28//!
29//! // Get the best result
30//! let best = study.best_trial().unwrap();
31//! println!("Best value: {} at x={:?}", best.value, best.params);
32//! ```
33//!
34//! # Creating a Study
35//!
36//! A [`Study`] manages optimization trials. Create one with an optimization direction:
37//!
38//! ```
39//! use optimizer::{Direction, RandomSampler, Study, TpeSampler};
40//!
41//! // Minimize with default random sampler
42//! let study: Study<f64> = Study::new(Direction::Minimize);
43//!
44//! // Maximize with TPE sampler
45//! let study: Study<f64> = Study::with_sampler(Direction::Maximize, TpeSampler::new());
46//!
47//! // With seeded sampler for reproducibility
48//! let study: Study<f64> = Study::with_sampler(Direction::Minimize, RandomSampler::with_seed(42));
49//! ```
50//!
51//! # Suggesting Parameters
52//!
53//! Within the objective function, use [`Trial`] to suggest parameter values:
54//!
55//! ```
56//! use optimizer::{Direction, Study};
57//!
58//! let study: Study<f64> = Study::new(Direction::Minimize);
59//!
60//! study
61//!     .optimize(10, |trial| {
62//!         // Float parameters
63//!         let x = trial.suggest_float("x", 0.0, 1.0)?;
64//!         let lr = trial.suggest_float_log("learning_rate", 1e-5, 1e-1)?;
65//!         let step = trial.suggest_float_step("step", 0.0, 1.0, 0.1)?;
66//!
67//!         // Integer parameters
68//!         let n = trial.suggest_int("n_layers", 1, 10)?;
69//!         let batch = trial.suggest_int_log("batch_size", 16, 256)?;
70//!         let units = trial.suggest_int_step("units", 32, 512, 32)?;
71//!
72//!         // Categorical parameters
73//!         let optimizer = trial.suggest_categorical("optimizer", &["sgd", "adam", "rmsprop"])?;
74//!
75//!         // Return objective value
76//!         Ok::<_, optimizer::TpeError>(x * n as f64)
77//!     })
78//!     .unwrap();
79//! ```
80//!
81//! # Configuring TPE
82//!
83//! The [`TpeSampler`] can be configured using the builder pattern:
84//!
85//! ```
86//! use optimizer::TpeSampler;
87//!
88//! let sampler = TpeSampler::builder()
89//!     .gamma(0.15)           // Quantile for good/bad split
90//!     .n_startup_trials(20)  // Random trials before TPE
91//!     .n_ei_candidates(32)   // Candidates to evaluate
92//!     .seed(42)              // Reproducibility
93//!     .build();
94//! ```
95//!
96//! # Async and Parallel Optimization
97//!
98//! With the `async` feature enabled, you can run trials asynchronously:
99//!
100//! ```ignore
101//! use optimizer::{Study, Direction};
102//!
103//! // Sequential async
104//! study.optimize_async(10, |mut trial| async move {
105//!     let x = trial.suggest_float("x", 0.0, 1.0)?;
106//!     Ok((trial, x * x))
107//! }).await?;
108//!
109//! // Parallel with bounded concurrency
110//! study.optimize_parallel(10, 4, |mut trial| async move {
111//!     let x = trial.suggest_float("x", 0.0, 1.0)?;
112//!     Ok((trial, x * x))
113//! }).await?;
114//! ```
115//!
116//! # Serialization
117//!
118//! With the `serde` feature enabled, studies can be serialized:
119//!
120//! ```ignore
121//! use optimizer::{Study, Direction, TpeSampler};
122//!
123//! // Save study state
124//! let study: Study<f64> = Study::new(Direction::Minimize);
125//! let json = serde_json::to_string(&study)?;
126//!
127//! // Load and continue
128//! let mut study: Study<f64> = serde_json::from_str(&json)?;
129//! study.set_sampler(TpeSampler::new());  // Restore sampler
130//! study.optimize_with_sampler(10, |trial| { /* ... */ }).unwrap();
131//! ```
132//!
133//! # Feature Flags
134//!
135//! - `serde`: Enable serialization/deserialization of studies and trials
136//! - `async`: Enable async optimization methods (requires tokio)
137
138mod distribution;
139mod error;
140mod kde;
141mod param;
142mod sampler;
143mod study;
144mod trial;
145mod types;
146
147pub use error::{Result, TpeError};
148pub use sampler::{CompletedTrial, RandomSampler, Sampler, TpeSampler, TpeSamplerBuilder};
149pub use study::Study;
150pub use trial::Trial;
151pub use types::{Direction, TrialState};