Name:
Andrew ID:
Collaborated with:

On this homework, you can collaborate with your classmates, but you must identify their names above, and you must submit your own homework as an knitted HTML file on Canvas, by Monday August 5 at 10pm, next week.

# Introduction to percolation

In this homework, we’ll be coding a series of functions to investigate percolation via simulation. We’ll spend this section to discuss the problem and setup. You can read related literature on this topic at Wikipedia, but we’ll be working with a simplified setting for this homework. As a word of caution, this is a coding heavy homework (as opposed to statistical), so be prepared to spend a lot of time debugging and testing.

Here’s the idea. Imagine you have a square board (10 by 10 squares) like the left board show below. This board consist of white “open” squares and black “blocked” squares. We are interested in knowing (abstractly) if we “pour water” from the top of the matrix, does the water “leak” from the bottom of the matrix. This is demonstrated in the right board. (Don’t worry, we’ll explain all the necessary specifics later.) You can think of this as the following: we indefinitely keep pouring water into each white square in the top row at the same time, and water runs through the board by spreading to any adjacent white square (left, right, top, and bottom). We keep pouring water until all the possibly-flooded squares are flooded. These are the blue squares shown below in the right board. Once we’re done, we see if the water reached any of the open squares in the bottom row of the board (i.e., are there any blue squares in the bottom row?). If so, we say the board “percolates”. Otherwise, it does not percolate. In the figure shown below, the displayed board percolates (left is the original board, and right is the percolated board).

However, not all boards percolate. Consider the next board, shown below. Once again, we show the initial board on the left, and we start pouring water, resulting in the board on the right.

Now imagine we had a way to randomly generate these boards. We would like to see if there are certain types of randomly-generated boards that more likely to percolate. We’ll formalize this task in this homework.

So what are the goals of this homework? We will be developing a package with version control and github connection. This package will encapsulate a set of functions related to a new object, called `board`. While developing our package, we will be writing the following functions: `generate_board_mat()` will generate a random board (matrix version) with white “open” squares and black “blocked” squares. `is_valid()` will check whether or not a given board matrix is correctly formatted. `plot.board()` will plot the board, similar to the four boards shown above. The last two functions contribute the challenges to this homework: `percolate.board()`, which determines whether or not a board percolates, and `read_board()` reads in a text file that specifies many boards. Note that `plot.board()` and `percolate.board()` will be methods of the class.

We will not give you explicit guidance on how to debug and test throughout most of this homework, but the concepts and tools you’ve learned in lecture will certainly be beneficial as you write and try out your code.

Note: The grading of this homework with depend mainly on whether or not you pass the test cases provided. Your implementation of `percolate.board()` and `read_boards()` might look quite different from another classmates, but be you sure that your code passes the tests if you want full credit!

# Making a package and using version control

As you will be learning version control and connection to github during Wednesday’s lecture and making packages but you should start this assignment early in the week, I provide 3 ways to approach this homework (conditional on your experience and willingness to read future lectures). I recommend that you try to at least start with Approach 2 if you have some knowledge about `Github`.

Approach 1 (Base Approach):

Start writing all you code into this homework `.Rmd` file as usual. As long as the code you write well documented the you can transfer your code to a package with version control at the very end (this is less prefered in terms of using version control - but is fine for now). At the very end of the assignment will be guidance on how to create your package with version control. Note: the “Approach 2/3” comments throught this document can also aid this this endeavor.

In this approach - it is very important that all functions and tests you write deal well with the “local” vs “global” paradigm - that is, don’t assume more things are in the global environment than you need.

Approach 2 (Github start):

Using the guide in Wednesday’s Lecture, create a new github public repository please call it `percolate` and create a project in your Rstudio that links to it. Please additionally make folders `R/` and `/tests/testthat/` in this new directory. We will put your functions and class definitions in `.R` files in the `R/` folder and your tests in `.R` files in the `tests/testthat/` folder. I provide a small section at the end of the homework on how you should moving from being “approach 2” to “approach 3”.

Approach 3 (package start):

Similar to the Approach 2, create a new github public repository please call it `percolate` and create a project in your Rstudio that links to it. Using `usethis::create_package("percolate")` create a package in this directory. Make sure in your console you call this function when you are in the folder that contains the folder `precolate`.

``To navigate in the console use `setwd()` and `getwd()` (which sets the directory you're in and returns which directory you're currently in)``

You will be using `usethis` to set up your package and `devtools` to check your tests, document your functions and more. Please also see closing remarks at the bottom of the file.

