├── .Rbuildignore ├── .github └── workflows │ └── ci.yaml ├── .gitignore ├── ChangeLog ├── DESCRIPTION ├── NAMESPACE ├── R └── RcppExports.R ├── README.md ├── cleanup ├── inst ├── NEWS.Rd ├── include │ ├── fastad │ └── fastad_bits │ │ ├── forward.hpp │ │ ├── forward │ │ ├── core.hpp │ │ └── core │ │ │ ├── dualnum.hpp │ │ │ └── forward.hpp │ │ ├── reverse.hpp │ │ ├── reverse │ │ ├── core.hpp │ │ ├── core │ │ │ ├── binary.hpp │ │ │ ├── bind.hpp │ │ │ ├── constant.hpp │ │ │ ├── det.hpp │ │ │ ├── dot.hpp │ │ │ ├── eq.hpp │ │ │ ├── eval.hpp │ │ │ ├── expr_base.hpp │ │ │ ├── for_each.hpp │ │ │ ├── glue.hpp │ │ │ ├── hessian.hpp │ │ │ ├── if_else.hpp │ │ │ ├── log_det.hpp │ │ │ ├── norm.hpp │ │ │ ├── pow.hpp │ │ │ ├── prod.hpp │ │ │ ├── sum.hpp │ │ │ ├── transpose.hpp │ │ │ ├── unary.hpp │ │ │ ├── value_adj_view.hpp │ │ │ ├── value_view.hpp │ │ │ ├── var.hpp │ │ │ └── var_view.hpp │ │ ├── stat.hpp │ │ └── stat │ │ │ ├── bernoulli.hpp │ │ │ ├── cauchy.hpp │ │ │ ├── normal.hpp │ │ │ ├── uniform.hpp │ │ │ └── wishart.hpp │ │ └── util │ │ ├── numeric.hpp │ │ ├── ptr_pack.hpp │ │ ├── shape_traits.hpp │ │ ├── size_pack.hpp │ │ ├── type_traits.hpp │ │ └── value.hpp └── tinytest │ ├── test_black_scholes.R │ ├── test_linear_regression.R │ └── test_quadratic_expression.R ├── man ├── RcppFastAD-package.Rd ├── black_scholes.Rd ├── linear_regression.Rd └── quadratic_expression.Rd ├── src ├── Makevars ├── Makevars.win ├── RcppExports.cpp ├── black_scholes.cpp ├── linear_regression.cpp └── quadratic_expression.cpp └── tests └── tinytest.R /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.git$ 2 | ^.*\.Rproj$ 3 | ^\.Rproj\.user$ 4 | ^.github$ 5 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | # Run CI for R using https://eddelbuettel.github.io/r-ci/ 2 | 3 | name: ci 4 | 5 | on: 6 | push: 7 | pull_request: 8 | 9 | env: 10 | _R_CHECK_FORCE_SUGGESTS_: "false" 11 | 12 | jobs: 13 | ci: 14 | strategy: 15 | matrix: 16 | include: 17 | #- {os: macOS-latest} 18 | - {os: ubuntu-latest} 19 | 20 | runs-on: ${{ matrix.os }} 21 | 22 | steps: 23 | - name: Checkout 24 | uses: actions/checkout@v4 25 | 26 | - name: Setup 27 | uses: eddelbuettel/github-actions/r-ci@master 28 | 29 | - name: Dependencies 30 | run: ./run.sh install_deps 31 | 32 | - name: Test 33 | run: ./run.sh run_tests 34 | 35 | #- name: Coverage 36 | # if: ${{ matrix.os == 'ubuntu-latest' }} 37 | # run: ./run.sh coverage 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Retrieved 2017-Oct-12 from https://github.com/github/gitignore/blob/master/R.gitignore 2 | # Licensed under CC0-1.0 https://github.com/github/gitignore/blob/master/LICENSE 3 | 4 | # History files 5 | .Rhistory 6 | .Rapp.history 7 | 8 | # Session Data files 9 | .RData 10 | 11 | # Example code in package build process 12 | *-Ex.R 13 | 14 | # Output files from R CMD build 15 | /*.tar.gz 16 | 17 | # Output files from R CMD check 18 | /*.Rcheck/ 19 | 20 | # RStudio files 21 | .Rproj.user/ 22 | 23 | # produced vignettes 24 | vignettes/*.html 25 | vignettes/*.pdf 26 | 27 | # OAuth2 token, see https://github.com/hadley/httr/releases/tag/v0.3 28 | .httr-oauth 29 | 30 | # knitr and R markdown default cache directories 31 | /*_cache/ 32 | /cache/ 33 | 34 | # Temporary files created by R markdown 35 | *.utf8.md 36 | *.knit.md 37 | 38 | # Binaries 39 | *.o 40 | *.so 41 | 42 | # Emacs 43 | *~ -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 2025-04-04 Dirk Eddelbuettel 2 | 3 | * .github/workflows/ci.yaml: Switch to r-ci with included bootstrap 4 | 5 | 2024-09-24 Dirk Eddelbuettel 6 | 7 | * DESCRIPTION (Version, Date): Release 0.0.4 8 | 9 | 2024-09-16 Dirk Eddelbuettel 10 | 11 | * DESCRIPTION (Version, Date): Roll micro version 12 | 13 | 2024-09-16 James Yang 14 | 15 | * inst/include/fastad_bits/forward/core/forward.hpp: Properly address 16 | clang warning on empty variadic macros arguments 17 | 18 | * src/Makevars (CXX_STD): Switch back to C++17 19 | * src/Makevars.win (CXX_STD): Idem 20 | 21 | 2024-09-15 Dirk Eddelbuettel 22 | 23 | * DESCRIPTION (Version, Date): Release 0.0.3 24 | 25 | * src/Makevars (CXX_STD): Use C++20 26 | * src/Makevars.win (CXX_STD): Idem 27 | 28 | 2024-05-22 Dirk Eddelbuettel 29 | 30 | * README.md: Use tinyverse.netlify.app for dependency badge 31 | 32 | 2024-03-04 Dirk Eddelbuettel 33 | 34 | * .github/workflows/ci.yaml (jobs): Update to actions/checkout@v4, 35 | add r-ci-setup actions 36 | 37 | 2023-03-05 Dirk Eddelbuettel 38 | 39 | * DESCRIPTION (Version, Date): Release 0.0.2 40 | 41 | 2023-03-03 James Yang 42 | 43 | * src/linear_regression.cpp (linear_regression): Further 44 | simplification 45 | * src/quadratic_expression.cpp (quadratic_expression): Idem 46 | 47 | 2023-03-03 Dirk Eddelbuettel 48 | 49 | * src/linear_regression.cpp (linear_regression): Return theta 50 | and gradient as vectors instead of (oversized) matrices 51 | * src/quadratic_expression.cpp (quadratic_expression): Return 52 | scalar and vector instead of two (oversized) matrices 53 | * inst/tinytest/test_quadratic_expression.R: Adjusted 54 | 55 | 2023-03-02 Dirk Eddelbuettel 56 | 57 | * inst/tinytest/test_black_scholes.R: Renamed 58 | * inst/quadratic_expression.R: New tests 59 | * inst/linear_regression.R: New tests 60 | 61 | 2023-03-01 Dirk Eddelbuettel 62 | 63 | * inst/include/fastad_bits/reverse/core/value_view.hpp: Protect 64 | one expression from nullptr 65 | 66 | 2023-02-28 Dirk Eddelbuettel 67 | 68 | * DESCRIPTION (URL, BugReports): Added 69 | 70 | 2023-02-27 Dirk Eddelbuettel 71 | 72 | * README.md: Additional badges 73 | 74 | 2023-02-25 Dirk Eddelbuettel 75 | 76 | * DESCRIPTION (Version, Date): Release 0.0.1 77 | 78 | 2023-02-24 Dirk Eddelbuettel 79 | 80 | * inst/NEWS.Rd: Added 81 | 82 | * src/linear_regression.cpp: Add example using data(trees) 83 | * man/linear_regression.Rd: Idem 84 | 85 | 2023-02-24 James Yang 86 | 87 | * src/linear_regression.cpp (linear_regression): Use gradient descent 88 | together with squared loss to fit model 89 | * man/linear_regression.Rd: Updated 90 | 91 | 2023-02-23 Dirk Eddelbuettel 92 | 93 | * README.md: Added 94 | * .github/workflows/ci.yaml (jobs): Turn on CI 95 | * .Rbuildignore: Add .github 96 | * DESCRIPTION: Tweaks and edits 97 | * NAMESPACE: Idem 98 | 99 | * src/linear_regression.cpp (linear_regression): Much more compact 100 | code (as suggested by James in #1) 101 | * src/quadratic_expression.cpp (quadratic_expression): Use a view for 102 | the sigma matrix (as suggested by James in #2) 103 | 104 | 2023-02-22 Dirk Eddelbuettel 105 | 106 | * src/linear_regression.cpp (linear_regression): Example of 107 | evaluating a linear regression at a given parameter estimate 108 | * man/linear_regression.Rd: Idem 109 | * src/RcppExport.cpp: Idem 110 | * R/RcppExports.R: Idem 111 | 112 | * inst/tinytest/test_RcppFastAD.R: Add minimal tests 113 | 114 | 2023-02-19 Dirk Eddelbuettel 115 | 116 | * src/black_scholes.cpp (black_scholes): Also provide rho and theta 117 | 118 | 2023-02-18 Dirk Eddelbuettel 119 | 120 | * src/quadratic_expression.cpp (quadratic_expression): New example 121 | for evaluating X' * Sigma * X and returning gradient of X 122 | * man/quadratic_expression.Rd: Idem 123 | * src/RcppExport.cpp: Idem 124 | * R/RcppExports.R: Idem 125 | 126 | 2023-02-17 Dirk Eddelbuettel 127 | 128 | * src/black_scholes.cpp (black_scholes): Renamed function and file, 129 | extended to take argument, and return a result matrix 130 | * man/black_scholes.Rd: Idem 131 | * src/RcppExport.cpp: Idem 132 | * R/RcppExports.R: Idem 133 | 134 | 2023-02-16 Dirk Eddelbuettel 135 | 136 | * src/black_scholes_example.cpp (black_scholes_example): Also compute 137 | vega via automatic differentiation 138 | 139 | * src/Makevars (CXX_STD): Set CXX_STD to CXX17 140 | * src/Makevars.win (CXX_STD): Idem 141 | 142 | 2023-02-15 Dirk Eddelbuettel 143 | 144 | * inst/include/: Include FastAD version 3.1.0 145 | 146 | * src/black_scholes_example.cpp: Add based on FastAD example 147 | * man/black_scholes_example.Rd: Generated 148 | 149 | * DESCRIPTION: Generated via kitten() as RcppEigen package 150 | * NAMESPACE: Idem 151 | * src/RcppExport.cpp: Idem 152 | * src/Makevars: Idem 153 | * src/Makevars.win: Idem 154 | * R/RcppExports.R: Idem 155 | * man/RcppFastAD-package.Rd: Idem 156 | * test/tinytest.R: Idem 157 | * inst/tinytest/test_RcppFastAD.R: Idem 158 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: RcppFastAD 2 | Type: Package 3 | Title: 'Rcpp' Bindings to 'FastAD' Auto-Differentiation 4 | Version: 0.0.4 5 | Date: 2024-09-24 6 | Authors@R: c(person(given = "Dirk", family = "Eddelbuettel", 7 | role = c("aut", "cre"), email = "edd@debian.org", 8 | comment = c(ORCID = "0000-0001-6419-907X")), 9 | person(given = "James", family = "Yang", 10 | role = "aut", email = "jamesyang916@gmail.com", 11 | comment = c(ORCID = "0000-0002-0015-7812"))) 12 | Description: The header-only 'C++' template library 'FastAD' for automatic 13 | differentiation is provided by 14 | this package, along with a few illustrative examples that can all be called 15 | from R. 16 | URL: https://github.com/eddelbuettel/rcppfastad 17 | BugReports: https://github.com/eddelbuettel/rcppfastad/issues 18 | License: GPL (>= 2) 19 | Suggests: tinytest 20 | Encoding: UTF-8 21 | RoxygenNote: 6.0.1 22 | Imports: Rcpp 23 | LinkingTo: Rcpp, RcppEigen 24 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | useDynLib(RcppFastAD) 2 | importFrom(Rcpp, evalCpp) 3 | ## export all regularly named functions 4 | ## (but allow for private functions whose name starts with a dot).name <- function(...) 5 | exportPattern("^[[:alpha:]]+") 6 | -------------------------------------------------------------------------------- /R/RcppExports.R: -------------------------------------------------------------------------------- 1 | # Generated by using Rcpp::compileAttributes() -> do not edit by hand 2 | # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 3 | 4 | #' Black-Scholes valuation and first derivatives via Automatic Differentiation 5 | #' 6 | #' This example illustrate how to use automatic differentiation to 7 | #' calculate the delte of a Black-Scholes call and put. It is based 8 | #' on the same example in the FastAD sources. 9 | #' @param spot A double with the spot price, default is 105 as in Boost example 10 | #' @param strike A double with the strike price, default is 100 as in Boost example 11 | #' @param vol A double with the (annualized) volatility (in percent), default is 5 12 | #' (for 500 per cent) as in Boost example 13 | #' @param r A double with the short-term risk-free rate, default is 0.0125 as in Boost example 14 | #' @param tau A double with the time to expiration (in fractional years), default is 30/365 15 | #' as in Boost example 16 | #' @return A matrix with rows for the call and put variant, and columns 17 | #' for option value, delta and vega 18 | #' @examples 19 | #' black_scholes() 20 | black_scholes <- function(spot = 105, strike = 100, vol = 5, r = 1.25 / 100, tau = 30.0 / 365) { 21 | .Call('_RcppFastAD_black_scholes', PACKAGE = 'RcppFastAD', spot, strike, vol, r, tau) 22 | } 23 | 24 | #' Evaluate a squared-loss linear regression at a given parameter value 25 | #' 26 | #' Not that this function does not actually fit the model. Rather it evaluates 27 | #' the squared sum of residuals and \sQuote{gradient} of parameters. 28 | #' 29 | #' @param X Matrix with independent explanatory variables 30 | #' @param y Vector with dependent variable 31 | #' @param theta_hat Vector with initial \sQuote{guess} of parameter values 32 | #' @param initial_lr [Optional] Scalar with initial step-size value, 33 | #' default is 1e-4 34 | #' @param max_iter [Optional] Scalar with maximum number of iterations, 35 | #' default is 100 36 | #' @param tol [Optional] Scalar with convergence tolerance, default is 1e-7 37 | #' @return A list object with the \sQuote{loss}, \sQuote{theta} (parameters), 38 | #' \sQuote{gradient} and \sQuote{iter} for iterations 39 | #' @examples 40 | #' data(trees) # also used in help(lm) 41 | #' X <- as.matrix(cbind(const=1, trees[, c("Girth", "Height")])) 42 | #' y <- trees$Volume 43 | #' linear_regression(X, y, rep(0, 3), tol=1e-12) 44 | #' coef(lm(y ~ X - 1)) # for comparison 45 | linear_regression <- function(X, y, theta_hat, initial_lr = 1e-4, max_iter = 100L, tol = 1e-7) { 46 | .Call('_RcppFastAD_linear_regression', PACKAGE = 'RcppFastAD', X, y, theta_hat, initial_lr, max_iter, tol) 47 | } 48 | 49 | #' Compute the value and derivate of a quadratic expression X' * Sigma * X 50 | #' 51 | #' @param X A 2 element vector 52 | #' @param Sigma A 2 x 2 matrix 53 | #' @return A list with two elements for the expression evaluated for X and Sigma as well as 54 | #' @examples 55 | #' X <- c(0.5, 0.6) 56 | #' S <- matrix(c(2, 3, 3, 6), 2, 2) 57 | #' quadratic_expression(X, S) 58 | quadratic_expression <- function(X, Sigma) { 59 | .Call('_RcppFastAD_quadratic_expression', PACKAGE = 'RcppFastAD', X, Sigma) 60 | } 61 | 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ## RcppFastAD: Rcpp Bindings for the FastAD C++ Header-Only Library 3 | 4 | [![CI](https://github.com/eddelbuettel/rcppfastad/workflows/ci/badge.svg)](https://github.com/eddelbuettel/rcppfastad/actions?query=workflow%3Aci) 5 | [![License](https://eddelbuettel.github.io/badges/GPL2+.svg)](https://www.gnu.org/licenses/gpl-2.0.html) 6 | [![CRAN](https://www.r-pkg.org/badges/version/RcppFastAD)](https://cran.r-project.org/package=RcppFastAD) 7 | [![Dependencies](https://tinyverse.netlify.app/badge/RcppFastAD)](https://cran.r-project.org/package=RcppFastAD) 8 | [![Last Commit](https://img.shields.io/github/last-commit/eddelbuettel/rcppfastad)](https://github.com/eddelbuettel/rcppfastad) 9 | 10 | ### Motivation 11 | 12 | [FastAD](https://github.com/JamesYang007/FastAD) is a header-only C++ template library for automatic differentiation 13 | supporting both forward and reverse mode. It utilizes the latest features in C++17 and expression templates for 14 | efficient computation. See the [FastAD](https://github.com/JamesYang007/FastAD) repo for more. 15 | 16 | This package brings this header-only library to R so that other R user can access it simply by 17 | adding `LinkingTo: RcppFastAD`. 18 | 19 | ### Example 20 | 21 | Three examples, taken from FastAD, are included. We can look at the `black_scholes()` one here: 22 | 23 | ```r 24 | > library(RcppFastAD) 25 | > black_scholes() 26 | value delta vega rho theta 27 | call 56.5136 0.773818 9.05493 2.03321 275.730 28 | put 51.4109 -0.226182 9.05493 -6.17753 274.481 29 | > 30 | ``` 31 | 32 | This evaluates a put and a call struck at 100 with spot at 105, and some default values (all taken from [an example 33 | included with Boost](https://www.boost.org/doc/libs/master/libs/math/doc/html/math_toolkit/autodiff.html#math_toolkit.autodiff.example-black_scholes)). 34 | The values can be set in the call too. Returned all the value along the first partial derivatives relative to spot, 35 | volatility, short rate and time to maturity---which are all calculated using automatic differentiation. 36 | 37 | (FastAD has a focus on speed leading to some design choices that make taking _second_ derivatives harder. So no 'gamma' here.) 38 | 39 | ### Status 40 | 41 | The package is complete and contains a mature version of FastAD. 42 | 43 | ### Contributing 44 | 45 | Any problems, bug reports, or features requests for the package can be submitted and handled most 46 | conveniently as [Github issues](https://github.com/eddelbuettel/rcppfastAD/issues) in the 47 | repository. 48 | 49 | Before submitting pull requests, it is frequently preferable to first discuss need and scope in such 50 | an issue ticket. See the file 51 | [Contributing.md](https://github.com/RcppCore/Rcpp/blob/master/Contributing.md) (in the 52 | [Rcpp](https://github.com/RcppCore/Rcpp) repo) for a brief discussion. 53 | 54 | ### Authors 55 | 56 | For the R package, [Dirk Eddelbuettel](https://github.com/eddelbuettel). 57 | 58 | For everything pertaining to FastAD: [James Yang](https://github.com/JamesYang007). 59 | 60 | -------------------------------------------------------------------------------- /cleanup: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | rm -f src/*.o src/*.so *~ */*~ 4 | -------------------------------------------------------------------------------- /inst/NEWS.Rd: -------------------------------------------------------------------------------- 1 | \name{NEWS} 2 | \title{News for Package \pkg{RcppFastAD}} 3 | \newcommand{\ghpr}{\href{https://github.com/eddelbuettel/rcppfastad/pull/#1}{##1}} 4 | \newcommand{\ghit}{\href{https://github.com/eddelbuettel/rcppfastad/issues/#1}{##1}} 5 | 6 | \section{Changes in version 0.0.4 (2024-09-24)}{ 7 | \itemize{ 8 | \item The package now properly addresses a clang warning on empty 9 | variadic macros arguments and is back to C++17 (James in \ghpr{10}) 10 | } 11 | } 12 | 13 | \section{Changes in version 0.0.3 (2024-09-15)}{ 14 | \itemize{ 15 | \item The package now compiles under the C++20 standard to avoid a warning 16 | under \code{clang++-18} (Dirk addressing \ghit{9}) 17 | \item Minor updates to continuous integration and badges have been made 18 | as well 19 | } 20 | } 21 | 22 | \section{Changes in version 0.0.2 (2023-03-05)}{ 23 | \itemize{ 24 | \item One C++ operation is protected from operating on a 25 | \code{nullptr} 26 | \item Additional tests have been added, tests now cover all three 27 | demo / example functions 28 | \item Return values and code for the examples 29 | \code{linear_regression} and \code{quadratic_expression} have been 30 | adjusted 31 | } 32 | } 33 | 34 | \section{Changes in version 0.0.1 (2023-02-24)}{ 35 | \itemize{ 36 | \item Initial release version and CRAN upload 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /inst/include/fastad: -------------------------------------------------------------------------------- 1 | // Export header file 2 | #pragma once 3 | #include "fastad_bits/forward.hpp" 4 | #include "fastad_bits/reverse.hpp" 5 | -------------------------------------------------------------------------------- /inst/include/fastad_bits/forward.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "forward/core.hpp" 3 | -------------------------------------------------------------------------------- /inst/include/fastad_bits/forward/core.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "core/dualnum.hpp" 3 | #include "core/forward.hpp" 4 | -------------------------------------------------------------------------------- /inst/include/fastad_bits/forward/core/dualnum.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace ad { 4 | namespace core { 5 | 6 | // Underlying data structure containing value and adjoint. 7 | // Represent value as "w" and adjoint as "df". 8 | // @tparam T underlying data type (ex. double) 9 | template 10 | struct DualNum 11 | { 12 | using value_type = T; 13 | 14 | DualNum(T w, T df) 15 | : w_(w), df_(df) 16 | {} 17 | 18 | value_type& get_value() 19 | { 20 | return w_; 21 | } 22 | 23 | const value_type& get_value() const 24 | { 25 | return w_; 26 | } 27 | 28 | value_type& set_value(value_type x) 29 | { 30 | return w_ = x; 31 | } 32 | 33 | value_type& get_adjoint() 34 | { 35 | return df_; 36 | } 37 | 38 | const value_type& get_adjoint() const 39 | { 40 | return df_; 41 | } 42 | 43 | value_type& set_adjoint(value_type x) 44 | { 45 | return df_ = x; 46 | } 47 | 48 | private: 49 | T w_; 50 | T df_; 51 | }; 52 | 53 | } // namepsace core 54 | } // namespace ad 55 | -------------------------------------------------------------------------------- /inst/include/fastad_bits/forward/core/forward.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | // Forward-mode Automatic Differentiation 6 | 7 | // Unary function definition with function name "f" that operates on ADForward variable x. 8 | // "first" represents code that computes the unary function on x value. 9 | // "second" represents code that computes the directional derivative of unary function on x value. 10 | // The variadic arguments are optional and represent code to be placed before executing 11 | // "first" and "second" for optimization purposes. 12 | // @tparam T underlying data type for x. 13 | // @param x variable to apply unary function to 14 | // @return a new ADForward with value and adjoint as the mathematical values for f(x), f'(x) * x'. 15 | // 16 | // Example generation with no variadic arguments: 17 | // 18 | // FORWARD_UNARY_FUNC(sin, std::sin(x.get_value()), std::cos(x.get_value()) * x.get_adjoint()) 19 | // => 20 | // template 21 | // inline auto sin(const ad::core::ADForward& x) 22 | // { 23 | // return ad::core::ADForward(std::sin(x.get_value()), std::cos(x.get_value()) * x.get_adjoint()); 24 | // } 25 | // 26 | // Example generation with variadic arguments: 27 | // 28 | // FORWARD_UNARY_FUNC(exp, tmp, tmp * x.get_adjoint(), auto tmp = std::exp(x.get_value());) 29 | // => 30 | // template 31 | // inline auto exp(const ad::core::ADForward& x) 32 | // { 33 | // auto tmp = std::exp(x.get_value()); 34 | // return ad::core::ADForward(tmp, tmp * x.get_adjoint()); 35 | // } 36 | // 37 | // Note that we only compute std::exp(x.get_value()) once and reuse to compute both "first" and "second". 38 | #define FORWARD_UNARY_FUNC(f, first, second) \ 39 | template \ 40 | inline auto f(const ad::core::ADForward& x) \ 41 | { \ 42 | return ad::core::ADForward(first, second); \ 43 | } \ 44 | 45 | #define FORWARD_UNARY_FUNC_PRE(f, first, second, ...) \ 46 | template \ 47 | inline auto f(const ad::core::ADForward& x) \ 48 | { \ 49 | __VA_ARGS__ \ 50 | return ad::core::ADForward(first, second); \ 51 | } \ 52 | 53 | // Binary function definition with function name "f" that operates on ADForward variables x, y. 54 | // "first" represents code that computes the binary function on x, y values. 55 | // "second" represents code that computes the directional derivative of binary function on x, y values 56 | // in the direction of (x.get_adjoint(), y.get_adjoint()). 57 | // The variadic arguments are optional and represent code to be placed before executing 58 | // "first" and "second" for optimization purposes. 59 | // @tparam T underlying data type for x. 60 | // @param x one of the variables to apply binary function to 61 | // @param y other variable to apply binary function to 62 | // @return a new ADForward with value and adjoint as the mathematical values for f(x, y), f'(x, y) * (x', y'). 63 | // 64 | // Example generation with no variadic arguments: 65 | // 66 | // FORWARD_BINARY_FUNC(operator+, x.get_value() + y.get_value(), x.get_adjoint() + y.get_adjoint()) 67 | // => 68 | // template 69 | // inline auto operator+(const ad::core::ADForward& x, ad::core::ADForward& y) 70 | // { 71 | // return ad::core::ADForward(x.get_value() + y.get_value(), x.get_adjoint() + y.get_adjoint()); 72 | // } 73 | #define FORWARD_BINARY_FUNC(f, first, second) \ 74 | template \ 75 | inline auto f(const ad::core::ADForward& x, const ad::core::ADForward& y) \ 76 | { \ 77 | return ad::core::ADForward(first, second); \ 78 | } \ 79 | 80 | namespace ad { 81 | namespace core { 82 | 83 | // Forward variable to store value and adjoint. 84 | // If x is an ADForward variable that is a result of composing functions of ADForward variables x1,...,xn 85 | // x.get_value() is the value of the function on these variables and x.get_adjoint() is the adjoint, i.e. 86 | // directional (total) derivative of the composed functions in the direction of x1.get_adjoint(),...,xn.get_adjoint() 87 | template 88 | struct ADForward : public core::DualNum 89 | { 90 | using data_t = core::DualNum; 91 | 92 | ADForward() 93 | : data_t(0, 0) 94 | {} 95 | 96 | ADForward(T w, T df = 0) 97 | : data_t(w, df) 98 | {} 99 | 100 | ADForward& operator+=(const ADForward& x); 101 | }; 102 | 103 | } // namespace core 104 | 105 | // user-exposed forward variable alias 106 | template 107 | using ForwardVar = core::ADForward; 108 | 109 | //================================================================================ 110 | 111 | // Unary functions 112 | 113 | // Negate forward variable 114 | FORWARD_UNARY_FUNC(operator-, -x.get_value(), -x.get_adjoint()) 115 | // ad::sin(core::ADForward) 116 | FORWARD_UNARY_FUNC(sin, std::sin(x.get_value()), 117 | std::cos(x.get_value())*x.get_adjoint()) 118 | // ad::cos(core::ADForward) 119 | FORWARD_UNARY_FUNC(cos, std::cos(x.get_value()), 120 | -std::sin(x.get_value())*x.get_adjoint()) 121 | // ad::tan(core::ADForward) 122 | FORWARD_UNARY_FUNC_PRE(tan, std::tan(x.get_value()), 123 | tmp*tmp * x.get_adjoint(), auto tmp = 1 / std::cos(x.get_value());) 124 | // ad::asin(core::ADForward) 125 | FORWARD_UNARY_FUNC(asin, std::asin(x.get_value()), 126 | x.get_adjoint() / (std::sqrt(1 - x.get_value()*x.get_value()))) 127 | // ad::acos(core::ADForward) 128 | FORWARD_UNARY_FUNC(acos, std::acos(x.get_value()), 129 | -x.get_adjoint() / (std::sqrt(1 - x.get_value()*x.get_value()))) 130 | // ad::atan(core::ADForward) 131 | FORWARD_UNARY_FUNC(atan, std::atan(x.get_value()), 132 | x.get_adjoint() / (1 + x.get_value()*x.get_value())) 133 | // ad::exp(core::ADForward) 134 | FORWARD_UNARY_FUNC_PRE(exp, tmp, tmp * x.get_adjoint(), 135 | auto tmp = std::exp(x.get_value());) 136 | // ad::log(core::ADForward) 137 | FORWARD_UNARY_FUNC(log, std::log(x.get_value()), 138 | x.get_adjoint() / x.get_value()) 139 | // ad::sqrt(core::ADForward) 140 | FORWARD_UNARY_FUNC_PRE(sqrt, tmp, x.get_adjoint() / (2 * tmp), 141 | auto tmp = std::sqrt(x.get_value());) 142 | // ad::erf(core::ADForward) 143 | FORWARD_UNARY_FUNC_PRE(erf, std::erf(x.get_value()), 144 | two_over_sqrt_pi * std::exp(-t_sq), 145 | static constexpr double two_over_sqrt_pi = 146 | 1.1283791670955126; 147 | auto t_sq = x.get_value() * x.get_value();) 148 | 149 | //================================================================================ 150 | 151 | // Binary operators 152 | 153 | namespace core { 154 | 155 | // Add forward variables 156 | FORWARD_BINARY_FUNC(operator+, x.get_value() + y.get_value(), 157 | x.get_adjoint() + y.get_adjoint()) 158 | // Subtract forward variables 159 | FORWARD_BINARY_FUNC(operator-, x.get_value() - y.get_value(), 160 | x.get_adjoint() - y.get_adjoint()) 161 | // Multiply forward variables 162 | FORWARD_BINARY_FUNC(operator*, x.get_value() * y.get_value(), 163 | x.get_value() * y.get_adjoint() + x.get_adjoint() * y.get_value()) 164 | // Divide forward variables 165 | FORWARD_BINARY_FUNC(operator/, x.get_value() / y.get_value(), 166 | (x.get_adjoint() * y.get_value() - x.get_value() * y.get_adjoint()) / (y.get_value() * y.get_value())) 167 | 168 | // Add current forward variable with x and update current variable with the result. 169 | template 170 | inline ADForward& ADForward::operator+=(const ADForward& x) 171 | { 172 | return *this = *this + x; 173 | } 174 | 175 | } // namespace core 176 | } // namespace ad 177 | -------------------------------------------------------------------------------- /inst/include/fastad_bits/reverse.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "reverse/core.hpp" 4 | #include "reverse/stat.hpp" 5 | -------------------------------------------------------------------------------- /inst/include/fastad_bits/reverse/core.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "fastad_bits/reverse/core/binary.hpp" 3 | #include "fastad_bits/reverse/core/bind.hpp" 4 | #include "fastad_bits/reverse/core/constant.hpp" 5 | #include "fastad_bits/reverse/core/dot.hpp" 6 | #include "fastad_bits/reverse/core/eq.hpp" 7 | #include "fastad_bits/reverse/core/eval.hpp" 8 | #include "fastad_bits/reverse/core/expr_base.hpp" 9 | #include "fastad_bits/reverse/core/for_each.hpp" 10 | #include "fastad_bits/reverse/core/glue.hpp" 11 | #include "fastad_bits/reverse/core/if_else.hpp" 12 | #include "fastad_bits/reverse/core/norm.hpp" 13 | #include "fastad_bits/reverse/core/pow.hpp" 14 | #include "fastad_bits/reverse/core/prod.hpp" 15 | #include "fastad_bits/reverse/core/sum.hpp" 16 | #include "fastad_bits/reverse/core/unary.hpp" 17 | #include "fastad_bits/reverse/core/value_view.hpp" 18 | #include "fastad_bits/reverse/core/var.hpp" 19 | #include "fastad_bits/reverse/core/var_view.hpp" 20 | //#include "fastad_bits/reverse/core/hessian.hpp" 21 | #include "fastad_bits/reverse/core/transpose.hpp" -------------------------------------------------------------------------------- /inst/include/fastad_bits/reverse/core/bind.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | namespace ad { 7 | namespace core { 8 | 9 | /** 10 | * ExprBind is a helper class that wraps an AD expression 11 | * and binds it with an internal cache for temporaries. 12 | * This is for convenience purposes so that users do not have 13 | * to worry about creating the cache line themselves. 14 | * 15 | * @tparam ExprType expression type 16 | */ 17 | 18 | template 19 | struct ExprBind 20 | { 21 | using expr_t = ExprType; 22 | using value_t = typename util::expr_traits::value_t; 23 | 24 | ExprBind(const expr_t& expr) 25 | : expr_{expr} 26 | , val_cache_() 27 | , adj_cache_() 28 | { 29 | auto size_pack = expr_.bind_cache_size(); 30 | val_cache_.resize(size_pack(0)); 31 | adj_cache_.resize(size_pack(1)); 32 | expr_.bind_cache({val_cache_.data(), adj_cache_.data()}); 33 | } 34 | 35 | expr_t& get() { return expr_; } 36 | 37 | private: 38 | expr_t expr_; 39 | Eigen::Matrix val_cache_; 40 | Eigen::Matrix adj_cache_; 41 | }; 42 | 43 | } // namespace core 44 | 45 | template 46 | inline auto bind(const core::ExprBase& expr) 47 | { 48 | return core::ExprBind(expr.self()); 49 | } 50 | 51 | } // namespace ad 52 | -------------------------------------------------------------------------------- /inst/include/fastad_bits/reverse/core/constant.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace ad { 10 | namespace core { 11 | 12 | template 13 | struct ConstantBase: ExprBase 14 | {}; 15 | 16 | /** 17 | * ConstantView represents constants in a mathematical formula. 18 | * Specifically, it treats the values it is viewing as a constant. 19 | * 20 | * If shape is selfadjmat, it does not check or symmetrify in any way. 21 | * It is user's responsibility to make sure the matrix is self adjoint. 22 | * 23 | * @tparam ValueType underlying data type 24 | */ 25 | 26 | template 28 | struct ConstantView: 29 | ConstantBase> 30 | { 31 | static_assert(!std::is_same_v, 32 | "ConstantView is currently disabled for scalars. " 33 | "It is more efficient to just create a Constant. "); 34 | using value_t = ValueType; 35 | using shape_t = ShapeType; 36 | using value_adj_view_t = ConstantView; 37 | using var_t = Eigen::Map>; 38 | using ptr_pack_t = util::PtrPack; 39 | 40 | ConstantView(const value_t* begin, 41 | size_t rows, 42 | size_t cols) 43 | : val_(begin, rows, cols) 44 | {} 45 | 46 | /** 47 | * Forward evaluation simply returns the constant value. 48 | * @return constant value 49 | */ 50 | const var_t& feval() const { return this->get(); } 51 | 52 | /** 53 | * Backward evaluation does nothing. 54 | */ 55 | template 56 | void beval(const T&) const {} 57 | 58 | /** 59 | * Templatized because constant can have a different value type 60 | * from what is expected from the PtrPack<...> that gets passed as T. 61 | */ 62 | template 63 | constexpr T bind(T begin) const { return begin; } 64 | 65 | template 66 | constexpr T bind_cache(T begin) const { return begin; } 67 | 68 | util::SizePack bind_cache_size() const { return {0,0}; } 69 | util::SizePack single_bind_cache_size() const { return {0,0}; } 70 | 71 | const var_t& get() const { return val_; } 72 | value_t get(size_t i, size_t j) const { return val_(i, j); } 73 | constexpr size_t size() const { return val_.size(); } 74 | constexpr size_t rows() const { return val_.rows(); } 75 | constexpr size_t cols() const { return val_.cols(); } 76 | const value_t* data() const { return val_.data(); } 77 | 78 | private: 79 | var_t val_; 80 | }; 81 | 82 | template 83 | struct Constant: 84 | ConstantBase> 85 | { 86 | private: 87 | using this_t = Constant; 88 | public: 89 | using value_t = ValueType; 90 | using shape_t = ShapeType; 91 | using var_t = util::constant_var_t; 92 | using value_adj_view_t = Constant; 93 | using ptr_pack_t = util::PtrPack; 94 | 95 | template 96 | Constant(const T& c) 97 | :c_(c) 98 | {} 99 | 100 | const var_t& feval() const { return c_; } 101 | 102 | template 103 | void beval(const T&) const {} 104 | 105 | template 106 | constexpr T bind(T begin) const { return begin; } 107 | 108 | template 109 | constexpr T bind_cache(T begin) const { return begin; } 110 | 111 | util::SizePack bind_cache_size() const { return {0,0}; } 112 | util::SizePack single_bind_cache_size() const { return {0,0}; } 113 | 114 | const var_t& get() const { return c_; } 115 | const value_t& get(size_t i, size_t j) const { 116 | if constexpr (util::is_scl_v) { 117 | static_cast(i); 118 | static_cast(j); 119 | return c_; 120 | } else { 121 | return c_(i,j); 122 | } 123 | } 124 | 125 | const value_t* data() const { 126 | if constexpr (util::is_scl_v) { 127 | return &c_; 128 | } else { 129 | return c_.data(); 130 | } 131 | } 132 | 133 | size_t rows() const { 134 | if constexpr (util::is_scl_v) { 135 | return 1; 136 | } else { 137 | return c_.rows(); 138 | } 139 | } 140 | 141 | size_t cols() const { 142 | if constexpr (util::is_scl_v) { 143 | return 1; 144 | } else { 145 | return c_.cols(); 146 | } 147 | } 148 | 149 | private: 150 | var_t c_; 151 | }; 152 | 153 | } // namespace core 154 | 155 | // Helper function: 156 | // ad::constant(...) and ad::constant_view(...) 157 | 158 | template 159 | inline auto constant_view(const ValueType* x, 160 | size_t rows) 161 | { 162 | return core::ConstantView(x, rows, 1); 163 | } 164 | 165 | template 166 | inline auto constant_view(const ValueType* x, 167 | size_t rows, 168 | size_t cols) 169 | { 170 | return core::ConstantView(x, rows, cols); 171 | } 172 | 173 | template > > 175 | inline auto constant(ValueType x) 176 | { 177 | return core::Constant(x); 178 | } 179 | 180 | template > > 182 | inline auto constant(const Eigen::EigenBase& x) 183 | { 184 | using value_t = typename Derived::Scalar; 185 | return core::Constant(x); 186 | } 187 | 188 | /** 189 | * By default, uses ad::mat as shape, but if user knows and 190 | * wishes to treat the matrix as a self-adjoint matrix, they can 191 | * specify the shape type to be ad::selfadjmat. 192 | */ 193 | template > > 196 | inline auto constant(const Eigen::EigenBase& x) 197 | { 198 | using value_t = typename Derived::Scalar; 199 | return core::Constant(x); 200 | } 201 | 202 | } // namespace ad 203 | -------------------------------------------------------------------------------- /inst/include/fastad_bits/reverse/core/det.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace ad { 10 | namespace core { 11 | 12 | /** 13 | * DetNode represents the determinant of a matrix. 14 | * No other shapes are permitted for this node. 15 | * Decomposition functor of type DecompType is provided to 16 | * define the policy in how to compute forward and backward-evaluation. 17 | * 18 | * The node assumes the same value type as that of the vector expression. 19 | * It is always a scalar shape. 20 | * 21 | * @tparam DecompType decomposition type 22 | * @tparam ExprType type of vector expression 23 | */ 24 | 25 | template 26 | struct DetNode: 27 | ValueAdjView::value_t, 28 | ad::scl>, 29 | ExprBase> 30 | { 31 | private: 32 | using decomp_t = DecompType; 33 | using expr_t = ExprType; 34 | using expr_value_t = typename util::expr_traits::value_t; 35 | 36 | static_assert(!util::is_scl_v); 37 | 38 | public: 39 | using value_adj_view_t = ValueAdjView; 40 | using typename value_adj_view_t::value_t; 41 | using typename value_adj_view_t::shape_t; 42 | using typename value_adj_view_t::var_t; 43 | using typename value_adj_view_t::ptr_pack_t; 44 | 45 | DetNode(const expr_t& expr) 46 | : value_adj_view_t(nullptr, nullptr, 1, 1) 47 | , expr_{expr} 48 | , decomp_(expr.rows()) 49 | { 50 | assert(expr.rows() == expr.cols()); 51 | } 52 | 53 | const var_t& feval() 54 | { 55 | return this->get() = decomp_.fmap(expr_.feval()); 56 | } 57 | 58 | void beval(value_t seed) 59 | { 60 | if (seed == 0 || !decomp_.valid()) return; 61 | auto a_inv_t = decomp_.bmap().array(); 62 | expr_.beval((seed * this->get()) * a_inv_t); 63 | } 64 | 65 | ptr_pack_t bind_cache(ptr_pack_t begin) 66 | { 67 | begin = expr_.bind_cache(begin); 68 | auto adj = begin.adj; 69 | begin.adj = nullptr; 70 | begin = value_adj_view_t::bind(begin); 71 | begin.adj = adj; 72 | return begin; 73 | } 74 | 75 | util::SizePack bind_cache_size() const 76 | { 77 | return expr_.bind_cache_size() + 78 | single_bind_cache_size(); 79 | } 80 | 81 | util::SizePack single_bind_cache_size() const 82 | { 83 | return {this->size(), 0}; 84 | } 85 | 86 | private: 87 | using mat_t = Eigen::Matrix; 88 | expr_t expr_; 89 | decomp_t decomp_; 90 | }; 91 | 92 | } // namespace core 93 | 94 | /* 95 | * Default method for decomposing a matrix for determinant. 96 | */ 97 | template 98 | struct DetFullPivLU 99 | { 100 | using value_t = ValueType; 101 | 102 | DetFullPivLU(size_t rows) 103 | : lu_(rows, rows) 104 | {} 105 | 106 | template 107 | value_t fmap(const Eigen::MatrixBase& X) 108 | { 109 | lu_.compute(X); 110 | return lu_.determinant(); 111 | } 112 | 113 | auto bmap() const 114 | { 115 | return lu_.inverse().transpose(); 116 | } 117 | 118 | bool valid() const { return lu_.isInvertible(); } 119 | 120 | private: 121 | using mat_t = Eigen::Matrix; 122 | Eigen::FullPivLU lu_; 123 | }; 124 | 125 | /* 126 | * Decomposing a positive or negative semi-definite matrix for determinant. 127 | */ 128 | template 129 | struct DetLDLT 130 | { 131 | using value_t = ValueType; 132 | 133 | DetLDLT(size_t rows) 134 | : ldlt_(rows) 135 | , inv_() 136 | {} 137 | 138 | template 139 | value_t fmap(const Eigen::MatrixBase& X) 140 | { 141 | ldlt_.compute(X); 142 | value_t det = ldlt_.vectorD().prod(); 143 | valid_ = (det != 0) && (ldlt_.info() == Eigen::Success); 144 | return det; 145 | } 146 | 147 | // Important to save the inverse, since otherwise Eigen 148 | // will dynamically allocate every time and result in bad-alloc. 149 | const auto& bmap() 150 | { 151 | size_t n = ldlt_.rows(); 152 | return inv_ = ldlt_.solve(mat_t::Identity(n, n)); 153 | } 154 | 155 | bool valid() const { return valid_; } 156 | 157 | private: 158 | using mat_t = Eigen::Matrix; 159 | bool valid_ = false; 160 | Eigen::LDLT ldlt_; 161 | mat_t inv_; 162 | }; 163 | 164 | /* 165 | * Decomposing a positive definite matrix for determinant. 166 | */ 167 | template 168 | struct DetLLT 169 | { 170 | using value_t = ValueType; 171 | 172 | DetLLT(size_t rows) 173 | : llt_(rows) 174 | , inv_() 175 | {} 176 | 177 | template 178 | value_t fmap(const Eigen::MatrixBase& X) 179 | { 180 | llt_.compute(X); 181 | value_t det = llt_.matrixL().determinant(); 182 | return det * det; 183 | } 184 | 185 | // Important to save the inverse, since otherwise Eigen 186 | // will dynamically allocate every time and result in bad-alloc. 187 | const auto& bmap() 188 | { 189 | size_t n = llt_.rows(); 190 | return inv_ = llt_.solve(mat_t::Identity(n, n)); 191 | } 192 | 193 | bool valid() const 194 | { 195 | return (llt_.info() == Eigen::Success); 196 | } 197 | 198 | private: 199 | using mat_t = Eigen::Matrix; 200 | Eigen::LLT llt_; 201 | mat_t inv_; 202 | }; 203 | 204 | /* 205 | * Creates a determinant expression node with a policy that defines the decomposition. 206 | * The default decomposition is Eigen::FullPivLU. 207 | * Currently, we support DetLDLT and DetLLT for some specialized matrices. 208 | * If x is a constant, the decomposition is ignored and 209 | * will always just invoke member function determinant of the underlying Eigen object. 210 | */ 211 | template