def compose_1q(lhs: Integral, rhs: Integral) -> Integral:
    """Return the composition of 1-qubit clifford integers."""
    return _CLIFFORD_COMPOSE_1Q[lhs, rhs]

def compose_2q(lhs: Integral, rhs: Integral) -> Integral:
    """Return the composition of 2-qubit clifford integers."""
    num = lhs
    for layer, idx in enumerate(_layer_indices_from_num(rhs)):
        circ = _CLIFFORD_LAYER[layer][idx]
        num = _compose_num_with_circuit_2q(num, circ)
    return num

def _compose_num_with_circuit_2q(num: Integral, qc: QuantumCircuit) -> Integral:
    """Compose a number that represents a Clifford, with a Clifford circuit, and return the
    number that represents the resulting Clifford."""
    lhs = num
    for inst in qc:
        qubits = tuple(qc.find_bit(q).index for q in inst.qubits)
        rhs = _num_from_2q_gate(op=inst.operation, qubits=qubits)
        try:
            lhs = _CLIFFORD_COMPOSE_2Q_GATE[lhs, rhs]
        except KeyError as err:
            raise Exception(f"_CLIFFORD_COMPOSE_2Q_GATE[{lhs}][{rhs}]") from err
    return lhs

from qiskit.providers.fake_provider import FakeManila
from qiskit_experiments.library.randomized_benchmarking import StandardRB
backend=FakeManila()

%%time
# create experiment
exp = StandardRB(
    qubits=[3],
    lengths=list(range(1, 1000, 100)),
    num_samples=3,
    seed=1234,
    backend=backend,
)
# run experiment
expdata = exp.run().block_for_results()
display(expdata.figure(0))

