1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
//! Ensemble / island parallelism.
//!
//! [`ensemble`] runs several independent instances of an optimizer — *islands*
//! — each with a deterministically derived seed, and returns the single best
//! result. This is the robust-restart pattern: many global optimizers benefit
//! far more from a handful of independent runs than from one long run, and the
//! islands are embarrassingly parallel.
//!
//! **Determinism is preserved regardless of scheduling.** Island `i` always
//! uses seed [`mix_seed`]`(seed, i)`, and ties are broken by the lowest island
//! index, so the winner is a pure function of `(algorithm, problem, term,
//! islands, seed)` — identical whether the islands run sequentially or across
//! Rayon threads, and identical between builds with and without the `rayon`
//! feature. (v0.1 has no inter-island migration; that is a later addition.)
//!
//! With the `rayon` feature enabled the islands run on a thread pool; without
//! it they run sequentially. The API is the same either way.
//!
//! [`mix_seed`]: crate::rng::mix_seed
use Optimizer;
use crateProblem;
use cratemix_seed;
use crateReport;
use crateTermination;
/// Runs `islands` independent instances of `algo` on `problem` and returns the
/// best [`Report`]. Each island `i` is seeded with `mix_seed(seed, i)`, so the
/// per-island RNG seed embedded in `algo` is ignored in favor of these derived
/// seeds. `islands` is clamped to at least 1.
///
/// **Budget semantics:** `term` applies *per island*, and the returned
/// `Report.evaluations` is the **winning island's** count — the total spend
/// across the ensemble is up to `islands ×` the per-island budget.
///
/// The `problem` must be `Sync` so islands can share it across threads.