Why is my Martingale Simulation Function Failing to Work? - r

I've just started getting back into coding, and I'm trying to write a few different functions to simulate betting strategies. The first I'm trying to simulate is the martingale strategy, a strategy where you place a roulette bet that has ~ 50% odds (black/red or even/odd) and each time you lose the bet, you double the bet until you won (or pass the max wager).
This is my current function which does not appear to be working. I'm not sure if the logic is sound (too many nested loops become confusing quickly). If anyone could point me in the right direction, that would be awesome.
possible_nums <- floor(runif(5, min=0, max=35)) # generate sequence of random numbers
wager = 5
tot_money <- 10000
wins <- 0
simulations <- 1:500
Martingale <- function(wager, tot_money) {
for(i in simulations) {
while(tot_money >= 5 & wager <= 500 ) { # stop betting if lose by running out of money or surpassing max wager
roll <- sample(possible_nums, 1) # roll number 1-35
if (roll %% 2 == 0) { # we will be betting even/odd (as opposed to black/red) for simulation
wins = wins + 1 # if even, we win
tot_money = tot_money + 5 # add 5 dollars to total money/balance if win
} else {
wager*2 # if roll was odd, double wager
}
}
}
}
print(wins)
print(tot_money)
}
Martingale(5, 1000) # run function
The function isn't even giving me an output when I run it. R seems very picky with the spacing of the brackets. I tried correcting them to not avail. If I get the function working, then I can correct the logic.
Thanks for any help!

You have one closing bracket too much, which closes the function before you print the results:
Martingale <- function(wager, tot_money) {
for(i in simulations) {
while(tot_money >= 5 & wager <= 500 ) { # stop betting if lose by running out of money or surpassing max wager
roll <- sample(possible_nums, 1) # roll number 1-35
if (roll %% 2 == 0) { # we will be betting even/odd (as opposed to black/red) for simulation
wins = wins + 1 # if even, we win
tot_money = tot_money + 5 # add 5 dollars to total money/balance if win
} else {
wager*2 # if roll was odd, double wager
}
}
}
} # <-- this one is too much,
print(wins)
print(tot_money)
}
Also note that your code will NOT terminate: you only increase tot_money, and do not modify the value of wager.
Let me note that you do not simulate a 50% chance: you choose at the beginning 5 random integers below 35 and take samples from those; if you want to simulate an odd/even change, you are better off with rbinom(1, 1, .5).
You might want to swap the way this is simulated and run the simulation-loop outside the Martingale function, and return the values and store them in a array:
Martingale2 <- function(wager, tot_money) {
while(tot_money >= 5 & wager <= 500 ) {
roll <- rbinom(1, 1, .5)
if (roll == 0) {
wins <- wins + 1
tot_money <- tot_money + 5
} else {
tot_money <- tot_money - wager
wager <- wager*2
}
}
list(wins = wins, tot_money = tot_money)
}
simulations <- 500
simulation_results <- t(replicate(simulations, Martingale2(5, 1000)))

Related

User defined function within for-loops

I am working on a project in which I am simulating 8 classroom social networks over 6 weeks, so 30 iterations. Students will nominate each other based on a number of factors, and I plan to simulate a number of conditions in which I remove or add some of these factors to the simulation. In other words, I'm going to be repeating a lot of code, so I'd rather use functions rather than cutting and pasting where ever possible.
Right now, I'm trying to create a function that adjusts the probability of one student selecting another based on the similarity of their emotions. When I include it in a set of nested for for loops, this works just fine:
num_students <- 5
names_students <- letters[1:num_students]
student_emotion <- sample(round(runif(5, min = -5, max = 5), digits = 1))
student_emotion_df <- cbind.data.frame(names_students, student_emotion)
probs <- rep(1/num_students, 5)
row_prob <- vector(length = 5)
for(i in 1:num_students){
for(q in 1:num_students){
if(abs(student_emotion[i]-student_emotion[q]) >= 0 &
abs(student_emotion[i]-student_emotion[q]) <= .5){
row_prob[q] <- 1*probs[q]
} else if(abs(student_emotion[i]-student_emotion[q]) > .5 &
abs(student_emotion[i]-student_emotion[q]) <= 1) {
row_prob[q] <- .75 * probs[q]
}
else {
row_prob[q] <- .5 * probs[q]
}
}
}
The row_prob object is a vector of probabilities a student i, in the column, will select student q, in the rows.
I've created a user-defined function based on the same code, and that works:
emotion_difference_fun <- function(probs){
for(q in 1:num_students){
if(abs(student_emotion[i]-student_emotion[q]) >= 0 &
abs(student_emotion[i]-student_emotion[q]) <= .5){
row_prob[q] <- 1*probs[q]
} else if(abs(student_emotion[i]-student_emotion[q]) > .5 &
abs(student_emotion[i]-student_emotion[q]) <= 1) {
row_prob[q] <- .75 * probs[q]
}
else {
row_prob[q] <- .5 * probs[q]
}
}
return(row_prob)
}
emotion_difference_fun(probs)
But when I try to embed that function within the for loop iterating through the columns, row_prob returns as an empty vector:
for(i in 1:num_students){
emotion_difference_fun(probs)
}
Any thoughts on how I can get this to work?
Thanks for any help you're able to offer.
If I understood your question properly, then you need to assign the results in your last 'for' loop:
for(i in 1:num_students){
if(i == 1) out <- NULL
out <- c(out, emotion_difference_fun(probs))
}
out
Is that what you are looking for?
What I am unclear about though, is why in your second code section you are not looking for a 5*5 matrix. Eventually, when running that code, it doesn't matter that you did it for i = 5 students, because it will only save in row_prob your last iteration (student = 5).
You can use replicate to repeat the function emotion_difference_fun for num_students.
result <- replicate(num_students, emotion_difference_fun(probs))
You can also set simplify = FALSE to get output as list.
result <- replicate(num_students, emotion_difference_fun(probs),simplify = FALSE)

Optimize simple r code for Project Euler 12

