數論轉換

来自testwiki
跳转到导航 跳转到搜索

Template:NoteTA

數論轉換是一種計算摺積的快速演算法。計算摺積的快速演算法中最常用的一種是使用快速傅里葉變換,然而快速傅立葉變換具有一些實現上的缺點,舉例來說,資料向量必須乘上複數係數的矩陣加以處理,而且每個複數係數的實部和虛部是一個正弦餘弦函數,因此大部分的係數都是浮點數,也就是說,必須做複數而且是浮點數的運算,因此計算量會比較大,而且浮點數運算產生的誤差會比較大。

而在數論轉換中,資料向量需要乘上的矩陣是一個整數的矩陣,因此不需要作浮點數的乘法運算,更進一步,在模數為M的情況下,只有M2種可能的加法與M2種可能的乘法,這可以使用記憶體把這些有限數目的加法和乘法存起來,利用查表法來計算,使得數論轉換完全不須任何乘法與加法運算,不過需要較大的記憶體與消耗較大的存取記憶體量。

雖然使用數論轉換可以降低計算摺積的複雜度,不過由於只進行整數的運算,所以只能用於對整數的信號計算摺積,而利用快速傅立葉變換可以對任何複數的信號計算摺積,這是降低運算複雜度所要付出的代價。

轉換公式

數論轉換的轉換式為

F[k]=n=0N1f[n]αnk(modM)k=0,1,2,,N1

而數論轉換的反轉換式為

f[n]=N1k=0N1F[k]αnk(modM)n=0,1,2,,N1

註解:

(1) M是一個質數

(2) (modM) 表示除以M的餘數

(3) N必須是M1因數。(當N1NM互質)

(4)N1N對模數M模反元素

(5)α為模M的N階單位根,即αN=1(modM)而且αk1(modM) k=1,2,,N1。若此時N=M1,我們稱α為模M的原根

舉一個例子:

一個M=5N=4點數論轉換與反轉換如下,取α=2,注意此時N1=4

正轉換 (F[0]F[1]F[2]F[3])=(1111124314141342)(f[0]f[1]f[2]f[3])(modM)

反轉換 (f[0]f[1]f[2]f[3])=(4444421341414312)(F[0]F[1]F[2]F[3])(modM)

數論轉換的性質

(1) 正交性質

