Simulador del kit de desarrollo de Quantum (QDK)
Los sistemas cuánticos que están muy bien aislados de sus entornos, de forma que ningún otro sistema interactúa con los cúbits, se denominan sistemas cuánticos cerrados. Por el contrario, un dispositivo que está sujeto a cierta cantidad de interacción, o ruido, de su entorno es un sistema cuántico abierto.
El Kit de desarrollo de Quantum proporciona un simulador en versión preliminar para la simulación de sistemas cuánticos abiertos. Esta característica permite simular el comportamiento de los programas de Q# bajo la influencia del ruido, y también usar la representación del estabilizador (también conocida como simulación CHP) de algoritmos cuánticos, es decir, algoritmos que constan únicamente de CNOT, Hadamard y puertas de fase.
El simulador de ruido se admite para su uso con:
- Programas host de Python
- Cuadernos de Q# independientes
- Programas host de C#
Los simuladores de ruido aún no son compatibles con:
- Programas de línea de comandos independientes de Q#
- Archivos ejecutables basados en QIR
Invocación de los simuladores en versión preliminar desde Python
Debe crear un programa host de Python que invoque el programa cuántico y pueda seguir procesando los resultados devueltos. Para más información, consulte Formas de ejecutar un programa de Q#.
Para empezar, importe la biblioteca QuTiP, una popular biblioteca de Python para manipular estados y procesos de sistemas cuánticos abiertos y cerrados.
import qutip as qt
Puede habilitar el uso del simulador de sistemas abiertos mediante el paquete
qsharp
:import qsharp
De forma similar al método
.simulate()
, las operaciones de Q# importadas en Python exponen un método.simulate_noise()
que se puede usar para ejecutar programas de Q# en los simuladores de sistemas abiertos.De forma predeterminada, el método
.simulate_noise()
asume un modelo de error ideal (es decir, sin ruido). Para configurar un modelo de error determinado, puede usar las funcionesqsharp.get_noise_model
yqsharp.set_noise_model
para obtener y establecer el modelo de ruido actual para los simuladores de versión preliminar. Cada modelo de error se representa como un diccionario de los nombres de operación intrínsecos a los objetos que representan los errores en esas operaciones intrínsecas. Para más información, consulte Configuración de modelos de ruido de sistemas abiertos.En la misma carpeta que el programa host de Python, cree el siguiente programa de Q# en un archivo llamado
NoisySimulation.qs
:namespace NoisySimulation { open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Measurement; open Microsoft.Quantum.Canon; open Microsoft.Quantum.Diagnostics; @EntryPoint() operation DumpPlus() : Unit { use q = Qubit(); H(q); DumpMachine(); X(q); Reset(q); } }
Agregue el código siguiente al programa host para importar la operación de Q#
DumpPlus
:from NoisySimulation import DumpPlus print(DumpPlus.simulate_noise())
'text/plain': 'Mixed state on 3 qubits: [ [0.5000000000000001 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i, 0.5000000000000001 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i] [0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i] [0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i] [0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i] [0.5000000000000001 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i, 0.5000000000000001 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i] [0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i] [0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i] [0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i, 0 + 0 i] ]'
Si mira la salida, puede observar dos diferencias respecto a la salida del simulador predeterminado, que puede invocar mediante
.simulate()
:
Los simuladores en versión preliminar usan registros cuánticos de un tamaño definido (de forma predeterminada, tres cúbits) y asignan cúbits de ese registro.
De forma predeterminada, los simuladores en versión preliminar representan estados cuánticos como operadores de densidad, $\rho =\left|\psi\right\rangle\left\langle\psi\right|$, en lugar de vectores de estado, $\left|\psi\right\rangle$.
Por ejemplo, en la salida anterior, el simulador en versión preliminar tiene el operador de densidad $\rho =\left|+00\right\rangle\left\langle+00\right|$, que puede comprobar mediante QuTiP.
ket_zero = qt.basis(2, 0) ket_one = qt.basis(2, 1) ket_plus = (ket_zero + ket_one).unit() ket_psi = qt.tensor(ket_plus, ket_zero, ket_zero) rho = ket_psi * ket_psi.dag() print(rho)
Quantum object: dims = [[2, 2, 2], [2, 2, 2]], shape = (8, 8), type = oper, isherm = True Qobj data = [[0.5 0. 0. 0. 0.5 0. 0. 0. ] [0. 0. 0. 0. 0. 0. 0. 0. ] [0. 0. 0. 0. 0. 0. 0. 0. ] [0. 0. 0. 0. 0. 0. 0. 0. ] [0.5 0. 0. 0. 0.5 0. 0. 0. ] [0. 0. 0. 0. 0. 0. 0. 0. ] [0. 0. 0. 0. 0. 0. 0. 0. ] [0. 0. 0. 0. 0. 0. 0. 0. ]]
Nota:
La biblioteca QuTiP es muy útil cuando se trabaja con estados cuánticos. En la notación QuTiP, los estados cuánticos se escriben como qt.basis(d,s)
, donde d es la dimensión de los sistemas y s es el estado. Por ejemplo, el estado cuántico $|0\rangle$ se puede escribir como ket_zero = qt.basis(2, 0)
. Para más información sobre los métodos y características de QuTiP, consulte la guía del usuario de QuTiP.
Configuración de modelos de ruido de sistemas abiertos
Los simuladores en versión preliminar se pueden configurar mediante el objeto qsharp.config
. Por ejemplo, para cambiar el tamaño del registro a un cúbit, puede modificar la opción de configuración simulators.noisy.nQubits
:
qsharp.config['simulators.noisy.nQubits'] = 1
print(DumpPlus.simulate_noise())
'text/plain': 'Mixed state on 1 qubits: [ [0.5000000000000001 + 0 i, 0.5000000000000001 + 0 i] [0.5000000000000001 + 0 i, 0.5000000000000001 + 0 i] ]'
Modelo de ruido ideal
Puede modificar el modelo de ruido utilizado en la simulación de programas de Q# con diversas funciones del paquete qsharp
. Por ejemplo, para inicializar el modelo de ruido en un modelo ideal (es decir, sin ruido), puede usar set_noise_model_by_name
. A continuación, puede acceder al modelo de ruido mediante get_noise_model
:
qsharp.set_noise_model_by_name('ideal')
noise_model = qsharp.get_noise_model()
Nota
Si usa cuadernos de Jupyter Notebook para desarrollar el programa de Python, use el comando magic %noise_model --set-by-name
para inicializar el modelo de ruido en un modelo ideal.
Este modelo de ruido se representa como un diccionario de Python de preparativos, medidas y puertas y los objetos de Python que representan el ruido de cada uno. Por ejemplo, en el modelo de ruido ideal, H operation se simula mediante una matriz unitaria:
print(noise_model.h)
Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
Qobj data =
[[ 0.70710678 0.70710678]
[ 0.70710678 -0.70710678]]
Despolarizar el modelo de ruido
Además del modelo de ruido ideal, puede configurar otros modelos de ruido. Por ejemplo, el canal de despolarización es un modelo simple para el ruido en los sistemas cuánticos. Un canal cuántico se puede ver como un mapa $\Delta_{p}$, que depende de un parámetro $\lambda$ y que asigna un estado cuántico $\rho$ a un estado cuántico $\rho^{'}$. El canal de despolarización de un cúbit se escribe como:
$$\Delta_{p}(\rho) = (1-p) \frac{\mathbb{I}}{{2} + p \rho $$
Puede modificar el modelo de ruido para agregar ruido de despolarización mediante funciones QuTiP.
I, X, Y, Z = [P.as_qobj() for P in qsharp.Pauli]
def depolarizing_noise(p=1.0):
return p * qt.to_super(I) + ((1 - p) / 4) * sum(map(qt.to_super, [I, X, Y, Z]))
noise_model.h = depolarizing_noise(0.99) * qt.to_super(qt.qip.operations.hadamard_transform())
print(noise_model.h)
Quantum object: dims = [[[2], [2]], [[2], [2]]], shape = (4, 4), type = super, isherm = True
Qobj data =
[[ 0.5 0.495 0.495 0.5 ]
[ 0.495 -0.495 0.495 -0.495]
[ 0.495 0.495 -0.495 -0.495]
[ 0.5 -0.495 -0.495 0.5 ]]
Puede aplicar el modelo de ruido de despolarización al operador de densidad $\rho_{\text{zero}}=\left|0\right\rangle\left\langle0\right|$ para comprobar cómo cambia bajo los efectos del ruido de despolarización. Con este modelo, ya no se obtiene el estado exacto $\rho_{+}=|+\rangle\langle+|$, porque el programa de Q# ha incurrido en algún pequeño error debido al ruido en la aplicación de H operation:
ket_zero = qt.basis(2, 0)
rho_zero = ket_zero * ket_zero.dag()
rho_zero_dep_noise = noise_model.h(rho_zero)
print(rho_zero_dep_noise)
Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
Qobj data =
[[0.5 0.495]
[0.495 0.5 ]]
Establecimiento de modelos de ruido
Una vez que haya modificado el modelo de ruido, puede establecerlo como el modelo de ruido activo que se usa en la simulación de programas de Q#:
qsharp.set_noise_model(noise_model)
print(DumpPlus.simulate_noise())
'text/plain': 'Mixed state on 1 qubits: [ [0.5002403569793327 + 0 i, 0.49578581259001314 + 0 i] [0.49578581259001314 + 0 i, 0.499235767960659
+ 0 i] ]'
Sugerencia
Cualquier canal cuántico tiene una representación de suma de operador en una matriz de densidad $\rho$, como $\Delta_{p}(\rho )=\sum_{i}K_{i}\rho K_{i}^{\dagger}$ y $\sum_{i}K_{i}^{\dagger}K_{i}= \mathcal{I}$, donde las matrices $K_{i}$ son los operadores de Kraus.
Puede calcular la descomposición de Kraus de un modelo de ruido mediante la biblioteca QuTiP:
kraus_operators = qt.to_kraus(noise_model.h)
print(kraus_operators)
[Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
Qobj data =
[[ 0.06123724 -0.02041241]
[-0.02041241 0.02041241]], Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
Qobj data =
[[ 0.70445014 0.70445014]
[ 0.70445014 -0.70445014]], Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = False
Qobj data =
[[ 0.01550345 -0.03309488]
[ 0.0506863 0.03309488]], Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = False
Qobj data =
[[-2.74180053e-18 5.00000000e-02]
[-5.27753089e-18 5.00000000e-02]]]
Los errores de tiempo continuo en las rotaciones, como las operaciones Rx
, Ry
y Rz
, se pueden especificar mediante el establecimiento de generadores dinámicos cuánticos que incluyen evolución coherente y no coherente.
Específicamente, se puede usar la función qsharp.to_generator
para crear un generador dinámico a partir de uno hamiltoniano y uno o varios operadores de salto (también conocidos como operadores de Lindblad).
Por ejemplo, para establecer la operación Rz
para aplicar un hamiltoniano de $H = -0,48 Z$ junto con un $T_1$ finito y un proceso $T_2$:
qsharp.set_noise_model_by_name(
'ideal',
rz=to_generator(
-0.48 * qt.sigmaz(),
t1_dissipation(100.0),
t2_dissipation(25.0)
)
)
Los procesos de error de tiempo continuo también se pueden especificar como conjuntos de generadores; es decir, con procesos cuánticos fijos que se aplican antes o después de un generador dinámico. Para especificar procesos que se aplican antes o después de la evolución de tiempo continuo, se pueden proporcionar a to_generator
los argumentos de palabra clave pre
y post
:
qsharp.set_noise_model_by_name(
'ideal',
rz=to_generator(
-0.48 * qt.sigmaz(),
t1_dissipation(100.0),
t2_dissipation(25.0),
# Applies a 5% depolarizing process after each call to Rz.
post=depolarizing_process(0.95)
)
)
Configuración de modelos de ruido del estabilizador
Puede configurar el simulador en versión preliminar para que se utilice con circuitos de estabilizador (o algoritmos de estabilizador), lo que también se conoce como simulación CHP. La simulación CHP (CNOT-Hadamard-Phase) permite la simulación de alto rendimiento de programas de estabilizador. Es decir, algoritmos cuánticos que constan únicamente de puertas NOT controladas, puertas Hadamard y puertas de fase π/2 (representadas en Q# por la operación S
), así como medidas en base de Pauli. Los programas de estabilizador se pueden simular de forma eficaz en un equipo clásico, tal y como se muestra en el teorema de Gottesman-Knill.
Cree un nuevo modelo de ruido mediante
get_noise_model_by_name
y establézcalo como el modelo de ruido activo:qsharp.set_noise_model_by_name('ideal_stabilizer')
Para hacer el mejor uso de los modelos de ruido del estabilizador, también debe configurar el simulador para que se inicie en la representación del estabilizador:
qsharp.config['simulators.noisy.representation'] = 'stabilizer' print(DumpPlus.simulate_noise())
La visualización de la salida es:
$$\begin{align}\left(\begin{array}{c|c|c} 0 & 1 & 0 \\ \hline 1 & 0 & 0 \end{array}\right) \end{align}$$
Sugerencia
Si ejecuta el programa host de Python desde el terminal, obtendrá los metadatos HTML de la salida de
print(.simulate_noise())
. Para facilitar la visualización, Jupyter Notebook muestra tablas HTML dentro del mismo cuaderno.En concreto, la representación del estabilizador no admite operaciones fuera del formalismo del estabilizador, como T y CCNOT. Esto permite que la representación del estabilizador admita significativamente más cúbits que otras representaciones. Por ejemplo, considere un registro cuántico de 10 cúbits:
qsharp.config['simulators.noisy.nQubits'] = 10 print(DumpPlus.simulate_noise())
La visualización de la salida es:
$$\begin{align}\left(\begin{array}{cccccccccc|cccccccccc|c} 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ \hline 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \end{array}\right) \end{\end{align}$$
Modifique el programa de Q# con el código siguiente, donde la operación
DumpBellPair
realiza una funciónDumpMachine
para un par de Bell, que es un par de cúbits entrelazado.operation DumpBellPair() : Unit { use left = Qubit(); use right = Qubit(); within { H(left); CNOT(left, right); } apply { DumpMachine(); } }
Ejecute la operación
DumpBellPair
con el simulador de ruido del estabilizador. Para simplificar, use un registro cuántico de cuatro cúbits.from NoisySimulation import DumpBellPair qsharp.config['simulators.noisy.nQubits'] = 4 DumpBellPair.simulate_noise()
La visualización de la salida es:
$$\begin{align}\left(\begin{array}{cccc|cccc|c} 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 \\ \hline 1 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 1 & 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \end{array}\right) \end{align}$$
El estilo de visualización de los estados del estabilizador se puede seleccionar mediante la opción de configuración
simulators.noisy.stabilizerStateStyle
. Por ejemplo, puede seleccionar la visualización sin desestabilizadores conmatrixWithoutDestabilizers
:qsharp.config['simulators.noisy.stabilizerStateStyle'] = 'matrixWithoutDestabilizers'
$$\begin{align}\left(\begin{array}{cccc|cccc|c} 1 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 1 & 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \end{array}\right) \end{align}$$
Para seleccionar la representación del grupo de estabilizador, use
denseGroupPresentation
:qsharp.config['simulators.noisy.stabilizerStateStyle'] = 'denseGroupPresentation'
$$\left\langle XX𝟙𝟙, ZZ𝟙𝟙, 𝟙𝟙Z𝟙, 𝟙𝟙𝟙Z \right\rangle$$
Para seleccionar la representación del grupo de estabilizador sin la matriz de identidad, use
sparseGroupPresentation
:qsharp.config['simulators.noisy.stabilizerStateStyle'] = 'sparseGroupPresentation'
$$\left\langle X_{0}X_{1}, Z_{0}Z_{1}, Z_{2}, Z_{{3}\right\rangle$$