Last Updated on 2022-12-19 by Clay
前一個章節我們使用 Qiskit 實作了一個半加法器(Half Adder)。現在,我們已經知道了什麼是『位元』(bits)、以及傳統電腦的部分工作原理。
在傳統電腦中,無論是變數(variables)、物件(objects)、資料結構(data structure),我們都可以視為由位元所組成。而在量子電腦中,最基本的單位為量子位元(qubits),是位元的量子版本。量子位元與傳統的位元有著相同的限制,它們都只能儲存二元表示的資訊:0 和 1。
然而,量子位元也可以使用量子力學的特性來進行操作,這給我們提供了新的門(gates),讓我們可以設計全新的演算法。
要完全了解這些新的門,我們必須先瞭解該如何表達量子的狀態。為此,我們需要使用向量(vector)、矩陣(matrix)、複數(complex number)等數學工具。雖然下面會逐步介紹,但是如果有一定程度的基礎會比較好。如果需要相關的知識,可以參考官方提供的連結,我預計將來也會進行翻譯。
目錄:
1. 傳統位元和量子位元的比較
1.1 狀態向量(Statevectors)
1.2 量子位元符號(Qubit Notation)
1.3 使用 Qiskit 探索量子位元
2. 測量規則
2.1 重要的規則
2.2 規則的含義
3. 布洛赫球面(The Bloch Sphere)
3.1 受限制量子位元狀態的描述
3.2 量子位元狀態的視覺化
1. 傳統位元與量子位元的比較
1.1 狀態向量(Statevectors)
在量子物理學中,我們會使用狀態向量(statevectors)來描述我們的系統狀態。比方說如果我們要描述一台車子在特定軌跡上的位置時,在經典的系統裡我們會使用一個符號 x
來代表位置。
以上圖為例,x = 4
就是我們的表示法。
或者是,我們可以使用向量中的一組數字來表達這個狀態,這就是所謂的狀態向量(statevectors)。狀態向量中的每個元素(element)都代表著在該元素對應的位置上找到汽車的機率。
不只是位置,我們也可以使用狀態向量來表示汽車可能擁有的所有速度的機率、或是可能擁有的所有外觀顏色。
在經典系統中,使用狀態向量可能是一件很沒有效率的事情 —— 因為我們可能會發現儲存這麼多的元素沒有意義,以電腦的角度還說就是浪費了很多記憶體在儲存沒有必要的資訊,而實際上我們只需要使用僅僅一個數值就能表示汽車的一個特徵狀態。
但是我們會在接下來的章節中看到,狀態向量是表示量子狀態的一個非常恰當的方式。
1.2 量子位元的符號
傳統位元總有一個非常明確的狀態:0 或 1,所以我們可以直接使用單一的變數來描述位元,例如 c = 0
或 c = 1
。
這個限制在量子位元上是不存在的。當我們要從量子位元上提取 0 或 1 時,我們僅需在抽取測量時明確定義我們要從量子位元中得到 0 或 1 即可。當然,因為量子位元可能需要提供這兩個選項(0 or 1)給我們,所以在一般情況下,它的狀態遠比二元數值更複雜。
為了瞭解如何去描述這個狀態,我們首先聚焦一兩個簡單的例子。
正如我們前一篇文章所介紹的,我們可以準備一個無論如何都給出 0 測量結果的量子位元。我們先幫它起一個毫無想像力的名字:ZERO。另一個無論如何測量結果都為 1 的量子位元,自然就叫做 ONE。
這兩種狀態是完全互斥的,所以如果要用數學式來表達,我們要使用正交向量(orthogonal vectors,內積為 0 的向量)來表達:
顯然,有些符號我們可能是第一次見到。首先我們就來看看 |
and ⟩
。它們是狄拉克(Dirac)引入的狄狄拉克符號(bra-ket notation),是量子力學中用來描述量子態的的標準符號系統。在這裡是為了表示跟純量的 0
和 1
是不同的。
如果你不熟悉向量,你可以想像它是一組我們使用固定規則操作的數值列表。如果你熟悉向量,就會明白向量很適合用來描述具有大小和方向的數值。
我們來描述一個比 |0⟩
和 |1⟩
更複雜的向量:
要了解這個狀態所代表的意義,我們需要使用一些數學規則來處理這個向量。具體來說,我們需要知道如何將向量相加與乘上一個純量。
如果我們要把兩組向量相加,我們可以把他們相同位置的元素加總:
如果將向量乘上一個純量,我們就是把向量中的每一個元素都乘以該純量值。
所以我們得到 |q_0⟩
的結果可以寫成以下表示:
由於 |0⟩
和 |1⟩
是正交向量,所以我們可以用它們來表達任何二維向量。這允許了我們寫出以下表達量子位元的狀態:
|q_0⟩
就被稱為量子位元的狀態向量。它告訴了我們關於量子位元我們可能需要知道的一切。現在,我們可以對於以上示例的量子狀態向量做出一個簡單的結論:它就不是完全的 |0⟩
、也不是完全的 |1⟩
,它是兩者的線性組合!
而這樣同時包含兩者的線性組合狀態向量,我們通常就稱之為『疊加態』(superposition)。
1.3 使用 Qiskit 探索量子位元
首先,我們匯入所有我們需要的套件。
from qiskit import QuantumCircuit, assemble, Aer
from qiskit.visualization import plot_histogram, plot_bloch_vector
from math import sqrt, pi
在 Qiskit 中,我們使用 QuantumCircuit
儲存我們的電路。
qc = QuantumCircuit(1) # Create a quantum circuit with one qubit
在我們的量子電路中,量子位元初始狀態總是從 |0⟩
開始。我們可以透過 initialize()
來將其轉換成任何狀態。
qc = QuantumCircuit(1) # Create a quantum circuit with one qubit
initial_state = [0, 1] # Define initial_state as |1>
qc.initialize(initial_state, 0) # Apply initialisation operation to the 0th qubit
qc.draw() # Let's view our circuit
Output:
接著,我們可以使用 Qiskit 的模擬器來查看量子位元的最終狀態。
sim = Aer.get_backend("aer_simulator") # Tell Qiskit how to simulate our circuit
qc = QuantumCircuit(1) # Create a quantum circuit with one qubit
initial_state = [0, 1] # Define initial_state as |1>
qc.initialize(initial_state, 0) # Apply initialisation operation to the 0th qubit
qc.save_statevector() # Tell simulator to save statevector
qobj = assemble(qc) # Create a Qobj from the circuit for the simulator to run
result = sim.run(qobj).result() # Do the simulation and return the result
out_state = result.get_statevector()
print(out_state) # Display the output state vector
Output:
Statevector([0.+0.j, 1.+0.j],
dims=(2,))
(備註:Python 中是使用 j
來代表複數 i
的,我們會發現在這個二維狀態向量依然可以簡寫成 [0, 1])
現在我們來看看電路。
qc.measure_all()
qc.draw()
Output:
這一次,我們使用 .get_counts()
來取得 0
和 1
的計數、而非狀態向量。
qobj = assemble(qc)
result = sim.run(qobj).result()
counts = result.get_counts()
plot_histogram(counts)
Output:
我們毫不意外地取得了 1
,當然這跟我們設定的初始狀態有關。如果大家還記得的話,在前幾章我們有提過,若將量子位元的初始值設為 1
的話,我們將永遠測得 1
的結果(0
反之亦同。)
那麼我們現在來做個有趣的實驗。我們將量子位元的初始值設定為『疊加態』!
sim = Aer.get_backend("aer_simulator") # Tell Qiskit how to simulate our circuit
qc = QuantumCircuit(1) # Create a quantum circuit with one qubit
initial_state = [1/sqrt(2), 1j/sqrt(2)]
qc.initialize(initial_state, 0) # Apply initialisation operation to the 0th qubit
qc.save_statevector() # Tell simulator to save statevector
qobj = assemble(qc) # Create a Qobj from the circuit for the simulator to run
result = sim.run(qobj).result() # Do the simulation and return the result
out_state = result.get_statevector()
print(out_state) # Display the output state vector
Output:
Statevector([0.70710678+0.j , 0. +0.70710678j],
dims=(2,))
qc.measure_all()
qc.draw()
Output:
qobj = assemble(qc)
result = sim.run(qobj).result()
counts = result.get_counts()
plot_histogram(counts)
Output:
我們會發現 |0⟩
和 |1⟩
幾乎擁有相等的機率!為什麼會這樣呢?要解釋這件事情,我們需要談談測量(measurement)這件事。
2. 測量規則
2.1 重要的規則
測量有一個非常簡單的規則。如果我們要測得 |ψ⟩
在 |x⟩
中,我們可以使用以下方式計算:
符號 ⟨
和 |
告訴我們 ⟨x|
是一個行向量(row vector),而 |
和 ⟩
告訴我們 |ψ⟩
是一個列向量(column vector)。
在量子力學中,我們稱行向量為 bras、列向量為 kets。它們之間構成了狄拉克符號(bra-ket notation)。而一個行向量是可以通過共軛轉置(conjugate transpos)轉換成列向量的。共軛轉置在轉換帶有複數的矩陣時需要特別注意和實矩陣不同的地方。
而矩陣相乘的計算方法不只一種,在這裡我們都採用所謂的內積/點積(inner product / dot product)來計算。我們可以把這種計算想像成行向量(row vector)和列向量(column vector)的運算。
與上面的公式相同,我們可以把 |x⟩
視為任何一種量子位元的狀態。如果我們要計算 |x⟩
的狀態,我們可以計算 |x⟩
和我們要測量的狀態 |ψ⟩
之間的內積。
假設我們要計算 |q_0⟩
在 |0⟩
狀態的機率值,我們可以這樣進行計算:
你可以自行驗證 |1⟩
狀態的機率值。
2.2 規則的含義
#1 正規化(Normalization)
規則告訴我們,振幅(amplitudes)與機率是有關聯的。如果我們希望機率值加總等於 1,也就是『人類所理解的機率的定義』,我們需要確認狀態向量經過了正規化處理。
實際上,若是我們在 Qiskit 當中初始化一個未正規化的向量,我們也會收到錯誤。請參考:
vector = [1,1]
qc.initialize(vector, 0)
我們會確實收到錯誤訊息 QiskitError: 'Sum of amplitudes-squared does not equal one.'
。
下面是三個關於 Qiskit 的例題:
- Create a state vector that will give a
1/3
probability of measuring|0⟩
. - Create a different state vector that will give the same measurement probabilities.
- Verify that the probability of measuring
|1⟩
for these two states is2/3
.
目前我是把初始值設定為:
initial_state = [1/sqrt(3), sqrt(2)*1j/sqrt(3)]
initial_state = [1j/sqrt(3), sqrt(2)/sqrt(3)]
不知道這樣算不算完成題目需求呢?但我驗證過,|1⟩
的機率值應該都是 2/3 左右。 Textbook 底下本來應該有個測試的函式,但是我無論是在網頁上還是本地端都跑不起來。所以如果有錯誤的話,再麻煩轉告我了。
#2 替代測量
測量規則讓我們在測量 |x⟩
的 |ψ⟩
狀態測得其機率值,它並沒有限制我們狀態值只為為 |0⟩
或是 |1⟩
。目前為止,我們考慮的測量方法僅僅只是測量量子位元的一種方式;對於任何正交的狀態對(pair of states),我們可以定義一個測量方法讓量子位元只能選擇其中一種。
#3 共同相位(Global Phase)
我們能確認 |1⟩
的結果一定是 1
,我們也能將其寫成下面的狀態:
要查看其行為,我們仍要用剛才提過的測量規則:
這裡我們會發現,複數 i
在計算過程中自然消失了。這個影響完全獨立於測量狀態 |x⟩
,無論我們正在測量何種狀態, i|1⟩
和 |1⟩
都是相等的。由於這是我們從量子位元中提取資訊的唯一方式,所以我們可以將其視為在物理層面等價。
同俗來講,我們所參考的所有商(factor, 我不確定這裡能不能翻譯、理解為係數)γ
在 |γ|=1
時被稱為共同相位(Global Phase);而僅有共同相位不同的狀態在物理層面上是無法區分的。像是以下的公式:
需要注意的是,這是疊加態的相位差不同,後者被稱為相對相位(Relative Phase)。
#4 觀察者效應(The Observer Effect)
我們知道振幅包含著我們找到特定狀態的量子位元資訊的機率,但是一但我們測量了量子位元,我們就可以確定量子位元的狀態。
比方說,我們觀察一個量子位元:
然後我們發現它是處於 |0⟩
的狀態。接著我們再觀察一次,我們會 100% 發現量子位元仍然處於 |0⟩
。這代表我們的觀測結果會改變量子位元的狀態。
我們將其稱之為『坍塌』(collapsing)量子位元的狀態。這是一個有力的影響,必須謹慎地使用。試想一個情況,如果我們不斷地觀測量子位元,量子位元總是呈現 0 或是 1,那麼在使用起來就跟傳統電腦一模一樣了,我們的計算方式可以很簡單地被傳統電腦取代。
為了實現真正的量子計算(quantum computing),我們必須讓量子位元做更複雜的事。
這就是為什麼測量狀態總是放在電路的末端,因為只有我們要提取結果時才會使用。
我們可以使用 Qiskit 的狀態向量模擬器來 demo。首先我們宣告一個處於疊加態的量子位元。
qc = QuantumCircuit(1) # We are redefining qc
initial_state = [0.+1.j/sqrt(2), 1/sqrt(2)+0.j]
qc.initialize(initial_state, 0)
qc.draw()
Output:
這應該將我們的量子位元初始化成了:
from qiskit.providers.aer.library import save_statevector
sim = Aer.get_backend("aer_simulator") # Tell Qiskit how to simulate our circuit
qc.save_statevector()
result = sim.run(assemble(qc)).result()
state = result.get_statevector()
print(f"Qubit State = {state}")
Output:
Qubit State = Statevector([0. +0.70710678j, 0.70710678+0.j ],
dims=(2,))
現在量子位元的狀態是我們的初始狀態,正如我們的想像。接下來我們嘗試看看抽取最終測量結果後的狀態。
qc = QuantumCircuit(1) # We are redefining qc
initial_state = [0.+1.j/sqrt(2), 1/sqrt(2)+0.j]
qc.initialize(initial_state, 0)
qc.measure_all()
qc.save_statevector()
qc.draw()
Output:
可以看到我們的電路會測量最後的結果。
qobj = assemble(qc)
state = sim.run(qobj).result().get_statevector()
print(f"State of Measured Qubit = {state}")
Output:
State of Measured Qubit = Statevector([0.+0.j, 1.+0.j],
dims=(2,))
你會發現,量子位元已經坍塌了,它的狀態永遠不再是疊加態了。
不過在使用真正的量子電腦進行運算時,我們永遠無法看到中間的計算狀態,因為這將讓量子位元坍塌。不過這不利於學習,所以 Qiskit 提供了不同的模擬器,讓我們可以嘗試理解量子計算的中間過程。
3. 布洛赫球面(The Bloch Sphere)
3.1 受限制量子位元狀態的描述
在本文稍早,我們看到都是量子位元的一般狀態。
第二行的意思是 α
和 β
皆屬於複數(conplex numbers)。由於我們無法測量共同相位,所以我們只能測量 |0⟩
和 |1⟩
的不同。我們可以把它們都限制在實數域並多添加一個項來表達它們之間的相對相位。
當然,我們也要對 α
、β
進行正規化。
我們可以寫成三角恆等式(trigonometric identity),也就是寫成 sin
跟 cos
。
我們可通過 θ
這個變數來描述 α
和 β
:
到最後,我們就能使用 ϕ
和 θ
來描述任何量子位元的狀態了。
3.2 量子位元狀態的視覺化
下面我們來視覺化量子位元的一般狀態。
如果我們能把 ϕ
和 θ
當作球面座標,我們可以在一個被稱為布洛赫球面(Bloch Sphere)的球體面積上繪製代表任何量子位元的狀態。
from qiskit.visualization import plot_bloch_vector
coords = [1, pi/2, 0] # [Radius, Theta(θ), Phi(Φ)]
plot_bloch_vector(coords, coord_type="spherical")
Output:
請注意!在第一次接觸『量子位元狀態』時,很容易跟『狀態向量』(statevectors)搞混。狀態向量是在 1.1 中討論的向量,它包含量子位元可能包含兩個狀態的振幅;而 Bloch 向量則是一種可視化工具,把二維複雜狀態向量映射到三維真實空間。