Commit 5f3ab2cc authored by Antonino's avatar Antonino

Reverted Gamma method to accept only Vector

parent 30cb3eb7
""" """
GammaMethod GammaMethod
It includes function for the the Gamma Method. It is intended to complement ADerrors, so any function that is made obsolete It includes function for the the Gamma Method. It is intended to complement ADerrors, so any function that is made obsolete
by an newer version of ADerrors should be deprecrated. by an newer version of ADerrors should be deprecrated.
# Methods # Methods
- calc_gamma(a1::ADerrors.uwreal [,a2::Aderrors.uwreal] ,id::Union{Int64,String}[, ws::ADerrors.wspace]) - calc_gamma(a1::ADerrors.uwreal [,a2::Aderrors.uwreal] ,id::Union{Int64,String}[, ws::ADerrors.wspace])
- bias(a1::ADerrors.uwreal [,a2::ADerrors.uwreal], id::Union{Int64,String} [, ws::Aderrors.wspace]; iw::Int64=0) - bias(a1::ADerrors.uwreal [,a2::ADerrors.uwreal], id::Union{Int64,String} [, ws::Aderrors.wspace]; iw::Int64=0)
- cov_pe(vobs::Vectir{ADerrors.uwreal}[,ws:ADerrors.wspace]) - cov_pe(vobs::Vectir{ADerrors.uwreal}[,ws:ADerrors.wspace])
...@@ -14,11 +14,11 @@ by an newer version of ADerrors should be deprecrated. ...@@ -14,11 +14,11 @@ by an newer version of ADerrors should be deprecrated.
- chiexp(chisq::Function,par,d,C,W) - chiexp(chisq::Function,par,d,C,W)
""" """
module GammaMethod module GammaMethod
import ADerrors, ForwardDiff, LinearAlgebra import ADerrors, ForwardDiff, LinearAlgebra
""" """
calc_gamma(a1::ADerrors.uwreal [,a2::Aderrors.uwreal] ,id::Union{Int64,String}[, ws::ADerrors.wspace]) calc_gamma(a1::ADerrors.uwreal [,a2::Aderrors.uwreal] ,id::Union{Int64,String}[, ws::ADerrors.wspace])
Computes the Gamma function associated to the ensemble `id` without the bias included by ADerrors for t>=0 Computes the Gamma function associated to the ensemble `id` without the bias included by ADerrors for t>=0
If `id` is not associated to a Montecarlo chain, it return a Vector with the correlation between `a1` and `a2` If `id` is not associated to a Montecarlo chain, it return a Vector with the correlation between `a1` and `a2`
...@@ -31,7 +31,7 @@ function calc_gamma(a1::ADerrors.uwreal,a2::ADerrors.uwreal,id::Int64,ws::ADerro ...@@ -31,7 +31,7 @@ function calc_gamma(a1::ADerrors.uwreal,a2::ADerrors.uwreal,id::Int64,ws::ADerro
if !(id in a1.ids) || !(id in a2.ids) if !(id in a1.ids) || !(id in a2.ids)
return [0.0] return [0.0]
end end
if nd==1 if nd==1
function get_v(a,id=id,ws=ws) function get_v(a,id=id,ws=ws)
v = 0 v = 0
...@@ -51,15 +51,15 @@ function calc_gamma(a1::ADerrors.uwreal,a2::ADerrors.uwreal,id::Int64,ws::ADerro ...@@ -51,15 +51,15 @@ function calc_gamma(a1::ADerrors.uwreal,a2::ADerrors.uwreal,id::Int64,ws::ADerro
nrep = length(ws.fluc[idx].ivrep) nrep = length(ws.fluc[idx].ivrep)
ftemp1 = Dict{Int64,Vector{Complex{Float64}}}() ftemp1 = Dict{Int64,Vector{Complex{Float64}}}()
ftemp2 = Dict{Int64,Vector{Complex{Float64}}}() ftemp2 = Dict{Int64,Vector{Complex{Float64}}}()
for i in 1:nrep for i in 1:nrep
ns = length(ws.fluc[idx].fourier[i]) ns = length(ws.fluc[idx].fourier[i])
ftemp1[i] = zeros(Complex{Float64}, ns) ftemp1[i] = zeros(Complex{Float64}, ns)
ftemp2[i] = zeros(Complex{Float64}, ns) ftemp2[i] = zeros(Complex{Float64}, ns)
end end
gamma = zeros(Float64, nt) gamma = zeros(Float64, nt)
for i in eachindex(a1.prop) for i in eachindex(a1.prop)
if (a1.prop[i] && (ws.map_nob[i] == id)) if (a1.prop[i] && (ws.map_nob[i] == id))
for k in 1:nrep for k in 1:nrep
...@@ -69,62 +69,62 @@ function calc_gamma(a1::ADerrors.uwreal,a2::ADerrors.uwreal,id::Int64,ws::ADerro ...@@ -69,62 +69,62 @@ function calc_gamma(a1::ADerrors.uwreal,a2::ADerrors.uwreal,id::Int64,ws::ADerro
end end
for i in eachindex(a2.prop) for i in eachindex(a2.prop)
if (a2.prop[i] && (ws.map_nob[i] == id)) if (a2.prop[i] && (ws.map_nob[i] == id))
for k in 1:nrep for k in 1:nrep
ftemp2[k] = ftemp2[k] + a2.der[i]*ws.fluc[i].fourier[k] ftemp2[k] = ftemp2[k] + a2.der[i]*ws.fluc[i].fourier[k]
end
end end
end
end end
for k in 1:nrep for k in 1:nrep
ftemp2[k] .= ftemp1[k].*conj(ftemp2[k]) ftemp2[k] .= ftemp1[k].*conj(ftemp2[k])
ADerrors.FFTW.ifft!(ftemp2[k]) ADerrors.FFTW.ifft!(ftemp2[k])
for ig in 1:min(nt,length(ftemp2[k])) for ig in 1:min(nt,length(ftemp2[k]))
gamma[ig] = gamma[ig] + real(ftemp2[k][ig]) gamma[ig] = gamma[ig] + real(ftemp2[k][ig])
end end
end end
for ig in 1:nt for ig in 1:nt
nrcnt = count(map(x -> div(x, 2*ws.fluc[idx].ibn), ws.fluc[idx].ivrep) .> ig-1) nrcnt = count(map(x -> div(x, 2*ws.fluc[idx].ibn), ws.fluc[idx].ivrep) .> ig-1)
gamma[ig] = gamma[ig] / (nd_eff - nrcnt*(ig-1)) gamma[ig] = gamma[ig] / (nd_eff - nrcnt*(ig-1))
end end
return gamma return gamma
end end
calc_gamma(a1::ADerrors.uwreal,a2::ADerrors.uwreal,id::String,ws::ADerrors.wspace) = calc_gamma(a1,a2,ws.str2id[id],ws) calc_gamma(a1::ADerrors.uwreal,a2::ADerrors.uwreal,id::String,ws::ADerrors.wspace) = calc_gamma(a1,a2,ws.str2id[id],ws)
calc_gamma(a1::ADerrors.uwreal,a2::ADerrors.uwreal,id::String) = calc_gamma(a1,a2,ADerrors.wsg.str2id[id],ADerrors.wsg) calc_gamma(a1::ADerrors.uwreal,a2::ADerrors.uwreal,id::String) = calc_gamma(a1,a2,ADerrors.wsg.str2id[id],ADerrors.wsg)
calc_gamma(a1::ADerrors.uwreal,a2::ADerrors.uwreal,id::Int64) = calc_gamma(a1,a2,id,ADerrors.wsg) calc_gamma(a1::ADerrors.uwreal,a2::ADerrors.uwreal,id::Int64) = calc_gamma(a1,a2,id,ADerrors.wsg)
calc_gamma(a::ADerrors.uwreal,id::Int64,ws::ADerrors.wspace) = calc_gamma(a,a,id,ws) calc_gamma(a::ADerrors.uwreal,id::Int64,ws::ADerrors.wspace) = calc_gamma(a,a,id,ws)
calc_gamma(a::ADerrors.uwreal,id::String,ws::ADerrors.wspace) = calc_gamma(a,a,ws.str2id[id],ws) calc_gamma(a::ADerrors.uwreal,id::String,ws::ADerrors.wspace) = calc_gamma(a,a,ws.str2id[id],ws)
calc_gamma(a::ADerrors.uwreal,id::String) = calc_gamma(a,a,ADerrors.wsg.str2id[id],ADerrors.wsg) calc_gamma(a::ADerrors.uwreal,id::String) = calc_gamma(a,a,ADerrors.wsg.str2id[id],ADerrors.wsg)
calc_gamma(a::ADerrors.uwreal,id::Int64) = calc_gamma(a,a,id,ADerrors.wsg) calc_gamma(a::ADerrors.uwreal,id::Int64) = calc_gamma(a,a,id,ADerrors.wsg)
function drho(rho::Vector{Float64},nd::Int64,iw::Int64=0) function drho(rho::Vector{Float64},nd::Int64,iw::Int64=0)
iw = iw ==0 ? ADerrors.wopt_ulli(nd,ADerrors.DEFAULT_STAU,rho) : iw iw = iw ==0 ? ADerrors.wopt_ulli(nd,ADerrors.DEFAULT_STAU,rho) : iw
nt = length(rho); nt = length(rho);
dr = zeros(nt); dr = zeros(nt);
for t in 1:nt for t in 1:nt
is = max(1, t-iw-2) + 1 is = max(1, t-iw-2) + 1
ie = is + iw-1 ie = is + iw-1
for m in is:ie for m in is:ie
aux=0.0 aux=0.0
if m <= nt if m <= nt
aux = -2*rho[t]*rho[m] aux = -2*rho[t]*rho[m]
end end
if abs(m-t)<nt if abs(m-t)<nt
aux += rho[abs(m-t)+1] aux += rho[abs(m-t)+1]
end end
if m+t-1<=nt if m+t-1<=nt
aux += rho[m+t-1] aux += rho[m+t-1]
end
dr[t] +=aux^2
end end
dr[t] +=aux^2 dr[t] = sqrt(dr[t]/nd)
end
dr[t] = sqrt(dr[t]/nd)
end end
return dr return dr
end end
""" """
bias(a1::ADerrors.uwreal [,a2::ADerrors.uwreal], id::Union{Int64,String} [, ws::Aderrors.wspace]; iw::Int64=0) bias(a1::ADerrors.uwreal [,a2::ADerrors.uwreal], id::Union{Int64,String} [, ws::Aderrors.wspace]; iw::Int64=0)
it return the bias associated to `id` that ADErrors includes in the estimate of the autocorrelation function it return the bias associated to `id` that ADErrors includes in the estimate of the autocorrelation function
...@@ -137,97 +137,97 @@ function calc_gamma(a1::ADerrors.uwreal,a2::ADerrors.uwreal,id::Int64,ws::ADerro ...@@ -137,97 +137,97 @@ function calc_gamma(a1::ADerrors.uwreal,a2::ADerrors.uwreal,id::Int64,ws::ADerro
if `iw = 0` the integration window is determined by the automatic windowing procedure with S_τ = 4.0 if `iw = 0` the integration window is determined by the automatic windowing procedure with S_τ = 4.0
""" """
function bias(a1::ADerrors.uwreal,a2::ADerrors.uwreal,id::Int64,ws::ADerrors.wspace;iw::Int64=0) function bias(a1::ADerrors.uwreal,a2::ADerrors.uwreal,id::Int64,ws::ADerrors.wspace;iw::Int64=0)
idx = ws.map_ids[id] idx = ws.map_ids[id]
nd = ws.fluc[idx].nd nd = ws.fluc[idx].nd
if nd ==1 if nd ==1
return 0.0 return 0.0
end end
gamma = calc_gamma(a1,a2,id,ws) gamma = calc_gamma(a1,a2,id,ws)
return gamma[1] + 2.0*sum(gamma[2:iw]) return gamma[1] + 2.0*sum(gamma[2:iw])
end end
bias(a1::ADerrors.uwreal,a2::ADerrors.uwreal,id::String,ws::ADerrors.wspace; iw::Int64=0)= bias(a1,a2,ws.str2id[id],ws,iw=iw) bias(a1::ADerrors.uwreal,a2::ADerrors.uwreal,id::String,ws::ADerrors.wspace; iw::Int64=0)= bias(a1,a2,ws.str2id[id],ws,iw=iw)
bias(a1::ADerrors.uwreal,a2::ADerrors.uwreal,id::Int64; iw::Int64=0) = bias(a1,a2,id,wsg,iw=iw) bias(a1::ADerrors.uwreal,a2::ADerrors.uwreal,id::Int64; iw::Int64=0) = bias(a1,a2,id,wsg,iw=iw)
bias(a1::ADerrors.uwreal,a2::ADerrors.uwreal,id::String; iw::Int64=0)= bias(a1,a2,ADerrors.wsg.str2id[id],wsg,iw=iw) bias(a1::ADerrors.uwreal,a2::ADerrors.uwreal,id::String; iw::Int64=0)= bias(a1,a2,ADerrors.wsg.str2id[id],wsg,iw=iw)
function bias(a::ADerrors.uwreal,id::Int64,ws::ADerrors.wspace;iw::Int64=0) function bias(a::ADerrors.uwreal,id::Int64,ws::ADerrors.wspace;iw::Int64=0)
idx = ws.map_ids[id] idx = ws.map_ids[id]
nd = ws.fluc[idx].nd nd = ws.fluc[idx].nd
if nd ==1 if nd ==1
return 0.0 return 0.0
end end
gamma = calc_gamma(a,id,ws) gamma = calc_gamma(a,id,ws)
iw = iw ==0 ? ADerrors.wopt_ulli(nd,ADerrors.DEFAULT_STAU,gamma) : iw iw = iw ==0 ? ADerrors.wopt_ulli(nd,ADerrors.DEFAULT_STAU,gamma) : iw
return gamma[1] + 2.0*sum(gamma[2:iw]) return gamma[1] + 2.0*sum(gamma[2:iw])
end end
bias(a::ADerrors.uwreal,id::String,ws::ADerrors.wspace; iw::Int64=0) = bias(a,ws.str2id[id],ws,iw=iw) bias(a::ADerrors.uwreal,id::String,ws::ADerrors.wspace; iw::Int64=0) = bias(a,ws.str2id[id],ws,iw=iw)
bias(a::ADerrors.uwreal,id::Int64; iw::Int64=0) = bias(a,id,ADerrors.wsg,iw=iw) bias(a::ADerrors.uwreal,id::Int64; iw::Int64=0) = bias(a,id,ADerrors.wsg,iw=iw)
bias(a::ADerrors.uwreal,id::String; iw::Int64=0) = bias(a,ADerrors.wsg.str2id[id],ADerrors.wsg,iw=iw) bias(a::ADerrors.uwreal,id::String; iw::Int64=0) = bias(a,ADerrors.wsg.str2id[id],ADerrors.wsg,iw=iw)
function bias(vobs::Vector{ADerrors.uwreal}, id::Int64, ws::ADerrors.wspace;) function bias(vobs::Vector{ADerrors.uwreal}, id::Int64, ws::ADerrors.wspace;)
b = zeros(length(vobs),length(vobs)) b = zeros(length(vobs),length(vobs))
iw = maximum([ADerrors.window(obs,id) for obs in vobs]) iw = maximum([ADerrors.window(obs,id) for obs in vobs])
for i in 1:length(vobs)-1, j in i+1:length(vobs) for i in 1:length(vobs)-1, j in i+1:length(vobs)
b[i,j] = bias(vobs[i],vobs[j],id,ws,iw=iw) b[i,j] = bias(vobs[i],vobs[j],id,ws,iw=iw)
b[j,i] = b[i,j] b[j,i] = b[i,j]
end end
for i in eachindex(vobs) for i in eachindex(vobs)
b[i,i] = bias(vobs[i],id,ws,iw = 0) b[i,i] = bias(vobs[i],id,ws,iw = 0)
end end
return b return b
end end
bias(vobs::Vector{ADerrors.uwreal}, id::String, ws::ADerrors.wspace) = bias(vobs,ws.str2id[id],ws) bias(vobs::Vector{ADerrors.uwreal}, id::String, ws::ADerrors.wspace) = bias(vobs,ws.str2id[id],ws)
bias(vobs::Vector{ADerrors.uwreal}, id::Int64) = bias(vobs,id,ADerrors.wsg) bias(vobs::Vector{ADerrors.uwreal}, id::Int64) = bias(vobs,id,ADerrors.wsg)
bias(vobs::Vector{ADerrors.uwreal}, id::String) = bias(vobs,ADerrors.wsg.str2id[id],ADerrors.wsg) bias(vobs::Vector{ADerrors.uwreal}, id::String) = bias(vobs,ADerrors.wsg.str2id[id],ADerrors.wsg)
@doc raw""" @doc raw"""
cov_pe(vobs::Vectir{ADerrors.uwreal}[,ws:ADerrors.wspace]) cov_pe(vobs::Vectir{ADerrors.uwreal}[,ws:ADerrors.wspace])
Computes the unbiased covariance matrix of `vobs` à la `pyerrors`. Computes the unbiased covariance matrix of `vobs` à la `pyerrors`.
It first computes the naive correlation matrix and the it multiply it with the errors It first computes the naive correlation matrix and the it multiply it with the errors
of the `vobs`. This method is exact if of the `vobs`. This method is exact if
tau_int^ij = sqrt(tau_int^i tau_int^j) tau_int^ij = sqrt(tau_int^i tau_int^j)
It assumes that `ADerrors.uwerr` has been run on `vobs` It assumes that `ADerrors.uwerr` has been run on `vobs`
This method is stable in the sense that the covarince of two `ADerrors.uwreal` depends only This method is stable in the sense that the covarince of two `ADerrors.uwreal` depends only
on them and not on the others `ADerrors.uwreal` that are in `vobs` on them and not on the others `ADerrors.uwreal` that are in `vobs`
See also [`cov_min`](@ref) [`cov_ad`](@ref) See also [`cov_min`](@ref) [`cov_ad`](@ref)
""" """
function cov_pe(vobs::AbstractVector{ADerrors.uwreal}, ws::ADerrors.wspace) function cov_pe(vobs::Vector{ADerrors.uwreal}, ws::ADerrors.wspace)
ids = ADerrors.unique_ids_multi(vobs, ws) ids = ADerrors.unique_ids_multi(vobs, ws)
nid = length(ids) nid = length(ids)
nobs = length(vobs) nobs = length(vobs)
cov = zeros(Float64, nobs,nobs) cov = zeros(Float64, nobs,nobs)
# naive covarince matrix # naive covarince matrix
for j in 1:nid for j in 1:nid
idx = ws.map_ids[ids[j]] idx = ws.map_ids[ids[j]]
nd_eff = div(ws.fluc[idx].nd, ws.fluc[idx].ibn) nd_eff = div(ws.fluc[idx].nd, ws.fluc[idx].ibn)
for n1 in 1:nobs, n2 in n1:nobs for n1 in 1:nobs, n2 in n1:nobs
gamma = calc_gamma(vobs[n1],vobs[n2],ids[j],ws) gamma = calc_gamma(vobs[n1],vobs[n2],ids[j],ws)
cov[n1,n2] +=gamma[1]/nd_eff cov[n1,n2] +=gamma[1]/nd_eff
end end
end end
for n1 in 1:nobs-1, n2 in n1+1:nobs ## symmetrizing for n1 in 1:nobs-1, n2 in n1+1:nobs ## symmetrizing
cov[n2,n1] = cov[n1,n2] cov[n2,n1] = cov[n1,n2]
end end
corr = [cov[i,j]/sqrt(cov[i,i]*cov[j,j]) for i in 1:nobs, j in 1:nobs] corr = [cov[i,j]/sqrt(cov[i,i]*cov[j,j]) for i in 1:nobs, j in 1:nobs]
cov = [corr[i,j]*vobs[i].err*vobs[j].err for i in 1:nobs, j in 1:nobs] cov = [corr[i,j]*vobs[i].err*vobs[j].err for i in 1:nobs, j in 1:nobs]
return cov return cov
end end
cov_pe(vobs::AbstractVector{ADerrors.uwreal}) = cov_pe(vobs,ADerrors.wsg) cov_pe(vobs::Vector{ADerrors.uwreal}) = cov_pe(vobs,ADerrors.wsg)
@doc raw""" @doc raw"""
cov_min(vobs::Vector{ADerrors.uwreal} [ws::ADerrors.wspace]) cov_min(vobs::Vector{ADerrors.uwreal} [ws::ADerrors.wspace])
It computes the unbiased covariance matrix of `vobs` using a mixed method. It computes the unbiased covariance matrix of `vobs` using a mixed method.
...@@ -237,55 +237,55 @@ function calc_gamma(a1::ADerrors.uwreal,a2::ADerrors.uwreal,id::Int64,ws::ADerro ...@@ -237,55 +237,55 @@ function calc_gamma(a1::ADerrors.uwreal,a2::ADerrors.uwreal,id::Int64,ws::ADerro
matrix "à la pyerrors, that is, it multipy the covarince matrix with the errors of `vobs` matrix "à la pyerrors, that is, it multipy the covarince matrix with the errors of `vobs`
It assumes that `ADerrors.uwerr` has been run on `vobs` It assumes that `ADerrors.uwerr` has been run on `vobs`
This method is not stable, in the sense that the covarince between two `ADerrors.uwreal` This method is not stable, in the sense that the covarince between two `ADerrors.uwreal`
depend also on the other `ADerrors.uwreal` included in `vobs` depend also on the other `ADerrors.uwreal` included in `vobs`
See also [`cov_pe`](@ref) [`cov_ad`](@ref) See also [`cov_pe`](@ref) [`cov_ad`](@ref)
""" """
function cov_min(vobs::AbstractVector{ADerrors.uwreal},ws::ADerrors.wspace) function cov_min(vobs::Vector{ADerrors.uwreal},ws::ADerrors.wspace)
ids = ADerrors.unique_ids_multi(vobs, ws) ids = ADerrors.unique_ids_multi(vobs, ws)
nid = length(ids) nid = length(ids)
iw = fill(typemax(Int64),nid) iw = fill(typemax(Int64),nid)
for obs in vobs, j in eachindex(obs.ids), i in eachindex(ids) for obs in vobs, j in eachindex(obs.ids), i in eachindex(ids)
if (obs.ids[j] == ids[i]) if (obs.ids[j] == ids[i])
iw[i] = min(iw[i], obs.cfd[j].iw) iw[i] = min(iw[i], obs.cfd[j].iw)
end end
end end
nobs = length(vobs) nobs = length(vobs)
cov = zeros(Float64, nobs,nobs) cov = zeros(Float64, nobs,nobs)
for j in 1:nid for j in 1:nid
idx = ws.map_ids[ids[j]] idx = ws.map_ids[ids[j]]
nd_eff = div(ws.fluc[idx].nd, ws.fluc[idx].ibn) nd_eff = div(ws.fluc[idx].nd, ws.fluc[idx].ibn)
for n in eachindex(vobs) for n in eachindex(vobs)
gamma = calc_gamma(vobs[n],ids[j],ws) gamma = calc_gamma(vobs[n],ids[j],ws)
cov[n,n] += length(gamma)==1 ? gamma[1]/nd_eff : (gamma[1] + 2.0*sum(gamma[2:iw[j]]))/nd_eff cov[n,n] += length(gamma)==1 ? gamma[1]/nd_eff : (gamma[1] + 2.0*sum(gamma[2:iw[j]]))/nd_eff
end end
for n1 in 1:nobs-1, n2 in n1+1:nobs for n1 in 1:nobs-1, n2 in n1+1:nobs
gamma12 = calc_gamma(vobs[n1],vobs[n2],ids[j],ws) gamma12 = calc_gamma(vobs[n1],vobs[n2],ids[j],ws)
if length(gamma12) == 1 if length(gamma12) == 1
cov[n1,n2] +=gamma12[1]/nd_eff cov[n1,n2] +=gamma12[1]/nd_eff
continue; continue;
end
gamma21 = calc_gamma(vobs[n2],vobs[n1],ids[j],ws)
cov[n1,n2] += (gamma12[1] + sum(gamma12[2:iw[j]]) + sum(gamma21[2:iw[j]]))/nd_eff
end end
gamma21 = calc_gamma(vobs[n2],vobs[n1],ids[j],ws)
cov[n1,n2] += (gamma12[1] + sum(gamma12[2:iw[j]]) + sum(gamma21[2:iw[j]]))/nd_eff
end
end end
for n1 in 1:nobs-1, n2 in n1+1:nobs for n1 in 1:nobs-1, n2 in n1+1:nobs
cov[n2,n1] = cov[n1,n2] cov[n2,n1] = cov[n1,n2]
end end
corr = [cov[i,j]/sqrt(cov[i,i]*cov[j,j]) for i in 1:nobs, j in 1:nobs] corr = [cov[i,j]/sqrt(cov[i,i]*cov[j,j]) for i in 1:nobs, j in 1:nobs]
cov = [corr[i,j]*vobs[i].err*vobs[j].err for i in 1:nobs, j in 1:nobs] cov = [corr[i,j]*vobs[i].err*vobs[j].err for i in 1:nobs, j in 1:nobs]
return cov return cov
end end
cov_min(vobs::AbstractVector{ADerrors.uwreal}) = cov_min(vobs,ADerrors.wsg) cov_min(vobs::Vector{ADerrors.uwreal}) = cov_min(vobs,ADerrors.wsg)
@doc raw""" @doc raw"""
cov_AD(vobs::Vector{ADerrors.uwrela} [ws::ADerrors.wspace]; biased::Bool=true, info::Bool=false) cov_AD(vobs::Vector{ADerrors.uwrela} [ws::ADerrors.wspace]; biased::Bool=true, info::Bool=false)
It computes the unbiased covariance matrix of `vobs` "à la ADerrors". It computes the unbiased covariance matrix of `vobs` "à la ADerrors".
...@@ -294,116 +294,116 @@ function calc_gamma(a1::ADerrors.uwreal,a2::ADerrors.uwreal,id::Int64,ws::ADerro ...@@ -294,116 +294,116 @@ function calc_gamma(a1::ADerrors.uwreal,a2::ADerrors.uwreal,id::Int64,ws::ADerro
and computes the covarince matrix integrating the autocorrelation function up to `IW` and computes the covarince matrix integrating the autocorrelation function up to `IW`
It assumes that `ADerrors.uwerr` has been run on `vobs` It assumes that `ADerrors.uwerr` has been run on `vobs`
This method is not stable, in the sense that the covarince between two `ADerrors.uwreal` This method is not stable, in the sense that the covarince between two `ADerrors.uwreal`
depend also on the other `ADerrors.uwreal` included in `vobs` depend also on the other `ADerrors.uwreal` included in `vobs`
# KEYWORD ARGUMENTS # KEYWORD ARGUMENTS
- `bias::Bool`: if `true` (default), it computes the covariance matrix including the bias as `ADerrors` - `bias::Bool`: if `true` (default), it computes the covariance matrix including the bias as `ADerrors`
- `info::Bool`: if `true` return the integration window used to compute the covariance matrix as a Dict{Int64,Int64}(id=> iw) - `info::Bool`: if `true` return the integration window used to compute the covariance matrix as a Dict{Int64,Int64}(id=> iw)
See also [`cov_min`](@ref) [`cov_pe`](@ref) See also [`cov_min`](@ref) [`cov_pe`](@ref)
""" """
function cov_AD(vobs::AbstractVector{ADerrors.uwreal},ws::ADerrors.wspace; biased::Bool=true, info::Bool=false) function cov_AD(vobs::Vector{ADerrors.uwreal},ws::ADerrors.wspace; biased::Bool=true, info::Bool=false)
ids = ADerrors.unique_ids_multi(vobs, ws) ids = ADerrors.unique_ids_multi(vobs, ws)
nid = length(ids) nid = length(ids)
iw = zeros(Int64,nid) iw = zeros(Int64,nid)
for obs in vobs, j in eachindex(obs.ids), i in eachindex(ids) for obs in vobs, j in eachindex(obs.ids), i in eachindex(ids)
if (obs.ids[j] == ids[i]) if (obs.ids[j] == ids[i])
iw[i] = max(iw[i], obs.cfd[j].iw) iw[i] = max(iw[i], obs.cfd[j].iw)
end end
end end
nobs = length(vobs) nobs = length(vobs)
cov = zeros(Float64, nobs,nobs) cov = zeros(Float64, nobs,nobs)
for j in 1:nid for j in 1:nid
idx = ws.map_ids[ids[j]] idx = ws.map_ids[ids[j]]
nd_eff = div(ws.fluc[idx].nd, ws.fluc[idx].ibn) nd_eff = div(ws.fluc[idx].nd, ws.fluc[idx].ibn)
for n in eachindex(vobs) for n in eachindex(vobs)
gamma = calc_gamma(vobs[n],ids[j],ws) gamma = calc_gamma(vobs[n],ids[j],ws)
if biased if biased
gamma .+= bias(vobs[n],ids[j],ws)/nd_eff gamma .+= bias(vobs[n],ids[j],ws)/nd_eff
end end
cov[n,n] += length(gamma)==1 ? gamma[1]/nd_eff : (gamma[1] + 2*sum(gamma[2:iw[j]]))/nd_eff cov[n,n] += length(gamma)==1 ? gamma[1]/nd_eff : (gamma[1] + 2*sum(gamma[2:iw[j]]))/nd_eff
end
for n1 in 1:nobs-1, n2 in n1+1:nobs
gamma12 = calc_gamma(vobs[n1],vobs[n2],ids[j],ws)
if length(gamma12) == 1
cov[n1,n2] += gamma12[1]/nd_eff
continue;
end end
gamma21 = calc_gamma(vobs[n2],vobs[n1],ids[j],ws)
if biased for n1 in 1:nobs-1, n2 in n1+1:nobs
cov[n1,n2] += (gamma12[1] + sum(gamma12[2:iw[j]]) + sum(gamma21[2:iw[j]]))/nd_eff*(1+(2*iw[j]-1)/nd_eff) gamma12 = calc_gamma(vobs[n1],vobs[n2],ids[j],ws)
else if length(gamma12) == 1
cov[n1,n2] += (gamma12[1] + sum(gamma12[2:iw[j]]) + sum(gamma21[2:iw[j]]))/nd_eff cov[n1,n2] += gamma12[1]/nd_eff
continue;
end
gamma21 = calc_gamma(vobs[n2],vobs[n1],ids[j],ws)
if biased
cov[n1,n2] += (gamma12[1] + sum(gamma12[2:iw[j]]) + sum(gamma21[2:iw[j]]))/nd_eff*(1+(2*iw[j]-1)/nd_eff)
else
cov[n1,n2] += (gamma12[1] + sum(gamma12[2:iw[j]]) + sum(gamma21[2:iw[j]]))/nd_eff
end
end end
end
end end
for n1 in 1:nobs-1, n2 in n1+1:nobs for n1 in 1:nobs-1, n2 in n1+1:nobs
cov[n2,n1] = cov[n1,n2] cov[n2,n1] = cov[n1,n2]
end end
return info ? (cov, Dict(ids.=>iw)) : cov return info ? (cov, Dict(ids.=>iw)) : cov
end end
cov_AD(vobs::AbstractVector{ADerrors.uwreal};biased::Bool=false) = cov_AD(vobs,ADerrors.wsg,biased=biased) cov_AD(vobs::Vector{ADerrors.uwreal};biased::Bool=false) = cov_AD(vobs,ADerrors.wsg,biased=biased)
""" """
chiexp(hess, C, W) chiexp(hess, C, W)
It computes the expected chisquare given the hessian of the chisquare function computed at its minimum, It computes the expected chisquare given the hessian of the chisquare function computed at its minimum,
the covariance matrix of data and the weigth function. the covariance matrix of data and the weigth function.
""" """
function chiexp(hess,C,W) function chiexp(hess,C,W)
N, = size(hess) N, = size(hess)
ndata, = size(C) ndata, = size(C)
npar = N-ndata; npar = N-ndata;
L = LinearAlgebra.cholesky(W).L L = LinearAlgebra.cholesky(W).L
Linv = LinearAlgebra.pinv(L) Linv = LinearAlgebra.pinv(L)
_hess = view(hess, 1:npar,npar+1:npar+ndata) _hess = view(hess, 1:npar,npar+1:npar+ndata)
S = [sum(Linv[alpha,gamma]*_hess[i,gamma] for gamma in 1:ndata) for i in 1:npar, alpha in 1:ndata] S = [sum(Linv[alpha,gamma]*_hess[i,gamma] for gamma in 1:ndata) for i in 1:npar, alpha in 1:ndata]
H = [sum(S[n,alpha]*S[m,alpha] for alpha in 1:ndata) for n in 1:npar, m in 1:npar] H = [sum(S[n,alpha]*S[m,alpha] for alpha in 1:ndata) for n in 1:npar, m in 1:npar]
Hinv = LinearAlgebra.pinv(H) Hinv = LinearAlgebra.pinv(H)
P = [ sum(_hess[i,alpha]*Hinv[i,j]*_hess[j,beta] for i in 1:npar, j in 1:npar) for alpha in 1:ndata, beta in 1:ndata] P = [ sum(_hess[i,alpha]*Hinv[i,j]*_hess[j,beta] for i in 1:npar, j in 1:npar) for alpha in 1:ndata, beta in 1:ndata]
chiexp = let aux = C*(W-P) chiexp = let aux = C*(W-P)
sum(aux[alpha,alpha] for alpha in 1:ndata ) sum(aux[alpha,alpha] for alpha in 1:ndata )
end end
return chiexp return chiexp
end end
""" """
chiexp(chisq::Function,par,d,C,W) chiexp(chisq::Function,par,d,C,W)
It computes the expected chisquare given the chisquare function, the fit parameters and the data. It computes the expected chisquare given the chisquare function, the fit parameters and the data.
This is preferred to ADerrors.chiexp for correlated fits since it accepts the covariance matrix as an input, This is preferred to ADerrors.chiexp for correlated fits since it accepts the covariance matrix as an input,
that usually has been already computed before hand. that usually has been already computed before hand.
""" """
function chiexp(chisq::Function,par::AbstractVector{Float64},d::AbstractVector{Float64},C::AbstractMatrix{Float64},W::AbstractMatrix{Float64}) function chiexp(chisq::Function,par::Vector{Float64},d::Vector{Float64},C::AbstractMatrix{Float64},W::AbstractMatrix{Float64})
ndata = length(d); ndata = length(d);
if size(W) != (ndata,ndata) if size(W) != (ndata,ndata)
throw(DimensionMismatch("[chiexp] d and W must have same dimension")) throw(DimensionMismatch("[chiexp] d and W must have same dimension"))
end end
npar = length(par); npar = length(par);
hess = zeros(npar+ndata,npar+ndata); hess = zeros(npar+ndata,npar+ndata);
ccsq(x) = chisq(view(x,1:npar),view(x,npar+1:npar+ndata)) ccsq(x) = chisq(view(x,1:npar),view(x,npar+1:npar+ndata))
ForwardDiff.hessian!(hess,ccsq,[par; d]) ForwardDiff.hessian!(hess,ccsq,[par; d])
return chiexp(hess,C,W) return chiexp(hess,C,W)
end end
function chiexp(chisq::Function,par::AbstractVector,d::AbstractVector{Float64},C::AbstractMatrix{Float64},W::AbstractVector{Float64}) function chiexp(chisq::Function,par::Vector,d::Vector{Float64},C::AbstractMatrix{Float64},W::Vector{Float64})
ndata = length(d); ndata = length(d);
if length(W) != ndata if length(W) != ndata
throw(DimensionMismatch("[chiexp] d and W must have same dimension")) throw(DimensionMismatch("[chiexp] d and W must have same dimension"))
end end
npar = length(par); npar = length(par);
hess = zeros(npar+ndata,npar+ndata); hess = zeros(npar+ndata,npar+ndata);
ccsq(x) = chisq(view(x,1:npar),view(x,npar+1:npar+ndata)) ccsq(x) = chisq(view(x,1:npar),view(x,npar+1:npar+ndata))
ForwardDiff.hessian!(hess,ccsq,[par; d]) ForwardDiff.hessian!(hess,ccsq,[par; d])
return chiexp(hess,C,LinearAlgebra.Diagonal(W)) return chiexp(hess,C,LinearAlgebra.Diagonal(W))
end end
chiexp(chisq::Function,par::AbstractVector{ADerrors.uwreal},d::AbstractVector{ADerrors.uwreal},C,W) = chiexp(chisq,ADerrors.value.(par),ADerrors.value.(d),C,W) chiexp(chisq::Function,par::Vector{ADerrors.uwreal},d::Vector{ADerrors.uwreal},C,W) = chiexp(chisq,ADerrors.value.(par),ADerrors.value.(d),C,W)
end 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