大好評だった初級編に引き続き、中級編もやってみましょう。
今回、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マス量子計算中級編
答え
今回は、左列から順に縦方向で答えを表示しています。
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('')
上級編?
量子ビット増やすとか、ゲート増やすとか、いくらでも難しくしようはあるんですが、ぶっちゃけこれ以上いりますかね……