Skip to content

Commit babdd57

Browse files
committed
Move over code
1 parent f04f7da commit babdd57

File tree

3 files changed

+255
-0
lines changed

3 files changed

+255
-0
lines changed

Project.toml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
name = "MultivariateSingularIntegrals"
2+
uuid = "afb3ad05-8577-40d5-8767-20c5aa8ee3cd"
3+
authors = ["Sheehan Olver <[email protected]>"]
4+
version = "0.1.0"
5+
6+
[deps]
7+
ClassicalOrthogonalPolynomials = "b30e2e7b-c4ee-47da-9d5f-2c5c27239acd"
8+
FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b"
9+
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
10+
SingularIntegrals = "d7440221-8b5e-42fc-909c-0567823f424a"
11+
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
12+
13+
[compat]
14+
ClassicalOrthogonalPolynomials = "0.15.1"
15+
FillArrays = "1.13.0"
16+
LinearAlgebra = "1.11.0"
17+
SingularIntegrals = "0.3.8"
18+
Test = "1.11.0"

src/MultivariateSingularIntegrals.jl

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
module MultivariateSingularIntegrals
2+
using LinearAlgebra, ClassicalOrthogonalPolynomials, SingularIntegrals, FillArrays
3+
import Base: size
4+
5+
export logkernelsquare, logkernelsquare!
6+
7+
"""
8+
L₀₀(z) = ∫_{-1}^1∫_{-1}^1 log(z-(s+im*t))dsdt
9+
"""
10+
L₀₀(z) = (1-z)*M0(z-1) + im*M1(z-1) + (1+z)*M0(z+1) - im*M1(z+1) - 4
11+
12+
#computes [a b; c d] \ [1,0]
13+
@inline function twobytwosolve_1(a, b, c, d)
14+
dt = inv(muladd(a,d,-b*c))
15+
d*dt, -c*dt
16+
end
17+
18+
#computes [a b; c d] \ [0, 1]
19+
@inline function twobytwosolve_2(a, b, c, d)
20+
dt = inv(muladd(a,d,-b*c))
21+
-b*dt, a*dt
22+
end
23+
24+
25+
26+
27+
"""
28+
biforwardsub!(M, A, B, R1, R2)
29+
30+
finds `X` such that `A*X + im*X*B' = R1` and `B*X + im*X*A' = R2`
31+
"""
32+
function biforwardsub!(M, z, A, B, R1, R2)
33+
m,n = size(M)
34+
begin
35+
# fill out first row
36+
a,b = twobytwosolve_2(A[1,2], B[1,2], im*B[1,2], im*A[1,2])
37+
M[1,2] = ((a+b)*z- (a+im*b)*(A[1,1]-im*B[1,1]))*M[1,1] - a*R1[1,1] - b*R2[1,1]
38+
for j = 2:n-1
39+
a,b = twobytwosolve_2(A[1,2], B[1,2], im*B[j,j+1], im*A[j,j+1])
40+
M[1,j+1] = ((a+b)*z - a*A[1,1] + b*B[1,1])*M[1,j] - im*(a*B[j,j-1] + b*A[j,j-1])*M[1,j-1] - a*R1[1,j] - b*R2[1,j]
41+
end
42+
43+
# fill out first column
44+
a,b = twobytwosolve_1(A[1,2], B[1,2], im*B[1,2], im*A[1,2])
45+
M[2,1] = ((a+b)*z- (a+im*b)*(A[1,1]-im*B[1,1]))*M[1,1] - a*R1[1,1] - b*R2[1,1]
46+
for k = 2:m-1
47+
a,b = twobytwosolve_1(A[k,k+1], B[k,k+1], im*B[1,2], im*A[1,2])
48+
M[k+1,1] = ((a+b)*z - im*(a*B[1,1] + b*A[1,1]))*M[k,1] - (a*A[k,k-1] + b*B[k,k-1])*M[k-1,1] - a*R1[k,1] - b*R2[k,1]
49+
end
50+
51+
# fill out 2nd column from first
52+
for k = 2:m
53+
a,b = twobytwosolve_2(A[k,k+1], B[k,k+1], im*B[1,2], im*A[1,2])
54+
M[k,2] = (a+b)*z*M[k,1] - (a*A[k,k-1] + b*B[k,k-1])*M[k-1,1] - (im*a*B[1,1] + im*b*A[1,1])*M[k,1] - a*R1[k,1] - b*R2[k,1]
55+
end
56+
57+
# fill out rest, column-by-column
58+
for k = 2:m, j = 2:n-1
59+
a,b = twobytwosolve_2(A[k,k+1], B[k,k+1], im*B[j,j+1], im*A[j,j+1])
60+
M[k,j+1] = (a+b)*z*M[k,j] - (a*A[k,k-1] + b*B[k,k-1])*M[k-1,j] - (im*a*B[j,j-1] + im*b*A[j,j-1])*M[k,j-1]- a*R1[k,j] - b*R2[k,j]
61+
end
62+
end
63+
64+
M
65+
end
66+
67+
function m_const_vec(n, z)
68+
(x,y) = reim(z)
69+
T = float(real(typeof(z)))
70+
if x > 0 || y 1 || (x == 0 && !signbit(x) && y < 0) # need to treat im*y+0.0 differently
71+
[im*convert(T,π); Zeros{T}(n-1)]
72+
elseif y -1
73+
[-3im*convert(T,π); Zeros{T}(n-1)]
74+
else # x ≤ 0 && -1 ≤ y ≤ 1
75+
r = Weighted(Jacobi{T}(1,1))[y,1:n-1]
76+
[((1 + y) - 3*(1-y))/2*im*convert(T,π); -im .* convert(T,π) .* r ./ (1:(n-1))]
77+
end
78+
end
79+
80+
function imlogkernel_vec(n, z)
81+
T = float(real(typeof(z)))
82+
transpose(complexlogkernel(Legendre{T}(), -im*float(z)))[1:n] + m_const_vec(n, float(z))
83+
end
84+
85+
function rec_rhs_k!(R, z)
86+
n = size(R,1)
87+
T = float(real(typeof(z)))
88+
P = Legendre{T}()
89+
x = axes(P,1)
90+
Mm1 = imlogkernel_vec(n+1, z+1)
91+
fill!(R, zero(T))
92+
R[1,1] = -2im*Mm1[2] +2*(z+1)*Mm1[1]-4
93+
R[2,1] = -convert(T,4)/3
94+
for j = 1:n-1
95+
R[1,j+1] = - 2im * convert(T,j+1)/(2j+1) * Mm1[j+2] + 2*(1+z)*Mm1[j+1] - 2im * convert(T,j)/(2j+1) * Mm1[j]
96+
end
97+
R
98+
end
99+
100+
rec_rhs_j!(R, z) = -1 real(z) 1 && -1 imag(z) 1 ? rec_rhs_j_insquare!(R, z) : rec_rhs_j_offsquare!(R, z)
101+
102+
103+
zlog(z) = iszero(z) ? zero(z) : z*log(z)
104+
105+
L0(z) = zlog(1 + complex(z)) - zlog(complex(z)-1) - 2one(z)
106+
L1(z, r0=L0(z)) = (z+1)*r0/2 + 1 - zlog(complex(z)+1)
107+
108+
M0(z) = L0(-im*float(z)) + m_const(0, float(z))
109+
M1(z, r0=L0(-im*z)) = L1(-im*float(z), r0) + m_const(1, float(z))
110+
111+
function m_const(k, z)
112+
(x,y) = reim(z)
113+
T = float(real(typeof(z)))
114+
im*convert(T,π) * if k == 0
115+
if x > 0 || y 1 || (x == 0 && !signbit(x) && y < 0) # need to treat im*y+0.0 differently
116+
convert(T, 1)
117+
elseif y -1 # x ≤ 0
118+
convert(T, -3)
119+
else # x ≤ 0 and -1 < y < 1
120+
((1 + y) - 3*(1-y))/2
121+
end
122+
elseif -1 y 1 && x 0 # k ≠ 0
123+
-Weighted(Jacobi{T}(1,1))[y,k]/k
124+
else
125+
zero(T)
126+
end
127+
end
128+
129+
130+
function rec_rhs_j_offsquare!(R, z)
131+
n = size(R,1)
132+
x,y = reim(z)
133+
T = float(real(typeof(z)))
134+
P = Legendre{T}()
135+
Lm1 = transpose(complexlogkernel(P, z+im))[1:n+1] # transpose makes col-vector, works around slowess
136+
μ = m_const_vec(n, z)
137+
fill!(R, zero(T))
138+
R[1,1] = - 2Lm1[2] - 4im*m_const(1,z)+ 2*(z+im)*(M0(1-im*z) + m_const0(z)) - 4im
139+
R[1,2] = -(convert(T,4)*im)/3 + 2x*m_const(1, z)
140+
for j = 3:n
141+
R[1,j] = 2x*μ[j]
142+
end
143+
R[2,1] = - convert(T,4)/3 * Lm1[3] - convert(T,2)/3 *M0(1-im*z) - convert(T,2)/3 *m_const0(z) + 2*(z+im)*Lm1[2]
144+
for j = 2:n
145+
R[2,j] = -2μ[j]/3
146+
end
147+
for k = 2:n-1
148+
R[k+1,1] = 2(im+z)*Lm1[k+1] - convert(T,2k)/(2k+1)*Lm1[k] - convert(T,2(k+1))/(2k+1)*Lm1[k+2]
149+
end
150+
R
151+
end
152+
153+
154+
155+
# averages the difference between M(k,z-s) and L(k,-im*(z-s))
156+
function m_const_square_0_vec(z, Wx)
157+
x,y = reim(z)
158+
T = float(typeof(x))
159+
n = length(Wx)
160+
[im*convert(T,π)*((1+x) + (1-x) * ((1 + y) - 3*(1-y))/2);
161+
(im*convert(T,π)* (-1 + ((1 + y) - 3*(1-y))/2)) .* Wx ./ (2*(1:n))]
162+
end
163+
164+
165+
function rec_rhs_j_insquare!(R, z)
166+
n = size(R,1)
167+
T = float(real(typeof(z)))
168+
x,y = reim(z)
169+
W = Weighted(Jacobi{T}(1,1))
170+
P = Legendre{T}()
171+
Wy = W[y,1:n-1]
172+
Wx = W[x,1:n]
173+
Vx = Weighted(Jacobi{T}(2,2))[x,1:n-2]
174+
Lm1 = transpose(complexlogkernel(P, z+im))[1:n+1] # transpose makes col-vector, works around slowess
175+
πT = convert(T, π)
176+
μ0 = m_const_square_0_vec(z, Wx)
177+
178+
R[3:end,2:end] .= (im * πT) .*Vx ./ (2 .* (2:n-1) .* (1:(n-2))) .* (Wy ./ (2 .* (1:n-1)))'
179+
for k = 2:n-1
180+
R[k+1,1] = - convert(T,2k)/(2k+1) * Lm1[k] + 2im*Lm1[k+1] - convert(T,2(k+1))/(2k+1) * Lm1[k+2] +
181+
- convert(T,k+1)/(2k+1) * μ0[k+2] - convert(T,k)/(2k+1) * μ0[k] +
182+
2z*Lm1[k+1] + (z+im)*μ0[k+1] - Wx[k]/k * πT*Wy[1]
183+
end
184+
for j = 2:n
185+
R[2,j] = (im*πT/6 * (x^2 + x - 2)*(x-1)) * Wy[j-1] / (j-1)
186+
end
187+
for j = 3:n
188+
R[1,j] = (im*πT*(x-1)^2) * Wy[j-1] / (2*(j-1))
189+
end
190+
R[1,2] = -convert(T,4)im/3 + im*πT*(1-x)^2/2 * Wy[1]
191+
R[2,1] = -4Lm1[3]/3 - 2μ0[3]/3 - 2M0(1-im*z)/3 - μ0[1]/3 - πT*Wx[1] * Wy[1] + 2*(z+im)*Lm1[2] + (z+im)*μ0[2]
192+
R[1,1] = -2Lm1[2] - μ0[2] + 2(z+im)*M0(1-im*z) - 2*πT*(1-x)*W[y,1] + (z+im)*μ0[1] - 4im
193+
R
194+
end
195+
196+
197+
198+
struct LogKernelSquareData{T}
199+
A::Tridiagonal{T, Vector{T}}
200+
B::Tridiagonal{T, Vector{T}}
201+
X::Matrix{Complex{T}}
202+
F::Matrix{Complex{T}} # A*X + im*X*B' == F
203+
G::Matrix{Complex{T}} # B*X + im*X*A' == G
204+
end
205+
206+
size(L::LogKernelSquareData, k...) = size(L.X, k...)
207+
208+
function LogKernelSquareData{T}(n) where T
209+
A = Tridiagonal((zero(T):n-1) ./ (3:2:(2n+1)), [-1; zeros(T, n)], (convert(T,2):(1+n)) ./ (1:2:(2n)))
210+
B = Tridiagonal((one(T):n) ./ (3:2:(2n+1)), zeros(T, n+1), (one(T):n) ./ (1:2:(2n)))
211+
X = Matrix{Complex{T}}(undef, n, n)
212+
F = Matrix{Complex{T}}(undef, n, n)
213+
G = Matrix{Complex{T}}(undef, n, n)
214+
LogKernelSquareData(A, B, X, F, G)
215+
end
216+
217+
LogKernelSquareData(n) = LogKernelSquareData{Float64}(n)
218+
219+
logkernelsquare(z, n) = logkernelsquare!(LogKernelSquareData{float(real(typeof(z)))}(n), z)
220+
function logkernelsquare!(data, z)
221+
R1 = rec_rhs_k!(data.F, z)
222+
R2 = rec_rhs_j!(data.G, z)
223+
224+
data.X[1,1] = L₀₀(z)
225+
biforwardsub!(data.X, z, data.A, data.B, R1, R2)
226+
end
227+
228+
end # module MultivariateSingularIntegrals

test/runtests.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using MultivariateSingularIntegrals, Test
2+
3+
z = 0.1 + 0.1im
4+
n = 10
5+
logkernelsquare(z, n)
6+
7+
8+
9+
logkernelsquare(big(z), n)

0 commit comments

Comments
 (0)