In [1]:
from IPython.html.services.config import ConfigManager
from IPython.utils.path import locate_profile
cm = ConfigManager(profile_dir=locate_profile(get_ipython().profile))
cm.update('livereveal', {
'theme': 'sky',
'transition': 'zoom',
'start_slideshow_at': 'selected',
})
Out[1]:
Books on integral equations
Recall the basic integral equation from electrostatics:
$$\int_{\Omega} \frac{q(y) dy}{\Vert x - y \Vert} = f(x).$$We can actually compute the anti-derivative of the integral in question, but taking successive integrals
$$ \frac{1}{\sqrt{x^2 + y^2}} $$\begin{equation} \begin{split} F(x, y) = \int \int \frac{1}{\sqrt{x^2 + y^2}} dx dy = \\ -y + y \log(x + \sqrt{x^2 + y^2}) + x \log(y + \sqrt{x^2 + y^2}), \end{split} \end{equation}and the final integral is just $$ I(x_0, y_0, x_1, y_1) = F(x_0, y_0) + F(x_1, y_1) - F(x_0, y_1) - F(x_1, y_0), $$
(generalization of the Newton-Leibniz formula)
In [ ]:
import sympy
from sympy import Symbol, sqrt
x = Symbol('x', real=True)
a = Symbol('a', real=True)
y = Symbol('y', real=True)
b = Symbol('b', real=True)
r = sqrt(x ** 2 + y ** 2)
sympy.init_printing()
z = sympy.integrate(1/r, x, conds='none')
print z
A Nystrom method is a popular choice: replace the integral by quadrature
probably by the simplest one: the rectangle formula,
which in 1D has the form
$$I(f) = \sum_{k=0}^n w_k f(x_k), $$where $x_k$ is the uniform grid on the interval, $w_0 = w_n = h/2, \quad w_k = h$ for all other $k$.
$$A_{ij} = \frac{1} {\Vert x_i - y_j \Vert} h^2,$$
the set $x_i$ can be called receivers and the set $y_j$ can be called sources ;
A typical way is to shift the grid by half-step, i.e. in 1D it will be
$$ A_{ij} = \frac{1}{|i-j| + \frac{1}{2}}. $$ By the way, do you remember, what is the rank of this matrix?
You can be a little bit smarter: approximate $1/r$ by something that can be well-integrated.
By a sum of separable functions!
$$\frac{1}{\Vert x - y\Vert } \approx \sum_{\alpha=1}^r u_{\alpha}(x) u_{\alpha}(y)$$We have used the symmetry.
But how to compute these functions $u_{\alpha}$? (why it is useful?)
We reduced the problem to the problem of creating a good quadrature rule for the integral
$$\int^{\infty}_0 \frac{e^{-px}}{\sqrt{p}} dp$$You have to do the $p = e^t$ (why do we do so?) and we the new integral
$$ \int^{\infty}_{-\infty} e^{-e^{t} x + t/2} dt $$and this integral is then approximate by trapezoidal rule $t_k = a_t + k h_t, \quad h_t = (b_t - a_t)/K$
The integral is doubly exponentially decaying, and also its Fourier transform is decaying exponentially fast.
Thus, trapezoidal rule has exponential convergence in this setting
A short demo...
In [6]:
import numpy as np
import math
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(style='ticks', palette='Set2')
sns.despine()
%matplotlib inline
a = -10
b = 20
n = 70
t = np.linspace(a, b, n)
h = t[1] - t[0]
w = np.ones(n) * h
w[0] = h/2
w[n-1] = h/2
w = w * np.exp(0.5 * t)/np.sqrt(math.pi)
ps = np.exp(t)
x = np.linspace(0.1, 1)
fun = 1.0/np.sqrt(x)
appr = 0 * x
for i in xrange(n):
appr = appr + w[i] * np.exp(-(x) * ps[i])
#plt.plot(x, fun)
ax = plt.subplot(1, 1, 1)
ax.plot(x, appr - fun)
#ax.set_title('Approximation error by %d Gaussians' % n)
ax.set_title('Error')
plt.tight_layout(.8)
The Helmholtz equation has the form
$$\Delta u + k^2 u = f,$$and it describes the propagation of scalar waves (acoustic wave).
$k$ is called wavenumber.
The fundamental solution (the one that gives $\delta$-function after the application of the operator) has the form
$$K(r) = \frac{\exp(i k r)}{r}.$$So it oscillates.
A demo
In [7]:
import numpy as np
import matplotlib.pyplot as plt
n = 128
a = [[1.0/(abs(i - j) + 0.5) for i in xrange(n)] for j in xrange(n)]
a = np.array(a)
plt.plot(np.linalg.svd(a)[1])
Out[7]:
In [8]:
#And for a block:
plt.semilogy(np.linalg.svd(a[:n/2, n/2:])[1])
Out[8]:
In [10]:
from numba import jit
n = 32
t = np.linspace(0, 1, n)
h = t[1] - t[0]
x_src, y_src = np.meshgrid(t, t)
x_src, y_src = x_src.flatten(), y_src.flatten()
x_rec, y_rec = x_src + h * 0.5, y_src + 0.5 * h
N = n * n
mat = np.zeros((N, N))
@jit(nopython=True)
def compute_mat(mat, x_src, y_src, x_rec, y_rec):
for i in range(N):
for j in xrange(N):
r = (x_src[i] - x_rec[j]) ** 2 + (y_src[i] - y_rec[j]) ** 2
mat[i, j] = 1.0/np.sqrt(r)
%timeit compute_mat(mat, x_src, y_src, x_rec, y_rec)
#(x_rec - x_src)/h
Plotting the singular values of the off-diagonal block shows that they do not decay that fast.
Why? Because they correspond to the non-separated sets of sources and receivers.
In [11]:
plt.semilogy(np.linalg.svd(mat[:N/2, N/2:])[1])
Out[11]:
This is the basis for the Barnes-Hut method (original work in astronomy)
and the preliminary approach to the Fast Multipole Method , proposed by Greengard and Rokhlin
In [2]:
from IPython.core.display import HTML
def css_styling():
styles = open("./styles/alex.css", "r").read()
return HTML(styles)
css_styling()
Out[2]:
In [ ]: