LoginSignup
6
6

More than 1 year has passed since last update.

Qiskit 機能色々(TIPS)

Last updated at Posted at 2021-01-01

QISKIT 機能色々(TIPS)

主に自分用のメモです。
コマンドの列挙ですので、同時に動かない機能があります。

  • 状態ベクトル系では、回路にmeasureがあるとバグる。(正確には、射影測定後の状態ベクトルが得られる)
  • 古典レジスタが存在すると使えない機能がある

install

pip install qiskit pylatexenc

import


#必要なモジュールのインポート
from qiskit import IBMQ, QuantumCircuit, ClassicalRegister, QuantumRegister
from qiskit import execute, Aer
from qiskit.qasm import pi
from qiskit.tools.visualization import plot_histogram, circuit_drawer, plot_gate_map, plot_circuit_layout
from qiskit import IBMQ, transpile
from qiskit.providers.ibmq.managed import IBMQJobManager
from qiskit.quantum_info.operators import Operator, Pauli
from qiskit.quantum_info import Statevector
from qiskit.aqua.utils import tensorproduct
from qiskit.quantum_info.analysis import average_data
from qiskit.aqua import QuantumInstance
from qiskit.aqua.operators import PauliExpectation, CircuitSampler, StateFn
from qiskit.aqua.operators import X, Y, Z, I
from qiskit.circuit.library import RYGate
from qiskit.aqua.operators.state_fns import CircuitStateFn
from qiskit.circuit.random import random_circuit
from qiskit.circuit.add_control import add_control
from qiskit.providers.aer import QasmSimulator

import numpy as np

IBMQロード

## "MY_API_TOKEN" に、上で取得したtokenを入れる
from qiskit import IBMQ
IBMQ.save_account('XXXXXXXX',overwrite = True)

# least busy な バックエンドを知る
from qiskit.providers.ibmq import least_busy

# 自分のアカウント情報をloadする。(あらかじめ IBMQ.save_account を実行しておく必要がある. 複数のアカウントを使い分ける時はここで行う)
provider = IBMQ.load_account()

# 自分のアカウントで使用できるバックエンドを見る
provider.backends()

# Run our circuit on the least busy backend. Monitor the execution of the job in the queue
from qiskit.tools.monitor import job_monitor

オブザーバブルの作り方

# Observableを作る (方法その1)
pauli0 = Pauli(label='II')
pauli1 = Pauli(label='IZ')
obs_op = Operator(pauli0) + Operator(pauli1) #O = II+IZ
obs1 = obs_op.data # from operator to matrix
print(obs1)
# Observableを作る (方法その2)
I_mat = np.array([[1, 0], [0, 1]])
Z_mat = np.array([[1, 0], [0, -1]])
obs2 = tensorproduct(I_mat,I_mat) + tensorproduct(I_mat,Z_mat) # matrix

# Observableを作る (方法その3)
obs3 = np.array([[2,0,0,0],[0,0,0,0],[0,0,2,0],[0,0,0,0]])

# Observableを作る (方法その4)
obs4 =  1*I^I + 1*I^Z

# Observableを作る (方法その5)
 from qiskit.aqua.operators import WeightedPauliOperator
 pauli_dict = {
      'paulis': [{"coeff": {"imag": 0.0, "real": 1}, "label": "II"},
                {"coeff": {"imag": 0.0, "real": 1}, "label": "IZ"},                             
                ]
  }
obs5 = WeightedPauliOperator.from_dict(pauli_dict).to_opflow()

ちなみに、方法4は若干の注意が必要です。
obs4 = 2*I^I + 2*I^Z はOKですが、
obs4 = 2*(I^I + I^Z) はだめです。
(エラー無く通りますが、期待値計算の際に定数倍が無視されます)

なんだかんだ、汎用性が高いのは方法5だと思います。
obs5.to_matrix() で配列形式にも出来ます。

回路準備

# 回路の定義
nqubits = 2 #qubits
ncbits = 1  #classical bits
qr = QuantumRegister(nqubits)
cr0 = ClassicalRegister(ncbits)
cr1 = ClassicalRegister(ncbits)
circuit = QuantumCircuit(qr,cr0,cr1) 
# レジスタに興味ない場合は QuantumCircuit(nqubits)や QuantumCircuit(nqubits,ncbits) でOK
#circuit.draw('mpl')

回路記述いろいろ

# 回路記述

# Define an arbitrary unitary gate
U_mat = np.array([[0,1],[1,0]])

#Note : this operation is invalied in ibmq real quantum devices
#circuit.reset(0) #reset 0th qubit as |0>
#circuit.reset(1) #reset 1st qubit as |0>
#circuit.initialize([0, 1],0) #set 0th qubit as [0,1] = |1>
circuit.h(0)
circuit.h(1)
#circuit.x(0).c_if(cr1,1) # Note : Only 1 classical bit register can be used in c_if.
#circuit.unitary(U_mat,0)
#circuit.x([0,1]) #add X-gate from 0th to 1st qubit.
#circuit.cx(0,1) #Controlled-NOT. The controlled and target bit is 0th and 1st one, respectively.
#circuit.rz(2,0) ## RZ(a)=exp(-i*a/2*Z)に注意. rz(rotation_angle, qbit_label)
#circuit.hamiltonian(obs1,10,[0,1]) #Hamitonian evaluation ?
psi = CircuitStateFn(circuit) # get final state vector. Note:The classical register shouldn't be used.
#circuit.measure_all() #Note : don't add measurement when you use statevector_simulator
circuit.draw('mpl')

image.png

psi = CircuitStateFn(circuit) を使う場合は、
-古典レジスタを使わない
-measureを使わない
が必要になります。

任意制御ゲートの作成


theta_01 = np.arctan(1)
Ugate_01 = RYGate(2*theta_01)
Ugate_01_ctrl = add_control(Ugate_01, num_ctrl_qubits=2, label='CU_01', ctrl_state='01')

def eigen_rot(circ):
    circ.append(Ugate_01_ctrl,[0,1,3])

回路の途中の状態ベクトルをメモる

回路の途中の状態ベクトルを取り出すことが出来ます。
この方法はシミュレーター限定ですが、statevector simulatorに限らず、qasm simulatorでも使えます。
回路の任意の位置で snapshot という操作を入れます。(ゲートのような感覚です)
circuit.snapshot('my_sv',snapshot_type='statevector') # get a snapshot of present statevector
snapshotはいくつでも入れられます。
次に、回路を実行します。
results = execute(circuit, backend, shots=1).result()
結果の変数resultsの中身に、以下の呪文でアクセスします。
statevec = results.data()['snapshots']['statevector']['my_sv'][k] # 2^nqubits complex vector |ψ>
ここで、kはsnapshotを複数とった場合に何番目を取り出すかを意味します。
出力結果は複素ベクトル(状態ベクトル)になっていますので、期待値計算は簡単です。
expectation = np.real(np.vdot(statevec,np.dot(obs_mat,statevec))) # Real[<ψ|O|ψ>]
obs_matはオブザーバブルの行列表現です。

c_ifの使い方

2021/01/02追記
c_ifは1bit古典レジスタしか引数に取れません。以前は複数bitが出来たようです。
複数bitでも実行可能に見えますが、実際には何も操作されなかったりします。ひどい。。
例えば、
image.png

は正常に動きます("11")が、

image.png

は正常に動きません("10")。なんでや! たぶん最初の古典ビットだけがc_ifの対象ぽいですね。

また、複数古典ビットを一気に渡す
cr = ClassicalRegister(2), circuit.x(0).c_if(cr,3) も、無効です。以前は出来た模様。

1 classical bit register をたくさん定義するのは面倒です。
circuit.x(0).c_if(cr[0],1) と書きたい。その場合は以下のようにします。

qr = QuantumRegister(2)
circuit = QuantumCircuit(qr) 
cr = [ ClassicalRegister(1) for _ in range(2) ]
for register in cr:
    circuit.add_register( register )
circuit.x([1])
circuit.measure(1,1)
circuit.x(0).c_if(cr[1],1)
circuit.measure(0,0)

また、c_ifは実機では動かないそうです。以下の5-1を見てください。
https://qiskit.org/textbook/ch-algorithms/teleportation.html#testing

回路を調べる

# depth of circuit
circuit.depth()

## decompose into hardware gates
circuit.decompose().draw('mpl')

image.png

backendの定義

# backendの定義
#backend = Aer.get_backend('qasm_simulator')
#backend = Aer.get_backend('statevector_simulator')
#backend = Aer.get_backend('unitary_simulator')
#backend = provider.get_backend('ibmq_santiago')

transpile関係

#ibmq information

#transpile
circuit_transpiled = transpile(circuit, backend=provider.get_backend('ibmq_santiago'), optimization_level=3)
plot_circuit_layout(circuit_transpiled, backend=provider.get_backend('ibmq_santiago'))

image.png

image.png

IBM実機プロパティを取る

# T1/T2 info.
backend = provider.get_backend('ibmq_santiago')
props = backend.properties()
def describe_qubit(qubit, properties):
    """Print a string describing some of reported properties of the given qubit."""

    # Conversion factors from standard SI units
    us = 1e6
    ns = 1e9
    GHz = 1e-9

    print("Qubit {0} has a \n"
          "  - T1 time of {1} microseconds\n"
          "  - T2 time of {2} microseconds\n".format(
              qubit,
              properties.t1(qubit) * us,
              properties.t2(qubit) * us))
              #properties.gate_error('u2', qubit),
              #properties.gate_length('u2', qubit) * ns,
              #properties.frequency(qubit) * GHz))

