---
title: "Detailed Documentation"
author: "Konrad Kraemer"
output: html_document
# pdf_document
#classoption:
#  - twocolumn
# rmarkdown::html_vignette

vignette: >
  %\VignetteIndexEntry{Detailed Documentation}
  %\VignetteEngine{knitr::rmarkdown}
  \usepackage{UTF-8}
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE, eval = FALSE)
```

```{css echo=FALSE}
/* Define a margin before h2 element */
h2  {
  margin-top: 6em;
}

/* Define a margin after every first p elements */
p:first-of-type {
  margin-bottom: 3em;
}
```

* [Overview](#overview)
* [Function arguments](#function-arguments)
* [Variable declaration](#variable-declaration)
* [Derivatives](#derivatives)
* [Subsetting](#subsetting)
* [Printing](#printing)
* [Math functions](#math-functions)
* [Interpolation](#interpolation)

<style>
body {
text-align: justify}
</style>

### Overview

The *ast2ast* package translates R functions into C++ functions,
returning either an external pointer (XPtr) or an R function.
This package is particularly useful for tasks requiring frequent function evaluations,
such as solving ODE systems or optimization problems.
Using the external pointer generated by C++ can significantly enhance performance,
as shown in the benchmark below.

![Benchmark](benchmark.png)

Supported objects:

*  scalar values
*  vectors
*  matrices

Supported functions:

*  assignment: = and <-
*  allocation: vector, rep and matrix
*  information about objects: length and dim
*  Basic operations: +, -, *, /
*  Indices: [] and at
*  mathematical functions: sin, asin, sinh, cos, acos, cosh, tan, atan, tanh, log, ^ and exp
*  concatenate objects: c
*  control flow: for, if, else if, else
*  comparison: ==, !=, >, <, >= and <=
*  printing: print
*  returning objects: return
*  is.na and is.infinite can be used to test for NA and Inf.

### Function arguments

#### Types of arguments

You can define the argument types for the generated functions.
When generating an R function, you can use the following types:

* Types: *logical*, *integer*, *double*
* When creating an XPtr, additional types are available:
  *const logical*, *const integer*, *const double*

#### Data structurs of the arguments

* Data structures: *scalar*, *vector*
* In case a XPtr is created one can also use *borrow* as a data structure

#### Memory handling

* Borrowing memory from a vector allows the R object to be modified within the function.
  Be cautious, as this is contrary to typical R behavior.
  * This can be done by specifying *borrow*. If borrowing is not desired use *copy* instead.
* In case a XPtr is created one can only chose between *""* and *"borrow"* as 
  copying does not make sense here. Moreover, one can pass the arguments by reference 
  which is indicated by a logical input (TRUE means arguments passed by reference).


```{r, eval = FALSE}
f <- function(a, b, c, d, e, f) {
  print(a) # logical scalar
  print(b) # integer scalar
  print(c) # double  scalar
  print(d) # logical vector
  print(e) # integer vector
  print(f) # double  vector
}
library(ast2ast)
fcpp <- translate(f,
  types_of_args = c("logical", "int", "double", "logical", "int", "double"),
  data_structures = c("scalar", "scalar", "scalar", "vector", "vector", "vector"),
  handle_inputs = c("copy", "copy", "copy", "borrow", "borrow", "borrow"),
  verbose = FALSE
)