# Generating and plotting boards

In the first section, we will be creating our new class `board` as well as helper function and a plot function for our object. We will write `generate_board_mat()`, and create a class object that can either take in a matrix or generate the board with certain parameters. In this section we will also create the function `is_valid()` and the method `plot.board()`. To no surprise, we can represent these boards as square, numeric matrices with dimension `n` by `n`. These matrices will only have values `0` (for black “blocked” squares), `1` (for white “open and dry” squares), and `2` (for blue “open and flooded”) squares.

Approach 2: you’ll see the names of files to create / update. Just run the code in these files into your console to get interactions.

• 1a. Before we define our class let’s define a helper funtion to generate boards. Write the function `generate_board_mat()` that takes arguments `n` (a positive integer denote the size of the board) and `p` (a number between 0 and 1 that denotes the fraction of the `n^2` squares are blocked). This function should return a `n` by `n` matrix with values `0` or `1`. The specific locations are the `floor(p*n^2)` blocked squares are chosen uniformly at random. Be sure to write lines to check that the input arguments are valid using `assert_that()`. Set the default values to be `n=5` and `p=0.25`. Print the matrix for `generate_board_mat()` (using the default parameters) and `generate_board_mat(n = 8, p = 0.75)`. Document the function using `Roxygen2` (control + alt + shift + R).

``````library(assertthat)
library(testthat)``````

Approach 3: To make sure you have a `tests/testthat` folder, run the commands in the console below while you’re in your package:

``````usethis::use_testthat()
# and
usethis::use_package("assertthat")``````

Approach 2/3:

Write this function `generate_board_mat` in a `.R` file called `utils.R` in the `R` folder. Put the suggested examples in the examples section (make sure to run them after your run your function in the console). For approach 3 you can create the file using `usethis::use_r("utils")`. and after you’re done writing the function use `devtools::document()` to document the function. Then use `devtools::load_all()` to put the `generate_board_mat` into your working space (you should use this function whenever you update a function or documentation - but I won’t keep mentioning it).

Finally, add the `utils.R` file (and potentially other files associated with it) and make a commit.

• 1b. Now, using the `test_that()` function, write the following tests: 1) ensure that when using `generate_board_mat()` (default parameters), the output is a `5` by `5` numeric matrix containing only `0` and `1`, 2) ensure the same but for a different value of `n`, 3) ensure that using `p = 0` gives a board with all `1`’s, 4) ensure that using `p = 1` gives a board with all `0`’s, 5) ensure that the function throws an error when `n = c(1,2)` or `n = "asdf"` or `n = 5.4` or `n = -5`.

Approaches 2/3:

Write these tests in a `.R` file called `test-utils.R` in the `tests/testthat/` folder. Run your tests and make sure the pass. For approach 3, use `usethis::use_test("utils.R")` to create the `test-utils.R` file in `tests/testthat/`, once written, save file and run `devtools::test()` and see that all your tests have passed.

Finally, add the `test-utils.R` file (and potentially other files associated with it) and make a commit.

• 1c. One last helper function before our class definition… Now we will write the `is_valid()` function (please document). This function should take in a matrix `mat` as input. It should check that `mat` is a square matrix that contains values only `0`, `1`, or `2` using `assert_that()`. Then, it should return `TRUE`. Hence, `is_valid()` will always throw an error or return `TRUE`. Print out the result of `is_valid(generate_board_mat())` and `is_valid(generate_board_mat(n = 1))` (which should both return `TRUE`). Then, write 3 tests using `test_that()` to ensure that `is_valid()` will throw an error for inputs `mat` that are not valid. Each of your 3 tests should be testing for a different reason for invalidity.

In your documentation please put `#' @import assertthat` at the bottom of the documentation. This will make it such that you can use all functions from `assertthat` in your package without having to do `assertthat::assert_that` every time. (See the challenge at the end of this assignment for a better approach - aka actually doing `assertthat::assert_that` every time).

Approaches 2/3:

Place this function into `utils.R` and the associated tests in `test-utils.R`. For approach 3, create documentation and check your tests using the correct `devtools` functions. Remember to do `devtools::load_all()` when done.

Finally, (sensing a pattern), add updated files and make a commit.

