Qiskit 1.0 チートシート

# はじめに
*Qiskit*は**量子プログラミング用SDKのパイオニアであり**、全世界から無料の量子コンピュータに接続できる機能を有することから、多くのユーザーに愛されています。
Qiitaでも、Qiskitで書かれた多くの量子プログラムや、実機実行結果を目にすることができます。
Qiskitは、**量子コンピュータの大衆化**を成功させたと思っています。

しかし、2024/12時点で、Qiskit が0.x から　1.x に major updateされ、破壊的な変更が続き、**Webにあるコードの多くが実行不可能となっています。**
加えて、IBM自身が公開するサイト(IBM Quantum Documentation)も更新が追いついておらず、現在では実行不可能なものが掲載されています。
**特に日本語では、正常動作するexampleに到達することがもはや困難**であり、多くの方が困っているのではないかと危惧しています。

**そこで、チートシートを作成し、公開することに決めました。**
Qiskit 0.x を使っていた方であれば、移行の助けになるものと思います。
本記事は随時アップデートしていきます。


# 動作確認環境
2024/12

Name: qiskit
Version: 1.3.0

Name: qiskit-ibm-runtime
Version: 0.33.2

Name: qiskit-aer
Version: 0.15.1

# 教材
- [IBM Quantum Learning](https://learning.quantum.ibm.com/)
    - [Courses](https://learning.quantum.ibm.com/catalog/courses)
        - [Basics](https://learning.quantum.ibm.com/course/basics-of-quantum-information)
- [IBM Quantum Documentation](https://docs.quantum.ibm.com/)
    - [Qiskit Functions](https://docs.quantum.ibm.com/guides/functions)　は有料の機能

# APIリファレンス
- [Qiskit SDK](https://docs.quantum.ibm.com/api/qiskit)
Runtime等のAPIリファレンスも、ページ上部のタブから移動できます。

# 実機マイページ
[IBMQ](https://quantum.ibm.com/login)

# 環境構築
```python
pip install qiskit
pip install qiskit-ibm-runtime
pip install qiskit-aer
```

```python
pip install pylatexenc
pip install matplotlib
```
pylatexencは、回路描画する場合に必要ですので、インストール推奨です。

IBMQに登録→ログイン(二段階認証が必要です)→　token文字列をコピーしておきます。
以下の"hoge"をtoken文字列に差し替えてください。

```python
from qiskit_ibm_runtime import QiskitRuntimeService
token = "hogehoge" 
QiskitRuntimeService.save_account(
  token=token,
  channel="ibm_quantum" # `channel` distinguishes between different account types
)
```

アカウント情報がセーブされていますので、以降はロードするだけでよくなります。

```python
# Load saved credentials
service = QiskitRuntimeService()
```

# 回路の記述

```python
import numpy as np
from qiskit import QuantumCircuit
qc = QuantumCircuit(2)
qc.x(0)
qc.h([0,1])
qc.rx(theta=np.pi/4,qubit=0)
qc.cx(0,1) # CNOT
qc.measure_all() # Measure all qubits
qc.draw("mpl")
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/79a4b191-f226-93b2-57e6-d2e2dab7bb5b.png)

# 状態ベクトルの出力
```python
qc.remove_final_measurements()  # no measurements allowed
from qiskit.quantum_info import Statevector
statevector = Statevector(qc) # qc is a quantum circuit
print(statevector)
```
>Statevector([ 0.46193977+0.19134172j, -0.46193977-0.19134172j,
              0.46193977+0.19134172j, -0.46193977-0.19134172j],
            dims=(2, 2))

## ケット表示出力(Latex)
[Plot quantum states](https://docs.quantum.ibm.com/guides/plot-quantum-states)
```python
statevector.draw("latex")  # psi is a Statevector object
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/4f1372da-44dc-6f1e-1d54-aa30160da7fa.png)


### ケット表示の文字列へ変換する例
```python
def dec_to_bin(decimal_number:int = 10, bit_len:int = None):
    binary_string = bin(decimal_number)[2:].zfill(bit_len)
    return binary_string
def sv_to_ket_str(sv_array):
    n_qubit = int(np.log2(len(sv_array)))
    ket = ""
    for idx, val in enumerate(sv_array):
        # ignore small value
        if np.abs(np.real(val)) < 1e-10:
            val = 0.0 + 1j*np.imag(val)
        if np.abs(np.imag(val)) < 1e-10:
            val = np.real(val) + 0.0*1j
        ket += str(val) + "|" + dec_to_bin(idx, n_qubit) + ">" + " + "
    ket = ket[:-2]
    return ket

ket = sv_to_ket_str(statevector)
print(ket)
```
>(0.46193976625564326+0.19134171618254484j)|00> + (-0.46193976625564326-0.19134171618254484j)|01> + (0.46193976625564326+0.19134171618254484j)|10> + (-0.46193976625564326-0.19134171618254484j)|11> 

# 回路の実行(バックエンドの指定)
バックエンドは、大きく3種類に分かれます。
- Qiskit SDK Primitives
    - ローカルPCでのシミュレーション。雑音を考慮できない。
- Qiskit Aer Primitives
    - ローカルPCでのシミュレーション。雑音を考慮できる。アルゴリズムが豊富。
    - スタビライザ追跡アルゴリズムでのシミュレーション等はこちら。
- Qiskit RUntime Primitive
    - 実機実行、または互換性のあるコードでのローカルPCシミュレーション（雑音考慮）。

[Exact simulation with Qiskit SDK primitives](https://docs.quantum.ibm.com/guides/simulate-with-qiskit-sdk-primitives)
>The reference primitives in the Qiskit SDK perform local statevector simulations. 

[Exact and noisy simulation with Qiskit Aer primitives](https://docs.quantum.ibm.com/guides/simulate-with-qiskit-aer)
>High-performance quantum computing simulators with realistic noise models.

> In this article, we demonstrate the use of Qiskit Aer primitives for exact and noisy simulation.

[Primitive Examples](https://docs.quantum.ibm.com/guides/primitives-examples)


## Qiskit SDK Primitives

### Observable 期待値

[qiskit-sdk-primitives](https://docs.quantum.ibm.com/guides/simulate-with-qiskit-sdk-primitives)

期待値計算は Estimator という種類のシミュレーターを使います。

```python
from qiskit import QuantumCircuit
 
# circuit for which you want to obtain the expected value
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0,1)
qc.draw("mpl", style="iqp")

from qiskit.quantum_info import SparsePauliOp
import numpy as np
 
# observable(s) whose expected values you want to compute
from qiskit.quantum_info import SparsePauliOp
observable = SparsePauliOp(["II", "XX", "YY", "ZZ"], coeffs=[1, 1, -1, 1]) # II+XX-YY+ZZ

from qiskit.primitives import StatevectorEstimator
estimator = StatevectorEstimator()

job = estimator.run([(qc, observable,)])
result = job.result()
print(f" > Expectation value: {result[0].data.evs}")
```
> Expectation value: 3.999999999999999

---

回路に埋め込んだ変数を変えながら実行。
かつ、実機を意識してレイアウトし直し（トランスパイル）。

```python
from qiskit import QuantumCircuit
from qiskit.circuit import Parameter
 
# circuit for which you want to obtain the expected value
qc = QuantumCircuit(2)
qc.ry(Parameter('theta'), 0)
qc.h(0)
qc.cx(0,1)
qc.draw("mpl", style="iqp")

from qiskit.quantum_info import SparsePauliOp
import numpy as np
 
# observable(s) whose expected values you want to compute
from qiskit.quantum_info import SparsePauliOp
observable = SparsePauliOp(["II", "XX", "YY", "ZZ"], coeffs=[1, 1, -1, 1])
 
# value(s) for the circuit parameter(s)
parameter_values = [[0], [np.pi/6], [np.pi/2]]

# Generate a pass manager without providing a backend
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
 
pm = generate_preset_pass_manager(optimization_level=1)
isa_circuit = pm.run(qc)
isa_observable = observable.apply_layout(isa_circuit.layout)

from qiskit.primitives import StatevectorEstimator
estimator = StatevectorEstimator()

job = estimator.run([(isa_circuit, isa_observable, parameter_values)])
result = job.result()

print(f" > Expectation value: {result[0].data.evs}")

```

> Expectation value: [4.         3.73205081 2.        ]

### Sampling
状態ベクトルから確率分布を計算し、疑似乱数でサンプルを生成します。
サンプル(あるいは確率分布)を取るのは Sampler という種類のシミュレーターを使います。


>By default, the reference Sampler performs an exact statevector calculation based on the quantum_info.Statevector class. 


```python
 # Define quantum circuit with 2 qubits
 circuit = QuantumCircuit(2)
 circuit.h(0)
 circuit.cx(0, 1)
 circuit.measure_all()
 circuit.draw()

# Transpile circuit
pm = generate_preset_pass_manager(optimization_level=1)
isa_circuit = pm.run(circuit)

# Run using sampler
from qiskit.primitives import StatevectorSampler
sampler = StatevectorSampler()
result = sampler.run([circuit]).result()
# Access result data for PUB 0
data_pub = result[0].data
# Access bitstring for the classical register "meas"
bitstrings = data_pub.meas.get_bitstrings()
print(f"The number of bitstrings is: {len(bitstrings)}")
# Get counts for the classical register "meas"
counts = data_pub.meas.get_counts()
print(f"The counts are: {counts}")

```
>The number of bitstrings is: 1024
The counts are: {'00': 509, '11': 515}

なお、シミュレーションなのでトランスパイルを飛ばしても動きます。

こんな感じ

```python
from qiskit.primitives import StatevectorSampler as Sampler
# initialization of the sampler
sampler = Sampler()
 
# collect 128 shots from the quantum circuit
job = sampler.run([qc], shots=128)
result = job.result()

# Get results for the first (and only) PUB
pub_result = result[0]
 
print(f" > Counts: {pub_result.data.meas.get_counts()}")
```
>Counts: {'01': 28, '00': 29, '11': 33, '10': 38}

```python
from qiskit.visualization import plot_histogram
plot_histogram(pub_result.data.meas.get_counts())
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/9c32bbdc-0443-4d96-de2d-62ba6f8dfce1.png)

Parall execution
```python
job = sampler.run([qc,qc,qc], shots=128)
result = job.result()
for i in range(3):
    pub_result = result[i]
    print(f" > Counts: {pub_result.data.meas.get_counts()}")
```
> > Counts: {'01': 29, '10': 40, '11': 28, '00': 31}
 > Counts: {'01': 43, '10': 23, '00': 28, '11': 34}
 > Counts: {'01': 29, '11': 32, '10': 36, '00': 31}


## Qiskit Aer primitives
[Aer primitives](https://docs.quantum.ibm.com/guides/simulate-with-qiskit-aer)

>In this article, we demonstrate the use of Qiskit Aer primitives for exact and noisy simulation.

### 雑音なしシミュレーション
[Simulating your first quantum program with Qiskit Aer](https://qiskit.github.io/qiskit-aer/getting_started.html)

一見、qiskit SDK primitivesと同じですが、qiskit_aerからimportをしています。

```python
import qiskit
from qiskit_aer.primitives import SamplerV2

# Generate 3-qubit GHZ state
circ = qiskit.QuantumCircuit(3)
circ.h(0)
circ.cx(0, 1)
circ.cx(1, 2)
circ.measure_all()

# Construct an ideal simulator with SamplerV2
sampler = SamplerV2()
job = sampler.run([circ], shots=128)

# Perform an ideal simulation
result_ideal = job.result()
counts_ideal = result_ideal[0].data.meas.get_counts()
print('Counts(ideal):', counts_ideal)

```
>Counts(ideal): {'111': 61, '000': 67}


### 雑音ありシミュレーション
[Device backend noise model simulations](https://qiskit.github.io/qiskit-aer/tutorials/2_device_noise_simulation.html)

```python
from qiskit import QuantumCircuit, transpile
from qiskit_aer import AerSimulator
from qiskit.visualization import plot_histogram
```

雑音なしの場合
```python
# Construct quantum circuit
circ = QuantumCircuit(3, 3)
circ.h(0)
circ.cx(0, 1)
circ.cx(1, 2)
circ.measure([0, 1, 2], [0, 1, 2])

sim_ideal = AerSimulator()

# Execute and get counts
result = sim_ideal.run(transpile(circ, sim_ideal)).result()
counts = result.get_counts(0)
plot_histogram(counts, title='Ideal counts for 3-qubit GHZ state')
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/580565e0-2e00-6784-d921-2d689f12d5c9.png)

雑音あり(ibm_quebec模擬)の場合
quebecの雑音モデルを取得するために、qiskit_ibm_runtimeを使う（依存性あり）。

```python
from qiskit_ibm_runtime.fake_provider import FakeQuebec
device_backend = FakeQuebec()

sim_quebec = AerSimulator.from_backend(device_backend)

# Transpile the circuit for the noisy basis gates
tcirc = transpile(circ, sim_quebec)

# Execute noisy simulation and get counts
result_noise = sim_quebec.run(tcirc).result()
counts_noise = result_noise.get_counts(0)
plot_histogram(counts_noise,
               title="Counts for 3-qubit GHZ state with device noise model")
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/5472fc7b-a1bb-487e-fb5f-4f35e704b89a.png)


[雑音モデルのカスタム](https://qiskit.github.io/qiskit-aer/tutorials/3_building_noise_models.html)

## Qiskit Runtime Primitives

### Local testing mode
[Local testing mode](https://docs.quantum.ibm.com/guides/local-testing-mode)
大きく2種類がある。
- Fake backend + Qiskit Runtime Primitives
- Fake backend + Aer simulator (前述)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/ce67bf19-f6cd-798d-ab61-26ec93689e70.png)

Aer simを使う場合、スタビライザ追跡アルゴリズムでのシミュレーション等もできる。
(特定構造や特定用途でシミュレーション時間に大きな差が出る。)

残る、Fake backend + Qiskit Runtime Primitives の場合だけ示します。

```python
from qiskit.circuit import QuantumCircuit
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import SamplerV2 as Sampler
from qiskit.circuit import QuantumCircuit
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import SamplerV2 as Sampler
from qiskit_ibm_runtime.fake_provider import FakeQuebec
 
# Bell Circuit
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
qc.measure_all()
 
fake_quebec = FakeQuebec()
pm = generate_preset_pass_manager(backend=fake_quebec, optimization_level=1)
isa_qc = pm.run(qc)
 
# You can use a fixed seed to get fixed results.
options = {"simulator": {"seed_simulator": 42}}
sampler = Sampler(mode=fake_quebec, options=options)
 
result = sampler.run([isa_qc]).result()

counts_noise = result[0].data.meas.get_counts()
plot_histogram(counts_noise,
               title="Counts for a state with device noise model")
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/3f8d2900-e4ac-d66e-699e-babb7b8249b0.png)

### 実機実行
[Primitives examples](https://docs.quantum.ibm.com/guides/primitives-examples)

```python
import numpy as np
from qiskit.circuit.library import IQP
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit.quantum_info import SparsePauliOp, random_hermitian
from qiskit_ibm_runtime import QiskitRuntimeService, EstimatorV2 as Estimator
 
n_qubits = 127
 
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False, min_num_qubits=n_qubits)
 
mat = np.real(random_hermitian(n_qubits, seed=1234))
circuit = IQP(mat)
observable = SparsePauliOp("Z" * n_qubits)
 
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(circuit)
isa_observable = observable.apply_layout(isa_circuit.layout)
 
estimator = Estimator(backend)
job = estimator.run([(isa_circuit, isa_observable)])
result = job.result()
 
print(f" > Expectation value: {result[0].data.evs}")
print(f" > Metadata: {result[0].metadata}")
```

> Expectation value: 0.00732421875
 > Metadata: {'shots': 4096, 'target_precision': 0.015625, 'circuit_metadata': {}, 'resilience': {}, 'num_randomizations': 32}



 # Qiskit ecosystem (関連ライブラリ)
 [Qiskit ecosystem](https://www.ibm.com/quantum/ecosystem)

 # おわりに
 本記事は随時アップデートしていきます。
**Qiskitは量子プログラミング用SDKのパイオニアであり、日本においてもこの発展に追随・貢献できる環境を維持・整備しておくことに、意味があると思います。**
量子コンピュータの実現には長い長い時間がかかりますから、これから参入する方へのハードルを上げてはいけません。

この思いに賛同していただける方は、ぜひ「いいね」を押して頂けると嬉しいです。