Nota
Esta página fue generada a partir de tutorials/circuits/01_circuit_basics.ipynb.
Aspectos Básicos de un Circuito¶
Aquí, proporcionamos una descripción general del trabajo con Qiskit. Qiskit proporciona los componentes básicos necesarios para programar computadoras cuánticas. La unidad fundamental de Qiskit es el circuito cuántico. Un flujo de trabajo básico con Qiskit consta de dos etapas: Construir y Ejecutar. Construir te permite crear diferentes circuitos cuánticos que representan el problema que estás resolviendo y Ejecutar te permite ejecutarlos en diferentes backends. Una vez que se han ejecutado los trabajos (jobs), los datos se recopilan y posprocesan según el resultado deseado.
[1]:
import numpy as np
from qiskit import QuantumCircuit
Construir el circuito¶
El elemento básico necesario para tu primer programa es el QuantumCircuit. Comenzamos creando un QuantumCircuit
compuesto de tres qubits.
[2]:
# Create a Quantum Circuit acting on a quantum register of three qubits
circ = QuantumCircuit(3)
Después de crear el circuito con sus registros, puedes agregar compuertas («operaciones») para manipular los registros. A medida que avances en los tutoriales, encontrarás más compuertas y circuitos; a continuación, se muestra un ejemplo de un circuito cuántico que genera un estado GHZ de tres qubits
Para crear dicho estado, comenzamos con un registro cuántico de tres qubits. De forma predeterminada, cada qubit del registro se inicializa en \(|0\rangle\). Para hacer el estado GHZ, aplicamos las siguientes compuertas: - Una compuerta Hadamard \(H\) en el qubit 0, que lo pone en el estado de superposición \(\left(|0\rangle+|1\rangle\right)/\sqrt{2}\). - Una operación NOT controlada (\(C_{X}\)) entre el qubit 0 y el qubit 1. - Una operación NOT controlada entre el qubit 0 y el qubit 2.
En una computadora cuántica ideal, el estado producido al ejecutar este circuito sería el estado GHZ anterior.
En Qiskit, las operaciones se pueden agregar al circuito una por una, como se muestra a continuación.
[3]:
# Add a H gate on qubit 0, putting this qubit in superposition.
circ.h(0)
# Add a CX (CNOT) gate on control qubit 0 and target qubit 1, putting
# the qubits in a Bell state.
circ.cx(0, 1)
# Add a CX (CNOT) gate on control qubit 0 and target qubit 2, putting
# the qubits in a GHZ state.
circ.cx(0, 2)
[3]:
<qiskit.circuit.instructionset.InstructionSet at 0x7f7c92288310>
Visualizar el circuito¶
Puedes visualizar tu circuito usando QuantumCircuit.draw()
de Qiskit, que dibuja el circuito en la forma que se encuentra en muchos libros de texto.
[4]:
circ.draw('mpl')
[4]:
En este circuito, los qubits se ordenan, con el qubit cero en la parte superior y el qubit dos en la parte inferior. El circuito se lee de izquierda a derecha (lo que significa que las primeras compuertas que se aplican en el circuito se muestran más a la izquierda).
Al representar el estado de un sistema de varios qubits, el orden de los tensores utilizado en Qiskit es diferente al utilizado en la mayoría de los libros de texto de física. Supongamos que hay \(n\) qubits, y el qubit \(j\) está etiquetado como \(Q_{j}\). Qiskit usa un orden en el que el qubit \(n^{\mathrm{th}}\) está en el lado izquierdo del producto tensorial, de modo que los vectores base están etiquetados como \(Q_{n-1}\otimes \cdots \otimes Q_1\otimes Q_0\).
Por ejemplo, si el qubit cero está en el estado 0, el qubit 1 está en el estado 0 y el qubit 2 está en el estado 1, Qiskit representaría este estado como \(|100\rangle\), mientras que muchos libros de texto de física lo representarían como \(|001\rangle\).
Esta diferencia en el etiquetado afecta la forma en que las operaciones de varios qubit se representan como matrices. Por ejemplo, Qiskit representa una operación X controlada (\(C_{X}\)) con el qubit 0 siendo el control y el qubit 1 siendo el objetivo como
Simular circuitos¶
Para simular un circuito usamos el módulo quant_info en Qiskit. Este simulador devuelve el estado cuántico, que es un vector complejo de dimensión \(2^n\), donde \(n\) es el número de qubits (así que ten cuidado al usar esto, ya que rápidamente se volverá demasiado grande para ejecutar en tu máquina).
Hay dos etapas en el simulador. La primera es establecer el estado de entrada y la segunda es hacer evolucionar el estado mediante el circuito cuántico.
[5]:
from qiskit.quantum_info import Statevector
# Set the intial state of the simulator to the ground state using from_int
state = Statevector.from_int(0, 2**3)
# Evolve the state by the quantum circuit
state = state.evolve(circ)
#draw using latex
state.draw('latex')
[5]:
[6]:
from qiskit.visualization import array_to_latex
#Alternative way of representing in latex
array_to_latex(state)
[6]:
Qiskit también proporciona un conjunto de herramientas de visualización que te permiten ver el estado.
A continuación, usamos la función de visualización para dibujar la qsphere y un diagrama de hinton que representa los componentes real e imaginario de la matriz de densidad de estado \(\rho\).
[7]:
state.draw('qsphere')
[7]:
[8]:
state.draw('hinton')
[8]:
Representación unitaria de un circuito¶
El módulo quant_info de Qiskit también tiene un método de operador que puede usarse para hacer un operador unitario para el circuito. Esto calcula la matriz \(2^n \times 2^n\) que representa el circuito cuántico.
[9]:
from qiskit.quantum_info import Operator
U = Operator(circ)
# Show the results
U.data
[9]:
array([[ 0.70710678+0.j, 0.70710678+0.j, 0. +0.j,
0. +0.j, 0. +0.j, 0. +0.j,
0. +0.j, 0. +0.j],
[ 0. +0.j, 0. +0.j, 0. +0.j,
0. +0.j, 0. +0.j, 0. +0.j,
0.70710678+0.j, -0.70710678+0.j],
[ 0. +0.j, 0. +0.j, 0.70710678+0.j,
0.70710678+0.j, 0. +0.j, 0. +0.j,
0. +0.j, 0. +0.j],
[ 0. +0.j, 0. +0.j, 0. +0.j,
0. +0.j, 0.70710678+0.j, -0.70710678+0.j,
0. +0.j, 0. +0.j],
[ 0. +0.j, 0. +0.j, 0. +0.j,
0. +0.j, 0.70710678+0.j, 0.70710678+0.j,
0. +0.j, 0. +0.j],
[ 0. +0.j, 0. +0.j, 0.70710678+0.j,
-0.70710678+0.j, 0. +0.j, 0. +0.j,
0. +0.j, 0. +0.j],
[ 0. +0.j, 0. +0.j, 0. +0.j,
0. +0.j, 0. +0.j, 0. +0.j,
0.70710678+0.j, 0.70710678+0.j],
[ 0.70710678+0.j, -0.70710678+0.j, 0. +0.j,
0. +0.j, 0. +0.j, 0. +0.j,
0. +0.j, 0. +0.j]])
Backend OpenQASM¶
Los simuladores anteriores son útiles porque proporcionan información sobre el estado de salida del circuito ideal y la representación matricial del circuito. Sin embargo, un experimento real termina midiendo cada qubit (generalmente en la base computacional \(|0\rangle, |1\rangle\)). Sin medición, no podemos obtener información sobre el estado. Las mediciones hacen que el sistema cuántico colapse en bits clásicos.
Por ejemplo, supongamos que hacemos mediciones independientes en cada qubit del estado GHZ de tres qubits
y denotemos la cadena de bits resultante como \(xyz\). Recuerda que, bajo el etiquetado de qubits utilizado por Qiskit, \(x\) correspondería al resultado en el qubit 2, \(y\) al resultado en el qubit 1, y \(z\) al resultado en qubit 0.
Nota: Esta representación de la cadena de bits coloca el bit más significativo (Most Significant Bit, MSB) a la izquierda y el bit menos significativo (Least Significant Bit, LSB) a la derecha. Este es el orden estándar de cadenas de bits binarias. Ordenamos los qubits de la misma manera (el qubit que representa el MSB tiene índice 0), por lo que Qiskit utiliza un orden de producto tensorial no estándar.
Recuerda la probabilidad de obtener un resultado \(xyz\) viene dada por
y como tal para el estado GHZ, la probabilidad de obtener 000 o 111 es 1/2.
Para simular un circuito que incluye medición, necesitamos agregar mediciones al circuito original anterior y usar un backend de Aer diferente.
[10]:
# Create a Quantum Circuit
meas = QuantumCircuit(3, 3)
meas.barrier(range(3))
# map the quantum measurement to the classical bits
meas.measure(range(3), range(3))
# The Qiskit circuit object supports composition.
# Here the meas has to be first and front=True (putting it before)
# as compose must put a smaller circuit into a larger one.
qc = meas.compose(circ, range(3), front=True)
#drawing the circuit
qc.draw('mpl')
[10]:
Este circuito agrega un registro clásico y tres mediciones que se utilizan para mapear el resultado de los qubits a los bits clásicos.
Para simular este circuito, usamos el qasm_simulator
de Qiskit Aer. Cada ejecución de este circuito producirá la cadena de bits 000 o 111. Para generar estadísticas sobre la distribución de las cadenas de bits (para, por ejemplo, estimar \(\mathrm{Pr}(000)\)), necesitamos repetir el circuito muchas veces. El número de veces que se repite el circuito se puede especificar en la función execute
, mediante la palabra clave shots
.
[11]:
# Adding the transpiler to reduce the circuit to QASM instructions
# supported by the backend
from qiskit import transpile
# Use AerSimulator
from qiskit_aer import AerSimulator
backend = AerSimulator()
# First we have to transpile the quantum circuit
# to the low-level QASM instructions used by the
# backend
qc_compiled = transpile(qc, backend)
# Execute the circuit on the qasm simulator.
# We've set the number of repeats of the circuit
# to be 1024, which is the default.
job_sim = backend.run(qc_compiled, shots=1024)
# Grab the results from the job.
result_sim = job_sim.result()
Una vez que tengas un objeto de resultado, puedes acceder a los recuentos a través de la función get_counts(circuit)
. Esto te brinda los resultados binarios agregados del circuito que enviaste.
[12]:
counts = result_sim.get_counts(qc_compiled)
print(counts)
{'111': 522, '000': 502}
Aproximadamente el 50 por ciento de las veces, la cadena de bits de salida es 000. Qiskit también proporciona una función plot_histogram
, que te permite ver los resultados.
[13]:
from qiskit.visualization import plot_histogram
plot_histogram(counts)
[13]:
Las probabilidades de salida estimadas \(\mathrm{Pr}(000)\) y \(\mathrm{Pr}(111)\) se calculan tomando los conteos agregados y dividiendo entre el número de iteraciones (cantidad de veces que el circuito fue repetido). Intenta cambiar el valor de shots
en la función execute
y ve cómo cambian las probabilidades estimadas.
[14]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright
Version Information
Qiskit Software | Version |
---|---|
Qiskit | 0.26.2 |
Terra | 0.17.4 |
Aer | 0.8.2 |
Ignis | 0.6.0 |
Aqua | 0.9.1 |
IBM Q Provider | 0.13.1 |
System information | |
Python | 3.8.5 (default, Sep 4 2020, 07:30:14) [GCC 7.3.0] |
OS | Linux |
CPUs | 2 |
Memory (Gb) | 7.523967742919922 |
Fri Jun 04 17:48:05 2021 IST |
This code is a part of Qiskit
© Copyright IBM 2017, 2021.
This code is licensed under the Apache License, Version 2.0. You may
obtain a copy of this license in the LICENSE.txt file in the root directory
of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
Any modifications or derivative works of this code must retain this
copyright notice, and modified files need to carry a notice indicating
that they have been altered from the originals.