• 1d. Finally! Let’s make a function that returns an object with class `board` (specifically, but have the object also inherit the `matrix` class functionality – aka have `board` be a subclass of `matrix`). This function should either take in a matrix (default `= NULL`) or take in and `n` and `p` value (defaults same as `generate_board`). Note: These comments means I want the parameter to be `mat = NULL, n = 5, p = .25`. Additionally, if a matrix (`mat`) is provided (aka non-NULL) then use that at the matrix and create a object of class board. Additionally, add attributes `n` and `p` to the object (empirical values for `p` if `mat` is provided or the generating parameters if not). Write a test to check that if you input a `mat` it returns a `board` with the same structure (use `expect_equivalent` and `unclass` here), and that the empirical `n` and `p` values are correct. Also check if you put in an incorrect matrix structure (check the same matrices in 1c) it errors. And finally, test some examples of inputting `n` and `p`. Document your function.

Approaches 2/3: Place this function/class definition into `board.R` and the associated tests in `test-board.R`. Continue following similar procedures for `devtools` calls (approach 3) and commits (everyone).

• 1d. Lastly, we will write the `plot.board()` method, which also takes in a board `x`. This function should check that `x` is valid using the `is_valid()` function prior to plotting (just in case someone is trying to trick us to plot a fake board). Using `ggplot` (remember back to `my_volcano`) Plot the board so the resulting plot is a square with axes labels or legend (`+ theme(legend.position = "none")`), has a title stating the size of the board, and has a black square for each `0` entry of `mat`, a white square for each `1` entry of `mat`, and a light blue square for each `2` entry of `mat`. Additionally make the theme `+ theme_void()`. (Hint: It might be desirable to define `n <- attr(board, "n")` before you do anything else. Also, please use the color `lightblue3` when making the image for the light blue squares. You’ll find the `+ scale_fill_manual()` function quite useful… use a named vector for the `values` in this function.)

As always: document, document, document.

In your documentation please put `#' @import ggplot2` (and additional lines for any other packages you use in this function: e.g. `tidyr`) at the bottom of the documentation. I won’t remind you to do this again, but you’ll need to do so.

For example, we provide a specific board below, `board_example`. The desired plot you should produce when running `plot(board_example)` is also shown below. Plot your output for `plot(board_example)`. We also provide `board_example2-4` that you should check (but no need to put in documentation or this document).

Challenge: make the axis proportional like our examples and have the title centered.

``````board_example <- board(matrix(c(0,1,1,1,0,
0,1,1,0,1,
0,0,1,0,0,
0,0,0,2,2,
2,2,2,2,0), 5, 5))
#^note the matrix will be the transpose of what you see here (due to byrow = F)

board_example2 <- board(matrix(c(0,1,1,1,0,
0,1,1,0,1,
0,0,1,0,0,
0,0,0,1,1,
1,1,1,1,0), 5, 5))

board_example3 <- board(matrix(c(0,2,2,2,0,
0,2,2,0,2,
0,0,2,0,0,
0,0,0,2,2,
2,2,2,2,0), 5, 5))

board_example4 <- board(    # board of size 10 (correctly percolated)
matrix(c(2, 0, 0, 2, 0, 0, 2, 2, 0, 0,
2, 2, 2, 0, 0, 2, 2, 0, 0, 1,
0, 2, 0, 0, 0, 0, 2, 0, 0, 0,
0, 2, 2, 2, 0, 0, 0, 0, 0, 0,
0, 2, 0, 0, 0, 0, 1, 0, 0, 0,
2, 2, 2, 0, 1, 0, 0, 1, 1, 1,
0, 2, 2, 0, 1, 1, 0, 0, 1, 0,
1, 0, 2, 0, 0, 0, 0, 1, 1, 0,
1, 0, 0, 1, 1, 0, 0, 0, 0, 0,
0, 1, 1, 0, 0, 1, 0, 1, 0, 0),
10, 10))``````

Approaches 2/3:

Place this function/class definition into `visualize.R` (tests are hard for visualizations - we’ll ignore them for now - but do put your board_examples in the documentation). Continue following similar procedures for `devtools` calls (approach 3) and commits (everyone). * Approach 3, since you’re also using a new package add `ggplot2` to the used packages (see how you added `assertthat` at the begining of this problem).*

• 1e. Challenge/Extra: Add an parameter to `plot.board()` called `grid` which is a boolean. If `grid = FALSE`, nothing additional happens. However, if `grid = TRUE`,draw dashed grid lines onto the plot as well, so each square of `mat` is outlined. This is a pretty similar update, but you’ll need to tinker around with it (Hint: look at `geom_tile`) The desired plot when running `plot.board(board_example, grid = TRUE)` is shown below. Plot your output for `plot.board(board_example, grid = TRUE)`.

Approach 2/3: update your function, documentation, etc and follow standard git/ devtools approach.