num_lengths = 10
# run several experiments with changing max clifford length (max_length)
for max_length in [1000, 2000, 3000, 4000, 5000]:  # [100, 200, 300, 400, 500] for 2Q RBs
    exp = StandardRB(
        qubits=[2],  # for 1Q RBs ([2, 1] for 2Q RBs)
        lengths=np.arange(1, max_length, max_length // num_lengths),  # see below for examples
        backend=FakeManilaV2(),
        num_samples=3,
        full_sampling=False,
    )
    # measure the time to generate transpiled RB circuits
    exp._transpiled_circuits()

import numpy as np
max_length, num_lengths = 1000, 10
print(np.arange(1, max_length, max_length // num_lengths))  # = range(1, 1000, 100)
max_clifford_length, num_lengths = 2000, 10
print(np.arange(1, max_length, max_length // num_lengths))  # = range(1, 2000, 100)

import copy
from qiskit.circuit.library.standard_gates import SXGate
from qiskit.providers.fake_provider import FakeManilaV2
from qiskit.pulse import Schedule, InstructionScheduleMap
from qiskit_experiments.library.randomized_benchmarking import StandardRB

qubits=(2,)
lengths=list(range(1, 1000, 100))
num_samples=3
seed=777
backend = FakeManilaV2()

%%time
qubits = (2,)
my_sched = Schedule(name="custom_sx_gate")
my_backend = copy.deepcopy(backend)
my_backend.target["sx"][qubits].calibration = my_sched

exp = StandardRB(qubits=qubits, lengths=lengths, num_samples=num_samples, backend=my_backend)
transpiled = exp._transpiled_circuits()

%%time
qubits = (2,)
my_sched = Schedule(name="custom_sx_gate")
my_inst_map = InstructionScheduleMap()
my_inst_map.add(SXGate(), qubits, my_sched)

exp = StandardRB(qubits=qubits, lengths=lengths, num_samples=num_samples, backend=backend)
exp.set_transpile_options(inst_map=my_inst_map)
transpiled = exp._transpiled_circuits()





from qiskit_experiments.library.randomized_benchmarking import StandardRB, InterleavedRB
from qiskit.providers.fake_provider import FakeManila

qubits=[2]
lengths=list(range(1, 1000, 100))
num_samples=3
seed=777
backend = FakeManila()
print("Cliford lengths:", lengths)
print("Number of circuits =", len(lengths)*num_samples)

%%time
# rb_speedup
exp = StandardRB(
    qubits=qubits,
    lengths=lengths,
    num_samples=num_samples,
    seed=seed,
    backend=backend,
)
transpiled = exp._transpiled_circuits()

# %%time
# # Main
# exp = StandardRB(
#     qubits=qubits,
#     lengths=lengths,
#     num_samples=num_samples,
#     seed=seed,
#     backend=backend,
# )
# transpiled = exp._transpiled_circuits()

qubits=[3, 2]
lengths=list(range(1, 200, 20))
num_samples=3
seed=777
backend = FakeManila()
print("Cliford lengths:", lengths)
print("Number of circuits =", len(lengths)*num_samples)

%%time
# rb_speedup
exp = StandardRB(
    qubits=qubits,
    lengths=lengths,
    num_samples=num_samples,
    seed=seed,
    backend=backend,
)
transpiled = exp._transpiled_circuits()

# %%time
# # Main
# exp = StandardRB(
#     qubits=qubits,
#     lengths=lengths,
#     num_samples=num_samples,
#     seed=seed,
#     backend=backend,
# )
# transpiled = exp._transpiled_circuits()

from qiskit.circuit import Delay
qubits=[2]
lengths=list(range(1, 1000, 100))
num_samples=3
seed=777
backend = FakeManila()
print("Cliford lengths:", lengths)
print("Number of circuits =", len(lengths)*num_samples*2)

from qiskit_experiments.framework.backend_timing import BackendTiming
timing = BackendTiming(backend)
duration_in_dt = timing.round_delay(time=backend.properties().gate_length("sx", qubits))  # 160[dt]

%%time
# rb_speedup
exp = InterleavedRB(
    interleaved_element=Delay(duration=duration_in_dt),
    qubits=qubits,
    lengths=lengths,
    num_samples=num_samples,
    seed=seed,
    backend=backend,
)
transpiled = exp._transpiled_circuits()

# %%time
# # Main
# exp = InterleavedRB(
#     interleaved_element=Delay(duration=duration_in_dt),
#     qubits=qubits,
#     lengths=lengths,
#     num_samples=num_samples,
#     seed=seed,
#     backend=backend,
# )
# transpiled = exp._transpiled_circuits()

qubits=[3, 2]
lengths=list(range(1, 200, 20))
num_samples=3
seed=777
backend = FakeManila()
print("Cliford lengths:", lengths)
print("Number of circuits =", len(lengths)*num_samples*2)

from qiskit.circuit import Delay, QuantumCircuit
delay_qc = QuantumCircuit(2)
delay_qc.delay(1600, 0)
delay_qc.delay(1600, 1)
delay_qc.draw()

%%time
# rb_speedup
exp = InterleavedRB(
    interleaved_element=delay_qc,
    qubits=qubits,
    lengths=lengths,
    num_samples=num_samples,
    seed=seed,
    backend=backend,
)
transpiled = exp._transpiled_circuits()

# %%time
# # Main
# exp = InterleavedRB(
#     interleaved_element=delay_qc,
#     qubits=qubits,
#     lengths=lengths,
#     num_samples=num_samples,
#     seed=seed,
#     backend=backend,
# )
# transpiled = exp._transpiled_circuits()

from qiskit.compiler import transpile
from qiskit.providers.fake_provider import FakeManila

# common RB configuration
qubits=[2]
lengths=list(range(1, 1000, 100))
num_samples=3
seed=777
backend = FakeManila()
print("Cliford lengths:", lengths)
print("Number of circuits =", len(lengths)*num_samples)

from qiskit.ignis.verification import randomized_benchmarking as rb

%%time
# Ignis
# create the RB circuits
circs, _ = rb.randomized_benchmarking_seq(
    rb_pattern=[qubits],
    length_vector=lengths,
    nseeds=num_samples,
    seed_offset=seed,
)
# transpile (for basis translation)
transpiled = []
for qcs in circs:
    for qc in qcs:
        transpiled.append(transpile(qc, backend=backend, optimization_level=0))

# transpiled[0].draw(idle_wires=False)

from qiskit_experiments.library.randomized_benchmarking import StandardRB, InterleavedRB

%%time
# Experiments
# create experiment object
exp = StandardRB(
    qubits=qubits,
    lengths=lengths,
    num_samples=num_samples,
    seed=seed,
    backend=backend,
)
# compute transpiled circuits
transpiled_qe = exp._transpiled_circuits()

# transpiled_qe[0].draw(idle_wires=False)

# common RB configuration
qubits=[3, 2]
lengths=list(range(1, 200, 20))
num_samples=3
seed=777
backend = FakeManila()
print("Cliford lengths:", lengths)
print("Number of circuits =", len(lengths)*num_samples)

from qiskit.ignis.verification import randomized_benchmarking as rb

%%time
# Ignis
# create the RB circuits
circs, _ = rb.randomized_benchmarking_seq(
    rb_pattern=[qubits],
    length_vector=lengths,
    nseeds=num_samples,
    seed_offset=seed,
)
# transpile (for basis translation)
transpiled = []
for qcs in circs:
    for qc in qcs:
        transpiled.append(transpile(qc, backend=backend, optimization_level=0))

# transpiled[0].draw(idle_wires=False)

from qiskit_experiments.library.randomized_benchmarking import StandardRB, InterleavedRB

%%time
# Experiments
# create experiment object
exp = StandardRB(
    qubits=qubits,
    lengths=lengths,
    num_samples=num_samples,
    seed=seed,
    backend=backend,
)
# compute transpiled circuits
transpiled_qe = exp._transpiled_circuits()

# transpiled_qe[0].draw(idle_wires=False)

# common RB configuration
from qiskit.circuit import Delay
qubits=[2]
lengths=list(range(1, 1000, 100))
num_samples=3
seed=777
backend = FakeManila()
print("Cliford lengths:", lengths)
print("Number of circuits =", len(lengths)*num_samples*2)

%%time
# Ignis
# create the RB circuits
circuits, xdata, circuits_interleaved = rb.randomized_benchmarking_seq(
    rb_pattern=[qubits],
    length_vector=lengths,
    nseeds=num_samples,
    seed_offset=seed,
    interleaved_elem=[Delay(duration=160)]
)
# transpile (for basis translation)
transpiled = []
for qcs in circuits:
    for qc in qcs:
        transpiled.append(transpile(qc, backend=backend, optimization_level=0))
for qcs in circuits_interleaved:
    for qc in qcs:
        transpiled.append(transpile(qc, backend=backend, optimization_level=0))

# transpiled[30].draw(idle_wires=False)

%%time
# Experiments
from qiskit_experiments.framework.backend_timing import BackendTiming

timing = BackendTiming(backend)
duration_in_dt = timing.round_delay(time=backend.properties().gate_length("sx", qubits))  # 160[dt]

# create experiment object
exp = InterleavedRB(
    interleaved_element=Delay(duration=duration_in_dt),
    qubits=qubits,
    lengths=lengths,
    num_samples=num_samples,
    seed=seed,
    backend=backend,
)
# compute transpiled circuits
transpiled_qe = exp._transpiled_circuits()

# transpiled_qe[30].draw(idle_wires=False)

duration_in_dt

timing.round_delay(time=100e-9)  # 100[ns] == 450[dt]

# common RB configuration
from qiskit.circuit import Delay, QuantumCircuit
qubits=[3, 2]
lengths=list(range(1, 200, 20))
num_samples=3
seed=777
backend = FakeManila()
print("Cliford lengths:", lengths)
print("Number of circuits =", len(lengths)*num_samples*2)

delay_qc = QuantumCircuit(2)
delay_qc.delay(1600, 0)
delay_qc.delay(1600, 1)
delay_qc.draw()

%%time
# Ignis
# create the RB circuits
circuits, xdata, circuits_interleaved = rb.randomized_benchmarking_seq(
    rb_pattern=[qubits],
    length_vector=lengths,
    nseeds=num_samples,
    seed_offset=seed,
    interleaved_elem=[delay_qc]
)
# transpile (for basis translation)
transpiled = []
for qcs in circuits:
    for qc in qcs:
        transpiled.append(transpile(qc, backend=backend, optimization_level=0))
for qcs in circuits_interleaved:
    for qc in qcs:
        transpiled.append(transpile(qc, backend=backend, optimization_level=0))

# transpiled[30].draw(idle_wires=False)

%%time
# Experiments
# create experiment object
exp = InterleavedRB(
    interleaved_element=delay_qc,
    qubits=qubits,
    lengths=lengths,
    num_samples=num_samples,
    seed=seed,
    backend=backend,
)
# compute transpiled circuits
transpiled_qe = exp._transpiled_circuits()

# transpiled_qe[30].draw(idle_wires=False)