amr <- function(x, ...) UseMethod("amr", x)
is.amr <- function(x) inherits(x, "amr")
#temp
amr_vals <- function(node) if(length(node[["refinement"]])>0) {
# browser()
unlist(lapply(node[["refinement"]], amr_vals))
} else node[["value"]]
# x must be a matrix with two columns
amr.matrix <- function(x, weights=NULL, xlim=NULL, ylim=NULL, ...) {
if(is.null(xlim)) xlim <- c(min(x[,1]), max(x[,1]))
if(is.null(ylim)) ylim <- c(min(x[,2]), max(x[,2]))
idx <- which(!is.na(x[,1]) & !is.na(x[,2]))
amr.default(x[idx,], weights=weights, type="data", xlim=xlim, ylim=ylim, ...)
}
# x must be a function that supports vector arguments
amr.function <- function(x, ...) amr.default(x, type="function", ...)
# the workhorse, since the difference between function and dataset is small
amr.default <- function(x, xlim, ylim, weights=NULL, minlevel=4, maxlevel=8, reltol=0.05, log="", type, ...) {
pts <- matrix(c(c(xlim,rev(xlim)), rep(ylim, each=2), rep(NA, 4)), byrow=FALSE, ncol=3)
if(type=="function") pts[1:4, 3] <- x(pts[1:4,1], pts[1:4, 2])
loglist <- strsplit(log,"")[[1]]
logx <- "x" %in% loglist
logy <- "y" %in% loglist
if(type=="data") zlim <- c(0,1)
pgrad.function <- function(node) {
vals <- pts[node[["pts_idx"]],3]
vals <- vals[is.finite(vals)]
ret <- sd(vals)/(mean(vals)+1)
# browser()
return(ret)
}
pgrad.data <- function(node) {
# prob. mass of this rectangle
ll <- pts[node[["pts_idx"]][1],1:2]
ur <- pts[node[["pts_idx"]][3],1:2]
ret <- node[["value"]] * (ur[[1]]-ll[[1]]) * (ur[[2]]-ll[[2]])
return(ret)
}
pgrad <- switch(type, "function"=pgrad.function, "data"=pgrad.data)
rectval.function <- function(node) {
# mean of the function value at the corners
vals <- pts[node[["pts_idx"]],3]
return(mean(vals[is.finite(vals)]))
}
rectval.data <- function(node) {
# probability mass per area unit. should integrate to 1.
ll <- pts[node[["pts_idx"]][1],1:2]
ur <- pts[node[["pts_idx"]][3],1:2]
idx <- (x[,1]>=ll[[1]]) & (x[,1]=ll[[2]]) & (x[,2]10000) browser()
# ret <- (sum(idx)*total_area) / (nrow(x) * (ur[[1]]-ll[[1]]) * (ur[[2]]-ll[[2]]))
zlim[[2]] <<- max(c(zlim[[2]], ret))
return(ret)
}
rectval <- switch(type, "function"=rectval.function, "data"=rectval.data)
refinement <- function(node) {
ll <- pts[node[["pts_idx"]][1],1:2]
ur <- pts[node[["pts_idx"]][3],1:2]
lvl <- node[["level"]]
midx <- if(logx) sqrt(ll[1]*ur[1]) else (ll[1]+ur[1])/2
midy <- if(logy) sqrt(ll[2]*ur[2]) else (ll[2]+ur[2])/2
add_pts <- matrix(c(
midx, ll[2], NA, # lower middle
ll[1], midy, NA, # left middle
midx, midy, NA, # middle
ur[1], midy, NA, # right middle
midx, ur[2], NA), # upper middle
byrow=TRUE, ncol=3
)
if(type=="function") add_pts[,3] <- x(add_pts[,1], add_pts[,2])
old_nrow <- nrow(pts)
pts <<- rbind(pts, add_pts)
node1 <- list(pts_idx=c(node[["pts_idx"]][1], old_nrow+c(1,3,2)), refinement=list(), level=lvl+1)
node1[["value"]] <- rectval(node1)
node1[["pgrad"]] <- pgrad(node1)
node2 <- list(pts_idx=c(old_nrow+1, node[["pts_idx"]][2], old_nrow+c(4,3)), refinement=list(), level=lvl+1)
node2[["value"]] <- rectval(node2)
node2[["pgrad"]] <- pgrad(node2)
node3 <- list(pts_idx=c(old_nrow+c(3,4), node[["pts_idx"]][3], old_nrow+5), refinement=list(), level=lvl+1)
node3[["value"]] <- rectval(node3)
node3[["pgrad"]] <- pgrad(node3)
node4 <- list(pts_idx=c(old_nrow+c(2,3,5), node[["pts_idx"]][4]), refinement=list(), level=lvl+1)
node4[["value"]] <- rectval(node4)
node4[["pgrad"]] <- pgrad(node4)
return(list(node1, node2, node3, node4))
}
needs_refinement <- function(node) {
if(node[["level"]]=maxlevel) return(FALSE)
if(!is.numeric(node[["pgrad"]]) | is.nan(node[["pgrad"]])) return(TRUE)
if(abs(node[["pgrad"]]) > reltol) return(TRUE)
# if(is.numeric(node[["pgrad"]])) browser()
# ans <- try(if(node[["pgrad"]] > reltol) return(TRUE))
# if (inherits(ans, "try-error")) browser()
return(FALSE)
}
refine_recursively <- function(node) {
if(needs_refinement(node)) {
node[["refinement"]] <- refinement(node)
# browser()
for (i in seq_len(length(node[["refinement"]])))
node[["refinement"]][[i]] <- refine_recursively(node[["refinement"]][[i]])
}
return(node)
}
root <- list(pts_idx=seq(1,4), refinement=list(), level=0)
root[["value"]] <- rectval(root)
root[["pgrad"]] <- pgrad(root)
root <- refine_recursively(root)
if(type=="function") {
zlim <- c(min(pts[,3]), max(pts[,3]))
# browser()
} else if(type=="data") {
# browser()
vals <- amr_vals(root)
zlim <- c(min(vals), max(vals))
}
res <- list(pts=pts, node=root, zlim=zlim)
class(res) <- "amr"
return(res)
}
# use classInt? quantile method not helpful due to irregular sampling
# image has a breaks argument that looks cool
plot.amr <- function(x, col=heat.colors(50), border=NA, xlab="x", ylab="y", zmag=1, ...) {
zmin <- if(is.finite(x[["zlim"]][[1]])) x[["zlim"]][[1]] else -zmag
zmax <- if(is.finite(x[["zlim"]][[2]])) x[["zlim"]][[2]] else zmag
colidx <- seq(zmin, zmax, length.out=length(col))
plot_node <- function(node) {
ll <- x[["pts"]][node[["pts_idx"]][1],1:2]
ur <- x[["pts"]][node[["pts_idx"]][3],1:2]
rect(ll[1], ll[2], ur[1], ur[2], border=border, col=col[findInterval(node[["value"]], colidx)])
if(length(node[["refinement"]])>0) lapply(node[["refinement"]], plot_node)
}
root <- x[["node"]]
ll <- x[["pts"]][root[["pts_idx"]][1], 1:2]
ur <- x[["pts"]][root[["pts_idx"]][3], 1:2]
plot_arg <- list(...)
plot_arg[["x"]] <- 1; plot_arg[["col"]] <- "white"; plot_arg[["type"]] <- "p"; plot_arg[["xlim"]] <- c(ll[1], ur[1])
plot_arg[["ylim"]] <- c(ll[2], ur[2]); plot_arg[["xlab"]] <- xlab; plot_arg[["ylab"]] <- ylab
do.call(plot, plot_arg)
plot_node(root)
}
# may need a different method (weighted mean instead of sum) for function
integrate_amr <- function(x, xlim, ylim) {
eval_rect <- function(node) {
ll <- x[["pts"]][node[["pts_idx"]][1],1:2]
ur <- x[["pts"]][node[["pts_idx"]][3],1:2]
if(xlim[1]>ur[1] || xlim[2]ur[2] || ylim[2]0) return(unlist(lapply(node[["refinement"]], eval_rect)))
area <- (min(c(ur[1], xlim[2])) - max(c(ll[1], xlim[1]))) * (min(c(ur[2], ylim[2]))-max(c(ll[2], ylim[1])))
tot_area <- (ur[1]-ll[1]) * (ur[2]-ll[2])
return(node[["value"]] * area / tot_area) # this is integreation
}
sum(eval_rect(x[["node"]])) # this is integration
}
# guess xlab and ylab
# add breaks argument
image.amr <- function(x, col=rev(gray(0:12/12)), border=NA, xlim=NULL, ylim=NULL, log="", xlab="x", ylab="y", zmag=1, length.out=100, breaks=NULL, ...) {
if(is.null(xlim)) xlim <- c(min(x[["pts"]][,1]), max(x[["pts"]][,1]))
if(is.null(ylim)) ylim <- c(min(x[["pts"]][,2]), max(x[["pts"]][,2]))
zmin <- if(is.finite(x[["zlim"]][[1]])) x[["zlim"]][[1]] else -zmag
zmax <- if(is.finite(x[["zlim"]][[2]])) x[["zlim"]][[2]] else zmag
if(length(length.out)==1) length.out <- rep(length.out,2)
loglist <- strsplit(log,"")[[1]]
logx <- "x" %in% loglist
logy <- "y" %in% loglist
xgrid <- if(logx) exp(seq(log(xlim[1]), log(xlim[2]), length.out=length.out[1])) else seq(xlim[1], xlim[2], length.out=length.out[1])
ygrid <- if(logy) exp(seq(log(ylim[1]), log(ylim[2]), length.out=length.out[2])) else seq(ylim[1], ylim[2], length.out=length.out[2])
z <- matrix(0, nrow=length.out[1], ncol=length.out[2])
for (i in seq.int(2,length.out[1]))
for (j in seq.int(2,length.out[2]))
z[i,j] <- integrate_amr(x, xlim=xgrid[seq.int(i-1,i)], ylim=ygrid[seq.int(j-1,j)])
if(!is.null(breaks) && length(breaks)==1) {
breaks <- classIntervals(as.vector(z), n=breaks, style="fisher")$brks
# browser()
# breaks <- quantile(as.vector(z), seq(0,1, length.out=(breaks+1)))
}
# browser()
image(x=xgrid, y=ygrid, z=z, zlim=c(zmin, zmax), xlim=xlim, ylim=ylim, col=col, xlab=xlab, ylab=ylab, log=log, breaks=breaks, ...)
}