The idea of Project Euler question 12 is to find the smallest triangular number with a specified number of divisors(https://projecteuler.net/problem=12). As an attempt to solve this problem, I wrote the following code:
# This function finds the number of divisors of a number and returns it.
FUN <- function(x) {
i = 1
lst = integer(0)
while(i<=x)
{
if(x %% i ==0)
{
lst = c(lst, i)
}
i = i +1
}
return(lst)
}
and
n = 1
i=1
while (length(FUN(n))<500)
{
i = i + 1
n = n + i
}
This code is producing the correct answer for few smaller test cases: length(FUN(n))<4 will produce 6, and length(FUN(n))<6 will produce 28.
However, this simple looking code is taking over 24 hours to run (and still running) for length(FUN(n))<500. I understand that for a number to have 500 divisors, the number is probably very big, but I am wondering why is it taking so long to run.
You FUN is much too inefficient for this task. As the first triangular number is above the 12,000th with a value of 75,000,000 and FUN runs through all these numbers ... the number of iterations to perform is almost
12000 * 75000000 / 2 = 450 * 10^9
This is clearly more than R's relatively slow for-loop can do in a reasonable time frame.
Instead, you could apply the divisors function from the numbers package that employs a prime factor decomposition. The following code need about 5-6 seconds (on my machine) to find the triangular number.
library(numbers)
t <- 0
system.time(
for (i in 1:100000) {
t <- t + i
d <- length( divisors(t) )
if (d > 500) {
cat(i, t, d, '\n')
break
}
}
)
## 12375 76576500 576
## user system elapsed
## 5.660 0.000 5.658
Instead of calculating the i-th triangular number, here i is added to the last triangular number. The time saving is minimal.
Here's my attempt:
library(gmp)
library(plyr)
get_all_factors <- function(n)
{
prime_factor_tables <- lapply(
setNames(n, n),
function(i)
{
if(i == 1) return(data.frame(x = 1L, freq = 1L))
plyr::count(as.integer(gmp::factorize(i)))
}
)
lapply(
prime_factor_tables,
function(pft)
{
powers <- plyr::alply(pft, 1, function(row) row$x ^ seq.int(0L, row$freq))
power_grid <- do.call(expand.grid, powers)
sort(unique(apply(power_grid, 1, prod)))
}
)
}
for (i in 99691200:100000) {
if (length(get_all_factors(i)[[1]])>500) print(paste(i, length(get_all_factors(i)[[1]])))
if (i %% 100000 == 0) print(paste("-",i,"-"))
}
Let it run as long as you can be bothered...

Data generation: Creating a vector of vectors

I have a vector of positive integers of unknown length. Let's call it vector a with elements a[1], a[2], ...
I want to perform calculations on vector b where for all i, 0 <= b[i] <= a[i].
The following does not work:
for(b in 0:a)
{
# calculations
}
The best I have come up with is:
probabilities <- function(a,p)
{
k <- a
k[1] <- 1
h <- rep(0,sum(a)+1)
for(i in 2:length(a))
{
k[i] <- k[i-1]*(a[i-1]+1)
}
for(i in 0:prod(a+1))
{
b <- a
for(j in 1:length(a))
{
b[j] <- (floor(i/k[j]) %% (a[j]+1))
}
t <- 1
for(j in 1:length(a))
{
t <- t * choose(a[j],b[j])*(p[j])^(b[j])*(1-p[j])^(a[j]-b[j])
}
h[sum(b)+1] <- h[sum(b)+1] + t
}
return(h)
}
In the middle of my function is where I create b. I start off by setting b equal to a (so that it is the same size). Then, I replace all of the elements of b with different elements that are rather tricky to calculate. This seems like an inefficient solution. It works, but it is fairly slow as the numbers get large. Any ideas for how I can cut down on process time? Essentially, what this does for b is the first time through, b is all zeros. Then, it is 1, 0,0,0,... The first element keeps incrementing until it reaches a[1], then b[2] increments and b[1] is set to 0. Then b[1] starts incrementing again.
I know the math is sound, I just do not trust that it is efficient. I studied combinatorics for a few years, but have never studied computational complexity theory, so coming up with a fast algorithm is a bit beyond my realm of knowledge. Any ideas would be helpful!

How to implement mutation function of genetic algorithm in R?

I'm implementing GA algorithm. The chromosomes have a combination of -1,0,1 values. In the mutation part, I want to change -1 to 1 with prob(-1 to 1) and change 1 to -1 with prob(1 to -1).
I don't know if there is any function in R which would make it easy for me. Would any one tell me if there is a function which helps me replace the values according to their probability?
You could throw a dice and if 1 comes up, you change the original value to another value. You could add if statements for all of your transitions. If you mean to mutate the whole string in one step, this can be better optimized.
from <- c(1,-1,1,0,-1)
probToMutate <- function(x) {
if (x == 1) {
dice <- rbinom(1, size = 1, prob = 0.1)
if (dice == 1) {
x <- -1
} else {
x <- 1
}
} else {
x
}
}
sapply(from, FUN = probToMutate)

Number of Dice rolling till reaches a Stop Value

I am trying to count the number of dice rolls till it reaches to a definite stop value. For example, I want the stop value as 100. I am writing the following code:
sumofsides <- function(stopvalue) {
totalsum <- 0
while (totalsum < stopvalue) {
face <- sample(6, 1, replace= TRUE)
totalsum <- totalsum + face
}
return(total value)
}
sumofsides(100)
[1] 103
When I am writing the following code to get the number of rolling till it reaches to the stop value. But it's always giving value of 1 which is wrong.
numofrolls <- function(stopvalue) {
totalsum <- 0
while (totalsum < stopvalue) {
face <- sample(6, 1, replace= TRUE)
totalsum <- totalsum + face
}
return(length(face))
}
numofrolls(100)
[1] 1
Any help is appreciated.
In your current loop, you are rewriting totalsum every iteration with a new value, so its length will never go beyond one. One solution would be to use a second variable to count the number of rolls:
rollUntil <- function(n) {
nRolls <- 0
sumRolls <- 0
while (sumRolls <= n) {
sumRolls <- sumRolls + sample.int(6, 1)
nRolls = nRolls + 1
}
return(nRolls)
}
# let's look at the distribution of rolls till 100:
hist(replicate(1000,rollUntil(100)))

Resources