Solution API Reference
Solution
Optimization algorithm results.
A Solution stores the results from solving a model, including variable assignments (samples), objective function values, feasibility status, constraint satisfaction, and runtime information.
Solutions can be created directly or converted from various solver formats (e.g., D-Wave, Qiskit, SCIP).
Parameters:
-
samples(Sequence[_Sample]) –List of variable assignment dictionaries.
-
counts(list[int], default:None) –Number of times each sample was observed.
-
raw_energies(list[float], default:None) –Raw energy values from the solver.
-
obj_values(list[float], default:None) –Evaluated objective function values.
-
feasible(list[bool], default:None) –Feasibility status for each sample.
-
constraints(list[dict[str, bool]], default:None) –Constraint satisfaction by constraint name for each sample.
-
variables_bounds(dict[str, list[bool]], default:None) –Variable bound satisfaction by variable name.
-
timing(Timing, default:None) –Runtime and timing information.
-
sense(Sense, default:None) –Optimization sense (MIN or MAX).
-
env(Environment, default:None) –The environment for variables.
-
vtypes(list[Vtype], default:None) –Variable types.
Attributes:
-
obj_values(NDArray or None) –Objective function values for each sample.
-
raw_energies(NDArray or None) –Raw energy values from solver.
-
counts(NDArray) –Observation counts for each sample.
-
runtime(Timing or None) –Timing information.
-
sense(Sense) –Optimization sense.
-
results(ResultIter) –Iterator over result views.
-
samples(Samples) –Collection of variable assignment samples.
-
variable_names(list[str]) –Names of variables in the solution.
Examples:
Create solution from samples:
>>> from luna_model import Solution, Environment, Variable
>>> env = Environment()
>>> x = Variable("x", env=env)
>>> y = Variable("y", env=env)
>>> samples = [{"x": 0, "y": 1}, {"x": 1, "y": 0}]
>>> solution = Solution(
... samples,
... counts=[1, 1],
... obj_values=[5.0, 3.0],
... feasible=[True, True],
... env=env,
... )
Get best results:
>>> best_results = solution.best()
>>> for result in best_results:
... print(f"Value: {result.obj_value}, Sample: {result.sample.to_dict()}")
Value: 3.0, Sample: {'x': 1, 'y': 0}
Filter feasible solutions:
Compute statistics:
obj_values: NDArray | None
property
writable
Get objective function values for each sample.
Returns:
-
NDArray or None–Array of objective values, one per sample.
raw_energies: NDArray | None
property
writable
Get raw energies.
counts: NDArray
property
Get counts.
runtime: Timing | None
property
writable
Get runtime.
sense: Sense
property
Get sense.
results: ResultIter
property
Get results.
samples: Samples
property
Get samples.
variable_names: list[str]
property
Get variable names.
__init__(samples: Sequence[_Sample], counts: list[int] | None = None, raw_energies: list[float] | None = None, obj_values: list[float] | None = None, feasible: list[bool] | None = None, constraints: Sequence[dict[str, bool]] | None = None, variables_bounds: dict[str, list[bool]] | None = None, timing: Timing | None = None, sense: Sense | None = None, env: Environment | None = None, vtypes: list[Vtype] | None = None) -> None
Initialize a solution with samples and metadata.
best() -> list[ResultView] | None
Get the best results according to the optimization sense.
Returns:
-
list[ResultView] or None–List of best results (lowest for MIN, highest for MAX).
cvar(alpha: float, value_toggle: ValueSource = ValueSource.OBJ) -> float
Compute Conditional Value at Risk (CVaR).
CVaR is the expected value of the best (lowest for MIN, highest for MAX) alpha fraction of samples, weighted by their counts.
Parameters:
-
alpha(float) –Risk level (0 < alpha <= 1). The fraction of best samples to consider.
-
value_toggle(ValueSource, default:OBJ) –Whether to use objective values or raw energies. Default is OBJ.
Returns:
-
float–The CVaR value (expected value of the alpha-tail).
Raises:
-
ValueError–If alpha is not in the range (0, 1].
temperature_weighted(beta: float, value_toggle: ValueSource = ValueSource.OBJ) -> float
Compute temperature-weighted expectation value.
Parameters:
-
beta(float) –Inverse temperature parameter (beta = 1/T). Higher values emphasize lower-energy states.
-
value_toggle(ValueSource, default:OBJ) –Whether to use objective values or raw energies. Default is OBJ.
Returns:
-
float–The temperature-weighted expectation value.
expectation_value(value_toggle: ValueSource = ValueSource.OBJ) -> float
Compute the expectation value weighted by counts.
Parameters:
-
value_toggle(ValueSource, default:OBJ) –Whether to use objective values or raw energies.
Returns:
-
float–The weighted mean value.
feasibility_ratio() -> float
filter(f: FilterFn) -> Solution
Filter results by a custom predicate function.
Parameters:
-
f(FilterFn) –Function that takes a ResultView and returns bool.
Returns:
-
Solution–New solution containing only filtered results.
filter_feasible() -> Solution
Filter to keep only feasible results.
Returns:
-
Solution–New solution containing only feasible results.
highest_constraint_violation() -> str | None
Get the constraint with the highest violation rate.
Returns:
-
str or None–Name of the constraint with the highest violation rate across all samples, or None if no constraints are violated or no constraint information exists.
print(layout: Literal['row', 'column'] = 'column', max_line_len: int = 80, max_col_len: int = 5, max_lines: int = 10, max_var_name_len: int = 10, show_metadata: Literal['before', 'after', 'hide'] = 'after') -> str
Get formatted string representation of the solution.
Parameters:
-
layout(('row', 'column'), default:"row") –Layout orientation for displaying samples. Default is "column".
-
max_line_len(int, default:80) –Maximum line length in characters. Default is 80.
-
max_col_len(int, default:5) –Maximum number of samples to display. Default is 5.
-
max_lines(int, default:10) –Maximum number of variable rows to display. Default is 10.
-
max_var_name_len(int, default:10) –Maximum variable name length. Default is 10.
-
show_metadata(('before', 'after', 'hide'), default:"before") –Where to show metadata (objective, feasibility, etc.). Default is "after".
Returns:
-
str–Formatted string representation.
add_var(var: str | Variable, data: Sequence[int | float], vtype: Vtype = Vtype.BINARY) -> None
Add a variable to all samples in the solution.
Parameters:
add_vars(variables: Sequence[Variable | str], data: Sequence[Sequence[int | float]], vtypes: Sequence[Vtype | None] | None = None) -> None
Add multiple variables to all samples in the solution.
Parameters:
-
variables(Sequence[Variable or str]) –List of variable names or Variable objects to add.
-
data(Sequence[Sequence[int or float]]) –Values for each variable across all samples. Outer sequence length must match number of variables, inner sequence length must match number of samples.
-
vtypes(Sequence[Vtype or None], default:None) –Variable types for each variable. If None, types are inferred.
remove_var(var: str | Variable) -> None
remove_vars(variables: Sequence[str | Variable]) -> None
__len__() -> int
__iter__() -> ResultIter
__getitem__(item: int) -> ResultView
Get a result by index.
Parameters:
-
item(int) –Index of the result to retrieve.
Returns:
-
ResultView–The result at the given index.
__eq__(other: Solution) -> bool
__reduce__() -> tuple[Callable[[bytes], Solution], tuple[bytes]]
encode() -> bytes
serialize() -> bytes
decode(data: bytes) -> Solution
classmethod
deserialize(data: bytes) -> Solution
classmethod
from_(other: SolutionFromTypes, timing: Timing | None = None, env: Environment | None = None, **kwargs: Any) -> Solution
classmethod
Create solution from various solver result formats.
Automatically detects the format and converts to a Solution object. Supports D-Wave SampleSet, Qiskit PrimitiveResult, SCIP Model, numpy arrays, dictionaries, and more.
Parameters:
-
other(SolutionFromTypes) –Result object from a solver (SampleSet, PrimitiveResult, etc.) or data structure (dict, list, ndarray).
-
timing(Timing, default:None) –Runtime information to attach to the solution.
-
env(Environment, default:None) –Environment for variables. Required for some formats.
-
**kwargs(Any, default:{}) –Additional keyword arguments specific to the source format.
Returns:
-
Solution–Converted solution object.
Raises:
-
ValueError–If the format is not recognized or supported.
-
RuntimeError–If required dependencies are not installed.
from_dict(data: _Sample, env: Environment | None = None, model: Model | None = None, timing: Timing | None = None, counts: int | None = None, sense: Sense | None = None, energy: float | None = None) -> Solution
classmethod
Create solution from a single sample dictionary.
Parameters:
-
data(dict) –Single sample as a dictionary mapping variable names/objects to values.
-
env(Environment, default:None) –Environment containing the variables.
-
model(Model, default:None) –Model to evaluate the sample against.
-
timing(Timing, default:None) –Runtime information.
-
counts(int, default:None) –Number of times this sample was observed. Default is 1.
-
sense(Sense, default:None) –Optimization sense. Inferred from model if provided.
-
energy(float, default:None) –Raw energy value for this sample.
Returns:
-
Solution–Solution containing one sample.
from_dicts(data: Sequence[_Sample], env: Environment | None = None, model: Model | None = None, timing: Timing | None = None, counts: list[int] | None = None, sense: Sense | None = None, energies: list[float] | None = None) -> Solution
classmethod
Create solution from multiple sample dictionaries.
Parameters:
-
data(Sequence[_Sample]) –List of samples, each as a dictionary mapping variable names/objects to values.
-
env(Environment, default:None) –Environment containing the variables.
-
model(Model, default:None) –Model to evaluate the samples against.
-
timing(Timing, default:None) –Runtime information.
-
counts(list[int], default:None) –Number of times each sample was observed. Default is 1 for each.
-
sense(Sense, default:None) –Optimization sense. Inferred from model if provided.
-
energies(list[float], default:None) –Raw energy values for each sample.
Returns:
-
Solution–Solution containing multiple samples.
from_arrays(data: NDArray, variables: Sequence[Variable | str] | None = None, env: Environment | None = None, model: Model | None = None, timing: Timing | None = None, counts: list[int] | None = None, sense: Sense | None = None, energies: list[float] | None = None) -> Solution
classmethod
Create solution from numpy arrays.
Parameters:
-
data(NDArray) –2D array where rows are samples and columns are variables.
-
variables(Sequence[Variable or str], default:None) –Variable names/objects corresponding to columns. Inferred from env or model if not provided.
-
env(Environment, default:None) –Environment containing the variables.
-
model(Model, default:None) –Model to evaluate the samples against.
-
timing(Timing, default:None) –Runtime information.
-
counts(list[int], default:None) –Number of times each sample was observed. Default is 1 for each.
-
sense(Sense, default:None) –Optimization sense. Inferred from model if provided.
-
energies(list[float], default:None) –Raw energy values for each sample.
Returns:
-
Solution–Solution created from array data.
from_counts(data: dict[str, int], env: Environment | None = None, model: Model | None = None, timing: Timing | None = None, sense: Sense | None = None, bit_order: Literal['LTR', 'RTL'] = 'RTL', energies: list[float] | None = None, var_order: list[str] | None = None) -> Solution
classmethod
Create solution from a counts dictionary.
Parameters:
-
data(dict[str, int]) –Dictionary mapping bitstrings (e.g., "0101") to observation counts.
-
env(Environment, default:None) –Environment containing the variables.
-
model(Model, default:None) –Model to evaluate the samples against.
-
timing(Timing, default:None) –Runtime information.
-
sense(Sense, default:None) –Optimization sense. Inferred from model if provided.
-
bit_order(('LTR', 'RTL'), default:"LTR") –Bit order interpretation: "RTL" (right-to-left, default) or "LTR" (left-to-right).
-
energies(list[float], default:None) –Raw energy values for each unique bitstring.
-
var_order(list[str], default:None) –Order of variable names corresponding to bit positions. Inferred from env or model if not provided.
Returns:
-
Solution–Solution created from counts data.
from_random(n_samples: int, seed: int | None = None, env: Environment | None = None, model: Model | None = None, sense: Sense | None = None) -> Solution
classmethod
Create a Solution from random sampling.
If a Model is passed, the solution will be evaluated immediately. Otherwise, there has to be an environment present to determine the correct variable types.
Parameters:
-
n_samples(int) –The number of samples drawn randomly.
-
seed(int, default:None) –The random seed
-
env(Environment, default:None) –The environment the variable types shall be determined from.
-
model(Model, default:None) –A model to evaluate the samples with.
-
sense(Senes, default:None) –The sense if no model is specified
Returns:
-
Solution–The solution object created from random sampling.
__str__() -> str
Get string representation of the solution.
Returns:
-
str–Formatted string showing samples and metadata.
__repr__() -> str
Get debug string representation of the solution.
Returns:
-
str–Debug representation including type and memory address.
Sample
Bases: Protocol
Protocol for a single solution sample.
Represents variable assignments for one solution. Can be accessed by variable ID, name, or Variable object.
Examples:
>>> from luna_model import Environment, Solution, Vtype
>>> solution = Solution(
... [{"x": 1, "y": 0, "z": 1}], counts=[1], raw_energies=[3], vtypes=[Vtype.BINARY, Vtype.BINARY, Vtype.BINARY]
... )
>>> result = solution[0]
>>> sample = result.sample
>>> value = sample["x"] # Access by name
>>> print(value)
1
>>> print(sample.to_dict())
{'x': 1, 'y': 0, 'z': 1}
to_dict() -> dict[str, int | float]
__getitem__(item: int | Variable | str) -> int | float
Get a variable value by ID, Variable, or name.
__len__() -> int
Get the number of variables in the sample.
__iter__() -> SampleIter
Iterate over variable values in the sample.
__str__() -> str
Return string representation of the sample.
Result
Bases: Protocol
Protocol for solution results.
Provides access to solution information including the sample, objective value, feasibility, and constraint satisfaction.
Attributes:
-
sample(Sample) –The variable assignments in this result.
-
obj_value(float or None) –The objective function value, if available.
-
constraints(dict[str, bool] or None) –Constraint satisfaction status by constraint name.
-
variable_bounds(dict[str, bool] or None) –Variable bound satisfaction status by variable name.
-
feasible(bool or None) –Whether the solution is feasible, if known.
sample: Sample
property
Get the variable assignments as a Sample.
obj_value: float | None
property
Get the objective function value.
constraints: dict[str, bool] | None
property
Get constraint satisfaction status.
variable_bounds: dict[str, bool] | None
property
Get variable bound satisfaction status.
feasible: bool | None
property
Get feasibility status.
ResultView
Extended result view with additional metadata.
Extends Result with counts, raw energy, and comparison capabilities.
Attributes:
-
counts(int) –Number of times this result was observed.
-
raw_energy(float or None) –Raw energy value from the solver, if available.
sample: Sample
property
Get the variable assignments as a Sample.
obj_value: float | None
property
Get the objective function value.
constraints: dict[str, bool] | None
property
Get constraint satisfaction status.
variable_bounds: dict[str, bool] | None
property
Get variable bound satisfaction status.
feasible: bool | None
property
Get feasibility status.
counts: int
property
Get the number of times this result was observed.
raw_energy: float | None
property
Get the raw energy from the solver.
__str__() -> str
Get human-readable string representation of the result view.
__repr__() -> str
Get debug string representation of the result view.
__eq__(other: ResultView) -> bool
Check if two result views are exactly equal.
ResultIter
Bases: Protocol
Iterates over ResultView objects in a solution.
__iter__() -> ResultIter
Return the iterator object itself.
__next__() -> ResultView
Get the next result view.