Sparse sampling#
In this page, we describe how to infer IR expansion coefficients using the sparse-sampling techiniques.
using SparseIR
using Plots
gr() # USE GR backend
using OMEinsum
using LaTeXStrings
Setup#
We consider a semicircular spectral modeli (full bandwidth of 2):
First, we compute the numerically exact expansion coefficients \(g_l\). Below, we plot the data for even \(l\).
function rho(omega)
return abs.(omega) < 1 ? (2/π) .* sqrt.(1-omega^2) : 0.0
end
beta = 10000.0
wmax = 1.0
eps = 1e-15 # cutoff for SVD
basis = FiniteTempBasis(Fermionic(), beta, wmax, eps)
rhol = overlap(basis.v, rho, -wmax, wmax)
gl = - basis.s .* rhol
ls = collect(0:length(basis)-1)
p = plot(marker=:x, yaxis=:log, ylabel=L"|g_l|", xlabel=L"l", ylims=(1e-15,10))
plot!(p, ls[1:2:end], abs.(gl[1:2:end]), marker=:x, yaxis=:log, ylabel=L"|g_l|", xlabel=L"l")
From sampling times#
We first create a TauSampling
object for the default sampling times.
smpl_tau = TauSampling(basis)
println("sampling times: ", smpl_tau.sampling_points)
println("Condition number: ", SparseIR.cond(smpl_tau))
sampling times:
[-4776.409486578611, -4333.600190763889, -3903.489199194745, -3493.245653743826, -3108.383597604443, -2752.5682814454813, -2427.695275407337, -2134.1542045122974, -1871.177146717915, -1637.191623041102, -1430.1294543119957, -1247.6709717638912, -1087.4231696403858, -947.0404299720082, -824.2999960143404, -717.1441939083734, -623.6995557013647, -542.2807084296066, -471.38476923572756, -409.6802519273501, -355.9931760732771, -309.2921218873168, -268.6733148680698, -233.34637878568486, -202.62110258773114, -175.895379252628, -152.64435851651936, -132.41078679801288, -114.79647003097338, -99.45477716380103, -86.08409590177001, -74.42215209472636, -64.24110556933593, -55.34333491259758, -47.557820265420325, -40.737027934796274, -34.754197984991904, -29.50094144826054, -24.88507029347886, -20.828608291441064, -17.26595749197979, -14.14221593762588, -11.41165361439711, -9.036355822161779, -6.985039124735026, -5.2320383801574, -3.7564568454939717, -2.5414665603407105, -1.573743570455477, -0.8430214467258779, -0.34174300046152517, -0.06472594109241392, 0.06472594109241392, 0.34174300046152517, 0.8430214467258779, 1.573743570455477, 2.5414665603407105, 3.7564568454939717, 5.2320383801574, 6.985039124735026, 9.036355822161779, 11.41165361439711, 14.14221593762588, 17.26595749197979, 20.828608291441064, 24.88507029347886, 29.50094144826054, 34.754197984991904, 40.737027934796274, 47.557820265420325, 55.34333491259758, 64.24110556933593, 74.42215209472636, 86.08409590177001, 99.45477716380103, 114.79647003097338, 132.41078679801288, 152.64435851651936, 175.895379252628, 202.62110258773114, 233.34637878568486, 268.6733148680698, 309.2921218873168, 355.9931760732771, 409.6802519273501, 471.38476923572756, 542.2807084296066, 623.6995557013647, 717.1441939083734, 824.2999960143404, 947.0404299720082, 1087.4231696403858, 1247.6709717638912, 1430.1294543119957, 1637.191623041102, 1871.177146717915, 2134.1542045122974, 2427.695275407337, 2752.5682814454813, 3108.383597604443, 3493.245653743826, 3903.489199194745, 4333.600190763889, 4776.409486578611]
Condition number: 51.83054439165606
The condition number is around 50, indicating that 1–2 significant digits may be lost in a fit from the sampling times. Let us fit from the sampling times!
# Evaluate G(τ) on the sampling times
gtau_smpl = evaluate(smpl_tau, gl)
plot(smpl_tau.sampling_points, gtau_smpl, marker=:x, xlabel=L"\tau", ylabel=L"G(\tau)")
# Fit G(τ) on the sampling times
gl_reconst_from_tau = fit(smpl_tau, gtau_smpl)
104-element Vector{Float64}:
-0.650908727340739
-1.338225836712941e-15
-0.5874748878888262
1.3695074512696427e-15
-0.26969535847287207
-1.9578894941739274e-15
-0.0835854838782452
1.9272339873209483e-15
-0.016527848807111743
-1.729808707768798e-15
0.0010656038792227435
8.291129978211573e-16
0.0034739976272110716
⋮
3.2770100572267654e-15
1.3402349443904298e-15
-1.2498256757532159e-15
-4.685982175431994e-16
-1.2646059134169163e-17
-8.894144560217121e-16
2.6201674318333993e-15
6.566518723049898e-16
-1.6388828778699829e-15
3.3961263499320843e-16
1.6368816880478648e-16
-3.919841327018492e-15
From sampling frequencies#
We create a MatsubaraSampling
object for the default sampling frequencies.
smpl_matsu = MatsubaraSampling(basis)
println("sampling frequencies: ", smpl_matsu.sampling_points)
println("Condition number: ", SparseIR.cond(smpl_matsu))
sampling frequencies: FermionicFreq
[FermionicFreq(-44377), FermionicFreq(-14981), FermionicFreq(-8743), FermionicFreq(-6213), FermionicFreq(-4765), FermionicFreq(-3733), FermionicFreq(-3089), FermionicFreq(-2523), FermionicFreq(-2093), FermionicFreq(-1797), FermionicFreq(-1513), FermionicFreq(-1315), FermionicFreq(-1117), FermionicFreq(-975), FermionicFreq(-859), FermionicFreq(-729), FermionicFreq(-623), FermionicFreq(-547), FermionicFreq(-469), FermionicFreq(-411), FermionicFreq(-361), FermionicFreq(-309), FermionicFreq(-267), FermionicFreq(-233), FermionicFreq(-205), FermionicFreq(-177), FermionicFreq(-153), FermionicFreq(-133), FermionicFreq(-115), FermionicFreq(-101), FermionicFreq(-87), FermionicFreq(-75), FermionicFreq(-65), FermionicFreq(-57), FermionicFreq(-49), FermionicFreq(-43), FermionicFreq(-37), FermionicFreq(-33), FermionicFreq(-29), FermionicFreq(-25), FermionicFreq(-23), FermionicFreq(-21), FermionicFreq(-19), FermionicFreq(-17), FermionicFreq(-15), FermionicFreq(-13), FermionicFreq(-11), FermionicFreq(-9), FermionicFreq(-7), FermionicFreq(-5), FermionicFreq(-3), FermionicFreq(-1), FermionicFreq(1), FermionicFreq(3), FermionicFreq(5), FermionicFreq(7), FermionicFreq(9), FermionicFreq(11), FermionicFreq(13), FermionicFreq(15), FermionicFreq(17), FermionicFreq(19), FermionicFreq(21), FermionicFreq(23), FermionicFreq(25), FermionicFreq(29), FermionicFreq(33), FermionicFreq(37), FermionicFreq(43), FermionicFreq(49), FermionicFreq(57), FermionicFreq(65), FermionicFreq(75), FermionicFreq(87), FermionicFreq(101), FermionicFreq(115), FermionicFreq(133), FermionicFreq(153), FermionicFreq(177), FermionicFreq(205), FermionicFreq(233), FermionicFreq(267), FermionicFreq(309), FermionicFreq(361), FermionicFreq(411), FermionicFreq(469), FermionicFreq(547), FermionicFreq(623), FermionicFreq(729), FermionicFreq(859), FermionicFreq(975), FermionicFreq(1117), FermionicFreq(1315), FermionicFreq(1513), FermionicFreq(1797), FermionicFreq(2093), FermionicFreq(2523), FermionicFreq(3089), FermionicFreq(3733), FermionicFreq(4765), FermionicFreq(6213), FermionicFreq(8743), FermionicFreq(14981), FermionicFreq(44377)]
Condition number:
210.8802635675065
The condition number is slightly larger than that for the sampling times.
# Evaluate G(iv) on the sampling frequencies
giv_smpl = evaluate(smpl_matsu, gl)
# `value` function evaluate the actual values of Matsubara frequencies
plot(SparseIR.value.(smpl_matsu.ωn, beta), imag.(giv_smpl), marker=:x, xlabel=L"\nu", ylabel=L"\mathrm{Im} G(i\nu)")
# Fit G(τ) on the sampling times
gl_reconst_from_matsu = fit(smpl_matsu, giv_smpl)
104-element Vector{Float64}:
-0.6509087273407396
5.696809823311181e-17
-0.5874748878888254
-1.9424372960240556e-17
-0.2696953584728692
9.545156116936036e-18
-0.08358548387824333
-1.553568520472352e-17
-0.01652784880710962
2.6881129533915344e-17
0.0010656038792250314
-8.644305416405723e-18
0.003473997627211692
⋮
1.4623718902484484e-15
6.331295039952252e-18
1.2750217548429532e-15
-2.8552898099140756e-18
1.5846698953048133e-15
-4.0291256253345e-18
1.4623718902484484e-15
4.793136846831369e-18
1.4324479102878485e-15
-9.498850162071637e-19
7.825771281000371e-16
-8.066482798586065e-18
Comparison with exact results#
We now compare the reconstructed expansion coefficients with the exact one. For clarity, we plot only the data for even \(l\).
p = plot(xlabel=L"l", ylabel=L"g_l", ylims=(1e-17, 10), yaxis=:log)
plot!(p, ls[1:2:end], abs.(gl[1:2:end]), marker=:none, label="Exact")
plot!(p, ls[1:2:end], abs.(gl_reconst_from_tau[1:2:end]), marker=:x, label="from sampling times")
plot!(p, ls[1:2:end], abs.(gl_reconst_from_matsu[1:2:end]), marker=:+, label="from sampling frequencies")
We saw a perfect match! Let us plot the differences from the exact one.
p = plot(xlabel=L"L", ylabel=L"Error in $g_l$", ylims=(1e-18, 10), yaxis=:log)
plot!(p, ls[1:2:end], abs.((gl_reconst_from_tau-gl)[1:2:end]), marker=:x, label="from sampling times")
plot!(p, ls[1:2:end], abs.((gl_reconst_from_matsu-gl)[1:2:end]), marker=:+, label="from sampling frequencies")