Table of Contents

Namespace OptunaSharp.Samplers.NsgaiiiCpt

Classes

ConditionalParams

Declares conditional parameters — parameters that only exist while an activator parameter holds one of a set of values — the rule set consumed by NSGAIIICptSampler (NSGA-III-CPT), the only sampler that accepts it. An OptunaSharp extension with no Optuna analog: opt-in, and the plain genetic samplers (NSGAIISampler / NSGAIIISampler) are bit-exact Optuna ports that do not take it.

Why it exists. Optuna's define-by-run API lets an objective suggest a parameter under a branch only (if (optimizer == "adam") t.SuggestFloat("beta1", …)), but the GA samplers evolve the intersection search space — the parameters present in every completed trial. A parameter absent from even one trial leaves the intersection for good and is resampled uniformly at random by the independent sampler on every later trial: no crossover, no mutation, no inheritance — no evolutionary pressure at all. Declaring the parameter here tells the sampler that its absence is expected (it was inactive), so it stays in the relative search space and is evolved like any other parameter whenever it is active, and is simply not present — never blended, never counted — whenever it is not.

Rules. When(activator, values…).Activates(parameters…) declares that each of parameters is active only while activator holds one of values (Python == semantics via CategoricalChoice: 1 == 1.0 == true, strings ordinal, a lone null is None); When(activator, predicate) takes an arbitrary test instead — the value arrives as the trial stores it: a boxed long for int parameters, a double for float parameters, the raw choice value for categorical ones. Several rules may name the same activator (they OR: any admissible value suffices) and a parameter may be declared under several activators (they AND: every activator must admit). An activator may itself be conditional (chains); self-activation and cycles are rejected at declaration.

What the sampler does with it. (1) Relative search space: a conditional parameter joins it once any completed trial has suggested it, provided every trial that did used the same distribution (a changing distribution excludes it, exactly as the intersection would). (2) Crossover: the categorical uniform crossover and the numerical crossover operator run over the parameters the selected parents all carry; a parameter carried by only some parents is inherited from one of those; one carried by none stays absent. (3) After crossover (or the no-crossover parent copy) every conditional parameter whose activators say "inactive" is removed from the child — it neither counts toward the default 1 / n_params mutation probability nor reaches the trial. (4) The objective's own Suggest* calls stay the final word: a proposed parameter the objective never suggests is never recorded, and a suggested parameter the sampler did not propose is drawn independently — the usual define-by-run contract. The sampler warns once per parameter when a completed trial contradicts the rules (present while inactive, or absent while active), which usually means the objective's branches and the declaration drifted apart.

var rules = new ConditionalParams()
             .When("optimizer", "adam", "adamw").Activates("beta1", "beta2")
             .When("optimizer", "sgd").Activates("momentum")
             .When("n_layers", v => (long)v! >= 3).Activates("width_3");
         var sampler = new NSGAIIICptSampler(populationSize: 32, seed: 0, conditionalParams: rules);
NsgaiiiCptChildGenerationStrategy

The default child-generation strategy of NSGAIIICptSampler — the conditional-parameter ("Categorical Parameter Trees") counterpart of NSGAIIChildGenerationStrategy, and the sole home of conditional child generation. It shares the genetic recipe with the Optuna-parity strategy (crossover with probability crossover_prob else copy a parent; then per-parameter mutation at mutation_prob, default 1 / len(params)), and adds the conditional handling the parity strategy no longer carries.

Conditional parameters. With ConditionalParams declared, the search space may hold parameters a parent lacks (inactive for it). Crossover then goes through PerformConditionalCrossover(BaseCrossover, Study, IReadOnlyList<FrozenTrial>, OrderedDict<string, BaseDistribution>, NumPyRandom, double, Func<FrozenTrial, FrozenTrial, IReadOnlyList<StudyDirection>, bool>, ConditionalParams), the parent copy takes what the parent carries, and every conditional parameter inactive for the child is pruned before the mutation pass — so it is neither mutated nor counted in the default 1 / n_params. The mutation pass itself is unchanged. With null rules this strategy is byte-for-byte the Optuna port (it delegates to the shared PerformCrossover(BaseCrossover, Study, IReadOnlyList<FrozenTrial>, OrderedDict<string, BaseDistribution>, NumPyRandom, double, Func<FrozenTrial, FrozenTrial, IReadOnlyList<StudyDirection>, bool>)), so an NSGAIIICptSampler without rules matches NSGAIIISampler.

NsgaiiiCptSearchSpace

The conditional-parameter search space of NSGAIIICptSampler — an OptunaSharp extension with no Optuna analog, extracted here so that IntersectionSearchSpace and every other sampler stay a bit-exact Optuna port. It is the sole home of the "Categorical Parameter Trees" (CPT) search-space fold.

Unconditional parameters intersect exactly as Optuna's IntersectionSearchSpace does (this class delegates to the shared parity fold Calculate(IReadOnlyList<FrozenTrial>, bool, OrderedDict<string, BaseDistribution>, int) for that). A parameter declared conditional in the supplied ConditionalParams is instead kept when a trial lacks it (it was inactive there), joins the space the first time any trial carries it, and is excluded for good once two trials carry it with conflicting distributions — so, like the intersection, the result is order-independent. Completed trials whose parameter set contradicts the declared rules are reported once per parameter through OptunaSharp.Internal.OptunaWarnings.

Parity contract. Constructed with a null rule set this class is a byte-for-byte pass-through to the shared intersection fold, so an NSGAIIICptSampler without rules is identical to NSGAIIISampler. The customized behavior only runs when rules are present.

Structs

ConditionalParams.ActivationBuilder

The second half of a When(string, params object?[]?) rule.