from qiskit import QuantumRegister

qubit1 = QuantumRegister(1) # el parámetro indica cuántos qubits queremos

qubit2 = QuantumRegister(1, 'qreg') # se puede indicar un nombre al registro cuántico (parámetro opcional)

print(qubit1) # al no especificar el nombre, le asigna uno con una numeración consecutiva
print(qubit2)

from qiskit import QuantumCircuit

circuit = QuantumCircuit(qubit1) # crear un circuito cuántico con un qubit

circuit.draw('mpl') # mostramos la representación gráfica del circuito

circ = QuantumCircuit(3, 2) # circuito con 3 qubits y 2 bits clásicos

circ.h(0)           # aplicar compuerta H al qubit 0
circ.cx(0, 1)       # aplicar compuerta CNOT a los qubits 0 y 1
circ.cx(0, 2)       # aplicar compuerta CNOT a los qubits 0 y 2
circ.measure(0, 1)  # medir el qubit 0 en el bit clásico 1
circ.measure(2, 0)  # medir el qubit 2 en el bit clásico 0

circ.draw('mpl')    # mostrar el circuito

circ1 = QuantumCircuit(1) # circuito con 1 qubit

circ1.x(0)                # aplicar compuerta X al (único) qubit 0

circ1.draw('mpl')         # mostrar el circuito

from qiskit.quantum_info import Statevector
from qiskit.visualization import array_to_latex


circ1 = QuantumCircuit(1)    # circuito con 1 qubit

psi_0 = Statevector(circ1)   # estado justo después de crear el circuito

circ1.x(0)                   # aplicar compuerta X al (único) qubit 0

psi_1 = Statevector(circ1)   # estado después aplicar la compuerta X

display(circ1.draw('mpl'))   # mostrar el circuito

print("👉 Estado inicial:")
print("➤ en forma de vector:")
display(array_to_latex(psi_0.data))
print("➤ en forma de ket:")
display(psi_0.draw('latex'))
print()
print("👉 Estado después de X:")
print("➤ en forma de vector:")
display(array_to_latex(psi_1.data))
print("➤ en forma de ket:")
display(psi_1.draw('latex'))

from qiskit.visualization import plot_bloch_multivector


print("🔵 Estado inicial:")
display(plot_bloch_multivector(psi_0))

print("🔵 Estado después de X:")
display(plot_bloch_multivector(psi_1))

circ2 = QuantumCircuit(1)    # circuito con 1 qubit

psi_0 = Statevector(circ2)   # estado justo después de crear el circuito

circ2.y(0)                   # aplicar compuerta Y al (único) qubit 0

psi_1 = Statevector(circ2)   # estado después aplicar la compuerta Y

display(circ2.draw('mpl'))   # mostrar el circuito

print("👉 Estado inicial:")
print("➤ en forma de vector:")
display(array_to_latex(psi_0))
print("➤ en forma de ket:")
display(psi_0.draw('latex'))
print()
print("👉 Estado después de Y:")
print("➤ en forma de vector:")
display(array_to_latex(psi_1))
print("➤ en forma de ket:")
display(psi_1.draw('latex'))

print("🔵 Estado inicial:")
display(plot_bloch_multivector(psi_0))

print("🔵 Estado después de Y:")
display(plot_bloch_multivector(psi_1))

circ3 = QuantumCircuit(1)    # circuito con 1 qubit

circ3.x(0)                   # obtener el estado |1>

psi_0 = Statevector(circ3)   # estado justo después de crear el circuito e iniciar el qubit en |1>

circ3.z(0)                   # aplicar compuerta Z al (único) qubit en la posición 0

psi_1 = Statevector(circ3)   # estado después aplicar la compuerta Z

display(circ3.draw('mpl'))   # mostrar el circuito

print("👉 Estado inicial:")
print("➤ en forma de vector:")
display(array_to_latex(psi_0))
print("➤ en forma de ket:")
display(psi_0.draw('latex'))
print()
print("👉 Estado después de Z:")
print("➤ en forma de vector:")
display(array_to_latex(psi_1))
print("➤ en forma de ket:")
display(psi_1.draw('latex'))

