import scipy as sp
import numpy as np
import scipy.sparse as sparse
import scipy.sparse.linalg as sla
import matplotlib.pyplot as plt
%matplotlib inline
def hnorm(r):
"""define ||r||_h = h ||r||_2"""
n = len(r)
h = 1.0 / (n+1)
hrnorm = h * np.linalg.norm(r)
return hrnorm
def poissonop(n):
A = (n+1)**2 * sparse.diags([-1, 2, -1], [-1, 0, 1], shape=(n,n), format='csr')
return A
def relax(A, u, f, nu):
n = A.shape[0]
Dinv = 1.0 / (2.0 * (n+1)**2)
omega = 2.0 / 3.0
for steps in range(nu):
u += omega * Dinv * (f - A * u)
def interpolate(uc):
"""interpolate u of size 2**(k-1)-1 to 2**(k)-1"""
nc = len(uc)
nf = 2**(int(np.log2(nc+1))+1)-1
uf = np.zeros((nf,))
I = np.arange(1,nf,2)
uf[I-1] = 0.5 * uc
uf[I] = uc
uf[I+1] += 0.5 * uc
return uf
def restrict(uf):
"""restrict u of size 2**(k)-1 to 2**(k-1)-1"""
nf = len(uf)
nc = 2**(int(np.log2(nf+1))-1)-1
uc = np.zeros((nc,))
I = np.arange(1,nf,2)
uc = 0.25 * uf[I-1] + 0.5 * uf[I] + 0.25 * uf[I+1]
return uc
k=3
nc = 2**(k-1)-1
nf = 2**(k)-1
xc = np.linspace(0,1,nc+2)[1:-1]
xf = np.linspace(0,1,nf+2)[1:-1]
uc = np.sin(xc*np.pi)
uf = interpolate(uc)
plt.plot(xc, uc, 'b-o', clip_on=False)
plt.plot(xf, uf, 'g--s')
plt.axis([0,1,0,1])
uf = np.sin(xf*np.pi)
uc = restrict(uf)
plt.plot(xc, uc, 'b-o')
plt.plot(xf, uf, 'g--s')
k = 12
n = 2**k - 1
print("size = %d" % n)
u = np.random.rand(n)
xx = np.linspace(0,1,n+2)[1:-1]
#f = np.random.rand(n)#np.pi**2 * np.sin(np.pi*xx)
A = poissonop(n)
f = A * np.random.rand(n)
ustar = sla.spsolve(A, f)
plt.plot(ustar)
print(hnorm(f - A * u))
relax(A, u, f, 1)
rc = restrict(f - A * u)
Ac = poissonop(len(rc))
ec = sparse.linalg.spsolve(Ac, rc)
ef = interpolate(ec)
u = u + ef
relax(A, u, f, 1)
print(hnorm(f - A * u))
ustar = sla.spsolve(A, f)
plt.plot(ustar)
u = np.random.rand(n)
res = [(1.0 / (n+1)) * np.linalg.norm(f - A * u)]
print("res[0] = %g"%res[-1])
for cycle in range(10):
relax(A, u, f, 10)
rc = restrict(f - A * u)
ec = sparse.linalg.spsolve(poissonop(len(rc)), rc)
ef = interpolate(ec)
u = u + ef
relax(A, u, f, 10)
res.append((1.0 / (n+1)) * np.linalg.norm(f - A * u))
print("res[%d] = %g"%(cycle+1,res[-1]))
res = np.array(res)
res[1:]/res[:-1]
plt.plot(u)