Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@dewittpe's solution and write up for @standupmaths's frog_problem #2

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 186 additions & 0 deletions dewittpe-solution/frog_jump.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
#'---
#'title: Frog Jump Problem
#'author: Peter DeWitt
#'output: pdf_document
#'header-includes:
#' - \usepackage{blkarray}
#' - \usepackage{amsmath}
#'---
#'
#+ label = "setup", include = FALSE, cache = FALSE
knitr::opts_chunk$set(cache = TRUE)
library(parallel)

#'
#' # The Problem:
#'
#' A frog is on one bank of a pond. There are $p$ lily pads between the frog
#' and the opposite bank of the pond. This frog has the ability to jump from
#' the bank it starts on to any of the $p$ lily pads or all the way to the
#' opposite bank. The frog will randomly jump, with equal probability, forward,
#' at least one pad. The question is, what is the expected number of jumps
#' the frog will make to transverse the pond?
#'
#' \begin{center}
#' \begin{tabular}{cccccccc}
#' \includegraphics[width=0.10\textwidth]{grass} &
#' \includegraphics[width=0.10\textwidth]{lilypad}&
#' \includegraphics[width=0.10\textwidth]{lilypad}&
#' \ldots &
#' \includegraphics[width=0.10\textwidth]{lilypad}&
#' \includegraphics[width=0.10\textwidth]{lilypad}&
#' \includegraphics[width=0.10\textwidth]{lilypad}&
#' \includegraphics[width=0.10\textwidth]{pictures-of-green-frogs-7} \\
#' Pad $0$ & Pad $1$ & Pad $2$ & \ldots & Pad $p - 2$ & Pad $p - 1$ & Pad $p$ & Pad $p+1$ \\
#' GOAL: Pond bank & & & & & & & Start
#' \end{tabular}
#' \end{center}
#'
#'
#' Goals for the solution:
#'
#' 1. Solution is to be general for any number of pads.
#' 2. Solution should not rely on recursion.
#'
#'
#' # Solution
#'
#' ## Simulation
#'
#' The simulation does rely on recursion. This simulation is used to test the
#' other solution. The code is writen in [R](https://www.r-project.org).
#'
# frog_jumper
# Arguments:
# pads : the number of lily pads between the frog and the bank of the pond.
# jumps : number of jumps taken so far
# verbose : if TRUE print status.
#
# Return:
# the number of jumps needed to transverse the pond for the given simulation.
#
frog_jumper <- function(pads, jumps = 0, verbose = FALSE) {
if (verbose) {cat("jump:", jumps, "frog is on pad:", pads + 1, "\n")}
distance <- sample(x = seq(1, pads + 1, by = 1), size = 1)
if (distance > pads) {
if (verbose) {cat("jump:", jumps + 1, "frog Has Reached the bank.\n")}
return(invisible(jumps + 1))
} else {
frog_jumper(pads = pads - distance, jumps + 1, verbose = verbose)
}
}

#'
#' A couple quick checks of the simulation code. If there are zero pads between
#' the frog and the pond bank then the function should return 1.
set.seed(42)
frog_jumper(0, verbose = TRUE)

#'
#' If there is one pad beween the frog and the bank then the function should
#' return the value 1 with probability 1/2 and the value 2 with probability 1/2.
#' Test this with 1,000,000 simulations.
x <- replicate(n = 1e6, expr = {frog_jumper(1)})
prop.table(table(x))

#'
#' The expected number of jumps the frog will take if there is only one pad
#' between the frog an the bank is
simulation <- function(pads, iterations = 1e6) {
mean(
do.call(c,
mclapply(X = seq(1, iterations),
FUN = function(i, ...) {frog_jumper(...) },
pads = pads,
mc.cores = 12))
)
}
simulation(1)

#'
#' For 10 pads between the frog and the opposite bank, the expected number of
#' jumps the frog will take is
simulation(10)

#'
#' ## A Maths Solution
#'
#' Define the transtion of the frog via a discrete time Markov chain with the
#' transition probability matrix $\boldsymbol{T}$ with the current state defined
#' on the rows and next state defined on columns.
#'
#' $$ \boldsymbol{T} =
#' \begin{pmatrix} \boldsymbol{Q} & \boldsymbol{B} \\ \boldsymbol{0} & 1 \end{pmatrix}.$$
#'
#' The bottom row of $\boldsymbol{T}$ is a row vector of zeros with $p + 1$
#' elements and the bottom right entry in $\boldsymbol{T}$ is 1. This row
#' represents the transition probability for jumping form the goal bank to the
#' goal bank.
#' $\boldsymbol{B}$ is a column vector with $p+1$ entries. This vector gives
#' the probabilities of jumping for the current pad to the goal bank. Finally,
#' the matrix $\boldsymbol{Q}$ is the $(p+1) \times (p+1)$ matrix of transition
#' probabilities from pad to pad.
#'
#' $$ \boldsymbol{Q} =
#'\begin{blockarray}{cccccc}
#' & \text{Pad } p + 1 & \text{Pad } p & \cdots & \text{Pad } 2 & \text{Pad } 1 \\
#'\begin{block}{c(ccccc)}
#' \text{Pad } p + 1 & 0 & \frac{1}{p+1} & \cdots & \frac{1}{p+1} & \frac{1}{p+1} \\
#' \text{Pad } p & 0 & 0 & \cdots & \frac{1}{p} & \frac{1}{p} \\
#' \vdots & \vdots & \vdots & \ddots & \vdots & \vdots \\
#' \text{Pad } 2 & 0 & 0 & 0 & 0 & \frac{1}{2} \\
#' \text{Pad } 1 & 0 & 0 & 0 & 0 & 0 \\
#'\end{block}
#'\end{blockarray}.
#'$$
#'
#' The expected number of transitions, i.e., jumps, the frog will take to
#' transverse the pond via lily pad can be found via the rowsums of the matrix
#' $\boldsymbol{J}:$
#' $$ \boldsymbol{J} = \left( \boldsymbol{I} - \boldsymbol{Q} \right)^{-1}, $$
#' where $\boldsymbol{I}$ is the identity matrix.
#'
#' The form of $\boldsymbol{J}$ is
#' $$ \boldsymbol{J} =
#'\begin{blockarray}{ccccccc}
#' & \text{Pad } p + 1 & \text{Pad } p & \cdots & \text{Pad } 3 & \text{Pad } 2 & \text{Pad } 1 \\
#'\begin{block}{c(cccccc)}
#' \text{Pad } p + 1 & 1 & \frac{1}{p+1} & \cdots & \frac{1}{4} & \frac{1}{3} & \frac{1}{2} \\
#' \text{Pad } p & 0 & 1 & \cdots & \frac{1}{4} & \frac{1}{3} & \frac{1}{2} \\
#' \vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \vdots \\
#' \text{Pad } 3 & 0 & 0 & 0 & 1 & \frac{1}{3} & \frac{1}{2} \\
#' \text{Pad } 2 & 0 & 0 & 0 & 0 & 1 & \frac{1}{2} \\
#' \text{Pad } 1 & 0 & 0 & 0 & 0 & 0 & 1 \\
#'\end{block}
#'\end{blockarray}.
#'$$
#'
#' The expected number of jumps the frog will take from pad $p$ to get to the
#' bank is
#'
#' $$ \text{E}\left(\text{jumps}\right) = \sum_{j = 1}^{p + 1} \frac{1}{j}.$$
#'
#' The expected number of jumps if there are 10 pads between the frog and the
#' bank is
PADS <- 10
sum(seq(1, PADS + 1, by = 1)^-1)

#'
#' For 20 pads between the frog and the bank:
PADS <- 20
sum(seq(1, PADS + 1, by = 1)^-1)
simulation(PADS)

#'
#' For 30 pads between the frog and the bank:
PADS <- 30
sum(seq(1, PADS + 1, by = 1)^-1)
simulation(PADS)

#'
#' The simulations and the closed form soluion see to match up.
#'
#' **Disclaimer** Part of the goal for this project was to avoid recursion in
#' the solution. The derivation of $\boldsymbol{J}$ could be considered
#' recursive. However, I would argue the final solution does not rely on
#' recursion.
212 changes: 212 additions & 0 deletions dewittpe-solution/frog_jump.Rmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
---
title: Frog Jump Problem
author: Peter DeWitt
output: pdf_document
header-includes:
- \usepackage{blkarray}
- \usepackage{amsmath}
---


```{r label = "setup", include = FALSE, cache = FALSE}
knitr::opts_chunk$set(cache = TRUE)
library(parallel)
```


# The Problem:

A frog is on one bank of a pond. There are $p$ lily pads between the frog
and the opposite bank of the pond. This frog has the ability to jump from
the bank it starts on to any of the $p$ lily pads or all the way to the
opposite bank. The frog will randomly jump, with equal probability, forward,
at least one pad. The question is, what is the expected number of jumps
the frog will make to transverse the pond?

\begin{center}
\begin{tabular}{cccccccc}
\includegraphics[width=0.10\textwidth]{grass} &
\includegraphics[width=0.10\textwidth]{lilypad}&
\includegraphics[width=0.10\textwidth]{lilypad}&
\ldots &
\includegraphics[width=0.10\textwidth]{lilypad}&
\includegraphics[width=0.10\textwidth]{lilypad}&
\includegraphics[width=0.10\textwidth]{lilypad}&
\includegraphics[width=0.10\textwidth]{pictures-of-green-frogs-7} \\
Pad $0$ & Pad $1$ & Pad $2$ & \ldots & Pad $p - 2$ & Pad $p - 1$ & Pad $p$ & Pad $p+1$ \\
GOAL: Pond bank & & & & & & & Start
\end{tabular}
\end{center}


Goals for the solution:

1. Solution is to be general for any number of pads.
2. Solution should not rely on recursion.


# Solution

## Simulation

