diff --git a/benches/optimization.rs b/benches/optimization.rs index c4f58dc..cfdaafe 100644 --- a/benches/optimization.rs +++ b/benches/optimization.rs @@ -2,10 +2,10 @@ mod test_functions; use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main}; -use optimizer::parameter::Parameter; +use optimizer::Study; +use optimizer::parameter::{FloatParam, Parameter}; use optimizer::sampler::random::RandomSampler; use optimizer::sampler::tpe::TpeSampler; -use optimizer::{FloatParam, Study}; fn make_params(dims: usize) -> Vec { (0..dims) diff --git a/benches/samplers.rs b/benches/samplers.rs index f2e9ec3..79da8a6 100644 --- a/benches/samplers.rs +++ b/benches/samplers.rs @@ -1,12 +1,11 @@ use std::collections::HashMap; use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main}; -use optimizer::parameter::Parameter; -use optimizer::sampler::Sampler; +use optimizer::parameter::{FloatParam, Parameter}; use optimizer::sampler::grid::GridSearchSampler; use optimizer::sampler::random::RandomSampler; use optimizer::sampler::tpe::TpeSampler; -use optimizer::{CompletedTrial, FloatParam}; +use optimizer::sampler::{CompletedTrial, Sampler}; /// Build a synthetic history of `n` completed trials over `dims` float parameters. fn build_history(n: usize, dims: usize) -> Vec> { @@ -33,7 +32,7 @@ fn build_history(n: usize, dims: usize) -> Vec> { let value: f64 = param_values .values() .map(|v| { - let optimizer::ParamValue::Float(f) = v else { + let optimizer::parameter::ParamValue::Float(f) = v else { unreachable!() }; f * f diff --git a/optimizer-derive/src/lib.rs b/optimizer-derive/src/lib.rs index 4d019f9..3e30885 100644 --- a/optimizer-derive/src/lib.rs +++ b/optimizer-derive/src/lib.rs @@ -4,13 +4,13 @@ use syn::{Data, DeriveInput, Fields, parse_macro_input}; /// Derive macro for the `Categorical` trait on fieldless enums. /// -/// Generates an implementation of `optimizer::Categorical` that maps +/// Generates an implementation of `optimizer::parameter::Categorical` that maps /// enum variants to/from sequential indices. /// /// # Example /// /// ```ignore -/// use optimizer::Categorical; +/// use optimizer::parameter::Categorical; /// /// #[derive(Clone, Categorical)] /// enum Color { @@ -49,7 +49,7 @@ pub fn derive_categorical(input: TokenStream) -> TokenStream { let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); let expanded = quote! { - impl #impl_generics optimizer::Categorical for #name #ty_generics #where_clause { + impl #impl_generics optimizer::parameter::Categorical for #name #ty_generics #where_clause { const N_CHOICES: usize = #n_choices; fn from_index(index: usize) -> Self { diff --git a/src/lib.rs b/src/lib.rs index 8df4aec..0636f54 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,7 +42,7 @@ //! |------|------| //! | [`Study`] | Drive an optimization loop: create trials, record results, track the best. | //! | [`Trial`] | A single evaluation of the objective function, carrying suggested parameter values. | -//! | [`Parameter`] | Define the search space — [`FloatParam`], [`IntParam`], [`CategoricalParam`], [`BoolParam`], [`EnumParam`]. | +//! | [`Parameter`](parameter::Parameter) | Define the search space — [`FloatParam`](parameter::FloatParam), [`IntParam`](parameter::IntParam), [`CategoricalParam`](parameter::CategoricalParam), [`BoolParam`](parameter::BoolParam), [`EnumParam`](parameter::EnumParam). | //! | [`Sampler`](sampler::Sampler) | Strategy for choosing the next point to evaluate (TPE, CMA-ES, random, etc.). | //! | [`Direction`] | Whether the study minimizes or maximizes the objective value. | //! @@ -52,23 +52,23 @@ //! //! | Sampler | Algorithm | Best for | Feature flag | //! |---------|-----------|----------|--------------| -//! | [`RandomSampler`] | Uniform random | Baselines, high-dimensional | — | -//! | [`TpeSampler`] | Tree-Parzen Estimator | General-purpose Bayesian | — | -//! | [`GridSearchSampler`] | Exhaustive grid | Small, discrete spaces | — | -//! | [`SobolSampler`] | Sobol quasi-random sequence | Space-filling, low dimensions | `sobol` | -//! | [`CmaEsSampler`] | CMA-ES | Continuous, moderate dimensions | `cma-es` | -//! | [`GpSampler`] | Gaussian Process + EI | Expensive objectives, few trials | `gp` | -//! | [`DifferentialEvolutionSampler`] | Differential Evolution | Non-convex, population-based | — | -//! | [`BohbSampler`] | BOHB (TPE + `HyperBand`) | Budget-aware early stopping | — | +//! | [`RandomSampler`](sampler::RandomSampler) | Uniform random | Baselines, high-dimensional | — | +//! | [`TpeSampler`](sampler::TpeSampler) | Tree-Parzen Estimator | General-purpose Bayesian | — | +//! | [`GridSearchSampler`](sampler::GridSearchSampler) | Exhaustive grid | Small, discrete spaces | — | +//! | [`SobolSampler`](sampler::SobolSampler) | Sobol quasi-random sequence | Space-filling, low dimensions | `sobol` | +//! | [`CmaEsSampler`](sampler::CmaEsSampler) | CMA-ES | Continuous, moderate dimensions | `cma-es` | +//! | [`GpSampler`](sampler::GpSampler) | Gaussian Process + EI | Expensive objectives, few trials | `gp` | +//! | [`DifferentialEvolutionSampler`](sampler::DifferentialEvolutionSampler) | Differential Evolution | Non-convex, population-based | — | +//! | [`BohbSampler`](sampler::BohbSampler) | BOHB (TPE + `HyperBand`) | Budget-aware early stopping | — | //! //! ## Multi-objective samplers //! //! | Sampler | Algorithm | Best for | Feature flag | //! |---------|-----------|----------|--------------| -//! | [`Nsga2Sampler`] | NSGA-II | 2-3 objectives | — | -//! | [`Nsga3Sampler`] | NSGA-III (reference-point) | 3+ objectives | — | -//! | [`MoeadSampler`] | MOEA/D (decomposition) | Many objectives, structured fronts | — | -//! | [`MotpeSampler`] | Multi-Objective TPE | Bayesian multi-objective | — | +//! | [`Nsga2Sampler`](sampler::Nsga2Sampler) | NSGA-II | 2-3 objectives | — | +//! | [`Nsga3Sampler`](sampler::Nsga3Sampler) | NSGA-III (reference-point) | 3+ objectives | — | +//! | [`MoeadSampler`](sampler::MoeadSampler) | MOEA/D (decomposition) | Many objectives, structured fronts | — | +//! | [`MotpeSampler`](sampler::MotpeSampler) | Multi-Objective TPE | Bayesian multi-objective | — | //! //! # Feature Flags //! @@ -77,10 +77,10 @@ //! | `async` | Async/parallel optimization via tokio ([`Study::optimize_async`], [`Study::optimize_parallel`]) | off | //! | `derive` | `#[derive(Categorical)]` for enum parameters | off | //! | `serde` | `Serialize`/`Deserialize` on public types, [`Study::save`]/[`Study::load`] | off | -//! | `journal` | [`JournalStorage`] — JSONL persistence with file locking (enables `serde`) | off | -//! | `sobol` | [`SobolSampler`] — quasi-random low-discrepancy sequences | off | -//! | `cma-es` | [`CmaEsSampler`] — Covariance Matrix Adaptation Evolution Strategy | off | -//! | `gp` | [`GpSampler`] — Gaussian Process surrogate with Expected Improvement | off | +//! | `journal` | [`JournalStorage`](storage::JournalStorage) — JSONL persistence with file locking (enables `serde`) | off | +//! | `sobol` | [`SobolSampler`](sampler::SobolSampler) — quasi-random low-discrepancy sequences | off | +//! | `cma-es` | [`CmaEsSampler`](sampler::CmaEsSampler) — Covariance Matrix Adaptation Evolution Strategy | off | +//! | `gp` | [`GpSampler`](sampler::GpSampler) — Gaussian Process surrogate with Expected Improvement | off | //! | `tracing` | Structured log events via [`tracing`](https://docs.rs/tracing) at key optimization points | off | /// Emit a `tracing::info!` event when the `tracing` feature is enabled. @@ -127,38 +127,8 @@ mod visualization; pub use error::{Error, Result, TrialPruned}; pub use fanova::{FanovaConfig, FanovaResult}; -pub use multi_objective::{MultiObjectiveSampler, MultiObjectiveStudy, MultiObjectiveTrial}; #[cfg(feature = "derive")] pub use optimizer_derive::Categorical; -pub use param::ParamValue; -pub use parameter::{ - BoolParam, Categorical, CategoricalParam, EnumParam, FloatParam, IntParam, ParamId, Parameter, -}; -pub use pruner::{ - HyperbandPruner, MedianPruner, NopPruner, PatientPruner, PercentilePruner, Pruner, - SuccessiveHalvingPruner, ThresholdPruner, WilcoxonPruner, -}; -pub use sampler::CompletedTrial; -pub use sampler::bohb::BohbSampler; -#[cfg(feature = "cma-es")] -pub use sampler::cma_es::CmaEsSampler; -pub use sampler::differential_evolution::{ - DifferentialEvolutionSampler, DifferentialEvolutionStrategy, -}; -#[cfg(feature = "gp")] -pub use sampler::gp::GpSampler; -pub use sampler::grid::GridSearchSampler; -pub use sampler::moead::{Decomposition, MoeadSampler}; -pub use sampler::motpe::MotpeSampler; -pub use sampler::nsga2::Nsga2Sampler; -pub use sampler::nsga3::Nsga3Sampler; -pub use sampler::random::RandomSampler; -#[cfg(feature = "sobol")] -pub use sampler::sobol::SobolSampler; -pub use sampler::tpe::TpeSampler; -#[cfg(feature = "journal")] -pub use storage::JournalStorage; -pub use storage::{MemoryStorage, Storage}; #[cfg(feature = "serde")] pub use study::StudySnapshot; pub use study::{Study, StudyBuilder}; @@ -177,33 +147,28 @@ pub mod prelude { pub use crate::error::{Error, Result, TrialPruned}; pub use crate::fanova::{FanovaConfig, FanovaResult}; - pub use crate::multi_objective::{MultiObjectiveStudy, MultiObjectiveTrial}; - pub use crate::param::ParamValue; + pub use crate::multi_objective::{ + MultiObjectiveSampler, MultiObjectiveStudy, MultiObjectiveTrial, + }; pub use crate::parameter::{ - BoolParam, Categorical, CategoricalParam, EnumParam, FloatParam, IntParam, Parameter, + BoolParam, Categorical, CategoricalParam, EnumParam, FloatParam, IntParam, ParamValue, + Parameter, }; pub use crate::pruner::{ HyperbandPruner, MedianPruner, NopPruner, PatientPruner, PercentilePruner, Pruner, - SuccessiveHalvingPruner, ThresholdPruner, + SuccessiveHalvingPruner, ThresholdPruner, WilcoxonPruner, }; - pub use crate::sampler::CompletedTrial; - pub use crate::sampler::bohb::BohbSampler; #[cfg(feature = "cma-es")] - pub use crate::sampler::cma_es::CmaEsSampler; - pub use crate::sampler::differential_evolution::{ - DifferentialEvolutionSampler, DifferentialEvolutionStrategy, - }; + pub use crate::sampler::CmaEsSampler; #[cfg(feature = "gp")] - pub use crate::sampler::gp::GpSampler; - pub use crate::sampler::grid::GridSearchSampler; - pub use crate::sampler::moead::{Decomposition, MoeadSampler}; - pub use crate::sampler::motpe::MotpeSampler; - pub use crate::sampler::nsga2::Nsga2Sampler; - pub use crate::sampler::nsga3::Nsga3Sampler; - pub use crate::sampler::random::RandomSampler; + pub use crate::sampler::GpSampler; #[cfg(feature = "sobol")] - pub use crate::sampler::sobol::SobolSampler; - pub use crate::sampler::tpe::TpeSampler; + pub use crate::sampler::SobolSampler; + pub use crate::sampler::{ + BohbSampler, CompletedTrial, Decomposition, DifferentialEvolutionSampler, + DifferentialEvolutionStrategy, GridSearchSampler, MoeadSampler, MotpeSampler, Nsga2Sampler, + Nsga3Sampler, RandomSampler, TpeSampler, + }; #[cfg(feature = "journal")] pub use crate::storage::JournalStorage; pub use crate::storage::{MemoryStorage, Storage}; diff --git a/src/multi_objective.rs b/src/multi_objective.rs index d47ce37..8dd144a 100644 --- a/src/multi_objective.rs +++ b/src/multi_objective.rs @@ -19,9 +19,9 @@ //! # Samplers //! //! By default a random sampler is used. For smarter search, pass a -//! [`MultiObjectiveSampler`] such as [`Nsga2Sampler`](crate::Nsga2Sampler), -//! [`Nsga3Sampler`](crate::Nsga3Sampler), or -//! [`MoeadSampler`](crate::MoeadSampler) via +//! [`MultiObjectiveSampler`] such as [`Nsga2Sampler`](crate::sampler::Nsga2Sampler), +//! [`Nsga3Sampler`](crate::sampler::Nsga3Sampler), or +//! [`MoeadSampler`](crate::sampler::MoeadSampler) via //! [`MultiObjectiveStudy::with_sampler`]. //! //! # Examples @@ -140,9 +140,9 @@ impl MultiObjectiveTrial { /// (`&[MultiObjectiveTrial]`) and the per-objective directions /// (`&[Direction]`). /// -/// Implementations include [`Nsga2Sampler`](crate::Nsga2Sampler), -/// [`Nsga3Sampler`](crate::Nsga3Sampler), and -/// [`MoeadSampler`](crate::MoeadSampler). +/// Implementations include [`Nsga2Sampler`](crate::sampler::Nsga2Sampler), +/// [`Nsga3Sampler`](crate::sampler::Nsga3Sampler), and +/// [`MoeadSampler`](crate::sampler::MoeadSampler). pub trait MultiObjectiveSampler: Send + Sync { /// Samples a parameter value from the given distribution. fn sample( diff --git a/src/parameter.rs b/src/parameter.rs index 6c48931..c266034 100644 --- a/src/parameter.rs +++ b/src/parameter.rs @@ -46,7 +46,7 @@ use crate::distribution::{ CategoricalDistribution, Distribution, FloatDistribution, IntDistribution, }; use crate::error::{Error, Result}; -use crate::param::ParamValue; +pub use crate::param::ParamValue; use crate::trial::Trial; static NEXT_PARAM_ID: AtomicU64 = AtomicU64::new(0); diff --git a/src/pareto.rs b/src/pareto.rs index c6a23c9..a7b321d 100644 --- a/src/pareto.rs +++ b/src/pareto.rs @@ -29,8 +29,8 @@ //! //! Internally, this module also provides the fast non-dominated sorting //! algorithm (Deb et al., 2002) used by -//! [`MultiObjectiveStudy::pareto_front()`](crate::MultiObjectiveStudy::pareto_front) -//! and [`Nsga2Sampler`](crate::Nsga2Sampler). +//! [`MultiObjectiveStudy::pareto_front()`](crate::multi_objective::MultiObjectiveStudy::pareto_front) +//! and [`Nsga2Sampler`](crate::sampler::Nsga2Sampler). //! //! # Example //! diff --git a/src/pruner/hyperband.rs b/src/pruner/hyperband.rs index ac82acf..697ea6c 100644 --- a/src/pruner/hyperband.rs +++ b/src/pruner/hyperband.rs @@ -317,7 +317,7 @@ mod tests { CompletedTrial::with_intermediate_values( id, - HashMap::::new(), + HashMap::::new(), HashMap::new(), HashMap::new(), 0.0, diff --git a/src/pruner/percentile.rs b/src/pruner/percentile.rs index 0495b6b..f12df01 100644 --- a/src/pruner/percentile.rs +++ b/src/pruner/percentile.rs @@ -233,7 +233,7 @@ mod tests { CompletedTrial::with_intermediate_values( id, - HashMap::::new(), + HashMap::::new(), HashMap::new(), HashMap::new(), 0.0, diff --git a/src/pruner/successive_halving.rs b/src/pruner/successive_halving.rs index 0408101..64d8791 100644 --- a/src/pruner/successive_halving.rs +++ b/src/pruner/successive_halving.rs @@ -285,7 +285,7 @@ mod tests { CompletedTrial::with_intermediate_values( id, - HashMap::::new(), + HashMap::::new(), HashMap::new(), HashMap::new(), 0.0, diff --git a/src/sampler/differential_evolution.rs b/src/sampler/de.rs similarity index 98% rename from src/sampler/differential_evolution.rs rename to src/sampler/de.rs index 3a11e55..7641084 100644 --- a/src/sampler/differential_evolution.rs +++ b/src/sampler/de.rs @@ -46,9 +46,7 @@ //! # Examples //! //! ``` -//! use optimizer::sampler::differential_evolution::{ -//! DifferentialEvolutionSampler, DifferentialEvolutionStrategy, -//! }; +//! use optimizer::sampler::de::{DifferentialEvolutionSampler, DifferentialEvolutionStrategy}; //! use optimizer::{Direction, Study}; //! //! // Minimize with DE using the Best1 strategy for faster convergence @@ -101,7 +99,7 @@ pub enum DifferentialEvolutionStrategy { /// # Examples /// /// ``` -/// use optimizer::sampler::differential_evolution::DifferentialEvolutionSampler; +/// use optimizer::sampler::de::DifferentialEvolutionSampler; /// use optimizer::{Direction, Study}; /// /// // Default configuration @@ -115,7 +113,7 @@ pub enum DifferentialEvolutionStrategy { /// ); /// /// // Custom configuration via builder -/// use optimizer::sampler::differential_evolution::DifferentialEvolutionStrategy; +/// use optimizer::sampler::de::DifferentialEvolutionStrategy; /// let sampler = DifferentialEvolutionSampler::builder() /// .mutation_factor(0.8) /// .crossover_rate(0.9) @@ -183,7 +181,7 @@ impl Default for DifferentialEvolutionSampler { /// # Examples /// /// ``` -/// use optimizer::sampler::differential_evolution::{ +/// use optimizer::sampler::de::{ /// DifferentialEvolutionSamplerBuilder, DifferentialEvolutionStrategy, /// }; /// diff --git a/src/sampler/mod.rs b/src/sampler/mod.rs index e1813e0..b512c49 100644 --- a/src/sampler/mod.rs +++ b/src/sampler/mod.rs @@ -3,7 +3,7 @@ pub mod bohb; #[cfg(feature = "cma-es")] pub mod cma_es; -pub mod differential_evolution; +pub mod de; pub(crate) mod genetic; #[cfg(feature = "gp")] pub mod gp; @@ -19,6 +19,22 @@ pub mod tpe; use std::collections::HashMap; +pub use bohb::BohbSampler; +#[cfg(feature = "cma-es")] +pub use cma_es::CmaEsSampler; +pub use de::{DifferentialEvolutionSampler, DifferentialEvolutionStrategy}; +#[cfg(feature = "gp")] +pub use gp::GpSampler; +pub use grid::GridSearchSampler; +pub use moead::{Decomposition, MoeadSampler}; +pub use motpe::MotpeSampler; +pub use nsga2::Nsga2Sampler; +pub use nsga3::Nsga3Sampler; +pub use random::RandomSampler; +#[cfg(feature = "sobol")] +pub use sobol::SobolSampler; +pub use tpe::TpeSampler; + use crate::distribution::Distribution; use crate::param::ParamValue; use crate::parameter::{ParamId, Parameter}; diff --git a/src/study.rs b/src/study.rs index e8effcf..3827942 100644 --- a/src/study.rs +++ b/src/study.rs @@ -382,8 +382,8 @@ where /// ``` /// use std::collections::HashMap; /// - /// use optimizer::parameter::{FloatParam, IntParam, Parameter}; - /// use optimizer::{Direction, ParamValue, Study}; + /// use optimizer::parameter::{FloatParam, IntParam, ParamValue, Parameter}; + /// use optimizer::{Direction, Study}; /// /// let study: Study = Study::new(Direction::Minimize); /// let x = FloatParam::new(0.0, 10.0); diff --git a/tests/differential_evolution_tests.rs b/tests/differential_evolution_tests.rs index 75328bc..eb7a927 100644 --- a/tests/differential_evolution_tests.rs +++ b/tests/differential_evolution_tests.rs @@ -1,7 +1,5 @@ use optimizer::prelude::*; -use optimizer::sampler::differential_evolution::{ - DifferentialEvolutionSampler, DifferentialEvolutionStrategy, -}; +use optimizer::sampler::de::{DifferentialEvolutionSampler, DifferentialEvolutionStrategy}; #[test] fn sphere_function() { diff --git a/tests/integration.rs b/tests/integration.rs index 9e8eb76..b895606 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -1707,7 +1707,7 @@ fn test_ask_and_tell_with_custom_value_type() { use std::collections::HashMap; -use optimizer::ParamValue; +use optimizer::parameter::ParamValue; #[test] fn test_enqueue_params_evaluated_first() { @@ -2291,7 +2291,7 @@ fn test_builder_with_sampler() { #[test] fn test_builder_with_pruner() { - use optimizer::NopPruner; + use optimizer::pruner::NopPruner; let study: Study = Study::builder().pruner(NopPruner).build(); @@ -2303,7 +2303,7 @@ fn test_builder_chaining() { let study: Study = Study::builder() .maximize() .sampler(RandomSampler::with_seed(42)) - .pruner(optimizer::NopPruner) + .pruner(optimizer::pruner::NopPruner) .build(); assert_eq!(study.direction(), Direction::Maximize); diff --git a/tests/multi_objective_tests.rs b/tests/multi_objective_tests.rs index ec5e200..dc30af9 100644 --- a/tests/multi_objective_tests.rs +++ b/tests/multi_objective_tests.rs @@ -1,11 +1,12 @@ //! Integration tests for multi-objective optimization. +use optimizer::Direction; use optimizer::multi_objective::MultiObjectiveStudy; use optimizer::parameter::{CategoricalParam, FloatParam, Parameter}; +use optimizer::sampler::Decomposition; use optimizer::sampler::moead::MoeadSampler; use optimizer::sampler::nsga2::Nsga2Sampler; use optimizer::sampler::nsga3::Nsga3Sampler; -use optimizer::{Decomposition, Direction}; // --------------------------------------------------------------------------- // Pareto utility tests (via public MultiObjectiveStudy) diff --git a/tests/serde_tests.rs b/tests/serde_tests.rs index 66aa745..202bc19 100644 --- a/tests/serde_tests.rs +++ b/tests/serde_tests.rs @@ -2,9 +2,9 @@ use std::collections::HashMap; -use optimizer::parameter::{FloatParam, IntParam, Parameter}; +use optimizer::parameter::{FloatParam, IntParam, ParamValue, Parameter}; use optimizer::sampler::CompletedTrial; -use optimizer::{Direction, ParamValue, Study, StudySnapshot, TrialState}; +use optimizer::{Direction, Study, StudySnapshot, TrialState}; #[test] fn round_trip_save_load() {