R/utility.R

Defines functions bridcrit opencrit bridcrit.logged bridcrit.normal opencrit.logged opencrit.normal exparg.brid exparg.open euratio.normal euratio.logged euratio bridjump openjump Eubrid Euopen u squash ct.Mpadj.brid ct.Madj.brid ct.Mpadj.open ct.Madj.open dct.logged dct ct

Documented in bridcrit bridcrit.logged bridcrit.normal bridjump ct dct dct.logged Eubrid Euopen euratio euratio.logged euratio.normal exparg.brid exparg.open opencrit opencrit.logged opencrit.normal openjump squash u

############################################################
# COMPETITION 

#' Competition function
#'
#' Competition function
#' @param delta distance from competitor
ct <- function(delta, ...) -1 / delta

#' Competition function (d/ddelta)
#'
#' Competition function (d/ddelta)
#' @param delta distance from competitor
dct <- function(delta, ...) 1 / (delta^2)

#' Log competition function (d/ddelta)
#'
#' Log competition function (d/ddelta)
#' @param delta distance from competitor
dct.logged <- function(delta, ...) -2*log(delta)

ct.Madj.open <- function(delta, ...) ct(delta, ...)
ct.Mpadj.open <- function(delta, ...) dct(delta, ...)
ct.Madj.brid <- function(delta, dbar, ...) ct(delta, ...) + ct(dbar, ...)
ct.Mpadj.brid <- function(delta, dbar, ...) dct(delta, ...) - dct(dbar, ...)

############################################################
# Helpers

#' Squash all arguments to 0
#'
squash <- function(...) 0

############################################################
# UTILITY

#' Utility function
#'
#' risk aversion = b * (1 / (1 + a/b exp(bm)))
#' a controls straightness, b controls bendiness
#' RA increasing in b, decreasing in a
#' @param m wealth
#' @param a a parameter
#' @param b b parameter
u <- function(m, a=1, b=1) a * m - exp(-b * m)

# #' Expected first derivative of utility function
# #'
# #' risk aversion = b * (1 / (1 + a/b exp(bm)))
# #' a controls straightness, b controls bendiness
# #' RA increasing in b, decreasing in a
# #' @param m wealth
# #' @param a a parameter
# #' @param b b parameter
# #' @param sigma random walk sigma parameter
# Edu <- function(delta, W0, a=1, b=1, sigma=1, ...) {
#     a + b * exp(-b * (W0 + ct(delta)) + 0.5 * b^2 * sigma^2 * delta)
# }

# #' Expected second derivative of utility function
# #'
# #' risk aversion = b * (1 / (1 + a/b exp(bm)))
# #' a controls straightness, b controls bendiness
# #' RA increasing in b, decreasing in a
# #' @param m wealth
# #' @param a a parameter
# #' @param b b parameter
# #' @param sigma random walk sigma parameter
# Ed2u <- function(delta, W0, a=1, b=1, ...) -b^2 * exp(-b * (W0 + ct(delta)) + 0.5 * b^2 * sigma^2 * delta)

#' Expected utility on open interval
#'
#' @param delta distance from known point
#' @param W0 value at known point
#' @param sigma random walk sigma parameter
#' @param a utility function *a* parameter
#' @param b utility function *b* parameter
#' @param ... capture additional arguments
Euopen <- function(delta, W0, sigma=1, a=1, b=1, Madj=squash, ...) {
    #exparg <- exparg.open(delta, W0=W0, sigma=sigma, b=b)
    exparg <- exparg.open(delta, W0=W0, sigma=sigma, b=b, Madj=Madj, ...)
    #a * (W0 + ct(delta)) - exp(-b * (W0 + c(delta)) + 0.5 * b^2 * sigma^2 * delta)
    #a * (W0 + ct(delta)) - exp(exparg)
    a * (W0 + Madj(delta, W = W0, ...)) - exp(exparg)
}