print()
print("🔵 Estado inicial:")
display(plot_bloch_multivector(psi_0))

print("🔵 Estado después de Z:")
display(plot_bloch_multivector(psi_1))

import numpy as np


circ4 = QuantumCircuit(1)    # circuito con 1 qubit

psi_0 = Statevector(circ4)   # estado justo después de crear el circuito

circ4.ry(np.pi/2, 0)         # rotar pi/2 alrededor del eje y

psi_1 = Statevector(circ4)   # estado después de la primera rotación

circ4.rz(np.pi/4, 0)         # rotar pi/4 alrededor del eje z

psi_2 = Statevector(circ4)   # estado después de la segunda rotación

circ4.rx(np.pi, 0)           # rotar pi alrededor del eje x

psi_3 = Statevector(circ4)   # estado después de la tercera rotación

display(circ4.draw('mpl'))   # mostrar el circuito

print("👉 Estado inicial:")
print("➤ en forma de vector:")
display(array_to_latex(psi_0))
print("➤ en forma de ket:")
display(psi_0.draw('latex'))
print()
print("👉 Estado después rotación de pi/2 alrededor del eje y:")
print("➤ en forma de vector:")
display(array_to_latex(psi_1))
print("➤ en forma de ket:")
display(psi_1.draw('latex'))
print()
print("👉 Estado después rotación de pi/4 alrededor del eje z:")
print("➤ en forma de vector:")
display(array_to_latex(psi_2))
print("➤ en forma de ket:")
display(psi_2.draw('latex'))
print()
print("👉 Estado después rotación de pi alrededor del eje x:")
print("➤ en forma de vector:")
display(array_to_latex(psi_3))
print("➤ en forma de ket:")
display(psi_3.draw('latex'))

print()
print("🔵 Estado inicial:")
display(plot_bloch_multivector(psi_0))

print("🔵 Estado después rotación de pi/2 alrededor del eje y:")
display(plot_bloch_multivector(psi_1))

print("🔵 Estado después rotación de pi/4 alrededor del eje z:")
display(plot_bloch_multivector(psi_2))

print("🔵 Estado después rotación de pi alrededor del eje x:")
display(plot_bloch_multivector(psi_3))

circ5 = QuantumCircuit(1)    # circuito con 1 qubit

psi_0 = Statevector(circ5)   # estado justo después de crear el circuito

circ5.h(0)                   # apliquemos H al estado |0>, quedamos en |+>

psi_1 = Statevector(circ5)   # estado justo después de aplicar H

circ5.z(0)                   # aplicar compuerta Z al (único) qubit 0, quedamos en el estado |->

psi_2 = Statevector(circ5)   # estado después aplicar la compuerta Z

circ5.h(0)                   # aplicar compuerta H de nuevo, quedamos en el estado |1>

psi_3 = Statevector(circ5)   # estado después aplicar la compuerta Z

display(circ5.draw('mpl'))   # mostrar el circuito

print("👉 Estado inicial:")
print("➤ en forma de vector:")
display(array_to_latex(psi_0))
print("➤ en forma de ket:")
display(psi_0.draw('latex'))
print()
print("👉 Estado después de primera H:")
print("➤ en forma de vector:")
display(array_to_latex(psi_1))
print("➤ en forma de ket:")
display(psi_1.draw('latex'))
print()
print("👉 Estado después de Z:")
print("➤ en forma de vector:")
display(array_to_latex(psi_2))
print("➤ en forma de ket:")
display(psi_2.draw('latex'))
print()
print("👉 Estado después de segunda H:")
print("➤ en forma de vector:")
display(array_to_latex(psi_3))
print("➤ en forma de ket:")
display(psi_3.draw('latex'))

print()
print("🔵 Estado inicial:")
display(plot_bloch_multivector(psi_0))

print("🔵 Estado después de primera H:")
display(plot_bloch_multivector(psi_1))

print("🔵 Estado después de Z:")
display(plot_bloch_multivector(psi_2))

print("🔵 Estado después de segunda H:")
display(plot_bloch_multivector(psi_3))

circ6 = QuantumCircuit(1)    # circuito con 1 qubit