數論轉換矩陣的每個列是互相正交的,即n=0N1αnlαnk={Nif k=l0if kl(modM)

(2) 對稱性

f[n]=f[Nn],則f[n]的數論轉換F[k]也會有F[k]=F[Nk]的特性。

f[n]=f[Nn],則f[n]的數論轉換F[k]也會有F[k]=F[Nk]的特性。

(3) 反數論轉換可由正數論轉換實現

f[n]=N1k=0N1F[k]αnk=N1k=0N1F[k]αnk,即N1F[k]的數論轉換。

步驟一:把F[k]改寫成F[k],若F[k]=F0,F1,,F2,FN1,則F[k]=F0,FN1,,F2,F1

步驟二:求F[k]的數論轉換。

步驟三:乘上N1

(4) 線性性質

f[n]F[k]g[n]G[k],(表互為數論轉換對)則有af[n]+bg[n]aF[k]+bg[k](modM)

(5) 平移性質

f[n]F[k],則f[n+l]αlkF[k](modM),而且f[n]αnlF[k+l]

(6) 圓周摺積性質

f[n]F[k]g[n]G[k],則f[n]g[n]F[k]G[k](modM),而且f[n]g[n]1NF[k]G[k](modM)。(代表圓形摺積。)

這個性質是數論轉換可以用來作為摺積的快速演算法的主要原因。

(7) 帕塞瓦爾定理(Parseval's Theorem)

f[n]F[k],則Nn=0N1f[n]f[n]=k=0N1F2[k](modM),而且Nn=0N1f2[n]=k=0N1F[k]F[k](modM)

快速數論轉換

如果轉換點數N是一個2的次方,則可以使用類似基數-2快速傅立葉變換的蝴蝶結構來有效率的實現數論轉換。同樣的互質因子算法也可以應用在數論轉換上。

F[k]=n=0N1f[n]αnk =r=0N/21f[2r]α2rk+r=0N/21f[2r+1]α(2r+1)k =r=0N/21f[2r](α2)rk+αkr=0N/21f[2r+1](α2)rk ={G[k]+αkH[k]0kN21G[kN2]αkH[kN2]N2kN1

其中,G[k]=r=0N/21f[2r](α2)rkH[k]=r=0N/21f[2r+1](α2)rk。 因此一個N點數論轉換可以拆解成兩個N2點的數論轉換。

N, M, alpha的選擇

由於數論轉換可以擁有類似快速傅立葉變換的快速演算法,因此通常N會選擇適合使用快速演算的值,比如說取為2的次,或是可以分解成許多小質數相乘的數。

在數論轉換中,需要大量地和α的冪次做乘法,因此,如果可以取α為2或2的冪次,則每一次的乘法在二進制中只會是一個移位的操作,可以省下大量的乘法運算。

因為要做模M的運算,所以M的二進位表示法中,1的個數越少越好,同時M的值不能取太小,這是因為數論轉換後的值都小於M,因此當真實的摺積的結果會大於M時就會發生錯誤,所以必須謹慎選取M的大小。

特殊的數論轉換

梅森質數數論轉換

梅森質數是指形如2p1的質數記做Mp,其中p是一個質數。

在梅森質數數論轉換中,取M=Mp,可以證明α,N可以如下選取:

(1) α=2,N=p,N1=MpMp1p

(2) α=2,N=2p,N1=MpMp12p

在這兩種選取方式下,由於α是2的冪次,所以只需移位運算,但N不是2的冪次,所以基數-2的蝴蝶結構不適用於此例中,同時N為質數或一個質數的兩倍,並不是一個可以拆解成很多質因數乘積的數,因此也無法由互質因子演算法得到太大的好處。梅森質數數論轉換通常用於較短序列的摺積運算

費馬數數論轉換

費馬數是指形如22t+1的數記做Ft

在費馬數數論轉換中,取M=Ft,可以證明在0<t4之下α,N可以如下選取:

(1) α=2,N=2t+1

(2) α=3,N=Ft1

在這兩種選取方式下,N是2的冪次,所以基數-2的蝴蝶結構適用於此例中,而若α是2的冪次,只需移位運算。費馬數數論轉換通常用於較長序列的摺積運算。

實作議題

由於數論轉換需運用到餘數下的反元素,這邊提供一些不同的演算法。

(一) Euclidean algorithm - iterative version

假設M為質數的mod,N為我們當前的元素且符合M-1的因數,藉由Euclidean Algorithm知道必然存在x, y的整數使得

xM + yN = 1 - (1)

由上式左右mod M 可以得到 yN mod M= 1,顯然y就是我們這邊想求的反元素。

我們已知最大公因數(gcd)有如下性質。

gcd(M, N) = gcd(N, M mod N) = gcd(M mod N, N mod (M mod N)) = ... = 1

這邊設定q為商數,r為餘數,接上面的等式方程式化如下。

M=q0N+r1,

N=q1r1+r2,

r1=q2r2+r3,

r2=q3r3+r4,...

整理一下

Mq0N=r1,

Nq1r1=r2,

r1q2r2=r3,

r2q3r3=r4,...

最後的r 一定會變成1,所以我們只要不斷的將r乘上-q帶往下一個式子(像是r1*(-q1)),跟代往下下個式子(像是r3的左邊式子要帶入r1)即可求得最後我們想得到的 (1),最後的N旁的係數就是反元素。

def modInv(x, M): #by Euclidean algorithm - iterative version
    t, new_t, r, new_r = 0, 1, M, x

    while new_r != 0:
        quotient = int(r / new_r)
        tmp_new_t = new_t
        tmp_t = t
        tmp_new_r = new_r
        tmp_r = r
        t, new_t = new_t, (t - quotient * new_t)
        r, new_r = new_r, (r % new_r)
    if r > 1:
        print("Inverse doesn't exist")
    if t < 0:
        t = t + M
    return t

(二) Euclidean algorithm - recursion version

根據gcd的性質gcd(M, N) = gcd(N, M mod N) = gcd(M mod N, N mod (M mod N)) = ... = 1

可以看出遞迴的關係,藉此我們可以從這邊得到N的係數,也就是反元素。

gcd(M, N) = 1來看,我們知道存在xM+yN=1

gcd(N, M mod N)=1,則存在x1N+y1(MmodN)=1

x1N+y1(MmodN)=x1N+y1(Mq1N)=y1M+(x1q1y1)N=1

這邊q就是相除的商數,比較M跟N的係數,這邊可以得到一個遞迴關係,

(x1q1y1)=y

y1=x

可以藉由下一層的係數來推出上一層的係數。

def egcd(a, b): # y = x1 - quotient * y1  , x = y1 
    if a == 0:
        return (b, 0, 1)
    else:
        g, y, x = egcd(b % a, a)
        return (g, x - (b // a) * y, y)

def modInv(n, m): #by Euclidean algorithm - recursion version 
    g, y, x = egcd(n, m)
    if g != 1:
        print("Inverse doesn't exist")
    else:
        return y % m

(三) Fermat little theorem

當M是質數時,我們知道任何一個數字N,NM1modM=1

N(NM2modM)modM=1

顯然NM2modM就是N的反元素。

搭配快速mod可以容易的算出反元素,power是偶數時則可以用

(a2modM)power/2

; power是基數時則可以用

(aNmodM)power1

,讓power變成偶數。反覆直到power變成1。

def modInv(a, m): #fermat little thm
      return modExponent(a, m - 2, m)
      
def modExponent(base, power, M): #quick mod O(log(power))
    result = 1
    power = int(power)
    base = base % M
    while power > 0:
        if power & 1:
            result = (result * base) % M
        base = (base * base) % M
        power = power >> 1
    return result

演算法

以下程式預設。

import numpy as np

Root of Unity 是從1到M-1中選出一個適當的 alpha,其滿足"轉換公式"段落的(5)。

def RootOfUnity(N, M):
    def mod_exp(base, exp, mod):
        result = 1
        base %= mod
        while exp > 0:
            if exp % 2 == 1:  # If exp is odd
                result = (result * base) % mod
            base = (base * base) % mod
            exp //= 2
        return result

    for r in range(1, M):  # Check integers from 1 to M-1
        if mod_exp(r, N, M) == 1:
            return r  # Return the first root of unity
    return None
def NTT(x,N,M):
    alpha = RootOfUnity(N, M)
    NInv = modInv(N, M)
    A = np.ones((N,N))
    for i in range(1,N):
        for j in range(1,i+1):
          A[i][j] = A[i][j-1]*modExponent(alpha,i,M) % M
          A[j][i] = A[i][j]
    return np.matmul(A,x) % M, alpha
def invNTT(x,alpha,N,M):
    alphaInv = modInv(alpha, M)
    NInv = modInv(N, M)
    B = np.ones((N,N))
    for i in range(1,N):
        for j in range(1,i+1):
          B[i][j] = B[i][j-1]*modExponent(alphaInv,i,M) % M
          B[j][i] = B[i][j]
    B = B * NInv 
    return np.matmul(B,x) % M

參考資料

[1] R.C. Agarval and C.S. Burrus,"Number Theoretic Transforms to Implement Fast Digital Convolution," Proc. IEEE, vol.63, no.4, pp. 550-560, Apr. 1975.

[2] I. Reed and T.K. Truong,"The use of finite fileds to compute convolution," IEEE Trans. Info. Theory, vol.21 ,pp.208-213, Mar. 1975.