Commit Graph

160 Commits

Author SHA1 Message Date
Manuel Raimann 38a20bbc42 fix(docs): resolve all broken rustdoc intra-doc links
Fix direct path references for in-scope items (GammaStrategy,
CompletedTrial) and convert feature-gated items to plain backtick
formatting so docs build cleanly without --all-features.
2026-02-12 15:47:53 +01:00
Manuel Raimann f0798ca58a refactor(study): move export_json() from persistence to export module 2026-02-12 15:42:34 +01:00
Manuel Raimann a502d7e1b8 refactor(tpe): split multivariate sampler into focused submodules
- Extract engine.rs (core sampling logic) and trials.rs (trial processing)
- Deduplicate TPE sampling functions by delegating to tpe::common
- Gate persistence.rs imports with #[cfg(feature = "serde")]
2026-02-12 15:38:23 +01:00
Manuel Raimann d80d2bb1fb refactor(sampler): extract shared utilities to reduce duplication
- Add sampler/common.rs with distribution helpers (internal_bounds,
  from_internal, to_internal, sample_random) used by 8 samplers
- Add sampler/tpe/common.rs with TPE sampling functions
  (sample_tpe_float, sample_tpe_int, sample_tpe_categorical)
  shared by TpeSampler, MultivariateTpeSampler, and MotpeSampler
- Remove ~940 lines of near-identical code across sampler modules
2026-02-12 15:25:27 +01:00
Manuel Raimann 4781107ede refactor(study): split monolithic study.rs into focused submodules
- mod.rs: core struct (pub(crate) fields), constructors, trial management
- builder.rs: StudyBuilder fluent API
- optimize.rs: sync optimization loop
- async_impl.rs: optimize_async/optimize_parallel (feature-gated)
- analysis.rs: best_trial, top_trials, param_importance, fanova
- export.rs: CSV, summary, Display, export_html
- persistence.rs: StudySnapshot, save/load, with_journal
- iter.rs: iter(), IntoIterator
2026-02-12 15:03:02 +01:00
Manuel Raimann 9ab94002d9 perf(tpe): eliminate unnecessary Vec allocations in KDE/TPE sampling
- In-place log transformation in sample_tpe_float (saves 2 allocs per log-scale float sample)
- Pass owned Vec<i64> to sample_tpe_int to reduce peak memory during int-to-float conversion
- Stack-allocate categorical count arrays for <=32 choices in sample_tpe_categorical
2026-02-12 14:51:03 +01:00
Manuel Raimann 1b158e4d1b perf: pre-allocate vectors in analysis methods
- Use Vec::with_capacity() in param_importance() and fanova_with_config()
  where iteration count is known or bounded
- Fix flaky MultivariateTpeSampler doctest by increasing trials from 30
  to 50
2026-02-12 14:46:46 +01:00
Manuel Raimann ddbbe294bc perf(journal): use incremental refresh instead of re-reading entire file
Track a byte offset so refresh() only parses lines appended since the
last read, reducing total I/O from O(n²) to O(n) over an n-trial run.
2026-02-12 14:44:19 +01:00
Manuel Raimann 5da63d8976 perf: reduce CompletedTrial cloning overhead
- Add Trial::into_completed() and into_multi_objective_trial() to move
  fields instead of cloning 5 HashMaps/Vecs per trial completion
- Fire after_trial callback before pushing to storage, eliminating the
  clone-from-storage pattern at all 4 call sites
- Optimize top_trials(n) to sort indices and clone only N trials instead
  of cloning all completed trials
- Remove unused set_complete/set_pruned methods
2026-02-12 14:44:19 +01:00
Manuel Raimann 74cf0643eb perf: replace RNG mutex with per-call seed derivation in stateless samplers
- Replace Mutex<fastrand::Rng> with a stored seed + MurmurHash3 mixer
  in RandomSampler, TpeSampler, and MotpeSampler so parallel workers
  no longer serialize on a shared lock
- Add mix_seed() and distribution_fingerprint() to rng_util for
  deterministic per-call RNG derivation from (seed, trial_id, distribution)
- Include an AtomicU64 call counter to disambiguate parameters that
  share the same distribution within a trial
