Reorganize orthogonalization in EC.jl

This commit is contained in:
Nuwan Yapa 2025-01-30 13:02:54 -05:00
parent dae6ed9f21
commit 3b2277cbd0
1 changed files with 41 additions and 60 deletions

101
EC.jl
View File

@ -29,12 +29,8 @@ end
"Train an EC model for a given range of c values. "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 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. 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.
If pseudo_inv_rtol > 0, the GEVP is avoided using Moore-Penrose psuedoinverse, using this value as the relative tolerance for dropping redundant vectors. If orthonormalize_threshold > 0, Gram-Schmidt orthonormalization is performed, using this value as the threshold for dropping redundant vectors."
If orthonormalize_threshold > 0, Gram-Schmidt orthonormalization is performed, using this value as the threshold for dropping redundant vectors. function train!(EC::affine_EC, c_vals; ref_eval=-10.0, CAEC=false, gram_schmidt_threshold=0, verbose=true, tol=1e-5)
If both are = 0, GEVP is solved instead."
function train!(EC::affine_EC, c_vals; ref_eval=-10.0, pseudo_inv_rtol=1e-6, gram_schmidt_threshold=0, CAEC=false, verbose=true, tol=1e-5)
@assert pseudo_inv_rtol == 0 || gram_schmidt_threshold == 0 "Cannot perform both psuedoinverse and Gram-Schmidt"
training_vecs = Vector{ComplexF64}[] training_vecs = Vector{ComplexF64}[]
for c in c_vals for c in c_vals
@ -58,66 +54,41 @@ function train!(EC::affine_EC, c_vals; ref_eval=-10.0, pseudo_inv_rtol=1e-6, gra
end end
CAEC && append!(training_vecs, conj.(training_vecs)) CAEC && append!(training_vecs, conj.(training_vecs))
weights_mat = spdiagm(EC.weights)
if gram_schmidt_threshold > 0 (EC.H0_EC, EC.H1_EC, EC.N_EC) = get_reduced_matrices(EC, training_vecs, gram_schmidt_threshold; verbose=true)
EC.ensemble_size > 0 && generate_resampled_EC_matrices(EC, training_vecs, weights_mat, gram_schmidt_threshold)
training_vecs = gram_schmidt!(training_vecs, EC.weights, gram_schmidt_threshold; verbose=verbose)
end
EC_basis = hcat(training_vecs...) for _ in 1:EC.ensemble_size
EC.H0_EC = transpose(EC_basis) * weights_mat * EC.H0 * EC_basis (H0_EC, H1_EC, N_EC) = get_reduced_matrices(EC, training_vecs, gram_schmidt_threshold, resample(length(training_vecs)); verbose=false)
EC.H1_EC = transpose(EC_basis) * weights_mat * EC.H1 * EC_basis push!(EC.H0_EC_ensemble, H0_EC)
EC.N_EC = transpose(EC_basis) * weights_mat * EC_basis push!(EC.H1_EC_ensemble, H1_EC)
push!(EC.N_EC_ensemble, N_EC)
if pseudo_inv_rtol > 0
EC.ensemble_size > 0 && generate_resampled_EC_matrices(EC, pseudo_inv_rtol)
inv_N_EC = pinv(EC.N_EC; rtol=pseudo_inv_rtol)
EC.H0_EC = inv_N_EC * EC.H0_EC
EC.H1_EC = inv_N_EC * EC.H1_EC
EC.N_EC = nothing
end end
EC.trained = true EC.trained = true
end end
function get_reduced_matrices(EC::affine_EC, training_vecs, gram_schmidt_threshold, subsample=1:length(training_vecs); verbose=false)
vecs = deepcopy(training_vecs[subsample])
if gram_schmidt_threshold > 0; vecs = gram_schmidt!(sampled_vecs, EC.weights, gram_schmidt_threshold; verbose=verbose); end
EC_basis = hcat(orth_vecs...)
weights_mat = spdiagm(EC.weights)
H0_EC = transpose(EC_basis) * weights_mat * EC.H0 * EC_basis
H1_EC = transpose(EC_basis) * weights_mat * EC.H1 * EC_basis
N_EC = transpose(EC_basis) * weights_mat * EC_basis
return (H0_EC, H1_EC, N_EC)
end
resample(n::Int) = rand(1:n, n) |> unique |> sort resample(n::Int) = rand(1:n, n) |> unique |> sort
"Generate an resampled ensemble of reduced matrices performing Gram-Schmidt orthonormalization for each."
function generate_resampled_EC_matrices(EC::affine_EC, training_vecs, weights_mat, gram_schmidt_threshold)
for _ in 1:EC.ensemble_size
sampled_vecs = deepcopy(training_vecs[resample(length(training_vecs))])
orth_vecs = gram_schmidt!(sampled_vecs, EC.weights, gram_schmidt_threshold; verbose=false)
EC_basis = hcat(orth_vecs...)
H0_EC = transpose(EC_basis) * weights_mat * EC.H0 * EC_basis
H1_EC = transpose(EC_basis) * weights_mat * EC.H1 * EC_basis
N_EC = transpose(EC_basis) * weights_mat * EC_basis
push!(EC.H0_EC_ensemble, H0_EC)
push!(EC.H1_EC_ensemble, H1_EC)
push!(EC.N_EC_ensemble, N_EC)
end
end
"Generate an resampled ensemble of reduced matrices performing Moore-Penrose psuedoinverse for each."
function generate_resampled_EC_matrices(EC::affine_EC, pseudo_inv_rtol)
for _ in 1:EC.ensemble_size
sample = resample(size(EC.N_EC, 1))
new_N_EC = EC.N_EC[sample, sample]
new_H0_EC = EC.H0_EC[sample, sample]
new_H1_EC = EC.H1_EC[sample, sample]
inv_N_EC = pinv(new_N_EC; rtol=pseudo_inv_rtol)
push!(EC.H0_EC_ensemble, inv_N_EC * new_H0_EC)
push!(EC.H1_EC_ensemble, inv_N_EC * new_H1_EC)
end
end
"Extrapolate using a trained EC model for a given range of c values "Extrapolate using a trained 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 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. 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.
If precalculated_exact_E is provided, ref_eval is ignored." If precalculated_exact_E is provided, ref_eval is ignored.
function extrapolate!(EC::affine_EC, c_vals; ref_eval=EC.training_E[end], verbose=true, tol=1e-5, precalculated_exact_E=nothing) If pseudo_inv_rtol > 0, the GEVP is avoided using Moore-Penrose psuedoinverse, using this value as the relative tolerance for dropping redundant vectors."
function extrapolate!(EC::affine_EC, c_vals; ref_eval=EC.training_E[end], pseudo_inv_rtol=1e-6, verbose=true, tol=1e-5, precalculated_exact_E=nothing)
@assert EC.trained "EC model must be trained using train() before extrapolation" @assert EC.trained "EC model must be trained using train() before extrapolation"
for c in c_vals for c in c_vals
@ -144,16 +115,14 @@ function extrapolate!(EC::affine_EC, c_vals; ref_eval=EC.training_E[end], verbos
verbose && println("Extrapolating for c = $c") verbose && println("Extrapolating for c = $c")
H_EC = EC.H0_EC + c .* EC.H1_EC evals = get_extrapolated_evals(EC.H0_EC, EC.H1_EC, EC.N_EC, c, pseudo_inv_rtol)
evals = isnothing(EC.N_EC) ? eigvals(H_EC) : eigvals(H_EC, EC.N_EC)
push!(EC.extrapolated_E, nearest(evals, current_E)) push!(EC.extrapolated_E, nearest(evals, current_E))
if EC.ensemble_size > 0 if EC.ensemble_size > 0
E_ensemble = ComplexF64[] E_ensemble = zeros(ComplexF64, EC.ensemble_size)
for i in 1:EC.ensemble_size for i in 1:EC.ensemble_size
H_EC = EC.H0_EC_ensemble[i] + c .* EC.H1_EC_ensemble[i] evals = get_extrapolated_evals(EC.H0_EC_ensemble[i], EC.H1_EC_ensemble[i], EC.N_EC_ensemble[i], c, pseudo_inv_rtol)
evals = isempty(EC.N_EC_ensemble) ? eigvals(H_EC) : eigvals(H_EC, EC.N_EC_ensemble[i]) E_ensemble[i] = nearest(evals, current_E)
push!(E_ensemble, nearest(evals, current_E))
end end
re_CI = std(real.(E_ensemble)) re_CI = std(real.(E_ensemble))
im_CI = std(imag.(E_ensemble)) im_CI = std(imag.(E_ensemble))
@ -162,6 +131,18 @@ function extrapolate!(EC::affine_EC, c_vals; ref_eval=EC.training_E[end], verbos
end end
end end
"Solve the GEVP with or without Moore-Penrose psuedoinverse"
function get_extrapolated_evals(H0_EC, H1_EC, N_EC, c, pseudo_inv_rtol)
H_EC = H0_EC + c .* H1_EC
if pseudo_inv_rtol > 0
inv_N_EC = pinv(N_EC; rtol=pseudo_inv_rtol)
H_EC = inv_N_EC * H_EC
return eigvals(H_EC)
else
return eigvals(H_EC, N_EC)
end
end
"Export EC data as CSV file" "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")) exportCSV(EC::affine_EC, filename) = exportCSV(filename, (EC.training_E, EC.exact_E, EC.extrapolated_E), ("training", "exact", "extrapolated"))