# Load the data
data <- read.table("data/hemlock.txt", header = TRUE)
obs = data[,2]
L = data[,1]
# Likelihood function
h <- function(obs, L, pars) {
a <- pars[1]
s <- pars[2]
sigma <- pars[3]
mu <- a*L/(a/s + L)
sum(log(dnorm(obs, mu, sigma)))
}
# Candidate function
c_x <- function(pars_lo, pars_hi) runif(1, pars_lo, pars_hi)
# Set conditions for the simulated annealing sequence
T_fn <- function(T0, alpha, step) T0*exp(alpha*step)
T0 <- 10
alpha = -0.001
nsteps <- 10000
# Prepare an object to store the result
res <- matrix(nr = nsteps, nc = 5)
# Initiate the algorithm
a0 <- 1
s0 <- 1000
sd0 <- 10
pars0 <- c(1, 100, 10)
pars_lo <- c(0, 1, 1)
pars_hi <- c(1000, 1000, 100)
# Main loop
for(step in 1:nsteps) {
for(j in 1:3) {
# Draw new value for parameter j
pars1 <- pars0
pars1[j] <- c_x(pars_lo[j], pars_hi[j])
# Evaluate the function
h1 <- h(obs, L, pars1)
h0 <- h(obs, L, pars0)
# Compute the difference
diff <- h1 - h0
# Accept if improvement
if(diff > 0) pars0 <- pars1
# Accept wrong candidates
else {
p <- exp(diff/T_fn(T0, alpha, step))
if(runif(1)<p) pars0 <- pars1
}
}
# Record values
res[step,] <- c(step,pars0,h(obs,L,pars0))
}
#Plot the results
plot(c(1:nsteps), res[,5], type = "l", xlab = "Time step", ylab = "h(x)",cex = 2, log = "x")
Rather than using the hemlock data, this example uses 42 random numbers, and tries to identify the known mean of 19.
DEFINE function to optimize h(X)
set.seed(1316)
fake_xs <- rnorm(42, 19, 4)
loglike_numbers <- function(numbers, mu) sum(dnorm(x = numbers, mean = mu, sd = 4, log = TRUE))
loglike_numbers(fake_xs, 7)
[1] -329.7753
DEFINE the sampling function c(X)
DEFINE temperature sequence
REPEAT
DRAW sample X from c(x)
COMPUTE difference diff = h(X) - h(X_0)
IF diff > 0 ACCEPT X
ELSE
COMPUTE acceptance probability p = exp(diff/T)
DRAW value P from random uniform on (0,1)
IF P < p
ACCEPT X
ELSE
REJECT X
UPDATE temperature
UNTIL nsteps is reached
# function to take temperature, diff, and give back TRUE or FALSE (will a negative be kept)
keep_neg_diff <- function(diff, Tmp){
stopifnot(diff<0)
runif(1, min = 0, max = 1) < exp(diff/Tmp)
}
keep_neg_diff(-30, Tmp = 40)
[1] FALSE
keep_neg_diff(10, Tmp = 0)
Error in keep_neg_diff(10, Tmp = 0): diff < 0 is not TRUE
# evaluate for these only
ll_fakenums_f_x <- function(x) loglike_numbers(fake_xs, mu = x)
# make temperatures
runs <- 299
temps <- temp_line(runs, 3, 0.98)
xx <- numeric(runs + 1)
startval <- 10
xx[1] <- startval
for (i in 2:runs){
maybe <- see_of_x(xx[i-1])
xx[i] <- keep_or_reject(x0 = xx[i-1], x1 = maybe, fun = ll_fakenums_f_x, temp = temps[i-1])
}
plot(xx, type = "l")