EC infrastructure refactored out to separate file

This commit is contained in:
Nuwan Yapa 2025-01-09 19:13:28 -05:00
parent 39b3da196c
commit e123ae0eaf
2 changed files with 116 additions and 48 deletions

110
EC.jl Normal file
View File

@ -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

View File

@ -1,4 +1,5 @@
using Plots using Plots
include("../EC.jl")
training_ref = -0.72763 training_ref = -0.72763
exact_ref = 4.0766890719636635 - 0.01275892774109674im exact_ref = 4.0766890719636635 - 0.01275892774109674im
@ -13,52 +14,9 @@ H0 = H
Vp_of_r(r) = -exp(-(r/3)^2) Vp_of_r(r) = -exp(-(r/3)^2)
@time "Vp" Vp = get_src_V_matrix(Vp_of_r, basis, μω, μω_global) @time "Vp" Vp = get_src_V_matrix(Vp_of_r, basis, μω, μω_global)
exact = ComplexF64[] EC = affine_EC(H0, Vp)
training = ComplexF64[] train!(EC, training_c; ref_eval=training_ref, CAEC=true)
extrapolated = ComplexF64[] extrapolate!(EC, extrapolating_c; ref_eval=exact_ref)
training_vecs = Vector{ComplexF64}[]
current_E = training_ref exportCSV(EC, "temp/HO_B2R.csv")
plot(EC, "temp/HO_B2R.pdf")
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")