Examples ======== This page shows practical C++ usage patterns for Minion. Reference files in this repository: - ``examples/main_minimizer.cpp`` - ``examples/main_cec.cpp`` - ``tests/test_minion.cpp`` Basic Pattern ============= Minion expects a **vectorized objective**: .. code-block:: cpp std::vector objective(const std::vector>& X, void* data) { std::vector out(X.size(), 0.0); for (size_t i = 0; i < X.size(); ++i) { const auto& x = X[i]; // compute f(x) out[i] = /* ... */; } return out; } Then call ``minion::Minimizer``: .. code-block:: cpp std::vector> bounds(dim, {-5.0, 5.0}); std::vector x0(dim, 0.0); std::string algo = "LSHADE"; auto settings = minion::DefaultSettings().getDefaultSettings(algo); minion::MinionResult res = minion::Minimizer( objective, bounds, x0, nullptr, nullptr, algo, 0.0, 100000, 42, settings ).optimize(); Understanding MinionResult ========================== ``optimize()`` returns ``minion::MinionResult`` with these fields: - ``x``: best decision vector found. - ``fun``: objective value at ``x``. - ``nit``: number of iterations/generations completed. - ``nfev``: number of objective evaluations. - ``success``: solver status flag. - ``message``: termination message (if provided by the algorithm). Example: .. code-block:: cpp minion::MinionResult res = minion::Minimizer( objective, bounds, x0, nullptr, nullptr, "ARRDE", 0.0, 100000, 42 ).optimize(); std::cout << "success: " << std::boolalpha << res.success << "\n"; std::cout << "fun: " << res.fun << "\n"; std::cout << "nit: " << res.nit << ", nfev: " << res.nfev << "\n"; std::cout << "x_best[0]: " << (res.x.empty() ? 0.0 : res.x[0]) << "\n"; if (!res.message.empty()) { std::cout << "message: " << res.message << "\n"; } Using Callback ============== You can pass a callback to monitor progress after each iteration: .. code-block:: cpp void progress_callback(minion::MinionResult* state) { std::cout << "iter=" << state->nit << " nfev=" << state->nfev << " best=" << state->fun << "\n"; } minion::MinionResult res = minion::Minimizer( objective, bounds, x0, nullptr, progress_callback, "LSHADE", 0.0, 100000, 42 ).optimize(); If you need custom early stopping, a practical pattern is to throw from the callback when your condition is met, then catch outside: .. code-block:: cpp struct StopNow : public std::exception { const char* what() const noexcept override { return "user stop"; } }; void early_stop_callback(minion::MinionResult* state) { if (state->nfev >= 20000 || state->fun < 1e-8) { throw StopNow(); } } try { auto res = minion::Minimizer( objective, bounds, x0, nullptr, early_stop_callback, "ARRDE", 0.0, 100000, 42 ).optimize(); (void)res; } catch (const StopNow&) { std::cout << "Optimization stopped by user callback.\n"; } Override Default Options ======================== Start from defaults, then override only what you need. .. code-block:: cpp std::string algo = "DE"; auto settings = minion::DefaultSettings().getDefaultSettings(algo); // Common overrides settings["population_size"] = 80; settings["bound_strategy"] = std::string("reflect-random"); // Algorithm-specific overrides if (algo == "DE") { settings["mutation_rate"] = 0.7; settings["crossover_rate"] = 0.9; settings["mutation_strategy"] = std::string("current_to_pbest1bin"); } minion::MinionResult res = minion::Minimizer( objective, bounds, x0, nullptr, nullptr, algo, 0.0, 100000, 42, settings ).optimize(); Notes: - Option keys are algorithm-specific. Use ``DefaultSettings`` as the source of valid keys. - Keep value types consistent with the expected type (``int``, ``double``, ``std::string``, ``bool``). Multithreading Objective Evaluation =================================== Minion calls your objective in batches (``X``). Parallelization for C++ workflows is typically implemented **inside your objective function**. 1) Standalone Function (Thread-Safe) ------------------------------------ If each evaluation is independent, parallelize the loop over ``X``. .. code-block:: cpp #include double sphere(const std::vector& x) { double s = 0.0; for (double v : x) s += v * v; return s; } std::vector sphere_batch(const std::vector>& X, void*) { std::vector out(X.size(), 0.0); #pragma omp parallel for for (int i = 0; i < static_cast(X.size()); ++i) { out[i] = sphere(X[i]); } return out; } 2) Non-Thread-Safe Class Method ------------------------------- If the class has mutable shared state, protect access. .. code-block:: cpp #include class Model { public: double eval(const std::vector& x) { // touches mutable shared state internally return /* ... */; } }; struct ModelData { Model* model; std::mutex* mtx; }; std::vector model_batch(const std::vector>& X, void* data) { auto* md = static_cast(data); std::vector out(X.size(), 0.0); #pragma omp parallel for for (int i = 0; i < static_cast(X.size()); ++i) { std::lock_guard lock(*md->mtx); out[i] = md->model->eval(X[i]); } return out; } If possible, prefer a re-entrant/stateless evaluator per thread to avoid lock contention. 3) Lambda Function ------------------ Use a lambda and assign it to ``minion::MinionFunction``. .. code-block:: cpp minion::MinionFunction objective = [](const std::vector>& X, void*) { std::vector out(X.size(), 0.0); #pragma omp parallel for for (int i = 0; i < static_cast(X.size()); ++i) { const auto& x = X[i]; double f = 0.0; for (size_t j = 0; j + 1 < x.size(); ++j) { const double a = x[j + 1] - x[j] * x[j]; const double b = 1.0 - x[j]; f += 100.0 * a * a + b * b; } out[i] = f; } return out; }; CEC Functions ============= Include both headers: .. code-block:: cpp #include #include Wrap CEC evaluator into Minion objective signature: .. code-block:: cpp std::vector cec2017_batch(const std::vector>& X, void* data) { auto* cec = static_cast(data); return (*cec)(X); } Example (CEC2017, F1, dimension 30): .. code-block:: cpp const int dim = 30; minion::CEC2017Functions cec_f1(1, dim); std::vector> bounds(dim, {-100.0, 100.0}); std::vector x0(dim, 0.0); auto settings = minion::DefaultSettings().getDefaultSettings("ARRDE"); minion::MinionResult res = minion::Minimizer( cec2017_batch, bounds, x0, &cec_f1, nullptr, "ARRDE", 0.0, 30000, 20250306, settings ).optimize(); For a larger CEC sweep (multiple functions and algorithms), see ``tests/test_minion.cpp``. For broader CEC benchmark utilities and bounds handling, see ``examples/main_cec.cpp``.