# 用 Pennylane 建立量子電路
在這一節中,我們會簡要介紹 pennylane 大致的工作流程,讓讀者有個概括性的認識,接著我們會對每一個細節作獨立介紹。
首先,打開您的 colab 或是 jupyter notebook,如果您是用 colab,請按照[此前的教學](https://www.entangletech.tw/lesson/pennylane-01)安裝 pennylane,在 cell 上輸入這行並執行,將 pennylane 匯入。
```python=+
import pennylane as qml
import numpy as np
```
## Devices
第二步要宣告你要使用的裝置(device)以及所需的 qubits 數(在這裡稱作 wires):
```python=+
dev = qml.device('default.qubit', wires=2)
```
括號中的第一個參數 "default.qubit" 就是你選用的裝置,在這裡我們使用模擬器(stimulator),亦即用經典電腦模擬量子電腦,不是在真的量子電路上執行。你能選用其他的模擬器(視你的使用情境)、其他公司開發的模擬器(像是 IBM Qiskit),或是在真的量子電腦上執行(像是 IonQ, AQT, Google 等等,如果你有權限的話),有興趣的讀者可以參考這篇[文章](https://pennylane.ai/plugins)了解怎麼使用。
第二個參數 "wires=2",宣告你需要多少的 qubits,以這裡為例就是 2 個 qubits。除了單純的數字外,你也可以為每個 qubit 命名,以下方程式碼為例,他創建 5 個 qubits,第一個 qubit 叫 ancilla,第二個 qubit 叫 q11,以此類推。
```python=+
dev = qml.device('default.qubit', wires=['ancilla', 'q11', 'q12', -1, 1])
```
走某些裝置,像是 default.qubit,是接受不寫 wires
有時候,你會需要電路執行好幾次,並統計每個測量結果出現的機率,這時候我們會添加 "shots",以下列為例,電路會執行 1000 次
```python=+
dev = qml.device('default.qubit', wires=2, shots=1000)
```
除了純數字外,你也能輸入一串數字(list)。以下列為例,代表會跑三輪模擬,第一輪執行五次,第二輪執行十次,第三輪執行 1000 次。
```python=+
shots_list = [5, 10, 1000]
dev_multi_shots = qml.device("default.qubit", wires=2, shots=shots_list)
```
## 建立量子電路
Pennylane 用 python 中的 def 來建立量子電路,如下:
```python=+
def my_circuit(): #定義函數(電路)名稱
# 將所需的 gate 放進函數中
# qml.量子邏輯閘(wires = qubit 編號)
qml.PauliX(wires = 0) # 在第一個 qubit 上放 X gate
qml.Hadamard(wires = 0) # 在第一個 qubit 上放 H gate
qml.CNOT(wires = [0,1]) # 在第一個與第二個 qubit 上放 CNOT gate
# 輸出每個量子態的機率分佈
return qml.probs(wires=[0, 1])
```
對於有參數的量子電路,則會在 def 後的括號中加入變量:
```python=+
theta = np.pi/2 # 定義變量(參數)
def my_circuit_theta(theta): #定義函數(電路)名稱與變量
# 將所需的 gate 放進函數中
# qml.有參數的量子邏輯閘(參數,wires = qubit 編號)
qml.RY(theta, wires = 0) # 在第一個 qubit 放上 RY,參數為 theta
# 輸出每個量子態的機率分佈
return qml.probs(wires=[0])
```
如果你想把電路圖示化,要先 import matplotlib
```python=+
import matplotlib.pyplot as plt
```
接著輸入以下程式碼
```python=+
fig,ax = qml.draw_mpl(my_circuit, show_all_wires=False, decimals = 1, style = 'sketch')()
fig.show()
```
<div style="text-align: center;">
<img src="https://hackmd.io/_uploads/HydJxclmyl.png" alt="Circuit" width="100%"/>
<p>
</p>
</div>
- 第一個參數就是你的電路
- "show_all_wires" 可打可不打,預設為 False,輸入 True 的話代表沒有放 gate 的 qubit 都要畫出來
- "decimals" 可打可不打,代表參數要顯示到小數點以下幾位,沒有打的話預設不在圖上標示參數
- style 是圖片風格,可打可不打,預設為 black_white,想知道有哪些風格可以選用可以參看[官方說明](https://docs.pennylane.ai/en/stable/code/api/pennylane.drawer.draw_mpl.html)
- 其他更多參數可以參看[官方說明](https://docs.pennylane.ai/en/stable/code/api/pennylane.drawer.draw_mpl.html)
對於有參數的電路,可以在第二個括號中打入參數:
```python=+
fig,ax = qml.draw_mpl(my_circuit_theta, decimals = 2)(np.pi/2)
fig.show()
```
<div style="text-align: center;">
<img src="https://hackmd.io/_uploads/r18xl5eX1x.png" alt="Circuit" width="100%"/>
<p>
</p>
</div>
## QNode
最後要透過 QNode 把上面定義的電路與 device 包裝在一起
```python=+
my_qnode = qml.QNode(my_circuit, dev)
```
最後就執行運算
```python=+
my_qnode()
# 執行後輸出 array([0.5, 0. , 0. , 0.5])
```
輸出結果代表測量到 $|00\rangle$ 和 $|11\rangle$ 的機率都是 50%,其他狀態則為 0%。
QNode 也可以在定義 circuit 前就先寫好,像這樣:
```python=+
@qml.qnode(dev) # 定義 qnode
def my_circuit(): #定義函數(電路)名稱
# 將所需的 gate 放進函數中
# qml.量子邏輯閘(wires = qubit 編號)
qml.PauliX(wires = 0) # 在第一個 qubit 上放 X gate
qml.Hadamard(wires = 0) # 在第一個 qubit 上放 H gate
qml.CNOT(wires = [0,1]) # 在第一個與第二個 qubit 上放 CNOT gate
# 輸出每個量子態的機率分佈
return qml.probs(wires=[0, 1])
# 執行運算
my_circuit()
# 輸出 array([0.5, 0. , 0. , 0.5])
```
由於我們舉的例子很簡單,因此看不出 pennylane 建立 qnode 的意義何在,實際上 QNode 本身有許多和機器學習有關的參數,pennylane 下了很多功夫在串接機器學習套件上,讓量子機器學習(QML)執行起來更加方便,有興趣的讀者可以參看[官方文件](https://docs.pennylane.ai/en/stable/code/api/pennylane.qnode.html)。
## 總結
完整的程式碼長這樣,恭喜你已經用程式碼建立出第一個量子電路:
```python=+
# 安裝 pennylane,如果你是用 colab
!pip install pennylane
# import pennylane, numpy 和 matplotlib
import pennylane as qml
import numpy as np
import matplotlib.pyplot as plt
# 定義 device
dev = qml.device('default.qubit', wires=2)
# 定義 qnode 與量子電路
@qml.qnode(dev) # 定義 qnode
def my_circuit(): #定義函數(電路)名稱
# 將所需的 gate 放進函數中
# qml.量子邏輯閘(wires = qubit 編號)
qml.PauliX(wires = 0) # 在第一個 qubit 上放 X gate
qml.Hadamard(wires = 0) # 在第一個 qubit 上放 H gate
qml.CNOT(wires = [0,1]) # 在第一個與第二個 qubit 上放 CNOT gate
# 輸出每個量子態的機率分佈
return qml.probs(wires=[0, 1])
# 執行運算
my_circuit()
# 輸出 array([0.5, 0. , 0. , 0.5])
# 將定義的量子電路畫成圖
fig,ax = qml.draw_mpl(my_circuit, decimals = 1, style = 'sketch')()
fig.show()
```
在接下來的文章我們會針對每一部分做細節討論,像是在 "my_circuit" 這段介紹每個 quantum gate 的程式碼,以及還能輸出(return)什麼等等。