Examples from Siskind and Pearlmutter AD2016 polyvariant submission

Run Times

Run times of the examples, normalized relative to a unit run time for Stalingrad
Language/Implementation
Stalingrad Ikarus Stalin Scheme->C Chicken Bigloo Gambit Larceny MzC MzScheme scmutils MLton sml/nj OCaml ghc fadbad++ adifor Tapenade
saddle 1.00 233.16 360.96 423.14 879.10 617.44 491.36 737.47 2303.10 2737.47 2689.98 42.31 63.90 79.44 116.58 23.31 1.96 2.47
particle 1.00 306.17 549.44 729.03 1336.23 1062.89 769.38 1212.42 3188.09 4086.43 3289.16 72.78 89.39 128.95 164.55 84.25 1.53 3.39

Source Code

Source code of the examples, for the various languages and implementations
Language/Implementation
Stalingrad Ikarus Stalin Scheme->C Chicken Bigloo Gambit Larceny MzC MzScheme scmutils MLton sml/nj OCaml ghc fadbad++ adifor Tapenade
common html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
saddle html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
particle html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text
html
text html
text html
text
html
text

Because adifor, Tapenade, and Stalingrad are so fast, we run the examples 1000 times under these systems. Many Scheme implementations do not allow redefinition of builtin arithmetic procedures. Thus the Scheme variants of our examples are written using alternate arithmetic procedures d+, d-, etc. SCMUTILS incorrectly implements the overloaded implementation of =. Thus the SCMUTILS variants of our examples are written using an alternate procedure d=. It is impossible to implement forward AD in ML in a fashion that applies to unmodified source code. Thus the ML variants of our examples require that (a) all code which implements the function whose derivative is taken, including all code called by such code, be syntactically nested inside the redefinition of the primitives and (b) all real constants in that code be syntactically wrapped with the BASE constructor. It is conjectured to be impossible to implement nestable forward AD in Haskell in a fashion that applies to unmodified source code. Thus the Haskell variants of our examples require that the code that implements the functions whose derivatives are taken be manually annotated with appropriate calls to lift to properly handle nesting. Code must be written with templates in FADBAD++ to support taking derivatives of different orders. Code that is transformed by Tapenade multiple times must be post-edited. The flow analysis used by ADIFOR yields incorrect derivative code that produces the wrong answer, without warning, when using the same file organization as all of the other variants, where each example is contained in a single file. Thus the ADIFOR variants of our examples circumvent this flaw by manually partitioning each example into three files that contain the code that is transformed zero, one, and two times. Finally, Tapenade cannot transform code that relies on indirect (i.e., external) subroutine calls. Thus the Tapenade variants of our examples require manual specialization of the multivariate_argmin subroutine. These AD-specific limitations of existing languages and systems are in addition to the standard limitations of languages like C++ and Fortran relative to higher-order functional-programming languages. (http://docs.lib.purdue.edu/ecetr/368 discusses the limitations of ADIFOR, Tapenade, ADIC, and FADBAD++ in greater detail. We could not benchmark against ADIC because we were unsuccessful in getting ADIC to transform its own generated code.) For example, since our examples make use of nested lambda expressions with lexically-scoped free variables to implement the nested minimax optimization in saddle and the potential function in particle, the FADBAD++, ADIFOR, and Tapenade variants of our examples manually implement the requisite closures by way of global variables in C++ and common blocks in Fortran.
This material is based upon work supported by the National Science Foundation under Grant No. 0438806. Any opinions, findings, and conclusions or recommendations expressed in this material are those of the author(s) and do not necessarily reflect the views of the National Science Foundation.