#' Expected utility on bridge interval
#'
#' @param delta distance from left point
#' @param xl location of left point
#' @param xr location of right point
#' @param Wl value of left point
#' @param Wr value of right point
#' @param sigma brownian walk *sigma* parameter
#' @param a utility function *a* parameter
#' @param b utility function *b* parameter
#' @param ... capture additional arguments
Eubrid <- function(delta, xl, xr, Wl, Wr, sigma=1, a=1, b=1, Madj=squash, ...) {
    #exparg <- exparg.brid(delta, xl=xl, xr=xr, Wl=Wl, Wr=Wr, sigma=sigma, b=b)
    exparg <- exparg.brid(delta, xl=xl, xr=xr, Wl=Wl, Wr=Wr, sigma=sigma, b=b, Madj=Madj, ...)
    dbar <- xr - xl - delta
    #arg <- delta * (Wr - Wl) / (xr - xl) + Wl + ct(delta) + ct(dbar)
    arg <- delta * (Wr - Wl) / (xr - xl) + Wl + Madj(delta, dbar, Wl = Wl, Wr = Wr, ...)
    a * arg - exp(exparg)
}

#' New value at open jump
#'
#' @param delta jump distance
#' @param sigma brownian standard deviation
#' @export
#' @importFrom stats rnorm
openjump <- function(delta, sigma=1, ...) sigma * sqrt(delta) * rnorm(1)

#' New value at bridge jump
#'
#' @param delta jump distance from left endpoint
#' @param xl left endpoint
#' @param xr right endpoint
#' @param Wl value of left point
#' @param Wr value of right point
#' @param sigma brownian standard deviation
#' @export
#' @importFrom stats rnorm
bridjump <- function(delta, xl, xr, Wl, Wr, sigma=1, ...) Wl + delta * (Wr - Wl) / (xr - xl) + sigma * sqrt((delta * (xr - xl - delta)) / (xr - xl)) * rnorm(1)



#' Ratio of -Ed2u / Edu
#' 
#' Multiplier on variance term, used in criteria calculations.
#' Logarithmic version relies on log(1 + exp(x)) for positive x.
#' For large x, this ~= x + exp(-x)
#' @param exparg argument inside exponential term
#' @param a utility function *a* parameter
#' @param b utility function *b* parameter
#' @param log use logarithmic version?
#' @param ... additional arguments to subfunctions
#' @export
euratio <- function(exparg, a=1, b=1, log=TRUE, ...) {
    if(log) {
        euratio.logged(exparg, a=a, b=b, ...)
    } else {
        euratio.normal(exparg, a=a, b=b, ...)
    }
}

#' Logarithm of -Ed2u / Edu
#' 
#' Relies on log(1 + exp(x)) for positive x. For large x, this ~= x + exp(-x)
#' @param exparg argument inside exponential term
#' @param a utility function *a* parameter
#' @param b utility function *b* parameter
#' @param ... capture additional arguments
euratio.logged <- function(exparg, a=1, b=1, ...) {
    exparg2 <- exparg + log(b/a)
    #log1pexp <- if(exparg2 <= 18) { log1p(exp(exparg2)) } else { exparg2 + exp(-exparg2) }
    #log1pexp <- log1p(exp(exparg2))*(exparg <= 18) + (exparg2+exp(-exparg2))*(exparg>18)
    log1pexp <- ifelse(exparg2 <= 18, log1p(exp(exparg2)), exparg2 + exp(-exparg2))

    2*log(b) - log(a) + exparg - log1pexp
}

#' -Ed2u / Edu
#' 
#' @param exparg argument inside exponential term
#' @param a utility function *a* parameter
#' @param b utility function *b* parameter
#' @param ... capture additional arguments
euratio.normal <- function(exparg, a=1, b=1, ...) {
    b^2 / a * exp(exparg) / (1 + (b/a) * exp(exparg))
}

# in general, for mean M and variance V,
# exparg = -b * M + (1/2) * b^2 * V

