Name:
Andrew ID:
Collaborated with:

This lab is to be completed in class. You can collaborate with your classmates, but you must identify their names above, and you must submit your own lab as an Rmd file on Blackboard, by 11:59pm on the day of the lab.

There are Homework 8 questions dispersed throughout. These must be written up in a separate Rmd document, together with all Homework 8 questions from other labs. Your homework writeup must start as this one: by listing your name, Andrew ID, and who you collaborated with. You must submit your own homework as a knit HTML file on Blackboard, by 11:59pm on Tuesday November 1. This document contains 15 of the 45 total points for Homework 8.

Some light defense

input.list = list(0, 1, 2, -1, "Jessica", exp(1), exp(pi))
for (i in 1:length(input.list)) {
  cat(paste("We are at iteration", i, "with x =", input.list[[i]],
            "and log(x) =", log(input.list[[i]]), "\n")) 
}
## We are at iteration 1 with x = 0 and log(x) = -Inf 
## We are at iteration 2 with x = 1 and log(x) = 0 
## We are at iteration 3 with x = 2 and log(x) = 0.693147180559945
## Warning in log(input.list[[i]]): NaNs produced
## We are at iteration 4 with x = -1 and log(x) = NaN
## Error in log(input.list[[i]]): non-numeric argument to mathematical function
fibonacci = function(n) {
  if (n==1 || n==2) return(1)
  my.fib = c(1,1)
  for (i in 3:n) my.fib[i] = my.fib[i-1] + my.fib[i-2]  
  return(my.fib[n])
}

fibonacci(20)
## [1] 6765
fibonacci(-1)
## Error in my.fib[i] = my.fib[i - 1] + my.fib[i - 2]: replacement has length zero
fibonacci(1.5)
## Error in my.fib[i] = my.fib[i - 1] + my.fib[i - 2]: replacement has length zero
fibonacci("hi")
## Warning in fibonacci("hi"): NAs introduced by coercion
## Error in 3:n: NA/NaN argument
fibonacci(matrix(1:4, 2, 2))
## [1] 1
fibonacci(list(x=0, y=1))
## Warning in 3:n: numerical expression has 2 elements: only the first used
## Error in 3:n: NA/NaN argument

Hw8 Q1 (6 points). Fill out the function skeleton quadratic.solver() below that takes inputs a, b, c, all numeric variables, representing the coefficients of a quadratic \(q(x)=ax^2 + bx + c\), and returns a numeric vector of length 2, which contains the roots of the quadratic, i.e., the solutions to \(q(x)=0\). Use error checking at the start to make sure that a, b, c are all really single numeric variables—if not, then your function should throw a warning (with an informative message), and return NA. Demonstrate this behavior on the test inputs below. Also, when one or two of the roots are complex numbers, your function should throw a warning (with an informative message). (Hint: you’ll want to remind yourself of the well-known formula for the roots of a quadratic; there’s even a song, to the tune of “Jing Bells”!) Check that the outputs of your function match those described in comments, for the test inputs below.

quadratic.solver = function(a,b,c) {
  return(0)
}

quadratic.solver("catch","this","bug") # Should throw a warning, and return NA
## [1] 0
quadratic.solver(1:5,6:10,1:15) # Should throw a warning, and return NA
## [1] 0
quadratic.solver(1,0,-1) # Should return c(1, -1)
## [1] 0
quadratic.solver(1,0,1) # Should return c(0+1i, 0-1i), with a warning
## [1] 0

Trying and catching

get.wordtab = function(str.url, split="[[:space:]]|[[:punct:]]",
                       tolower=TRUE, keep.numbers=FALSE) {
  lines = readLines(str.url)
  text = paste(lines, collapse=" ")
  words = strsplit(text, split=split)[[1]]
  words = words[words != ""]
    
  # Convert to lower case, if we're asked to
  if (tolower) words = tolower(words)
  
  # Get rid of words with numbers, if we're asked to
  if (!keep.numbers)
    words = grep("[0-9]", words, inv=TRUE, val=TRUE)
  
  table(words)
}

get.wordtabs = function(str.urls, split="[[:space:]]|[[:punct:]]",
                       tolower=TRUE, keep.numbers=FALSE) {
  wordtabs = list()
  for (i in 1:length(str.urls)) {
    cat(paste("* Website:",str.urls[i],"\n"))
    wordtabs[[i]] = get.wordtab(str.urls[i], split, tolower, keep.numbers)
  }
  return(wordtabs)
}

str.urls = c("http://stat.cmu.edu/~ryantibs/research.html",
             "www.this.is.not.a.real.website.com",
             "http://stat.cmu.edu/~ryantibs/teaching.html")
wordtab = get.wordtab(str.urls[2]) 
## Warning in file(con, "r"): cannot open file
## 'www.this.is.not.a.real.website.com': No such file or directory
## Error in file(con, "r"): cannot open the connection
wordtabs = get.wordtabs(str.urls)
## * Website: http://stat.cmu.edu/~ryantibs/research.html 
## * Website: www.this.is.not.a.real.website.com
## Warning in file(con, "r"): cannot open file
## 'www.this.is.not.a.real.website.com': No such file or directory
## Error in file(con, "r"): cannot open the connection

Hw8 Q2 (9 points). The function evil.rbinom() below is an evil binomial sampler written by your professor. Think about it as operating in three modes: “warning” mode, “error” mode, and “normal” mode. Each time evil.rbinom() is called, it enters warning mode with probability \(p_{\rm warning}\), error mode with probability \(p_{\rm error}\), and normal mode otherwise. In warning mode, the function throws a warning, and returns an arbitrary number between 1 and 100. In error mode, the function throws an error. In normal mode, it samples a binomial random variable, with size 100, and success probability \(p_{\rm heads}\) (i.e., this is the number of coin tosses that came up heads out of 100 i.i.d. coin tosses, each with probability \(p_{\rm heads}\) of coming up heads.)

Your task is to estimate \(p_{\rm warning}\) (the probability of getting a warning), \(p_{\rm error}\) (the probability of getting an error), and \(p_{\rm heads}\) (the probability of single coin toss being heads, in normal mode), by calling evil.rbinom() as many times as you wish. After we have loaded it with source() below, this function is included in your R workspace, so you may just call evil.rbinom() directly. (Hint: you’ll want to use a for() loop to repeatedly call evil.rbinom() many times. You’ll also want to use a tryCatch() statement to catch both errors and warnings, that could appear each time you call evil.rbinom(). For example, code of the form:

tryCatch({
  # EXPRESSION GOES HERE
  }, warning = function(w) { 
    return(-1) 
  }, error = function (e) {
    return(-2)  
  })

will run some expression and then either call the warning function or the error function, depending on what gets encountered. When a warning is encountered, the above code block will evaluate to -1; when an error is encountered, the above will evaluate to -2; otherwise it evaluates to the value of the expression.) Your code must support your estimated probabilities, i.e., it must show clearly how you computed them. Simply stating numbers will not get you points.

source("http://www.stat.cmu.edu/~ryantibs/statcomp-F16/labs/evil.rbinom.R")