Algoritmo de Shor
Para este módulo de Qiskit in Classrooms, los estudiantes deben disponer de un entorno de Python trabajo con los siguientes paquetes instalados:
- v2.1.0
qiskito más reciente - v0.40.1
qiskit-ibm-runtimeo más reciente - v0.17.0
qiskit-aero más reciente qiskit.visualizationnumpypylatexenc
Para configurar e instalar los paquetes anteriores, consulte la guía Instalar Qiskit. Para ejecutar trabajos en ordenadores cuánticos reales, los estudiantes deberán crear una cuenta siguiendo los pasos que IBM Quantum® se indican en la guía Configurar su IBM Cloud cuenta.
Este módulo se probó y utilizó tres segundos de tiempo de QPU. Esto es solo una estimación. Su uso real puede variar.
# Uncomment and modify this line as needed to install dependencies
#!pip install 'qiskit>=2.1.0' 'qiskit-ibm-runtime>=0.40.1' 'qiskit-aer>=0.17.0' 'numpy' 'pylatexenc'Introducción
A principios de la década 1990s, crecía el entusiasmo en torno al potencial de los ordenadores cuánticos para resolver problemas que resultaban difíciles para los ordenadores clásicos. Algunos informáticos con talento habían ideado algoritmos que demostraban el poder de la computación cuántica para algunos problemas específicos y artificiales, pero nadie había encontrado una única «aplicación revolucionaria» de la computación cuántica que fuera capaz de revolucionar el campo. Así fue hasta 1994, cuando Peter Shor ideó lo que hoy se conoce como el algoritmo de Shor para factorizar números grandes.
En aquella época era bien sabido que encontrar los factores primos de un número grande resultaba extremadamente difícil para un ordenador clásico. De hecho, los protocolos de seguridad de Internet se basaban en esta dificultad. Shor encontró una forma de hallar estos factores de manera exponencialmente más eficiente al descargar algunos de los pasos más difíciles en un ordenador cuántico teórico futuro.
En este módulo, exploraremos el algoritmo de Shor. En primer lugar, daremos un poco más de contexto al algoritmo, formalizando el problema que resuelve y explicando su relevancia para la ciberseguridad. A continuación, ofreceremos una introducción a las matemáticas modulares y cómo aplicarlas al problema de la factorización, mostrando cómo la factorización se reduce a otro problema denominado «búsqueda de orden» Mostraremos cómo se aplican la transformada de Fourier cuántica y la estimación de fase cuántica que aprendimos en un módulo anterior, y cómo utilizarlas para resolver el problema de búsqueda de orden.
¡Por fin ejecutaremos el algoritmo de Shor en un ordenador cuántico real! Sin embargo, hay que tener en cuenta que este algoritmo solo será realmente útil cuando dispongamos de un ordenador cuántico grande y tolerante a fallos, lo que aún tardará algunos años en llegar. Por lo tanto, solo factorizaremos un número pequeño para demostrar cómo funciona el algoritmo.
El problema del factoring
El objetivo del problema de factorización es encontrar los factores primos de un número . Para algunos números , esto es bastante fácil. Por ejemplo, si es par, uno de sus factores primos será 2. Si es una potencia prima, es decir, para algún número primo , también es bastante fácil encontrar : solo hay que aproximar la raíz de y buscar números primos cercanos que podrían ser .
Sin embargo, donde los ordenadores clásicos tienen dificultades es cuando es impar y no es una potencia prima. Este es el caso que aborda el algoritmo de Shor. El algoritmo encuentra dos factores y tales que . Se puede aplicar de forma recursiva hasta que todos los factores sean primos. En las siguientes secciones veremos cómo se aborda este problema.
Relevancia para la ciberseguridad
Se han creado muchos sistemas criptográficos basados en el hecho de que factorizar números grandes es difícil, incluido uno que se utiliza habitualmente en la actualidad, llamado RSA. En RSA, se crea una clave pública multiplicando dos números primos grandes entre sí para obtener . A continuación, cualquiera puede utilizar esta clave pública para cifrar datos. Pero solo alguien que tenga la clave privada, y , puede descifrar esos datos.
Si fuera fácil de factorizar, entonces cualquiera podría determinar cuáles son y y descifrar la encriptación. Pero no lo es. Este es un problema famoso por su dificultad. De hecho, los factores primos de un número llamado RSA1024, que tiene 1024 dígitos binarios y 309 dígitos decimales, aún no se han encontrado, a pesar de que en 1991 se ofreció un premio de 100 000 dólares por su factorización.
La solución de Shor
En 1994, Peter Shor se dio cuenta de que un ordenador cuántico podía factorizar un número grande de forma exponencialmente más eficiente que un ordenador clásico. Su visión se basaba en la relación entre este problema de factorización y la aritmética modular. Repasaremos brevemente los fundamentos de la aritmética modular y luego veremos cómo podemos utilizarla para factorizar .
Aritmética modular
La aritmética modular es un sistema de conteo cíclico, lo que significa que, aunque el conteo comienza de la forma habitual, con los números enteros 0, 1, 2, etc., En algún momento, tras un periodo de tiempo , el recuento vuelve a empezar. Veamos cómo funciona esto con un ejemplo. Digamos que nuestro período es 5. Entonces, mientras contamos, donde normalmente llegaríamos a 5, en su lugar volvemos a empezar desde 0:
Esto se debe a que en el mundo «» modulo-5, 5 equivale a 0. Decimos que . De hecho, todos los múltiplos de 5 serán equivalentes a .
Comprueba tu comprensión
Utiliza la aritmética modular para resolver el siguiente problema:
Sale en un largo viaje transcontinental en tren a las 8 de la mañana. El viaje en tren dura 60 horas. ¿A qué hora llegas?
El período es 24, ya que hay 24 horas en un día. Por lo tanto, este problema se puede escribir en aritmética modular como:
Por lo tanto, llegarías a tu destino a las 20:00, o las 8 de la tarde.
y
A menudo resulta útil introducir dos conjuntos, y . es simplemente el conjunto de números que existen en un mundo «módulo ». Por ejemplo, cuando contábamos modulo-5, el conjunto sería . Otro ejemplo: . Podemos realizar sumas y multiplicaciones (módulo ) con los elementos de , y el resultado de cada una de estas operaciones también es un elemento de , lo que convierte a en un objeto matemático denominado anillo.
Hay un subconjunto especial de que nos interesa especialmente para el algoritmo de Shor. Es el subconjunto de números en tal que el máximo común divisor entre cada elemento y es 1, por lo que cada elemento es «coprimario» con respecto a . Si tomamos el conjunto de estos números junto con la operación de multiplicación modular, se forma otro objeto matemático, llamado grupo. A este grupo lo llamamos. Resulta que con (y con los grupos finitos en general), si elegimos cualquier elemento y multiplicamos repetidamente por sí mismo, siempre acabaremos obteniendo el número . El número mínimo de veces que hay que multiplicar por sí mismo para obtener se denomina orden de . Este hecho será muy importante para nuestro análisis sobre cómo factorizar números más adelante.
Comprueba tu comprensión
¿Qué es ?
Hemos excluido los siguientes números:
¿Cuál es el orden de cada uno de los elementos en ?
El orden es el número más bajo tal que para cada elemento .
Tenga en cuenta que, aunque pudimos encontrar el orden de los números en , esto NO es una tarea fácil en general, para números más grandes . Este es el quid de la cuestión del problema de la factorización y la razón por la que necesitamos un ordenador cuántico. Veremos por qué a medida que avancemos con el resto del cuaderno.
Aplicar la aritmética modular al problema de la factorización
La clave para encontrar factores y tales que se reduce a encontrar algún otro entero tal que
y
¿Cómo nos ayuda encontrar a hallar los factores y ? Analicemos ahora el razonamiento. Dado que, eso significa que . En otras palabras, es un múltiplo de . Por lo tanto, para algún entero ,
Podemos factorizar para obtener:
A partir de nuestras hipótesis iniciales sabemos que , por lo que no se divide uniformemente ni en ni en. Por lo tanto, los dos factores de , y, deben dividirse cada uno en y . O bien es un factor de y es un factor de , o viceversa. Por lo tanto, si calculamos los máximos comunes divisores (MCD) entre y tanto como , obtendremos los factores y . Calcular el MCD entre dos números es una tarea clásicamente fácil que se puede realizar, por ejemplo, utilizando el algoritmo de Euclides.
Comprueba tu comprensión
Puede resultar complicado comprender cada paso de la lógica anterior, así que intente aplicarla con un ejemplo. Utilice y . En primer lugar, compruebe que y . A continuación, continúe verificando cada paso. Por último, calcula y comprueba que son los factores de .
, que es , por lo que .
, que no es equivalente a .
, que no es equivalente a .
Ahora sabemos que para algún entero . Esto se verifica cuando sustituimos y : cuando .
Ahora, necesitamos calcular y .
Así que, ¡encontramos nuestros factores de !
El algoritmo
Ahora que hemos visto cómo encontrar un número entero tal que nos ayuda a factorizar , podemos repasar el algoritmo de Shor. Básicamente, se trata de encontrar :
- Elige un número entero aleatorio Elige un número entero aleatorio tal que .
- Calcular de forma clásica.
- Si , ya has encontrado un factor. Alto.
- De lo contrario, continúe.
-
Encuentra el orden del módulo Encuentra el entero positivo más pequeño que satisfaga .
-
Comprueba si el pedido es par.
- Si es impar, vuelve al paso 1 y elige un nuevo .
- Si es par, continúe con el paso 4.
- Calcular
- Comprueba que y .
- Si , vuelve al paso 1 y elige uno nuevo .
- De lo contrario, calcula los mcd para extraer los factores:
Estos serán factores no triviales de .
- Factorizar recursivamente si es necesario.
- Si y/o no son primos, aplique el algoritmo de forma recursiva para factorizarlos completamente.
- Una vez que todos los factores son primos, el factorización está completa.
Basándonos en este procedimiento, podría no resultar obvio por qué se necesita un ordenador cuántico para completar esta tarea. Es necesario porque el paso 2, encontrar el orden del módulo , es clásicamente un problema muy difícil. La complejidad aumenta exponencialmente con el número . Pero con un ordenador cuántico, solo tenemos que utilizar la estimación de fase cuántica para resolverlo. El paso 4, hallar el MCD de dos números enteros, es en realidad algo bastante fácil de hacer de forma clásica. Por lo tanto, el único paso que realmente necesita la potencia de un ordenador cuántico es el paso de búsqueda de órdenes. Decimos que el problema del factoraje «se reduce» al problema de encontrar el orden.
La parte difícil: encontrar el pedido
Ahora veremos cómo podemos utilizar un ordenador cuántico para la búsqueda. En primer lugar, aclaremos qué entendemos por «orden» Por supuesto, ya te he explicado lo que significa matemáticamente el orden: es el primer entero distinto de cero tal que Pero veamos si podemos entender un poco mejor este concepto.
Para valores suficientemente pequeños , podemos determinar el orden calculando cada potencia de , tomando el módulo de ese número y deteniéndonos cuando encontramos la potencia que satisface . Eso es lo que hicimos con nuestro ejemplo, , arriba. Veamos algunos gráficos de estas potencias modulares para algunos valores de muestra de y :
¿Notas algo? ¡Son funciones periódicas! ¡Y el orden es el mismo que el período! Por lo tanto, encontrar el orden equivale a encontrar el período.
Las computadoras cuánticas son muy adecuadas para hallar el período de las funciones. Para ello, podemos utilizar una subrutina algorítmica denominada «estimación de fase cuántica». En el módulo anterior hablamos sobre QPE y su relación con la transformada de Fourier cuántica. Para obtener información detallada, consulte el módulo QFT o la lección de John Watrous sobre estimación de fase cuántica en su curso sobre algoritmos cuánticos. Ahora repasaremos los puntos principales del procedimiento:
En la estimación de fase cuántica (QPE), comenzamos con un operador unitario y un estado propio de ese operador unitario . A continuación, utilizamos la QPE para aproximar el valor propio correspondiente, que, dado que el operador es unitario, tendrá la forma . Por lo tanto, hallar el valor propio equivale a hallar el valor de en la función periódica. El circuito tiene el siguiente aspecto:
donde el número de qubits de control (los qubits superiores en la figura anterior) determina la precisión de la aproximación.
En el algoritmo de Shor, utilizamos QPE en el operador unitario :
Aquí, denota un estado de base computacional del registro multiqubit, donde el valor binario de los qubits corresponde al entero . Por ejemplo, si y , entonces se representa mediante el estado de base de cuatro qubits, ya que se necesitan cuatro qubits para codificar números hasta 15. (Si este concepto le resulta desconocido, consulte el módulo introductorio Qiskit en las aulas para refrescar sus conocimientos sobre la codificación binaria de los estados cuánticos)
Ahora, necesitamos averiguar un estado propio de esta unidad. Si comenzamos en el estado , podemos ver que cada aplicación sucesiva de multiplicará el estado de nuestro registro por , y después de aplicaciones llegaremos nuevamente al estado. Por ejemplo, con y :
Así, las superposiciones de los estados en este ciclo ( ) de la forma:
son todos los estados propios de . (Hay más estados propios además de estos. Pero solo nos interesan los que tienen la forma anterior)
Comprueba tu comprensión
Encuentre un estado propio del unitario correspondiente a y .
Entonces, el orden . Los estados propios que nos interesan serán una superposición igual de todos los estados que se han repetido anteriormente, con varias fases:
Supongamos que pudiéramos inicializar nuestro estado cuántico en uno de estos estados propios (spoiler: no podemos). O, al menos, no fácilmente. Explicaremos por qué y qué podemos hacer en su lugar en breve). Entonces podríamos usar QPE para estimar el valor propio correspondiente, donde . A continuación, podremos determinar el orden mediante la sencilla ecuación:
Pero recuerde, dije que se trata de * estimaciones* de QPE, no nos da un valor exacto. Necesitamos que la estimación sea lo suficientemente buena como para diferenciar entre y . Cuantos más qubits de control tengamos, mejor será la estimación. En los problemas al final de la lección, se te pedirá que determines el mínimo necesario para factorizar un número .
Ahora tenemos que resolver un problema. Toda la explicación anterior sobre cómo encontrar comienza con la preparación del estado propio . Pero no sabemos cómo hacerlo sin saber ya qué es. La lógica es circular. Necesitamos una forma de estimar el valor propio sin inicializar el estado propio.
En lugar de comenzar con un estado propio de , podemos preparar el estado inicial en el estado de -qubit correspondiente a en binario (como en ) . Aunque este estado en sí mismo obviamente no es un estado propio de , es una superposición sobre todos los estados propios :
Comprueba tu comprensión
Verifica que es equivalente a la superposición sobre los estados propios que encontraste para y en la pregunta anterior.
Los cuatro estados propios eran:
Entonces,
¿Cómo nos permite esto encontrar el orden ? Dado que el estado inicial es una superposición de todos los estados propios de la forma indicada anteriormente, el algoritmo QPE estima simultáneamente cada uno de los correspondientes a estos estados propios. Por lo tanto, la medición de los qubits de control al final dará como resultado una aproximación al valor donde es uno de los valores propios elegidos al azar. Si repetimos este circuito varias veces y obtenemos algunas muestras con diferentes valores de , rápidamente podremos deducir .
Implementar en Qiskit
Como mencionamos anteriormente, nuestro hardware no está en condiciones de factorizar números tan grandes como RSA1024. Vamos a factorizar un número pequeño para demostrar cómo funciona el algoritmo. Para esta demostración, utilizaremos una versión simplificada del código presentado en el tutorial del algoritmo de Shor. Si desea obtener más detalles, visite el tutorial.
Ejecutaremos el algoritmo utilizando nuestro marco estándar para resolver problemas cuánticos, denominado marco de patrones Qiskit. Esto consta de cuatro pasos:
- Asignación de su problema a un circuito cuántico
- Optimizar el circuito para que se ejecute en hardware cuántico
- Ejecuta tu circuito en el ordenador cuántico
- Procesar posteriormente las mediciones
1. Mapa
Factorizemos , seleccionando como nuestro entero coprimo.
En primer lugar, debemos construir el circuito que implementará la unidad de multiplicación modular. Esta es, en realidad, la parte más complicada de toda la implementación y puede requerir un gran esfuerzo computacional, dependiendo de cómo se haga. Para ello, haremos un poco de trampa: sabemos que estamos empezando en el estado , y por una pregunta anterior,
Por lo tanto, construiremos una unidad que realice las operaciones correctas en estos cuatro estados, pero que deje todos los demás estados tal cual. Esto es hacer trampa porque estamos utilizando nuestro conocimiento del orden de para simplificar el unitario. Si realmente estuviéramos tratando de factorizar un número cuyos factores nos fueran desconocidos, no podríamos hacerlo.
Comprueba tu comprensión
Con tu conocimiento de cómo el operador transforma los estados anteriores, construye el operador a partir de una serie de puertas SWAP, que intercambian los estados de dos qubits. (Pista: escribir cada estado en binario te ayudará)
Reescribamos la acción de sobre los estados en binario:
Cada una de estas acciones se puede realizar con un simple SWAP. se consigue intercambiando los estados de los qubits y . se consigue intercambiando los estados de los qubits y . Y así sucesivamente. Por lo tanto, podemos descomponer la matriz en la siguiente serie de puertas SWAP:
Recordando que los operadores actúan de derecha a izquierda, comprobemos que esto tiene el efecto que queremos en cada uno de los estados:
Ahora podemos codificar el circuito equivalente a este operador en Qiskit.
Primero, importamos los paquetes necesarios:
# Import necessary packages
import numpy as np
from fractions import Fraction
from math import floor, gcd, log
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.circuit.library import QFTGate
from qiskit.transpiler import generate_preset_pass_manager
from qiskit.visualization import plot_histogram
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import SamplerV2 as SamplerA continuación, creamos el operador:
def M2mod15():
"""
M2 (mod 15)
"""
b = 2
U = QuantumCircuit(4)
U.swap(2, 3)
U.swap(1, 2)
U.swap(0, 1)
U = U.to_gate()
U.name = f"M_{b}"
return U# Get the M2 operator
M2 = M2mod15()
# Add it to a circuit and plot
circ = QuantumCircuit(4)
circ.compose(M2, inplace=True)
circ.decompose(reps=2).draw(output="mpl", fold=-1)Output:
El algoritmo QPE utiliza una puerta controlada. Ahora que tenemos un circuito, necesitamos convertirlo en un circuito * controlado* :
def controlled_M2mod15():
"""
Controlled M2 (mod 15)
"""
b = 2
U = QuantumCircuit(4)
U.swap(2, 3)
U.swap(1, 2)
U.swap(0, 1)
U = U.to_gate()
U.name = f"M_{b}"
c_U = U.control()
return c_U# Get the controlled-M2 operator
controlled_M2 = controlled_M2mod15()
# Add it to a circuit and plot
circ = QuantumCircuit(5)
circ.compose(controlled_M2, inplace=True)
circ.decompose(reps=1).draw(output="mpl", fold=-1)Output:
Ahora tenemos nuestra puerta controlada. Pero para ejecutar el algoritmo de estimación de fase cuántica, necesitaremos controlado , controlado , hasta controlado , donde es el número de qubits utilizados para estimar la fase. Cuantos más qubits, más precisa será la estimación de fase. Utilizaremos qubits de control para nuestro procedimiento de estimación de fase. Por lo tanto, necesitamos:
donde el índice , con , corresponde al qubit de control. Ahora calculemos para cada valor de :
def a2kmodN(a, k, N):
"""Compute a^{2^k} (mod N) by repeated squaring"""
for _ in range(k):
a = int(np.mod(a**2, N))
return ak_list = range(8)
b_list = [a2kmodN(2, k, 15) for k in k_list]
print(b_list)Output:
[2, 4, 1, 1, 1, 1, 1, 1]
Dado que para , todos los operadores correspondientes ( y superiores) son equivalentes a la identidad. Por lo tanto, solo necesitamos construir una matriz más,
Nota: Esta simplificación solo funciona aquí porque el orden de es . Una vez que (por lo tanto, ), cada potencia posterior del operador es la identidad. En general, para números más grandes o diferentes elecciones de , no se puede omitir la construcción de las potencias superiores. Esta es una de las razones por las que se considera un ejemplo simplificado : los números pequeños permiten atajos que no funcionarían en casos más grandes.
def M4mod15():
"""
M4 (mod 15)
"""
b = 4
U = QuantumCircuit(4)
U.swap(1, 3)
U.swap(0, 2)
U = U.to_gate()
U.name = f"M_{b}"
return U# Get the M4 operator
M4 = M4mod15()
# Add it to a circuit and plot
circ = QuantumCircuit(4)
circ.compose(M4, inplace=True)
circ.decompose(reps=2).draw(output="mpl", fold=-1)Output:
Y, como antes, lo convertimos en un operador * controlado* :
def controlled_M4mod15():
"""
Controlled M4 (mod 15)
"""
b = 4
U = QuantumCircuit(4)
U.swap(1, 3)
U.swap(0, 2)
U = U.to_gate()
U.name = f"M_{b}"
c_U = U.control()
return c_U# Get the controlled-M4 operator
controlled_M4 = controlled_M4mod15()
# Add it to a circuit and plot
circ = QuantumCircuit(5)
circ.compose(controlled_M4, inplace=True)
circ.decompose(reps=1).draw(output="mpl", fold=-1)Output:
Ahora, podemos juntarlo todo para encontrar el orden de con un circuito cuántico, utilizando la estimación de fase:
# Order finding problem for N = 15 with a = 2
N = 15
a = 2
# Number of qubits
num_target = floor(log(N - 1, 2)) + 1 # for modular exponentiation operators
num_control = 2 * num_target # for enough precision of estimation
# List of M_b operators in order
k_list = range(num_control)
b_list = [a2kmodN(2, k, 15) for k in k_list]
# Initialize the circuit
control = QuantumRegister(num_control, name="C")
target = QuantumRegister(num_target, name="T")
output = ClassicalRegister(num_control, name="out")
circuit = QuantumCircuit(control, target, output)
# Initialize the target register to the state |1>
circuit.x(num_control)
# Add the Hadamard gates and controlled versions of the
# multiplication gates
for k, qubit in enumerate(control):
circuit.h(k)
b = b_list[k]
if b == 2:
circuit.compose(
M2mod15().control(), qubits=[qubit] + list(target), inplace=True
)
elif b == 4:
circuit.compose(
M4mod15().control(), qubits=[qubit] + list(target), inplace=True
)
else:
continue # M1 is the identity operator
# Apply the inverse QFT to the control register
circuit.compose(QFTGate(num_control).inverse(), qubits=control, inplace=True)
# Measure the control register
circuit.measure(control, output)
circuit.draw("mpl", fold=-1)Output:
2. Optimizar
Ahora que hemos mapeado nuestro circuito, el siguiente paso es optimizarlo para que se ejecute en un ordenador cuántico concreto. Primero tenemos que cargar el backend.
service = QiskitRuntimeService()
backend = service.backend("ibm_marrakesh")Si no dispone de tiempo en su cuenta o desea utilizar un simulador por cualquier motivo, puede ejecutar la celda siguiente para configurar un simulador que imitará el dispositivo cuántico que hemos seleccionado anteriormente:
pm = generate_preset_pass_manager(optimization_level=2, backend=backend)
transpiled_circuit = pm.run(circuit)
print(f"2q-depth: {transpiled_circuit.depth(lambda x: x.operation.num_qubits==2)}")
print(f"2q-size: {transpiled_circuit.size(lambda x: x.operation.num_qubits==2)}")
print(f"Operator counts: {transpiled_circuit.count_ops()}")
transpiled_circuit.draw(output="mpl", fold=-1, style="clifford", idle_wires=False)Output:
2q-depth: 188
2q-size: 281
Operator counts: OrderedDict({'sx': 548, 'rz': 380, 'cz': 281, 'measure': 8, 'x': 6})
3. Ejecutar
# Sampler primitive to obtain the probability distribution
sampler = Sampler(backend)
# Turn on dynamical decoupling with sequence XpXm
sampler.options.dynamical_decoupling.enable = True
sampler.options.dynamical_decoupling.sequence_type = "XpXm"
# Enable gate twirling
sampler.options.twirling.enable_gates = True
pub = transpiled_circuit
job = sampler.run([pub], shots=1024)result = job.result()[0]
counts = result.data["out"].get_counts()plot_histogram(counts, figsize=(35, 5))Output:
Vemos cuatro picos claros en 00000000, 01000000, 10000000 y 11000000, con algunos recuentos en otras cadenas de bits debido al ruido en el ordenador cuántico. Ignoraremos estos y mantendremos solo los cuatro dominantes imponiendo un umbral: solo los recuentos por encima de este umbral se consideran una señal verdadera por encima del ruido.
# Dictionary of bitstrings and their counts to keep
counts_keep = {}
# Threshold to filter
threshold = np.max(list(counts.values())) / 2
for key, value in counts.items():
if value > threshold:
counts_keep[key] = value
print(counts_keep)4. Postprocesamiento
En el caso del algoritmo de Shor, gran parte del algoritmo se ejecuta de forma clásica. Por lo tanto, pondremos el resto en el paso de «posprocesamiento», después de haber obtenido nuestras mediciones del ordenador cuántico. Cada una de las mediciones anteriores se puede convertir en números enteros que, tras dividirlos por , son nuestras aproximaciones para , donde es aleatorio cada vez.
a = 2
N = 15
FACTOR_FOUND = False
num_attempt = 0
while not FACTOR_FOUND:
print(f"\nATTEMPT {num_attempt}:")
# Here, we get the bitstring by iterating over outcomes
# of a previous hardware run with multiple shots.
# Instead, we can also perform a single-shot measurement
# here in the loop.
bitstring = list(counts_keep.keys())[num_attempt]
num_attempt += 1
# Find the phase from measurement
decimal = int(bitstring, 2)
phase = decimal / (2**num_control) # phase = k / r
print(f"Phase: theta = {phase}")
# Guess the order from phase
frac = Fraction(phase).limit_denominator(N)
r = frac.denominator # order = r
print(f"Order of {a} modulo {N} estimated as: r = {r}")
if phase != 0:
# Guesses for factors are gcd(a^{r / 2} ± 1, 15)
if r % 2 == 0:
x = pow(a, r // 2, N) - 1
d = gcd(x, N)
if d > 1:
FACTOR_FOUND = True
print(f"*** Non-trivial factor found: {x} ***")Output:
ATTEMPT 0:
Phase: theta = 0.0
Order of 2 modulo 15 estimated as: r = 1
ATTEMPT 1:
Phase: theta = 0.75
Order of 2 modulo 15 estimated as: r = 4
*** Non-trivial factor found: 3 ***
Conclusión
Después de completar el módulo, es posible que te sorprenda una nueva apreciación de la genialidad de Peter Shor al haber ideado un algoritmo tan inteligente. Pero esperamos que también hayas alcanzado un nuevo nivel de comprensión de su engañosa simplicidad. Aunque el algoritmo pueda parecer impresionantemente (o intimidantemente) complejo, si lo desglosas en cada paso lógico y lo sigues lentamente, tú también podrás ejecutar el algoritmo de Shor.
Aunque aún estamos lejos de utilizar este algoritmo para factorizar números como RSA1024, nuestros ordenadores cuánticos mejoran cada día y, una vez que se alcance un umbral denominado «tolerancia a fallos», algoritmos como estos no tardarán en llegar. ¡Es un momento emocionante para aprender sobre la computación cuántica!
Problemas
Conceptos fundamentales:
- Los sistemas criptográficos modernos se basan en la dificultad clásica de factorizar números enteros grandes.
- La aritmética modular —incluidas las estructuras y — proporciona la base matemática para el algoritmo de Shor.
- El problema de factorizar un número entero puede reducirse al problema de hallar el orden de un número módulo .
- La búsqueda de orden cuántico utiliza técnicas de estimación de fase cuántica para determinar el periodo de la función .
- El algoritmo de Shor consiste en un flujo de trabajo híbrido clásico-cuántico que selecciona una base, realiza la búsqueda del orden cuántico y, a continuación, calcula de forma clásica los factores a partir del resultado.
Verdadero/Falso:
- V/F La eficiencia del algoritmo de Shor amenaza la seguridad del cifrado RSA.
- V/F El algoritmo de Shor se puede ejecutar de manera eficiente en cualquier ordenador cuántico moderno.
- El algoritmo de T/F Shor utiliza la estimación de fase cuántica (QPE) como subrutina clave.
- V/F La parte clásica del algoritmo de Shor implica calcular el máximo común divisor (MCD).
- V/F El algoritmo de Shor solo funciona para factorizar números pares.
- V/F Una ejecución correcta del algoritmo de Shor siempre garantiza los factores correctos.
Respuesta breve:
- ¿Por qué se considera que el algoritmo de Shor es una amenaza potencial futura para el cifrado RSA?
- ¿Por qué es útil encontrar el período, o orden, de una función exponencial modular para factorizar un número en el algoritmo de Shor?
Problemas desafiantes:
-
¿Cuántos qubits de control necesitamos para un número dado que estamos tratando de factorizar para obtener la precisión en el QPE necesaria para encontrar el valor correcto del orden ?
-
Siguiendo el procedimiento que hemos descrito aquí para factorizar 15, ahora intenta factorizar 21.