Translating a VBA function into R - r

I am attempting to translate the function DISCRINV() which is an excel function available in the simtools excel add-in that was created by Roger Myerson into an R function. I believe i am close, but am having difficulty understanding the looping syntax of VBA.
The VBA code for this function is as follows:
Function DISCRINV(ByVal randprob As Double, values As Object, probabilities As Object)
On Error GoTo 63
Dim i As Integer, cumv As Double, cel As Object
If values.Count <> probabilities.Count Then GoTo 63
For Each cel In probabilities
i = i + 1
cumv = cumv + cel.Value
If randprob < cumv Then
DISCRINV = values.Cells(i).Value
Exit Function
End If
Next cel
If randprob < cumv + 0.001 Then
DISCRINV = values.Cells(i).Value
Exit Function
End If
63 DISCRINV = CVErr(xlErrValue)
End Function
Attempting to translate this directly from the VBA code i have come up with this (Not Correct):
DISCRINV <- function(R,V,P){
if(length(V) != length(P)){
print("ERROR NUMBER OF VALUES DOES NOT EQUAL NUMBER OF PROBABILITIES")
} else{
for (i in 1:length(P)){
cumv=cumv+P[i]
if (R < cumv){
DISCY1 = V[i]
return(DISCY1)
}
print(cumv)
if (R < cumv +0.001){
DISCY2 = V[i]
return(DISCY2)
}
}
}
}
Attempting to translate this through my understanding of what it is doing i have come up with this:
DISCRINV <- function(x,values,probabilities){
require(FSA)
precumsum <- pcumsum(probabilities)
middle <- c()
for (i in 1:(length(values)-2)){
if (precumsum[i+1] <= x & x < precumsum[i+2]){
middle[i] <- values[i+1]}
else{
middle[i] <- 0
}
}
firstrow <- ifelse(x < precumsum[2], values[1], 0)
lastrow <- ifelse(precumsum[length(precumsum)] <= x , values[length(precumsum)] , 0)
Gvector <- c(firstrow,middle,lastrow)
print(firstrow)
print(middle)
print(lastrow)
print(Gvector)
simulatedvalue <- sum(Gvector)
return(simulatedvalue)
}
The latter option works 99% of the time, but not when the first function parameter is over 0.5, the second parameter is a vector of values c(1000,2000) and the third parameter is a vector (0.5,0.5). The case of the latter option not working 100% of the time is what has led me to try to translate the function directly. Could someone please give some insight into where my translation is going wrong?
Additionally a description of the function is as follows:
DISCRINV(randprob, values, probabilities) returns inverse cumulative values for a discrete random variable. When the first parameter is a RAND, DISCRINV returns a discrete random variable with possible values and corresponding probabilities in the given ranges.
Thank you in advance for the insight!

For anyone that is interested, i was able to successfully translate this VBA script using this code
DISCRINV <- function(x,values,probabilities){
require(FSA)
precumsum <- pcumsum(probabilities)
middle <- c()
if(length(values <3 )){
if(x<0.5){
middle1 <- values[1]
return(middle1)
} else{
middle2 <- values[2]
return(middle2)
}
}
else{
for (i in 1:(length(values)-2)){
if (precumsum[i+1] <= x & x < precumsum[i+2]){
middle[i] <- values[i+1]}
else{
middle[i] <- 0
}
}
firstrow <- ifelse(x < precumsum[2], values[1], 0)
lastrow <- ifelse(precumsum[length(precumsum)] <= x , values[length(precumsum)] , 0)
Gvector <- c(firstrow,middle,lastrow)
print(firstrow)
print(middle)
print(lastrow)
print(Gvector)
simulatedvalue <- sum(Gvector)
return(simulatedvalue)
}
}

Related

How to implement a function with a sum inside in R?

I am trying to define a function with a for loop and inside a conditional in R studio. Yesterday I was able with the help of another thread to devise this piece of code. The problem is that I want to sum the vector elements ma for any possible x, so that is inside the function l. This is a simpler case which I am trying to solve to adapt the original model. However, I do not know how to proceed.
ma<-rep(0,20)
l <- function(x, ma) {
for(i in seq_along(ma)) {
if(i %% 2 == 1) {
ma[i] <- i + x
} else {
ma[i] <- 0
}
}
return(ma)
}
My problem is that I would like to have the sum of i+x+0+i+x... for any possible x. I mean a function of the kind for any possible x.
Question:
Can someone explain to me how to implement such a function in R?
Thanks in advance!
I am going to update the original function:
Theta_alpha_s<-function(s,alpha,t,Basis){
for (i in seq_along(Basis)){
if(i%% 2==1) {Basis[i]=s*i^{-alpha-0.5}*sqrt(2)*cos(2*pi*i*t)}
else{Basis[i]=s*i^{-alpha-0.5}*sqrt(2)*sin(2*pi*i*t)}
}
return(Basis)
}
If you don't want to change the values in Basis, you can create a new vector in the function (here result) that you will return:
l = function(s,alpha,t,Basis){
is.odd = which(Basis %% 2 == 1)
not.odd = which(Basis %% 2 == 0)
result = rep(NA, length(Basis))
result[is.odd] = s*is.odd^{-alpha-0.5}*sqrt(2)*cos(2*pi*is.odd*t)
result[not.odd] = s*not.odd^{-alpha-0.5}*sqrt(2)*sin(2*pi*not.odd*t)
#return(result)
return(c(sum(result[is.odd]), sum(result[not.odd])))
}

Manually written function doesn't behave the same as the gamma function

