Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
allendowney
GitHub Repository: allendowney/cpython
Path: blob/main/Modules/_decimal/libmpdec/literature/matrix-transform.txt
12 views
1
2
3
(* Copyright (c) 2011-2020 Stefan Krah. All rights reserved. *)
4
5
6
The Matrix Fourier Transform:
7
=============================
8
9
In libmpdec, the Matrix Fourier Transform [1] is called four-step transform
10
after a variant that appears in [2]. The algorithm requires that the input
11
array can be viewed as an R*C matrix.
12
13
All operations are done modulo p. For readability, the proofs drop all
14
instances of (mod p).
15
16
17
Algorithm four-step (forward transform):
18
----------------------------------------
19
20
a := input array
21
d := len(a) = R * C
22
p := prime
23
w := primitive root of unity of the prime field
24
r := w**((p-1)/d)
25
A := output array
26
27
1) Apply a length R FNT to each column.
28
29
2) Multiply each matrix element (addressed by j*C+m) by r**(j*m).
30
31
3) Apply a length C FNT to each row.
32
33
4) Transpose the matrix.
34
35
36
Proof (forward transform):
37
--------------------------
38
39
The algorithm can be derived starting from the regular definition of
40
the finite-field transform of length d:
41
42
d-1
43
,----
44
\
45
A[k] = | a[l] * r**(k * l)
46
/
47
`----
48
l = 0
49
50
51
The sum can be rearranged into the sum of the sums of columns:
52
53
C-1 R-1
54
,---- ,----
55
\ \
56
= | | a[i * C + j] * r**(k * (i * C + j))
57
/ /
58
`---- `----
59
j = 0 i = 0
60
61
62
Extracting a constant from the inner sum:
63
64
C-1 R-1
65
,---- ,----
66
\ \
67
= | r**k*j * | a[i * C + j] * r**(k * i * C)
68
/ /
69
`---- `----
70
j = 0 i = 0
71
72
73
Without any loss of generality, let k = n * R + m,
74
where n < C and m < R:
75
76
C-1 R-1
77
,---- ,----
78
\ \
79
A[n*R+m] = | r**(R*n*j) * r**(m*j) * | a[i*C+j] * r**(R*C*n*i) * r**(C*m*i)
80
/ /
81
`---- `----
82
j = 0 i = 0
83
84
85
Since r = w ** ((p-1) / (R*C)):
86
87
a) r**(R*C*n*i) = w**((p-1)*n*i) = 1
88
89
b) r**(C*m*i) = w**((p-1) / R) ** (m*i) = r_R ** (m*i)
90
91
c) r**(R*n*j) = w**((p-1) / C) ** (n*j) = r_C ** (n*j)
92
93
r_R := root of the subfield of length R.
94
r_C := root of the subfield of length C.
95
96
97
C-1 R-1
98
,---- ,----
99
\ \
100
A[n*R+m] = | r_C**(n*j) * [ r**(m*j) * | a[i*C+j] * r_R**(m*i) ]
101
/ ^ /
102
`---- | `---- 1) transform the columns
103
j = 0 | i = 0
104
^ |
105
| `-- 2) multiply
106
|
107
`-- 3) transform the rows
108
109
110
Note that the entire RHS is a function of n and m and that the results
111
for each pair (n, m) are stored in Fortran order.
112
113
Let the term in square brackets be f(m, j). Step 1) and 2) precalculate
114
the term for all (m, j). After that, the original matrix is now a lookup
115
table with the mth element in the jth column at location m * C + j.
116
117
Let the complete RHS be g(m, n). Step 3) does an in-place transform of
118
length n on all rows. After that, the original matrix is now a lookup
119
table with the mth element in the nth column at location m * C + n.
120
121
But each (m, n) pair should be written to location n * R + m. Therefore,
122
step 4) transposes the result of step 3).
123
124
125
126
Algorithm four-step (inverse transform):
127
----------------------------------------
128
129
A := input array
130
d := len(A) = R * C
131
p := prime
132
d' := d**(p-2) # inverse of d
133
w := primitive root of unity of the prime field
134
r := w**((p-1)/d) # root of the subfield
135
r' := w**((p-1) - (p-1)/d) # inverse of r
136
a := output array
137
138
0) View the matrix as a C*R matrix.
139
140
1) Transpose the matrix, producing an R*C matrix.
141
142
2) Apply a length C FNT to each row.
143
144
3) Multiply each matrix element (addressed by i*C+n) by r**(i*n).
145
146
4) Apply a length R FNT to each column.
147
148
149
Proof (inverse transform):
150
--------------------------
151
152
The algorithm can be derived starting from the regular definition of
153
the finite-field inverse transform of length d:
154
155
d-1
156
,----
157
\
158
a[k] = d' * | A[l] * r' ** (k * l)
159
/
160
`----
161
l = 0
162
163
164
The sum can be rearranged into the sum of the sums of columns. Note
165
that at this stage we still have a C*R matrix, so C denotes the number
166
of rows:
167
168
R-1 C-1
169
,---- ,----
170
\ \
171
= d' * | | a[j * R + i] * r' ** (k * (j * R + i))
172
/ /
173
`---- `----
174
i = 0 j = 0
175
176
177
Extracting a constant from the inner sum:
178
179
R-1 C-1
180
,---- ,----
181
\ \
182
= d' * | r' ** (k*i) * | a[j * R + i] * r' ** (k * j * R)
183
/ /
184
`---- `----
185
i = 0 j = 0
186
187
188
Without any loss of generality, let k = m * C + n,
189
where m < R and n < C:
190
191
R-1 C-1
192
,---- ,----
193
\ \
194
A[m*C+n] = d' * | r' ** (C*m*i) * r' ** (n*i) * | a[j*R+i] * r' ** (R*C*m*j) * r' ** (R*n*j)
195
/ /
196
`---- `----
197
i = 0 j = 0
198
199
200
Since r' = w**((p-1) - (p-1)/d) and d = R*C:
201
202
a) r' ** (R*C*m*j) = w**((p-1)*R*C*m*j - (p-1)*m*j) = 1
203
204
b) r' ** (C*m*i) = w**((p-1)*C - (p-1)/R) ** (m*i) = r_R' ** (m*i)
205
206
c) r' ** (R*n*j) = r_C' ** (n*j)
207
208
d) d' = d**(p-2) = (R*C) ** (p-2) = R**(p-2) * C**(p-2) = R' * C'
209
210
r_R' := inverse of the root of the subfield of length R.
211
r_C' := inverse of the root of the subfield of length C.
212
R' := inverse of R
213
C' := inverse of C
214
215
216
R-1 C-1
217
,---- ,---- 2) transform the rows of a^T
218
\ \
219
A[m*C+n] = R' * | r_R' ** (m*i) * [ r' ** (n*i) * C' * | a[j*R+i] * r_C' ** (n*j) ]
220
/ ^ / ^
221
`---- | `---- |
222
i = 0 | j = 0 |
223
^ | `-- 1) Transpose input matrix
224
| `-- 3) multiply to address elements by
225
| i * C + j
226
`-- 3) transform the columns
227
228
229
230
Note that the entire RHS is a function of m and n and that the results
231
for each pair (m, n) are stored in C order.
232
233
Let the term in square brackets be f(n, i). Without step 1), the sum
234
would perform a length C transform on the columns of the input matrix.
235
This is a) inefficient and b) the results are needed in C order, so
236
step 1) exchanges rows and columns.
237
238
Step 2) and 3) precalculate f(n, i) for all (n, i). After that, the
239
original matrix is now a lookup table with the ith element in the nth
240
column at location i * C + n.
241
242
Let the complete RHS be g(m, n). Step 4) does an in-place transform of
243
length m on all columns. After that, the original matrix is now a lookup
244
table with the mth element in the nth column at location m * C + n,
245
which means that all A[k] = A[m * C + n] are in the correct order.
246
247
248
--
249
250
[1] Joerg Arndt: "Matters Computational"
251
http://www.jjj.de/fxt/
252
[2] David H. Bailey: FFTs in External or Hierarchical Memory
253
http://crd.lbl.gov/~dhbailey/dhbpapers/
254
255
256
257
258