circ6.h(0)                   # nos movemos al estado |+>

psi_0 = Statevector(circ6)   # estado justo después de crear el circuito y posicionarse en |+>

circ6.s(0)                   # aplicar compuerta S, rotando pi/2

psi_1 = Statevector(circ6)   # estado justo después de aplicar P

circ6.tdg(0)                 # aplicar compuerta T† rotanfo -pi/4

psi_2 = Statevector(circ6)   # estado después aplicar la compuerta S

circ6.p(2*np.pi/3, 0)        # aplicar compuerta P, rotando 2pi/3

psi_3 = Statevector(circ6)   # estado después aplicar la compuerta T†

display(circ5.draw('mpl'))   # mostrar el circuito

print("👉 Estado inicial |+>:")
print("➤ en forma de vector:")
display(array_to_latex(psi_0))
print("➤ en forma de ket:")
display(psi_0.draw('latex'))
print()
print("👉 Estado después de S:")
print("➤ en forma de vector:")
display(array_to_latex(psi_1))
print("➤ en forma de ket:")
display(psi_1.draw('latex'))
print()
print("👉 Estado después de T†:")
print("➤ en forma de vector:")
display(array_to_latex(psi_2))
print("➤ en forma de ket:")
display(psi_2.draw('latex'))
print()
print("👉 Estado después de P(2*pi/3):")
print("➤ en forma de vector:")
display(array_to_latex(psi_3))
print("➤ en forma de ket:")
display(psi_3.draw('latex'))

print()
print("🔵 Estado inicial |+>:")
display(plot_bloch_multivector(psi_0))

print("🔵 Estado después de S:")
display(plot_bloch_multivector(psi_1))

print("🔵 Estado después de T†:")
display(plot_bloch_multivector(psi_2))

print("🔵 Estado después de P(2*pi/3):")
display(plot_bloch_multivector(psi_3))

circ_u = QuantumCircuit(1)               # circuito con 1 qubit

psi_0 = Statevector(circ_u)              # estado justo después de crear el circuito e iniciar el qubit en |1>

circ_u.u(np.pi/3, np.pi/2, np.pi/5, 0)   # aplicar compuerta U3 al (único) qubit en la posición 0

psi_1 = Statevector(circ_u)              # estado después aplicar la compuerta U3

display(circ_u.draw('mpl'))              # mostrar el circuito

print("👉 Estado inicial:")
print("➤ en forma de vector:")
display(array_to_latex(psi_0))
print("➤ en forma de ket:")
display(psi_0.draw('latex'))
print()
print("👉 Estado después de U3(pi/3, pi/8, pi/5):")
print("➤ en forma de vector:")
display(array_to_latex(psi_1))
print("➤ en forma de ket:")
display(psi_1.draw('latex'))

print()
print("🔵 Estado inicial:")
display(plot_bloch_multivector(psi_0))

print("🔵 Estado después de U3(pi/3, pi/8, pi/5):")
display(plot_bloch_multivector(psi_1))

from qiskit.quantum_info import Operator

circuit = QuantumCircuit(2) # circuito con 2 qubits

circuit.h(0)    # Hadamard en q0
circuit.id(1)   # Identidad en q1

display(circuit.draw('mpl'))

op = Operator(circuit)
display(array_to_latex(op))

psi = Statevector(circuit)

display(plot_bloch_multivector(psi))

circuit = QuantumCircuit(3) # circuito con 3 qubits

circuit.rx(np.pi/4, 0)      # Rx de pi/4  al q0
circuit.ry(3*np.pi/5, 1)    # Ry de 3pi/5 al q1
circuit.h(2)                # Hadamard al q2

display(circuit.draw('mpl'))

op = Operator(circuit)
display(array_to_latex(op))

psi = Statevector(circuit)

print()
display(plot_bloch_multivector(psi))

circ7 = QuantumCircuit(2)   # circuito con 2 qubits

circ7.x(0)                  # ponemos el control en |1> para que la compuerta sea aplicada

circ7.cx(0, 1)              # CNOT con q0 como control y q1 como objetivo

