<jupyter_start><jupyter_text>**Monitoring and Optimizing Quantum Circuits**<jupyter_code>import numpy as np

# Importing standard Qiskit libraries
from qiskit import QuantumCircuit, transpile, Aer, IBMQ, execute
from qiskit.tools.jupyter import *
from qiskit.visualization import *
from ibm_quantum_widgets import *
from qiskit.providers.aer import QasmSimulator

# Loading your IBM Quantum account(s)
provider = IBMQ.load_account()<jupyter_output><empty_output><jupyter_text>**Monitoring and Tracking Jobs**<jupyter_code># Import the Qiskit Jupyter tools 
from qiskit.tools import jupyter
# Initialize the job tracker to automatically track all jobs
%qiskit_job_watcher
# Let's run a simple circuit on the least busy quantum device 
# and check the job watcher widget.
from qiskit.providers.ibmq import least_busy

backend = least_busy(provider.backends(filters=lambda x: x.configuration().n_qubits >= (2) and 
                                       not x.configuration().simulator 
                                       and x.status().operational==True))

#Create a simple circuit
qc = QuantumCircuit(1)
qc.h(0)
qc.measure_all()
#Execute the circuit on the backend
job = execute(qc, backend)
#Disable the job watcher
%qiskit_disable_job_watcher
#Display the list of all available backends and provide 
#a brief overview of each 
%qiskit_backend_overview<jupyter_output><empty_output><jupyter_text>**Transpiling a Circuit**<jupyter_code># Import the transpiler passes object
from qiskit.transpiler import passes
# List out all the passes available
print(dir(passes))
#Basic Toffoli gate,
qc = QuantumCircuit(3)
qc.ccx(0,1,2)
qc.draw()
qc_decomposed = qc.decompose()
qc_decomposed.draw()
#Basic circuit with a single and multi-qubit gates
qc = QuantumCircuit(4)
qc.h(0)
qc.cx(0,1)
qc.cx(0,2)
qc.cx(0,3)
qc.draw()
#Print the depth of both inital and decomposed circuit
print('Initial circuit depth: ', qc.depth())
print('Decomposed circuit depth: ', qc_decomposed.depth())
#Get the number of operators in initial circuit
print('Initial circuit operation count: ', qc.count_ops())
#Get the number of operators in decomposed circuit
print('Decomposed circuit operation count: ', qc_decomposed.count_ops())<jupyter_output>Initial circuit depth:  4
Decomposed circuit depth:  11
Initial circuit operation count:  OrderedDict([('cx', 3), ('h', 1)])
Decomposed circuit operation count:  OrderedDict([('cx', 6), ('t', 4), ('tdg', 3), ('h', 2)])<jupyter_text>**Configuration and Optimization**<jupyter_code># Get the backend device: ibmq_santiago 
backend_santiago = provider.get_backend('ibmq_santiago')
# Launch backend viewer of ibmq_santiago
backend_santiago
# Get the backend device: ibmq_lima
backend_lima = provider.get_backend('ibmq_lima')
# Launch backend viewer of ibmq_lima
backend_lima
# Visualize the coupling directional map between the qubits 
plot_gate_map(backend_santiago, plot_directed=True)
# Visualize the coupling directional map between the qubits 
plot_gate_map(backend_lima, plot_directed=True)
# Quantum circuit with a single and multi-qubit gates
qc = QuantumCircuit(4)
qc.h(0)
qc.cx(0,1)
qc.cx(0,2)
qc.cx(0,3)
qc.draw()
# Transpile the circuit with an optimization level = 0
qc_santiago_0 = transpile(qc, backend_santiago, 
seed_transpiler=10258, optimization_level=0)
# Print out the depth of the circuit
print('Depth:', qc_santiago_0.depth())
# Plot the resulting layout of the quantum circuit after Layout
plot_circuit_layout(qc_santiago_0, backend_santiago)
# Draw the transpiled circuit pertaining to Santiago
qc_santiago_0.draw()
# View the transpiled circuit with an optimization level = 0
qc_lima_0 = transpile(qc, backend_lima, seed_transpiler=10258, optimization_level=0)
print('Depth:', qc_lima_0.depth())
plot_circuit_layout(qc_lima_0, backend_lima)
# Draw the transpiled circuit pertaining to Lima
qc_lima_0.draw()
# Transpile the circuit with the optimization level = 3
qc_transpiled_santiago = transpile(qc, backend_santiago, optimization_level=3)
# Print the depth of the transpiled circuit
print('Depth:', qc_transpiled_santiago.depth())
# Print the number of operations of the transpiled circuit
print('Ops count: ', qc_transpiled_santiago.count_ops())
# Plot the layout mapping of the transpiled circuit
plot_circuit_layout(qc_transpiled_santiago, backend_santiago)
# Redraw the transpiled circuit at new level
qc_transpiled_santiago.draw()
# Transpile the quantum circuit with the optimization level = 3
qc_transpiled_lima = transpile(qc, backend_lima, optimization_level=3)
# Get the depth and operation count of the transpiled circuit. 
print('Depth:', qc_transpiled_lima.depth())
print('Ops count: ', qc_transpiled_lima.count_ops())
# Print the circuit layout
plot_circuit_layout(qc_transpiled_lima, backend_lima)
# View the ibmq_quito backend device configuration and properties
backend = provider.get_backend('ibmq_quito')
backend
# View the backend coupling map, displayed as CNOTs (Control-Target)
backend = provider.get_backend('ibmq_quito')
# Extract the coupling map from the backend
ibmqquito_coupling_map = backend.configuration().coupling_map
# List out the extracted coupling map
ibmqquito_coupling_map
# Transpile a custom circuit using only the coupling map. 
# Set the backend to ‘None’ so it will force using the coupling map provided.
qc_custom = transpile(qc, backend=None, 
coupling_map=ibmqquito_coupling_map)
# Draw the resulting custom topology circuit.
qc_custom.draw()
# Create our own coupling map (custom topology)
custom_linear_topology = [[0,1],[1,2],[2,3],[3,4]]
# Set the coupling map to our custom linear topology
qc_custom = transpile(qc, backend=None, coupling_map=custom_linear_topology)
# Draw the resulting circuit.
qc_custom.draw()
# Import the PassManager and a few Passes
from qiskit.transpiler import PassManager, CouplingMap
from qiskit.transpiler.passes import TrivialLayout, BasicSwap
# Create a TrivialLayout based on the ibmqx2 coupling map
trivial = TrivialLayout(CouplingMap(ibmqquito_coupling_map))

pm = PassManager()
# Append the TrivialLayout to the PassManager
pm.append(trivial)
# Run the PassManager and draw the resulting circuit
tv_qc = pm.run(qc)
tv_qc.draw()
# Create a BasicSwap based on the ibmq_quito coupling map we used earlier
basic_swap = BasicSwap(CouplingMap(ibmqquito_coupling_map))
#Add the BasicSwap to the PassManager
pm = PassManager(basic_swap)
# Run the PassManager and draw the results
new_qc = pm.run(qc)
new_qc.draw()
# Sample quantum circuit 
qc = QuantumCircuit(4)
qc.h(0)
qc.cx(0,1)
qc.barrier()
qc.cx(0,2)
qc.cx(0,3)
qc.barrier()
qc.cz(3,0)
qc.h(0)
qc.measure_all()
# Draw the circuit using the default renderer
qc.draw()
qc.draw('latex')<jupyter_output><empty_output>