describe_qubit(0, props)
describe_qubit(1, props)

image.png

qubitアサイン手動設定

image.png

# Virtual -> physical
#    0    ->    3
#    1    ->    4
#    2    ->    2

circuit_opt = transpile(circuit, backend=provider.get_backend('ibmqx2'), initial_layout=[3, 4, 2])
plot_circuit_layout(circuit_opt, backend=provider.get_backend('ibmqx2'))

image.png

#execute関連

IBMQ認証

"MY_API_TOKEN" に、IBMQ HPで取得したtokenを入れる

from qiskit import IBMQ
IBMQ.save_account('MY_API_TOKEN',overwrite = True)

# 自分のアカウント情報をloadする。(あらかじめ IBMQ.save_account を実行しておく必要がある. 複数のアカウントを使い分ける時はここで行う)
provider = IBMQ.load_account()

# 自分のアカウントで使用できるバックエンドを見る
print(provider.backends())

# 実行(実行状況のモニタアリ)
from qiskit.tools.monitor import job_monitor
job= execute(circuit, backend=provider.get_backend('ibmq_qasm_simulator'), shots=8192) #ibmq
results = job.result()
counts=results.get_counts()
plot_histogram(counts)

単一jobのexecute

# execute on qasm simulator
results = execute(circuit, backend=Aer.get_backend('qasm_simulator'), shots=1024).result()

# execute on ibmq
#job= execute(circuit, backend=provider.get_backend('ibmq_santiago'), shots=1024)
#job_monitor(job, interval=2)
#results = job.result()
#counts = results.get_counts()

# execute on state vector simulator
#results = execute(circuit, backend=Aer.get_backend('statevector_simulator'),shots=1).result()
#results.get_statevector()

過去のjobの回収

指定したマシンで直近10個の実行結果のIDを取る

[x.job_id() for x in provider.get_backend('ibmq_qasm_simulator').jobs(limit=10)]

指定したID"hogehoge"の結果を回収する

provider.get_backend('ibmq_qasm_simulator').retrieve_job("hogehoge")

jobの実行上限を確認

backend_job_limit = backend.job_limit()
remain_jobs = backend.remaining_jobs_count()
maximum_jobs = backend_job_limit.maximum_jobs
print('Job is {:} / {:}'.format(remain_jobs, maximum_jobs))

Job is 5 / 5

error mitigation

from qiskit.aqua import QuantumInstance
# Import measurement calibration functions
from qiskit.ignis.mitigation.measurement import (complete_meas_cal, tensored_meas_cal,CompleteMeasFitter, TensoredMeasFitter)
qi_noise_model_ibmq = QuantumInstance(backend=provider.get_backend('ibmqx2'), shots=8000, measurement_error_mitigation_cls=CompleteMeasFitter, measurement_error_mitigation_shots=8000)
job=qi_noise_model_ibmq.execute(circuit_opt)
results = job # q_instance.execute の戻り値は、既に.resultなので注意。
counts=results.get_counts()
plot_histogram(counts)

noise model を使ったexecute

#Noise model
from qiskit.providers.aer.noise import NoiseModel
backend_dev = provider.get_backend('ibmqx2')
coupling_map = backend_dev.configuration().coupling_map
noise_model = NoiseModel.from_backend(backend_dev.properties())
q_instance = QuantumInstance(backend=Aer.get_backend("qasm_simulator"), shots=8192, noise_model=noise_model,  coupling_map=coupling_map, measurement_error_mitigation_cls=CompleteMeasFitter, cals_matrix_refresh_period=30)
job=q_instance.execute(circuit)
results = job
counts=results.get_counts()
plot_histogram(counts)

または、

  backend_dev = provider.get_backend('ibmqx2')
  coupling_map = backend_dev.configuration().coupling_map
  basis_gates =  backend_dev.configuration().basis_gates
  noise_model = NoiseModel.from_backend(backend_dev.properties())
  print(noise_model)  
  results = execute(circs,backend=backend,   noise_model=noise_model, coupling_map=coupling_map, basis_gates=basis_gates).result()  

または、

ibmqx2_simulator = QasmSimulator.from_backend(provider.get_backend('ibmqx2'))
results = execute(circs,backend=ibmqx2_simulator).result()

複数jobの同時execute

 # Build ten circuits.
circs = []
for _ in range(10):
    circs.append(random_circuit(n_qubits=5, depth=4))

results = execute(circs,backend=backend).result()
results.get_counts(5)  # Counts for experiment 5.

または、


 # Build ten circuits.
circs = []
for _ in range(10):
    circs.append(random_circuit(n_qubits=5, depth=4))