print("Este es el caso para CNOT(0,1)|01> = |11>")

display(circ7.draw('mpl'))

op = Operator(circ7)
display(array_to_latex(op))

psi = Statevector(circ7)

print()
display(plot_bloch_multivector(psi))

circ8 = QuantumCircuit(2)   # circuito con 2 qubits

circ8.x(1)                  # ponemos el control en |1> para que la compuerta sea aplicada

circ8.cx(1, 0)              # CNOT con q1 como control y q0 como objetivo

print("Este es el caso para CNOT(1,0)|10> = |11>")

display(circ8.draw('mpl'))

op = Operator(circ8)
display(array_to_latex(op))

psi = Statevector(circ8)

print()
display(plot_bloch_multivector(psi))

circ9 = QuantumCircuit(2)    # circuito con 2 qubits

circ9.cy(0, 1)               # Y controlada, qubit control es q0, y objetivo es q1
circ9.cz(1, 0)               # Z controlada, qubit control es q1, y objetivo es q0
circ9.cx(0, 1)               # X controlada, qubit control es q0, y objetivo es q1

circ9.ch(0, 1)               # H controlada, qubit control es q0, y objetivo es q1

circ9.crx(np.pi/8, 1, 0)     # Rx controlada, ángulo de pi/8, qubit control es q1, y objetivo es q0
circ9.crz(3*np.pi/5, 0, 1)   # Rz controlada, ángulo de 3pi/5, qubit control es q0, y objetivo es q1

circ9.cp(7*np.pi/9, 1, 0)    # P controlada, ángulo de 7pi/9, qubit control es q1, y objetivo es q0

display(circ9.draw('mpl'))

from qiskit.extensions import UnitaryGate

matrix = [[1j, 0],
          [0 , 1,]]

mi_gate = UnitaryGate(matrix, 'mi_gate')

circ10 = QuantumCircuit(2)      # circuito con 2 qubits

circ10.append(mi_gate, [0])     # le agregamos al circuito la compuerta personalizada


mi_gate_controlada = mi_gate.control(1)   # hacemos la version controlada de mi_gate

circ10.append(mi_gate_controlada, [0, 1]) # se indican los qubits, primero el control y luego el objetivo


display(circ10.draw('mpl'))

circ11 = QuantumCircuit(2)    # circuito con 2 qubit

circ11.x(0)                   # obtener el estado |01>

psi_0 = Statevector(circ11)   # estado justo después de crear el circuito e iniciar el qubit en |01>

circ11.swap(0, 1)             # aplicar compuerta SWAP a los dos quibits existentes

psi_1 = Statevector(circ11)   # estado después aplicar la compuerta Z

display(circ11.draw('mpl'))   # mostrar el circuito

print("👉 Estado inicial:")
print("➤ en forma de vector:")
display(array_to_latex(psi_0))
print("➤ en forma de ket:")
display(psi_0.draw('latex'))
print()
print("👉 Estado después de SWAP:")
print("➤ en forma de vector:")
display(array_to_latex(psi_1))
print("➤ en forma de ket:")
display(psi_1.draw('latex'))

print()
print("🔵 Estado inicial:")
display(plot_bloch_multivector(psi_0))

print("🔵 Estado después de SWAP:")
display(plot_bloch_multivector(psi_1))

circ12 = QuantumCircuit(3)    # circuito con 3 qubit

circ12.x(1)                   # obtener el estado |010>
circ12.x(2)                   # obtener el estado |110>

psi_0 = Statevector(circ12)   # estado justo después de crear el circuito e iniciar el qubit en |110>

circ12.ccx(1, 2, 0)           # aplicar compuerta CCX: control1, control2, objetivo

psi_1 = Statevector(circ12)   # estado después aplicar la compuerta Z

display(circ12.draw('mpl'))   # mostrar el circuito

print("👉 Estado inicial:")
print("➤ en forma de vector:")
display(array_to_latex(psi_0))
print("➤ en forma de ket:")
display(psi_0.draw('latex'))
print()
print("👉 Estado después de CCX(1, 2, 0):")
print("➤ en forma de vector:")
display(array_to_latex(psi_1))
print("➤ en forma de ket:")
display(psi_1.draw('latex'))

