Construir circuitos
Versiones de paquetes
El código en esta página se desarrolló utilizando los siguientes requisitos. Recomendamos usar estas versiones o versiones más recientes.
qiskit[all]~=2.3.0
Esta página examina más de cerca la clase QuantumCircuit en el SDK de Qiskit, incluidos algunos métodos más avanzados que puedes usar para crear circuitos cuánticos.
¿Qué es un circuito cuántico?
Un circuito cuántico simple es una colección de qubits y una lista de instrucciones que actúan sobre esos qubits. Para demostrarlo, la siguiente celda crea un nuevo circuito con dos nuevos qubits, luego muestra el atributo qubits del circuito, que es una lista de Qubits en orden desde el bit menos significativo hasta el bit más significativo .
# Added by doQumentation — required packages for this notebook
!pip install -q qiskit
from qiskit import QuantumCircuit
qc = QuantumCircuit(2)
qc.qubits
[<Qubit register=(2, "q"), index=0>, <Qubit register=(2, "q"), index=1>]
Se pueden combinar múltiples objetos QuantumRegister y ClassicalRegister para crear un circuito. Cada QuantumRegister y ClassicalRegister también puede ser nombrado.
from qiskit.circuit import QuantumRegister, ClassicalRegister
qr1 = QuantumRegister(2, "qreg1") # Create a QuantumRegister with 2 qubits
qr2 = QuantumRegister(1, "qreg2") # Create a QuantumRegister with 1 qubit
cr1 = ClassicalRegister(3, "creg1") # Create a ClassicalRegister with 3 cbits
combined_circ = QuantumCircuit(
qr1, qr2, cr1
) # Create a quantum circuit with 2 QuantumRegisters and 1 ClassicalRegister
combined_circ.qubits
[<Qubit register=(2, "qreg1"), index=0>,
<Qubit register=(2, "qreg1"), index=1>,
<Qubit register=(1, "qreg2"), index=0>]
Puedes encontrar el índice y el registro de un qubit usando el método find_bit del circuito y sus atributos.
desired_qubit = qr2[0] # Qubit 0 of register 'qreg2'
print("Index:", combined_circ.find_bit(desired_qubit).index)
print("Register:", combined_circ.find_bit(desired_qubit).registers)
Index: 2
Register: [(QuantumRegister(1, 'qreg2'), 0)]
Agregar una instrucción al circuito anexa la instrucción al atributo data del circuito. La siguiente salida de celda muestra que data es una lista de objetos CircuitInstruction, cada uno de los cuales tiene un atributo operation y un atributo qubits.
qc.x(0) # Add X-gate to qubit 0
qc.data
[CircuitInstruction(operation=Instruction(name='x', num_qubits=1, num_clbits=0, params=[]), qubits=(<Qubit register=(2, "q"), index=0>,), clbits=())]
La forma más fácil de ver esta información es a través del método draw, que devuelve una visualización de un circuito. Consulta Visualizar circuitos para diferentes formas de mostrar circuitos cuánticos.
qc.draw("mpl")
Los objetos de instrucción de circuito pueden contener circuitos de "definición" que describen la instrucción en términos de instrucciones más fundamentales. Por ejemplo, la compuerta X se define como un caso específico de la compuerta U3, una compuerta de un solo qubit más general.
# Draw definition circuit of 0th instruction in `qc`
qc.data[0].operation.definition.draw("mpl")
Las instrucciones y los circuitos son similares en que ambos describen operaciones sobre bits y qubits, pero tienen propósitos diferentes:
- Las instrucciones se tratan como fijas, y sus métodos generalmente devolverán nuevas instrucciones (sin mutar el objeto original).
- Los circuitos están diseñados para construirse a lo largo de muchas líneas de código, y los métodos
QuantumCircuita menudo mutan el objeto existente.
¿Qué es la profundidad del circuito?
La profundidad (depth) de un circuito cuántico es una medida del número de "capas" de compuertas cuánticas, ejecutadas en paralelo, que se necesitan para completar el cálculo definido por el circuito. Debido a que las compuertas cuánticas toman tiempo para implementarse, la profundidad de un circuito corresponde aproximadamente a la cantidad de tiempo que tarda la computadora cuántica en ejecutar el circuito. Por lo tanto, la profundidad de un circuito es una cantidad importante que se usa para medir si un circuito cuántico puede ejecutarse en un dispositivo.
El resto de esta página ilustra cómo manipular circuitos cuánticos.
Construir circuitos
Métodos como QuantumCircuit.h y QuantumCircuit.cx agregan instrucciones específicas a los circuitos. Para agregar instrucciones a un circuito de manera más general, usa el método append. Esto toma una instrucción y una lista de qubits a los que aplicar la instrucción. Consulta la documentación de la API de Circuit Library para obtener una lista de instrucciones compatibles.
from qiskit.circuit.library import HGate
qc = QuantumCircuit(1)
qc.append(
HGate(), # New HGate instruction
[0], # Apply to qubit 0
)
qc.draw("mpl")
Para combinar dos circuitos, use el método compose. Este acepta otro QuantumCircuit y una lista opcional de mapeos de qubits.
qc_a = QuantumCircuit(4)
qc_a.x(0)
qc_b = QuantumCircuit(2, name="qc_b")
qc_b.y(0)
qc_b.z(1)
# compose qubits (0, 1) of qc_a to qubits (1, 3) of qc_b respectively
combined = qc_a.compose(qc_b, qubits=[1, 3])
combined.draw("mpl")
También es posible que desees compilar circuitos en instrucciones para mantener tus circuitos organizados. Puedes convertir un circuito en una instrucción usando el método to_instruction, luego anexar esto a otro circuito como lo haría con cualquier otra instrucción. El circuito dibujado en la siguiente celda es funcionalmente equivalente al circuito dibujado en la celda anterior.
inst = qc_b.to_instruction()
qc_a.append(inst, [1, 3])
qc_a.draw("mpl")
Si tu circuito es unitario, puedes convertirlo en un Gate usando el método to_gate. Los objetos Gate son tipos específicos de instrucciones que tienen algunas características adicionales, como el método control, que agrega un control cuántico.
gate = qc_b.to_gate().control()
qc_a.append(gate, [0, 1, 3])
qc_a.draw("mpl")
Para ver qué está sucediendo, puedes usar el método decompose para expandir cada instrucción en su definición.
El método decompose devuelve un nuevo circuito y no muta el circuito sobre el que actúa.
qc_a.decompose().draw("mpl")
Medir qubits
Las mediciones se utilizan para muestrear los estados de qubits individuales y transferir los resultados a un registro clásico. Ten en cuenta que si estás enviando circuitos a una primitiva Sampler, se requieren mediciones. Sin embargo, los circuitos enviados a una primitiva Estimator no deben contener mediciones.
Los qubits se pueden medir usando tres métodos: measure, measure_all y measure_active. Para aprender cómo visualizar resultados medidos, consulte la página Visualizar resultados.
-
QuantumCircuit.measure: mide cada qubit en el primer argumento en el bit clásico dado como segundo argumento. Este método permite un control total sobre dónde se almacena el resultado de la medición. -
QuantumCircuit.measure_all: no toma argumentos y se puede usar para circuitos cuánticos sin bits clásicos predefinidos. Crea cables clásicos y almacena los resultados de la medición en orden. Por ejemplo, la medición del qubit se almacena en cbit ). También agrega una barrera antes de la medición. -
QuantumCircuit.measure_active: similar ameasure_all, pero mide solo los qubits que tienen operaciones.
qc1 = QuantumCircuit(2, 2)
qc1.measure(0, 1)
qc1.draw("mpl", cregbundle=False)
qc2 = QuantumCircuit(2)
qc2.measure_all()
qc2.draw("mpl", cregbundle=False)
qc3 = QuantumCircuit(2)
qc3.x(1)
qc3.measure_active()
qc3.draw("mpl", cregbundle=False)
Circuitos parametrizados
Muchos algoritmos cuánticos a corto plazo implican ejecutar muchas variaciones de un circuito cuántico. Dado que construir y optimizar circuitos grandes puede ser computacionalmente costoso, Qiskit admite circuitos parametrizados. Estos circuitos tienen parámetros indefinidos, y sus valores no necesitan definirse hasta justo antes de ejecutar el circuito. Esto te permite mover la construcción y optimización del circuito fuera del bucle del programa principal. La siguiente celda crea y muestra un circuito parametrizado.
from qiskit.transpiler import generate_preset_pass_manager
from qiskit.circuit import Parameter
angle = Parameter("angle") # undefined number
# Create and optimize circuit once
qc = QuantumCircuit(1)
qc.rx(angle, 0)
qc = generate_preset_pass_manager(
optimization_level=3, basis_gates=["u", "cx"]
).run(qc)
qc.draw("mpl")
La siguiente celda crea muchas variaciones de este circuito y muestra una de las variaciones.
circuits = []
for value in range(100):
circuits.append(qc.assign_parameters({angle: value}))
circuits[0].draw("mpl")
Puedes encontrar una lista de los parámetros indefinidos de un circuito en su atributo parameters.
qc.parameters
ParameterView([Parameter(angle)])
Cambiar el nombre de un parámetro
Por defecto, los nombres de los parámetros para un circuito parametrizado tienen el prefijo x- por ejemplo, x[0]. Puedes cambiar los nombres después de que se definen, como se muestra en el siguiente ejemplo.
from qiskit.circuit.library import z_feature_map
from qiskit.circuit import ParameterVector
# Define a parameterized circuit with default names
# For example, x[0]
circuit = z_feature_map(2)
# Set new parameter names
# They will now be prefixed by `hi` instead
# For example, hi[0]
training_params = ParameterVector("hi", 2)
# Assign parameter names to the quantum circuit
circuit = circuit.assign_parameters(parameters=training_params)
Próximos pasos
- Para aprender sobre algoritmos cuánticos a corto plazo, toma el curso Diseño de algoritmos variacionales.
- Ve un ejemplo de circuitos siendo utilizados en el tutorial Algoritmo de Grover.
- Trabaja con circuitos simples usando IBM Quantum Composer.