2026-02-12 14:44:19 +01:00
Manuel Raimann baebbae64c docs: add pre-commit guidelines for formatting and testing 2026-02-12 14:44:19 +01:00
Manuel Raimann 750bbad0d8 test: assert pruned count unconditionally in summary test
Remove the conditional guard on pruned trial assertions since the test
explicitly prunes 2 trials. Assert the expected count first, then check
summary content unconditionally to catch regressions.
2026-02-12 14:44:19 +01:00
Manuel Raimann 271748700f perf(tpe): use quickselect instead of full sort in split_trials 2026-02-12 14:44:19 +01:00
Manuel Raimann c561caaa34 fix: validate NaN/Inf in deserialized trials during journal loading
- Add `CompletedTrial::validate()` checking all f64 fields are finite
- Call validate after deserializing each trial in journal storage
- Make `distribution` and `param` modules public (types already in public fields)
2026-02-12 14:44:19 +01:00
Manuel 04d822479e Update Cargo.toml
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-12 14:12:52 +01:00
Manuel Raimann 8713a93636 refactor: adjust indentation for better readability in pruning.rs 2026-02-12 13:59:14 +01:00
Manuel Raimann 3723f91849 refactor: update rustfmt configuration by commenting out unused options 2026-02-12 13:56:09 +01:00
Manuel Raimann 968eb67d07 fix: return error instead of panicking on out-of-bounds categorical index 2026-02-12 13:55:00 +01:00
Manuel 2d88526d8d Update examples/pruning.rs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-12 13:52:26 +01:00
Manuel Raimann cc3937d4f7 Add LICENSE.md 2026-02-12 13:49:49 +01:00
Manuel Raimann 6f1c070b7d test: actually use NaN values in test_best_trial_with_nan_values 2026-02-12 13:38:54 +01:00
Manuel 12f7f25baa Update README.md
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-12 13:29:44 +01:00
Manuel Raimann e68a3788be refactor: move RandomMultiObjectiveSampler into sampler::random 2026-02-12 13:21:37 +01:00
Manuel Raimann d20f09c66a refactor: shorten sampler type names
- GridSearchSampler → GridSampler
- DifferentialEvolutionSampler → DESampler
- DifferentialEvolutionStrategy → DEStrategy
- DifferentialEvolutionSamplerBuilder → DESamplerBuilder
2026-02-12 13:19:06 +01:00
Manuel Raimann 47b5f9cec8 feat: unify optimize and optimize_with via blanket Objective impl
- Add blanket `impl Objective<V> for Fn(&mut Trial) -> Result<V, E>`
  so closures work directly with `optimize`
- Rewrite optimize, optimize_async, optimize_parallel to accept
  `impl Objective<V>` with before_trial/after_trial hooks
- Remove optimize_with, optimize_with_async, optimize_with_parallel
- Remove max_retries and retry logic from Objective trait
- Add explicit closure type annotations for HRTB inference
- Convert FnMut test closures to Fn via RefCell/Cell
2026-02-12 13:09:14 +01:00
Manuel Raimann c20a53dfba fix: bump minimum tokio version to 1.30 for JoinSet::len() 2026-02-12 12:52:02 +01:00
Manuel Raimann d81d1de4ff refactor(tests): split integration.rs into focused subfolders
- Delete 20 duplicate tests already covered by parameter_tests.rs
- Move 11 pure Trial unit tests into src/trial.rs
- Split remaining 84 integration tests into tests/study/ (9 modules)
- Group sampler tests into tests/sampler/ (7 modules)
- Group pruner tests into tests/pruner/ (2 modules)
2026-02-12 12:49:24 +01:00
Manuel Raimann 964b4d5749 feat: add Objective trait and unify optimize API
- Add `Objective<V>` trait with lifecycle hooks (`before_trial`,
  `after_trial`, `max_retries`) in new `src/objective.rs`
- Replace 14+ optimize variants with 6 methods: `optimize`,
  `optimize_with`, and async/parallel counterparts
- `optimize*` methods accept closures directly (FnMut for sync, Fn for
  async); `optimize_with*` methods accept `impl Objective<V>` for
  struct-based objectives with hooks and retries
- Remove `optimize_until`, `optimize_with_callback`,
  `optimize_with_retries`, `optimize_with_checkpoint`, and all
  deprecated `_with_sampler` methods
2026-02-12 12:49:24 +01:00
Manuel Raimann ee59c9cdd0 refactor(examples): split multi-concept examples into focused single-topic files
- Split pruning_and_callbacks into pruning and early_stopping
- Split advanced_features into async_parallel, journal_storage, ask_and_tell, multi_objective
- Each example now requires only its own feature flag
- Trim sampler_comparison winner logic and verbose header
- Update CI workflow and README to match new example names
2026-02-12 12:49:24 +01:00
Manuel Raimann 6a4b27c46f refactor: move all type re-exports out of crate root into their modules
- Sampler, pruner, storage, parameter, and multi_objective types are no
  longer re-exported at the crate root; access via module paths instead
  (e.g. optimizer::sampler::TpeSampler, optimizer::parameter::FloatParam)
- Prelude continues to re-export everything for convenience
- Add module-level pub use re-exports in sampler/mod.rs and parameter.rs
- Update derive macro to reference optimizer::parameter::Categorical
- Rename sampler::differential_evolution to sampler::de
- Fix all downstream imports in tests, benches, and doctests
- Fix all rustdoc intra-doc links to use explicit module paths
2026-02-12 12:49:24 +01:00
Manuel Raimann cc0dce5daf ci: add doc tests and update examples to match current codebase 2026-02-12 12:49:24 +01:00
Manuel Raimann 1f1e9d1779 refactor(docs): Documentation Overhaul 2026-02-12 12:49:24 +01:00
Manuel Raimann 3581187cd3 chore: release v0.9.1 v0.9.1 2026-02-12 08:17:28 +01:00
Manuel Raimann 349ffcbed3 fix: update journal file handling to support reading and writing 2026-02-12 08:13:48 +01:00
Manuel Raimann 88e2ac0ff0 chore: release v0.9.0 v0.9.0 2026-02-12 00:01:44 +01:00
Manuel Raimann d122582bf7 Revert "feat: add SQLite storage backend for multi-process optimization"
This reverts commit ed80c59795.

