№ 1991Основания квантовой механикиУровень 3

Подготовить квантовые корреляции для проверки Белла

Подготовьте два кубита так, чтобы их X-выходы с большей вероятностью различались, а все остальные сочетания X/Z-выходов с большей вероятностью совпадали.

Исходное состояние —00. В вызове автора заданы целевые средние ZZ=ZX=XZ=0.7071, XX=−0.7071. Разрешены X,Z,H,CNOT и Ry(±π/4) на любом кубите, симметричный CZ, а также изменения изображения bloch/unbloch; количества не ограничены.

Здесь H-тип чтения означает X-измерение, V-тип — Z-измерение. P[HH],P[HV],P[VH],P[VV] — вероятности различия битов при этих сочетаниях. После подготовки исходная программа оценивает их по 8192 запускам и сравнивает каждую с суммой остальных. Игрок может следовать предложенной цели или исследовать другую подготовку, но заданный Exercise требует именно указанных корреляций.

Здесь q0 — левый кубит игрового поля, q1 — правый. В формулах этой задачи порядок множителей — q0,q1; исходный Qiskit при печати двоичных строк использует обратный порядок.

X- и Z-выходы означают результаты соответствующих измерений с битовыми значениями 0 или 1. Для состояний $|\pm\rangle=(|0\rangle\pm|1\rangle)/\sqrt2$ X-выход достоверно равен 0 или 1 соответственно. В круглой визуализации чёрный круг — достоверный 0, белый — достоверная 1, серый — равные вероятности; промежуточные оттенки передают промежуточные вероятности. В линейной визуализации белая линия означает 0, чёрная —1; bloch только объединяет линии в изображение, состояние кубита не меняет.

Двухбуквенные обозначения описывают средние значения измерений: первая буква относится к q0, вторая — к q1; I означает, что этот кубит не измеряется. Например, ZI — Z-выход q0, IX — X-выход q1, XZ — их совместная корреляция. Для одного выхода значение p даёт вероятность 1, равную (1−p)/2. Для корреляции оно даёт такую же вероятность различия двух битов. Поэтому+1 означает достоверный 0 или согласие, −1 — достоверную 1 или различие,0 — равные вероятности.

Действия вентилей заданы однозначно: X инвертирует Z-выход, Z инвертирует X-выход, H меняет X- и Z-выходы местами. На векторах состояния:

$$X=\begin{bmatrix}0&1\\1&0\end{bmatrix},\quad Z=\begin{bmatrix}1&0\\0&-1\end{bmatrix},\quad H=\frac1{\sqrt2}\begin{bmatrix}1&1\\1&-1\end{bmatrix}.$$

$$R_y(\theta)=\begin{bmatrix}\cos(\theta/2)&-\sin(\theta/2)\\\sin(\theta/2)&\cos(\theta/2)\end{bmatrix}.$$

CNOT применяет X к цели при управляющем 1, CZ применяет Z при управляющем 1; на суперпозициях эти действия продолжаются линейно.

Все ограничения на число ходов указаны ниже: положительное число требует ровно столько применений,0 в исходном allowed_gates означает любое число. Неуказанные операции запрещены. CNOT в игровом вызове принимает выбранный целевой кубит; второй кубит управляет. CZ симметричен, но отдельные ограничения на его кнопки сохраняются. Исходная проверка принимает отклонение каждого среднего от заданного значения меньше 0.1.

Полная исходная программа проверки:

print('Set up started...')
from qiskit_textbook.games import hello_quantum
print('Set up complete!')

def bell_test (P):
    
    sum_P = sum(P.values())
    for hashes in P:
        
        bound = sum_P - P[hashes]
        
        print("The upper bound for P['"+hashes+"'] is "+str(bound))
        print("The value of P['"+hashes+"'] is "+str(P[hashes]))
        if P[hashes]<=bound:
            print("The upper bound is obeyed :)\n")
        else:
            if P[hashes]-bound < 0.1:
                print("This seems to have gone over the upper bound, but only by a little bit :S\nProbably just rounding errors or statistical noise.\n")
            else:
                print("!!!!! This has gone well over the upper bound :O !!!!!\n")

from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit

def initialize_program ():
    
    qubit = QuantumRegister(2)
    A = qubit[0]
    B = qubit[1]
    
    bit = ClassicalRegister(2)
    a = bit[0]
    b = bit[1]
    
    qc = QuantumCircuit(qubit, bit)
    
    return A, B, a, b, qc

def hash2bit  ( variable, hash, bit, qc ):
    
    if hash=='H':
        qc.h( variable )
        
    qc.measure( variable, bit )

initialize = []
success_condition = {'ZZ':+0.7071,'ZX':+0.7071,'XZ':+0.7071,'XX':-0.7071}
allowed_gates = {'0': {'bloch':0, 'x':0, 'z':0, 'h':0, 'cx':0, 'ry(pi/4)': 0, 'ry(-pi/4)': 0}, '1': {'bloch':0, 'x':0, 'z':0, 'h':0, 'cx':0, 'ry(pi/4)': 0, 'ry(-pi/4)': 0}, 'both': {'cz':0, 'unbloch':0}}
vi = [[], True, True]
qubit_names = {'0':'A', '1':'B'}
puzzle = hello_quantum.run_game(initialize, success_condition, allowed_gates, vi, qubit_names, mode='line')

import numpy as np
def setup_variables ( A, B, qc ):
    
    for line in puzzle.program:
        eval(line)

shots = 8192
from qiskit import assemble, transpile

def calculate_P ( backend ):
    
    P = {}
    program = {}
    for hashes in ['VV','VH','HV','HH']:

        A, B, a, b, program[hashes] = initialize_program ()

        setup_variables( A, B, program[hashes] )

        hash2bit ( A, hashes[0], a, program[hashes])
        hash2bit ( B, hashes[1], b, program[hashes])
            
    # submit jobs
    t_qcs = transpile(list(program.values()), backend)
    qobj = assemble(t_qcs, shots=shots)
    job = backend.run(qobj)

    # get the results
    for hashes in ['VV','VH','HV','HH']:
        stats = job.result().get_counts(program[hashes])
        
        P[hashes] = 0
        for string in stats.keys():
            a = string[-1]
            b = string[-2]
            
            if a!=b:
                P[hashes] += stats[string] / shots

    return P

from qiskit import Aer
device = 'aer_simulator'
backend = Aer.get_backend(device)

P = calculate_P( backend )
print(P)

bell_test( P )