Table of Contents

Distributions

A distribution describes the range and shape of a single hyperparameter: its bounds, whether it is sampled on a log scale, its discretization step, or its set of categorical choices. Every Suggest* call on a trial is backed by a distribution, and each is recorded on the trial so the search space can be reconstructed later. OptunaSharp ports optuna.distributions into the OptunaSharp.Distributions namespace.

The three distributions

using OptunaSharp.Distributions;

// Float: continuous, optionally log-scaled or stepped (log and step are mutually exclusive).
var lr      = new FloatDistribution(1e-5, 1e-1, log: true);
var dropout = new FloatDistribution(0.0, 0.5, step: 0.1);

// Int: integer range with a step (default 1), optionally log-scaled.
var units   = new IntDistribution(16, 256, log: true);
var layers  = new IntDistribution(1, 5);

// Categorical: an ordered set of choices.
var optimizer = new CategoricalDistribution("adam", "sgd", "rmsprop");
Type Constructor Notes
FloatDistribution (double low, double high, bool log = false, double? step = null) Low, High, Log, Step
IntDistribution (long low, long high, bool log = false, long step = 1) Low, High, Log, Step
CategoricalDistribution (IEnumerable<CategoricalChoice> choices) / (params CategoricalChoice[]) Choices, ChoiceAt(index)

You usually never construct these directly — trial.SuggestFloat/SuggestInt/SuggestCategorical create them for you. Construct them explicitly when pre-defining a search space, for example the fixedDistributions argument to study.Ask(...) or a GridSampler grid.

All three derive from the abstract BaseDistribution, which defines the internal/external representation conversions the samplers use (ToInternalRepr, ToExternalRepr) and Single() (true when the distribution admits exactly one value).

Categorical values: CategoricalChoice

Categorical choices are not plain objects. Optuna's choices are a Python Union[None, bool, int, float, str] and compare with Python equality, where True == 1, 1.0 == 1, and NaN != NaN. C#'s object.Equals disagrees on every one of those. OptunaSharp therefore models a choice as the readonly struct CategoricalChoice, which reproduces Python's semantics exactly — the one place where getting object equality "right" for .NET would be wrong for Optuna.

CategoricalChoice a = true;      // implicit conversion from bool
CategoricalChoice b = 1;         // from int
Console.WriteLine(a == b);       // True  — Python semantics (True == 1)

CategoricalChoice nan = double.NaN;
Console.WriteLine(nan == nan);   // False — NaN != NaN

CategoricalChoice none = CategoricalChoice.None;   // Python None
var made = CategoricalChoice.From(someObject);      // from an arbitrary boxed value

Implicit conversions exist from bool, int, long, double, and string, so the typed SuggestCategorical overloads and collection initializers read naturally. Inspect a value with Kind (CategoricalChoiceKind.None/Bool/Int/Float/String), Value, IsNone, and IsNaN.

Serialization and compatibility

Distributions round-trip to and from Optuna's JSON representation, so a search space written by Python Optuna is understood by OptunaSharp and vice versa:

string json = Distribution.ToJson(lr);
BaseDistribution back = Distribution.FromJson(json);

// Throws when a parameter's distribution changed incompatibly between trials:
Distribution.CheckDistributionCompatibility(oldDist, newDist);

Deprecated distributions

Optuna's pre-3.0 distribution classes are kept as [Obsolete] aliases that forward to the modern three: UniformDistribution, LogUniformDistribution, DiscreteUniformDistribution (→ FloatDistribution), and IntUniformDistribution, IntLogUniformDistribution (→ IntDistribution). Prefer the modern types.

Relationship to Optuna

Optuna (Python) OptunaSharp
FloatDistribution(1e-5, 1e-1, log=True) new FloatDistribution(1e-5, 1e-1, log: true)
IntDistribution(16, 256, step=8) new IntDistribution(16, 256, step: 8)
CategoricalDistribution(["a", "b"]) new CategoricalDistribution("a", "b")
a categorical choice 1 == True CategoricalChoice equality ((CategoricalChoice)1 == true)
distribution_to_json / json_to_distribution Distribution.ToJson / Distribution.FromJson

Divergence. Like Optuna, CategoricalDistribution cannot distinguish True from 1 or 1.0 from 1 when mapping a value back to its internal index — the choices collapse under Python equality. This is an accepted upstream behavior, reproduced deliberately and pinned by tests.

See also

Study and Trials · Search Spaces · Samplers · the API reference.