# in general, criterion is 0 = M' + ( 1/2 * V' * ( -Ed2u/Edu ) )
# logged criterion is 0 = -log M' + log(1/2 V') + log( -Ed2u/Edu )
# we denote these as nlogMp + loghVp + logEurat()

#' Calculate Eu exponential argument on open interval
#'
exparg.open <- function(delta, W0, sigma=1, b=1, Madj=squash, ...) {
    #exparg <- -b * (W0 + ct(delta)) + 0.5 * b^2 * sigma^2 * delta
    exparg <- -b * (W0 + Madj(delta, W = W0, ...)) + 0.5 * b^2 * sigma^2 * delta
    exparg
}

#' Calculate Eu exponential argument on bridge interval
#'
exparg.brid <- function(delta, xl, xr, Wl, Wr, sigma=1, b=1, Madj=squash, ...) {
    dbar <- xr - xl - delta
    #exparg <- -b * (Wl + ct(delta) + ct(dbar) + delta*((Wr-Wl)/(xr-xl))) + 
    exparg <- -b * (Wl + Madj(delta, dbar, Wl = Wl, Wr = Wr, ...) + delta*((Wr-Wl)/(xr-xl))) + 
        0.5 * b^2 * sigma^2 * ((dbar * delta) / (xr - xl))
    exparg
}

#' Calculate open interval criterion
#'
opencrit.normal <- function(delta, W0, sigma=1, b=1, Mpadj=squash, augment=FALSE, ...) {
    exparg <- exparg.open(delta, W0=W0, sigma=sigma, b=b, ...)
    #Mp <- dct(delta)
    Mp <- Mpadj(delta, W = W0, ...)
    hVp <- 0.5 * sigma^2
    eurat <- euratio.normal(exparg, b=b, ...)
    crit <- Mp - hVp*eurat
    if(augment) {
        attr(crit, 'crit') <- crit
        attr(crit, 'Mp') <- Mp
        attr(crit, 'hVp') <- hVp
        attr(crit, 'eurat') <- eurat
        attr(crit, 'hVpeurat') <- hVp*eurat
    }
    crit
}

#' Calculate open interval criterion (logged)
#'
opencrit.logged <- function(delta, W0, sigma=1, b=1, Mpadj=squash, augment=FALSE, ...) {
    exparg <- exparg.open(delta, W0=W0, sigma=sigma, b=b, ...)
    #logMp <- dct.logged(delta)
    logMp <- suppressWarnings(log(Mpadj(delta, W = W0, ...)))
    loghVp <- 2*log(sigma) - log(2)
    eurat <- euratio.logged(exparg, b=b, ...)
    crit <- logMp - loghVp - eurat
    if(augment) {
        attr(crit, 'crit') <- crit
        attr(crit, 'Mp') <- logMp
        attr(crit, 'hVp') <- loghVp
        attr(crit, 'eurat') <- eurat
        attr(crit, 'hVpeurat') <- loghVp+eurat
    }
    crit
}

#' Calculate bridge interval criterion
#'
bridcrit.normal <- function(delta, xl, xr, Wl, Wr, sigma=1, b=1, Mpadj=squash, augment=FALSE, ...) {
    dbar <- xr - xl - delta
    exparg <- exparg.brid(delta, xl=xl, xr=xr, Wl=Wl, Wr=Wr, sigma=sigma, b=b, ...)
    #Mp <- ((Wr-Wl)/(xr-xl)) + dct(delta) - dct(dbar)
    Mp <- ((Wr-Wl)/(xr-xl)) + Mpadj(delta, dbar, Wl = Wl, Wr = Wr, ...)
    hVp <- 0.5 * sigma^2 * (dbar-delta)/(xr-xl)
    eurat <- euratio.normal(exparg, b=b, ...)
    crit <- Mp - hVp*eurat
    if(augment) {
        attr(crit, 'crit') <- crit
        attr(crit, 'Mp') <- Mp
        attr(crit, 'hVp') <- hVp
        attr(crit, 'eurat') <- eurat
        attr(crit, 'hVpeurat') <- hVp*eurat
    }
    crit
}

