目錄
寫在前面
複數算法
種種原因,最近一年總是靜不下心來學一些東西。前些天在網上閒逛時,看到量子計算機的一些新聞,查找了一些資料,決定以量子計算為方向,進行學習。期間會將學習過程整理出來,分享給大家。
2019年,谷歌發布了53位量子計算機,號稱只用3分20秒,完成了世界第一超算Summit需要計算 1 萬年的實驗。微軟也發布了Horse Ridge量子計算控制晶片,有望解決目前原型機上百根控制線密布問題,為量子計算機小型化提供了希望。
學習路線是根據Microsoft上的【Microsoft Quantum 入門】一文進行,分為【量子計算概念入門】、【量子計算基礎知識】、【算法】、【協議和庫】幾個部分。期間代碼實現用的是Python,學習前掌握一些Python基礎,有助於理解本文。
理解複數算法,對於處理量子計算很重要。這裡,【複數算法】是學習量子計算的第一部分內容。
需要用到的數學知識:實數、虛數、複數的三角形式、複數的指數形式、複數的極坐標形式、複數的運算。
在一些特定情況下, 實數是不夠用的,例如:
在實數中,沒有x的解。在高等數學中,面對這樣的情況,引入了虛數單位,即。虛數單位為i,我們稱i的實數倍為虛數。
虛數有以下特點:
虛數相加很簡單,但如果是虛數和實數相加呢?這個加法的結果部分是實得,部分是虛的,也就是複數。
複數通常寫成兩部分的和:a + bi,其中a和b都是實數。例如3 + 4i或-5 + 7i都是有效的複數。注意,純實數或純虛數也可以寫成複數形式:2是2 + 0i,-3i是0 - 3i。
這裡我們先定義下複數和極坐標,後續會使用到。這裡,我沒用用tuple表示複數,其中第一個元素是實部,第二個元素是虛部。
from typing import Tupleimport mathComplex = Tuple[float, float]Polar = Tuple[float, float]
輸入:
1.複數x = a + bi,表示成一個元組(a, b)
2.複數y = c + di,表示成一個元組(c, d)
目標:
返回這兩個數字的和x+y=z=g+hi,表示為一個元組(g, h)。
兩複數相加就是,實部與實部相加,虛部與虛部相加,公式為:
用Python定義複數加法:
# 複數加法def complex_add(x: Complex, y: Complex) -> complex: a = x[0] b = x[1] c = y[0] d = y[1] # 分別求實部和虛部的值 real = a + c imaginary = b + d ans = (real, imaginary) return ans
輸入:
1.複數x = a + bi,表示成一個元組(a, b)
2.複數y = c + di,表示成一個元組(c, d)
目標:
返回這兩個數字的和,表示為一個元組(g, h)。
兩複數想成就像多項式相乘,公式為:
用Python定義複數乘法:
# 複數乘法# x = a + bi; y = c + di# x * y = a * (c + di) + b*(c + di) = a * c - b * d + (a * d + b * c)idef complex_mult(x: Complex, y: Complex) -> Complex: a = x[0] b = x[1] c = y[0] d = y[1] # 分別求實部和虛部的值 real = a * c - b * d imaginary = a * d + b * c ans = (real, imaginary) return ans
在學習其他的複數運算前,這裡先介紹下共軛複數。共軛是一個簡單的操作:一個複數,它的共軛複數是。如果將一個複數乘以它的共軛複數:
即一個複數乘以它的共軛複數會得到一個非負的實數。
共軛複數的另一個特性體現在加法和乘法上:
用Python定義複數轉換為共軛複數:
# 返回共軛複數def conjugate(x: Complex) -> Complex: a = x[0] b = x[1] # 共軛是實部相同,虛部相反,複數乘以共軛複數,虛部為0 ans = (a, -b) return ans
輸入:
1.複數x = a + bi,表示成一個元組(a, b)
2.複數y = c + di ≠ 0,表示成一個元組(c, d)
目標:
返回x除以y,x / y = (g + hi),表示為一個元組(g, h)。
利用共軛複數,我們可以把分母(0除外)轉換為實數。轉換過程如下:
通過這樣的轉換,我們使得分子變成了複數,分母變成了實數,即。這樣就變成了複數除以實數,用實部和虛部分別除以分母(實數)即可。
用Python定義複數的除法:
# 除法x / ydef complex_div(x: Complex, y: Complex) -> Complex: # 分子分母分別乘以y的共軛 num_ator = complex_mult(x, conjugate(y)) num_deno = complex_mult(y, conjugate(y)) # m為分子實部,n為分子虛部,r為分母實部(分母虛部為0) m = num_ator[0] n = num_ator[1] r = num_deno[0] # 分別求實部和虛部的值 real = m / r imaginary = n / r ans = (real, imaginary) return ans
實數可以用數軸來表示,數軸上的每個點代表一個實數。我們可以把這種表示擴展成實數和虛數,從而生成一個特殊的數軸:虛數軸,它只與實數軸在0處相交,這樣一個坐標系我們稱為複平面。
複數x = a + bi對應著複平面上的點(a, b),也對應複平面上的一個向量(如上圖所示)。這個向量的長度叫做複數a+bi的模,一般用字母r表示。同時這個向量針對x軸的正方向有一個方向角,我們稱為幅角,一般用希臘字母θ表示。
顯然,代入複數代數形式得:。
我們把叫做a+bi的三角形式。有時間的可以自己定義下複數三角形式下的運算。
三角形式下,複數的乘法「一部分」轉換成加法(模相乘,幅度相加),轉換公式如下:
除法遵從模相除,幅度相減,這裡不展開講解。
上述提到的向量的長度叫做複數x = a + bi的模,複數的模用r表示,求模的公式轉換如下:
用Python定義求模:
# 求模def modulus(x: Complex) -> Complex: a = x[0] b = x[1] ans = math.sqrt(a * a + b * b) return ans
根據歐拉公式可以推導出,具體證明過程我也沒有去了解,這裡也不展開講。有興趣的朋友可以自行查找資料。
需要用到的幾個等式,可以留個印象:
我們還可以計算自然常數e的複數冪,計算的轉換公式如下:
tip:可以轉換為模為1,幅度為b的三角形式的複數,即
用Python定義自然常數e的複數冪:
# 自然常數e的複數冪,x = a + bi ,輸出 e^x = g + hidef complex_exp(x : Complex) -> Complex: a = x[0] b = x[1] # e^x = e^(a+bi)= e^a * e^bi = e^a * (cos(b) + i*sin(b)) real = (math.e ** a) * math.cos(b) imaginary = (math.e ** a ) * math.sin(b) ans = (real, imaginary) return ans
輸入:
1.一個實數r
2.複數x = a + bi,表示成一個元組(a, b)
目標:
返回
用Python定義實數的複數冪:
# 實數的複數冪, x = a + bi, r^x = g + hidef complex_exp_real(r: float, x: Complex) -> Complex: a = x[0] b = x[1] # r^x = r^(a +bi) = r^a * r^bi = r^a * (cos(b) + i*sin(b)) real = r ** a * math.cos(b) imaginary = r ** a * math.sin(b) ans = (real, imaginary) return ans
已知表達式,如果我們把這個數映射到複平面上,它將落在一個圍繞0+0i的單位圓上,這意味著它的模總是1。利用這個事實,我們可以用極坐標表示複數,在極坐標系統中,複數,我們用兩個數字來表示,r表示長度,θ表示方向角,轉換為元組形式為(r, θ)。
輸入:
1.複數x = a + bi,表示成一個元組(a, b)
目標:
返回極坐標形式,表示成一個元組(r, θ)
用Python定義複數代數形式轉換為極坐標:
# 通過笛卡爾坐標求極坐標def polar_convert(x : Complex) -> Ploar: r = modulus(x) value_cos = x[0] / r degree = math.acos(value_cos) # 如果虛數為負,則θ為2π-θ if x[1] < 0: degree = 2 * math.pi - degree ans = (r, degree) return ans
輸入:
1.複數極坐標形式,表示成一個元組(r, θ)
目標:
返回極坐標形式x = a + bi,表示成一個元組(a, b)
用Python定義複數極坐標z形式轉換為代數形式:
# 通過極坐標求笛卡爾坐標def cartesian_convert(x : Ploar) -> Complex: a = x[0] * math.cos(x[1]) b = x[0] * math.sin(x[1]) ans = (a, b) return ans
輸入:
1.複數極坐標形式,表示成一個元組
2.複數極坐標形式,表示成一個元組
目標:
返回,表示成一個元組。注意,,
用Python定義極坐標的乘法:
# 極坐標乘法def ploar_mult(x : Ploar, y : Ploar) -> Ploar: r1 = x[0] r2 = y[0] degree1 = x[1] degree2 = y[1] r3 = r1 * r2 degree3 = degree1 + degree2 if degree3 >= 0: degree3 = degree3 % (2 * math.pi) else: degree3 = degree3 % (-2 * math.pi) ans = (r3, degree3) return ans
通過上述的學習,已經了解了很多複數相關的知識,下面嘗試定義複數的任意指數計算。
輸入:
1.複數x = a + bi,表示成一個元組(a, b)
2.複數y = c + di,表示成一個元組(c, d)
目標:
返回,表示成一個元組(g, h)
推導過程:
1.將x轉換為極坐標形式:
2.則
用Python定義複數的任意指數計算:
def complex_exp_arbitary(x : Complex, y : Complex) ->Complex: # x = a + bi, y = c + di, x^y = g + hi # polar_convert(x) -> (r, θ) -> x = r*e^θi -> x^y = (r*e^θi)^(c+di) = r^(c+di) * e^(-dθ+cθi) # Complex : x -> Ploar : x (r, θ) ploar_x = polar_convert(x) # tmp_v1 = r^(c+di) tmp_v1 = complex_exp_real(ploar_x[0], y) # tmp_v2 = -dθ+cθi tmp_v2 = (-y[1]*ploar_x[1], y[0]*ploar_x[1]) # tmp_v3 = e^(-dθ+cθi) tmp_v3 = complex_exp(tmp_v2) # Complex: x^y = r^(c+di) * e^(-dθ+cθi) = tmp_v1 * tmp_v3 ans_complex = complex_mult(tmp_v1, tmp_v3) ans = polar_convert(ans_complex) return ans