---
title: "Identification-through-group-testing"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Identification-through-group-testing}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  prompt = TRUE, 
  comment = NA, 
  background = "white", 
  tidy = TRUE,
  tidy.opts = list(width.cutoff = 65, blank = TRUE),
  collapse = TRUE,
  comment = "#>"
)

options(continue = " ") # Removes a "+" from a line of code that continues on to the next line
```

```{r setup}
library(binGroup2)
```

We provide a few examples here showing how to use `binGroup2` for the identification aspect of group testing. More in-depth examples are available in Bilder et al. (2023), which has been tentatively accepted by the *R Journal* at the time of writing this vignette. For further information on group testing, please see [www.chrisbilder.com/grouptesting](https://www.chrisbilder.com/grouptesting/). This website also includes the most recent version of Bilder et al. (2023).

## Operating characteristics

```{r groupmem, echo=FALSE}
GroupMembershipMatrix <- function(stage1, stage2 = NULL,
                                  stage3 = NULL, stage4 = NULL) {

  # Check group sizes
  if (!is.null(stage2)) {
    if (sum(stage2) != stage1) {
      stop("The number of individuals in stage 2 is not the same as in stage 1.\n")
    }

    if (is.null(stage1)) {
      stop("Please provide an initial group size for stage 1 of testing.\n")
    }
  }

  if (!is.null(stage3)) {
    if (sum(stage3) != stage1) {
      stop("The number of individuals in stage 3 is not the same as in stage 1.\n")
    }

    if (is.null(stage1)) {
      stop("Please provide an initial group size for stage 1 of testing.\n")
    }

    if (is.null(stage2)) {
      stop("No group sizes were provided for stage 2 of testing. A group membership matrix will be constructed for a two-stage hierarchical algorithm.\n")
    }
  }

  if (!is.null(stage4)) {
    if (sum(stage4) != stage1) {
      stop("The number of individuals in stage 3 is not the same as in stage 1.\n")
    }

    if (is.null(stage1)) {
      stop("Please provide an initial group size for stage 1 of testing.\n")
    }

    if (is.null(stage2)) {
      stop("No group sizes were provided for stage 2 of testing. A group membership matrix will be constructed for a two-stage hierarchical algorithm.\n")
    }

    if (is.null(stage3)) {
      stop("No group sizes were provided for stage 3 of testing. A group membership matrix will be constructed for a three-stage hierarchical algorithm.\n")
    }

  }

  # Create group membership matrix for two-stage hierarchical testing
  if (is.null(stage2)) {
    # Set row1
    row1 <- rep(x = 1, time = stage1)

    # Set row2
    row2 <- 1:stage1

    # Set hier.config
    hier.config <- matrix(data = c(row1, row2), nrow = 2, byrow = TRUE)
    }

  # Create group membership matrix for three-stage hierarchical testing
  else if (is.null(stage3)) {
    # Set row1
    row1 <- rep(x = 1, time = stage1)

    # Set row2
    row2 <- NULL # Initiate row2
    for (i in 1:length(stage2)) {
      row2 <- c(row2, rep(x = i, time = stage2[i]))
      }

    # Set row3
    row3 <- 1:stage1

    # Set hier.config
    hier.config <- matrix(data = c(row1, row2, row3), nrow = 3, byrow = TRUE)
    }

  # Create group membership matrix for four-stage hierarchical testing
  else if (is.null(stage4)) {
    # Set row1
    row1 <- rep(x = 1, time = stage1)

    # Set row2
    row2 <- NULL # Initiate row2
    for (i in 1:length(stage2)) {
      row2 <- c(row2, rep(x = i, time = stage2[i]))
      }

    # Set row3
    row3 <- NULL # Initiate row3
    for (i in 1:length(stage3)) {
      row3 <- c(row3, rep(x = i, time = stage3[i]))
      }

    # Set row4
    row4 <- 1:stage1

    # Set hier.config
    hier.config <- matrix(data = c(row1, row2, row3, row4),
                          nrow = 4, byrow = TRUE)
    }

  else {
    # Set row1
    row1 <- rep(x = 1, time = stage1)

    # Set row2
    row2 <- NULL # Initiate row2
    for (i in 1:length(stage2)) {
      row2 <- c(row2, rep(x = i, time = stage2[i]))
      }

    # Set row3
    row3 <- NULL # Initiate row3
    for (i in 1:length(stage3)) {
      row3 <- c(row3, rep(x = i, time = stage3[i]))
      }

    # Set row4
    row4 <- NULL # Initiate row3
    for (i in 1:length(stage4)) {
      row4 <- c(row4, rep(x = i, time = stage4[i]))
      }

    # Set row5
    row5 <- 1:stage1

    # Set hier.config
    hier.config <- matrix(data = c(row1, row2, row3, row4, row5),
                          nrow = 5, byrow = TRUE)
    }

  hier.config
}
```

The `opChar1()` and `opChar2()` functions compute operating characteristics, such as the expected number of tests, for a group testing algorithm. Below is an example of how `opChar1()` can be used for two-stage hierarchical testing (also known as Dorfman testing) with a one-infection assay. In this example, we use an overall prevalence of 0.01, a sensitivity and specificity of 0.99 at each stage, and an initial group size of 10.

```{r}
# Group membership matrix
group.member <- GroupMembershipMatrix(stage1 = 10)
group.member

