Shor9.py
This commit is contained in:
280
task11/shor9.py
Normal file
280
task11/shor9.py
Normal file
@@ -0,0 +1,280 @@
|
||||
import concurrent.futures
|
||||
import random
|
||||
from typing import List, Tuple
|
||||
|
||||
import cirq
|
||||
import numpy as np
|
||||
|
||||
|
||||
def build_shor9_circuit(
|
||||
p_error: float, with_correction: bool = True
|
||||
) -> Tuple[cirq.Circuit, List[cirq.Qid]]:
|
||||
"""Построение схемы кода Шора на 9 кубитах."""
|
||||
qubits = [cirq.LineQubit(i) for i in range(9)]
|
||||
circuit = cirq.Circuit()
|
||||
|
||||
# Подготовка исходного состояния логического кубита
|
||||
circuit.append(cirq.rx(np.pi / 5)(qubits[0]))
|
||||
|
||||
# ----- Блок кодирования -----
|
||||
# S1: CNOT 0->3
|
||||
circuit.append(cirq.CNOT(qubits[0], qubits[3]))
|
||||
# S2: CNOT 0->6
|
||||
circuit.append(cirq.CNOT(qubits[0], qubits[6]))
|
||||
# S3: H на 0, 3, 6
|
||||
circuit.append(cirq.H.on_each(qubits[0], qubits[3], qubits[6]))
|
||||
# S4: CNOT внутри блоков
|
||||
circuit.append(cirq.CNOT(qubits[0], qubits[1]))
|
||||
circuit.append(cirq.CNOT(qubits[3], qubits[4]))
|
||||
circuit.append(cirq.CNOT(qubits[6], qubits[7]))
|
||||
# S5: еще CNOT внутри блоков
|
||||
circuit.append(cirq.CNOT(qubits[0], qubits[2]))
|
||||
circuit.append(cirq.CNOT(qubits[3], qubits[5]))
|
||||
circuit.append(cirq.CNOT(qubits[6], qubits[8]))
|
||||
|
||||
# ----- Блок шума -----
|
||||
# ВАЖНО: как в оригинале - по одному кубиту проверяем вероятность ошибки
|
||||
error_count = 0
|
||||
error_idx = None
|
||||
error_type = None
|
||||
|
||||
for idx in range(9):
|
||||
if random.random() <= p_error:
|
||||
error_count += 1
|
||||
if error_count > 1:
|
||||
break # Более одной ошибки - сразу неудача
|
||||
error_idx = idx
|
||||
error_type = "X" if random.random() > 0.5 else "Z"
|
||||
|
||||
if error_count == 1:
|
||||
if error_type == "X":
|
||||
circuit.append(cirq.X(qubits[error_idx]))
|
||||
else:
|
||||
circuit.append(cirq.Z(qubits[error_idx]))
|
||||
|
||||
# ----- Блок декодирования и коррекции -----
|
||||
if with_correction and error_count <= 1:
|
||||
# S6: обратное S4
|
||||
circuit.append(cirq.CNOT(qubits[0], qubits[1]))
|
||||
circuit.append(cirq.CNOT(qubits[3], qubits[4]))
|
||||
circuit.append(cirq.CNOT(qubits[6], qubits[7]))
|
||||
# S7: обратное S5
|
||||
circuit.append(cirq.CNOT(qubits[0], qubits[2]))
|
||||
circuit.append(cirq.CNOT(qubits[3], qubits[5]))
|
||||
circuit.append(cirq.CNOT(qubits[6], qubits[8]))
|
||||
# S8: Toffoli для коррекции
|
||||
circuit.append(cirq.TOFFOLI(qubits[1], qubits[2], qubits[0]))
|
||||
circuit.append(cirq.TOFFOLI(qubits[4], qubits[5], qubits[3]))
|
||||
circuit.append(cirq.TOFFOLI(qubits[7], qubits[8], qubits[6]))
|
||||
# S9: обратное S3
|
||||
circuit.append(cirq.H.on_each(qubits[0], qubits[3], qubits[6]))
|
||||
# S10: обратное S1
|
||||
circuit.append(cirq.CNOT(qubits[0], qubits[3]))
|
||||
# S11: обратное S2
|
||||
circuit.append(cirq.CNOT(qubits[0], qubits[6]))
|
||||
# S12: Toffoli между блоками
|
||||
circuit.append(cirq.TOFFOLI(qubits[3], qubits[6], qubits[0]))
|
||||
|
||||
return circuit, qubits, error_count
|
||||
|
||||
|
||||
def shor9(P: float = 0.05, debug: bool = False) -> Tuple[bool, int]:
|
||||
"""Один прогон кода Шора - точно как в оригинале."""
|
||||
simulator = cirq.Simulator()
|
||||
|
||||
# Сохраняем начальное состояние кубита 0
|
||||
# Создаем схему только с подготовкой состояния
|
||||
prep_circuit = cirq.Circuit(cirq.rx(np.pi / 5)(cirq.LineQubit(0)))
|
||||
prep_result = simulator.simulate(prep_circuit)
|
||||
|
||||
# Получаем начальные амплитуды
|
||||
initial_state = prep_result.final_state_vector
|
||||
initial_0 = np.abs(initial_state[0]) ** 2
|
||||
initial_1 = np.abs(initial_state[1]) ** 2
|
||||
|
||||
# Строим полную схему Шора
|
||||
circuit, qubits, error_count = build_shor9_circuit(P, with_correction=True)
|
||||
|
||||
# Если более одной ошибки - сразу неудача (как в оригинале)
|
||||
if error_count > 1:
|
||||
return False, error_count
|
||||
|
||||
result = simulator.simulate(circuit)
|
||||
final_state = result.final_state_vector
|
||||
|
||||
# Получаем амплитуды для кубита 0
|
||||
# Вектор состояния имеет размер 2^9 = 512
|
||||
# Индексы где q0=0: 0-255, где q0=1: 256-511
|
||||
|
||||
prob_0 = 0.0
|
||||
prob_1 = 0.0
|
||||
|
||||
for i in range(512):
|
||||
amp = final_state[i]
|
||||
prob = np.abs(amp) ** 2
|
||||
if i < 256: # q0 = 0
|
||||
prob_0 += prob
|
||||
else: # q0 = 1
|
||||
prob_1 += prob
|
||||
|
||||
# Проверяем как в оригинале: np.isclose с tolerance 0.01
|
||||
success = np.isclose(prob_0, initial_0, atol=0.01) and np.isclose(
|
||||
prob_1, initial_1, atol=0.01
|
||||
)
|
||||
|
||||
return success, error_count
|
||||
|
||||
|
||||
def no_correction(P: float = 0.05, debug: bool = False) -> Tuple[bool, int]:
|
||||
"""Модель без коррекции ошибок - точно как в оригинале."""
|
||||
q = cirq.LineQubit(0)
|
||||
|
||||
# Сохраняем начальное состояние
|
||||
prep_circuit = cirq.Circuit(cirq.rx(np.pi / 5)(q))
|
||||
simulator = cirq.Simulator()
|
||||
prep_result = simulator.simulate(prep_circuit)
|
||||
initial_state = prep_result.final_state_vector
|
||||
initial_0 = np.abs(initial_state[0]) ** 2
|
||||
initial_1 = np.abs(initial_state[1]) ** 2
|
||||
|
||||
# Создаем схему с возможной ошибкой
|
||||
circuit = cirq.Circuit(cirq.rx(np.pi / 5)(q))
|
||||
|
||||
# Применяем ошибку с вероятностью P
|
||||
error_count = 0
|
||||
if random.random() <= P:
|
||||
error_count += 1
|
||||
circuit.append(cirq.X(q))
|
||||
|
||||
result = simulator.simulate(circuit)
|
||||
final_state = result.final_state_vector
|
||||
|
||||
final_0 = np.abs(final_state[0]) ** 2
|
||||
final_1 = np.abs(final_state[1]) ** 2
|
||||
|
||||
# Проверяем как в оригинале, но с tolerance 0.0001
|
||||
success = np.isclose(final_0, initial_0, atol=0.0001) and np.isclose(
|
||||
final_1, initial_1, atol=0.0001
|
||||
)
|
||||
|
||||
return success, error_count
|
||||
|
||||
|
||||
def compute_failure_probability(
|
||||
P: float, total_rounds: int = 500
|
||||
) -> Tuple[float, float, float]:
|
||||
"""Оценка вероятности сбоя для заданного P - точно как в оригинале."""
|
||||
failure_count = 0
|
||||
|
||||
# Если P == 0, то вероятность ошибки = 0 (как в оригинале)
|
||||
if P == 0:
|
||||
return P, 0.0, 0.0
|
||||
|
||||
for _ in range(total_rounds):
|
||||
correct, _ = shor9(P=P)
|
||||
if not correct:
|
||||
failure_count += 1
|
||||
|
||||
p_e = failure_count / total_rounds
|
||||
p_e_nc = P # Как в оригинале: для схемы без коррекции вероятность ошибки = P
|
||||
|
||||
return P, p_e, p_e_nc
|
||||
|
||||
|
||||
def parallel_compute_failure_probability(
|
||||
p_values: List[float], total_rounds: int = 500
|
||||
):
|
||||
"""Параллельный запуск оценки."""
|
||||
results = []
|
||||
with concurrent.futures.ProcessPoolExecutor() as executor:
|
||||
results = list(
|
||||
executor.map(
|
||||
compute_failure_probability, p_values, [total_rounds] * len(p_values)
|
||||
)
|
||||
)
|
||||
return results
|
||||
|
||||
|
||||
def theory(p: float) -> float:
|
||||
"""Теоретическая оценка вероятности ошибки для кода Шора."""
|
||||
return 1 - (1 + 8 * p) * (1 - p) ** 8
|
||||
|
||||
|
||||
def shor9_withplot():
|
||||
"""Построение графика."""
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
p = [0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1]
|
||||
p_e = []
|
||||
p_e_nc = []
|
||||
total_rounds = 100
|
||||
|
||||
print("Запуск моделирования...")
|
||||
results = parallel_compute_failure_probability(p, total_rounds)
|
||||
|
||||
for P, p_e_value, p_e_nc_value in results:
|
||||
p_e.append(p_e_value)
|
||||
p_e_nc.append(p_e_nc_value)
|
||||
print(f"P={P:.2f}: P_e={p_e_value:.4f} || P_e_nc={p_e_nc_value:.4f}")
|
||||
|
||||
# Построение графика
|
||||
plt.figure(figsize=(10, 6))
|
||||
|
||||
# Экспериментальные данные
|
||||
plt.plot(
|
||||
p,
|
||||
p_e,
|
||||
marker="o",
|
||||
label="С коррекцией (Шор)",
|
||||
linestyle="-",
|
||||
color="b",
|
||||
alpha=0.7,
|
||||
)
|
||||
plt.plot(
|
||||
p,
|
||||
p_e_nc,
|
||||
marker="s",
|
||||
label="Без коррекции",
|
||||
linestyle="-",
|
||||
color="r",
|
||||
alpha=0.7,
|
||||
)
|
||||
|
||||
# Теоретическая кривая
|
||||
p_values = np.linspace(0, max(p), 100)
|
||||
theory_values = [theory(x) for x in p_values]
|
||||
plt.plot(
|
||||
p_values,
|
||||
theory_values,
|
||||
label="Теория (Шор)",
|
||||
color="green",
|
||||
linestyle="--",
|
||||
linewidth=2.0,
|
||||
)
|
||||
|
||||
plt.xlabel("Вероятность ошибки P")
|
||||
plt.ylabel("Вероятность логической ошибки P_e")
|
||||
plt.title("Зависимость вероятности ошибки от P")
|
||||
plt.grid(True, alpha=0.3)
|
||||
plt.legend()
|
||||
plt.tight_layout()
|
||||
|
||||
# Сохраняем график
|
||||
plt.savefig("shor_code_cirq.pdf", format="pdf", bbox_inches="tight")
|
||||
plt.show()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Быстрый тест
|
||||
print("Тестирование кода Шора...")
|
||||
for P_test in [0, 0.05, 0.1]:
|
||||
success, errors = shor9(P=P_test)
|
||||
print(f"P={P_test:.2f}: Успех={success}, Ошибок={errors}")
|
||||
|
||||
print("\nТестирование без коррекции...")
|
||||
for P_test in [0, 0.05, 0.1]:
|
||||
success, errors = no_correction(P=P_test)
|
||||
print(f"P={P_test:.2f}: Успех={success}, Ошибок={errors}")
|
||||
|
||||
# Основное моделирование
|
||||
shor9_withplot()
|
||||
Reference in New Issue
Block a user