---
title: "Custom functions and DeclareDesign"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Custom functions and DeclareDesign}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r echo=FALSE, warning=FALSE, message=FALSE}
set.seed(42)
library(DeclareDesign)
options(digits=2)
```

The `declare_*` functions in **DeclareDesign** use functions in the **fabricatr**, **randomizr**, and **estimatr** packages as defaults, which work great for most designs. Sometimes, however, you might want to write your own function. This advanced vignette declares a design using only custom functions.

First, we'll write custom functions for each of the steps in the design. All functions must take a data.frame and return a data.frame, with the exception of a population step, whose inputs can be anything but whose output must be a data.frame.

```{r}
# M: Model
custom_population <- function(N) {
  data.frame(u = rnorm(N))
}
custom_potential_outcomes <-
  function(data) {
    within(data,{
      Y_Z_0 <- u
      Y_Z_1 <- 0.25 + u
    })
  }

# I: Inquiry
custom_inquiry <- function(data, label) {
  data.frame(inquiry = label,
  inquiry = with(data, median(Y_Z_1 - Y_Z_0)))
}

# D: Data Strategy
custom_sampling <- function(data) {
     data$S <- rbinom(n = nrow(data),
            size = 1,
            prob = 0.1)
     data[data$S == 1, ]
}

custom_assignment <- function(data) {
  data$Z <- rbinom(n = nrow(data),
         size = 1,
         prob = 0.5)
  data
}

custom_reveal <- function(data){
  within(data, Y <- Y_Z_1 * Z + Y_Z_0 * (1 - Z))
}

# A: Answer strategy
custom_estimator <- function(data){
  data.frame(estimate = with(data, mean(Y)))
}
```

In order to declare the design, we pass each of the custom functions to the `handler` argument of each declaration step:

```{r}
design <- 
  declare_model(handler = custom_population, N = 100) + 
  declare_potential_outcomes(handler = custom_potential_outcomes) + 
  declare_inquiry(handler = custom_inquiry, label = "medianTE") + 
  declare_sampling(handler = custom_sampling) + 
  declare_assignment(handler = custom_assignment) + 
  declare_reveal(handler = custom_reveal) + 
  declare_estimator(handler = tidy_estimator(custom_estimator), 
                    inquiry = "medianTE")
head(draw_data(design))
run_design(design)
```

This example used very simple custom functions, but this framework is flexible enough to accommodate any design step that can be expressed as a function of data that returns data.
