VariationalQuantumAlgorithm¶
- class VariationalQuantumAlgorithm(backend, optimizer=None, seed=None, progress_queue=None, early_stopping=None, **kwargs)[source]¶
Bases:
ObservableMeasuringMixin,QuantumProgramBase class for variational quantum algorithms.
This class provides the foundation for implementing variational quantum algorithms in Divi. It handles circuit execution, parameter optimization, and result management for algorithms that optimize parameterized quantum circuits to minimize cost functions.
Variational algorithms work by: 1. Generating parameterized quantum circuits 2. Executing circuits on quantum hardware/simulators 3. Computing expectation values of cost Hamiltonians 4. Using classical optimizers to update parameters 5. Iterating until convergence
- Variables:
_losses_history – History of loss values during optimization.
_param_history (
list[ndarray[tuple[Any,...],dtype[double]]]) – Raw per-callback parameter batches; useparam_history()to read copies with optional filtering._final_params – Final optimized parameters.
_best_params – Parameters that achieved the best loss.
_best_loss (
float) – Best loss achieved during optimization._circuits – Generated quantum circuits.
_total_circuit_count (
int) – Total number of circuits executed._total_run_time (
float) – Total execution time in seconds._seed – Random seed for parameter initialization.
_rng – Random number generator.
_grouping_strategy – Strategy for grouping quantum operations.
_qem_protocol – Quantum error mitigation protocol.
_cancellation_event – Event for graceful termination.
_meta_circuit_factories (
dict) – Lazily-built mapping of circuit names to MetaCircuit factories.
Initialize the VariationalQuantumAlgorithm.
This constructor is specifically designed for hybrid quantum-classical variational algorithms. The instance variables n_layers and n_params_per_layer must be set by subclasses, where: - n_layers is the number of layers in the quantum circuit. - n_params_per_layer is the number of parameters per layer.
For exotic variational algorithms where these variables may not be applicable, the _initialize_param_sets method should be overridden to generate the starting parameters for a fresh optimization run.
- Parameters:
backend (
CircuitRunner) – Quantum circuit execution backend.optimizer (
Optimizer|None) – The optimizer to use for parameter optimization. Defaults to MonteCarloOptimizer().seed (
int|None) – Random seed for parameter initialization. Defaults to None.progress_queue (
Queue|None) – Queue for progress reporting. Defaults to None.early_stopping (
EarlyStopping|None) – Early stopping controller. When provided, the optimization loop will be halted if any of the configured criteria are met (e.g. patience exceeded, gradient below threshold, cost variance settled). Defaults to None.
- Keyword Arguments:
grouping_strategy (
str) – Strategy for partitioning Hamiltonian terms into compatible measurement groups; one circuit is executed per group. Options:"qwc"(qubit-wise-commuting — most compact),"wires"(group by support wires), orNone(one circuit per term). Defaults to"qwc".shot_distribution (
strorcallable(), optional) –Focus the backend’s shot budget on the Hamiltonian terms that matter most. Without this option, every measurement group is sampled with the backend’s full shot count, even tiny terms with little impact on the final energy. With
shot_distributionset, the same total budget is split across groups according to their importance — reducing variance without spending more shots.Available strategies:
"uniform"— equal split across groups."weighted"— proportional to per-group coefficient L1 norm; dominant Hamiltonian terms get more shots."weighted_random"— multinomial sample of the same probabilities; may drop more low-weight groups than the deterministic"weighted"for the same budget.A callable
(group_l1_norms, total_shots) -> per_group_shotsfor fully custom allocation.
Example:
vqe = MyVQA( backend=QiskitSimulator(shots=1000), shot_distribution="weighted", ) vqe.run()
Only valid when sampling is actually used. Setting it on a backend that computes expectation values analytically (
grouping_strategy="_backend_expval") is rejected because shots are ignored in that mode. Defaults toNone(every group receives the full shot budget).precision (
int) – Forwarded toQuantumProgram— decimal places for numeric parameter values in QASM conversion. Higher values produce longer QASM strings (more data sent to cloud backends); lower values trade resolution for compactness. Defaults toDEFAULT_PRECISION.decode_solution_fn – Function to decode bitstrings into problem-specific solution representations. Called during final computation and when get_top_solutions(include_decoded=True) is used. The function should take a binary string (e.g., “0101”) and return a decoded representation (e.g., a list of indices, numpy array, or custom object). Defaults to lambda bitstring: bitstring (identity function).
Attributes Summary
Get the best loss achieved so far.
Get a copy of the parameters that achieved the best (lowest) loss.
Get normalized probabilities for the best parameters.
Get a copy of the final optimized parameters.
Get a copy of the optimization loss history.
Get the meta-circuit factories used by this program.
Get the minimum loss value for each iteration.
Number of trainable parameters per ansatz layer.
Reason the optimization was stopped early, or
None.Access visualization helpers for this variational program.
Methods Summary
Get the expected shape for initial parameters.
get_top_solutions([n, min_prob, include_decoded])Get the top-N solutions sorted by probability.
Return True once the program has produced results.
load_state(checkpoint_dir, backend[, ...])Load program state from a checkpoint directory.
param_history([mode])Parameter vectors recorded at each optimization callback.
run([initial_params, ...])Run the variational quantum algorithm.
sample_solution([params])Run the final measurement and decode the solution.
save_state(checkpoint_config)Save the program state to a checkpoint directory.
Attributes Documentation
- best_loss¶
Get the best loss achieved so far.
- Returns:
The best loss achieved so far.
- Return type:
- best_params¶
Get a copy of the parameters that achieved the best (lowest) loss.
- Returns:
- Copy of the best parameters. Modifications to this array
will not affect the internal state.
- Return type:
npt.NDArray[np.float64]
- best_probs¶
Get normalized probabilities for the best parameters.
This property provides access to the probability distribution computed by running measurement circuits with the best parameters found during optimization. The distribution maps bitstrings (computational basis states) to their measured probabilities.
The probabilities are normalized and have deterministic ordering when iterated (dictionary insertion order is preserved in Python 3.7+).
- Returns:
- Dictionary mapping parameter-set keys to
bitstring probability dictionaries. Bitstrings are binary strings (e.g., “0101”), values are probabilities in range [0.0, 1.0]. Returns an empty dict if final computation has not been performed.
- Return type:
- Raises:
RuntimeError – If attempting to access probabilities before running the algorithm with final computation enabled.
Note
To populate this distribution, you must run the algorithm with perform_final_computation=True (the default):
>>> program.run(perform_final_computation=True) >>> probs = program.best_probs
Example
>>> program.run() >>> probs = program.best_probs >>> for bitstring, prob in probs.items(): ... print(f"{bitstring}: {prob:.2%}") 0101: 42.50% 1010: 31.20% ...
- final_params¶
Get a copy of the final optimized parameters.
- Returns:
- Copy of the final parameters. Modifications to this array
will not affect the internal state.
- Return type:
npt.NDArray[np.float64]
- losses_history¶
Get a copy of the optimization loss history.
Each entry is a dictionary mapping parameter indices to loss values.
- meta_circuit_factories¶
Get the meta-circuit factories used by this program.
- Returns:
- Dictionary mapping circuit names to their
MetaCircuit factories.
- Return type:
- min_losses_per_iteration¶
Get the minimum loss value for each iteration.
Returns a list where each element is the minimum (best) loss value across all parameter sets for that iteration.
- n_params_per_layer¶
Number of trainable parameters per ansatz layer.
Used by the base class to compute the total parameter count as
n_layers * n_params_per_layer.
- stop_reason¶
Reason the optimization was stopped early, or
None.- Returns:
- The
StopReason that triggered early stopping, or
Noneif optimization completed normally or has not been run yet.
- The
- Return type:
StopReason | None
- viz¶
Access visualization helpers for this variational program.
The returned object exposes a thin convenience wrapper over the standalone
divi.vizAPI, so scans can be written either asdivi.viz.scan_1d(program, ...)orprogram.viz.scan_1d(...).- Returns:
Convenience wrapper bound to this program instance.
- Return type:
Methods Documentation
- get_top_solutions(n=10, *, min_prob=0.0, include_decoded=False)[source]¶
Get the top-N solutions sorted by probability.
This method extracts the most probable solutions from the measured probability distribution. Solutions are sorted by probability (descending) with deterministic tie-breaking using lexicographic ordering of bitstrings.
- Parameters:
n (
int) – Maximum number of solutions to return. Must be non-negative. If n is 0 or negative, returns an empty list. If n exceeds the number of available solutions (after filtering), returns all available solutions. Defaults to 10.min_prob (
float) – Minimum probability threshold for including solutions. Only solutions with probability >= min_prob will be included. Must be in range [0.0, 1.0]. Defaults to 0.0 (no filtering).include_decoded (
bool) – Whether to populate the decoded field of each SolutionEntry by calling the decode_solution_fn provided in the constructor. If False, the decoded field will be None. Defaults to False.
- Returns:
- List of solution entries sorted by probability
(descending), then by bitstring (lexicographically ascending) for deterministic tie-breaking. Returns an empty list if no probability distribution is available or n <= 0.
- Return type:
- Raises:
RuntimeError – If probability distribution is not available because optimization has not been run or final computation was not performed.
ValueError – If min_prob is not in range [0.0, 1.0] or n is negative.
Note
The probability distribution must be computed by running the algorithm with perform_final_computation=True (the default):
>>> program.run(perform_final_computation=True) >>> top_10 = program.get_top_solutions(n=10)
Example
>>> # Get top 5 solutions with probability >= 5% >>> program.run() >>> solutions = program.get_top_solutions(n=5, min_prob=0.05) >>> for sol in solutions: ... print(f"{sol.bitstring}: {sol.prob:.2%}") 1010: 42.50% 0101: 31.20% 1100: 15.30% 0011: 8.50% 1111: 2.50%
>>> # Get solutions with decoding >>> solutions = program.get_top_solutions(n=3, include_decoded=True) >>> for sol in solutions: ... print(f"{sol.bitstring} -> {sol.decoded}") 1010 -> [0, 2] 0101 -> [1, 3] ...
- classmethod load_state(checkpoint_dir, backend, subdirectory=None, **kwargs)[source]¶
Load program state from a checkpoint directory.
- Return type:
- param_history(mode='all_evaluated')[source]¶
Parameter vectors recorded at each optimization callback.
- Parameters:
mode (
Literal['all_evaluated','best_per_iteration']) –Which rows to return for each iteration:
"all_evaluated"— full batch from the callback, shape(n_param_sets, n_params)per iteration (mirrorslosses_historypopulation layout)."best_per_iteration"— single best member by loss for that iteration, shape(1, n_params)per iteration.
- Returns:
One array per completed callback. Use
numpy.vstack(...)for a 2D sample matrix (e.g. PCA).- Return type:
- Raises:
RuntimeError – If internal loss and parameter histories are out of sync.
- run(initial_params=None, perform_final_computation=True, checkpoint_config=None, **kwargs)[source]¶
Run the variational quantum algorithm.
The outputs are stored in the algorithm object and can be accessed via properties such as
total_circuit_count,total_run_time,losses_history, andbest_params.- Parameters:
initial_params (
ndarray[tuple[Any,...],dtype[double]] |None) – Optional initial parameter sets for a fresh optimization run. Must have shape(n_param_sets, n_layers * n_params_per_layer). Cannot be combined with a checkpoint-resumed optimizer state.perform_final_computation (
bool) – Whether to perform final computation after optimization completes. Typically, this step involves sampling with the best found parameters to extract solution probability distributions. Set this to False in warm-starting or pre-training routines where the final sampling step is not needed. Defaults to True.checkpoint_config (
CheckpointConfig|None) – Checkpoint configuration. If None, no checkpointing is performed.**kwargs – Additional keyword arguments for subclasses.
- Returns:
Returns
selffor method chaining.- Return type:
- sample_solution(params=None, **kwargs)[source]¶
Run the final measurement and decode the solution.
Called by
run()(withparams=None, falling back toself._best_params) after optimization completes. It can also be called directly with externally-providedparamswhen you already have trained parameters (e.g. from a priorrun(), a checkpoint, or external training) and only need to sample the circuit — skipping the EXPECTATION jobs thatrun()would otherwise dispatch during optimization.When called with explicit
params, this method does NOT mutateself._best_paramsor any optimizer state (optimize_result,_losses_history,_param_history,current_iteration). Only the measurement-side attributes are updated:_best_probs,_total_circuit_count,_total_run_time, and subclass-specific solution fields (e.g.solution_bitstringfor QAOA,_eigenstatefor VQE).- Parameters:
params (
ndarray[tuple[Any,...],dtype[double]] |None) – Optional parameter set to evaluate. Must have shape(n_layers * n_params_per_layer,)for a single set or(n_param_sets, n_layers * n_params_per_layer)for a batch. WhenNone(the default), usesself._best_params.**kwargs – Subclass-specific keyword arguments.
- Returns:
Returns
selffor method chaining.- Return type:
- Raises:
ValueError – If
paramsdoes not have the expected number of parameters per set.RuntimeError – If
params=Noneandself._best_paramsis empty (i.e.run()has not been called yet).
Note
Subclasses override this method to add their algorithm-specific decoding step. They should call
super().sample_solution(params)to perform parameter validation and the measurement-pipeline dispatch, then read fromself._best_probsto extract algorithm-specific solution state.