#' Calculate bridge interval criterion (logged)
#'
bridcrit.logged <- function(delta, xl, xr, Wl, Wr, sigma=1, b=1, Mpadj=squash, augment=FALSE, ...) {
    dbar <- xr - xl - delta
    # flip signs in back half of search space
    flip <- sign(dbar-delta)
    exparg <- exparg.brid(delta, xl=xl, xr=xr, Wl=Wl, Wr=Wr, sigma=sigma, b=b, ...)
    #Mp <- ((Wr-Wl)/(xr-xl)) + dct(delta) - dct(dbar)
    Mp <- ((Wr-Wl)/(xr-xl)) + Mpadj(delta, dbar, Wl = Wl, Wr = Wr, ...)
    #logMp <- ifelse(flip*Mp>0, log(flip*Mp), -Inf)
    # avoid warning about NaN
    fMp <- flip*Mp
    logMp <- rep(-Inf, length.out=length(Mp))
    logMp[fMp>0] <- log(fMp[fMp>0])
    loghVp <- 2*log(sigma) - log(2) - log(xr-xl) + log(flip*(dbar-delta))
    eurat <- euratio.logged(exparg, b=b, ...)
    logMp <- flip*logMp
    loghVp <- flip*loghVp
    eurat <- flip*eurat
    crit <- logMp - loghVp - eurat
    #crit <- flip*(logMp - loghVp - eurat)
    if(augment) {
        attr(crit, 'crit') <- crit
        attr(crit, 'Mp') <- logMp
        attr(crit, 'hVp') <- loghVp
        attr(crit, 'eurat') <- eurat
        attr(crit, 'hVpeurat') <- loghVp+eurat
    }
    crit
}

#' Open interval criterion function
#'
#' General criterion is 0 = M' + ( 1/2 * V' * ( -Ed2u/Edu ) )
#' Logged criterion is 0 = -log M' + log(1/2 V') + log( -Ed2u/Edu )
#' General criterion: 0 = -log M' + log(1/2 V') + log( -Ed2u/Edu )
#' Open criterion: M' = c'(delta)
#' Open criterion: V' = sigma^2
#' @param delta distance from point
#' @param W0 value at point
#' @param sigma brownian walk *sigma* parameter
#' @param b utility function *b* parameter
#' @param log use logged criterion?
#' @param ... additional arguments to criterion subfunctions
opencrit <- function(delta, W0, sigma=1, b=1, log=TRUE, ...) {
    if(log) {
        opencrit.logged(delta, W0=W0, sigma=sigma, b=b, ...)
    } else {
        opencrit.normal(delta, W0=W0, sigma=sigma, b=b, ...)
    }
}

#' Bridge interval criterion function
#'
#' General criterion is 0 = M' + ( 1/2 * V' * ( -Ed2u/Edu ) )
#' Logged criterion is 0 = -log M' + log(1/2 V') + log( -Ed2u/Edu )
#' Bridge criterion: M' = (Wr-Wl)/(xr-xl) + c'(delta) - c'(dbar)
#' Bridge criterion: V' = (dbar-delta)/(xr-xl) * sigma^2
#' @param delta distance from left point
#' @param xl position of left point
#' @param xr position of right point
#' @param Wl value at left point
#' @param Wr value at right point
#' @param sigma brownian walk *sigma* parameter
#' @param b utility function *b* parameter
#' @param log use logged criterion?
#' @param ... additional arguments to criterion subfunctions
bridcrit <- function(delta, xl, xr, Wl, Wr, sigma=1, b=1, log=TRUE, ...) {
    if(log) {
        bridcrit.logged(delta, xl=xl, xr=xr, Wl=Wl, Wr=Wr, sigma=sigma, b=b, ...)
    } else {
        bridcrit.normal(delta, xl=xl, xr=xr, Wl=Wl, Wr=Wr, sigma=sigma, b=b, ...)
    }
}
balachia/pcPack documentation built on Dec. 19, 2021, 6:40 a.m.