EC infrastructure refactored out to separate file
This commit is contained in:
parent
39b3da196c
commit
e123ae0eaf
|
|
@ -0,0 +1,110 @@
|
|||
using SparseArrays, LinearAlgebra, Arpack
|
||||
include("helper.jl")
|
||||
|
||||
"EC model for a Hamiltonian family H(c) = H0 + c * H1"
|
||||
mutable struct affine_EC
|
||||
H0::SparseMatrixCSC{ComplexF64}
|
||||
H1::SparseMatrixCSC{ComplexF64}
|
||||
weights::Vector{ComplexF64}
|
||||
trained::Bool
|
||||
|
||||
H0_EC
|
||||
H1_EC
|
||||
N_EC
|
||||
|
||||
training_E::Vector{ComplexF64}
|
||||
exact_E::Vector{ComplexF64}
|
||||
extrapolated_E::Vector{ComplexF64}
|
||||
|
||||
affine_EC(H0::SparseMatrixCSC{ComplexF64}, H1::SparseMatrixCSC{ComplexF64}, weights::Vector{ComplexF64}=ones(ComplexF64, size(H0, 1))) = new(H0, H1, weights, false, nothing, nothing, nothing, ComplexF64[], ComplexF64[], ComplexF64[])
|
||||
end
|
||||
|
||||
"Train an EC model for a given range of c values.
|
||||
If a list is provided for ref_eval, they are used as reference values for picking the closest eigenvalues at each sampling point.
|
||||
If a single number is provided for ref_eval, it is used as a reference for the first point, and the previous eigenvalue is used as the reference for each successive point.
|
||||
Set orthonormalize_threshold=0 to skip Gram-Schmidt orthonormalization and use GEVP. Otherwise this value is used as the threshold for dropping redundant vectors."
|
||||
function train!(EC::affine_EC, c_vals; ref_eval=nothing, orthonormalize_threshold=1e-5, CAEC=false, verbose=true, tol=1e-5)
|
||||
training_vecs = Vector{ComplexF64}[]
|
||||
current_E = -10.0 # randomly chosen reference value
|
||||
|
||||
for c in c_vals
|
||||
verbose && println("Training for c = $c")
|
||||
|
||||
if ref_eval isa Number
|
||||
current_E = ref_eval
|
||||
ref_eval = nothing
|
||||
elseif !isnothing(ref_eval)
|
||||
current_E = pop!(ref_eval)
|
||||
end
|
||||
|
||||
H = EC.H0 + c .* EC.H1
|
||||
|
||||
evals, evecs = eigs(H, sigma=current_E, maxiter=5000, tol=tol, ritzvec=true, check=1)
|
||||
current_E = nearest(evals, current_E)
|
||||
|
||||
push!(EC.training_E, current_E)
|
||||
push!(training_vecs, evecs[:, nearestIndex(evals, current_E)])
|
||||
end
|
||||
|
||||
CAEC && append!(training_vecs, conj.(training_vecs))
|
||||
|
||||
if orthonormalize_threshold ≠ 0
|
||||
training_vecs = gram_schmidt!(training_vecs, EC.weights, orthonormalize_threshold; verbose=verbose)
|
||||
end
|
||||
|
||||
EC_basis = hcat(training_vecs...)
|
||||
weights_mat = spdiagm(EC.weights)
|
||||
EC.H0_EC = transpose(EC_basis) * weights_mat * EC.H0 * EC_basis
|
||||
EC.H1_EC = transpose(EC_basis) * weights_mat * EC.H1 * EC_basis
|
||||
|
||||
if orthonormalize_threshold == 0
|
||||
EC.N_EC = transpose(EC_basis) * weights_mat * EC_basis
|
||||
end
|
||||
|
||||
EC.trained = true
|
||||
end
|
||||
|
||||
"Extrapolate using a train EC model for a given range of c values
|
||||
If a list is provided for ref_eval, they are used as reference values for picking the closest eigenvalues at each point.
|
||||
If a single number is provided for ref_eval, it is used as a reference for the first point, and the previous eigenvalue is used as the reference for each successive point."
|
||||
function extrapolate!(EC::affine_EC, c_vals; ref_eval=nothing, verbose=true, tol=1e-5)
|
||||
@assert EC.trained "EC model must be trained using train() before extrapolation"
|
||||
|
||||
current_E = -10.0 # randomly chosen reference value
|
||||
|
||||
for c in c_vals
|
||||
verbose && println("Extact solution for c = $c")
|
||||
|
||||
if ref_eval isa Number
|
||||
current_E = ref_eval
|
||||
ref_eval = nothing
|
||||
elseif !isnothing(ref_eval)
|
||||
current_E = pop!(ref_eval)
|
||||
end
|
||||
|
||||
H = EC.H0 + c .* EC.H1
|
||||
|
||||
evals, _ = eigs(H, sigma=current_E, maxiter=5000, tol=tol, ritzvec=false, check=1)
|
||||
current_E = nearest(evals, current_E)
|
||||
|
||||
push!(EC.exact_E, current_E)
|
||||
|
||||
verbose && println("Extrapolating for c = $c")
|
||||
|
||||
H_EC = EC.H0_EC + c .* EC.H1_EC
|
||||
|
||||
evals = isnothing(EC.N_EC) ? eigvals(H_EC) : eigvals(H_EC, EC.N_EC)
|
||||
push!(EC.extrapolated_E, nearest(evals, current_E))
|
||||
end
|
||||
end
|
||||
|
||||
"Export EC data as CSV file"
|
||||
exportCSV(EC::affine_EC, filename) = exportCSV(filename, (EC.training_E, EC.exact_E, EC.extrapolated_E), ("training", "exact", "extrapolated"))
|
||||
|
||||
"Plot EC data and optionally save figure to a file"
|
||||
function plot(EC::affine_EC, save_fig_filename=nothing)
|
||||
scatter(real.(EC.training_E), imag.(EC.training_E), label="training")
|
||||
scatter!(real.(EC.exact_E), imag.(EC.exact_E), label="exact")
|
||||
scatter!(real.(EC.extrapolated_E), imag.(EC.extrapolated_E), label="extrapolated")
|
||||
isnothing(save_fig_filename) || savefig(save_fig_filename)
|
||||
end
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
using Plots
|
||||
include("../EC.jl")
|
||||
|
||||
training_ref = -0.72763
|
||||
exact_ref = 4.0766890719636635 - 0.01275892774109674im
|
||||
|
|
@ -13,52 +14,9 @@ H0 = H
|
|||
Vp_of_r(r) = -exp(-(r/3)^2)
|
||||
@time "Vp" Vp = get_src_V_matrix(Vp_of_r, basis, μω, μω_global)
|
||||
|
||||
exact = ComplexF64[]
|
||||
training = ComplexF64[]
|
||||
extrapolated = ComplexF64[]
|
||||
training_vecs = Vector{ComplexF64}[]
|
||||
EC = affine_EC(H0, Vp)
|
||||
train!(EC, training_c; ref_eval=training_ref, CAEC=true)
|
||||
extrapolate!(EC, extrapolating_c; ref_eval=exact_ref)
|
||||
|
||||
current_E = training_ref
|
||||
|
||||
for c in training_c
|
||||
println("Training for c = $c")
|
||||
local H = H0 + c .* Vp
|
||||
local evals, evecs = eigs(H, nev=3, ncv=24, which=:LI, maxiter=5000, tol=1e-5, ritzvec=true, check=1)
|
||||
|
||||
global current_E = nearest(evals, current_E)
|
||||
push!(training, current_E)
|
||||
push!(training_vecs, evecs[:, nearestIndex(evals, current_E)])
|
||||
end
|
||||
|
||||
# CA-EC
|
||||
training_vecs = vcat(training_vecs, conj(training_vecs))
|
||||
|
||||
println("Original EC dimensionality = $(length(training_vecs))")
|
||||
@time "Gram-Schmidt" training_vecs = gram_schmidt!(training_vecs; verbose=true) # orthonormalization
|
||||
|
||||
EC_basis = hcat(training_vecs...)
|
||||
H0_EC = transpose(EC_basis) * H0 * EC_basis
|
||||
Vp_EC = transpose(EC_basis) * Vp * EC_basis
|
||||
|
||||
current_E = exact_ref
|
||||
|
||||
for c in extrapolating_c
|
||||
println("Extrapolating for c = $c")
|
||||
local H = H0 + c .* Vp
|
||||
local evals, _ = eigs(H, nev=3, ncv=24, which=:LI, maxiter=5000, tol=1e-5, ritzvec=false, check=1)
|
||||
|
||||
global current_E = nearest(evals, current_E)
|
||||
push!(exact, current_E)
|
||||
|
||||
# extrapolation
|
||||
H_EC = H0_EC + c .* Vp_EC
|
||||
evals = eigvals(H_EC)
|
||||
push!(extrapolated, nearest(evals, current_E))
|
||||
end
|
||||
|
||||
exportCSV("temp/HO_B2R.csv", (training, exact, extrapolated), ("training", "exact", "extrapolated"))
|
||||
|
||||
scatter(real.(training),imag.(training), label="training")
|
||||
scatter!(real.(exact),imag.(exact), label="exact")
|
||||
scatter!(real.(extrapolated),imag.(extrapolated), label="extrapolated")
|
||||
savefig("temp/HO_B2R.pdf")
|
||||
exportCSV(EC, "temp/HO_B2R.csv")
|
||||
plot(EC, "temp/HO_B2R.pdf")
|
||||
|
|
|
|||
Loading…
Reference in New Issue