はじめに
Qiskitで量子プログラミングをするのに際して重要なclassの使い方を記します。
特に、Qiskit AquaなどでQAOAだったりを使うときに必要かなと思います。
まだまだ未熟なところもあると思いますが、参考にしてくれると嬉しいです。
WeightedPailiOperator
QAOAだったり、VQEだったりにハミルトニアンを読み込ませるときに使うclass methodです。
qiskit.aqua.optimization.ising ではmax cutやtspなどのWeigthedPauliOperatorを返してくれるclass methodが提供されていますが、実際に自分で作ろうとすると少し大変です。
WeightedPauliOperatorに入れるclass methodはPauli classと呼ばれるものです。この説明を行いたいと思い餡巣。
Pauli
まずは、sample code
とりあえず、使う物すべてimport
import numpy as np
from qiskit.aqua.operators import WeightedPauliOperator, MatrixOperator
from qiskit.aqua.operators.op_converter import to_weighted_pauli_operator
from qiskit.aqua.components.initial_states import Custom, InitialState
from qiskit.quantum_info import Pauli
from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit
次に一番簡単な例
pauli_list = []
num_qubit = 3
z_p = np.zeros(num_qubit, dtype=bool)
x_p = np.zeros(num_qubit, dtype=bool)
pauli_list.append([1, Pauli(z_p, x_p)])
この場合はIIIをハミルトニアンに追加します。
次に、ZIZを追加したいとき
z_p[0] = True
z_p[2] = True
pauli_list.append([1, Pauli(z_p, x_p)])
ちなみに、appendしているlistの一つ目の要素(今は1)のところにはcomplex numberを入れることができます。次に、XXXを追加したいとき。
for i in range(num_qubit):
x_p[i] = True
z_p = np.zeros(num_qubit, dtype=bool)
pauli_list.append([1, Pauli(z_p, x_p)])
Yを入れたいときはxもzもTrueにすればいいですね。
これを直接QAOAなどには入力できないので
qubitOp = WeightedPauliOperator(paulis=pauli_list)
で、完了です。
ちなみに、中身を見たい場合は
print(qubitOp.print_details())
でok
出力は
III (1+0j)
ZIZ (1+0j)
XXX (1+0j)
MatrixOperator
このclassはもっと直感的に記述したい人におすすめです。
例えばZ operatorを入れたいときは
z = np.array([[1, 0], [0, -1]])
z = MatrixOperator(z)
# 中身を見てみる
print(z.print_details())
出力は
(0, 0) 1
(1, 1) -1
この形はなんだろう??と思うかもしれませんが、
|0><0|-|1><1|
のことですね。
しかし、このままではQAOAなどに入力することができません。そこでconvertします。
z = to_weighted_pauli_operator(z)
# 中身を見てみる
print(z.print_details())
出力は
Z (1+0j)
しっかり変形されましたね。しかしながら、複数のqubitを使っていきたい場合はtensorを計算しないといけないので、少し大変です。
InitialState
QAOAの関数の四つ目の引数のinitial_state
使い方がいまいちわからずInitialStateを使えばよいことは分かるが、いまいち、、、
調べてみてもなかなか出なかったのでここに記します。
Custom
circuitをInitialStateに変換するmethodがCustomです。
例えば
\frac{|00>+|01>+|10>+|11>}{2}
をinitial stateとして使いたいとき
qr = QuantumRegister(2)
qc = QuantumCircuit(qr)
qc.h(qr)
Custom(2, circuit=qc)
とすれば、QuantumCircuit classをInitialState classに変換することができます。
追記
Customを使うにあたって,qiskitのライブラリーを書き換える箇所があります.
qiskit/aqua/algorithms/minimum_eigen_solvers/qaoa/var_form.pyの中の
def construct_circuit(self, parameters, q=None):
""" construct circuit """
angles = parameters
if not len(angles) == self.num_parameters:
raise ValueError('Incorrect number of angles: expecting {}, but {} given.'.format(
self.num_parameters, len(angles)
))
# initialize circuit, possibly based on given register/initial state
if q is None:
q = QuantumRegister(self._num_qubits, name='q')
if self._initial_state is not None:
circuit = self._initial_state.construct_circuit('circuit', q)
else:
circuit = QuantumCircuit(q)
circuit.u2(0, np.pi, q)
for idx in range(self._p):
beta, gamma = angles[idx], angles[idx + self._p]
circuit += self._cost_operator.evolve(
evo_time=gamma, num_time_slices=1, quantum_registers=q
)
circuit += self._mixer_operator.evolve(
evo_time=beta, num_time_slices=1, quantum_registers=q
)
return circuit
を
def construct_circuit(self, angles):
if not len(angles) == self.num_parameters:
raise ValueError('Incorrect number of angles: expecting {}, but {} given.'.format(
self.num_parameters, len(angles)
))
circuit = QuantumCircuit()
if self._initial_state:
circuit += self._initial_state.construct_circuit('circuit')
if len(circuit.qregs) == 0:
q = QuantumRegister(self._cost_operator.num_qubits, name='q')
circuit.add_register(q)
elif len(circuit.qregs) == 1:
q = circuit.qregs[0]
else:
raise NotImplementedError
circuit.u2(0, np.pi, q)
for idx in range(self._p):
beta, gamma = angles[idx], angles[idx + self._p]
circuit += self._cost_operator.evolve(None, evo_time=gamma, num_time_slices=1, quantum_registers=q)
circuit += self._mixer_operator.evolve(None, evo_time=beta, num_time_slices=1, quantum_registers=q)
return circuit
まとめ
自分で作ったHamiltonianでQAOAを実行してみたかったので勉強しました。
Qiskitの資料がネットに少ないので少しでも助けになればと思っています。