# Compute operating characteristics for a one-infection assay
save1 <- opChar1(algorithm = "D2", p = 0.01, Se = 0.99, Sp = 0.99, 
                 hier.config = group.member, print.time = FALSE)
names(save1)
summary(save1)
ExpTests(save1)
```

The group membership matrix shows that each individual is tested in group 1 for the first stage. If this group tests positive, each individual is tested separately in the second stage. The `opChar1()` function returns its calculations in a list object that is then summarized by `summary()`. For example, the expected number of tests is 2.04 for this group. Additional functions, like `ExpTests()`, can access the information available in objects created by `opChar1()` as well.

The `opChar2()` function performs very similar calculations but for two-infection assays. Below is an example using two-stage hierarchical testing again. Because there are two infections, a vector of joint probabilities is specified in the form $(p_{--},p_{+-},p_{-+},p_{++})$, where $p_{ab}$ is the probability of being positive/negative $(+/-)$ for infections $a$ and $b$. We continue using a sensitivity and specificity of 0.99 at each stage and an initial group size of 10.

```{r}
# Compute operating characteristics for a two-infection assay
save2 <- opChar2(algorithm = "D2", p.vec = c(0.95, 0.02, 0.02, 0.01), 
                 Se = c(0.99, 0.99), Sp = c(0.99, 0.99), 
                 hier.config = group.member, print.time = FALSE)
names(save2)
summary(save2)
ExpTests(save2)
```

The expected number of tests is 5.10 for this testing configuration.

## Optimal testing configuration

The `OTC1()` and `OTC2()` functions find the optimal testing configuration for a group testing algorithm. Below is an example of how `OTC1()` can be used for two-stage hierarchical testing with a one-infection assay. In this example, we again use an overall prevalence of 0.01 and a sensitivity and specificity of 0.99 at each stage. The OTC is searched for over group sizes of 3 to 20.

```{r}
# Find OTC for a one-infection assay
save3 <- OTC1(algorithm = "D2", p = 0.01, Se = 0.99, Sp = 0.99, 
              group.sz = 3:20, obj.fn = "ET", print.time = FALSE)
names(save3)
summary(save3)
Config(save3)
```

The OTC has a group size of 11 with an expected number of tests per individual of 0.2035. This testing configuration is slightly more efficient than using a group size of 10 as specified in our previous example. This can be seen by comparing the `summary()` outputs or from the `Config()` function results which accesses information stored in `save3`.

The `OTC2()` function works in much the same way as `OTC1()` with the main difference being the specification of joint probabilities rather a single-infection prevalence. In the example below, we search for the OTC over group sizes of 3 to 20 when using a two-stage hierarchical testing algorithm.

```{r}
# Find OTC for a two-infection assay
save4 <- OTC2(algorithm = "D2", p.vec = c(0.95, 0.02, 0.02, 0.01), 
              Se = c(0.99, 0.99), Sp = c(0.99, 0.99), 
              group.sz = 3:20, obj.fn = "ET", print.time = FALSE)
names(save4)
summary(save4)
Config(save4)
```

The OTC has a group size of 5 with an expected number of tests per individual of 0.4399. To determine how much more efficient the OTC is in comparison to our previous two-infection example's use of a group size of 10, we use the `CompareConfig()` function.

```{r}
# Compare testing configurations
group.member.OTC <- GroupMembershipMatrix(stage1 = 5)
save5 <- opChar2(algorithm = "D2", p.vec = c(0.95, 0.02, 0.02, 0.01), 
                 Se = c(0.99, 0.99), Sp = c(0.99, 0.99), 
                 hier.config = group.member.OTC, print.time = FALSE)
CompareConfig(save2, save5)
```

The OTC is 13.81% more efficient than using a group size of 10.

This vignette focuses on a two-stage hierarchical testing algorithm in a homogeneous population. Many other group testing algorithms are available! We provide a large number of examples within the help for the package to illustrate these other algorithms. Our Bilder et al. (2023) paper also provides many examples. In particular, the appendix of the paper provides more advanced uses of functions in the package.