print()
print("🔵 Estado inicial:")
display(plot_bloch_multivector(psi_0))

print("🔵 Estado después de CCX(1, 2, 0):")
display(plot_bloch_multivector(psi_1))

circ13 = QuantumCircuit(3)    # circuito con 3 qubit

circ13.x(2)                   # obtener el estado |100>
circ13.x(1)                   # obtener el estado |110>

psi_0 = Statevector(circ13)   # estado justo después de crear el circuito e iniciar el qubit en |110>

circ13.cswap(2, 0, 1)         # aplicar compuerta CCX: control1, objetivo1, objetivo2

psi_1 = Statevector(circ13)   # estado después aplicar la compuerta Z

display(circ13.draw('mpl'))   # mostrar el circuito

print("👉 Estado inicial:")
print("➤ en forma de vector:")
display(array_to_latex(psi_0))
print("➤ en forma de ket:")
display(psi_0.draw('latex'))
print()
print("👉 Estado después de SWAP(2, 0, 1):")
print("➤ en forma de vector:")
display(array_to_latex(psi_1))
print("➤ en forma de ket:")
display(psi_1.draw('latex'))

print()
print("🔵 Estado inicial:")
display(plot_bloch_multivector(psi_0))

print("🔵 Estado después de SWAP(2, 0, 1):")
display(plot_bloch_multivector(psi_1))

# Crear una comperta a partir de un circuito
qc1 = QuantumCircuit(2)
# estos dos quits serán los objetivos
qc1.x(0)
qc1.h(1)
custom = qc1.to_gate().control(2) # se indica que debe ser controlada con dos qubits

# Aplicar esa compuerta a otro circuito
qc2 = QuantumCircuit(4)
qc2.append(custom, [0, 3, 1, 2]) # primeros 2 son control, el resto a los que se aplica la compuerta
qc2.draw('mpl')

circ_bell_1 = QuantumCircuit(2)    # circuito con 2 qubits

circ_bell_1.barrier()
circ_bell_1.h(0)                   # aplicar compuerta H al qubit 0
circ_bell_1.cx(0,1)                # aplicar compuerta CNOT

psi_bell_1 = Statevector(circ_bell_1)   # estado final

display(circ_bell_1.draw('mpl'))   # mostrar el circuito

print("👉 Estado de Bell 1:")
print("➤ en forma de vector:")
display(array_to_latex(psi_bell_1))
print("➤ en forma de ket:")
display(psi_bell_1.draw('latex'))

circ_bell_2 = QuantumCircuit(2)    # circuito con 2 qubits

circ_bell_2.x(0)                   # aplicar compuerta X al qubit 0
circ_bell_2.barrier()
circ_bell_2.h(0)                   # aplicar compuerta H al qubit 0
circ_bell_2.cx(0,1)                # aplicar compuerta CNOT

psi_bell_2 = Statevector(circ_bell_2)   # estado final

display(circ_bell_2.draw('mpl'))   # mostrar el circuito

print("👉 Estado de Bell 2:")
print("➤ en forma de vector:")
display(array_to_latex(psi_bell_2))
print("➤ en forma de ket:")
display(psi_bell_2.draw('latex'))

circ_bell_3 = QuantumCircuit(2)    # circuito con 2 qubits

circ_bell_3.x(1)                   # aplicar compuerta X al qubit 1
circ_bell_3.barrier()
circ_bell_3.h(0)                   # aplicar compuerta H al qubit 0
circ_bell_3.cx(0,1)                # aplicar compuerta CNOT

psi_bell_3 = Statevector(circ_bell_3)   # estado final

display(circ_bell_3.draw('mpl'))   # mostrar el circuito

print("👉 Estado de Bell 2:")
print("➤ en forma de vector:")
display(array_to_latex(psi_bell_3))
print("➤ en forma de ket:")
display(psi_bell_3.draw('latex'))

circ_bell_4 = QuantumCircuit(2)    # circuito con 2 qubits