fcpp(TRUE, 1L, 1.5, c(TRUE, FALSE), c(1L, 2L), c(3.14, 3.14))
```

### Variable declaration

If you declare a variable in C++ the type is attached to it and cannot be changed anymore. 
The default type is a vector holding doubles. This vector can either be a matrix or a vector.
Whether it is a vector or a matrix can be changed within the function. \

Additionally, other types can be defined for a variable. This is possible by using *::* followed 
by a type during the definition of a variable. You can only do this once.
The possible type words are:

* logical
* integer
* double
* logical_vector
* integer_vector
* double_vector

```{r, eval = FALSE}
f <- function() {
  a::logical <- TRUE
  b::integer <- 1
  c::double <- 3.14
  d::logical_vector <- c(TRUE, FALSE)
  e::integer_vector <- c(1L, 2L, 3L)
  f::double_vector <- c(3.14, 3.5)
}
library(ast2ast)
fcpp <- translate(f)
```


### Derivatives

The first derivative from each variable with respect to another variable
can be calculated. Three requirements have to be met in order to enable this.

* the independent and the dependent variable have to be of data structure *vector* or *borrow*
* the underlying data type of the independent and dependent variable is of type *double*
* the variables which are part of expression from which derivatives should be calculated
  should have the data type *double*. 

In order to define the current independent variable one uses the function
*set_indep*. The function requires one argument and does not return anything.
Afterwards, one defines the function code. At the end one can get the derivative
by using the function *get_deriv*. If several independent variables should be 
used one has to use *unset_indep* to remove the old independent variable.


```{r, eval = FALSE}
f <- function(y, x) {
  jac <- matrix(0, length(y), length(x))
  for (i in 1:length(x)) {
    set_indep(x[i])
    y[1] <- (x[1]^2) * x[2]
    y[2] <- 5 * x[1] + sin(x[2])
    unset_indep(x[i])
    jac[, i] <- get_deriv(y)
  }
  return(jac)
}
```
### Subsetting

If you want to subset a vector or a matrix object you can use either *[]* or the *at* function.
The *[]* is slower than *at* but more powerful.

The following objects can be passed to *[]* when using a vector or matrix:


```{r, eval = FALSE}
f <- function() {
  print("pass nothing")
  a <- 1:8
  print(a)
  a[] <- 100
  print(a)
  print()

  print("pass logical")
  a <- 1:8
  print(a)
  a[TRUE] <- 100
  print(a)
  print()

  print("pass scalar")
  a <- 1:8
  print(a)
  a[1] <- 100
  print(a)
  print()


  print("pass vector")
  a <- 1:8
  b <- 2:5
  print(a)
  a[b] <- 100
  print(a)
  print()

  print("pass result of ==")
  a <- 1:8
  a[a < 5] <- 100
  print(a)
  print()


  print("pass result of !=")
  a <- 1:8
  b <- c(1, 2, 3, 0, 0, 0, 0, 8)
  a[a != b] <- 100
  print(a)
  print()


  print("pass result of <=")
  a <- 1:8
  b <- c(1, 2, 3, 0, 0, 0, 0, 8)
  a[a <= b] <- 100
  print(a)
  print()


  print("pass result of >=")
  a <- 1:8
  b <- c(1, 2, 3, 0, 0, 0, 0, 9)
  a[a >= b] <- 100
  print(a)
  print()


  print("pass result of >")
  a <- 1:8
  b <- c(0, 2, 3, 0, 0, 0, 0, 9)
  a[a > b] <- 100
  print(a)
  print()


  print("pass result of <")
  a <- 1:8
  b <- c(0, 2, 3, 0, 0, 0, 0, 9)
  a[a < b] <- 100
  print(a)
  print()


  print("pass scalar, scalar")
  a <- matrix(3, 4, 4)
  a[1, 1] <- 100
  print(a)
  print()


  print("pass vector, vector")
  a <- matrix(3, 4, 4)
  b <- c(1, 3)
  c <- c(2, 4)
  a[b, c] <- 100
  print(a)
  print()


  print("pass ==, >=")
  a <- matrix(1:16, 4, 4)
  b <- 1:4
  c <- c(1, 8, 3, 8)
  a[b == c, b >= c] <- 100
  print(a)
  print()


  print("at")
  a <- 1:16
  at(a, 2) <- 100
  print(a)
  print()


  print("at")
  a <- matrix(1:16, 4, 4)
  at(a, 1, 4) <- 100
  print(a)
  print()
}

library(ast2ast)
fetr <- translate(f)
fetr()
```

### Printing

Using the function print as common in R. 

* print() is different to R
* print("string")
* print(logical)
* print(scalar)
* print(vector) 
* print(matrix)

### Math functions

Following mathematical functions are available.

* sin
* asin
* sinh
* cos
* acos
* cosh
* tan
* atan
* tanh
* sqrt
* log
* ^ and exp

### Interpolation

To interpolate values, the 'cmr' function can be used. The function needs three arguments.

* the first argument is the point of the independent variable (x) for which the dependent variable should be calculated (y). This has to be a vector of length one.
* the second argument is a vector defining the points of the independent variable (x). This has to be a vector of at least length four.
* the third argument is a vector defining the points of the dependent variable (y). This has to be a vector of at least length four.

```{r, eval = FALSE}
f <- function() {
  dep <- c(0, 1, 0.5, 2.5, 3.5, 4.5, 4)
  indep <- 1:7
  evalpoints <- c(
    0.5, 1, 1.5, 2, 2.5,
    3, 3.5, 4, 4.5, 5,
    5.5, 6, 6.5
  )
  for (i in evalpoints) {
    print(cmr(i, indep, dep))
  }
}

```


