SampleSet#
- class SampleSet#
Multiple candidates evaluated against the same optimization problem.
Samplescontains candidate assignments identified by sample IDs; a SampleSet adds their objective values, feasibility, evaluated variables and constraints, and modeling labels. Samples corresponds toState, while SampleSet corresponds toSolution. Candidates may come from a sampler or be supplied manually.Use
evaluate_samples()with Samples, a dictionary of sample IDs to assignments, or an iterable of assignments. Explicit IDs are preserved; iterables receive IDs from 0. SeeSamplesfor construction and repeated-assignment semantics.Evaluate several candidates
Let’s consider a simple optimization problem:
maximize x_1 + 2 x_2 + 3 x_3 subject to x_1 + x_2 + x_3 = 1 x_1, x_2, x_3 in {0, 1}
>>> from ommx import DecisionVariable, Instance, Sense >>> x = [DecisionVariable.binary(i) for i in range(3)] >>> instance = Instance.from_components( ... decision_variables=x, ... objective=x[0] + 2*x[1] + 3*x[2], ... constraints={0: sum(x) == 1}, ... sense=Sense.Maximize, ... )
with three samples:
>>> samples = { ... 0: {0: 1, 1: 0, 2: 0}, # x1 = 1, x2 = x3 = 0 ... 1: {0: 0, 1: 0, 2: 1}, # x3 = 1, x1 = x2 = 0 ... 2: {0: 1, 1: 1, 2: 0}, # x1 = x2 = 1, x3 = 0 (infeasible) ... } # ^ sample ID
Evaluate all candidates using the same Instance:
>>> sample_set = instance.evaluate_samples(samples) >>> sample_set.summary objective feasible sample_id 1 3.0 True 0 1.0 True 2 3.0 False
summaryshows each sample’s objective and feasibility. Feasible candidates appear first, ordered by the objective according tosense. Feasibility checks variable kinds and bounds and all retained constraints, including removed constraints. Retrieve an individual sample as a Solution using its ID:>>> solution = sample_set.get(sample_id=0) >>> solution.objective 1.0
best_feasibleselects the largest objective value among feasible samples for this maximization problem:>>> solution = sample_set.best_feasible >>> solution.objective 3.0
Minimization selects the smallest objective instead. This is the best among the supplied candidates, not a proof of global optimality. Selection raises ValueError when no candidate is feasible, including for an empty SampleSet.
Inspect a candidate’s values and diagnostics
The Solution returned by
get()retains variable labels, evaluated constraints, named metrics, and the evaluation tolerance. Use its extraction methods or queryextract_decision_variables(),extract_constraints(), andextract_named_functions()with a sample ID directly.NamedFunctionrecords additional metrics without changing the objective or adding feasibility conditions.constraintsexposes per-constraint results across samples throughSampledConstraintCollection.constraints_df()selects one family for a table;summaryis the per-sample overview.Evaluate transformed problems
Evaluate candidates with the transformed Instance supplied to the sampler. It retains the fixed values and dependencies needed to restore variables, removed constraints to inspect, and any preserved output objective. Evaluation reports that output objective and sense, which may differ from the active solver-facing objective.
>>> from ommx import Instance, Optimality, Sense >>> original = Instance.maximize() >>> x = original.new_binary("x") >>> y = original.new_binary("y") >>> original.objective = 3 * x + y >>> prepared = original.partial_evaluate({x.id: 1}) >>> assert prepared.convert_active_objective(Sense.Minimize) >>> results = prepared.evaluate_samples({7: {y.id: 0}, 9: {y.id: 1}}) >>> assert results.sense == Sense.Maximize >>> assert results.objectives == {7: 3.0, 9: 4.0} >>> assert results.get(7).state.entries == {x.id: 1.0, y.id: 0.0} >>> assert results.best_feasible_id == 9 >>> assert results.best_feasible.optimality == Optimality.Unspecified
Successful value reconstruction, feasibility, and optimality remain separate questions.
feasibleincludes retained removed constraints;feasible_relaxedexcludes them while still checking all variable domains. SeeSolutionfor output interpretation andpopulate_state()for reconstruction, defaults, and normalization. Choosing the best supplied candidate never establishes optimality of the original or transformed problem.- __copy__() SampleSet#
- add_user_annotation(key: str, value: str, *, annotation_namespace: str = 'org.ommx.user.') None#
- add_user_annotations(annotations: Mapping[str, str], *, annotation_namespace: str = 'org.ommx.user.') None#
- constraint_context_df(*, kind: ConstraintKind[ConstraintIDBase]) DataFrame#
Constraint context DataFrame (id-indexed). See
ommx.Instance.constraint_context_df()for column /kind=semantics. Reads from the sampled collection’s context store.
- constraint_parameters_df(*, kind: ConstraintKind[ConstraintIDBase]) DataFrame#
Constraint parameters DataFrame (long format).
- constraint_provenance_df(*, kind: ConstraintKind[ConstraintIDBase]) DataFrame#
Constraint provenance DataFrame (long format).
- constraint_removed_reasons_df(*, kind: ConstraintKind[ConstraintIDBase]) DataFrame#
Removed-constraint reasons DataFrame (long format).
- constraints_df(*, kind: ConstraintKind[ConstraintIDBase], include: Optional[Sequence[str]] = None) DataFrame#
DataFrame of sampled constraints, dispatched on
kind=. Seeommx.Instance.constraints_df()for column /kind=/include=semantics. Adds dynamic per-sample columns (value.{sample_id},feasible.{sample_id}, etc.) on top of the kind-specific core columns.SampleSethas noremoved=parameter (no active/removed distinction at the sampled stage); reason data is gated by"removed_reason"ininclude=.
- decision_variables_df(include: Optional[Sequence[str]] = None) DataFrame#
DataFrame of decision variables with per-sample value columns. Static columns: id, kind, lower, upper, name, subscripts, description. Dynamic columns: one per sample_id (int) with the variable’s value.
- extract_all_decision_variables(sample_id: int) dict#
Extract all decision variables grouped by name for a given sample ID.
Returns a mapping from variable name to a mapping from subscripts to values. This is useful for extracting all variables at once in a structured format. Variables without names are not included in the result. Inner keys are subscript tuples, with
()for a scalar variable. Parameters and descriptions do not distinguish matching labels. Usestate_from_named_values()on a receiving Instance to resolve its IDs from this dictionary before evaluating it there.Raises KeyError if the sample ID does not exist, and ValueError if the same name and subscript combination is found multiple times.
Examples#
>>> from ommx import DecisionVariable, Instance, Sense >>> x = [DecisionVariable.binary(i, name="x", subscripts=[i]) for i in range(3)] >>> y = [DecisionVariable.binary(i+3, name="y", subscripts=[i]) for i in range(2)] >>> instance = Instance.from_components( ... decision_variables=x + y, ... objective=sum(x) + sum(y), ... constraints={}, ... sense=Sense.Maximize, ... ) >>> sample_set = instance.evaluate_samples({0: {i: 1 for i in range(5)}}) >>> all_vars = sample_set.extract_all_decision_variables(0) >>> all_vars["x"] {(0,): 1.0, (1,): 1.0, (2,): 1.0} >>> all_vars["y"] {(0,): 1.0, (1,): 1.0}
- extract_all_named_functions(sample_id: int) dict#
Extract all named function values grouped by name for a given sample ID.
The outer keys are names; inner keys are subscript tuples, with
()for a scalar metric. Entries without names are excluded. Parameters and descriptions are ignored when grouping.Raises KeyError if the sample ID does not exist, and ValueError if the same name and subscript combination is found multiple times.
- extract_constraints(name: str, sample_id: int) dict[tuple[int, ...], float]#
Extract nonnegative violations of all constraint families by name for one sample.
Raises KeyError if the name or sample ID does not exist. Raises ValueError if matching constraints share subscripts, including across families. Parameters and descriptions are ignored. Retained removed constraints are included. Regular constraints return violations, not signed function values.
- extract_decision_variables(name: str, sample_id: int) dict#
Extract decision variable values for a given name and sample ID.
Returns a dictionary keyed by subscript tuples. A scalar variable uses
(). This is equivalent to extracting the name fromget(sample_id); names and subscripts identify matches, not parameters or descriptions. Seeextract_decision_variables()for the relationship between named dictionaries, variable IDs, and DataFrames.Raises KeyError if the name or sample ID does not exist, and ValueError if the same subscript is found more than once.
>>> from ommx import Instance >>> instance = Instance.maximize() >>> x = instance.new_binary("selected", subscripts=[0]) >>> instance.objective = x >>> results = instance.evaluate_samples({7: {x.id: 1}}) >>> assert results.extract_decision_variables("selected", 7) == {(0,): 1.0} >>> assert results.get(7).extract_decision_variables("selected") == {(0,): 1.0}
- extract_named_functions(name: str, sample_id: int) dict#
Extract named function values for a given name and sample ID.
Returns a dictionary keyed by subscript tuples, with
()for a scalar metric. Named functions report candidate metrics without changing the objective or feasibility conditions. Seeextract_named_functions()for the corresponding single-candidate query, orNamedFunctionfor the complete registration and evaluation workflow. Parameters and descriptions do not distinguish matching labels.Raises KeyError if the name or sample ID does not exist, and ValueError if the same subscript is found more than once.
>>> from ommx import DecisionVariable, Instance, NamedFunction, Sense >>> x = DecisionVariable.binary(0, name="selected") >>> cost = NamedFunction(id=10, function=4 * x, name="cost") >>> instance = Instance.from_components( ... decision_variables=[x], objective=x, constraints={}, ... sense=Sense.Maximize, named_functions=[cost], ... ) >>> results = instance.evaluate_samples({7: {x.id: 0}, 9: {x.id: 1}}) >>> assert results.extract_named_functions("cost", 9) == {(): 4.0} >>> assert results.get(9).extract_named_functions("cost") == {(): 4.0}
- feasible_ids() set[int]#
- feasible_relaxed_ids() set[int]#
- feasible_unrelaxed_ids() set[int]#
- from_v1_bytes(bytes: bytes) SampleSet#
- from_v2_bytes(bytes: bytes) SampleSet#
- get(sample_id: int) Solution#
Return one sample as a Solution.
sample_idis the candidate’s ID, not its row position insummary. The independent result contains evaluated values, variable and constraint labels, retained removed constraints, named functions, reported objective and sense, and the stored tolerance. Changing the extracted Solution does not update the SampleSet. Raises KeyError if the sample ID does not exist.>>> from ommx import Instance, Solution >>> instance = Instance.maximize() >>> x = instance.new_binary("selected", subscripts=[0]) >>> instance.objective = x >>> results = instance.evaluate_samples({10: {x.id: 0}, 20: {x.id: 1}}) >>> assert list(results.summary.index) == [20, 10] >>> solution = results.get(sample_id=10) >>> assert isinstance(solution, Solution) >>> assert solution.objective == 0.0 >>> assert solution.extract_decision_variables("selected") == {(0,): 0.0}
- get_decision_variable_by_id(variable_id: int) SampledDecisionVariable#
Get a specific sampled decision variable by ID
- get_named_function_by_id(named_function_id: int) SampledNamedFunction#
Get a specific sampled named function by ID
- get_sample_by_id(sample_id: int) Solution#
Get sample by ID (alias for get method).
Raises KeyError if the sample ID does not exist.
- get_user_annotation(key: str, *, annotation_namespace: str = 'org.ommx.user.') str#
- get_user_annotations(*, annotation_namespace: str = 'org.ommx.user.') dict[str, str]#
- named_functions_df(include: Optional[Sequence[str]] = None) DataFrame#
DataFrame of named functions with per-sample value columns. Static columns: id, used_ids, name, subscripts, description, parameters.{key}. Dynamic columns: one per sample_id (int) with the function’s evaluated value.
- num_samples() int#
Number of candidate IDs, including repeated assignments with different IDs.
- sample_ids() set[int]#
All candidate IDs as an independent set of integers.
- to_v1_bytes() bytes#
- to_v2_bytes() bytes#
- variable_labels_df() DataFrame#
Decision-variable modeling-label DataFrame (id-indexed).
- variable_parameters_df() DataFrame#
Decision-variable parameters DataFrame (long format).
- property annotations: MappingProxyType[str, str]#
Read-only property.
Returns a read-only mapping of flat annotations.
Use
add_user_annotation(), metadata properties, orreplace_annotations()to modify annotations.
- property best_feasible: Solution#
Read-only property.
The best feasible candidate as an independent Solution.
Selects only candidates satisfying
feasible, including variable domains and retained removed constraints. Minimization selects the smallest reported objective; maximization selects the largest. Selection does not prove global optimality or change the extracted Solution’s optimality status.Raises ValueError if there is no feasible candidate, including when the SampleSet is empty. There is no universal ordering of infeasible candidates: choose your own criteria from the constraint and variable diagnostics. The objective ordering in
summaryis not such a feasibility criterion.>>> from ommx import Instance >>> instance = Instance.maximize() >>> x = instance.new_binary("x") >>> instance.objective = x >>> _ = instance.add_constraint(x == 1, "required") >>> results = instance.evaluate_samples({10: {x.id: 0}, 20: {x.id: 1}}) >>> assert results.best_feasible_id == 20 >>> assert results.best_feasible.state.entries == {x.id: 1.0} >>> infeasible = instance.evaluate_samples([{x.id: 0}]) >>> infeasible.best_feasible Traceback (most recent call last): ... ValueError: No feasible solution found
- property best_feasible_id: int#
Read-only property.
ID of the best feasible candidate, using the same selection as
best_feasible.Raises ValueError if there is no feasible sample, including when empty.
- property best_feasible_relaxed: Solution#
Read-only property.
The best candidate satisfying relaxed feasibility as an independent Solution.
Uses
feasible_relaxed: removed constraints are excluded, while all variable kinds and bounds still apply. The selected candidate can therefore failfeasible. Comparison still uses the reported objective and sense; it does not switch to an active solver-facing objective. Raises ValueError if there is no qualifying candidate, including when empty.
- property best_feasible_relaxed_id: int#
Read-only property.
ID of the best candidate satisfying
feasible_relaxed.Uses the reported objective and
sense, likebest_feasible_relaxed. Raises ValueError if there is no such candidate, including when empty.
- property best_feasible_unrelaxed: Solution#
Read-only property.
Alias for
best_feasible, including removed constraints. Raises ValueError if there is no feasible sample.
- property constraint_names: set[str]#
Read-only property.
Unique names across all constraint families, as a set of strings.
Retained removed constraints are included; no sample ID is needed. The scope matches
extract_constraints. Unnamed constraints are excluded; an explicitly empty name is included. Duplicate names appear once, even when extraction would reject duplicate subscripts. Each access returns a fresh set; editing it does not change this owner.
- property constraints: SampledConstraintCollection#
Read-only property.
Live mapping of all constraint families, including removed results. Typed IDs select the family. Rows are fetched only when indexed.
- property decision_variable_names: set[str]#
Read-only property.
Get all unique decision variable names in this sample set.
Returns a set of all unique variable names. Variables without names are not included.
Examples#
>>> from ommx import DecisionVariable, Instance, Sense >>> x = [DecisionVariable.binary(i, name="x", subscripts=[i]) for i in range(3)] >>> y = [DecisionVariable.binary(i+3, name="y", subscripts=[i]) for i in range(2)] >>> instance = Instance.from_components( ... decision_variables=x + y, ... objective=sum(x) + sum(y), ... constraints={}, ... sense=Sense.Maximize, ... ) >>> sample_set = instance.evaluate_samples({0: {i: 1 for i in range(5)}}) >>> sorted(sample_set.decision_variable_names) ['x', 'y']
- property decision_variables: list[SampledDecisionVariable]#
Read-only property.
Get decision variables for compatibility with existing Python code
- property feasibility_atol: float#
Read-only property.
Absolute tolerance associated with the stored evaluation and feasibility results.
Pass this to an extracted constraint’s explicit feasibility query to use the enclosing result’s threshold.
- property feasible: dict[int, bool]#
Read-only property.
Get feasibility status for all samples, including variable bounds and kinds.
Includes all retained regular and special constraints, even removed ones. Each value matches
feasibleon the corresponding extracted Solution and usesfeasibility_atol.
- property feasible_relaxed: dict[int, bool]#
Read-only property.
Get relaxed feasibility status for all samples.
Removed constraints are excluded; variable bounds and kinds still apply.
- property feasible_unrelaxed: dict[int, bool]#
Read-only property.
Alias for
feasible, keyed by sample ID.
- property named_function_names: set[str]#
Read-only property.
Get all unique named function names in this sample set
- property named_functions: list[SampledNamedFunction]#
Read-only property.
Get named functions for compatibility with existing Python code
- property objectives: dict[int, float]#
Read-only property.
Reported objective values keyed by sample ID.
Evaluation uses the Instance’s preserved output objective when present, otherwise its active objective. An infeasible candidate can still have an objective value; read this together with
feasible.
- property sample_ids_list: list[int]#
Read-only property.
Get sample IDs as a list (property version)
- property sense: Sense#
Read-only property.
The sense associated with the reported objective values.
This is the preserved output sense when recorded by the evaluated Instance, otherwise its active sense.
summaryand thebest_feasibleselectors use it even if a transformation changed the solver-facing sense.
- property summary: DataFrame#
Read-only property.
A materialized overview with one row per sample ID.
The index is
sample_idand the columns areobjectiveandfeasible. Feasibility matchesfeasible, including variable kinds and bounds and all retained constraints, even removed ones. Feasible candidates appear first; within each feasibility group, objective values are ascending for minimization and descending for maximization, according tosense.The index keeps the candidate’s ID rather than its displayed row position; use that ID with
get(). Identical assignments under different IDs remain separate rows. Editing the DataFrame does not update the SampleSet. See theSampleSetexample for the table layout.