Associated Material

Module: Module 09 - Iteration

Readings

Topics

Iteration Use Cases

For loops

  • Syntax
  • Sequence options
  • Loop driver variable
  • Nested for loops

While loops

  • Syntax
  • Loop conditions
  • Infinite while loops

Alternatives for single function loops

  • Map family
  • Apply family

Exercises

Loop Driver Practice

Write a for loop that prints the even numbers between 2 and 20. That is, you should print 2, 4, 6, 8… There are multiple ways to achieve this outcome. Get more practice working with loop driver variables by trying to find two different solutions. Hint: If you’ve never used the modulo operator, this is a good time to learn (see for example, https://www.geeksforgeeks.org/r-operators/). Repeat the exercise, with a while loop.

Modeling and simulation with stochasticity

Mathematical modeling is a discipline of study where complex, stochastic phenomena are described using deterministic, empirically testable systems. These systems often involve advanced mathematical techniques. For example, one can define a mathematical model for the response of an architectural design to ground disturbances, and use it to predict the ability of the building to withstand earthquakes of varying intensity. Or one can model the effect of habitat loss on a prey species and use that to predict impacts on an entire food chain.

Because such systems are generally stochastic (i.e. there is random variability in their behaviour), modeled effects are usually simulated many, many times, and a distribution of outcomes produced. While the code required to simulate a system can be very complex, the process of running it many times and accruing the results is easy – just use a for loop.

For example, we have used the function rnorm to randomly select a single value from a normal distribution. In a mature language like R, we can assume that this function behaves correctly, but this is a testable claim. If we were to select many, many single values with rnorm and plot them, we would expect them to be normally distributed. (Note that is is actually possible to select multiple values with rnorm without looping, but we will ignore that small fact for this example.) This simple simulation illustrates the loop-compute-accrue computational pattern, which forms the basis of much modern computer modelling and simulation.

# Number of trials to run -- more is generally better
n_trials <- 10000

# Vector to store results in
sample_value_vector <- c()

# Simulation parameters
sim_mean <- 100
sim_sd <- 10

# Loop, compute, accrue
for (trial in 1:n_trials)
{
  # Compute -- IRL can be 1000s of lines of code here
  sample_value <- rnorm(1, sim_mean, sim_sd)
  
  # Accrue results, using the loop driver to add each
  # value on to the end of the vector
  sample_value_vector[trial] <- sample_value
}


# At the end of the for loop, we have 10,000 values
# gathered in sample_value_vector, and we can plot them
# to confirm that they are, in fact, distributed normally

hist(sample_value_vector)

Last week, we wrote a function to play Rock-Paper-Scissors, where each player selected randomly from the three possible moves. (If you didn’t write that function, you can use the version shown below.) Use the loop-compute-accrue pattern to determine the probability of the game ending in a draw (i.e. both players make the same move) if both players are selecting their move randomly.

The game

rock_paper_scissors <- function()
{
  # Vector of the three possible moves
  moves <- c("rock", "paper", "scissors")
  
  # Randomly select a move for Bob
  bob_move <- sample(moves,1)
  
  # Randomly select a move for Fred
  fred_move <- sample(moves,1)
  
  
  # Work through the game win conditions
  if (bob_move == fred_move){
    winner = "draw"
  }
  
  if( bob_move == "rock"){
    if (fred_move == "paper"){
      winner = "fred"
    }
    if (fred_move == "scissors"){
      winner = "bob"
    }
      
  }
  
  if (bob_move == "paper"){
    if (fred_move == "rock"){
      winner = "bob"
    }
    if (fred_move == "scissors"){
      winner = "fred"
    }
  }
  
  if (bob_move == "scissors") {
    if (fred_move == "rock"){
      winner = "fred"
    }
    if (fred_move == "paper"){
      winner = "bob"
    }
  }
  
  # Return the winner
  return(winner)
} # end rock_paper_scissors

The simulation

# Number of trials to run -- more is usually better
n_trials <- 100000

# Vector to accrue results
game_result_vector <- c()

# Loop
for (i in 1:n_trials)
{
  # Compute the winner
  game_result <- rock_paper_scissors()
  
  # Accrue
  game_result_vector[i] <- game_result
}


# At the end of the for loop, we have 100,000 game results.
# We can find the frequency distribution of these categorical
# data using function table

fd <- table(game_result_vector)
print(fd)
#> game_result_vector
#>   bob  draw  fred 
#> 33101 33299 33600

Our simulation shows that, when both players select their moves randomly, the probability of a draw is approximately 1/3, as is the probability of each player winning. That is, all outcomes are equally likely.

Comparing strategies

When very small children play Rock-Paper-Scissors, they often pick one move and use it every time. This makes them extremely easy to beat. Modify your game function so that one of the players (e.g. “bob” in my solution) always picks Scissors. What outcome probabilities would you predict under this new strategy, where one player’s move is fixed? Repeat your simulation. Was your prediction confirmed? If not, explain the unexpected result.

LS0tCnRpdGxlOiAiWm9vbSBOb3RlcyAwOTogUmVwZWF0aW5nIENvZGUiCmRhdGU6ICJTZW1lc3RlciAyLCAyMDIzIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0b2NfZGVwdGg6IDMKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KGtuaXRyKQoKa25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGNvbW1lbnQgPSAiIz4iLAogIGZpZy5wYXRoID0gImZpZ3VyZXMvMDkvIiwgIyB1c2Ugb25seSBmb3Igc2luZ2xlIFJtZCBmaWxlcwogIGNvbGxhcHNlID0gVFJVRSwKICBlY2hvID0gVFJVRQopCgojIGtlZXAgdGhlIHJlc3VsdGluZyBodG1sIHRoZSBzYW1lIHNpbmNlIHNhbXBsaW5nIGlzIHVzZWQgbGF0ZXIgb24gaW4gdGhlIGxlc3NvbgpzZXQuc2VlZCg0MikKYGBgCgoKPiAjIyMjIEFzc29jaWF0ZWQgTWF0ZXJpYWwKPgo+IE1vZHVsZTogW01vZHVsZSAwOSAtIEl0ZXJhdGlvbl0oMDktaXRlcmF0ZS5odG1sKQo+Cj4gUmVhZGluZ3MKPgo+IC0gW1IgZm9yIERhdGEgU2NpZW5jZSAtIENoYXB0ZXIgMjFdKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovaXRlcmF0aW9uLmh0bWwpCgoKIyBUb3BpY3MKCiMjIEl0ZXJhdGlvbiBVc2UgQ2FzZXMKCiMjIEZvciBsb29wcwoKLSAgU3ludGF4Ci0gIFNlcXVlbmNlIG9wdGlvbnMKLSAgTG9vcCBkcml2ZXIgdmFyaWFibGUKLSAgTmVzdGVkIGZvciBsb29wcwoKIyMgV2hpbGUgbG9vcHMKCi0gIFN5bnRheAotICBMb29wIGNvbmRpdGlvbnMKLSAgSW5maW5pdGUgd2hpbGUgbG9vcHMKCiMjIEFsdGVybmF0aXZlcyBmb3Igc2luZ2xlIGZ1bmN0aW9uIGxvb3BzCgotICBNYXAgZmFtaWx5Ci0gIEFwcGx5IGZhbWlseQoKIyBFeGVyY2lzZXMKCiMjIyBMb29wIERyaXZlciBQcmFjdGljZQoKV3JpdGUgYSBmb3IgbG9vcCB0aGF0IHByaW50cyAqKnRoZSBldmVuIG51bWJlcnMqKiBiZXR3ZWVuIDIgYW5kIDIwLiBUaGF0IGlzLCB5b3Ugc2hvdWxkIHByaW50IDIsIDQsIDYsIDguLi4gVGhlcmUgYXJlIG11bHRpcGxlIHdheXMgdG8gYWNoaWV2ZSB0aGlzIG91dGNvbWUuIEdldCBtb3JlIHByYWN0aWNlIHdvcmtpbmcgd2l0aCBsb29wIGRyaXZlciB2YXJpYWJsZXMgYnkgdHJ5aW5nIHRvIGZpbmQgdHdvIGRpZmZlcmVudCBzb2x1dGlvbnMuIEhpbnQ6IElmIHlvdSd2ZSBuZXZlciB1c2VkIHRoZSAqKm1vZHVsbyBvcGVyYXRvcioqLCB0aGlzIGlzIGEgZ29vZCB0aW1lIHRvIGxlYXJuIChzZWUgZm9yIGV4YW1wbGUsIGh0dHBzOi8vd3d3LmdlZWtzZm9yZ2Vla3Mub3JnL3Itb3BlcmF0b3JzLykuIFJlcGVhdCB0aGUgZXhlcmNpc2UsIHdpdGggYSB3aGlsZSBsb29wLgoKCiMjIyBNb2RlbGluZyBhbmQgc2ltdWxhdGlvbiB3aXRoIHN0b2NoYXN0aWNpdHkKCioqTWF0aGVtYXRpY2FsIG1vZGVsaW5nKiogaXMgYSBkaXNjaXBsaW5lIG9mIHN0dWR5IHdoZXJlIGNvbXBsZXgsIHN0b2NoYXN0aWMgcGhlbm9tZW5hIGFyZSBkZXNjcmliZWQgdXNpbmcgZGV0ZXJtaW5pc3RpYywgZW1waXJpY2FsbHkgdGVzdGFibGUgc3lzdGVtcy4gVGhlc2Ugc3lzdGVtcyBvZnRlbiBpbnZvbHZlIGFkdmFuY2VkIG1hdGhlbWF0aWNhbCB0ZWNobmlxdWVzLiBGb3IgZXhhbXBsZSwgb25lIGNhbiBkZWZpbmUgYSBtYXRoZW1hdGljYWwgbW9kZWwgZm9yIHRoZSByZXNwb25zZSBvZiBhbiBhcmNoaXRlY3R1cmFsIGRlc2lnbiB0byBncm91bmQgZGlzdHVyYmFuY2VzLCBhbmQgdXNlIGl0IHRvIHByZWRpY3QgdGhlIGFiaWxpdHkgb2YgdGhlIGJ1aWxkaW5nIHRvIHdpdGhzdGFuZCBlYXJ0aHF1YWtlcyBvZiB2YXJ5aW5nIGludGVuc2l0eS4gT3Igb25lIGNhbiBtb2RlbCB0aGUgZWZmZWN0IG9mIGhhYml0YXQgbG9zcyBvbiBhIHByZXkgc3BlY2llcyBhbmQgdXNlIHRoYXQgdG8gcHJlZGljdCBpbXBhY3RzIG9uIGFuIGVudGlyZSBmb29kIGNoYWluLgoKQmVjYXVzZSBzdWNoIHN5c3RlbXMgYXJlIGdlbmVyYWxseSBzdG9jaGFzdGljIChpLmUuIHRoZXJlIGlzIHJhbmRvbSB2YXJpYWJpbGl0eSBpbiB0aGVpciBiZWhhdmlvdXIpLCBtb2RlbGVkIGVmZmVjdHMgYXJlIHVzdWFsbHkgc2ltdWxhdGVkIG1hbnksIG1hbnkgdGltZXMsIGFuZCBhIGRpc3RyaWJ1dGlvbiBvZiBvdXRjb21lcyBwcm9kdWNlZC4gV2hpbGUgdGhlIGNvZGUgcmVxdWlyZWQgdG8gc2ltdWxhdGUgYSBzeXN0ZW0gY2FuIGJlIHZlcnkgY29tcGxleCwgdGhlIHByb2Nlc3Mgb2YgcnVubmluZyBpdCBtYW55IHRpbWVzIGFuZCBhY2NydWluZyB0aGUgcmVzdWx0cyBpcyBlYXN5IC0tIGp1c3QgdXNlIGEgZm9yIGxvb3AuCgpGb3IgZXhhbXBsZSwgd2UgaGF2ZSB1c2VkIHRoZSBmdW5jdGlvbiBgcm5vcm1gIHRvIHJhbmRvbWx5IHNlbGVjdCBhIHNpbmdsZSB2YWx1ZSBmcm9tIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbi4gSW4gYSBtYXR1cmUgbGFuZ3VhZ2UgbGlrZSBSLCB3ZSBjYW4gYXNzdW1lIHRoYXQgdGhpcyBmdW5jdGlvbiBiZWhhdmVzIGNvcnJlY3RseSwgYnV0IHRoaXMgaXMgYSB0ZXN0YWJsZSBjbGFpbS4gSWYgd2Ugd2VyZSB0byBzZWxlY3QgbWFueSwgbWFueSBzaW5nbGUgdmFsdWVzIHdpdGggYHJub3JtYCBhbmQgcGxvdCB0aGVtLCB3ZSB3b3VsZCBleHBlY3QgdGhlbSB0byBiZSBub3JtYWxseSBkaXN0cmlidXRlZC4gKE5vdGUgdGhhdCBpcyBpcyBhY3R1YWxseSBwb3NzaWJsZSB0byBzZWxlY3QgbXVsdGlwbGUgdmFsdWVzIHdpdGggcm5vcm0gd2l0aG91dCBsb29waW5nLCBidXQgd2Ugd2lsbCBpZ25vcmUgdGhhdCBzbWFsbCBmYWN0IGZvciB0aGlzIGV4YW1wbGUuKSBUaGlzIHNpbXBsZSBzaW11bGF0aW9uIGlsbHVzdHJhdGVzIHRoZSAqKmxvb3AtY29tcHV0ZS1hY2NydWUqKiBjb21wdXRhdGlvbmFsIHBhdHRlcm4sIHdoaWNoIGZvcm1zIHRoZSBiYXNpcyBvZiBtdWNoIG1vZGVybiBjb21wdXRlciBtb2RlbGxpbmcgYW5kIHNpbXVsYXRpb24uCgpgYGB7ciBybm9ybSB0ZXN0fQojIE51bWJlciBvZiB0cmlhbHMgdG8gcnVuIC0tIG1vcmUgaXMgZ2VuZXJhbGx5IGJldHRlcgpuX3RyaWFscyA8LSAxMDAwMAoKIyBWZWN0b3IgdG8gc3RvcmUgcmVzdWx0cyBpbgpzYW1wbGVfdmFsdWVfdmVjdG9yIDwtIGMoKQoKIyBTaW11bGF0aW9uIHBhcmFtZXRlcnMKc2ltX21lYW4gPC0gMTAwCnNpbV9zZCA8LSAxMAoKIyBMb29wLCBjb21wdXRlLCBhY2NydWUKZm9yICh0cmlhbCBpbiAxOm5fdHJpYWxzKQp7CiAgIyBDb21wdXRlIC0tIElSTCBjYW4gYmUgMTAwMHMgb2YgbGluZXMgb2YgY29kZSBoZXJlCiAgc2FtcGxlX3ZhbHVlIDwtIHJub3JtKDEsIHNpbV9tZWFuLCBzaW1fc2QpCiAgCiAgIyBBY2NydWUgcmVzdWx0cywgdXNpbmcgdGhlIGxvb3AgZHJpdmVyIHRvIGFkZCBlYWNoCiAgIyB2YWx1ZSBvbiB0byB0aGUgZW5kIG9mIHRoZSB2ZWN0b3IKICBzYW1wbGVfdmFsdWVfdmVjdG9yW3RyaWFsXSA8LSBzYW1wbGVfdmFsdWUKfQoKCiMgQXQgdGhlIGVuZCBvZiB0aGUgZm9yIGxvb3AsIHdlIGhhdmUgMTAsMDAwIHZhbHVlcwojIGdhdGhlcmVkIGluIHNhbXBsZV92YWx1ZV92ZWN0b3IsIGFuZCB3ZSBjYW4gcGxvdCB0aGVtCiMgdG8gY29uZmlybSB0aGF0IHRoZXkgYXJlLCBpbiBmYWN0LCBkaXN0cmlidXRlZCBub3JtYWxseQoKaGlzdChzYW1wbGVfdmFsdWVfdmVjdG9yKQpgYGAKCkxhc3Qgd2Vlaywgd2Ugd3JvdGUgYSBmdW5jdGlvbiB0byBwbGF5IFJvY2stUGFwZXItU2Npc3NvcnMsIHdoZXJlIGVhY2ggcGxheWVyIHNlbGVjdGVkIHJhbmRvbWx5IGZyb20gdGhlIHRocmVlIHBvc3NpYmxlIG1vdmVzLiAoSWYgeW91IGRpZG4ndCB3cml0ZSB0aGF0IGZ1bmN0aW9uLCB5b3UgY2FuIHVzZSB0aGUgdmVyc2lvbiBzaG93biBiZWxvdy4pIFVzZSB0aGUgbG9vcC1jb21wdXRlLWFjY3J1ZSBwYXR0ZXJuIHRvIGRldGVybWluZSB0aGUgcHJvYmFiaWxpdHkgb2YgdGhlIGdhbWUgZW5kaW5nIGluIGEgZHJhdyAoaS5lLiBib3RoIHBsYXllcnMgbWFrZSB0aGUgc2FtZSBtb3ZlKSBpZiBib3RoIHBsYXllcnMgYXJlIHNlbGVjdGluZyB0aGVpciBtb3ZlIHJhbmRvbWx5LgoKCiMjIyMgVGhlIGdhbWUKYGBge3IgZ2FtZX0Kcm9ja19wYXBlcl9zY2lzc29ycyA8LSBmdW5jdGlvbigpCnsKICAjIFZlY3RvciBvZiB0aGUgdGhyZWUgcG9zc2libGUgbW92ZXMKICBtb3ZlcyA8LSBjKCJyb2NrIiwgInBhcGVyIiwgInNjaXNzb3JzIikKICAKICAjIFJhbmRvbWx5IHNlbGVjdCBhIG1vdmUgZm9yIEJvYgogIGJvYl9tb3ZlIDwtIHNhbXBsZShtb3ZlcywxKQogIAogICMgUmFuZG9tbHkgc2VsZWN0IGEgbW92ZSBmb3IgRnJlZAogIGZyZWRfbW92ZSA8LSBzYW1wbGUobW92ZXMsMSkKICAKICAKICAjIFdvcmsgdGhyb3VnaCB0aGUgZ2FtZSB3aW4gY29uZGl0aW9ucwogIGlmIChib2JfbW92ZSA9PSBmcmVkX21vdmUpewogICAgd2lubmVyID0gImRyYXciCiAgfQogIAogIGlmKCBib2JfbW92ZSA9PSAicm9jayIpewogICAgaWYgKGZyZWRfbW92ZSA9PSAicGFwZXIiKXsKICAgICAgd2lubmVyID0gImZyZWQiCiAgICB9CiAgICBpZiAoZnJlZF9tb3ZlID09ICJzY2lzc29ycyIpewogICAgICB3aW5uZXIgPSAiYm9iIgogICAgfQogICAgICAKICB9CiAgCiAgaWYgKGJvYl9tb3ZlID09ICJwYXBlciIpewogICAgaWYgKGZyZWRfbW92ZSA9PSAicm9jayIpewogICAgICB3aW5uZXIgPSAiYm9iIgogICAgfQogICAgaWYgKGZyZWRfbW92ZSA9PSAic2Npc3NvcnMiKXsKICAgICAgd2lubmVyID0gImZyZWQiCiAgICB9CiAgfQogIAogIGlmIChib2JfbW92ZSA9PSAic2Npc3NvcnMiKSB7CiAgICBpZiAoZnJlZF9tb3ZlID09ICJyb2NrIil7CiAgICAgIHdpbm5lciA9ICJmcmVkIgogICAgfQogICAgaWYgKGZyZWRfbW92ZSA9PSAicGFwZXIiKXsKICAgICAgd2lubmVyID0gImJvYiIKICAgIH0KICB9CiAgCiAgIyBSZXR1cm4gdGhlIHdpbm5lcgogIHJldHVybih3aW5uZXIpCn0gIyBlbmQgcm9ja19wYXBlcl9zY2lzc29ycwoKYGBgCgoKIyMjIyBUaGUgc2ltdWxhdGlvbgpgYGB7ciBzaW11bGF0aW9ufQojIE51bWJlciBvZiB0cmlhbHMgdG8gcnVuIC0tIG1vcmUgaXMgdXN1YWxseSBiZXR0ZXIKbl90cmlhbHMgPC0gMTAwMDAwCgojIFZlY3RvciB0byBhY2NydWUgcmVzdWx0cwpnYW1lX3Jlc3VsdF92ZWN0b3IgPC0gYygpCgojIExvb3AKZm9yIChpIGluIDE6bl90cmlhbHMpCnsKICAjIENvbXB1dGUgdGhlIHdpbm5lcgogIGdhbWVfcmVzdWx0IDwtIHJvY2tfcGFwZXJfc2Npc3NvcnMoKQogIAogICMgQWNjcnVlCiAgZ2FtZV9yZXN1bHRfdmVjdG9yW2ldIDwtIGdhbWVfcmVzdWx0Cn0KCgojIEF0IHRoZSBlbmQgb2YgdGhlIGZvciBsb29wLCB3ZSBoYXZlIDEwMCwwMDAgZ2FtZSByZXN1bHRzLgojIFdlIGNhbiBmaW5kIHRoZSBmcmVxdWVuY3kgZGlzdHJpYnV0aW9uIG9mIHRoZXNlIGNhdGVnb3JpY2FsCiMgZGF0YSB1c2luZyBmdW5jdGlvbiB0YWJsZQoKZmQgPC0gdGFibGUoZ2FtZV9yZXN1bHRfdmVjdG9yKQpwcmludChmZCkKCgpgYGAKCk91ciBzaW11bGF0aW9uIHNob3dzIHRoYXQsIHdoZW4gYm90aCBwbGF5ZXJzIHNlbGVjdCB0aGVpciBtb3ZlcyByYW5kb21seSwgdGhlIHByb2JhYmlsaXR5IG9mIGEgZHJhdyBpcyBhcHByb3hpbWF0ZWx5IDEvMywgYXMgaXMgdGhlIHByb2JhYmlsaXR5IG9mIGVhY2ggcGxheWVyIHdpbm5pbmcuIFRoYXQgaXMsIGFsbCBvdXRjb21lcyBhcmUgZXF1YWxseSBsaWtlbHkuCgoKIyMjIyBDb21wYXJpbmcgc3RyYXRlZ2llcwoKV2hlbiB2ZXJ5IHNtYWxsIGNoaWxkcmVuIHBsYXkgUm9jay1QYXBlci1TY2lzc29ycywgdGhleSBvZnRlbiBwaWNrIG9uZSBtb3ZlIGFuZCB1c2UgaXQgZXZlcnkgdGltZS4gVGhpcyBtYWtlcyB0aGVtIGV4dHJlbWVseSBlYXN5IHRvIGJlYXQuIE1vZGlmeSB5b3VyIGdhbWUgZnVuY3Rpb24gc28gdGhhdCBvbmUgb2YgdGhlIHBsYXllcnMgKGUuZy4gImJvYiIgaW4gbXkgc29sdXRpb24pIGFsd2F5cyBwaWNrcyBTY2lzc29ycy4gV2hhdCBvdXRjb21lIHByb2JhYmlsaXRpZXMgd291bGQgeW91IHByZWRpY3QgdW5kZXIgdGhpcyBuZXcgc3RyYXRlZ3ksIHdoZXJlIG9uZSBwbGF5ZXIncyBtb3ZlIGlzIGZpeGVkPyBSZXBlYXQgeW91ciBzaW11bGF0aW9uLiBXYXMgeW91ciBwcmVkaWN0aW9uIGNvbmZpcm1lZD8gSWYgbm90LCBleHBsYWluIHRoZSB1bmV4cGVjdGVkIHJlc3VsdC4gCgoKCgoKCgoKCgoKCgoKCgoKCgoK