A course in quantitative research workflow for students in the higher education administration program at the University of Florida
Using collegeloc.RDS
and cblocks.RDS
, please answer the following
question. Use comments to respond as necessary.
Below is a function that computes the great circle distance using
Vincenty’s
formula. It’s
more accurate than the haversine version, but can be much more
computationally intensive. Try to convert the base R function into an
Rcpp function. You’ll need to start a new script and then use
sourceCpp()
to read it in and test. Once you’ve got, substitute the
respective Vincenty formula functions into the dist_min_*()
functions and compare times.
A few things to keep in mind:
double
); don’t forget that double numbers need a decimal,
otherwise C++ thinks they are integers.abs()
in C++ is fabs()
a^2 = a * a
## base R distance function using Vincenty formula
dist_vincenty <- function(xlon,
xlat,
ylon,
ylat) {
## return 0 if same point
if (xlon == ylon && xlat == ylat) { return(0) }
## convert degrees to radians
xlon <- deg_to_rad(xlon)
xlat <- deg_to_rad(xlat)
ylon <- deg_to_rad(ylon)
ylat <- deg_to_rad(ylat)
## ---------------------------------------------------
## https:##en.wikipedia.org/wiki/Vincenty%27s_formulae
## ---------------------------------------------------
## some constants
a <- 6378137
f <- 1 / 298.257223563
b <- (1 - f) * a
U1 <- atan((1 - f) * tan(xlat))
U2 <- atan((1 - f) * tan(ylat))
sinU1 <- sin(U1)
sinU2 <- sin(U2)
cosU1 <- cos(U1)
cosU2 <- cos(U2)
L <- ylon - xlon
lambda <- L # initial value
## set up loop
iters <- 100 # no more than 100 loops
tol <- 1.0e-12 # tolerance level
again <- TRUE
## while loop...
while (again) {
## sin sigma
sinLambda <- sin(lambda)
cosLambda <- cos(lambda)
p1 <- cosU2 * sinLambda
p2 <- cosU1 * sinU2 - sinU1 * cosU2 * cosLambda
sinsig <- sqrt(p1^2 + p2^2)
## cos sigma
cossig <- sinU1 * sinU2 + cosU1 * cosU2 * cosLambda
## plain ol' sigma
sigma <- atan2(sinsig, cossig)
## sin alpha
sina <- cosU1 * cosU2 * sinLambda / sinsig
## cos^2 alpha
cos2a <- 1 - (sina * sina)
## cos 2*sig_m
cos2sigm <- cossig - 2 * sinU1 * sinU2 / cos2a
## C
C <- f / 16 * cos2a * (4 + f * (4 - 3 * cos2a))
## store old lambda
lambdaOld <- lambda
## update lambda
lambda <- L + (1 - C) * f * sina *
(sigma + C * sinsig * (cos2sigm + C * cossig *
(-1 + 2 * cos2sigm^2)))
## subtract from iteration total
iters <- iters - 1
## go again if lambda diff is > tolerance and still have iterations
again <- (abs(lambda - lambdaOld) > tol && iters > 0)
}
## if iteration count runs out, stop and send message
if (iters == 0) {
stop("Failed to converge!", call. = FALSE)
}
else {
## u^2
Usq <- cos2a * (a^2 - b^2) / (b^2)
## A
A <- 1 + Usq / 16384 * (4096 + Usq * (-768 + Usq * (320 - 175 * Usq)))
## B
B <- Usq / 1024 * (256 + Usq * (-128 + Usq * (74 - 47 * Usq)))
## delta sigma
dsigma <- B * sinsig *
(cos2sigm + B / 4 *
(cossig * (-1 + 2 * cos2sigm^2)
- B / 6 * cos2sigm * (-3 + 4 * sinsig^2)
* (-3 + 4 * cos2sigm^2)))
## return the distance
return(b * A * (sigma - dsigma))
}
}
<lastname>_assignment_rcpp.R
) in your scripts
directory.