---
output: rmarkdown::html_vignette
title: Conditional Threading Optimizer
vignette: >
  %\VignetteIndexEntry{Conditional Threading Optimizer}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r echo=FALSE, message=FALSE}
library("rco")
library("microbenchmark")
library("ggplot2")
autoplot.microbenchmark <- function(obj) {
  levels(obj$expr) <- paste0("Expr_", seq_along(levels(obj$expr)))
  microbenchmark:::autoplot.microbenchmark(obj)
}
speed_up <- function(obj) {
  levels(obj$expr) <- paste0("Expr_", seq_along(levels(obj$expr)))
  obj <- as.data.frame(obj)
  summaries <- do.call(rbind, by(obj$time, obj$expr, summary))
  res <- c()
  for (i in seq_len(nrow(summaries) - 1) + 1) {
    res <- rbind(res, summaries[1, ] / summaries[i, ])
  }
  rownames(res) <- levels(obj$expr)[-1]
  return(res)
}
```

# Conditional Threading Optimizer

## Background

Conditional Threading is an optimization that searches for separate blocks of `IF` statements but with exactly the same conditions. When several conditionals present the same boolean condition, merging their inside actions would avoid computing the condition several times. Also, in the cases where a second `IF` statement has been used with the exact negation of the condition of the first `IF`, the second `IF` could then be incorporated in an `ELSE` statement.

## Example

Consider the following example:

```{r}
code <- paste(
  "n_evens <- 0",
  "n_odds <- 0",
  "odds_sum <- 0",
  "evens_sum <- 0",
  "",
  "for (i in sample(10000, replace = TRUE)) {",
  "  if (i %% 2 == 1) {",
  "    n_odds <- n_odds + 1",
  "  }",
  "  if (i %% 2 == 1) {",
  "    odds_sum <- odds_sum + i",
  "  }",
  "  if (!(i %% 2 == 1)) {",
  "    n_evens <- n_evens + 1",
  "  }",
  "  if (!(i %% 2 == 1)) {",
  "    evens_sum <- evens_sum + i",
  "  }",
  "}",
  sep = "\n"
)
cat(code)
```

Then, the automatically optimized code would be:

```{r}
opt_code <- opt_cond_thread(list(code))
cat(opt_code$codes[[1]])
```

And if we measure the execution time of each one, and the speed-up:

```{r message=FALSE}
bmark_res <- microbenchmark({
  eval(parse(text = code))
}, {
  eval(parse(text = opt_code))
})
autoplot(bmark_res)
speed_up(bmark_res)
```

## Implementation

The `opt-cond-thread` optimizer simply looks for `IF` statements in the code snippet given as the input and if it finds an `IF` statement, it checks the immediate next block of code. If it is another `IF` statement, the optimizer merges the two `IF` blocks if the `IF` conditions were same or converts the second `IF` statement to `ELSE` if the conditions were negation of each other.
