Повторить квантовую факторизацию15
Авторская ячейка повторяет алгоритм, пока не найден нетривиальный делитель 15. Несколько раз запустите её, чтобы посмотреть, как меняется поведение.
В программе a=7. Каждый опыт получает одну оценку фазы s/r квантовым поиском периода, переводит её в дробь со знаменателем не более 15 и пробует делители $\gcd(7^{r/2}-1,15)$ и $\gcd(7^{r/2}+1,15)$. Сохраняется исходный целочисленный r//2, проверка найденного делителя и весь цикл; исходная программа приведена полностью.
Original complete repeated experiment:
# pylint: disable=invalid-name
import matplotlib.pyplot as plt
import numpy as np
from qiskit import QuantumCircuit, Aer, transpile
from qiskit.visualization import plot_histogram
from math import gcd
from numpy.random import randint
import pandas as pd
from fractions import Fraction
print("Imports Successful")
def c_amod15(a, power):
"""Controlled multiplication by a mod 15"""
if a not in [2,4,7,8,11,13]:
raise ValueError("'a' must be 2,4,7,8,11 or 13")
U = QuantumCircuit(4)
for _iteration in range(power):
if a in [2,13]:
U.swap(2,3)
U.swap(1,2)
U.swap(0,1)
if a in [7,8]:
U.swap(0,1)
U.swap(1,2)
U.swap(2,3)
if a in [4, 11]:
U.swap(1,3)
U.swap(0,2)
if a in [7,11,13]:
for q in range(4):
U.x(q)
U = U.to_gate()
U.name = f"{a}^{power} mod 15"
c_U = U.control()
return c_U
def qft_dagger(n):
"""n-qubit QFTdagger the first n qubits in circ"""
qc = QuantumCircuit(n)
# Don't forget the Swaps!
for qubit in range(n//2):
qc.swap(qubit, n-qubit-1)
for j in range(n):
for m in range(j):
qc.cp(-np.pi/float(2**(j-m)), m, j)
qc.h(j)
qc.name = "QFT†"
return qc
N = 15
def qpe_amod15(a):
"""Performs quantum phase estimation on the operation a*r mod 15.
Args:
a (int): This is 'a' in a*r mod 15
Returns:
float: Estimate of the phase
"""
N_COUNT = 8
qc = QuantumCircuit(4+N_COUNT, N_COUNT)
for q in range(N_COUNT):
qc.h(q) # Initialize counting qubits in state |+>
qc.x(N_COUNT) # And auxiliary register in state |1>
for q in range(N_COUNT): # Do controlled-U operations
qc.append(c_amod15(a, 2**q),
[q] + [i+N_COUNT for i in range(4)])
qc.append(qft_dagger(N_COUNT), range(N_COUNT)) # Do inverse-QFT
qc.measure(range(N_COUNT), range(N_COUNT))
# Simulate Results
aer_sim = Aer.get_backend('aer_simulator')
# `memory=True` tells the backend to save each measurement in a list
job = aer_sim.run(transpile(qc, aer_sim), shots=1, memory=True)
readings = job.result().get_memory()
print("Register Reading: " + readings[0])
phase = int(readings[0],2)/(2**N_COUNT)
print(f"Corresponding Phase: {phase}")
return phase
a = 7
FACTOR_FOUND = False
ATTEMPT = 0
while not FACTOR_FOUND:
ATTEMPT += 1
print(f"\nATTEMPT {ATTEMPT}:")
phase = qpe_amod15(a) # Phase = s/r
frac = Fraction(phase).limit_denominator(N)
r = frac.denominator
print(f"Result: r = {r}")
if phase != 0:
# Guesses for factors are gcd(x^{r/2} ±1 , 15)
guesses = [gcd(a**(r//2)-1, N), gcd(a**(r//2)+1, N)]
print(f"Guessed Factors: {guesses[0]} and {guesses[1]}")
for guess in guesses:
if guess not in [1,N] and (N % guess) == 0:
# Guess is a factor!
print(f"*** Non-trivial factor found: {guess} ***")
FACTOR_FOUND = True