Circuit Transformations
In many quantum workflows, applying circuit transformations—like Zero-Noise Extrapolation (ZNE) or observable grouping—can improve accuracy or reduce measurement overhead. Divi makes it very easy to apply the transformations present with very minimal code changes, through a simple declarative approach.
Observable Grouping
When measuring expectation values of quantum Hamiltonians—especially those with many terms—naively measuring each term individually can lead to significant overhead. Observable grouping 1 reduces the number of required circuit executions by identifying sets of commuting terms that can be measured simultaneously.
Divi uses PennyLane’s grouping strategies under the hood to perform this optimization automatically. With a single argument, you can enable grouping and benefit from reduced quantum evaluation time without modifying the core circuit logic. Therefore, you should refer to the documentation of the linked function to understand the differences between the different grouping strategies.
Code Example
from divi.parallel_simulator import ParallelSimulator
from divi.qprog import VQE, VQEAnsatze
from divi.qprog.optimizers import Optimizers
if __name__ == "__main__":
vqe_input = dict(
symbols=["H", "H"],
bond_length=0.5,
coordinate_structure=[(0, 0, 0), (0, 0, 1)],
n_layers=1,
ansatz=VQEAnsatze.HARTREE_FOCK,
optimizer=Optimizer.NELDER_MEAD,
max_iterations=1,
seed=2000,
backend=ParallelSimulator(simulation_seed=1997),
)
vqe_problem_no_grouping = VQE(
**vqe_input,
grouping_strategy=None,
)
no_grouping_measurement_groups = vqe_problem_no_grouping.meta_circuits[
"cost_circuit"
].measurement_groups
vqe_problem_wire_grouping = VQE(
**vqe_input,
grouping_strategy="wires",
)
wire_grouping_measurement_groups = vqe_problem_wire_grouping.meta_circuits[
"cost_circuit"
].measurement_groups
vqe_problem_qwc_grouping = VQE(
**vqe_input,
grouping_strategy="qwc",
)
qwc_grouping_measurement_groups = vqe_problem_qwc_grouping.meta_circuits[
"cost_circuit"
].measurement_groups
print(
f"Number of measurement groups without grouping: {len(no_grouping_measurement_groups)}"
)
print(
f"Number of measurement groups with wires grouping: {len(wire_grouping_measurement_groups)}"
)
print(
f"Number of measurement groups with qwc grouping: {len(qwc_grouping_measurement_groups)}"
)
If you look closely at the code above, you will notice how we are passing a different grouping_strategy
for each new instance of VQE. The code above extracts the measurement groups (i.e. a group of observables that will
be measured simultaneously) for each instance from the “scaffold” circuits we mentioned previously. Executing the
code above generates the following output:
Number of measurement groups without grouping: 14
Number of measurement groups with wires grouping: 8
Number of measurement groups with qwc grouping: 5
As you can see, the Hamiltonian has original 14 terms. Using grouping, this can go all the way down to 5. However, since
qwc
grouping can be time-consuming for large Hamiltonians, wire
grouping is generally a sufficient, faster alternative.
Zero-Noise Extrapolation (ZNE)
Noise is an unavoidable reality on today’s quantum hardware. Zero-Noise Extrapolation (ZNE) 234 is a popular error mitigation technique that estimates the ideal (zero-noise) expectation value by running the same circuit at artificially amplified noise levels and extrapolating back to the zero-noise limit.
Divi supports ZNE natively through integration with Mitiq, a leading open-source library for quantum error mitigation. Users can enable ZNE with minimal configuration, leveraging Mitiq’s existing folding protocols and extrapolation methods—again with minimal changes to existing code.
Code Example
from functools import partial
from mitiq.zne.inference import RichardsonFactory
from mitiq.zne.scaling import fold_gates_at_random
from divi.parallel_simulator import ParallelSimulator
from divi.qem import ZNE
from divi.qprog import VQE, VQEAnsatze
from divi.qprog.optimizers import Optimizers
scale_factors = [1.0, 3.0, 5.0]
vqe_instance = VQE(
### VQE Arguments as Before ###
# Need a noisy simulator for illustration purposes
backend=ParallelSimulator(qiskit_backend="auto"),
qem_protocol=ZNE(
scale_factors,
folding_fn=partial(fold_gates_at_random),
extrapolation_factory=RichardsonFactory(scale_factors=scale_factors),
)
)
In this example, you can see that we initialized a noisy simulation backend to illustration the effect of ZNE. We then initialized the ZNE instance, providing the scale factors of the folding function, the folding function itself, and the extrapolation class.
You might wonder about this partial
function that we are passing the folding function to. This is a native
Python function that lets you initialize the arguments of some function, so you don’t have to provide them later.
Any folding function has to be wrapped in this higher-order function, even if there are no arguments being set.
This is an example of how it can be properly used:
qem_protocol=ZNE(
scale_factors,
folding_fn=partial(fold_gates_at_random, seed=1234),
extrapolation_factory=RichardsonFactory(scale_factors=scale_factors),
)
-
Vladyslav Verteletskyi, Tzu-Ching Yen, Artur F. Izmaylov; Measurement optimization in the variational quantum eigensolver using a minimum clique cover. J. Chem. Phys. 31 March 2020; 152 (12): 124114. ↩︎
-
Ying Li and Simon C. Benjamin. Efficient variational quantum simulator incorporating active error minimization. Phys. Rev. X, 7:021050 (2017). ↩︎
-
Kristan Temme, Sergey Bravyi, and Jay M. Gambetta. Error mitigation for short-depth quantum circuits. Physical Review Letters (2017). ↩︎
-
Abhinav Kandala, Kristan Temme, Antonio D. Córcoles, Antonio Mezzacapo, Jerry M. Chow, and Jay M. Gambetta.Error mitigation extends the computational reach of a noisy quantum processor. Nature, 567(7749):491–495 (2019). ↩︎