Demo Play

ここではPItBEを用いてBlock-Encoding法を実行する際の手順を紹介する。
本モジュールを用いる際には一読することを推奨する。

計算条件

  • 量子回路上で再現したい行列 粒子6個の系に対する横磁場イジングモデルのハミルトニアン\(\hat{H}\)

    \[\hat{H} = 0.5\sum_i^{6}\hat{Z}_i\hat{Z}_{i+1} + 0.8\sum_i^{6}\hat{X}_i\]
  • 行列を作用させたい量子状態 スピンが\(+z\)方向にそろった系

    \[|\psi\rangle = |000000\rangle\]

実行

実行に向けての準備

初めに補助ビット部分の量子状態を決定する行列を作成する。
理想としてはPauli回転ゲートの積によって表現したいが、任意の状態を生成するPauli回転ゲートの積を作成する方法は現状提案されていない。
そのため今回は全て0の状態をとる補助ビットに対して作用させることで、任意の量子状態に変換させるユニタリゲートを用いることとする。
[1]:
import math
import numpy as np
import pitbe

# The coefficients and Pauli matrix production
# in the linear combination representation of the matrix to be Block-Encoded
coefficients = [0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8]
paulies = ['Z0Z1', 'Z1Z2', 'Z2Z3', 'Z3Z4', 'Z4Z5', 'Z5Z0',
           'X0', 'X1', 'X2', 'X3', 'X4', 'X5']

# Normalize coefficients
norm_cf = np.sum(np.abs(coefficients))
alphas = (np.sqrt(np.abs(coefficients)) / np.sqrt(np.sum(np.abs(coefficients))))
if math.floor(np.log2(len(alphas))) != np.log2(len(alphas)):
        zero_list = np.zeros(2**(math.floor(np.log2(len(alphas))) + 1) - len(alphas))
        alphas = np.append(alphas, zero_list)

# Creating a matrix for adjusting coefficient signs
opposite_list = np.ones(len(alphas))
for j in range(len(coefficients)):
    if (coefficients[j] < 0):
        opposite_list[j] = -1

# Creating a matrix for adjusting ancilla qubits
cf = pitbe.coeff_make(alphas)
mat_for_anci = pitbe.mat_maker(alphas, cf)

量子回路の作成

次にBlock-Encoding法を実行する量子回路を作成する。
量子回路の流れはBlock-Encoding法について説明したページを参照。
今回はQulacsをシュミレータとして選択して実行する。
[2]:
from qulacs import QuantumState, QuantumCircuit
from qulacs.state import inner_product
from qulacs.gate import X, Y, Z, DenseMatrix, H, CNOT, to_matrix_gate, CZ, RY, RZ, merge
from qulacs.observable import create_observable_from_openfermion_text
from qulacs.quantum_operator import create_quantum_operator_from_openfermion_file
from qulacs.quantum_operator import create_quantum_operator_from_openfermion_text
from qulacsvis import circuit_drawer

# Detect the number of main qubits and ancilla qubits
main = pitbe.total_search(paulies)
anci = int(np.log2(len(alphas)))

# Prepare the control qubit information
cont_list = []
for j in range(len(paulies)):
    cont_list.append(pitbe.cont_order(j, anci))

# Create quantum circuit and quantum state
total = anci + main
state = QuantumState(total)
state.set_zero_state()
circ = QuantumCircuit(total)

# Convert matrices into quantum gates
gate = DenseMatrix([j for j in range(anci)], mat_for_anci)
opp_gate = DenseMatrix([j for j in range(anci)], np.diag(opposite_list))
gate_dag = gate.get_inverse()

# Create quantum circuit
circ.add_gate(gate)
circ.add_gate(opp_gate)
for j in range(len(cont_list)):
    pitbe.circ_make(paulies[j], cont_list[j], circ, total, anci)
circ.add_gate(gate_dag)

量子回路の実行・結果の分析

最後に量子回路を実行し、結果を分析する。
具体的には実行結果から補助ビット部分の値が全て0のものを選び取り、係数を調節して出力する。
なおBlock-Encoding法について解説したページでも触れたように、実行後に得られるのはあくまでも再現した行列を作用させた量子状態についての情報であり、固有値が直接出力されるわけではない。
[3]:
# Run the quantum circuit
circ.update_quantum_state(state)

# Calculate probability to get the result of Block-Encoding
obser_order = []
for j in range(anci):
    obser_order.append(0)
for j in range(main):
    obser_order.append(2)
prob = state.get_marginal_probability(obser_order)

# Analyze the result of Block-Encoding
res_state = state.get_vector()
desire_state = []
for i in range(2**anci):
    desire_state.append(res_state[2**anci*i]/prob**0.5*norm_cf)
print(desire_state)
[(6.530303194575586+0j), (1.7414141852201561+0j), (1.7414141852201561+0j), 0j, (1.7414141852201561+0j), 0j, 0j, 0j, (1.7414141852201561+0j), 0j, 0j, 0j, 0j, 0j, 0j, 0j]
この結果は実際にハミルトニアン\(\hat{H}\)を量子状態\(|\psi\rangle\)に作用させた結果 \(\hat{H}|\psi\rangle\)と一致している。
以上までが本モジュールPItBEを用いてBlock-Encoding法を実行する一連の流れである。