The simulation does rely on recursion. This simulation is used to test the
other solution. The code is writen in [R](https://www.r-project.org).


```{r }
# frog_jumper
# Arguments:
# pads : the number of lily pads between the frog and the bank of the pond.
# jumps : number of jumps taken so far
# verbose : if TRUE print status.
#
# Return:
# the number of jumps needed to transverse the pond for the given simulation.
#
frog_jumper <- function(pads, jumps = 0, verbose = FALSE) {
if (verbose) {cat("jump:", jumps, "frog is on pad:", pads + 1, "\n")}
distance <- sample(x = seq(1, pads + 1, by = 1), size = 1)
if (distance > pads) {
if (verbose) {cat("jump:", jumps + 1, "frog Has Reached the bank.\n")}
return(invisible(jumps + 1))
} else {
frog_jumper(pads = pads - distance, jumps + 1, verbose = verbose)
}
}
```


A couple quick checks of the simulation code. If there are zero pads between
the frog and the pond bank then the function should return 1.

```{r }
set.seed(42)
frog_jumper(0, verbose = TRUE)
```


If there is one pad beween the frog and the bank then the function should
return the value 1 with probability 1/2 and the value 2 with probability 1/2.
Test this with 1,000,000 simulations.

```{r }
x <- replicate(n = 1e6, expr = {frog_jumper(1)})
prop.table(table(x))
```


The expected number of jumps the frog will take if there is only one pad
between the frog an the bank is

```{r }
simulation <- function(pads, iterations = 1e6) {
mean(
do.call(c,
mclapply(X = seq(1, iterations),
FUN = function(i, ...) {frog_jumper(...) },
pads = pads,
mc.cores = 12))
)
}
simulation(1)
```


For 10 pads between the frog and the opposite bank, the expected number of
jumps the frog will take is

```{r }
simulation(10)
```


## A Maths Solution

Define the transtion of the frog via a discrete time Markov chain with the
transition probability matrix $\boldsymbol{T}$ with the current state defined
on the rows and next state defined on columns.

$$ \boldsymbol{T} =
\begin{pmatrix} \boldsymbol{Q} & \boldsymbol{B} \\ \boldsymbol{0} & 1 \end{pmatrix}.$$

The bottom row of $\boldsymbol{T}$ is a row vector of zeros with $p + 1$
elements and the bottom right entry in $\boldsymbol{T}$ is 1. This row
represents the transition probability for jumping form the goal bank to the
goal bank.
$\boldsymbol{B}$ is a column vector with $p+1$ entries. This vector gives
the probabilities of jumping for the current pad to the goal bank. Finally,
the matrix $\boldsymbol{Q}$ is the $(p+1) \times (p+1)$ matrix of transition
probabilities from pad to pad.

$$ \boldsymbol{Q} =
\begin{blockarray}{cccccc}
& \text{Pad } p + 1 & \text{Pad } p & \cdots & \text{Pad } 2 & \text{Pad } 1 \\
\begin{block}{c(ccccc)}
\text{Pad } p + 1 & 0 & \frac{1}{p+1} & \cdots & \frac{1}{p+1} & \frac{1}{p+1} \\
\text{Pad } p & 0 & 0 & \cdots & \frac{1}{p} & \frac{1}{p} \\
\vdots & \vdots & \vdots & \ddots & \vdots & \vdots \\
\text{Pad } 2 & 0 & 0 & 0 & 0 & \frac{1}{2} \\
\text{Pad } 1 & 0 & 0 & 0 & 0 & 0 \\
\end{block}
\end{blockarray}.
$$

The expected number of transitions, i.e., jumps, the frog will take to
transverse the pond via lily pad can be found via the rowsums of the matrix
$\boldsymbol{J}:$
$$ \boldsymbol{J} = \left( \boldsymbol{I} - \boldsymbol{Q} \right)^{-1}, $$
where $\boldsymbol{I}$ is the identity matrix.

The form of $\boldsymbol{J}$ is
$$ \boldsymbol{J} =
\begin{blockarray}{ccccccc}
& \text{Pad } p + 1 & \text{Pad } p & \cdots & \text{Pad } 3 & \text{Pad } 2 & \text{Pad } 1 \\
\begin{block}{c(cccccc)}
\text{Pad } p + 1 & 1 & \frac{1}{p+1} & \cdots & \frac{1}{4} & \frac{1}{3} & \frac{1}{2} \\
\text{Pad } p & 0 & 1 & \cdots & \frac{1}{4} & \frac{1}{3} & \frac{1}{2} \\
\vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \vdots \\
\text{Pad } 3 & 0 & 0 & 0 & 1 & \frac{1}{3} & \frac{1}{2} \\
\text{Pad } 2 & 0 & 0 & 0 & 0 & 1 & \frac{1}{2} \\
\text{Pad } 1 & 0 & 0 & 0 & 0 & 0 & 1 \\
\end{block}
\end{blockarray}.
$$

The expected number of jumps the frog will take from pad $p$ to get to the
bank is

$$ \text{E}\left(\text{jumps}\right) = \sum_{j = 1}^{p + 1} \frac{1}{j}.$$

The expected number of jumps if there are 10 pads between the frog and the
bank is

```{r }
PADS <- 10
sum(seq(1, PADS + 1, by = 1)^-1)
```


For 20 pads between the frog and the bank:

```{r }
PADS <- 20
sum(seq(1, PADS + 1, by = 1)^-1)
simulation(PADS)
```


For 30 pads between the frog and the bank:

```{r }
PADS <- 30
sum(seq(1, PADS + 1, by = 1)^-1)
simulation(PADS)
```


The simulations and the closed form soluion see to match up.

**Disclaimer** Part of the goal for this project was to avoid recursion in
the solution. The derivation of $\boldsymbol{J}$ could be considered
recursive. However, I would argue the final solution does not rely on
recursion.
Binary file added dewittpe-solution/frog_jump.pdf
Binary file not shown.
Binary file added dewittpe-solution/grass.pdf
Binary file not shown.
Binary file added dewittpe-solution/lilypad.pdf
Binary file not shown.
Loading