1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
|
#
# fields is a package for analysis of spatial data written for
# the R software environment.
# Copyright (C) 2024 Colorado School of Mines
# 1500 Illinois St., Golden, CO 80401
# Contact: Douglas Nychka, douglasnychka@gmail.com,
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with the R software environment if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# or see http://www.r-project.org/Licenses/GPL-2
##END HEADER
"cover.design" <- function(R, nd, nruns = 1, nn = TRUE,
num.nn = 100, fixed = NULL, scale.type = "unscaled", R.center,
R.scale, P = -20, Q = 20, start = NULL, DIST = NULL, return.grid = TRUE,
return.transform = TRUE, max.loop = 20, verbose = FALSE) {
if (!is.null(start) && is.matrix(start)) {
if (any(duplicated(start)))
stop("Error: start must not have duplicate rows")
test <- duplicated(start, R)
if (sum(test) < nrow(start))
stop("Error: Starting design must be a subset of R")
}
R.orig <- R
R <- as.matrix(R)
# some checks on inputs
if (nd >= nrow(R)) {
stop(" number of design points >= the number of candidates")
}
if (any(duplicated.array(R)))
stop("Error: R must not have duplicate rows")
if (num.nn >= (nrow(R) - nd)) {
nn <- FALSE
warning("Number of nearst neighbors (nn) reduced to the actual number of candidates")
}
if (is.null(DIST))
DIST <- function(x, y) {
rdist(x, y)
}
id <- 1:nrow(R)
if (!is.null(start))
nd <- length(start)
if (is.null(fixed))
n <- nd
else {
n <- nd + length(fixed)
}
R <- transformx(R, scale.type, R.center, R.scale)
transform <- attributes(R)
saved.crit <- rep(NA, nruns)
saved.designs <- matrix(NA, nrow = nruns, ncol = n)
saved.hist <- list(1:nruns)
if (verbose) {
cat(dim(R), fill = TRUE)
}
#
# do nruns with initial desing drawn at random
#
# in this code Dset are the indices of the design
# Cset are the complement set of indices indicating the candidate points
# no used in the design
#
for (RUNS in 1:nruns) {
if (is.null(start)) {
if (!is.null(fixed)) {
Dset <- sample((1:nrow(R))[-fixed], nd)
Dset <- c(Dset, fixed)
}
else Dset <- sample(1:nrow(R), nd)
}
else {
if (length(start) > nd)
stop("Error: the start matrix must have nd rows")
Dset <- start
if (!is.null(fixed))
Dset <- c(Dset, fixed)
}
design.original <- R.orig[Dset, ]
Dset.orginal <- Dset
Cset <- id[-Dset]
dist.mat <- DIST(R[Cset, ], R[Dset, ])
rs <- dist.mat^P %*% rep(1, n)
crit.i <- crit.original <- sum(rs^(Q/P))^(1/Q)
CRIT <- rep(NA, length(Cset))
CRIT.temp <- rep(NA, length(Cset))
hist <- matrix(c(0, 0, crit.i), ncol = 3, nrow = 1)
loop.counter <- 1
repeat {
for (i in 1:nd) {
# loop over current design points looking for a productive swap
Dset.i <- matrix(R[Dset[i], ], nrow = 1)
if (verbose) {
cat("design point", i, Dset.i, fill = TRUE)
}
partial.newrow <- sum(DIST(Dset.i, R[Dset[-i],
])^P)
rs.without.i <- rs - c(DIST(Dset.i, R[-Dset,
])^P)
if (nn)
vec <- (1:length(Cset))[order(dist.mat[, i])[1:num.nn]]
else vec <- 1:length(Cset)
for (j in vec) {
# loop over possible candidates to swap with design point
Cset.j <- matrix(R[Cset[j], ], nrow = 1)
newcol <- c(DIST(Cset.j, R[c(-Dset, -Cset[j]),
])^P)
CRIT[j] <- (sum((rs.without.i[-j] + newcol)^(Q/P)) +
(DIST(Cset.j, Dset.i)^P + partial.newrow)^(Q/P))^(1/Q)
if (verbose) {
cat(j, " ")
}
}
best <- min(CRIT[!is.na(CRIT)])
best.spot <- Cset[CRIT == best][!is.na(Cset[CRIT ==
best])][1]
if (verbose) {
cat(i, "best found ", best, " at", best.spot,
fill = TRUE)
}
crit.old <- crit.i
# check if the best swap is really better thatn what you already have.
if (best < crit.i) {
if (verbose) {
cat(i, "best swapped ", fill = TRUE)
}
crit.i <- best
hist <- rbind(hist, c(Dset[i], best.spot, crit.i))
Dset[i] <- best.spot
Cset <- id[-Dset]
dist.mat <- DIST(R[Cset, ], R[Dset, ])
rs <- (dist.mat^P) %*% rep(1, n)
}
}
if ((crit.i == crit.old) | (loop.counter >= max.loop))
break
loop.counter <- loop.counter + 1
}
saved.crit[RUNS] <- crit.i
saved.designs[RUNS, ] <- Dset
saved.hist[[RUNS]] <- hist
}
ret <- (1:nruns)[saved.crit == min(saved.crit)]
if (length(ret) > 1) {
print("Greater than 1 optimal design; keeping first one......")
ret <- ret[1]
}
crit.i <- saved.crit[ret]
hist <- saved.hist[[ret]]
nhist <- nrow(hist)
nloop <- nruns
hist <- cbind(c(0:(nrow(hist) - 1)), hist)
dimnames(hist) <- list(NULL, c("step", "swap.out", "swap.in",
"new.crit"))
out.des <- R[saved.designs[ret, ], ]
out.des <- unscale(out.des, transform$x.center, transform$x.scale)
out <- list(design = out.des, call = match.call(), best.id = c(saved.designs[ret,
]), fixed = fixed, opt.crit = crit.i, start.design = design.original,
start.crit = crit.original, history = hist, other.designs = saved.designs,
other.crit = saved.crit, DIST = DIST, nn = nn, num.nn = num.nn,
P = P, Q = Q, nhist = nhist - 1, nloop = (nloop - 1)/n)
if (return.grid)
out$grid <- R.orig
if (return.transform)
out$transform <- transform
class(out) <- "spatialDesign"
out
}
|