So I implemented a function that calculates the value of the gamma function. and when I try to multiply f5(a) with a numeric I receive the error : Error in result * f5(a) : non-numeric argument to binary operator and if I instead use result * gamma(a) which is the predefined function it works just fine. It seems like it won't let me do any arithmetic operation with f5 even though it returns the same result as gamma
f5 <- function(a)
{
f <- function(x)
x^(a-1)*exp(-x)
integrate(f, 0, Inf)
}
f6 <- function(a)
{
if (a < 0)
print("a is negative")
else if (a%%1 == 0)
return (factorial(a-1))
else
{
result <- 1
while (a > 1)
{
result <- result * (a - 1)
a <- a - 1
}
result <- result * f5(a)
result
}
}
gamma(0.3)
f5(0.3)
f6(0.3)
This is because of the class of object that gets returned from f5().
class(f5(0.3))
[1] "integrate"
This is a named list object, and you can call the specific value from it:
names(f5(a))
[1] "value" "abs.error" "subdivisions" "message" "call"
You want the value component. Modifying f6() to the code below makes it work:
f6 <- function(a){
if (a < 0){
print("a is negative")
}else if (a%%1 == 0){
return (factorial(a-1))
}else{
result <- 1
while (a > 1){
result <- result * (a - 1)
a <- a - 1
}
result <- result * f5(a)$value
result
}
}

Average Sample Number using Page's CUSUM procedure?

I am trying reproduce the Table 1 results from the page 12 using the equation given the page 13.To access the journal article please click https://arxiv.org/pdf/math/0605322.pdf. The corresponding equation is given below.
My r code is give below. Am I programmed correctly?
mytest=function(n,s,c1){
t = sum(s)
k=which.max(s[19:n]>=c1)
if(k==1 && s[19]<c1)
return(c(n,0))
else
return(c(k,1))
}
for (n in c(100,200,400)){
for (i in c(-0.5, -1.0)){
a1=0
c1 = 20
asn1=0
for (m in 1:1000){
g=c(dnorm(n,0,1))
f=c(dnorm(n,i,1))
s = log(g/f)
test=mytest(n,s,c1)
a1=a1+test[2]
asn1=asn1+test[1]
}
}
out <- list(power= a1/m, asn=asn1/m)
return(out)
}
But I am getting the following errors.
Error in if (k == 1 && s[19] < c1) return(c(n, 0)) else return(c(k, 1)) :
missing value where TRUE/FALSE needed
The first time you call mytest, you have n=100, i=-0.5 which yields s=NaN. Therefore, you get an error on line if(k==1 && s[19]<c1) given that s[19]=NaN.
Here's a workaround, but you need to make sure it does what you expect/wish :
mytest=function(n,s,c1){
if(is.na(s)) return(c(c1,1)) # skips if NaN
t = sum(s)
k=which.max(s[19:n]>=c1)
if(k==1 && s[19]<c1)
return(c(n,0))
else
return(c(k,1))
}

decimal increments in loop for R

I would like to find the value of "p" below (which is between 0 and 1), knowing the following equations:
RI_26 = min(IR,na.rm=FALSE)
RI_min = 100-(sse*SUM/((1+p)*Dotation2017*100))^(1/p)
where RI_26 is the minimum of resources index of my 26 area. It is a constant in my case. In RI_min, sse and Dotations2017 are 2 constants and p is a unknown. I know that RI_26 should be equal to RI_min.
It would be easy to solve it, but SUM (which is present in RI_min) is as well unknown as it is a function of p as following:
`sum.function = function(p){
SUM <- c(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
for(i in 1:length(Canton))
if(IR[i] < 100) {
SUM[i] <- (100-IR[i])^(1+p)*Pop[i]
SUM[27] <- SUM[27]+SUM[i]
}
SUM <- round(SUM,0)
return(SUM[27])
}
SUM = sum.function(p)
SUM returns a number (or vector 1X1). To deal with it, I would like to find the value of p that satisfied:
RI_26/RI_min = 1
To do so, I would like to do a loop, beginning with p = 0 and then increasing the value of p by 0.01 until it reaches 1. The loop should return the value of p_star when the constraint is True (RI_26/RI_min = 1.00).
I don't have any idea how to do this but it could look like the following code:
p.function = function(){
for(...)
if(RI_26/RI_min = 1.000000) {
p_star <- p
}
return(p_star)
}
So the function will return the value of p_star when RI_26/RI_min = 1.000000. What am I suppose to write in my function: p.function to increment "p" and have the result that I want? Any idea?
for (i in seq(0, 1, by = 0.1)) {
"Your code here"
}

In R, how to read multiple integers from user prompt?

I need to create a vector with multiple inputs (integers) from user.
The intent is to create a list and verify if it has a mode and where is its median.
I am using this code:
ReadVector <- function()
{
x <- 0
while(x<16) {
n <- readline(prompt="Input one integer: ")
return(as.integer(n))
VectorUser <- c(n)
x <- x+1
}
print(VectorUser)
}
ReadVector()
And I can only get one integer, I dont know if my mistake is in the while loop or(and) in the concatenate command after it. Can you help me?
Does this work for you?
ReadVector <- function()
{
x <- 0
myvector = vector()
while(x<16) {
n <- readline(prompt="Input one integer: ")
myvector = c(myvector,n)
x <- x+1
}
return (as.integer(myvector))
}
You need yo save your values in a vector, and keep it (without returning inside the loop), until you completed it.
Hope it helps
ff=function(){
d=c()
while (TRUE){
int = readline('ENTER to quit > ')
if(nchar(int)==0) {
if(length(d)>0)cat("The numbers you entered are:",d)
else(cat("You did not enter any number!!"));break}
else{
value=suppressWarnings(as.integer(int))
if(!is.na(value)){cat(value);d=c(d,value)} else cat(ran[sample(6,1)])
}}
ff()

Resources