job_manager = IBMQJobManager()
job_set_foo = job_manager.run(circs, backend=backend, name='foo')
results = job_set_foo.results()
results.get_counts(5)  # Counts for experiment 5.

IBMQ job manager を使う場合、transpileがすっ飛ばされる。
そのため、特定のゲートの回路しか通らない。
これを回避するには、手動transpileしてから投げればOK。(backend指定transpileは、やや長めの時間がかかります)
circs = transpile(circs, backend)
https://qiskit.org/documentation/stubs/qiskit.providers.ibmq.managed.IBMQJobManager.html

測定結果の加工

results.get_memory(circuit) #全shotの結果を列挙
counts = results.get_counts()
counts.most_frequent() # 頻度最大のbit列を取得
counts.get('00') # '00'の観測された回数を取得

期待値計算

#Calc. expectation

# qasm_simulator or ibmq

#方法その1 , Note : obs should be diagonalized in Z basis
#counts = results.get_counts()
#expectation = average_data(counts, obs)

#方法その2
q_instance = QuantumInstance(backend=Aer.get_backend('qasm_simulator'), shots=8192)
# define the state to sample
measurable_expression = StateFn(obs4,is_measurement=True).compose(psi) 
# convert to expectation value
expectation = PauliExpectation().convert(measurable_expression)  
sampler = CircuitSampler(q_instance).convert(expectation)    # get state sampler (you can also pass the backend directly)
Expectation = sampler.eval().real

# state vector simulator
#result_statevec = Statevector(results.get_statevector())
#expectation = np.real(result_statevec.expectation_value(Operator(obs1)))

plot関連

ヒストグラムplot

plot_histogram(counts)

確率0のcountsも表示する


# zero-padding
for i in range (2**nqubits):
    counts.setdefault(format(i, '0'+str(nqubits)+'b'),0)

plot_histogram(counts, figsize = [20,5])

image.png

statevector simulator を使ったときのヒストグラムplot

n = nqubits
results = execute(circuit, backend=Aer.get_backend('statevector_simulator'), shots=1).result()
final_state = results.get_statevector()

## z方向に観測した時の確率分布を求める. (状態ベクトルの各成分の絶対値の二乗=観測確率)
probs = np.abs(final_state**2)
print(probs)
# プロットする
import matplotlib.pyplot as plt
%matplotlib inline

## z方向に射影測定した時に得られる可能性があるビット列
z_basis = [format(i,"b").zfill(n) for i in range(probs.size)]

plt.figure(figsize=(10, 5))
plt.xlabel("states")
plt.ylabel("probability(%)")
plt.bar(z_basis, probs*100)
plt.show()

Statevectorクラスのメソッドを使っても出来るかもしれません。

回路プロットの横幅変更

改行したくないときはfoldの値を増やす。

circuit.draw('mpl', fold = 30)

image.png

更に、 scale = 0.5 等で画像サイズを変えられる。

matplotlibによるグラフ

"""複数のグラフを重ねて描画するプログラム"""
import matplotlib.pyplot as plt

fig, ax = plt.subplots()


c1,c2 = "blue","green"     # 各プロットの色
l1,l2 = "ibmq_santiago","simulator"   # 各ラベル

ax.set_xlabel('time')  # x軸ラベル
ax.set_ylabel('magnetization')  # y軸ラベル
ax.set_title('Evolution of magnetization') # グラフタイトル
# ax.set_aspect('equal') # スケールを揃える
ax.grid()            # 罫線
#ax.set_xlim([-10, 10]) # x方向の描画範囲を指定
#ax.set_ylim([0, 1])    # y方向の描画範囲を指定
ax.plot(x, y, color=c1, label=l1, marker="o")
ax.plot(x_sim, y_sim, color=c2, label=l2)

ax.legend(loc=0)    # 凡例
fig.tight_layout()  # レイアウトの設定
# plt.savefig('hoge.png') # 画像の保存
plt.show()

qiskit.aqua

QAOA

# Weighted matrix. 
w = np.array([
    [0, 1, 0, 1],
    [1, 0, 1, 0],
    [0, 1, 0, 1],
    [1, 0, 1, 0]
])

p = 1
backend = Aer.get_backend('statevector_simulator')
optimizer = COBYLA()
qubitOp, offset = max_cut.get_operator(w)

qaoa = QAOA(qubitOp, optimizer, p)
quantum_instance = QuantumInstance(backend)
result = qaoa.run(quantum_instance)


Statevec = Statevector(result.eigenstate)
counts = Statevec.probabilities_dict()
plot_histogram(counts)

その他

circuit.remove_final_measurement() の意義

動作がよくわかりません。
古典レジスタも一緒に消してしまって、回路として使えなくなってしまうような。

状態ベクトルシミュレーターのときはmeasureを無効化するオプションがほしい

QPEのライブラリ

6
6
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
6
6