Multi-objective (mo)¶
sezgi.mo.*: NSGA-II over the built-in ZDT/DTLZ/WFG problem families,
plus hypervolume, IGD, an analytic Pareto-front sampler, and
sezgi-moa-format archive logging/reading. sezgi.NSGA2
(Built-in algorithm classes) is a thin class-first skin
over mo.nsga2 below.
mo.nsga2 ¶
_mo_nsga2(problem, dim, pop_size, budget, m=None, seed=0, eta_c=20.0, eta_m=20.0, p_c=0.9, p_m=None, p_c_bin=0.9, p_m_bin=None, p_c_cat=0.9, p_m_cat=None, k=None, l=None, log_dir=None, label=None)
mo.nsga2(problem, dim, pop_size, budget, m=None, seed=0, eta_c=20.0,
eta_m=20.0, p_c=0.9, p_m=None, p_c_bin=0.9, p_m_bin=None, p_c_cat=0.9,
p_m_cat=None, k=None, l=None, log_dir=None, label=None) -> dict
Runs NSGA-II (Deb et al. 2002) over one of this module's built-in
multi-objective problem families -- see this file's own "Problem
strings" note above for problem/dim/m/k/l's per-family
validation rules.
Returns a dict with keys individuals (list of float-lists, one per final-population member -- a Binary block's bits are flattened to 0.0/1.0), objectives (list of float-lists, parallel to individuals), front0 (list of ints: indices of the final population's non-dominated set), evals_used (int), and violations (list of floats, <= 0.0, 0.0 = feasible; present ONLY when the problem is constrained -- dtlz8/ dtlz9 today).
eta_c/eta_m/p_c default to the NSGA-II paper's own pinned experimental settings (Deb et al. 2002, Sec. IV.A); p_m=None resolves on the Rust side to 1/n_variables. p_c_bin/p_m_bin are the binary-genotype counterparts (consulted only for zdt5's all-Binary space); p_c_bin defaults to 0.9 (mirroring p_c; the paper gives no verified binary-specific default), p_m_bin=None resolves to 1/l (the paper's own stated binary default). p_c_cat/p_m_cat are the Categorical-genotype counterparts (consulted only for a Mixed space containing a Categorical block -- no problem string in this module's own catalog builds one today, so they are currently validated but inert, exactly like p_c_bin/p_m_bin on every non-zdt5 problem); p_c_cat defaults to 0.9 (mirroring p_c_bin's own reasoning), p_m_cat=None resolves to 1/n_cat (n_cat = the space's total flattened Categorical dimension).
pop_size must be >= 4 AND a multiple of 4 (a KanGAL-faithful tightening
of the naive "even, >= 4" rule) or this raises ValueError. When log_dir
is given, the run is additionally streamed to
mo.hypervolume_2d
builtin
¶
mo_hypervolume_2d(front, ref_point)
sezgi.mo.hypervolume_2d(front, ref_point) -- binds
[sezgi_stats::hypervolume_2d] exactly (see that function's doc for the
pinned S-metric definition and reference-point convention). front: a
list of [f1, f2] rows (minimization). ref_point: a 2-element
[f64; 2]-shaped list.
Errors¶
ValueError if ref_point does not have exactly 2 values, or for any
[sezgi_stats::StatsError] (empty front, a non-2-objective row, or a
non-finite value).
mo.hypervolume
builtin
¶
mo_hypervolume(front, ref_point)
sezgi.mo.hypervolume(front, ref_point) -- binds [sezgi_stats::hypervolume]
(M3-7 Task 8/10), the exact general-M hypervolume via the WFG algorithm
(While, Bradstreet & Barone, "A Fast Way of Calculating Exact
Hypervolumes", IEEE TEC 2012). Unlike hypervolume_2d, front/
ref_point may have any number M >= 1 of objectives (M == 2
delegates internally to the SAME hypervolume_2d, that module's own "2D
shortcut" doc section).
ref_point is REQUIRED, with no default (a plain positional/keyword
argument -- calling this with only front raises Python's own
TypeError for a missing argument, by signature, not a ValueError
this binding raises itself): sezgi_stats::moo_indicators's own module
doc, "Choosing a reference point: explicit-always, contested in the
literature" section, deliberately never picks one FOR the caller. One
common convention from that literature (also the module's own examples/
tests' choice, and the specific one critiqued by Ishibuchi, Imada,
Setoguchi & Nojima 2018, "How to Specify a Reference Point in
Hypervolume Calculation for Fair Performance Comparison", GECCO
Companion) is the analytic front's nadir point (the componentwise worst
value across the front) scaled by 1.1 -- a caller-supplied choice,
never defaulted here.
Errors¶
ValueError for any [sezgi_stats::StatsError] (ref_point empty, a
front row with a different number of objectives than ref_point, or a
non-finite value). An EMPTY front is NOT an error -- it returns 0.0
(the algorithm's own base case, hypervolume's own "empty front"
doc section).
mo.igd
builtin
¶
mo_igd(front, reference_front)
sezgi.mo.igd(front, reference_front) -- binds [sezgi_stats::igd]
exactly (Ishibuchi et al. 2015, eq. 12, p = 1; see that function's doc
for the pinned definition). Any (equal, consistent) number of objectives
across both front and reference_front.
Errors¶
ValueError for any [sezgi_stats::StatsError] (an empty front or
reference_front, a dimension mismatch, or a non-finite value).
mo.pareto_front ¶
_mo_pareto_front(problem, dim, n, m=None, k=None, l=None)
mo.pareto_front(problem, dim, n, m=None, k=None, l=None) -> list of
float-lists, or None
A deterministic n-point sample of the analytic Pareto front in
OBJECTIVE space for one of this module's built-in problem families --
same problem/dim/m/k/l mapping and validation as mo.nsga2.
Returns None when the problem has no known analytic front sample at
this m (e.g. DTLZ5/DTLZ6 with m > 3, or WFG1/WFG2 unconditionally).
mo.evaluate
builtin
¶
mo_evaluate(problem, x, dim=None, m=None, k=None, l=None)
sezgi.mo.evaluate(problem, x, dim=None, m=None, k=None, l=None) ->
list[float] -- direct, one-shot objective evaluation of a decision
vector x against any sezgi.mo problem string, bypassing nsga2's
population/budget machinery entirely (problem/dim/m/k/l share
mo_nsga2's own mo_problem_from_str mapping).
# sezgi decision: (M3-7 Task 10) added purely so this binding's OWN
test suite can pin exact fixture values (zdt5's all-ones/all-zeros hand
fixtures, dtlz8/9's hand fixtures, the committed
wfg_reference_values.json points) directly from Python -- mirroring
the existing cec2022_evaluate/cec2014_evaluate/cec2017_evaluate
one-shot-evaluation convention already established in this file. Not
literally named in this task's brief (which only names
nsga2/pareto_front for the new problem families), but required by
the brief's own Test section, since nsga2's randomly-initialized
population cannot pin a fixture at a chosen x.
x: for an all-Float problem, its raw decision values; for zdt5 (the
only all-Binary problem reachable here), each entry is read as a bit
(!= 0.0 -> true) -- see [genotype_from_flat]'s own doc.
Errors¶
Same problem-construction errors as mo.nsga2/mo.pareto_front, plus a
ValueError if len(x) does not match the problem's own dimension.
mo.evaluate_constraints
builtin
¶
mo_evaluate_constraints(problem, x, dim=None, m=None, k=None, l=None)
sezgi.mo.evaluate_constraints(problem, x, dim=None, m=None, k=None,
l=None) -> Optional[list[float]] -- direct, one-shot constraint-row
evaluation, mirroring mo.evaluate's calling convention exactly (same
[mo_problem_from_str] mapping, same [genotype_from_flat] decoding).
Returns None for an unconstrained problem (every zdt/wfg problem, and
dtlz1-7), or the constraint row (g_1..g_ncon, g_j >= 0 meaning
SATISFIED -- see [sezgi_core::mo::MoProblem::evaluate_constraints_batch]'s
own doc for the pinned sign convention) for a constrained one (dtlz8/
dtlz9).
Errors¶
Same as mo.evaluate.
mo.read_moa
builtin
¶
mo_read_moa(path, at=None)
sezgi.mo.read_moa(path, at=None) -- binds [sezgi_bench::read_moa] (a
"sezgi-moa v1" archive file written by mo.nsga2(..., log_dir=...,
label=...), M3-7 Task 9/10). Returns a dict:
- algo (str): the logging algorithm name -- always "nsga2" today
(nsga2_run_logged's own fixed NSGA2_ALGO_NAME).
- problem (str): the label mo.nsga2 was called with. Kept as the
literal on-disk header key name (crates/bench/src/mo_archive.rs's
own format grammar: the header line is problem <label>, not
label <label>) rather than renamed here to "label" -- this
binding stays a thin, direct mirror of [MoArchiveRun]'s own field
names, so a reader cross-checking against the Rust struct (or the R
binding, M3-7 Task 11) sees the SAME key everywhere.
- m (int), seed (int), budget (int).
- kind (str): "float" or "binary".
- records (list of dicts, in file/eval order): eval_index (int),
objectives (list of float), genotype (list of float for
kind="float", list of bool for kind="binary" -- [MoArchiveGenotype]'s
own two variants).
- archive (list of float-lists): the reconstructed nondominated
archive at evaluation budget at, via [MoArchiveRun::archive_at].
# sezgi decision: at=None resolves to the file's own logged budget
header field (the full run's final archive) -- archive_at itself takes
a REQUIRED evals: u64 with no Rust-side default, and the file's own
budget is the one value guaranteed to reconstruct the run's COMPLETE
trajectory (nsga2_run_logged's own MoEvaluator budget enforcement
means no eval_index beyond it was ever charged) -- a natural,
self-contained default rather than requiring every caller to pass the
budget back in by hand after already reading it out of the same dict.
Errors¶
ValueError for any [sezgi_bench::MoArchiveError] (missing file, a
malformed header, or a malformed record line).