circ_bell_4.x(0)                   # aplicar compuerta X al qubit 0
circ_bell_4.x(1)                   # aplicar compuerta X al qubit 1
circ_bell_4.barrier()
circ_bell_4.h(0)                   # aplicar compuerta H al qubit 0
circ_bell_4.cx(0,1)                # aplicar compuerta CNOT

psi_bell_4 = Statevector(circ_bell_4)   # estado final

display(circ_bell_4.draw('mpl'))   # mostrar el circuito

print("👉 Estado de Bell 2:")
print("➤ en forma de vector:")
display(array_to_latex(psi_bell_4))
print("➤ en forma de ket:")
display(psi_bell_4.draw('latex'))

circ_ghz = QuantumCircuit(3, 3)     # circuito con 3 qubits y 3 bits clásicos

circ_ghz.h(0)                       # aplicar compuerta H al qubit 0
circ_ghz.cx(0, 1)                   # aplicar compuerta CNOT a los qubits 0 y 1
circ_ghz.cx(0, 2)                   # aplicar compuerta CNOT a los qubits 0 y 2
circ_ghz.barrier()
circ_ghz.measure([0,1,2], [0,1,2])  # medir los 3 qubits en los 3 bits clásicos

circ_ghz.draw('mpl')                # mostrar el circuito

from qiskit import execute, Aer

simulator = Aer.get_backend('aer_simulator')

job = execute(circ_ghz, simulator, shots=1)               # ejecutar el circuito una sola vez
counts = job.result().get_counts(circ_ghz)                # obtener los resultados de la ejecución
print(counts)

from qiskit.tools.visualization import plot_histogram

job = execute(circ_ghz, simulator, shots=1000)            # ejecutar el circuito 1000 veces
counts = job.result().get_counts(circ_ghz)                # obtener los resultados de la ejecución
print(counts)

plot_histogram(counts, title='Conteos del estado GHZ')    # mostrar los resultados en forma de histograma

Aer.backends()

# incrementar la cantidad de 'shots' reduce la variación en el muestreo
shots = 10000

# Método de simulación: Stabilizer
sim_stabilizer = Aer.get_backend('aer_simulator_stabilizer')
job_stabilizer = sim_stabilizer.run(circ_ghz, shots=shots)   #también se puede usar el método 'run' del backend
counts_stabilizer = job_stabilizer.result().get_counts(0)

# Método de simulación: Statevector
sim_statevector = Aer.get_backend('aer_simulator_statevector')
job_statevector = sim_statevector.run(circ_ghz, shots=shots)
counts_statevector = job_statevector.result().get_counts(0)

# Método de simulación: Density Matrix
sim_density = Aer.get_backend('aer_simulator_density_matrix')
job_density = sim_density.run(circ_ghz, shots=shots)
counts_density = job_density.result().get_counts(0)

# Método de simulación: Matrix Product State
sim_mps = Aer.get_backend('aer_simulator_matrix_product_state')
job_mps = sim_mps.run(circ_ghz, shots=shots)
counts_mps = job_mps.result().get_counts(0)

plot_histogram([counts_stabilizer, counts_statevector, counts_density, counts_mps],
               title='Conteos para diferentes métodos de simulación',
               legend=['stabilizer', 'statevector',
                       'density_matrix', 'matrix_product_state'])

from qiskit import IBMQ

#IBMQ.save_account('TOKEN')  # guardar tu cuenta en tu disco duro

IBMQ.load_account()         # cargar cuenta desde el disco duro

IBMQ.providers()            # listar todos los proveedores disponibles (para tu cuenta)


provider = IBMQ.get_provider(hub='ibm-q')                  # obtenemos un proveedor

provider.backends()

provider = IBMQ.get_provider(hub='ibm-q')                  # obtenemos un proveedor

backend = provider.get_backend('ibmq_qasm_simulator')      # obtenemos un backend, en este ejemplo estamos usando
                                                           # un simulador, pero uno que se encuentra en la nube,
                                                           # es decir, la ejecución no ocurrirá en nuestra máquina local
                                                           # esto para obtener un resultado de manera rápida,
                                                           # más adelante veremos cómo ejecutar en un dispositivo real

