LoginSignup
3
1

More than 3 years have passed since last update.

100マス量子回路計算やってみよう〜中級編〜

Last updated at Posted at 2019-12-17

大好評だった初級編に引き続き、中級編もやってみましょう。
今回、2量子ビットに増えて、CNOTゲートが加わりました。

それに伴い、状態の数がめちゃくちゃに増えました。
|0>, |1>, |+>, |->, |i>, |-i>の直積で書けるものや、4つのベル状態

|\Phi_+>=(|00>+|11>)/ \sqrt{2}
|\Phi_->=(|00>-|11>)/ \sqrt{2}
|\Psi_+>=(|01>+|10>)/ \sqrt{2}
|\Psi_->=(|01>-|10>)/ \sqrt{2}

で書けるものもありますが、位相が違っていてそのような書き方ができないものも多数出来ました。

なので、今回は、直積やベル状態で書くか、1/√2|00> - 1/√2|10>のように書くか、各状態の成分を書くかのいずれかで回答してください。
また、1/2と1/√2は省略してもいいものとします。

暗算でやるのはかなり難しいと思いますが、がんばってみてください。

100マス量子計算中級編

100マス量子計算中級編.png

答え

今回は、左列から順に縦方向で答えを表示しています。

from cmath import phase
from math import pi
import math
import numpy as np
from blueqat import Circuit

# 中級編
tate = [
    Circuit().h[0].cx[0, 1],
    Circuit().h[0].cx[0, 1].h[1],
    Circuit().x[0].h[0].cx[0, 1],
    Circuit().h[0, 1],
    Circuit().x[0].h[1],
    Circuit().h[:].s[0].sdg[1],
    Circuit().h[0].sdg[0].y[1],
    Circuit().h[0].cx[0, 1].s[1],
    Circuit().h[0].cx[0, 1].y[0],
    Circuit().h[0].cx[0, 1].y[:],
]

yoko = [
    Circuit().h[0].cx[0, 1],
    Circuit().cx[1, 0].h[1],
    Circuit().y[0, 1],
    Circuit().s[1].cx[0, 1].h[1],
    Circuit().h[:].s[0].sdg[1],
    Circuit().z[1].cx[1, 0].h[1],
    Circuit().x[0].z[1].cx[0, 1].h[0],
    Circuit().h[0].cx[0, 1].y[0],
    Circuit().h[0].cx[0, 1].s[1],
    Circuit().cx[0, 1].cx[1, 0],
]

states = [
    (np.array([1, 0], dtype=complex), '|0>'),
    (np.array([0, 1], dtype=complex), '|1>'),
    (np.array([1, 1], dtype=complex) / np.sqrt(2), '|+>'),
    (np.array([1, -1], dtype=complex) / np.sqrt(2), '|->'),
    (np.array([1, 1j], dtype=complex) / np.sqrt(2), '|i>'),
    (np.array([1, -1j], dtype=complex) / np.sqrt(2), '|-i>'),
]
sqrt2_inv = 1/2**0.5

def to_str(val, label, is_firstterm):
    val_abs = abs(val)

    if abs(val_abs) < 1e-5:
        return '' # Zero
    if abs(val_abs - 1) < 1e-5:
        val_s = ''
    elif abs(val_abs - sqrt2_inv) < 1e-5:
        val_s = '/√2'
    elif abs(val_abs - 0.5) < 1e-5:
        val_s = '/2'
    else:
        raise ValueError('Strange value. val = ', val)

    if is_firstterm:
        sign = ''
    else:
        sign = '+'
    imag = '1' # if real '1' else 'i'
    val_phase = phase(val)
    if abs(val_phase) < 1e-5:
        pass
    elif abs(val_phase - 0.5 * pi) < 1e-5:
        imag = 'i'
    elif abs(val_phase + 0.5 * pi) < 1e-5:
        sign = '-'
        imag = 'i'
    elif abs(val_phase - pi) < 1e-5 or abs(val_phase + pi) < 1e-5:
        sign = '-'
    else:
        raise ValueError('Strange phase. val = ', val)

    if imag == '1' and val_s == '':
        imag = ''
    if is_firstterm:
        return sign + imag + val_s + '|' + label + '>'
    return sign + ' ' + imag + val_s + '|' + label + '>'



def to_phasearr(state):
    zeros = np.isclose(state, 0.j)
    factor = math.sqrt(4 - sum(zeros))

    def to_phase(val, is_zero):
        if is_zero:
            return 0
        if np.isclose(val * factor, 1):
            return 1
        if np.isclose(val * factor, -1):
            return -1
        if np.isclose(val * factor, 1j):
            return 1j
        if np.isclose(val * factor, -1j):
            return -1j
        raise ValueError(f'val: {val}')

    return [to_phase(val, zero) for val, zero in zip(state, zeros)]


def check_bell(state):
    if np.allclose(state, np.array([sqrt2_inv, 0, 0, sqrt2_inv])):
        return '|Φ+>'
    if np.allclose(state, np.array([sqrt2_inv, 0, 0, -sqrt2_inv])):
        return '|Φ->'
    if np.allclose(state, np.array([0, sqrt2_inv, sqrt2_inv, 0])):
        return '|ψ+>'
    if np.allclose(state, np.array([0, sqrt2_inv, -sqrt2_inv, 0])):
        return '|ψ->'
    return None

single = {
        '|0>': np.array([1, 0], dtype=complex),
        '|1>': np.array([0, 1], dtype=complex),
        '|+>': np.array([sqrt2_inv, sqrt2_inv], dtype=complex),
        '|->': np.array([sqrt2_inv, -sqrt2_inv], dtype=complex),
        '|i>': np.array([sqrt2_inv, 1j * sqrt2_inv], dtype=complex),
        '|-i>': np.array([sqrt2_inv, -1j * sqrt2_inv], dtype=complex)
}
double = {k2 + k1: np.kron(s1, s2) for k1, s1 in single.items() for k2, s2 in single.items()}

def check_kron(state):
    for k, v in double.items():
        if np.allclose(state, v):
            return k
    return None

def get_answer(c1, c2):
    state = (c1.copy() + c2).run(ignore_global=True)
    bell = check_bell(state)
    kron = check_kron(state)
    ss = []
    for val, label in zip(state, ['00', '10', '01', '11']):
        s = to_str(val, label, not ss)
        if s:
            ss.append(s)
    s = ' '.join(ss)
    if bell:
        s = bell + '\t= ' + s
    elif len(ss) > 1 and kron:
        s = kron + '\t= ' + s
    return s

for c1 in yoko:
    for c2 in tate:
        print(get_answer(c2, c1))
    print('')

上級編?

量子ビット増やすとか、ゲート増やすとか、いくらでも難しくしようはあるんですが、ぶっちゃけこれ以上いりますかね……

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1