qrunch.quantum.algorithms.second_quantization.vqes.vqe_protocols

Interfaces for the VQE classes and their options dataclasses.

Classes

AdaptiveIterationCallback

Protocol for a callback that can be called at each iteration of the adaptive minimizer.

IntermittentOrbitalOptimizerAlgorithmOptions

Options for when to apply orbital optimization in an iterative VQE.

OrbitalOptimizationAction

Action to take for an intermittent orbital optimization step.

SecondQuantizationAdaptiveVqeAlgorithm

Protocol class for VQE that takes a second quantized operator as input and returns the eigenvalue.

SecondQuantizationAdaptiveVqeResult

Result of the SecondQuantizationAdaptiveVqe calculation.

SecondQuantizationVqeAlgorithm

Protocol class for VQE that takes a second quantized operator as input and returns the eigenvalue.

SecondQuantizationVqeResult

Result of the VQE calculation.

class AdaptiveIterationCallback

Bases: Protocol

Protocol for a callback that can be called at each iteration of the adaptive minimizer.

__init__(*args, **kwargs)
record_adaptive_iteration(adaptive_iteration: int, unoptimized_circuit: Circuit, minimized_parameters: dict[Parameter, float], expectation_value: ExpectationValue, n_estimator_shots: int, operator: FermionHermitianSum | PairedHardcoreBosonHermitianSum | None = None) → None

Call the callback function with the indicated parameters from the finished adaptive iteration.

Note that the adaptive_iteration integer starts at 0 and is incremented with 1 each iteration, except for when reminimizing, then a special value of -1 is given.

Parameters:
Return type:

None

class IntermittentOrbitalOptimizerAlgorithmOptions

Bases: DataclassPublicAPI

Options for when to apply orbital optimization in an iterative VQE.

All fields are immutable (frozen=True) so an instance can be safely reused.

The orbital optimization is considered on every every_nth_iteration-th adaptive VQE iteration. When considered, the orbital gradient norm is computed and compared against two thresholds to decide how much work to do:

  • If the gradient norm is above gradient_threshold, a full (converged) orbital optimization is performed via OrbitalOptimizerAlgorithm.run().

  • If the gradient norm is between skip_gradient_threshold and gradient_threshold, a cheap single Newton step is performed via OrbitalOptimizerAlgorithm.run_single_step(). This evaluates one gradient and solves one Hessian system — roughly the same cost as computing the gradient norm — but still updates the orbitals so they track the shifting landscape as new gates are added.

  • If the gradient norm is below skip_gradient_threshold, the orbital optimization step is skipped entirely (orbital change is reported as 0.0).

Additionally, if the orbital change of the last OO step exceeds orbital_change_threshold, a full optimization is performed regardless of the gradient norm.

After force_full_after_n_non_full_steps consecutive iterations where the decision was not FULL (i.e. SINGLE_STEP or SKIP), a forced (unconditional, fully converged) orbital optimization is performed regardless of the gradient norm or orbital change. Set to 0 to disable this safety net.

Parameters:
  • every_nth_iteration – How often to consider an OO step (default=1, i.e. every iteration).

  • gradient_threshold – Below this gradient norm a single Newton step is taken instead of a full optimization (default=1.0e99).

  • skip_gradient_threshold – Below this gradient norm the orbital optimization is skipped entirely (default=1.0e-16). Must be less than or equal to gradient_threshold.

  • orbital_change_threshold – If the absolute orbital change from the previous OO step exceeds this value, a full optimization is performed (default=1.0e99).

  • force_full_after_n_non_full_steps – Force a full optimization after this many consecutive non-full (single-step or skip) OO decisions (default=10). Set to 0 to disable.

  • gate_addition_threshold – If the absolute change due to addition of gate exceeds this value, a full optimization is performed (default=1.0e-3).

__init__(*, every_nth_iteration: int = 1, gradient_threshold: float = inf, skip_gradient_threshold: float = 1e-16, orbital_change_threshold: float = inf, force_full_after_n_non_full_steps: int = 10, gate_addition_threshold: float = 0.001) → None
Parameters:
  • every_nth_iteration (int)

  • gradient_threshold (float)

  • skip_gradient_threshold (float)

  • orbital_change_threshold (float)

  • force_full_after_n_non_full_steps (int)

  • gate_addition_threshold (float)

Return type:

None

classmethod accurate() → IntermittentOrbitalOptimizerAlgorithmOptions

Accurate preset: Does full orbital optimization at every iteration.

Return type:

IntermittentOrbitalOptimizerAlgorithmOptions

classmethod balanced() → IntermittentOrbitalOptimizerAlgorithmOptions

Balanced preset.

A single Newton step is taken at every iteration.

Except that it does full orbital optimization whenever new gate cause large change. Furthermore, it does a full orbital optimization after 10 conscutive iterations where the orbital optimization is not full, to ensure that the orbitals track the shifting landscape as new gates are added.

Return type:

IntermittentOrbitalOptimizerAlgorithmOptions

every_nth_iteration: int = 1
force_full_after_n_non_full_steps: int = 10
gate_addition_threshold: float = 0.001
gradient_threshold: float = inf
orbital_change_threshold: float = inf
classmethod quick() → IntermittentOrbitalOptimizerAlgorithmOptions

Quick preset: a single Newton step is taken at every iteration.

Return type:

IntermittentOrbitalOptimizerAlgorithmOptions

skip_gradient_threshold: float = 1e-16
class OrbitalOptimizationAction

Bases: Enum