circuit = QuantumCircuit(3, 3)                             # creamos un circuito de 3 qubits y 3 registros clásicos
circuit.x(0)                                               # aplicamos algunas compuertas
circuit.x(1) 
circuit.ccx(0, 1, 2)
circuit.cx(0, 1)
circuit.barrier()
circuit.measure([0, 1, 2], [0, 1, 2])                      # agregamos mediciones a los 3 qubits

display(circuit.draw('mpl'))                               # mostramos el circuito

job = backend.run(circuit)                                 # mandamos ejecutar el circuito al backend en la nube,
                                                           # recuerda, este aún es un simulador, pero no local
                                                           # esta línea de código puede tardarse varios segundos, o
                                                           # incluso minutos dependiendo de la saturación de la red

result = job.result()                                      # la ejecución nos regresa un 'job'

counts = result.get_counts()                               # al que le podemos pedir los conteos

print(counts)                                              # imprimimos los conteos

# obtenemos todos los backends que no sean simuladores y que estén en línea

provider.backends(simulator=False, operational=True)

# obtenemos todos los backends con más de 3 qubits, que no sean simuladores y que estén en línea

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

from qiskit.providers.ibmq import least_busy

devices = provider.backends(simulator=False, operational=True)

least_busy_device = least_busy(devices)                 # de la lista de dispositivos, averiguar cual es el menos ocupado

least_busy_device

from qiskit.compiler import transpile


circuit = QuantumCircuit(3, 3)                             # creamos un circuito de 3 qubits y 3 registros clásicos
circuit.x(0)                                               # aplicamos algunas compuertas
circuit.x(1) 
circuit.ccx(0, 1, 2)
circuit.cx(0, 1)
circuit.barrier()
circuit.measure([0, 1, 2], [0, 1, 2])                      # agregamos mediciones a los 3 qubits

display(circuit.draw('mpl'))                               # mostramos el circuito


circuit = transpile(circuit, least_busy_device)            # transpilamos el circuito para el backend en específico


display(circuit.draw('mpl'))                               # mostramos el circuito transpilado

job = least_busy_device.run(circuit)                       # mandamos ejecutar el circuito al backend en la nube
                                                           # guardado en la variable 'least_busy_device'
                                                           # esta línea de código puede tardarse hasta varios minutos 
                                                           # dependiendo de la cantidad de 'jobs' encolados

result = job.result()                                      # la ejecución nos regresa un 'job'

counts = result.get_counts()                               # al que le podemos pedir los conteos

print(counts)                                              # imprimimos los conteos

least_busy_device.status()                         # su estado actual

# creamos un circuito para probar

circuit = QuantumCircuit(3, 3)
for i in range(10):
    circuit.x(0)
    circuit.x(1)
    circuit.ccx(0, 1, 2)
    circuit.cx(0, 1)
    circuit.barrier()

circuit.measure_all()

display(circuit.draw('mpl')) 

from qiskit.providers.jobstatus import JobStatus
from time import sleep
from IPython.display import clear_output


circuit = transpile(circuit, least_busy_device)               # transpilamos el circuito para el backend en específico

job = least_busy_device.run(circuit)                          # creamos el 'job' al solicitar la ejecución del circuito

print("Identificador del job:\t", job.job_id())               # obtenemos el identificador del 'job'

print("Job creado el:\t\t", job.creation_date())              # preguntamos la fecha de creacion del 'job'
print()

tt = 0                                                        # tiempo transcurrido (en segundos)

job_status = job.status()                                     # preguntamos por el estatus del 'job'

while job_status.name not in ["DONE", "CANCELLED", "ERROR"]:
    try:
        job_status = job.status()                             # preguntamos por el estatus del 'job' nuevamente
        if job_status is JobStatus.RUNNING:
            print("\rEl job sigue ejecutándose, tt = " + str(tt) + " s", end="")
            tt += 1
            sleep(1)
    except IBMApiError as ex:
        print("Algo malo sucedió!: {}".format(ex))


print()
print("\n\t>>> El job ha terminado su ejecución")
print("\n\n")

print("Resultado:\t", job.result().get_counts())               # resultado de la ejecución en el dispositivo real