This commit is contained in:
2025-12-28 15:16:22 +03:00
parent 7c58e681b2
commit b1e6ef4e6b

280
task11/shor9.py Normal file
View 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()