This commit is contained in:
Steven G. Johnson 2023-04-28 20:13:13 -04:00
parent f5f6d49454
commit b4dcc299cd
2 changed files with 133 additions and 1 deletions

View File

@ -333,7 +333,6 @@ http://dx.doi.org/10.1137/S1052623499362822) — I used the "linear and separabl
* [(Discrete) convolutions](https://en.wikipedia.org/wiki/Convolution#Discrete_convolution), translation-invariance, [circulant matrices](https://en.wikipedia.org/wiki/Circulant_matrix), and convolutional neural networks (CNNs)
* [pset 5 solutions](psets/pset5sol.ipynb)
* pset 6: coming soon, due Friday May 5.
**Further reading:** Strang textbook sections IV.2 (circulant matrices) and VII.2 (CNNs), and [OCW lecture 32](https://ocw.mit.edu/courses/18-065-matrix-methods-in-data-analysis-signal-processing-and-machine-learning-spring-2018/resources/lecture-32-imagenet-is-a-cnn-the-convolution-rule/). See also these [Stanford lecture slides](http://cs231n.stanford.edu/slides/2016/winter1516_lecture7.pdf) and [MIT lecture slides](https://mit6874.github.io/assets/sp2020/slides/L03_CNNs_MK2.pdf).
@ -352,6 +351,8 @@ http://dx.doi.org/10.1137/S1052623499362822) — I used the "linear and separabl
## Lecture 32 (Apr 25)
* [pset 6](psets/pset6.ipynb): due Friday May 5.
Fourier series vs. DFT: If we view the DFT as a [Riemann sum](https://en.wikipedia.org/wiki/Riemann_sum) approximation for a [Fourier series](https://en.wikipedia.org/wiki/Fourier_series) coefficient (which turns out to be *exponentially* accurate for smooth periodic f(t)!), then the errors are an instance of [aliasing](https://en.wikipedia.org/wiki/Aliasing) (see e.g. the ["wagon-wheel" effect](https://en.wikipedia.org/wiki/Wagon-wheel_effect)). For band-limited signals where we sample at a rate > twice the bandwidth, there is no aliasing and no information loss, a result known as the [Nyquist—Shannon sampling theorem](https://en.wikipedia.org/wiki/Nyquist%E2%80%93Shannon_sampling_theorem); in the common case where the bandwidth is centered at ω=0, this corresponds to sampling at more than *twice* the highest frequency.
**Further reading**: For a periodic function, a Riemann sum is equivalent to a trapezoidal rule (since the 0th and Nth samples are identical), and the exponential convergence to the integral is reviewed by [Trefethen and Weideman (2014)](https://epubs.siam.org/doi/pdf/10.1137/130932132); SGJ gave a [simplified review for IAP (2011)](https://math.mit.edu/~stevenj/trap-iap-2011.pdf). The subject of aliasing, sampling, and signal processing leads to the field of [digital signal processing (DSP)](https://en.wikipedia.org/wiki/Digital_signal_processing), on which there are many books and courses. A classic textbook is [*Discrete-Time Signal Processing*](https://research.iaun.ac.ir/pd/naghsh/pdfs/UploadFile_2230.pdf) by Oppenheim and Schafer, and there are whole courses at MIT (like 6.3000 and 6.7000) on these topics.

131
psets/pset6.ipynb Normal file
View File

@ -0,0 +1,131 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "a65bff2e",
"metadata": {},
"source": [
"# 18.065 Problem Set 6\n",
"\n",
"Due Friday May 5."
]
},
{
"cell_type": "markdown",
"id": "46c6dd3c",
"metadata": {},
"source": [
"## Problem 1 (10+10 points)\n",
"\n",
"**(a)** In class, we showed that if $\\tilde{y} = \\bar{F} y, \\tilde{a} = \\bar{F} a, \\tilde{x} = \\bar{F} x$ where $F$ is the DFT matrix, then $y = a \\circledast x$ (circular convolution) implies $\\tilde{y} = \\tilde{a} \\, \\mbox{.*} \\, \\tilde{x}$ (element-wise product). Show that the reverse is also true: show that if $\\tilde{y} = \\tilde{a} \\circledast \\tilde{x}$, then $y = a \\, \\mbox{.*} \\, x$. \n",
"\n",
"**(b)** Differentiating through convolutions, in class, involved the \"reversal\" permutation $R$:\n",
"$$\n",
"R\\begin{pmatrix} x_0 \\\\ x_1 \\\\ x_2 \\\\ \\vdots \\\\ x_{N-1} \\end{pmatrix}\n",
"=\\begin{pmatrix} x_0 \\\\ x_{N-1} \\\\ x_{N-2} \\\\ \\vdots \\\\ x_1 \\end{pmatrix}\n",
"$$\n",
"What happens when we combine this with a DFT, e.g. to apply the convolution theorem? Show that $FRx = \\bar{F}x$.\n",
"\n",
"(This is illustrated by the code below: `fft(x)` computes $Fx$ and `bfft(x)` computes $\\bar{F}x$ using the [FFTW.jl package](https://github.com/JuliaMath/FFTW.jl).)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e1ce6605",
"metadata": {},
"outputs": [],
"source": [
"using FFTW\n",
"R(x) = [x[begin]; x[end:-1:begin+1]] # compute R*x\n",
"x = rand(20)\n",
"fft(R(x)) ≈ bfft(x)"
]
},
{
"cell_type": "markdown",
"id": "fc26407d",
"metadata": {},
"source": [
"## Problem 2 (10+10+10 points)\n",
"\n",
"Think way back to grade school, when you learned to multiply two numbers $a_{N_a-1} \\cdots a_2 a_1 a_0 \\times x_{N_x-1} \\cdots x_2 x_1 x_0$, where $a_k$ and $x_k$ are the **decimal digits** of two numbers with $N_a$ and $N_x$ digits, respectively. (That is, $x_{N_x-1} \\cdots x_2 x_1 x_0 = \\sum_k {10}^k x_k$.)\n",
"\n",
"**(a)** Show that, if you ignore carries (i.e. you allow \"digits\" $> 9$) then the *result* $ y_{N_y-1} \\cdots y_2 y_1 y_0$ is in fact a **convolution** of the digits $y = a \\ast x$, but *not* a cyclic convolution — there is no \"wraparound\". (What is $N_y$?)\n",
"\n",
"**(b)** Show that you can write your previous answer as a *cyclic* convolution simply by \"padding\" $a,x,y$ with zeros. That is, if you add some zeros to each of them (in the right place) to extend them to a common length $N$ (what must $N$ be?), then $\\mbox{pad}(y,N) = \\mbox{pad}(a,N) \\circledast \\mbox{pad}(x,N)$.\n",
"\n",
"**(c)** Write Julia code to compute\n",
"$$\n",
"\\underbrace{94403147635990179114}_a \\times \\underbrace{33855185913241354461}_x \\\\\n",
"= \\underbrace{3196036114011618584561027454963352927554}_y\n",
"$$\n",
"by:\n",
"* Implement the function `pad(x,N)` to zero-pad as in part (b)\n",
"* Implement a function `conv(a,x)` to perform a circular convolution using $Fx =$ `fft(x)` and $\\bar{F}x =$ `bfft(x)`. (You may want to call `round.(Int,real(y))` on the result to discard tiny roundoff errors, since the final values should be integers).\n",
"* Implement a function `carry(y)` to perform the carries: any \"digits\" larger than $10$ should have the tens place \"carried\" to the next digit etc. (You may find the [`divrem` function](https://docs.julialang.org/en/v1/base/math/#Base.divrem) useful to divide by 10 and find a remainder.)\n",
"Check that you get the right answer: `bignum(carry(y)) == 3196036114011618584561027454963352927554`."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9ac00a3f",
"metadata": {},
"outputs": [],
"source": [
"using FFTW\n",
"\n",
"a = [4, 1, 1, 9, 7, 1, 0, 9, 9, 5, 3, 6, 7, 4, 1, 3, 0, 4, 4, 9]\n",
"x = [1, 6, 4, 4, 5, 3, 1, 4, 2, 3, 1, 9, 5, 8, 1, 5, 5, 8, 3, 3]\n",
"\n",
"bignum(x) = evalpoly(BigInt(10), x)\n",
"@show bignum(a)\n",
"@show bignum(x)\n",
"@show bignum(a) * bignum(x)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bdcd7ae6",
"metadata": {},
"outputs": [],
"source": [
"pad(x, N) = ...\n",
"conv(x,y) = ..."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "53f03b79",
"metadata": {},
"outputs": [],
"source": [
"function carry(y)\n",
" ...\n",
"end"
]
}
],
"metadata": {
"@webio": {
"lastCommId": null,
"lastKernelId": null
},
"kernelspec": {
"display_name": "Julia 1.8.3",
"language": "julia",
"name": "julia-1.8"
},
"language_info": {
"file_extension": ".jl",
"mimetype": "application/julia",
"name": "julia",
"version": "1.8.5"
}
},
"nbformat": 4,
"nbformat_minor": 5
}