Action to take for an intermittent orbital optimization step.

The three tiers are:

  • SKIP The orbital gradient is very small and no orbital optimization is needed. The orbital change is reported as 0.0.

  • SINGLE_STEP A single Newton step is taken.

  • FULL A fully converged orbital optimization is performed.

FULL = 'full'
SINGLE_STEP = 'single_step'
SKIP = 'skip'
class SecondQuantizationAdaptiveVqeAlgorithm

Bases: ABC

Protocol class for VQE that takes a second quantized operator as input and returns the eigenvalue.

The VQEs are based on an underlying quantum algorithm, which perform the eigenvalue calculation.

abstractmethod clear_cache() → None

Clear the cache of the underlying VQE.

Return type:

None

abstractmethod run(second_quantized_operator: T, gate_pool: GatePool, initial_ansatz: Circuit, callback: AdaptiveIterationCallback | None = None, input_result: SecondQuantizationAdaptiveVqeResult[T] | None = None) → SecondQuantizationAdaptiveVqeResult[T]

Run the VQE and find the eigenvalue.

Parameters:
  • second_quantized_operator (T) – The operator whose expectation value should be minimized.

  • gate_pool (GatePool) – The set of gates to choose from when building the ansatz.

  • initial_ansatz (Circuit) – The starting ansatz circuit. Gates from the gate_pool is appended to this.

  • callback (AdaptiveIterationCallback | None) – An optional callback function that is called at each adaptive iteration.

  • input_result (SecondQuantizationAdaptiveVqeResult[T] | None) – A prior results that should be refined.

Return type:

SecondQuantizationAdaptiveVqeResult[T]

class SecondQuantizationAdaptiveVqeResult

Bases: HasCustomEncoding, Generic[T_COV]

Result of the SecondQuantizationAdaptiveVqe calculation.

All fields are immutable (frozen=True) so an instance can be safely reused.

Parameters:
  • unspecified_circuit – Circuit ansatz

  • parameters – Optimal parameters that minimizes the expectation value of the ansatz

  • estimated_value – Final estimated expectation value of the operator.

  • estimated_value_per_gate_iteration – Estimated expectation value of the operator for every iteration where an additional gate was added.

  • operator – The second quantized operator under consideration. Might be rotated compared to the input.

  • is_converged – True if VQE converged.

  • best_iteration – The iteration with the best estimated cost

__init__(unspecified_circuit: Circuit, parameters: dict[Parameter, float], estimated_value: ExpectationValue, estimated_value_per_gate_iteration: ListOfExpectationValues, operator: T_COV, is_converged: bool, best_iteration: int) → None
Parameters:
Return type:

None

best_iteration: int
classmethod decode(data: dict[str, Any]) → SecondQuantizationAdaptiveVqeResult[T_COV]

Decode a dictionary to an instance of TensorHyperContractionIntegrals.

Parameters:

data (dict[str, Any]) – The dictionary representation of a TensorHyperContractionIntegrals instance.

Return type:

SecondQuantizationAdaptiveVqeResult[T_COV]

encode() → dict[str, Any]

Encode the instance into a dictionary.

Return type:

dict[str, Any]

estimated_value: ExpectationValue
estimated_value_per_gate_iteration: ListOfExpectationValues
is_converged: bool
operator: T_COV
parameters: dict[Parameter, float]
property specified_circuit: Circuit

Circuit ansatz with the optimal parameters.

to_pauli_result() → PauliAdaptiveVqeResult

Return the result of the VQE calculation as a Pauli VQE result.

Return type:

PauliAdaptiveVqeResult

unspecified_circuit: Circuit
class SecondQuantizationVqeAlgorithm

Bases: ABC

Protocol class for VQE that takes a second quantized operator as input and returns the eigenvalue.

The VQEs are based on an underlying quantum algorithm, which perform the eigenvalue calculation.

abstractmethod clear_cache() → None

Clear the cache of the underlying VQE.

Return type:

None

abstractmethod run(second_quantized_operator: T, circuit: Circuit, initial_parameter_guess: dict[Parameter, float] | None = None) → SecondQuantizationVqeResult[T]

Run the VQE and find the eigenvalue.

Parameters:
  • second_quantized_operator (T) – The operator whose expectation value should be minimized.

  • circuit (Circuit) – The parametrized circuit to find optimal parameters for. Should contain unspecified parameters.

  • initial_parameter_guess (dict[Parameter, float] | None) – Dict specifying the initial value of each Parameter. If None is given initial guess is 0.0

Return type:

SecondQuantizationVqeResult[T]

class SecondQuantizationVqeResult

Bases: Generic[T_COV]

Result of the VQE calculation.

All fields are immutable (frozen=True) so an instance can be safely reused.

Parameters:
  • estimator_shots – The total amount of shots used by the estimator

  • parameters – Optimal parameters that minimizes the expectation value of the ansatz.

  • estimated_value – Final estimated expectation value of the operator.

  • operator – The second quantized operator under consideration. Might be rotated compared to the input.

  • unspecified_circuit – The unspecified circuit.

__init__(estimator_shots: int, parameters: dict[Parameter, float], estimated_value: ExpectationValue, operator: T_COV, unspecified_circuit: Circuit) → None
Parameters:
Return type:

None

estimated_value: ExpectationValue
estimator_shots: int
operator: T_COV
parameters: dict[Parameter, float]
property specified_circuit: Circuit | None

Circuit ansatz with the optimal parameters.

unspecified_circuit: Circuit