# Conflicts:
#	src/lib.rs
#	src/storage/sqlite.rs
2026-02-12 00:01:27 +01:00
Manuel Raimann 705687a42e feat: add NSGA-III and MOEA/D samplers for many-objective optimization
Extract shared evolutionary algorithm infrastructure (genetic operators,
candidate management, Das-Dennis reference points) from NSGA-II into a
new genetic.rs module, then build two new multi-objective samplers on top:

- NSGA-III: reference-point-based niching for well-distributed fronts
  on 3+ objective problems (Das-Dennis structured points, normalization,
  perpendicular distance association, niching selection)

- MOEA/D: decomposition-based optimization with three scalarization
  methods (Tchebycheff, WeightedSum, PBI), weight-vector neighborhoods,
  and neighborhood-based mating selection

Both implement MultiObjectiveSampler with builder pattern, seeded RNG,
and SBX crossover / polynomial mutation via the shared genetic module.
2026-02-11 23:53:20 +01:00
Manuel Raimann 03deedd775 feat: add Zlib license to deny.toml 2026-02-11 23:40:22 +01:00
Manuel Raimann 047a788afd fix: remove unnecessary feature flag for visualization example in CI 2026-02-11 23:39:43 +01:00
Manuel Raimann d2e36ec304 refactor: move next_trial_id counter from Study into Storage trait 2026-02-11 23:32:15 +01:00
Manuel Raimann d14f4e0792 feat: add StudyBuilder for fluent study construction 2026-02-11 23:23:56 +01:00
Manuel Raimann ed80c59795 feat: add SQLite storage backend for multi-process optimization 2026-02-11 23:21:47 +01:00
Manuel Raimann ed1e9e31da fix: use atomic counter for temp paths in journal tests
On Windows, SystemTime::now().as_nanos() has ~15ms resolution,
causing parallel tests to generate identical file paths and
corrupt each other's data.
2026-02-11 23:17:09 +01:00
Manuel Raimann 36c6262dbc refactor: remove visualization and fanova feature flags
Always build visualization and fanova code unconditionally.
2026-02-11 23:06:28 +01:00
Manuel Raimann 0c295b4bc7 ci: simplify test command by removing feature matrix 2026-02-11 23:03:38 +01:00
Manuel Raimann 0a6f2345a8 feat: add Storage trait and JSONL journal backend
Replace the internal Vec<CompletedTrial<V>> with a pluggable Storage<V>
trait. MemoryStorage is the default (no behavior change for existing
users). Behind the `journal` feature flag, JournalStorage persists
trials to a JSONL file with fs2 file locking for multi-process safety.

- Storage<V> trait with push(), trials_arc(), refresh() methods
- MemoryStorage<V> wraps Arc<RwLock<Vec<CompletedTrial<V>>>>
- JournalStorage<V> appends JSON lines with exclusive file locks
- Study::with_sampler_and_storage() general constructor
- Study::with_journal() convenience constructor (journal feature)
- Refresh from storage on create_trial() for multi-process discovery
- MSRV bumped to 1.89
2026-02-11 22:58:38 +01:00
Manuel Raimann 24a0bdd473 feat: add Differential Evolution sampler
Population-based optimizer with mutation + crossover. Supports three
strategies (Rand1, Best1, CurrentToBest1), configurable F and CR,
and auto-sized populations. No extra dependencies needed.
2026-02-11 22:04:23 +01:00
Manuel Raimann 8239cc58a1 refactor: replace rand 0.10 with fastrand 2.3
fastrand is smaller, faster, and has no dependencies. Add rng_util
helper for f64 range generation since fastrand lacks a built-in
equivalent. Migrate all samplers, KDE modules, and fANOVA to use
fastrand's concrete Rng type instead of rand's trait-based generics.
2026-02-11 21:54:34 +01:00
Manuel Raimann 906e5296de fix: seed importance tests to eliminate flakiness
The no_effect_parameter test (and others) used unseeded random sampling,
causing spurious correlations between the noise parameter and the
objective in unlucky runs. Seed all importance tests with
RandomSampler::with_seed(42) for deterministic results.
2026-02-11 21:30:21 +01:00
Manuel Raimann 947701e83f feat: add Gaussian Process sampler with Expected Improvement
Implement a classical Bayesian optimization sampler using a GP surrogate
with Matérn 5/2 kernel and Expected Improvement acquisition function.
Feature-gated behind `gp = ["dep:nalgebra"]`.
2026-02-11 21:27:40 +01:00