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()