Commit a2f4bcfc authored by Antonino's avatar Antonino

bug fixes in fit routine

parent 5f3ab2cc
"""
"""
plat_av(obs::Vector{uwreal}, plat::Vector{Int64}, [W::VecOrMat{Float64},] wpm::Union{Dict{Int64},Vector{Float{64}},Dict{String,Vector{Float{64}},Nothing}=nothing} ) plat_av(obs::Vector{uwreal}, plat::Vector{Int64}, [W::VecOrMat{Float64},] wpm::Union{Dict{Int64},Vector{Float{64}},Dict{String,Vector{Float{64}},Nothing}=nothing} )
It computes plateau average of `obs` in the range `plat`. Effectively this perform a fit to a constant. It computes plateau average of `obs` in the range `plat`. Effectively this perform a fit to a constant.
The field `W` is optional. When absent, `W` is a `Vector{Float64}` constructed from the error of `obs`. The field `W` is optional. When absent, `W` is a `Vector{Float64}` constructed from the error of `obs`.
When `W` is a `Vector{Float64}` it performs an uncorrelated fit, when `W` is a `Matrix{Float64}`, it perfom a correlated fit When `W` is a `Vector{Float64}` it performs an uncorrelated fit, when `W` is a `Matrix{Float64}`, it perfom a correlated fit
# Potential side effects # Potential side effects
...@@ -16,7 +15,7 @@ function plat_av(obs::Vector{uwreal}, plat::Vector{Int64}, wpm::Union{Dict{Int64 ...@@ -16,7 +15,7 @@ function plat_av(obs::Vector{uwreal}, plat::Vector{Int64}, wpm::Union{Dict{Int64
isnothing(wpm) ? uwerr.(obs) : [uwerr(obs_aux, wpm) for obs_aux in obs] isnothing(wpm) ? uwerr.(obs) : [uwerr(obs_aux, wpm) for obs_aux in obs]
w = 1 ./ err.(obs)[plat[1]:plat[2]].^2 w = 1 ./ err.(obs)[plat[1]:plat[2]].^2
av = sum(w .* obs[plat[1]:plat[2]]) / sum(w) av = sum(w .* obs[plat[1]:plat[2]]) / sum(w)
return av return av
end end
plat_av(obs::Vector{uwreal}, plat::Vector{Int64}, W::Vector{Float64},wpm::Union{Dict{Int64,Vector{Float64}},Dict{String,Vector{Float64}}, Nothing}=nothing) = sum(W .* obs[plat[1]:plat[2]]) / sum(W) plat_av(obs::Vector{uwreal}, plat::Vector{Int64}, W::Vector{Float64},wpm::Union{Dict{Int64,Vector{Float64}},Dict{String,Vector{Float64}}, Nothing}=nothing) = sum(W .* obs[plat[1]:plat[2]]) / sum(W)
...@@ -74,16 +73,16 @@ y_lin_fit(par::Vector{uwreal}, x::Union{uwreal, Float64}) = par[1] + par[2] * x ...@@ -74,16 +73,16 @@ y_lin_fit(par::Vector{uwreal}, x::Union{uwreal, Float64}) = par[1] + par[2] * x
@doc """ @doc """
get_chi(model::Function,x::Vector,par,data,W::VecOrMat{Float64}) get_chi(model::Function,x::Vector,par,data,W::VecOrMat{Float64})
It computes the chi square of a fit. `model` is assumed to be of the type f(xdata,par). It computes the chi square of a fit. `model` is assumed to be of the type f(xdata,par).
If `W::Vector` the chisquare is computed for an uncorrelated fit If `W::Vector` the chisquare is computed for an uncorrelated fit
If `W::Matrix` the chisquare is computed for a correlated fit If `W::Matrix` the chisquare is computed for a correlated fit
""" """
function get_chi(model::Function,x,par,data,W::Array{Float64,2}) function get_chi(model::Function,x,par,data,W::Array{Float64,2})
return sum((data.-model(x,par))' * W * (data.-model(x,par))) return sum((data.-model(x,par))' * W * (data.-model(x,par)))
end end
function get_chi(model::Function,x,par,data,W::Vector{Float64}) function get_chi(model::Function,x,par,data,W::Vector{Float64})
return sum((data.-model(x,par)).^2 .* W) return sum((data.-model(x,par)).^2 .* W)
end end
...@@ -91,12 +90,12 @@ end ...@@ -91,12 +90,12 @@ end
fit_routine(model::Function,xdata::AbstractArray{<:Real},ydata::AbstractArray{ADerrors.uwreal},npar; kwargs...) fit_routine(model::Function,xdata::AbstractArray{<:Real},ydata::AbstractArray{ADerrors.uwreal},npar; kwargs...)
fit_routine(model::Function,xdata::AbstractArray{uwreal},ydata::AbstractArray{ADerrors.uwreal},npar; kwargs...) fit_routine(model::Function,xdata::AbstractArray{uwreal},ydata::AbstractArray{ADerrors.uwreal},npar; kwargs...)
It executes a fit of the `ydata` with the fit function `model`. It executes a fit of the `ydata` with the fit function `model`.
# Arguments: # Arguments:
- `model`: Fit function used to fit the data. the function assumes that its called as `model(xdata,parameters)`. - `model`: Fit function used to fit the data. the function assumes that its called as `model(xdata,parameters)`.
- `xdata`: indipendent variable in the fit. It can be an `AbstractArray{<:Real}`, that is the "default" method, or - `xdata`: indipendent variable in the fit. It can be an `AbstractArray{<:Real}`, that is the "default" method, or
a `AbstractArray{uwreal}`. In the latter case, the method builds the function a `AbstractArray{uwreal}`. In the latter case, the method builds the function
``math ``math
F(q_i) = \begin{cases} F(q_i) = \begin{cases}
...@@ -105,7 +104,7 @@ F(q_i) = \begin{cases} ...@@ -105,7 +104,7 @@ F(q_i) = \begin{cases}
\end{cases} \end{cases}
`` ``
and then call the default method with dummy `xdata` and `vcat(ydata,xdata)` as new `ydata` and then call the default method with dummy `xdata` and `vcat(ydata,xdata)` as new `ydata`
- `ydata`: Data variable that carries the error - `ydata`: Data variable that carries the error
- `npar`: number of parameters used in the fit. - `npar`: number of parameters used in the fit.
# Keyword parameters: # Keyword parameters:
...@@ -125,11 +124,11 @@ F(q_i) = \begin{cases} ...@@ -125,11 +124,11 @@ F(q_i) = \begin{cases}
If `W` is not given, and `corr` is `true`, then it is used to compute `W`. If `W` is not given, and `corr` is `true`, then it is used to compute `W`.
If need to computed `W` but not given, then `C = ADerrors.cov(ydata,wpm)`. See also ADerrors documentation. If need to computed `W` but not given, then `C = ADerrors.cov(ydata,wpm)`. See also ADerrors documentation.
If available, it will be used to better estimate the fit pvalue and the expected chi-square, If available, it will be used to better estimate the fit pvalue and the expected chi-square,
but it will not be computed if not available at this point. but it will not be computed if not available at this point.
- `guess::Vector{Float64}`: Initial guess for the parameter used in the fit routine. If not given, default to `fill(0.5,npar)`. - `guess::Vector{Float64}`: Initial guess for the parameter used in the fit routine. If not given, default to `fill(0.5,npar)`.
If `xdata isa Vector{uwreal}`, the mean value of `xdata` are used as guess for the relevant `q_i` parameters. If `xdata isa Vector{uwreal}`, the mean value of `xdata` are used as guess for the relevant `q_i` parameters.
- `logfile`: handle to a logfile. If `nothing`, no log will be written. It can be `IO` file or a custom log structure that has - `logfile`: handle to a logfile. If `nothing`, no log will be written. It can be `IO` file or a custom log structure that has
an overloading for `print()` and `println()`. an overloading for `print()` and `println()`.
...@@ -137,15 +136,15 @@ F(q_i) = \begin{cases} ...@@ -137,15 +136,15 @@ F(q_i) = \begin{cases}
It returns a `NamedTuple` with names: It returns a `NamedTuple` with names:
- `:par`: fit parameter as `Vector{uwreal}` - `:par`: fit parameter as `Vector{uwreal}`
- `:chi2`: chisquare, - `:chi2`: chisquare,
- `:chiexp`: chisquare expected - `:chiexp`: chisquare expected
- `:pval`: pvalue - `:pval`: pvalue
""" """
function fit_routine(model::Function, function fit_routine(model::Function,
xdata::AbstractArray{<:Real}, xdata::AbstractArray{<:Real},
ydata::AbstractArray{uwreal}, ydata::AbstractArray{uwreal},
npar::Int64; npar::Int64;
wpm::Union{Dict{Int64,Vector{Float64}},Dict{String,Vector{Float64}}}=Dict{Int64,Vector{Float64}}(), wpm::Union{Dict{Int64,Vector{Float64}},Dict{String,Vector{Float64}}}=Dict{Int64,Vector{Float64}}(),
corr::Bool = true, corr::Bool = true,
W::AbstractArray{Float64}=Vector{Float64}(), W::AbstractArray{Float64}=Vector{Float64}(),
guess::AbstractVector{Float64} = fill(0.5,npar), guess::AbstractVector{Float64} = fill(0.5,npar),
logfile = nothing, logfile = nothing,
...@@ -158,8 +157,8 @@ function fit_routine(model::Function, ...@@ -158,8 +157,8 @@ function fit_routine(model::Function,
[uwerr(y, wpm) for y in ydata] [uwerr(y, wpm) for y in ydata]
if length(W) ==0 if length(W) ==0
if corr if corr
C = length(C) ==0 ? GammaMethod.cov_AD(ydata,wpm) : C C = length(C) ==0 ? GammaMethod.cov_AD(ydata) : C
W = LinearAlgebra.pinv(C); W = LinearAlgebra.pinv(C);
W = (W'+W)*0.5 W = (W'+W)*0.5
else else
...@@ -173,9 +172,9 @@ function fit_routine(model::Function, ...@@ -173,9 +172,9 @@ function fit_routine(model::Function,
chi2 = sum(fit.resid.^2) chi2 = sum(fit.resid.^2)
par = fit_error(chisq,LsqFit.coef(fit),ydata,wpm,W,false) par = fit_error(chisq,LsqFit.coef(fit),ydata,wpm,W,false)
# if the fit is correlated we have already C, no need to recompute it. # if the fit is correlated we have already C, no need to recompute it.
chiexp,pval = if length(C) !=0 chiexp,pval = if length(C) !=0
GammaMethod.chiexp(chisq,LsqFit.coef(fit),value.(ydata),C,W),juobs.pvalue(chisq,chi2,LsqFit.coef(fit),ydata,W,C=C) GammaMethod.chiexp(chisq,LsqFit.coef(fit),value.(ydata),C,W),juobs.pvalue(chisq,chi2,LsqFit.coef(fit),ydata,W,C=C)
else else
ADerrors.chiexp(chisq,LsqFit.coef(fit),ydata,wpm,W=W),juobs.pvalue(chisq,chi2,LsqFit.coef(fit),ydata,W) ADerrors.chiexp(chisq,LsqFit.coef(fit),ydata,wpm,W=W),juobs.pvalue(chisq,chi2,LsqFit.coef(fit),ydata,W)
end end
...@@ -244,7 +243,7 @@ function fit_routine(model::Function, ...@@ -244,7 +243,7 @@ function fit_routine(model::Function,
guess=new_guess, wpm=wpm,corr=corr, guess=new_guess, wpm=wpm,corr=corr,
W=W,C=C,logfile=nothing) W=W,C=C,logfile=nothing)
if !isnothing(logfile) if !isnothing(logfile)
uwerr.(fit.par) uwerr.(fit.par)
println(logfile, "juobs.fit_routine output:") println(logfile, "juobs.fit_routine output:")
println(logfile, "\t\txdata carries uncertainty") println(logfile, "\t\txdata carries uncertainty")
...@@ -270,7 +269,7 @@ end ...@@ -270,7 +269,7 @@ end
fit_routine(model::AbstractArray{Function}, fit_routine(model::AbstractArray{Function},
xdata::AbstractArray{<:AbstractArray}, xdata::AbstractArray{<:AbstractArray},
ydata::AbstractArray{<:AbstractArray{ADerrors.uwreal}},npar; kwargs...) ydata::AbstractArray{<:AbstractArray{ADerrors.uwreal}},npar; kwargs...)
It executes a combined fit of the `ydata` with the fit functions in `model`. The method define the general model `F(X_{mi},p) = model[m](xdata[i],p)` It executes a combined fit of the `ydata` with the fit functions in `model`. The method define the general model `F(X_{mi},p) = model[m](xdata[i],p)`
and call `fit_routine(F,vcat(xdata),vcat(ydata),npar;kwargs....)`. The `kwargs` parameters are accordingly updated to reflect the new function. and call `fit_routine(F,vcat(xdata),vcat(ydata),npar;kwargs....)`. The `kwargs` parameters are accordingly updated to reflect the new function.
...@@ -279,39 +278,39 @@ and call `fit_routine(F,vcat(xdata),vcat(ydata),npar;kwargs....)`. The `kwargs` ...@@ -279,39 +278,39 @@ and call `fit_routine(F,vcat(xdata),vcat(ydata),npar;kwargs....)`. The `kwargs`
It returns a `NamedTuple` with names: It returns a `NamedTuple` with names:
- `:par`: fit parameter as `Vector{uwreal}` - `:par`: fit parameter as `Vector{uwreal}`
- `:chi2`: chisquare, - `:chi2`: chisquare,
- `:chiexp`: chisquare expected - `:chiexp`: chisquare expected
- `:pval`: pvalue - `:pval`: pvalue
""" """
function fit_routines(models::AbstractArray{Function}, function fit_routine(models::AbstractArray{Function},
xdata::AbstractArray{<:AbstractArray}, xdata::AbstractArray{<:AbstractArray},
ydata::AbstractArray{<:AbstractArray{ADerrors.uwreal}}, ydata::AbstractArray{<:AbstractArray{ADerrors.uwreal}},
npar::Int64; npar::Int64;
W::AbstractArray = Float64[], W = Float64[],
C::AbstractArray = Float64[], C = Float64[],
wpm::AbstractDict = Dict{Int64,Vector{Float64}}(), wpm::AbstractDict = Dict{Int64,Vector{Float64}}(),
corr::Bool = true, corr::Bool = true,
guess::AbstractArray = fill(0.5,npar), guess::AbstractArray = fill(0.5,npar),
logfile = nothing, logfile = nothing,
) )
Nmodel = length(models) Nmodel = length(models)
ndata = length.(xdata)
Ntotal = sum(ndata);
if Nmodel != length(xdata) != length(ydata) if Nmodel != length(xdata) != length(ydata)
error("[juobs] Error: you need the same number of model, xdata and ydata") error("[juobs] Error: you need the same number of model, xdata and ydata")
end end
if !(length(W) == 0 || length(W)==Nmodel) if !(length(W) == 0 || length(W)==Nmodel || length(W) == Ntotal^2)
error("[juobs] Error: You need to pass a W matrix for model or none") error("[juobs] Error: You need to pass a W matrix for model, for all the data or none")
end end
if !(length(C) == 0 || length(C)==Nmodel) if !(length(C) == 0 || length(C)==Nmodel || length(C) == Ntotal^2)
error("[juobs] Error: You need to pass a C matrix for model or none") error("[juobs] Error: You need to pass a C matrix for model, for all the data or none")
end end
ndata = length.(xdata)
if !all(length.(ydata).== ndata) if !all(length.(ydata).== ndata)
error("[juobs] Error: Mismatch in xdata and ydata. Make sure that the data corresponds") error("[juobs] Error: Mismatch in xdata and ydata. Make sure that the data corresponds")
end end
Ntotal = sum(ndata);
X = vcat(xdata...) X = vcat(xdata...)
Y = vcat(ydata...) Y = vcat(ydata...)
function make_matrix(M) function make_matrix(M::Vector{<:AbstractMatrix})
aux = zeros(Ntotal,Ntotal) aux = zeros(Ntotal,Ntotal)
ie = 0 ie = 0
for m in 1:Nmodel for m in 1:Nmodel
...@@ -321,6 +320,7 @@ function fit_routines(models::AbstractArray{Function}, ...@@ -321,6 +320,7 @@ function fit_routines(models::AbstractArray{Function},
end end
return aux return aux
end end
make_matrix(M::T where {T<:AbstractMatrix}) = M
WW = length(W)==0 ? W : make_matrix(W); WW = length(W)==0 ? W : make_matrix(W);
CC = length(C)==0 ? C : make_matrix(C); CC = length(C)==0 ? C : make_matrix(C);
...@@ -331,17 +331,17 @@ function fit_routines(models::AbstractArray{Function}, ...@@ -331,17 +331,17 @@ function fit_routines(models::AbstractArray{Function},
is= 1 is= 1
ie= 0 ie= 0
for i in 1:Nmodel for i in 1:Nmodel
ie += ndata[i] ie += ndata[i]
rd = is:ie rd = is:ie
res[i] = models[i](x[rd],p) res[i] = models[i](x[rd],p)
is = ie +1 is = ie +1
end end
return vcat(res...) return vcat(res...)
end end
fit = juobs.fit_routine(Model,X,Y,npar,guess = guess,W=WW,C=CC,corr=corr,logfile=nothing,wpm=wpm) fit = juobs.fit_routine(Model,X,Y,npar,guess = guess,W=WW,C=CC,corr=corr,logfile=nothing,wpm=wpm)
if !isnothing(logfile) if !isnothing(logfile)
uwerr.(fit.par) uwerr.(fit.par)
flag = typeof(xdata) <: AbstractArray{<:AbstractArray{ADerrors.uwreal}} flag = typeof(xdata) <: AbstractArray{<:AbstractArray{ADerrors.uwreal}}
println(logfile, "juobs.fit_routine output:") println(logfile, "juobs.fit_routine output:")
......
#= #=
using ForwardDiff, LinearAlgebra using ForwardDiff, LinearAlgebra
for op in (:eigvals, :eigvecs) for op in (:eigvals, :eigvecs)
@eval function LinearAlgebra.$op(a::Matrix{uwreal}) @eval function LinearAlgebra.$op(a::Matrix{uwreal})
function fvec(x::Matrix) function fvec(x::Matrix)
return LinearAlgebra.$op(x) return LinearAlgebra.$op(x)
end end
return fvec(value.(a)) return fvec(value.(a))
#return uwreal(LinearAlgebra.$op(a.mean), a.prop, ForwardDiff.derivative($op, a.mean)*a.der) #return uwreal(LinearAlgebra.$op(a.mean), a.prop, ForwardDiff.derivative($op, a.mean)*a.der)
end end
end end
=# =#
@doc raw""" @doc raw"""
get_matrix(diag::Vector{Array}, upper::Vector{Array} ) get_matrix(diag::Vector{Array}, upper::Vector{Array} )
This function allows the user to build an array of matrices, where each matrix is a symmetric matrix of correlators at a given timeslice. This function allows the user to build an array of matrices, where each matrix is a symmetric matrix of correlators at a given timeslice.
It takes as input: It takes as input:
- `diag::Vector{Array}`: vector of correlators. Each correlator will constitute a diagonal element of the matrices A[i] where i runs over the timeslices, i.e. - `diag::Vector{Array}`: vector of correlators. Each correlator will constitute a diagonal element of the matrices A[i] where i runs over the timeslices, i.e.
`A[i][1,1] = diag[1], .... A[i][n,n] = diag[n]` `A[i][1,1] = diag[1], .... A[i][n,n] = diag[n]`
`Given n=length(diag)`, the matrices will have dimension n*n `Given n=length(diag)`, the matrices will have dimension n*n
- `upper::Vector{Array}`: vector of correlators liying on the upper diagonal position. - `upper::Vector{Array}`: vector of correlators liying on the upper diagonal position.
`A[i][1,2] = upper[1], .. , A[i][1,n] = upper[n-1], ` `A[i][1,2] = upper[1], .. , A[i][1,n] = upper[n-1], `
`A[i][2,3] = upper[n], .. , A[i][n-1,n] = upper[n(n-1)/2]` `A[i][2,3] = upper[n], .. , A[i][n-1,n] = upper[n(n-1)/2]`
Given n, `length(upper)=n(n-1)/2` Given n, `length(upper)=n(n-1)/2`
The method returns an array of symmetric matrices of dimension n for each timeslice The method returns an array of symmetric matrices of dimension n for each timeslice
Examples: Examples:
```@example ```@example
## load data ## load data
pp_data = read_mesons(path, "G5", "G5") pp_data = read_mesons(path, "G5", "G5")
pa_data = read_mesons(path, "G5", "G0G5") pa_data = read_mesons(path, "G5", "G0G5")
aa_data = read_mesons(path, "G0G5", "G0G5") aa_data = read_mesons(path, "G0G5", "G0G5")
## create Corr struct ## create Corr struct
corr_pp = corr_obs.(pp_data) corr_pp = corr_obs.(pp_data)
corr_pa = corr_obs.(pa_data) corr_pa = corr_obs.(pa_data)
corr_aa = corr_obs.(aa_data) # array of correlators for different \mu_q combinations corr_aa = corr_obs.(aa_data) # array of correlators for different \mu_q combinations
## set up matrices ## set up matrices
corr_diag = [corr_pp[1], corr_aa[1]] corr_diag = [corr_pp[1], corr_aa[1]]
corr_upper = [corr_pa[1]] corr_upper = [corr_pa[1]]
matrices = [corr_diag, corr_upper] matrices = [corr_diag, corr_upper]
Julia> matrices[i] Julia> matrices[i]
pp[i] ap[i] pp[i] ap[i]
pa[i] aa[i] pa[i] aa[i]
## where i runs over the timeslices ## where i runs over the timeslices
``` ```
""" """
function get_matrix(corr_diag::Vector{Vector{uwreal}}, corr_upper::Vector{Vector{uwreal}}) function get_matrix(corr_diag::Vector{Vector{uwreal}}, corr_upper::Vector{Vector{uwreal}})
time = length(corr_diag[1]) # total time slices time = length(corr_diag[1]) # total time slices
n = length(corr_diag) # matrix dimension n = length(corr_diag) # matrix dimension
d = length(corr_upper) # upper elements d = length(corr_upper) # upper elements
if d != (n*(n-1) / 2) if d != (n*(n-1) / 2)
error("Error get_matrix") error("Error get_matrix")
end end
res = Vector{Matrix{uwreal}}(undef, time) # array with all the matrices at each time step. res = Vector{Matrix{uwreal}}(undef, time) # array with all the matrices at each time step.
aux = Matrix{uwreal}(undef, n, n) aux = Matrix{uwreal}(undef, n, n)
for t in 1:time for t in 1:time
count=0 count=0
for i in range(n-1,1, step=-1) for i in range(n-1,1, step=-1)
for j in range(n, i+1, step=-1) for j in range(n, i+1, step=-1)
aux[i,j] = corr_upper[d-count][t] aux[i,j] = corr_upper[d-count][t]
aux[j,i] = corr_upper[d-count][t] aux[j,i] = corr_upper[d-count][t]
count +=1 count +=1
end end
aux[i,i] = corr_diag[i][t] aux[i,i] = corr_diag[i][t]
end end
aux[n,n] = corr_diag[n][t] aux[n,n] = corr_diag[n][t]
res[t] = copy(aux) res[t] = copy(aux)
end end
return res return res
end end
get_matrix(corr_diag::Vector{Corr}, corr_upper::Vector{Corr}) = get_matrix(getfield.(corr_diag, :obs), getfield.(corr_upper, :obs)) get_matrix(corr_diag::Vector{Corr}, corr_upper::Vector{Corr}) = get_matrix(getfield.(corr_diag, :obs), getfield.(corr_upper, :obs))
@doc raw""" @doc raw"""
energies(evals::Vector{Array}; wpm::Union{Dict{Int64,Vector{Float64}},Dict{String,Vector{Float64}}, Nothing}=nothing) energies(evals::Vector{Array}; wpm::Union{Dict{Int64,Vector{Float64}},Dict{String,Vector{Float64}}, Nothing}=nothing)
This method computes the energy level from the eigenvalues according to: This method computes the energy level from the eigenvalues according to:
``E_i(t) = \log(λ(t) / λ(t+1))`` ``E_i(t) = \log(λ(t) / λ(t+1))``
where `i=1,..,n` with `n=length(evals[1])` and `t=1,..,T` total time slices. where `i=1,..,n` with `n=length(evals[1])` and `t=1,..,T` total time slices.
It returns a vector array en where each entry en[i][t] contains the i-th states energy at time t It returns a vector array en where each entry en[i][t] contains the i-th states energy at time t
Examples: Examples:
```@example ```@example
## load data ## load data
pp_data = read_mesons(path, "G5", "G5") pp_data = read_mesons(path, "G5", "G5")
pa_data = read_mesons(path, "G5", "G0G5") pa_data = read_mesons(path, "G5", "G0G5")
aa_data = read_mesons(path, "G0G5", "G0G5") aa_data = read_mesons(path, "G0G5", "G0G5")
## create Corr struct ## create Corr struct
corr_pp = corr_obs.(pp_data) corr_pp = corr_obs.(pp_data)
corr_pa = corr_obs.(pa_data) corr_pa = corr_obs.(pa_data)
corr_aa = corr_obs.(aa_data) # array of correlators for different \mu_q combinations corr_aa = corr_obs.(aa_data) # array of correlators for different \mu_q combinations
## set up matrices ## set up matrices
corr_diag = [corr_pp[1], corr_aa[1]] corr_diag = [corr_pp[1], corr_aa[1]]
corr_upper = [corr_pa[1]] corr_upper = [corr_pa[1]]
matrices = [corr_diag, corr_upper] matrices = [corr_diag, corr_upper]
## solve the GEVP ## solve the GEVP
evals = getall_eigvals(matrices, 5) #where t_0=5 evals = getall_eigvals(matrices, 5) #where t_0=5
en = energies(evals) en = energies(evals)
Julia> en[i] # i-th state energy at each timeslice Julia> en[i] # i-th state energy at each timeslice
``` ```
""" """
function energies(evals::Union{Vector{Vector{uwreal}},Array{Array{uwreal}} }; wpm::Union{Dict{Int64,Vector{Float64}},Dict{String,Vector{Float64}}, Nothing}=nothing) function energies(evals::Union{Vector{Vector{uwreal}},Array{Array{uwreal}} }; wpm::Union{Dict{Int64,Vector{Float64}},Dict{String,Vector{Float64}}, Nothing}=nothing)
time = length(evals) time = length(evals)
n = length(evals[1]) n = length(evals[1])
eff_en = Array{Array{uwreal}}(undef, n) eff_en = Array{Array{uwreal}}(undef, n)
aux_en = Vector{uwreal}(undef, time-1) aux_en = Vector{uwreal}(undef, time-1)
for i in 1:n for i in 1:n
for t in 1:time-1 for t in 1:time-1
ratio = evals[t][i] / evals[t+1][i] ratio = evals[t][i] / evals[t+1][i]
aux_en[t] = 0.5*log(ratio * ratio) aux_en[t] = 0.5*log(ratio * ratio)
end end
#uwerr.(aux_en) #uwerr.(aux_en)
#isnothing(wpm) ? uwerr.(aux_en) : [uwerr(a, wpm) for a in aux_en] #isnothing(wpm) ? uwerr.(aux_en) : [uwerr(a, wpm) for a in aux_en]
eff_en[i] = copy(aux_en) eff_en[i] = copy(aux_en)
end end
return eff_en return eff_en
end end
@doc raw""" @doc raw"""
getall_eigvals(a::Vector{Matrix}, t0; iter=30 ) getall_eigvals(a::Vector{Matrix}, t0; iter=30 )
This function solves a GEVP problem, returning the eigenvalues, for a list of matrices, taking as generalised matrix the one This function solves a GEVP problem, returning the eigenvalues, for a list of matrices, taking as generalised matrix the one
at index t0, i.e: at index t0, i.e:
``C(t_i)v_i = λ_i C(t_0) v_i``, with i=1:lenght(a) ``C(t_i)v_i = λ_i C(t_0) v_i``, with i=1:lenght(a)
It takes as input: It takes as input:
- `a::Vector{Matrix}` : a vector of matrices - `a::Vector{Matrix}` : a vector of matrices
- `t0::Int64` : idex value at which the fixed matrix is taken - `t0::Int64` : idex value at which the fixed matrix is taken
- `iter=30` : the number of iterations of the qr algorithm used to extract the eigenvalues - `iter=30` : the number of iterations of the qr algorithm used to extract the eigenvalues
It returns: It returns:
- `res` = Vector{Vector{uwreal}} - `res` = Vector{Vector{uwreal}}
where `res[i]` are the generalised eigenvalues of the i-th matrix of the input array. where `res[i]` are the generalised eigenvalues of the i-th matrix of the input array.
Examples: Examples:
```@example ```@example
## load data ## load data
pp_data = read_mesons(path, "G5", "G5") pp_data = read_mesons(path, "G5", "G5")
pa_data = read_mesons(path, "G5", "G0G5") pa_data = read_mesons(path, "G5", "G0G5")
aa_data = read_mesons(path, "G0G5", "G0G5") aa_data = read_mesons(path, "G0G5", "G0G5")
## create Corr struct ## create Corr struct
corr_pp = corr_obs.(pp_data) corr_pp = corr_obs.(pp_data)
corr_pa = corr_obs.(pa_data) corr_pa = corr_obs.(pa_data)
corr_aa = corr_obs.(aa_data) # array of correlators for different \mu_q combinations corr_aa = corr_obs.(aa_data) # array of correlators for different \mu_q combinations
## set up matrices ## set up matrices
corr_diag = [corr_pp[1], corr_aa[1]] corr_diag = [corr_pp[1], corr_aa[1]]
corr_upper = [corr_pa[1]] corr_upper = [corr_pa[1]]
matrices = [corr_diag, corr_upper] matrices = [corr_diag, corr_upper]
## solve the GEVP ## solve the GEVP
#evals = getall_eigvals(matrices, 5) #where t_0=5 #evals = getall_eigvals(matrices, 5) #where t_0=5
Julia> Julia>
``` ```
""" """
function getall_eigvals(a::Vector{Matrix{uwreal}}, t0::Int64; iter=5 ) function getall_eigvals(a::Vector{Matrix{uwreal}}, t0::Int64; iter=5 )
n = length(a) n = length(a)
res = Vector{Vector{uwreal}}(undef, n) res = Vector{Vector{uwreal}}(undef, n)
[res[i] = uweigvals(a[i], a[t0], iter=iter) for i=1:n] [res[i] = uweigvals(a[i], a[t0], iter=iter) for i=1:n]
return res return res
end end
@doc raw""" @doc raw"""
uweigvals(a::Matrix{uwreal}; iter = 30) uweigvals(a::Matrix{uwreal}; iter = 30)
uweigvals(a::Matrix{uwreal}, b::Matrix{uwreal}; iter = 30) uweigvals(a::Matrix{uwreal}, b::Matrix{uwreal}; iter = 30)
This function computes the eigenvalues of a matrix of uwreal objects. This function computes the eigenvalues of a matrix of uwreal objects.
If a second matrix b is given as input, it returns the generalised eigenvalues instead. If a second matrix b is given as input, it returns the generalised eigenvalues instead.
It takes as input: It takes as input:
- `a::Matrix{uwreal}` : a matrix of uwreal - `a::Matrix{uwreal}` : a matrix of uwreal
- `b::Matrix{uwreal}` : a matrix of uwreal, optional - `b::Matrix{uwreal}` : a matrix of uwreal, optional
- `iter=30`: optional flag to set the iterations of the qr algorithm used to solve the eigenvalue problem - `iter=30`: optional flag to set the iterations of the qr algorithm used to solve the eigenvalue problem
It returns: It returns:
- `res = Vector{uwreal}`: a vector where each elements is an eigenvalue - `res = Vector{uwreal}`: a vector where each elements is an eigenvalue
```@example ```@example
a = Matrix{uwreal}(nothing, n,n) ## n*n matrix of uwreal with nothing entries a = Matrix{uwreal}(nothing, n,n) ## n*n matrix of uwreal with nothing entries
b = Matrix{uwreal}(nothing, n,n) ## n*n matrix of uwreal with nothing entries b = Matrix{uwreal}(nothing, n,n) ## n*n matrix of uwreal with nothing entries
res = uweigvals(a) ##eigenvalues res = uweigvals(a) ##eigenvalues
res1 = uweigvals(a,b) ## generalised eigenvalues res1 = uweigvals(a,b) ## generalised eigenvalues
``` ```
""" """
function uweigvals(a::Matrix{uwreal}; iter::Int64=5, diag::Bool=true) function uweigvals(a::Matrix{uwreal}; iter::Int64=5, diag::Bool=true)
n = size(a,1) n = size(a,1)
if n == 2 if n == 2
return uweigvals_dim_geq3(a, iter=iter, diag=diag) #uweigvals_dim2(a) return uweigvals_dim_geq3(a, iter=iter, diag=diag) #uweigvals_dim2(a)
else else
return uweigvals_dim_geq3(a, iter=iter, diag=diag) return uweigvals_dim_geq3(a, iter=iter, diag=diag)
end end
end end
function uweigvals(a::Matrix{uwreal}, b::Matrix{uwreal}; iter = 5, diag::Bool=true) function uweigvals(a::Matrix{uwreal}, b::Matrix{uwreal}; iter = 5, diag::Bool=true)
c = uwdot(invert(b),a) c = uwdot(invert(b),a)
n = size(c,1) n = size(c,1)
if n == 2 if n == 2
return uweigvals_dim_geq3(c, iter=iter, diag=diag) #uweigvals_dim2(c) return uweigvals_dim_geq3(c, iter=iter, diag=diag) #uweigvals_dim2(c)
else else
return uweigvals_dim_geq3(c, iter=iter, diag=diag) return uweigvals_dim_geq3(c, iter=iter, diag=diag)
end end
#for k in 1:iter #for k in 1:iter
# q_k, r_k = qr(c) # q_k, r_k = qr(c)
# c = uwdot(r_k, q_k) # c = uwdot(r_k, q_k)
#end #end
end end
function uweigvals_dim_geq3(a::Matrix{uwreal}; iter = 5, diag::Bool=true) function uweigvals_dim_geq3(a::Matrix{uwreal}; iter = 5, diag::Bool=true)
n = size(a,1) n = size(a,1)
#a = tridiag_reduction(a) #a = tridiag_reduction(a)
for k in 1:iter for k in 1:iter
q_k, r_k = qr(a) q_k, r_k = qr(a)
a = uwdot(r_k, q_k) a = uwdot(r_k, q_k)
end end
diag == true ? (return get_diag(a)) : (return a) diag == true ? (return get_diag(a)) : (return a)
end end
function uweigvals_dim2(a::Matrix{uwreal}) function uweigvals_dim2(a::Matrix{uwreal})
res = Vector{uwreal}(undef,2) res = Vector{uwreal}(undef,2)
aux_sum = a[1,1] + a[2,2] aux_sum = a[1,1] + a[2,2]
delta = ADerrors.sqrt((aux_sum)^2 - 4*(a[1,1]*a[2,2]- a[1,2]*a[2,1])) delta = ADerrors.sqrt((aux_sum)^2 - 4*(a[1,1]*a[2,2]- a[1,2]*a[2,1]))
res[1] = (aux_sum + delta) / 2 res[1] = (aux_sum + delta) / 2
res[2] = (aux_sum - delta) / 2 res[2] = (aux_sum - delta) / 2
return res return res
end end
@doc raw""" @doc raw"""
getall_eigvecs(a::Vector{Matrix}, delta_t; iter=30 ) getall_eigvecs(a::Vector{Matrix}, delta_t; iter=30 )
This function solves a GEVP problem, returning the eigenvectors, for a list of matrices. This function solves a GEVP problem, returning the eigenvectors, for a list of matrices.
``C(t_i)v_i = λ_i C(t_i-\delta_t) v_i ``, with i=1:lenght(a) ``C(t_i)v_i = λ_i C(t_i-\delta_t) v_i ``, with i=1:lenght(a)
Here `delta_t` is the time shift within the two matrices of the problem, and is kept fixed. Here `delta_t` is the time shift within the two matrices of the problem, and is kept fixed.
It takes as input: It takes as input:
- `a::Vector{Matrix}` : a vector of matrices - `a::Vector{Matrix}` : a vector of matrices
- `delta_t::Int64` : the fixed time shift t-t_0 - `delta_t::Int64` : the fixed time shift t-t_0
- `iter=30` : the number of iterations of the qr algorithm used to extract the eigenvalues - `iter=30` : the number of iterations of the qr algorithm used to extract the eigenvalues
It returns: It returns:
- `res = Vector{Matrix{uwreal}}` - `res = Vector{Matrix{uwreal}}`
where each `res[i]` is a matrix with the eigenvectors as columns where each `res[i]` is a matrix with the eigenvectors as columns
Examples: Examples:
```@example ```@example
mat_array = get_matrix(diag, upper_diag) mat_array = get_matrix(diag, upper_diag)
evecs = getall_eigvecs(mat_array, 5) evecs = getall_eigvecs(mat_array, 5)
``` ```
""" """
function getall_eigvecs(a::Vector{Matrix{uwreal}}, delta_t; iter=5) function getall_eigvecs(a::Vector{Matrix{uwreal}}, delta_t; iter=5)
n = length(a)-delta_t n = length(a)-delta_t
res = Vector{Matrix{uwreal}}(undef, n) res = Vector{Matrix{uwreal}}(undef, n)
[res[i] = uweigvecs(a[i+delta_t], a[i]) for i=1:n] [res[i] = uweigvecs(a[i+delta_t], a[i]) for i=1:n]
return res return res
end end
@doc raw""" @doc raw"""
uweigvecs(a::Matrix{uwreal}; iter = 30) uweigvecs(a::Matrix{uwreal}; iter = 30)
uweigvecs(a::Matrix{uwreal}, b::Matrix{uwreal}; iter = 30) uweigvecs(a::Matrix{uwreal}, b::Matrix{uwreal}; iter = 30)
This function computes the eigenvectors of a matrix of uwreal objects. This function computes the eigenvectors of a matrix of uwreal objects.
If a second matrix b is given as input, it returns the generalised eigenvectors instead. If a second matrix b is given as input, it returns the generalised eigenvectors instead.
It takes as input: It takes as input:
- `a::Matrix{uwreal}` : a matrix of uwreal - `a::Matrix{uwreal}` : a matrix of uwreal
- `b::Matrix{uwreal}` : a matrix of uwreal, optional - `b::Matrix{uwreal}` : a matrix of uwreal, optional
- `iter=30` : the number of iterations of the qr algorithm used to extract the eigenvalues - `iter=30` : the number of iterations of the qr algorithm used to extract the eigenvalues
It returns: It returns:
- `res = Matrix{uwreal}`: a matrix where each column is an eigenvector - `res = Matrix{uwreal}`: a matrix where each column is an eigenvector
Examples: Examples:
```@example ```@example
a = Matrix{uwreal}(nothing, n,n) ## n*n matrix of uwreal with nothing entries a = Matrix{uwreal}(nothing, n,n) ## n*n matrix of uwreal with nothing entries
b = Matrix{uwreal}(nothing, n,n) ## n*n matrix of uwreal with nothing entries b = Matrix{uwreal}(nothing, n,n) ## n*n matrix of uwreal with nothing entries
res = uweigvecs(a) ##eigenvectors in column res = uweigvecs(a) ##eigenvectors in column
res1 = uweigvecs(a,b) ## generalised eigenvectors in column res1 = uweigvecs(a,b) ## generalised eigenvectors in column
``` ```
""" """
function uweigvecs(a::Matrix{uwreal}; iter = 10) function uweigvecs(a::Matrix{uwreal}; iter = 10)
n = size(a,1) n = size(a,1)
# if n > 2 # if n > 2
# a, q = tridiag_reduction(a, q_mat=true) # a, q = tridiag_reduction(a, q_mat=true)
# end # end
u = idty(n) u = idty(n)
for k in 1:iter for k in 1:iter
q_k, r_k = qr(a) q_k, r_k = qr(a)
a = uwdot(r_k, q_k) a = uwdot(r_k, q_k)
u = uwdot(u, q_k) u = uwdot(u, q_k)
end end
#n > 2 ? (return uwdot(q,u)) : (return u) #n > 2 ? (return uwdot(q,u)) : (return u)
return u return u
end end
function uweigvecs(a::Matrix{uwreal}, b::Matrix{uwreal}; iter = 10) function uweigvecs(a::Matrix{uwreal}, b::Matrix{uwreal}; iter = 10)
c = uwdot(invert(b), a) c = uwdot(invert(b), a)
#return uweigvecs(c, iter=iter) #return uweigvecs(c, iter=iter)
n = size(c,1) n = size(c,1)
u = idty(n) u = idty(n)
for k in 1:iter for k in 1:iter
q_k, r_k = qr(c) q_k, r_k = qr(c)
c = uwdot(r_k, q_k) c = uwdot(r_k, q_k)
u = uwdot(u, q_k) u = uwdot(u, q_k)
end end
return u return u
end end
@doc raw""" @doc raw"""
uweigen(a::Matrix{uwreal}; iter = 30) uweigen(a::Matrix{uwreal}; iter = 30)
uweigen(a::Matrix{uwreal}, b::Matrix{uwreal}; iter = 30) uweigen(a::Matrix{uwreal}, b::Matrix{uwreal}; iter = 30)
This function computes the eigenvalues and the eigenvectors of a matrix of uwreal objects. This function computes the eigenvalues and the eigenvectors of a matrix of uwreal objects.
If a second matrix b is given as input, it returns the generalised eigenvalues and eigenvectors instead. If a second matrix b is given as input, it returns the generalised eigenvalues and eigenvectors instead.
It takes as input: It takes as input:
- `a::Matrix{uwreal}` : a matrix of uwreal - `a::Matrix{uwreal}` : a matrix of uwreal
- `b::Matrix{uwreal}` : a matrix of uwreal, optional - `b::Matrix{uwreal}` : a matrix of uwreal, optional
- `iter=30` : the number of iterations of the qr algorithm used to extract the eigenvalues - `iter=30` : the number of iterations of the qr algorithm used to extract the eigenvalues
It returns: It returns:
- `evals = Vector{uwreal}`: a vector where each elements is an eigenvalue - `evals = Vector{uwreal}`: a vector where each elements is an eigenvalue
- `evecs = Matrix{uwreal}`: a matrix where the i-th column is the eigenvector of the i-th eigenvalue - `evecs = Matrix{uwreal}`: a matrix where the i-th column is the eigenvector of the i-th eigenvalue
Examples: Examples:
```@example ```@example
a = Matrix{uwreal}(nothing, n,n) ## n*n matrix of uwreal with nothing entries a = Matrix{uwreal}(nothing, n,n) ## n*n matrix of uwreal with nothing entries
b = Matrix{uwreal}(nothing, n,n) ## n*n matrix of uwreal with nothing entries b = Matrix{uwreal}(nothing, n,n) ## n*n matrix of uwreal with nothing entries
eval, evec = uweigen(a) eval, evec = uweigen(a)
eval1, evec1 = uweigvecs(a,b) eval1, evec1 = uweigvecs(a,b)
``` ```
""" """
function uweigen(a::Matrix{uwreal}; iter = 5, diag::Bool=true) function uweigen(a::Matrix{uwreal}; iter = 5, diag::Bool=true)
return uweigvals(a, iter=iter,diag=diag), uweigvecs(a, iter=iter) return uweigvals(a, iter=iter,diag=diag), uweigvecs(a, iter=iter)
end end
function uweigen(a::Matrix{uwreal}, b::Matrix{uwreal}; iter = 5, diag::Bool=true) function uweigen(a::Matrix{uwreal}, b::Matrix{uwreal}; iter = 5, diag::Bool=true)
return uweigvals(a, b, iter=iter, diag=diag), uweigvecs(a, b, iter=iter) return uweigvals(a, b, iter=iter, diag=diag), uweigvecs(a, b, iter=iter)
end end
function norm_evec(evec::Matrix{uwreal}, ctnot::Matrix{uwreal}) function norm_evec(evec::Matrix{uwreal}, ctnot::Matrix{uwreal})
n=size(evec,1) n=size(evec,1)
res_evec=Matrix{uwreal}(undef, n, n) res_evec=Matrix{uwreal}(undef, n, n)
for i =1:n for i =1:n
aux_norm = (uwdot(evec[:,i], uwdot(ctnot, evec[:,i])).^2).^0.25 aux_norm = (uwdot(evec[:,i], uwdot(ctnot, evec[:,i])).^2).^0.25
res_evec[:,i] = 1 ./aux_norm .* evec[:,i] res_evec[:,i] = 1 ./aux_norm .* evec[:,i]
end end
return res_evec return res_evec
end end
function get_diag(a::Matrix{uwreal}) function get_diag(a::Matrix{uwreal})
n = size(a,1) n = size(a,1)
res = [a[k, k] for k = 1:n] res = [a[k, k] for k = 1:n]
return res return res
end end
function get_diag(v::Vector{uwreal}) function get_diag(v::Vector{uwreal})
n = length(v) n = length(v)
res = idty(n) res = idty(n)
for i =1:n for i =1:n
res[i,i] = v[i] res[i,i] = v[i]
end end
return res return res
end end
""" """
Given an input matrix of uwreals, this function returns the inverse of that matrix using QR decomposition and Given an input matrix of uwreals, this function returns the inverse of that matrix using QR decomposition and
backward substitution. backward substitution.
""" """
function invert(a::Matrix{uwreal}) function invert(a::Matrix{uwreal})
q,r = qr(a) q,r = qr(a)
r_inv = upper_inversion(r) r_inv = upper_inversion(r)
return uwdot(r_inv, transpose(q)) return uwdot(r_inv, transpose(q))
end end
""" """
Performs a Cholesky decomposition of A, which must Performs a Cholesky decomposition of A, which must
be a symmetric and positive definite matrix. The function be a symmetric and positive definite matrix. The function
returns the lower variant triangular matrix, L. returns the lower variant triangular matrix, L.
""" """
function uwcholesky(A::Matrix{uwreal}) function uwcholesky(A::Matrix{uwreal})
n = size(A,1) n = size(A,1)
L = fill(uwreal(0), n, n) L = fill(uwreal(0), n, n)
for i in 1:n for i in 1:n
for k in 1:i for k in 1:i
tmp_sum = sum(L[i,j] * L[k,j] for j in 1:k) tmp_sum = sum(L[i,j] * L[k,j] for j in 1:k)
if i==k if i==k
L[i,k] = sqrt(((A[i,i] - tmp_sum))) L[i,k] = sqrt(((A[i,i] - tmp_sum)))
else else
L[i,k] = (1.0 / L[k,k] * (A[i,k]-tmp_sum)) L[i,k] = (1.0 / L[k,k] * (A[i,k]-tmp_sum))
end end
end end
end end
return L return L
end end
""" """
qr(A::Matrix{uwreal}) qr(A::Matrix{uwreal})
qr(A::Matrix{Float64}) qr(A::Matrix{Float64})
This methods returns the QR decomposition of a matrix A of either uwreal or Float64 variables This methods returns the QR decomposition of a matrix A of either uwreal or Float64 variables
""" """
function qr(A::Matrix{uwreal}) function qr(A::Matrix{uwreal})
m,n = size(A) m,n = size(A)
Q = idty(m) Q = idty(m)
for i in 1:(n-(m==n)) for i in 1:(n-(m==n))
H = idty(m) H = idty(m)
H[i:m,i:m] = make_householder(A[i:m,i]) H[i:m,i:m] = make_householder(A[i:m,i])
Q = uwdot(Q,H) Q = uwdot(Q,H)
A = uwdot(H,A) A = uwdot(H,A)
end end
for i in 2:n for i in 2:n
for j in 1:i-1 for j in 1:i-1
A[i,j] = 0.0 A[i,j] = 0.0
end end
end end
return Q,A return Q,A
end end
function qr(A::Matrix{Float64}) function qr(A::Matrix{Float64})
m,n = size(A) m,n = size(A)
Q = Matrix{Float64}(I,m,m) Q = Matrix{Float64}(I,m,m)
for i in 1:(n-(m==n)) for i in 1:(n-(m==n))
H = Matrix{Float64}(I,m,m) H = Matrix{Float64}(I,m,m)
H[i:m,i:m] = make_householder(A[i:m,i]) H[i:m,i:m] = make_householder(A[i:m,i])
X = similar(Q) X = similar(Q)
Y = similar(A) Y = similar(A)
Q = mul!(X,Q,H) Q = mul!(X,Q,H)
A = mul!(Y,H,A) A = mul!(Y,H,A)
end end
return Q,A return Q,A
end end
""" """
make_householder(a::Vector{uwreal}) make_householder(a::Vector{uwreal})
make_householder(a::Vector{Float64}) make_householder(a::Vector{Float64})
This method returns the householder matrix used in qr decomposition to get an upper triangular matrix This method returns the householder matrix used in qr decomposition to get an upper triangular matrix
It takes as input either a vector of uwreal or a vector of Float64 It takes as input either a vector of uwreal or a vector of Float64
""" """
function make_householder(a::Vector{uwreal}) function make_householder(a::Vector{uwreal})
n = length(a) n = length(a)
v = Vector{uwreal}(undef, n) v = Vector{uwreal}(undef, n)
for i in 1:n for i in 1:n
v[i] = a[i] / (a[1] + uwcopysign(uwnorm(a), a[1])) v[i] = a[i] / (a[1] + uwcopysign(uwnorm(a), a[1]))
end end
v[1] = uwreal(1.0) v[1] = uwreal(1.0)
H = idty(n) H = idty(n)
H = H - (2.0 / uwdot(v,v)) * uwdot(reshape(v, :,1), transpose(v)) #this last term is a vector product H = H - (2.0 / uwdot(v,v)) * uwdot(reshape(v, :,1), transpose(v)) #this last term is a vector product
return H return H
end end
function make_householder(a::Vector{Float64}) function make_householder(a::Vector{Float64})
n = length(a) n = length(a)
v = a / (a[1] + copysign(norm(a), a[1])) v = a / (a[1] + copysign(norm(a), a[1]))
v[1] = 1.0 v[1] = 1.0
H = Matrix{Float64}(I, n, n) H = Matrix{Float64}(I, n, n)
println(typeof(v)) println(typeof(v))
y = similar(H) y = similar(H)
println(typeof(y)) println(typeof(y))
H = H .- (2.0 / dot(v,v)) * mul!(y, v, transpose(v)) H = H .- (2.0 / dot(v,v)) * mul!(y, v, transpose(v))
return H return H
end end
""" """
This function computes a vector u that generates a Householder reflection H = I - uu* satisfying Ha=nu*e1. This function computes a vector u that generates a Householder reflection H = I - uu* satisfying Ha=nu*e1.
Accumulating this transformations any matrix can Accumulating this transformations any matrix can
be reduced to upper Hessenberg form. be reduced to upper Hessenberg form.
""" """
function house_gen(a::Vector{uwreal}) function house_gen(a::Vector{uwreal})
u = deepcopy(a) u = deepcopy(a)
nu = uwnorm(a) nu = uwnorm(a)
if nu == 0 if nu == 0
u[1] = sqrt(2) u[1] = sqrt(2)
end end
if u[1] != 0 if u[1] != 0
rho = u[1] / sqrt(u[1]*u[1]) rho = u[1] / sqrt(u[1]*u[1])
else else
rho = 1 rho = 1
end end
u = uwdot(rho/nu, u) u = uwdot(rho/nu, u)
u[1] += 1 u[1] += 1
u = uwdot(u , 1/sqrt(u[1])) u = uwdot(u , 1/sqrt(u[1]))
nu = -(rho) * nu nu = -(rho) * nu
return u, nu return u, nu
end end
""" """
hess_red(a::Matrix{uwreal}) hess_red(a::Matrix{uwreal})
Given a matrix of uwreal variables, this function returns the Hessenberg form of the matrix by applying householder transformations. Given a matrix of uwreal variables, this function returns the Hessenberg form of the matrix by applying householder transformations.
""" """
function hess_reduce(a::Matrix{uwreal}; q_mat::Bool=false) function hess_reduce(a::Matrix{uwreal}; q_mat::Bool=false)
n = size(a,1) n = size(a,1)
H = deepcopy(a) H = deepcopy(a)
Q = idty(n) Q = idty(n)
for k in 1:n-2 for k in 1:n-2
u, H[k+1,k] = house_gen(H[k+1:n,k]) u, H[k+1,k] = house_gen(H[k+1:n,k])
Q[k+1:n,k] = u Q[k+1:n,k] = u
v = uwdot(u,H[k+1:n, k+1:n]) v = uwdot(u,H[k+1:n, k+1:n])
H[k+1:n, k+1:n] .= H[k+1:n, k+1:n] .- uwdot(reshape(u,length(u),1),v) H[k+1:n, k+1:n] .= H[k+1:n, k+1:n] .- uwdot(reshape(u,length(u),1),v)
H[k+2:n,k] .= 0.0 H[k+2:n,k] .= 0.0
v = uwdot(H[1:n,k+1:n], u) v = uwdot(H[1:n,k+1:n], u)
H[1:n,k+1:n] .= H[1:n,k+1:n] .- uwdot(v,reshape(u,1,length(u))) H[1:n,k+1:n] .= H[1:n,k+1:n] .- uwdot(v,reshape(u,1,length(u)))
end end
if q_mat if q_mat
Id = idty(n) Id = idty(n)
for k in reverse(1:n-2) for k in reverse(1:n-2)
u = Q[k+1:n, k] u = Q[k+1:n, k]
v = uwdot(u, Q[k+1:n,k+1:n]) v = uwdot(u, Q[k+1:n,k+1:n])
Q[k+1:n,k+1:n] .= Q[k+1:n,k+1:n] .- uwdot(reshape(u,length(u),1),v) Q[k+1:n,k+1:n] .= Q[k+1:n,k+1:n] .- uwdot(reshape(u,length(u),1),v)
Q[:,k] = Id[:,k] Q[:,k] = Id[:,k]
end end
return H,Q return H,Q
else else
return H return H
end end
end end
""" """
""" """
function tridiag_reduction(a::Matrix{uwreal}; q_mat::Bool=false) function tridiag_reduction(a::Matrix{uwreal}; q_mat::Bool=false)
n = size(a,1) n = size(a,1)
H = deepcopy(a) H = deepcopy(a)
Q = idty(n) Q = idty(n)
for k in 1:n-2 for k in 1:n-2
u, H[k+1,k] = house_gen(H[k+1:n,k]) u, H[k+1,k] = house_gen(H[k+1:n,k])
Q[k+1:n,k] = u Q[k+1:n,k] = u
v = uwdot(u,H[k+1:n, k+1:n]) v = uwdot(u,H[k+1:n, k+1:n])
H[k+1:n, k+1:n] .= H[k+1:n, k+1:n] .- uwdot(reshape(u,length(u),1),v) H[k+1:n, k+1:n] .= H[k+1:n, k+1:n] .- uwdot(reshape(u,length(u),1),v)
H[k+2:n,k] .= 0.0 H[k+2:n,k] .= 0.0
v = uwdot(H[1:n,k+1:n], u) v = uwdot(H[1:n,k+1:n], u)
H[1:n,k+1:n] .= H[1:n,k+1:n] .- uwdot(v,reshape(u,1,length(u))) H[1:n,k+1:n] .= H[1:n,k+1:n] .- uwdot(v,reshape(u,1,length(u)))
H[k,k+2:n] .= 0.0 H[k,k+2:n] .= 0.0
end end
if q_mat if q_mat
Id = idty(n) Id = idty(n)
for k in reverse(1:n-2) for k in reverse(1:n-2)
u = Q[k+1:n, k] u = Q[k+1:n, k]
v = uwdot(u, Q[k+1:n,k+1:n]) v = uwdot(u, Q[k+1:n,k+1:n])
Q[k+1:n,k+1:n] .= Q[k+1:n,k+1:n] .- uwdot(reshape(u,length(u),1),v) Q[k+1:n,k+1:n] .= Q[k+1:n,k+1:n] .- uwdot(reshape(u,length(u),1),v)
Q[:,k] = Id[:,k] Q[:,k] = Id[:,k]
end end
return H,Q return H,Q
else else
return H return H
end end
end end
""" """
upper_inversion(u::Matrix{uwreal}) upper_inversion(u::Matrix{uwreal})
This method uses backward propagation to compute the inverse of an upper triangular matrix u. Note that the inverse of u must be upper triangular as well. This method uses backward propagation to compute the inverse of an upper triangular matrix u. Note that the inverse of u must be upper triangular as well.
Tests executed so far always confirmed this property. Tests executed so far always confirmed this property.
""" """
function upper_inversion(u::Matrix{uwreal}) function upper_inversion(u::Matrix{uwreal})
n = size(u,1) n = size(u,1)
u_inv = Matrix{uwreal}(undef, n, n) u_inv = Matrix{uwreal}(undef, n, n)
for i in 1:n for i in 1:n
e_i = canonical_basis(n, i) e_i = canonical_basis(n, i)
x = backward_sub(u, e_i) x = backward_sub(u, e_i)
u_inv[:,i] = x u_inv[:,i] = x
end end
return u_inv return u_inv
end end
""" """
backward_sub(u::Matrix{uwreal}, y::Vector{uwreal}) backward_sub(u::Matrix{uwreal}, y::Vector{uwreal})
This method operates backward substitution to solve a liner system Ux = y where U is an upper triangular uwreal matrix This method operates backward substitution to solve a liner system Ux = y where U is an upper triangular uwreal matrix
and y is a uwreal vector. It returns a vector of uwreal x that might be used to inverte the upper triangular matrix U. and y is a uwreal vector. It returns a vector of uwreal x that might be used to inverte the upper triangular matrix U.
""" """
function backward_sub(u::Matrix{uwreal}, y::Vector{uwreal}) function backward_sub(u::Matrix{uwreal}, y::Vector{uwreal})
n = length(y) n = length(y)
x = Vector{uwreal}(undef, n) x = Vector{uwreal}(undef, n)
x[n] = y[n] / u[n,n] x[n] = y[n] / u[n,n]
for i in range(n-1,1, step=-1) for i in range(n-1,1, step=-1)
temp = 0.0 temp = 0.0
for j in i+1:n for j in i+1:n
temp += u[i,j] * x[j] temp += u[i,j] * x[j]
end end
x[i] = (y[i] - temp) /u[i,i] x[i] = (y[i] - temp) /u[i,i]
if x[i] !=0 if x[i] !=0
end end
end end
return x return x
end end
""" """
canonical_basis(n::Int64, k::Int64) canonical_basis(n::Int64, k::Int64)
Given the dimension n and the position k, canonical_basis returns a vector of uwreal with all entries set to zero Given the dimension n and the position k, canonical_basis returns a vector of uwreal with all entries set to zero
except for the k-th entry which is set to 1.0. except for the k-th entry which is set to 1.0.
This method is used as input vector in backward_sub to compute the inverse of an upper triangular matrix. This method is used as input vector in backward_sub to compute the inverse of an upper triangular matrix.
""" """
function canonical_basis(n::Int64, k::Int64) function canonical_basis(n::Int64, k::Int64)
e = zeros(n) e = zeros(n)
e[k] = 1.0 e[k] = 1.0
return [uwreal(e[i]) for i=1:n] return [uwreal(e[i]) for i=1:n]
end end
""" """
uwdot(a::Vector{uwreal}, b::Vector{uwreal}) uwdot(a::Vector{uwreal}, b::Vector{uwreal})
uwdot(a::Matrix{uwreal}, b::Matrix{uwreal}) uwdot(a::Matrix{uwreal}, b::Matrix{uwreal})
Depending on the arguments, uwdot returns the vector vector or the matrix matrix product Depending on the arguments, uwdot returns the vector vector or the matrix matrix product
of uwreal data type. of uwreal data type.
""" """
uwdot(a::Vector{uwreal}, b::Vector{uwreal}) = sum(a .* b) uwdot(a::Vector{uwreal}, b::Vector{uwreal}) = sum(a .* b)
uwdot(a::Vector{uwreal}, b::uwreal) = [a[i] * b for i=1:length(a)] uwdot(a::Vector{uwreal}, b::uwreal) = [a[i] * b for i=1:length(a)]
uwdot(a::uwreal, b::Vector{uwreal}) = uwdot(b,a) uwdot(a::uwreal, b::Vector{uwreal}) = uwdot(b,a)
uwdot(a::Matrix{uwreal}, b::Vector{uwreal}) = uwdot(a, reshape(b,(length(b),1))) uwdot(a::Matrix{uwreal}, b::Vector{uwreal}) = uwdot(a, reshape(b,(length(b),1)))
uwdot(a::Vector{uwreal}, b::Matrix{uwreal}) = uwdot(reshape(a,(1,length(a))), b) uwdot(a::Vector{uwreal}, b::Matrix{uwreal}) = uwdot(reshape(a,(1,length(a))), b)
function uwdot(a::Matrix{uwreal}, b::Matrix{uwreal}) function uwdot(a::Matrix{uwreal}, b::Matrix{uwreal})
n,m = size(a) n,m = size(a)
k,p = size(b) k,p = size(b)
c = Matrix{uwreal}(undef, n, p) c = Matrix{uwreal}(undef, n, p)
if m != k if m != k
error("Error uwdot: in a*b the size of a is ", size(a), " while the size of b is ", size(b) ) error("Error uwdot: in a*b the size of a is ", size(a), " while the size of b is ", size(b) )
end end
for i = 1:n for i = 1:n
for j = 1:p for j = 1:p
c[i, j] = sum(a[i, :] .* b[:, j]) c[i, j] = sum(a[i, :] .* b[:, j])
end end
end end
return c return c
end end
""" """
uwnorm(a::Vector{uwreal}) uwnorm(a::Vector{uwreal})
It returns the norm of a vector of uwreal It returns the norm of a vector of uwreal
""" """
function uwnorm(a::Vector{uwreal}; wpm::Union{Dict{Int64,Vector{Float64}},Dict{String,Vector{Float64}}, Nothing}=nothing) function uwnorm(a::Vector{uwreal}; wpm::Union{Dict{Int64,Vector{Float64}},Dict{String,Vector{Float64}}, Nothing}=nothing)
norm = sqrt(uwdot(a,a)) norm = sqrt(uwdot(a,a))
#isnothing(wpm) ? uwerr(norm) : uwerr(norm, wpm) #isnothing(wpm) ? uwerr(norm) : uwerr(norm, wpm)
return norm return norm
end end
""" """
Return the transpose of a matrix or vector of uwreals Return the transpose of a matrix or vector of uwreals
""" """
function Base.transpose(a::Matrix{uwreal}) function Base.transpose(a::Matrix{uwreal})
res = similar(a) res = similar(a)
n = size(a, 1) n = size(a, 1)
if size(a,1) == 1 if size(a,1) == 1
return reshape(a, :,1) return reshape(a, :,1)
elseif size(a,2) == 1 elseif size(a,2) == 1
return reshape(a, 1,:) return reshape(a, 1,:)
end end
for i in 1:n-1 for i in 1:n-1
for j in i+1:n for j in i+1:n
temp = a[i,j] temp = a[i,j]
res[i,j] = a[j,i] res[i,j] = a[j,i]
res[j,i] = temp res[j,i] = temp
end end
res[i,i] = a[i,i] res[i,i] = a[i,i]
end end
res[n,n] = a[n,n] res[n,n] = a[n,n]
return res return res
end end
function Base.transpose(vec::Vector{uwreal}) function Base.transpose(vec::Vector{uwreal})
res = deepcopy(vec) res = deepcopy(vec)
return reshape(res,1,:) return reshape(res,1,:)
end end
""" """
uwcopysign(a::uwreal, b::uwreal) uwcopysign(a::uwreal, b::uwreal)
It implements the copysign function for uwreal variables It implements the copysign function for uwreal variables
""" """
function uwcopysign(a::uwreal, b::uwreal) function uwcopysign(a::uwreal, b::uwreal)
c = deepcopy(a) c = deepcopy(a)
aux = copysign(value(a), value(b)) aux = copysign(value(a), value(b))
c.mean = aux c.mean = aux
return c return c
end end
""" """
idty(n::Int64) idty(n::Int64)
It returns an indetity matrix of uwreal variables given the size n It returns an indetity matrix of uwreal variables given the size n
""" """
function idty(n::Int64) function idty(n::Int64)
res = Matrix{uwreal}(undef,n,n) res = Matrix{uwreal}(undef,n,n)
for i in 1:n for i in 1:n
for j in 1:n for j in 1:n
if i==j if i==j
res[i,j]=1.0 res[i,j]=1.0
else else
res[i,j]=0.0 res[i,j]=0.0
end end
end end
end end
return res return res
end end
function make_positive_def(A::Matrix; eps::Float64=10^(-14)) function make_positive_def(A::Matrix; eps::Float64=10^(-14))
vals, vecs = eigen(Symmetric(A)) vals, vecs = eigen(Symmetric(A))
idx = findall(x-> x<0.0, vals) idx = findall(x-> x<0.0, vals)
vals[idx] .= eps vals[idx] .= eps
return Symmetric(vecs * Diagonal(vals) * vecs') return Symmetric(vecs * Diagonal(vals) * vecs')
#B = 0.5 * (A + A') #B = 0.5 * (A + A')
#U, S, V = svd(B) #U, S, V = svd(B)
#H = V * Diagonal(S) * V' #H = V * Diagonal(S) * V'
#A_hat = 0.5 * (B + H) #A_hat = 0.5 * (B + H)
#A_hat = 0.5 * ( A_hat + A_hat') #A_hat = 0.5 * ( A_hat + A_hat')
#k = 0 #k = 0
#while !isposdef(A_hat) #while !isposdef(A_hat)
# mineig = minimum(eigvals(A_hat)) # mineig = minimum(eigvals(A_hat))
# eps = 2.220446049250313e-16 # eps = 2.220446049250313e-16
# A_hat = A_hat + (-mineig*k^2 .+ eps*Matrix(I, size(A))) # A_hat = A_hat + (-mineig*k^2 .+ eps*Matrix(I, size(A)))
# k+=1 # k+=1
#end #end
#return A_hat #return A_hat
end end
function invert_covar_matrix(A::Matrix; eps::Float64=10^(-9)) function invert_covar_matrix(A::Matrix; eps::Float64=10^(-9))
F = svd(A) F = svd(A)
s_diag = F.S s_diag = F.S
for i in 1:length(s_diag) for i in 1:length(s_diag)
if s_diag[i] < eps if s_diag[i] < eps
s_diag[i] = 0.0 s_diag[i] = 0.0
else else
s_diag[i] = 1 / s_diag[i] s_diag[i] = 1 / s_diag[i]
end end
end end
cov_inv = F.V * Diagonal(s_diag) * F.U' cov_inv = F.V * Diagonal(s_diag) * F.U'
return cov_inv return cov_inv
end end
function more_penrose_inv(A::Matrix) function more_penrose_inv(A::Matrix)
F = svd(A) F = svd(A)
end end
######################## ########################
# OPERATOR OVERLOADING # OPERATOR OVERLOADING
######################## ########################
function Base.:*(x::uwreal, y::Array{Any}) function Base.:*(x::uwreal, y::Array{Any})
N = size(y, 1) N = size(y, 1)
return fill(x, N) .* y return fill(x, N) .* y
end end
Base.:*(x::Array{Any}, y::uwreal) = Base.:*(y,x) Base.:*(x::Array{Any}, y::uwreal) = Base.:*(y,x)
function Base.:*(x::uwreal, y::Array{Float64}) function Base.:*(x::uwreal, y::Array{Float64})
N = size(y, 1) N = size(y, 1)
return fill(x, N) .* y return fill(x, N) .* y
end end
Base.:*(x::Array{Float64}, y::uwreal) = Base.:*(y,x) Base.:*(x::Array{Float64}, y::uwreal) = Base.:*(y,x)
function Base.:*(x::uwreal, y::Array{uwreal}) function Base.:*(x::uwreal, y::Array{uwreal})
N = size(y, 1) N = size(y, 1)
return fill(x, N) .* y return fill(x, N) .* y
end end
Base.:*(x::Array{uwreal}, y::uwreal) = Base.:*(y,x) Base.:*(x::Array{uwreal}, y::uwreal) = Base.:*(y,x)
function Base.:+(x::uwreal, y::Vector{uwreal}) function Base.:+(x::uwreal, y::Vector{uwreal})
N = size(y, 1) N = size(y, 1)
return fill(x, N) .+ y return fill(x, N) .+ y
end end
function Base.:+(x::Float64, y::Vector{Float64}) function Base.:+(x::Float64, y::Vector{Float64})
N = size(y, 1) N = size(y, 1)
return fill(x, N) .+ y return fill(x, N) .+ y
end end
function Base.:+(x::Float64, y::Vector{uwreal}) function Base.:+(x::Float64, y::Vector{uwreal})
N = size(y, 1) N = size(y, 1)
return fill(x, N) .+ y return fill(x, N) .+ y
end end
function Base.:-(x::Float64, y::Vector{Any}) function Base.:-(x::Float64, y::Vector{Any})
N = size(y, 1) N = size(y, 1)
return fill(x, N) .- y return fill(x, N) .- y
end end
function Base.:-(x::Float64, y::Vector{Float64}) function Base.:-(x::Float64, y::Vector{Float64})
N = size(y, 1) N = size(y, 1)
return fill(x, N) .- y return fill(x, N) .- y
end end
function Base.:-(x::Float64, y::Vector{uwreal}) function Base.:-(x::Float64, y::Vector{uwreal})
N = size(y, 1) N = size(y, 1)
return fill(x, N) .- y return fill(x, N) .- y
end end
function Base.length(uw::uwreal) function Base.length(uw::uwreal)
return length(value(uw)) return length(value(uw))
end end
Base.length(c::juobs.Corr) = 1 Base.length(c::juobs.Corr) = 1
function Base.iterate(uw::uwreal) function Base.iterate(uw::uwreal)
return iterate(uw, 1) return iterate(uw, 1)
end end
function Base.iterate(c::juobs.Corr,state::Int64) function Base.iterate(c::juobs.Corr,state::Int64)
if state >length(c) if state >length(c)
return nothing return nothing
else else
return c[state], state+1 return c[state], state+1
end end
end end
Base.iterate(c::juobs.Corr) = iterate(c,1) Base.iterate(c::juobs.Corr) = iterate(c,1)
function Base.iterate(uw::uwreal, state::Int64) function Base.iterate(uw::uwreal, state::Int64)
if state > length(uw) if state > length(uw)
return nothing return nothing
else else
return uw[state], state +1 return uw[state], state +1
end end
end end
function Base.iterate(uw::Vector{uwreal}) function Base.iterate(uw::Vector{uwreal})
return iterate(uw, 1) return iterate(uw, 1)
end end
function Base.iterate(uw::Vector{uwreal}, state::Int64) function Base.iterate(uw::Vector{uwreal}, state::Int64)
if state > length(uw) if state > length(uw)
return nothing return nothing
else else
return uw[state], state +1 return uw[state], state +1
end end
end end
function Base.getindex(uw::uwreal, ii) function Base.getindex(uw::uwreal, ii)
if ii>length(uw) || ii<=0 if ii>length(uw) || ii<=0
throw(BoundsError(uw,[ii])) throw(BoundsError(uw,[ii]))
end end
return uw # uwreal([getindex(value(uw), kwargs...), err(uw)], " ") return uw # uwreal([getindex(value(uw), kwargs...), err(uw)], " ")
end end
function Base.getindex(c::juobs.Corr, ii) function Base.getindex(c::juobs.Corr, ii)
if ii>length(c) || ii<=0 if ii>length(c) || ii<=0
throw(BoundsError(c,[ii])) throw(BoundsError(c,[ii]))
end end
return c return c
end end
""" """
Base.abs2(uw::uwreal) Base.abs2(uw::uwreal)
Return the square absolute value. Return the square absolute value.
## Warning ## Warning
Previously this function returned the absolute value of `uw`, not the square absolute value. Previously this function returned the absolute value of `uw`, not the square absolute value.
The function was changed to make it consistent with `Base.abs2()` in Julia. The function was changed to make it consistent with `Base.abs2()` in Julia.
When used, a warning is printed to informe of this change future users, feel free to remove the warning """
from your branch! Base.abs2(uw::uwreal) = uw^2
"""
function Base.abs2(uw::uwreal) """
@warn "This function was updated by Antonino to make it consisted with the Julia version of it. Base.abs(uw::uwreal)
Check the documentation for info and then feel free to comment out this warning in your branch"
return uw^2 Return the absolute value of `uw` by taking the square root of `uw^2`.
end """
""" Base.abs(uw::uwreal) = sqrt(uw^2);
Base.abs(uw::uwreal)
"""
Return the absolute value of `uw` by taking the square root of `uw^2`. Base.:*(x::uwreal, y::Matrix{uwreal})
"""
Base.abs(uw::uwreal) = sqrt(uw^2); Multiplication operator overloading between uwreal variable and matrix of uwreal
"""
""" function Base.:*(x::uwreal, y::Matrix{uwreal})
Base.:*(x::uwreal, y::Matrix{uwreal}) n,m = size(y)
res = Matrix{uwreal}(undef, n,m)
Multiplication operator overloading between uwreal variable and matrix of uwreal for i in 1:n
""" for j in 1:m
function Base.:*(x::uwreal, y::Matrix{uwreal}) res[i,j] = x * y[i,j]
n,m = size(y) if res[i,j] !=0 && res[i,j] !=1
res = Matrix{uwreal}(undef, n,m) end
for i in 1:n end
for j in 1:m end
res[i,j] = x * y[i,j] return res
if res[i,j] !=0 && res[i,j] !=1 end
end
end
end
return res
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment