#
# Copyright 2021 Quantum Benchmark Inc.
#
"""
Interleaved randomized benchmarking (IRB)
=========================================
"""
#%%
# This example page demonstrates how to use :py:func:`~trueq.make_irb` method to
# estimate the infidelity of a specific gate. This protocol differs from
# :doc:`../../guides/protocols/cb` in several ways:
#
# - It estimates the infidelity of a specific gate (not cycle) composed with gates from
# the twirling group, see :doc:`../../guides/protocols/irb` for more details. Gate
# infidelity can then be estimated by taking into account the results of an SRB
# experiment.
# - IRB uses a different twirling group than CB, Cliffords instead of Paulis by default.
# Paulis being a reference group with no entangling operations and therefore usually
# higher fidelity, leading to less systematic uncertainty in estimates.
# - Typically uses fewer circuits than CB.
# - IRB only gives information about specific gates (possibly in the context of being
# simultaneously applied), not an entire cycles like CB.
#
# We begin by defining some cycles that contain the gates we want to characterize using
# IRB. Next we generate IRB circuits for these cycles.
# Note that we could perform simultaneous two qubit IRB with a cycle such as:
#
# ``{(1, 2): tq.Gate.cz, (3, 4): tq.Gate.cz}``
#
# See :py:func:`~trueq.make_irb` for more details.
import trueq as tq
cycle1 = {1: tq.Gate.h}
cycle2 = {2: tq.Gate.h}
cycle12 = {(1, 2): tq.Gate.cz}
# Generate a circuit collection to run IRB on the above cycles with 30 random circuits
# for each circuit length in [4, 32, 64]:
n_random_cycles = [4, 32, 64]
circuits = tq.make_irb(cycle1, n_random_cycles)
circuits += tq.make_irb(cycle2, n_random_cycles)
circuits += tq.make_irb(cycle12, n_random_cycles)
len(circuits)
#%%
# We are interested in the gate fidelity of the individual gates in the cycles defined
# above, e.g. :math:`CZ` alone, so we also need a reference SRB experiment to translate
# from the average fidelity of cycles dressed with gates in the twirling group to
# fidelity of the undressed gates. Optionally, to tighten the bound on the infidelity
# estimate, we also do an XRB experiment. The double nesting ``[[1, 2]]`` is necessary
# to characterize the :math:`CZ` gate because just ``[1, 2]`` refers to simultaneous
# single-qubit gates.
circuits += tq.make_srb([1], n_random_cycles)
circuits += tq.make_srb([2], n_random_cycles)
circuits += tq.make_srb([[1, 2]], n_random_cycles)
circuits += tq.make_xrb([1], n_random_cycles)
circuits += tq.make_xrb([2], n_random_cycles)
circuits += tq.make_xrb([[1, 2]], n_random_cycles)
#%%
# Create a noisy simulator in lieu of a physical device and populate all circuits
# with results.
sim = tq.Simulator().add_depolarizing(0.01).add_overrotation(0.04)
sim.run(circuits)
#%%
# Print a summary of the results for the CZ gate:
circuits.fit()
#%%
# Plot a summary of information:
circuits.plot.irb_summary()
#%%
# For a refresher on the parameters plotted above, see
# :doc:`../../guides/protocols/irb`\.