#' Get the sdot expression from the output of the output of the integration of the approximated geodesic eqn with constant christoffel symbols.
#' this I do because bvptwpC has problems if i add the sdot=sqrt(gmunu zmu znu) term to the equations.
#' It somehow has problems with accuracy even though it's just a value to be evaluated, it doesn't affect the solution of the other terms.
#'
#' The expression for sdot is again just an approximation, that replaces the integral by a discrete sum.
#'
#' @param bestfit bestfit
#'
#' @param out Argument of returned function, the output of the numerical integration of the geodesic
#' @param line Argument of the returned function, the line to be accessed in "out".
#'
#'
#' @export
sdotfun<- function(bestfit) {
myresidual <- resi(bestfit)
myderiv <- data.matrix(attr(myresidual, "deriv")[,-c(1,2)])
mysderiv <- data.matrix(attr(myresidual, "sderiv")[,-c(1,2)])
gmunu <- t(myderiv)%*%myderiv
# covariant derivative of gmunu
gmunu.alpha <- array(t(myderiv)%*%mysderiv, dim=rep(length(bestfit), 3)) #indices: (mu, nu, alpha). this term is t(dr/dmu)%*%(d^2r/dnu dalpha)
gmunu.alpha <- array(gmunu.alpha + aperm(gmunu.alpha, c(2,1,3)), dim=c(length(bestfit)^2, length(bestfit))) #add with swapped mu<->nu # indices: (munu,alpha)
##################################################
# !!!! substract the christoffel symbol part of the covariant derivative###
##################################################
sdot <- function(out, line) {
Theta <- out[line,-c(1)]
Thalpha <- Theta[1:length(bestfit)]
gmunu.alpha <- matrix(gmunu.alpha%*%Thalpha, nrow=length(bestfit))
gmunu <- gmunu+gmunu.alpha
value <- sqrt(Theta[(length(bestfit)+1):(2*length(bestfit))]%*%gmunu%*%Theta[(length(bestfit)+1):(2*length(bestfit))])
names(value) <- "sdot"
return(value)
}
return(sdot)
}
#' Integrate sdot and square the total distance travelled to get an expression for Delta chi^2
#'
#' It is assumed that the sqrt-expression of sdot is constant for each time point in "out",
#' so the integral becomes the sum of the sqrts times the DeltaTaus provided by "out", the solution of the geodesic bvp
#'
#' The function sdot <- sdotfun(bestfit) has to be evaluated in advance
#'
#' Giving the residual explicitly is necessary to avoid conflicting dlls.
#'
#' @param out the output of the numerical integration of the geodesic
#' @param sigma sigma of the data
#' @param bestfit
#'
#' @export
ssquared<-function(out, sigma, residual) {
chi0 <- residual[,7]%*%residual[,7]
Deltatau <- diff(out[,1])
val <- do.call(rbind, lapply(1:length(Deltatau), function(i) {Deltatau[i]*sdot(out,i)}))
val <- diffinv(val)
val <- val[length(val)]
return(val^2/(sigma^2)+as.numeric(chi0))
}
#' Jacobian dp/dTh in approximate metric approach
#'
#' @param Thend
#' @param out
#' @param sigma
#' @param bestfit
#' @param residual
#' @param stepwidth
#'
#' @export
RNCjacssfinite <- function(Thend, out, sigma, bestfit, residual, stepwidth) {
# stepwidth <- 0.001
xguess <- out[,1]
yguess <- yguessout(out)
mybd <- geodesicboundaries(bestfit, Thend)
yini <- mybd[1:length(bestfit),2]
names(yini) <- names(bestfit)
yend <- mybd[1:length(bestfit),3]
names(yend) <- names(bestfit)
x <- xguess
vini <- out[1,-(1:(length(Thend)+1))]
myjac <- do.call(rbind, lapply(1:length(Thend), function(n) {
# Variate the parameters
newyend <- yend
newyend[n] <- newyend[n] + stepwidth
newvini <- bvptwpC(x = x, func = eqns, yini = yini, yend = newyend, parms = pars, nmax=50000, xguess = xguess, yguess = yguess)[1,-(1:(length(Thend)+1))]
return((newvini - vini)/stepwidth)
}) ) # matrix (dp^mu/dTh^alpha)^mu_alpha
return(myjac)
}
#' Compute the gradient of s^2 with finite differences
#'
#' This function computes the gradient of s^2 with finite differences. s^2 is the squared arclength of the geodesic.
#' It takes really long to evaluate but I know of no other expression for the derivative.
#'
#' @param Thend
#' @param out
#' @param sigma
#' @param bestfit
#' @param residual
#' @param stepwidth
#'
#'
#' @export
gradssfinite <- function(Thend, out, sigma = 0.02, bestfit, residual, stepwidth) {
# stepwidth <- 0.001
xguess <- out[,1]
yguess <- yguessout(out)
mybd <- geodesicboundaries(bestfit, Thend)
yini <- mybd[1:length(bestfit),2]
names(yini) <- names(bestfit)
yend <- mybd[1:length(bestfit),3]
names(yend) <- names(bestfit)
if(is.null(out)) {
x <- seq(0,1, by= 0.1)
myssquared <- 0
} else {
x <- xguess
myssquared <- ssquared(out, sigma, residual)[length(xguess)]
}
mygrad <- unlist(lapply(names(Thend), function(n) {
# Variate the parameters
newyend <- yend
newyend[n] <- newyend[n] + stepwidth
newout <- bvptwpC(x = x, func = eqns, yini = yini, yend = newyend, parms = pars, nmax=50000, xguess = xguess, yguess = yguess)
newssquared <- ssquared(newout, sigma, residual)[nrow(newout)]
# Take finite difference
return((newssquared-myssquared)/stepwidth)
}) )
names(mygrad) <- names(Thend)
return(mygrad)
}
#' Hessian of ssquared with finite differences
#'
#' This function computes the hessian of s^2 with finite differences. s^2 is the squared arclength of the geodesic.
#' It takes really long to evaluate but I know of no other expression for the derivative.
#'
#' @param Thend
#' @param out
#' @param sigma
#' @param bestfit
#' @param residual
#' @param stepwidth
#'
#' @export
hessianssfinite <- function(Thend, out, sigma = 0.02, bestfit, residual, stepwidth) {
# stepwidth <- 0.001
xguess <- out[,1]
yguess <- yguessout(out)
mybd <- geodesicboundaries(bestfit, Thend)
yini <- mybd[1:length(bestfit),2]
names(yini) <- names(bestfit)
yend <- mybd[1:length(bestfit),3]
names(yend) <- names(bestfit)
if(is.null(out)) {
x <- seq(0,1, by= 0.1)
myssquared <- 0
} else {
x <- xguess
myssquared <- ssquared(out, sigma, residual)[length(xguess)]
}
#compute hessian
hessianij<-NULL
myhessian <- unlist(lapply(1:length(Thend), function(i) {
lapply(1:i, function(j) {
# Variate the parameters
inewyend <- jnewyend <- ijnewyend <- yend
inewyend[i] <- inewyend[i] + stepwidth
jnewyend[j] <- jnewyend[j] + stepwidth
ijnewyend[i] <- yend[i] + stepwidth
ijnewyend[j] <- ijnewyend[j] + stepwidth
inewout <- bvptwpC(
x = x,
func = eqns,
yini = yini,
yend = inewyend,
parms = pars,
nmax = 50000,
xguess = xguess,
yguess = yguess
)
inewssquared <- ssquared(inewout, sigma, residual)[nrow(inewout)]
ijnewout <- bvptwpC(
x = x,
func = eqns,
yini = yini,
yend = ijnewyend,
parms = pars,
nmax = 50000,
xguess = xguess,
yguess = yguess
)
ijnewssquared <- ssquared(ijnewout, sigma, residual)[nrow(ijnewout)]
if(i!=j) {
jnewout <- bvptwpC(
x = x,
func = eqns,
yini = yini,
yend = jnewyend,
parms = pars,
nmax = 50000,
xguess = xguess,
yguess = yguess
)
jnewssquared <- ssquared(jnewout, sigma, residual)[nrow(newout)]
# Take finite difference
hessianij <- (ijnewssquared-inewssquared-jnewssquared+myssquared)/(stepwidth^2)
names(hessianij) <- paste(as.character(i), as.character(j), sep=".")
} else {
# Take finite difference
hessianij <- (ijnewssquared-2*inewssquared+myssquared)/(stepwidth^2)
names(hessianij) <- paste(as.character(i), as.character(j), sep=".")
}
return(hessianij)
})
}) )
myhs <- diag(nrow = length(bestfit))
myhs[lower.tri(myhs, diag = T)] <- myhessian
myhs <- myhs + t(myhs) - diag(diag(myhs))
dimnames(myhs) <- list(names(bestfit), names(bestfit))
return(myhs)
}
#' Objective function for the bvp-solutions
#'
#' Objective function for the approach with the approximated metric. The value is the integrated arclength computed by ssquared(), gradient and hessian are computed by finite differences.
#' Takes really long. Residual has to be given to the function because else one has two conflicting DLLs.
#'
#'
#' @param Thend
#' @param out
#' @param sigma
#' @param bestfit
#' @param residual
#' @param stepwidth
#'
#'
#' @export
ssquaredobj <- function(Thend, fixed=NULL, sigma=0.02, bestfit, residual) {
out <- geodesicbvp(Thend = Thend, bestfit)
value <- ssquared(out = out, sigma=sigma, residual = residual)[nrow(out)]
gradient <- gradssfinite(Thend = Thend, out = out, sigma = sigma, bestfit = bestfit, residual = residual, stepwidth = 0.001)
hessian <- hessianssfinite(Thend = Thend, out = out, sigma = sigma, bestfit = bestfit, residual = residual, stepwidth = 0.001)
out <- list(value = value, gradient = gradient, hessian = hessian)
attr(out, "class") <- "objlist"
attr(out, "valueData") <- value
attr(out, "valuePrior") <- 0
return(out)
}
#' Get the difference of initial and end velocity to see how much they change.
#' This is to evaluate whether the approximation in RNC works well.
#' Actually this is nonsense, because gmunuvmuvnu=const along the geodesic. Thus RNCssquared is a perfect measure.
#'
#' @param Thend
#' @param bestfit
#'
#'
#'
#' @export
velocitydifference <- function(Thend, bestfit) {
out <- geodesicbvp(Thend = Thend, bestfit = bestfit)
vini <- out[1, -(1:(length(Thend)+1))]
vend <- out[nrow(out), -(1:(length(Thend)+1))]
return(vend-vini)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.