├── .gitignore ├── AUTHORS ├── COPYING ├── ChangeLog ├── INSTALL ├── Makefile.am ├── NEWS ├── README ├── README.md ├── adept ├── Makefile.am ├── adept.cpp └── adept_openmp.cpp ├── benchmark ├── Makefile.am ├── README ├── advection_schemes.h ├── advection_schemes_AD.cpp ├── advection_schemes_AD.h ├── advection_schemes_K.cpp ├── advection_schemes_K.h ├── animate.cpp ├── autodiff_benchmark.cpp ├── differentiator.h └── nx.h ├── configure.ac ├── doc ├── COPYING ├── Makefile.am ├── README ├── adept_documentation.pdf └── adept_documentation.tex ├── include ├── Makefile.am ├── Timer.h ├── adept.h └── create_adept_source_header ├── makefile_include.in └── test ├── Makefile ├── README ├── algorithm.cpp ├── algorithm.h ├── algorithm_with_and_without_ad.h ├── rosenbrock_banana_function.cpp ├── simulate_radiances.cpp ├── simulate_radiances.h ├── state.cpp ├── state.h ├── test_adept.cpp ├── test_adept_with_and_without_ad.cpp ├── test_checkpoint.cpp ├── test_gsl_interface.cpp ├── test_misc.cpp ├── test_no_lib.cpp ├── test_radiances.cpp ├── test_stack_nesting.cpp └── test_thread_safe.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | Makefile.in 2 | /TODO 3 | /aclocal.m4 4 | /config.guess 5 | /config.h.in 6 | /config.log 7 | /config.sub 8 | /configure 9 | /depcomp 10 | /install-sh 11 | /ltmain.sh 12 | /missing 13 | *.o 14 | *.a 15 | *.so 16 | *.la 17 | *.tar* 18 | .deps 19 | *~ 20 | Makefile 21 | !test/Makefile 22 | !doc/Makefile 23 | include/adept_source.h 24 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Robin Hogan -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | version 1.1.1: 2 | - Fixed bugs in hand-coded adjoint of Toon advection scheme 3 | - Fixed bugs in benchmarking tool that failed to correctly compare accuracy of automatic differentiation tools 4 | 5 | version 1.1: 6 | - Added ./configure script using autotools 7 | - Added support for additional mathematical functions: asinh, acosh, atanh, expm1, log1p, cbrt, erf, erfc, exp2, log2 8 | - Changed license from GNU General Public License to Apache 9 | License, Version 2.0 10 | - Jacobian calculation uses OpenMP parallelization 11 | - Removed multiscatter example code 12 | - New benchmarking program in benchmark/ that compares to other automatic differentiation tools if available 13 | - Fixed bug so that gaps in the gradient list now merge properly 14 | - Provided capability to compile code without an external library, to facilitate porting to Windows 15 | - Added programs in test/ demonstrating checkpointing, thread-safety and compiling without an external library 16 | 17 | version 1.0: 18 | - Very many internal changes and added features 19 | - Detailed documentation in the doc/ directory 20 | - Removed the LIFO requirement on the order with which aReal objects ought to be created and destroyed 21 | - For users of version 0.9, the main change to the interface is that the Stack::start() member function is no longer supported; rather you should call the Stack::new_recording() member function *after* the independent variables have been initialized but *before* any mathematical operations are performed using them 22 | 23 | version 0.9: 24 | - First public release 25 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Installation Instructions 2 | ************************* 3 | 4 | Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, 5 | 2006, 2007 Free Software Foundation, Inc. 6 | 7 | This file is free documentation; the Free Software Foundation gives 8 | unlimited permission to copy, distribute and modify it. 9 | 10 | Basic Installation 11 | ================== 12 | 13 | Briefly, the shell commands `./configure; make; make install' should 14 | configure, build, and install this package. The following 15 | more-detailed instructions are generic; see the `README' file for 16 | instructions specific to this package. 17 | 18 | The `configure' shell script attempts to guess correct values for 19 | various system-dependent variables used during compilation. It uses 20 | those values to create a `Makefile' in each directory of the package. 21 | It may also create one or more `.h' files containing system-dependent 22 | definitions. Finally, it creates a shell script `config.status' that 23 | you can run in the future to recreate the current configuration, and a 24 | file `config.log' containing compiler output (useful mainly for 25 | debugging `configure'). 26 | 27 | It can also use an optional file (typically called `config.cache' 28 | and enabled with `--cache-file=config.cache' or simply `-C') that saves 29 | the results of its tests to speed up reconfiguring. Caching is 30 | disabled by default to prevent problems with accidental use of stale 31 | cache files. 32 | 33 | If you need to do unusual things to compile the package, please try 34 | to figure out how `configure' could check whether to do them, and mail 35 | diffs or instructions to the address given in the `README' so they can 36 | be considered for the next release. If you are using the cache, and at 37 | some point `config.cache' contains results you don't want to keep, you 38 | may remove or edit it. 39 | 40 | The file `configure.ac' (or `configure.in') is used to create 41 | `configure' by a program called `autoconf'. You need `configure.ac' if 42 | you want to change it or regenerate `configure' using a newer version 43 | of `autoconf'. 44 | 45 | The simplest way to compile this package is: 46 | 47 | 1. `cd' to the directory containing the package's source code and type 48 | `./configure' to configure the package for your system. 49 | 50 | Running `configure' might take a while. While running, it prints 51 | some messages telling which features it is checking for. 52 | 53 | 2. Type `make' to compile the package. 54 | 55 | 3. Optionally, type `make check' to run any self-tests that come with 56 | the package. 57 | 58 | 4. Type `make install' to install the programs and any data files and 59 | documentation. 60 | 61 | 5. You can remove the program binaries and object files from the 62 | source code directory by typing `make clean'. To also remove the 63 | files that `configure' created (so you can compile the package for 64 | a different kind of computer), type `make distclean'. There is 65 | also a `make maintainer-clean' target, but that is intended mainly 66 | for the package's developers. If you use it, you may have to get 67 | all sorts of other programs in order to regenerate files that came 68 | with the distribution. 69 | 70 | 6. Often, you can also type `make uninstall' to remove the installed 71 | files again. 72 | 73 | Compilers and Options 74 | ===================== 75 | 76 | Some systems require unusual options for compilation or linking that the 77 | `configure' script does not know about. Run `./configure --help' for 78 | details on some of the pertinent environment variables. 79 | 80 | You can give `configure' initial values for configuration parameters 81 | by setting variables in the command line or in the environment. Here 82 | is an example: 83 | 84 | ./configure CC=c99 CFLAGS=-g LIBS=-lposix 85 | 86 | *Note Defining Variables::, for more details. 87 | 88 | Compiling For Multiple Architectures 89 | ==================================== 90 | 91 | You can compile the package for more than one kind of computer at the 92 | same time, by placing the object files for each architecture in their 93 | own directory. To do this, you can use GNU `make'. `cd' to the 94 | directory where you want the object files and executables to go and run 95 | the `configure' script. `configure' automatically checks for the 96 | source code in the directory that `configure' is in and in `..'. 97 | 98 | With a non-GNU `make', it is safer to compile the package for one 99 | architecture at a time in the source code directory. After you have 100 | installed the package for one architecture, use `make distclean' before 101 | reconfiguring for another architecture. 102 | 103 | Installation Names 104 | ================== 105 | 106 | By default, `make install' installs the package's commands under 107 | `/usr/local/bin', include files under `/usr/local/include', etc. You 108 | can specify an installation prefix other than `/usr/local' by giving 109 | `configure' the option `--prefix=PREFIX'. 110 | 111 | You can specify separate installation prefixes for 112 | architecture-specific files and architecture-independent files. If you 113 | pass the option `--exec-prefix=PREFIX' to `configure', the package uses 114 | PREFIX as the prefix for installing programs and libraries. 115 | Documentation and other data files still use the regular prefix. 116 | 117 | In addition, if you use an unusual directory layout you can give 118 | options like `--bindir=DIR' to specify different values for particular 119 | kinds of files. Run `configure --help' for a list of the directories 120 | you can set and what kinds of files go in them. 121 | 122 | If the package supports it, you can cause programs to be installed 123 | with an extra prefix or suffix on their names by giving `configure' the 124 | option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. 125 | 126 | Optional Features 127 | ================= 128 | 129 | Some packages pay attention to `--enable-FEATURE' options to 130 | `configure', where FEATURE indicates an optional part of the package. 131 | They may also pay attention to `--with-PACKAGE' options, where PACKAGE 132 | is something like `gnu-as' or `x' (for the X Window System). The 133 | `README' should mention any `--enable-' and `--with-' options that the 134 | package recognizes. 135 | 136 | For packages that use the X Window System, `configure' can usually 137 | find the X include and library files automatically, but if it doesn't, 138 | you can use the `configure' options `--x-includes=DIR' and 139 | `--x-libraries=DIR' to specify their locations. 140 | 141 | Specifying the System Type 142 | ========================== 143 | 144 | There may be some features `configure' cannot figure out automatically, 145 | but needs to determine by the type of machine the package will run on. 146 | Usually, assuming the package is built to be run on the _same_ 147 | architectures, `configure' can figure that out, but if it prints a 148 | message saying it cannot guess the machine type, give it the 149 | `--build=TYPE' option. TYPE can either be a short name for the system 150 | type, such as `sun4', or a canonical name which has the form: 151 | 152 | CPU-COMPANY-SYSTEM 153 | 154 | where SYSTEM can have one of these forms: 155 | 156 | OS KERNEL-OS 157 | 158 | See the file `config.sub' for the possible values of each field. If 159 | `config.sub' isn't included in this package, then this package doesn't 160 | need to know the machine type. 161 | 162 | If you are _building_ compiler tools for cross-compiling, you should 163 | use the option `--target=TYPE' to select the type of system they will 164 | produce code for. 165 | 166 | If you want to _use_ a cross compiler, that generates code for a 167 | platform different from the build platform, you should specify the 168 | "host" platform (i.e., that on which the generated programs will 169 | eventually be run) with `--host=TYPE'. 170 | 171 | Sharing Defaults 172 | ================ 173 | 174 | If you want to set default values for `configure' scripts to share, you 175 | can create a site shell script called `config.site' that gives default 176 | values for variables like `CC', `cache_file', and `prefix'. 177 | `configure' looks for `PREFIX/share/config.site' if it exists, then 178 | `PREFIX/etc/config.site' if it exists. Or, you can set the 179 | `CONFIG_SITE' environment variable to the location of the site script. 180 | A warning: not all `configure' scripts look for a site script. 181 | 182 | Defining Variables 183 | ================== 184 | 185 | Variables not defined in a site shell script can be set in the 186 | environment passed to `configure'. However, some packages may run 187 | configure again during the build, and the customized values of these 188 | variables may be lost. In order to avoid this problem, you should set 189 | them in the `configure' command line, using `VAR=value'. For example: 190 | 191 | ./configure CC=/usr/local2/bin/gcc 192 | 193 | causes the specified `gcc' to be used as the C compiler (unless it is 194 | overridden in the site shell script). 195 | 196 | Unfortunately, this technique does not work for `CONFIG_SHELL' due to 197 | an Autoconf bug. Until the bug is fixed you can use this workaround: 198 | 199 | CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash 200 | 201 | `configure' Invocation 202 | ====================== 203 | 204 | `configure' recognizes the following options to control how it operates. 205 | 206 | `--help' 207 | `-h' 208 | Print a summary of the options to `configure', and exit. 209 | 210 | `--version' 211 | `-V' 212 | Print the version of Autoconf used to generate the `configure' 213 | script, and exit. 214 | 215 | `--cache-file=FILE' 216 | Enable the cache: use and save the results of the tests in FILE, 217 | traditionally `config.cache'. FILE defaults to `/dev/null' to 218 | disable caching. 219 | 220 | `--config-cache' 221 | `-C' 222 | Alias for `--cache-file=config.cache'. 223 | 224 | `--quiet' 225 | `--silent' 226 | `-q' 227 | Do not print messages saying which checks are being made. To 228 | suppress all normal output, redirect it to `/dev/null' (any error 229 | messages will still be shown). 230 | 231 | `--srcdir=DIR' 232 | Look for the package's source code in directory DIR. Usually 233 | `configure' can determine that directory automatically. 234 | 235 | `configure' also accepts some other, not widely useful, options. Run 236 | `configure --help' for more details. 237 | 238 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | pkgdata_DATA = README COPYING ChangeLog NEWS AUTHORS 2 | SUBDIRS = adept include doc test benchmark 3 | # The test and doc directories do not use automake so we need to 4 | # specify the files that will be included in the distribution 5 | EXTRA_DIST = test/Makefile test/README test/*.cpp test/*.h 6 | ACLOCAL_AMFLAGS = -I m4 7 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | version 1.1 2 | - Added ./configure script 3 | - Added support for additional mathematical functions: asinh, acosh, atanh, expm1, log1p, cbrt, erf, erfc, exp2, log2 4 | - License changed to Apache License, Version 2.0 -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Adept: Automatic Differentiation using Expression Templates 2 | Version: 1.1, June 2015 3 | By Robin Hogan 4 | 5 | 6 | INTRODUCTION 7 | 8 | The Adept software library provides the capability to automatically 9 | differentiate an algorithm written in C or C++. It uses expression 10 | templates in a way that allows it to compute adjoints significantly 11 | faster than the leading current tools that use the same approach of 12 | operator overloading. Benchmark calculations found that Adept was 13 | significantly faster than ADOL-C, CppAD and Sacado for adjoint 14 | calculations, and often not much slower than hand-written adjoint 15 | code. The code to run these benchmarks on your platform is provided in 16 | this package. 17 | 18 | The web site is at http://www.met.reading.ac.uk/clouds/adept/ where 19 | you can find the latest version of the code as well as a paper 20 | describing how it works: 21 | 22 | Hogan, R. J., 2014: Fast reverse-mode automatic differentiation using 23 | expression templates in C++. ACM Trans. Math. Soft., l40, 26:1-26:16. 24 | 25 | 26 | INSTALLING FROM AN OFFICIAL RELEASE 27 | 28 | To create the Makefiles, type 29 | 30 | ./configure 31 | 32 | Aspects of the configuration can be configured via both arguments to 33 | the script and environment variables. Here we focus on options that 34 | are more likely to be useful in the case of Adept. To set the 35 | destination root directory to your home directory and to change the 36 | C++ compiler options, type this instead: 37 | 38 | ./configure "CXXFLAGS=-O3 -g" --prefix=$HOME 39 | 40 | Note that by default the compiler flags are "-O2 -g", but you may find 41 | measurable speed-up in using the "-O3" optimization flag (the "-g" 42 | option stores debugging information in the library, which shouldn't 43 | affect execution speed). 44 | 45 | The configure script also looks for the other 46 | automatic-differentiation libraries ADOL-C, CppAD and Sacado, since 47 | the benchmarking code has the capability to compile the test 48 | algorithms using these libraries. If they are in non-standard 49 | directories, for example your home directory, you can specify them 50 | with 51 | 52 | ./configure CPPFLAGS=-I$HOME/include LDFLAGS=-L$HOME/lib 53 | 54 | If you don't have these libraries then the benchmarking code will 55 | simply be compiled without the capability to use them. Similarly, the 56 | configure script looks for the GNU Scientific Library (GSL) used by 57 | the test program "test_gsl_interface" but if it is not found this test 58 | program will not be built. 59 | 60 | For more information on the use of the configure script, see the 61 | INSTALL file, type "./configure --help", or see the 62 | doc/adept_documentation.pdf file. 63 | 64 | Once you've configured the build, you can build the Adept library with 65 | 66 | make 67 | 68 | and install it with 69 | 70 | make install 71 | 72 | Note that you will need to log in with super-user access before this 73 | step if you are installing to a system directory (e.g. the default 74 | /usr/local). The files installed are the C++ header file 75 | /include/adept.h, the static library /lib/libadept.a 76 | along with the shared version of the library. 77 | 78 | This code has been tested under Linux using the GNU C++ compiler. 79 | 80 | 81 | INSTALLING FROM A GITHUB SNAPSHOT 82 | 83 | In the top-level directory, type: 84 | 85 | libtoolize 86 | aclocal 87 | autoheader 88 | automake --add-missing 89 | autoconf 90 | 91 | and then follow the instructions under "INSTALLING FROM AN OFFICIAL 92 | RELEASE". 93 | 94 | 95 | TESTING AND BENCHMARKING 96 | 97 | Once the code has been compiled, type 98 | 99 | make check 100 | 101 | to build the example programs in the test directory and the 102 | benchmarking program benchmark/autodiff_benchmark. The test programs 103 | test different aspects of the library; for more information, see 104 | test/README. The benchmarking program is useful to test the speed of 105 | Adept and also compare it to other automatic differentiation libraries 106 | on the Lax-Wendroff and Toon algorithms used by Hogan (2014). See 107 | benchmark/README for details. Note that in order for these programs to 108 | work without Adept being installed, they have been linked statically, 109 | which means that the executables are rather large. 110 | 111 | Version 1.0 of Adept included the "Multiscatter" algorithm adapted to 112 | use Adept, which provided a further two benchmarks ("PVC" and "TDTS") 113 | used by Hogan (2014). However, this used GNU C++ extensions and I 114 | don't have the resources to time maintain it in the Adept package, so 115 | it has been removed from Adept version 1.1. Note that version 1.0 is 116 | still available from the Adept web site. 117 | 118 | 119 | 120 | DOCUMENTATION 121 | 122 | This is a PDF file in the doc/ directory, along with the latex source 123 | file available under the GNU Free Documentation License in doc/COPYING. 124 | 125 | If this documentation, the Hogan (2014) paper and the information on 126 | the Adept web site do not answer your questions, then feel free to 127 | email me with queries, or send an email to the mailing list. I'm also 128 | interested to know of successful uses of the code, comments and bug 129 | fixes. 130 | 131 | 132 | LICENSE AND COPYRIGHT 133 | 134 | The Adept library and all code in this package has the same copyright: 135 | 136 | Copyright (C) 2012-2015 University of Reading 137 | 138 | Two licenses are used for the code in this package: 139 | 140 | 1) The files that form the Adept library are distributed under the 141 | conditions of the Apache License, Version 2 - see the COPYING file for 142 | details. This is a permissive free-software license but one that does 143 | impose a few conditions if you intend to distribute derivative works. 144 | The files this license applies to are: 145 | include/adept.h 146 | adept/adept.cpp 147 | adept/adept_openmp.cpp 148 | 149 | 2) All other code is subject to the terms of the GNU all-permissive 150 | license, given at the top of those files - basically you can do what 151 | you like with the code from these files. 152 | 153 | If you use Adept in published scientific work then I request that you 154 | cite the paper above, but this is not a condition of the license. 155 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Adept 1.1 2 | ## Fast automatic differentiation library in C++ 3 | 4 | The Adept software library provides the capability to automatically 5 | differentiate an algorithm written in C++. It uses expression 6 | templates in a way that allows it to compute adjoints and Jacobian 7 | matrices significantly faster than the leading current tools that use 8 | the same approach of operator overloading, and often not much slower 9 | than hand-written adjoint code. 10 | 11 | Note that this is not the latest version of Adept: if you want a 12 | library that combines array features with automatic differentiation 13 | then consider using [Adept 2.0](https://github.com/rjhogan/Adept-2). 14 | 15 | For further information see: 16 | * The [Adept web site](http://www.met.reading.ac.uk/clouds/adept/) 17 | * A detailed [User Guide](http://www.met.reading.ac.uk/clouds/adept/adept_documentation_1.1.pdf) 18 | * [A paper published in ACM TOMS](http://www.met.reading.ac.uk/~swrhgnrj/publications/adept.pdf) describing how it works. 19 | 20 | To build Adept from a GitHub snapshot, do the following: 21 | 22 | autoreconf -fi 23 | 24 | Then the normal make sequence: 25 | 26 | ./configure 27 | make 28 | make install -------------------------------------------------------------------------------- /adept/Makefile.am: -------------------------------------------------------------------------------- 1 | lib_LTLIBRARIES = libadept.la 2 | libadept_la_SOURCES = adept.cpp adept_openmp.cpp 3 | libadept_la_CPPFLAGS = -I../include 4 | -------------------------------------------------------------------------------- /adept/adept_openmp.cpp: -------------------------------------------------------------------------------- 1 | /* adept_openmp.cpp -- OpenMP-enabled Jacobian calculation for Adept library 2 | 3 | Copyright (C) 2013-2015 The University of Reading 4 | 5 | Author: Robin Hogan 6 | 7 | This file is part of the Adept library. 8 | 9 | 10 | Licensed under the Apache License, Version 2.0 (the "License"); 11 | you may not use this file except in compliance with the License. 12 | You may obtain a copy of the License at 13 | 14 | http://www.apache.org/licenses/LICENSE-2.0 15 | 16 | Unless required by applicable law or agreed to in writing, software 17 | distributed under the License is distributed on an "AS IS" BASIS, 18 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 | See the License for the specific language governing permissions and 20 | limitations under the License. 21 | 22 | 23 | This file can and should be compiled even if OpenMP is not enabled. 24 | 25 | */ 26 | 27 | #ifdef _OPENMP 28 | #include 29 | #endif 30 | 31 | #include "adept.h" 32 | 33 | namespace adept { 34 | 35 | // Compute the Jacobian matrix, parallelized using OpenMP. Normally 36 | // the user would call the jacobian or jacobian_forward functions, 37 | // and the OpenMP version would only be called if OpenMP is 38 | // available and the Jacobian matrix is large enough for 39 | // parallelization to be worthwhile. Note that jacobian_out must be 40 | // allocated to be of size m*n, where m is the number of dependent 41 | // variables and n is the number of independents. The independents 42 | // and dependents must have already been identified with the 43 | // functions "independent" and "dependent", otherwise this function 44 | // will fail with FAILURE_XXDEPENDENT_NOT_IDENTIFIED. In the 45 | // resulting matrix, the "m" dimension of the matrix varies 46 | // fastest. This is implemented using a forward pass, appropriate 47 | // for m>=n. 48 | void 49 | Stack::jacobian_forward_openmp(Real* jacobian_out) 50 | { 51 | if (independent_offset_.empty() || dependent_offset_.empty()) { 52 | throw(dependents_or_independents_not_identified()); 53 | } 54 | 55 | // Number of blocks to cycle through, including a possible last 56 | // block containing fewer than ADEPT_MULTIPASS_SIZE variables 57 | int n_block = (n_independent() + ADEPT_MULTIPASS_SIZE - 1) 58 | / ADEPT_MULTIPASS_SIZE; 59 | Offset n_extra = n_independent() % ADEPT_MULTIPASS_SIZE; 60 | 61 | int iblock; 62 | 63 | #pragma omp parallel 64 | { 65 | std::vector > 66 | gradient_multipass_b(max_gradient_); 67 | 68 | #pragma omp for 69 | for (iblock = 0; iblock < n_block; iblock++) { 70 | // Set the offset to the dependent variables for this block 71 | Offset i_independent = ADEPT_MULTIPASS_SIZE * iblock; 72 | 73 | Offset block_size = ADEPT_MULTIPASS_SIZE; 74 | // If this is the last iteration and the number of extra 75 | // elements is non-zero, then set the block size to the number 76 | // of extra elements. If the number of extra elements is zero, 77 | // then the number of independent variables is exactly divisible 78 | // by ADEPT_MULTIPASS_SIZE, so the last iteration will be the 79 | // same as all the rest. 80 | if (iblock == n_block-1 && n_extra > 0) { 81 | block_size = n_extra; 82 | } 83 | 84 | // Set the initial gradients all to zero 85 | for (Offset i = 0; i < gradient_multipass_b.size(); i++) { 86 | gradient_multipass_b[i].zero(); 87 | } 88 | // Each seed vector has one non-zero entry of 1.0 89 | for (Offset i = 0; i < block_size; i++) { 90 | gradient_multipass_b[independent_offset_[i_independent+i]][i] = 1.0; 91 | } 92 | // Loop forward through the derivative statements 93 | for (Offset ist = 1; ist < n_statements_; ist++) { 94 | const Statement& statement = statement_[ist]; 95 | // We copy the LHS to "a" in case it appears on the RHS in any 96 | // of the following statements 97 | Block a; // Initialized to zero 98 | // automatically 99 | 100 | // Loop through operations 101 | for (Offset iop = statement_[ist-1].end_plus_one; 102 | iop < statement.end_plus_one; iop++) { 103 | // Loop through columns within this block; we hope the 104 | // compiler can optimize this loop. Note that it is faster 105 | // to always use ADEPT_MULTIPASS_SIZE, always known at 106 | // compile time, than to use block_size, which is not, even 107 | // though in the last iteration this may involve redundant 108 | // computations. 109 | if (multiplier_[iop] == 1.0) { 110 | for (Offset i = 0; i < ADEPT_MULTIPASS_SIZE; i++) { 111 | // for (Offset i = 0; i < block_size; i++) { 112 | a[i] += gradient_multipass_b[offset_[iop]][i]; 113 | } 114 | } 115 | else { 116 | for (Offset i = 0; i < ADEPT_MULTIPASS_SIZE; i++) { 117 | // for (Offset i = 0; i < block_size; i++) { 118 | a[i] += multiplier_[iop]*gradient_multipass_b[offset_[iop]][i]; 119 | } 120 | } 121 | } 122 | // Copy the results 123 | for (Offset i = 0; i < ADEPT_MULTIPASS_SIZE; i++) { 124 | gradient_multipass_b[statement.offset][i] = a[i]; 125 | } 126 | } // End of loop over statements 127 | // Copy the gradients corresponding to the dependent variables 128 | // into the Jacobian matrix 129 | for (Offset idep = 0; idep < n_dependent(); idep++) { 130 | for (Offset i = 0; i < block_size; i++) { 131 | jacobian_out[(i_independent+i)*n_dependent()+idep] 132 | = gradient_multipass_b[dependent_offset_[idep]][i]; 133 | } 134 | } 135 | } // End of loop over blocks 136 | } // End of parallel section 137 | } // End of jacobian function 138 | 139 | 140 | 141 | // Compute the Jacobian matrix, parallelized using OpenMP. Normally 142 | // the user would call the jacobian or jacobian_reverse functions, 143 | // and the OpenMP version would only be called if OpenMP is 144 | // available and the Jacobian matrix is large enough for 145 | // parallelization to be worthwhile. Note that jacobian_out must be 146 | // allocated to be of size m*n, where m is the number of dependent 147 | // variables and n is the number of independents. The independents 148 | // and dependents must have already been identified with the 149 | // functions "independent" and "dependent", otherwise this function 150 | // will fail with FAILURE_XXDEPENDENT_NOT_IDENTIFIED. In the 151 | // resulting matrix, the "m" dimension of the matrix varies 152 | // fastest. This is implemented using a reverse pass, appropriate 153 | // for m > 181 | gradient_multipass_b(max_gradient_); 182 | 183 | #pragma omp for 184 | for (iblock = 0; iblock < n_block; iblock++) { 185 | // Set the offset to the dependent variables for this block 186 | Offset i_dependent = ADEPT_MULTIPASS_SIZE * iblock; 187 | 188 | Offset block_size = ADEPT_MULTIPASS_SIZE; 189 | // If this is the last iteration and the number of extra 190 | // elements is non-zero, then set the block size to the number 191 | // of extra elements. If the number of extra elements is zero, 192 | // then the number of independent variables is exactly divisible 193 | // by ADEPT_MULTIPASS_SIZE, so the last iteration will be the 194 | // same as all the rest. 195 | if (iblock == n_block-1 && n_extra > 0) { 196 | block_size = n_extra; 197 | } 198 | 199 | // Set the initial gradients all to zero 200 | for (Offset i = 0; i < gradient_multipass_b.size(); i++) { 201 | gradient_multipass_b[i].zero(); 202 | } 203 | // Each seed vector has one non-zero entry of 1.0 204 | for (Offset i = 0; i < block_size; i++) { 205 | gradient_multipass_b[dependent_offset_[i_dependent+i]][i] = 1.0; 206 | } 207 | 208 | // Loop backward through the derivative statements 209 | for (Offset ist = n_statements_-1; ist > 0; ist--) { 210 | const Statement& statement = statement_[ist]; 211 | // We copy the RHS to "a" in case it appears on the LHS in any 212 | // of the following statements 213 | Real a[ADEPT_MULTIPASS_SIZE]; 214 | #if ADEPT_MULTIPASS_SIZE > ADEPT_MULTIPASS_SIZE_ZERO_CHECK 215 | // For large blocks, we only process the ones where a[i] is 216 | // non-zero 217 | Offset i_non_zero[ADEPT_MULTIPASS_SIZE]; 218 | #endif 219 | Offset n_non_zero = 0; 220 | for (Offset i = 0; i < block_size; i++) { 221 | a[i] = gradient_multipass_b[statement.offset][i]; 222 | gradient_multipass_b[statement.offset][i] = 0.0; 223 | if (a[i] != 0.0) { 224 | #if ADEPT_MULTIPASS_SIZE > ADEPT_MULTIPASS_SIZE_ZERO_CHECK 225 | i_non_zero[n_non_zero++] = i; 226 | #else 227 | n_non_zero = 1; 228 | #endif 229 | } 230 | } 231 | 232 | // Only do anything for this statement if any of the a values 233 | // are non-zero 234 | if (n_non_zero) { 235 | // Loop through the operations 236 | for (Offset iop = statement_[ist-1].end_plus_one; 237 | iop < statement.end_plus_one; iop++) { 238 | // Try to minimize pointer dereferencing by making local 239 | // copies 240 | register Real multiplier = multiplier_[iop]; 241 | register Real* __restrict gradient_multipass 242 | = &(gradient_multipass_b[offset_[iop]][0]); 243 | #if ADEPT_MULTIPASS_SIZE > ADEPT_MULTIPASS_SIZE_ZERO_CHECK 244 | // For large blocks, loop over only the indices 245 | // corresponding to non-zero a 246 | for (Offset i = 0; i < n_non_zero; i++) { 247 | gradient_multipass[i_non_zero[i]] += multiplier*a[i_non_zero[i]]; 248 | } 249 | #else 250 | // For small blocks, do all indices 251 | for (Offset i = 0; i < block_size; i++) { 252 | // for (Offset i = 0; i < ADEPT_MULTIPASS_SIZE; i++) { 253 | gradient_multipass[i] += multiplier*a[i]; 254 | } 255 | #endif 256 | } 257 | } 258 | } // End of loop over statement 259 | // Copy the gradients corresponding to the independent 260 | // variables into the Jacobian matrix 261 | for (Offset iindep = 0; iindep < n_independent(); iindep++) { 262 | for (Offset i = 0; i < block_size; i++) { 263 | jacobian_out[iindep*n_dependent()+i_dependent+i] 264 | = gradient_multipass_b[independent_offset_[iindep]][i]; 265 | } 266 | } 267 | } // End of loop over blocks 268 | } // end #pragma omp parallel 269 | } // end jacobian_reverse_openmp 270 | } // End of namespace adept 271 | -------------------------------------------------------------------------------- /benchmark/Makefile.am: -------------------------------------------------------------------------------- 1 | check_PROGRAMS = autodiff_benchmark animate 2 | autodiff_benchmark_SOURCES = autodiff_benchmark.cpp advection_schemes_AD.cpp \ 3 | advection_schemes_K.cpp differentiator.h advection_schemes.h \ 4 | advection_schemes_AD.h advection_schemes_K.h nx.h 5 | autodiff_benchmark_CPPFLAGS = -I../include 6 | autodiff_benchmark_LDFLAGS = -static -no-install -L../adept/.libs 7 | autodiff_benchmark_LDADD = -ladept 8 | 9 | animate_SOURCES = animate.cpp 10 | -------------------------------------------------------------------------------- /benchmark/README: -------------------------------------------------------------------------------- 1 | This directory contains the code to run benchmarks for the 2 | Lax-Wendroff and Toon advection schemes described in the Adept 3 | paper. Type "make check" a directory above to compile the program 4 | "autodiff_benchmark". A second executable "animate" is also compiled 5 | that allows the 1D advection to be visualized (you may need to expand 6 | the size of your terminal). 7 | 8 | Reverse-mode and Jacobian calculations are compared for hand-coded 9 | differentiation, Adept, and if found by the configure script, also the 10 | ADOL-C, Sacado and CppAD libraries. The numerical values are compared 11 | as well as the computational speed. 12 | 13 | For a very basic run, just type 14 | 15 | ./autodiff_benchmark 16 | 17 | For a proper benchmark you will need to carry out more repeats. Type 18 | 19 | ./autodiff_benchmark --help 20 | 21 | to see the full list of options. You will probably need at least 22 | 10000 repeats ("-r 10000") for a reliable benchmark, and repeated 23 | calls to the program will also be needed to verify the consistency, on 24 | a machine that is otherwise idle. By default, for Jacobian 25 | calculations Adept uses as many OpenMP threads as there are processing 26 | cores available, which gives it an advantage over the other libraries 27 | that are single-threaded only. You can turn off OpenMP with the 28 | "--no-openmp" option. 29 | 30 | There are caveats you should be aware of, the main being that while 31 | these algorithms are different (Lax-Wendroff uses no mathematical 32 | functions while Toon uses exp and log), both are rather small in terms 33 | of number of operations and memory required. Some automatic 34 | differentiation libraries scale better than others to larger problems, 35 | so do test more than one library on your own code. Hopefully the code 36 | in this directory demonstrates that it is fairly straightforward to 37 | apply different automatic differentiation libraries to the same 38 | code. 39 | 40 | Note that that these two algorithms both have 100 inputs or 41 | independent variables x, and 100 outputs or dependent variables y, so 42 | the Jacobian matrix is square. More commonly, x and y are 43 | different. Note that forward-mode Jacobian calculation is generally 44 | faster if y > x while reverse-mode Jacobian calculation is generally 45 | faster if y < x, and not all libraries can do both modes. 46 | -------------------------------------------------------------------------------- /benchmark/advection_schemes.h: -------------------------------------------------------------------------------- 1 | /* advection_schemes.h - Two test advection algorithms from the Adept paper 2 | 3 | Copyright (C) 2014 The University of Reading 4 | 5 | Copying and distribution of this file, with or without modification, 6 | are permitted in any medium without royalty provided the copyright 7 | notice and this notice are preserved. This file is offered as-is, 8 | without any warranty. 9 | */ 10 | 11 | // Use templates so that these functions can be easily compiled with 12 | // different automatic differentiation tools in order that the 13 | // performance of these tools can be compared. 14 | 15 | #ifndef ADVECTION_SCHEMES_H 16 | #define ADVECTION_SCHEMES_H 1 17 | 18 | #include 19 | 20 | // Use a fixed problem size 21 | #include "nx.h" 22 | 23 | // Lax-Wendroff scheme applied to linear advection 24 | template 25 | void lax_wendroff(int nt, double c, const adouble q_init[NX], adouble q[NX]) { 26 | adouble flux[NX-1]; // Fluxes between boxes 27 | for (int i=0; i 37 | void toon(int nt, double c, const adouble q_init[NX], adouble q[NX]) { 38 | adouble flux[NX-1]; // Fluxes between boxes 39 | for (int i=0; i q[i] || bigdiff < -q[i]) { 48 | flux[i] = (exp(c*log(q[i]/q[i+1]))-1.0) 49 | * q[i]*q[i+1] / (q[i]-q[i+1]); 50 | } 51 | else { 52 | flux[i] = c*q[i]; // Upwind scheme 53 | } 54 | } 55 | for (int i=1; i 12 | #include 13 | 14 | // Include this purely for the NX define: 15 | #include "advection_schemes.h" 16 | 17 | // Include to check for agreement between declaration and definition 18 | #include "advection_schemes_AD.h" 19 | 20 | 21 | // Hand-coded adjoint of Lax-Wendroff advection scheme 22 | void lax_wendroff_AD(int nt, double c, const double q_init[NX], double q[NX], 23 | const double q_AD_const[NX], double q_init_AD[NX]) { 24 | // Forward pass 25 | double flux[NX-1]; 26 | 27 | for (int i = 0; i < NX; i++) q[i] = q_init[i]; 28 | 29 | // Forward pass 30 | for (int j = 0; j < nt; j++) { 31 | for (int i = 0; i < NX-1; i++) flux[i] = 0.5*c*(q[i]+q[i+1]+c*(q[i]-q[i+1])); 32 | for (int i = 1; i < NX-1; i++) q[i] += flux[i-1]-flux[i]; 33 | q[0] = q[NX-2]; q[NX-1] = q[1]; // Treat boundary conditions 34 | } 35 | 36 | double q_AD[NX]; 37 | double flux_AD[NX-1]; 38 | for (int i = 0; i < NX; i++) q_AD[i] = q_AD_const[i]; 39 | for (int i = 0; i < NX-1; i++) flux_AD[i] = 0.0; 40 | 41 | // Reverse pass 42 | for (int j = nt-1; j >= 0; j--) { 43 | q_AD[NX-2] += q_AD[0]; 44 | q_AD[0] = 0.0; 45 | q_AD[1] += q_AD[NX-1]; 46 | q_AD[NX-1] = 0.0; 47 | 48 | for(int i = 1; i < NX-1; i++) { 49 | flux_AD[i-1] += q_AD[i]; 50 | flux_AD[i] -= q_AD[i]; 51 | // q_AD[i] = 0.0; 52 | } 53 | double factor1 = 0.5*c*(1.0+c); 54 | double factor2 = 0.5*c*(1.0-c); 55 | for (int i = 0; i < NX-1; i++) { 56 | q_AD[i] += factor1*flux_AD[i]; 57 | q_AD[i+1] += factor2*flux_AD[i]; 58 | flux_AD[i] = 0.0; 59 | } 60 | } 61 | for (int i = 0; i < NX; i++) { 62 | q_init_AD[i] = q_AD[i]; 63 | q_AD[i] = 0.0; 64 | } 65 | } 66 | 67 | // Hand-coded adjoint of Toon advection scheme 68 | void toon_AD(int nt, double c, const double q_init[NX], double q_out[NX], 69 | const double q_AD_const[NX], double q_init_AD[NX]) { 70 | // Forward pass 71 | double flux[NX-1]; 72 | 73 | double* q_save = new double[NX*(nt+1)]; 74 | // double q_save[NX*(nt+1)]; 75 | double* q = &(q_save[0]); 76 | 77 | for (int i = 0; i < NX; i++) q[i] = q_init[i]; 78 | 79 | // Forward pass 80 | for (int j = 0; j < nt; j++) { 81 | for (int i=0; i= 0; j--) { 97 | q_AD[NX-2] += q_AD[0]; 98 | q_AD[0] = 0.0; 99 | q_AD[1] += q_AD[NX-1]; 100 | q_AD[NX-1] = 0.0; 101 | 102 | for(int i = 1; i < NX-1; i++) { 103 | flux_AD[i-1] += q_AD[i]; 104 | flux_AD[i] -= q_AD[i]; 105 | // q_AD[i] = 0.0; 106 | } 107 | q -= NX; 108 | for (int i = 0; i < NX-1; i++) { 109 | // Need to check if the difference between adjacent points is 110 | // not too small or we end up with close to division by zero. 111 | if (fabs(q[i]-q[i+1]) > q[i]*1.0e-6) { 112 | double factor = exp(c*log(q[i]/q[i+1])); 113 | double one_over_q_i = 1.0/q[i]; 114 | double one_over_q_i_plus_one = 1.0/q[i+1]; 115 | double one_over_denominator = 1.0/(one_over_q_i_plus_one-one_over_q_i); 116 | q_AD[i] += one_over_denominator*one_over_q_i 117 | * (c*factor - (factor-1.0)*one_over_denominator*one_over_q_i) 118 | * flux_AD[i]; 119 | q_AD[i+1] += one_over_denominator*one_over_q_i_plus_one 120 | * (- c*factor + (factor-1.0)*one_over_denominator*one_over_q_i_plus_one) 121 | * flux_AD[i]; 122 | flux_AD[i] = 0.0; 123 | } 124 | else { 125 | q_AD[i] += c*flux_AD[i]; 126 | flux_AD[i] = 0.0; 127 | } 128 | } 129 | } 130 | for (int i = 0; i < NX; i++) { 131 | q_init_AD[i] = q_AD[i]; 132 | q_AD[i] = 0.0; 133 | } 134 | 135 | delete[] q_save; 136 | } 137 | 138 | 139 | -------------------------------------------------------------------------------- /benchmark/advection_schemes_AD.h: -------------------------------------------------------------------------------- 1 | /* advection_schemes_AD.h - Header for the hand-coded adjoints 2 | 3 | Copyright (C) 2014 The University of Reading 4 | 5 | Copying and distribution of this file, with or without modification, 6 | are permitted in any medium without royalty provided the copyright 7 | notice and this notice are preserved. This file is offered as-is, 8 | without any warranty. 9 | */ 10 | 11 | #include "nx.h" 12 | 13 | // Hand-coded adjoint of Lax-Wendroff advection scheme 14 | void lax_wendroff_AD(int nt, double c, const double q_init[NX], double q[NX], 15 | const double q_AD_const[NX], double q_init_AD[NX]); 16 | 17 | // Hand-coded adjoint of Toon advection scheme 18 | void toon_AD(int nt, double c, const double q_init[NX], double q_out[NX], 19 | const double q_AD_const[NX], double q_init_AD[NX]); 20 | -------------------------------------------------------------------------------- /benchmark/advection_schemes_K.cpp: -------------------------------------------------------------------------------- 1 | /* advection_schemes_K.cpp - Hand-coded Jacobians of advection schemes in Adept paper 2 | 3 | Copyright (C) 2014 The University of Reading 4 | 5 | Copying and distribution of this file, with or without modification, 6 | are permitted in any medium without royalty provided the copyright 7 | notice and this notice are preserved. This file is offered as-is, 8 | without any warranty. 9 | */ 10 | 11 | // Use templates so that these functions can be easily compiled with 12 | // different automatic differentiation tools in order that the 13 | // performance of these tools can be compared. 14 | 15 | #include 16 | #include 17 | #include "nx.h" 18 | 19 | // Lax-Wendroff scheme applied to linear advection 20 | void lax_wendroff_K(int nt, double c, const double q_init[NX], 21 | double q[NX], double jacobian[NX*NX]) { 22 | double flux[NX-1]; // Fluxes between boxes 23 | double flux_K[NX-1][NX]; // Flux Jacobian (dflux/dq_init) 24 | // double (&q_K)[NX][NX] = *reinterpret_cast(jacobian); 25 | double q_K[NX][NX]; 26 | double coeff1 = 0.5*c*(1.0+c); 27 | double coeff2 = 0.5*c*(1.0-c); 28 | 29 | for (int i=0; i q[i]*1.0e-6) { 86 | double factor = exp(c*log(q[i]/q[i+1])); 87 | double one_over_denominator = 1.0/(q[i]-q[i+1]); 88 | coeff1 = one_over_denominator*q[i+1] 89 | * (c*factor + (factor-1.0)*(1.0-q[i]*one_over_denominator)); 90 | coeff2 = one_over_denominator*q[i] 91 | * (- c*factor + (factor-1.0)*(1.0+q[i+1]*one_over_denominator)); 92 | flux[i] = (factor-1.0) * q[i]*q[i+1]*one_over_denominator; 93 | } 94 | else { 95 | flux[i] = c*q[i]; // Upwind scheme 96 | coeff1 = c; 97 | coeff2 = 0.0; 98 | } 99 | for (int k=0; k 1.0) { 102 | // std::cout << "! " << i << " " << k << " " << flux_K[i][k] << "\n"; 103 | } 104 | } 105 | } 106 | 107 | for (int i=1; i 12 | #include 13 | #include 14 | 15 | #include "advection_schemes.h" 16 | 17 | int 18 | main(int argc, char** argv) 19 | { 20 | double q1_save[NX]; 21 | double q2_save[NX]; 22 | double* q1 = q1_save; 23 | double* q2 = q2_save; 24 | double pi = 4.0*atan(1.0); 25 | 26 | double min_q = -0.2; 27 | double max_q = 1.2; 28 | double dq = 0.05; 29 | 30 | double dt = 0.125; 31 | int nt = 8; 32 | int cycles = 5; 33 | 34 | int j_min = min_q/dq; 35 | int j_max = max_q/dq; 36 | 37 | std::string line; 38 | line.resize(NX); 39 | 40 | timespec t; 41 | t.tv_sec = 0; 42 | t.tv_nsec = 20000000; 43 | 44 | for (int i = 0; i < NX; i++) q1[i] = (0.5+0.5*sin((i*2.0*pi)/(NX-1.5)))+0.0001; 45 | for (int k = 0; k < cycles*NX/(nt*dt); k++) { 46 | std::cout << "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"; 47 | 48 | for (int j = j_max; j > 0; j--) { 49 | double q_thresh = j*dq; 50 | for (int i = 0; i < NX; i++) { 51 | if (q1[i] > q_thresh) { 52 | line[i] = '#'; 53 | } 54 | else { 55 | line[i] = ' '; 56 | } 57 | } 58 | std::cout << line << "\n"; 59 | } 60 | for (int i = 0; i < NX; i++) { 61 | line[i] = '-'; 62 | } 63 | std::cout << line << "\n"; 64 | for (int j = -1; j > j_min; j--) { 65 | double q_thresh = j*dq; 66 | for (int i = 0; i < NX; i++) { 67 | if (q1[i] <= q_thresh) { 68 | line[i] = '$'; 69 | } 70 | else { 71 | line[i] = ' '; 72 | } 73 | } 74 | std::cout << line << "\n"; 75 | std::cout.flush(); 76 | } 77 | nanosleep(&t, 0); 78 | //toon(nt, dt, q1, q2); 79 | lax_wendroff(nt, dt, q1, q2); 80 | double* tmp = q1; 81 | q2 = q1; 82 | q1 = tmp; 83 | } 84 | return 0; 85 | } 86 | -------------------------------------------------------------------------------- /benchmark/autodiff_benchmark.cpp: -------------------------------------------------------------------------------- 1 | /* autodiff_benchmark.cpp - Program to benchmark different automatic differentiation tools 2 | 3 | Copyright (C) 2014 The University of Reading 4 | 5 | Copying and distribution of this file, with or without modification, 6 | are permitted in any medium without royalty provided the copyright 7 | notice and this notice are preserved. This file is offered as-is, 8 | without any warranty. 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "differentiator.h" 18 | 19 | static 20 | double 21 | rms(const std::vector& a, const std::vector&b) 22 | { 23 | if (a.size() != b.size()) { 24 | throw differentiator_exception("Attempt to compute RMS difference between vectors of different size"); 25 | } 26 | double sum = 0.0; 27 | for (size_t i = 0; i < a.size(); i++) { 28 | sum += (a[i]-b[i])*(a[i]-b[i]); 29 | } 30 | return sqrt(sum/a.size()); 31 | } 32 | 33 | static 34 | void 35 | usage(const char* argv0) 36 | { 37 | std::cout << "Usage: " << argv0 << " [OPTIONS] where OPTIONS can be\n"; 38 | std::cout << " -h|--help Print this message\n"; 39 | std::cout << " -a|--algorithm s Use test algorithms specified by string s which may be\n"; 40 | std::cout << " \"all\" or a comma separated list with possible entries\n"; 41 | std::cout << " " << test_algorithms() << "\n"; 42 | std::cout << " -t|--tool s Use automatic differentiation tools specified by string\n"; 43 | std::cout << " s which may be \"all\" or a comma separated list with\n"; 44 | std::cout << " possible entries " << autodiff_tools() << "\n"; 45 | std::cout << " -r|--repeat n Benchmark repeats the simulation n times\n"; 46 | std::cout << " -j|--jrepeat n Repeat the Jacobian simulation n times\n"; 47 | std::cout << " -n|--timesteps n Simulation uses n timesteps\n"; 48 | std::cout << " --print-result Print the final output from the simulation(s)\n"; 49 | std::cout << " --print-adjoint Print the hand-coded adjoint\n"; 50 | std::cout << " --print-jacobian Print the hand-coded Jacobian matrix\n"; 51 | std::cout << " --no-openmp Don't use OpenMP to speed up Adept\n"; 52 | std::cout << " --jacobian-forward Force use of forward-mode Jacobian\n"; 53 | std::cout << " --jacobian-reverse Force use of reverse-mode Jacobian\n"; 54 | std::cout << " --tolerance x Agreement with hand-coded requires RMS difference < x\n"; 55 | std::cout << " --verify-only No benchmark: only verify correctness of results\n"; 56 | std::cout << "Return code: 0 if all automatic differentiation tools produce adjoints and\n" 57 | " Jacobians whose RMS difference with the values from hand-coded\n" 58 | " differentiation is less than the required tolerance; 1 otherwise.\n"; 59 | } 60 | 61 | int 62 | main(int argc, char** argv) 63 | { 64 | int nt = 2000; 65 | int nr = 100; 66 | int nr_jacobian = nr/10; 67 | double dt = 0.125; 68 | double tolerance = 1.0e-6; 69 | int force_jacobian = 0; 70 | 71 | bool verbose = false; 72 | bool print_result = false; 73 | bool print_adjoint = false; 74 | bool print_jacobian = false; 75 | bool no_openmp = false; 76 | bool verify_only = false; 77 | 78 | std::valarray use_tool(N_AUTODIFF_TOOLS); 79 | std::valarray use_algorithm(N_TEST_ALGORITHMS); 80 | 81 | use_tool = true; 82 | use_algorithm = true; 83 | 84 | int iarg = 1; 85 | 86 | while (iarg < argc) { 87 | if (std::string("-h") == argv[iarg] 88 | || std::string("--help") == argv[iarg]) { 89 | usage(argv[0]); 90 | return 0; 91 | } 92 | if (std::string("-v") == argv[iarg] 93 | || std::string("--verbose") == argv[iarg]) { 94 | verbose = true; 95 | } 96 | else if (std::string("--print-result") == argv[iarg]) { 97 | print_result = true; 98 | } 99 | else if (std::string("--print-adjoint") == argv[iarg]) { 100 | print_adjoint = true; 101 | } 102 | else if (std::string("--print-jacobian") == argv[iarg]) { 103 | print_jacobian = true; 104 | } 105 | else if (std::string("--jacobian-forward") == argv[iarg]) { 106 | force_jacobian = +1; 107 | } 108 | else if (std::string("--jacobian-reverse") == argv[iarg]) { 109 | force_jacobian = -1; 110 | } 111 | else if (std::string("--no-openmp") == argv[iarg]) { 112 | no_openmp = true; 113 | } 114 | else if (std::string("--verify-only") == argv[iarg]) { 115 | verify_only = true; 116 | } 117 | else if (std::string("-a") == argv[iarg] 118 | || std::string("--algorithm") == argv[iarg]) { 119 | if (++iarg < argc) { 120 | if (std::string(argv[iarg]) != "all") { 121 | use_algorithm = false; 122 | std::istringstream ss(argv[iarg]); 123 | std::string alg; 124 | while (std::getline(ss, alg, ',')) { 125 | bool found = false; 126 | for (int i = 0; i < N_TEST_ALGORITHMS; i++) { 127 | if (alg == test_algorithm_string[i]) { 128 | use_algorithm[i] = true; 129 | found = true; 130 | break; 131 | } 132 | } 133 | if (!found) { 134 | std::cout << "Test algorithm \"" 135 | << alg << "\" not available; available algorithms are " 136 | << test_algorithms() << "\n"; 137 | } 138 | } 139 | } 140 | } 141 | else { 142 | std::cout << "Arguments \"-a\" or \"--algorithm\" need to be followed by a string containing a comma-separated list of algorithms\n"; 143 | return 1; 144 | } 145 | } 146 | else if (std::string("-t") == argv[iarg] 147 | || std::string("--tool") == argv[iarg]) { 148 | if (++iarg < argc) { 149 | if (std::string(argv[iarg]) != "all") { 150 | use_tool = false; 151 | std::istringstream ss(argv[iarg]); 152 | std::string tool; 153 | while (std::getline(ss, tool, ',')) { 154 | bool found = false; 155 | for (int i = 0; i < N_AUTODIFF_TOOLS; i++) { 156 | if (tool == autodiff_tool_string[i]) { 157 | use_tool[i] = true; 158 | found = true; 159 | break; 160 | } 161 | } 162 | if (!found) { 163 | std::cout << "Automatic differentiation tool \"" 164 | << tool << "\" not available; available tools are " 165 | << autodiff_tools() << "\n"; 166 | } 167 | } 168 | } 169 | } 170 | else { 171 | std::cout << "Arguments \"-a\" or \"--algorithm\" need to be followed by a string containing a comma-separated list of algorithms\n"; 172 | return 1; 173 | } 174 | } 175 | else if (std::string("-r") == argv[iarg] 176 | || std::string("--repeat") == argv[iarg]) { 177 | if (++iarg < argc) { 178 | std::stringstream ss(argv[iarg]); 179 | if (ss >> nr) { 180 | if (nr <= 0) { 181 | std::cout << "Number of repeats must be greater than zero\n"; 182 | return 1; 183 | } 184 | } 185 | else { 186 | std::cout << "Failed to read \"" 187 | << argv[iarg] 188 | << "\"as an integer\n"; 189 | return 1; 190 | } 191 | } 192 | else { 193 | throw differentiator_exception("Arguments \"-r\" or \"--repeat\" need to be followed by a number"); 194 | } 195 | } 196 | else if (std::string("-j") == argv[iarg] 197 | || std::string("--jrepeat") == argv[iarg]) { 198 | if (++iarg < argc) { 199 | std::stringstream ss(argv[iarg]); 200 | if (ss >> nr_jacobian) { 201 | if (nr <= 0) { 202 | throw differentiator_exception("Number of repeats must be greater than zero"); 203 | } 204 | } 205 | else { 206 | std::string msg = "Failed to read \""; 207 | msg += argv[iarg]; 208 | msg += "\"as an integer"; 209 | throw differentiator_exception(msg.c_str()); 210 | } 211 | } 212 | else { 213 | throw differentiator_exception("Arguments \"-j\" or \"--jrepeat\" need to be followed by a number"); 214 | } 215 | } 216 | else if (std::string("-n") == argv[iarg] 217 | || std::string("--timesteps") == argv[iarg]) { 218 | if (++iarg < argc) { 219 | std::stringstream ss(argv[iarg]); 220 | if (ss >> nt) { 221 | if (nt < 0) { 222 | throw differentiator_exception("Number of timesteps must be greater than or equal to zero"); 223 | } 224 | } 225 | else { 226 | std::string msg = "Failed to read \""; 227 | msg += argv[iarg]; 228 | msg += "\"as an integer"; 229 | throw differentiator_exception(msg.c_str()); 230 | } 231 | } 232 | else { 233 | throw differentiator_exception("Arguments \"-n\" or \"--timesteps\" need to be followed by a number"); 234 | } 235 | } 236 | else if (std::string("--tolerance") == argv[iarg]) { 237 | if (++iarg < argc) { 238 | std::stringstream ss(argv[iarg]); 239 | if (ss >> tolerance) { 240 | if (tolerance < 0) { 241 | throw differentiator_exception("Tolerance must be greater than or equal to zero"); 242 | } 243 | } 244 | else { 245 | std::string msg = "Failed to read \""; 246 | msg += argv[iarg]; 247 | msg += "\"as a double"; 248 | throw differentiator_exception(msg.c_str()); 249 | } 250 | } 251 | else { 252 | throw differentiator_exception("Arguments \"-j\" or \"--jrepeat\" need to be followed by a number"); 253 | } 254 | } 255 | else { 256 | std::string msg = "Argument \""; 257 | msg += argv[iarg]; 258 | msg += "\" not understood\n"; 259 | std::cout << msg; 260 | usage(argv[0]); 261 | return 1; 262 | } 263 | iarg++; 264 | } 265 | 266 | double pi = 4.0*atan(1.0); 267 | std::vector q_init(NX); 268 | std::vector q(NX); 269 | std::vector q_AD(NX); 270 | std::vector q_init_AD(NX); 271 | std::vector q_init_AD_reference(NX); 272 | std::vector jac(NX*NX); 273 | std::vector jac_reference(NX*NX); 274 | 275 | int nr_warm_up = nr/10; 276 | int nr_jacobian_warm_up = nr_jacobian/10; 277 | if (nr_warm_up < 1) { 278 | nr_warm_up = 1; 279 | } 280 | if (nr_jacobian_warm_up < 1) { 281 | nr_jacobian_warm_up = 1; 282 | } 283 | 284 | if (verify_only) { 285 | nr = 0; 286 | nr_jacobian = 0; 287 | nr_warm_up = 1; 288 | nr_jacobian_warm_up = 1; 289 | } 290 | 291 | for (int i = 0; i < NX; i++) q_init[i] = (0.5+0.5*sin((i*2.0*pi)/(NX-1.5)))+1.0; 292 | for (int i = 0; i < NX; i++) q_AD[i] = 0.1; 293 | 294 | bool verify_error = false; 295 | 296 | Timer timer; 297 | 298 | std::cout << "Automatic differentiation benchmark and verification\n"; 299 | std::cout << " Automatic differentiation tools = "; 300 | bool is_first = true; 301 | for (int i = 0; i < N_AUTODIFF_TOOLS; i++) { 302 | if (use_tool[i]) { 303 | if (!is_first) { 304 | std::cout << ", "; 305 | } 306 | else { 307 | is_first = false; 308 | } 309 | std::cout << autodiff_tool_long_string[i]; 310 | } 311 | } 312 | std::cout << "\n"; 313 | 314 | std::cout << " Test algorithms = "; 315 | is_first = true; 316 | for (int i = 0; i < N_TEST_ALGORITHMS; i++) { 317 | if (use_algorithm[i]) { 318 | if (!is_first) { 319 | std::cout << ", "; 320 | } 321 | else { 322 | is_first = false; 323 | } 324 | std::cout << test_algorithm_long_string[i]; 325 | } 326 | } 327 | std::cout << "\n"; 328 | 329 | std::cout << " Number of x points = " << NX << "\n"; 330 | std::cout << " Number of timesteps = " << nt << ", Courant number = " << dt << "\n"; 331 | if (!verify_only) { 332 | std::cout << " Algorithm repeats = " << nr << ", warm-up repeats = " << nr_warm_up << "\n"; 333 | std::cout << " Jacobian repeats = " << nr_jacobian << ", warm-up repeats = " << nr_jacobian_warm_up << "\n"; 334 | } 335 | else { 336 | std::cout << " Verifying results only: no repeats\n"; 337 | } 338 | 339 | std::cout << "\nAdept library version " << ADEPT_VERSION_STR << "\n"; 340 | std::cout << " Compiled with " << adept::compiler_version() << "\n"; 341 | std::cout << " Compiler flags \"" << adept::compiler_flags() 342 | << "\" (\"-g -O3\" is recommended)\n"; 343 | std::cout << " Jacobians processed in blocks of size " 344 | << ADEPT_MULTIPASS_SIZE << "\n"; 345 | 346 | // Loop through test algorithms 347 | for (int ialg = 0; ialg < N_TEST_ALGORITHMS; ialg++) { 348 | if (use_algorithm[ialg]) { 349 | 350 | std::string algorithm_string = test_algorithm_long_string[ialg]; 351 | std::cout << "\nRunning test algorithm \"" << algorithm_string << "\":\n"; 352 | 353 | TestAlgorithm ta = static_cast(ialg); 354 | 355 | std::cout << " Hand coded (forward-mode Jacobian only)\n"; 356 | 357 | HandCodedDifferentiator hand_coded_differentiator(timer, algorithm_string); 358 | hand_coded_differentiator.initialize(nt, dt); 359 | for (int i = 0; i < nr_warm_up; i++) { 360 | hand_coded_differentiator.func(ta, q_init, q); 361 | hand_coded_differentiator.adjoint(ta, q_init, q, q_AD, q_init_AD_reference); 362 | hand_coded_differentiator.jacobian(ta, q_init, q, jac_reference); 363 | } 364 | hand_coded_differentiator.reset_timings(); 365 | for (int i = 0; i < nr; i++) { 366 | hand_coded_differentiator.func(ta, q_init, q); 367 | hand_coded_differentiator.adjoint(ta, q_init, q, q_AD, q_init_AD_reference); 368 | hand_coded_differentiator.jacobian(ta, q_init, q, jac_reference); 369 | } 370 | 371 | if (print_result) { 372 | std::cout << " result = [" << q[0]; 373 | for (int i = 1; i < NX; i++) { 374 | std::cout << ", " << q[i]; 375 | } 376 | std::cout << "]\n"; 377 | } 378 | 379 | if (print_adjoint) { 380 | std::cout << "adjoint = [" << q_init_AD_reference[0]; 381 | for (int i = 1; i < NX; i++) { 382 | std::cout << ", " << q_init_AD_reference[i]; 383 | } 384 | std::cout << "]\n"; 385 | } 386 | if (print_jacobian) { 387 | double (&q_K)[NX][NX] 388 | = *reinterpret_cast(&jac_reference[0]); 389 | std::cout << "jacobian = [\n"; 390 | for (int i = 0; i < NX; i++) { 391 | std::cout << q_K[i][0]; 392 | for (int j = 1; j < NX; j++) { 393 | std::cout << ", " << q_K[i][j]; 394 | } 395 | std::cout << "\n"; 396 | } 397 | std::cout << "]\n"; 398 | } 399 | 400 | double base_time = timer.timing(hand_coded_differentiator.base_timer_id()); 401 | 402 | if (!verify_only) { 403 | std::cout << " Time of original algorithm: " << base_time << " seconds\n"; 404 | std::cout << " Absolute time of adjoint: " 405 | << timer.timing(hand_coded_differentiator.adjoint_compute_timer_id()) 406 | << " s\n"; 407 | std::cout << " Relative time of adjoint: " 408 | << timer.timing(hand_coded_differentiator.adjoint_compute_timer_id()) 409 | / base_time << "\n"; 410 | std::cout << " Absolute time of Jacobian: " 411 | << timer.timing(hand_coded_differentiator.jacobian_timer_id()) 412 | << " s\n"; 413 | std::cout << " Relative time of Jacobian: " 414 | << timer.timing(hand_coded_differentiator.jacobian_timer_id()) 415 | / base_time << "\n"; 416 | } 417 | 418 | for (int itool = 0; itool < N_AUTODIFF_TOOLS; itool++) { 419 | if (use_tool[itool]) { 420 | Differentiator* differentiator 421 | = new_differentiator(static_cast(itool), 422 | timer, algorithm_string); 423 | if (!differentiator) { 424 | if (verbose) std::cout << "Automatic differentiation tool with code " << itool << " not available\n"; 425 | continue; 426 | } 427 | 428 | differentiator->initialize(nt, dt); 429 | if (no_openmp) { 430 | differentiator->no_openmp(); 431 | } 432 | 433 | std::cout << " " << differentiator->name() << "\n"; 434 | 435 | for (int i = 0; i < nr_warm_up; i++) { 436 | differentiator->adjoint(ta, q_init, q, q_AD, q_init_AD); 437 | } 438 | double rms_verify = rms(q_init_AD, q_init_AD_reference); 439 | if (rms_verify > tolerance) { 440 | std::cout << " *** Adjoint RMS difference with hand-coded of " << rms_verify << " is greater than tolerance of " << tolerance << " ***\n"; 441 | verify_error = true; 442 | if (print_adjoint) { 443 | std::cout << "adjoint_auto = [" << q_init_AD[0]; 444 | for (int i = 1; i < NX; i++) { 445 | std::cout << ", " << q_init_AD[i]; 446 | } 447 | std::cout << "]\n"; 448 | } 449 | } 450 | else { 451 | std::cout << " Adjoint agrees with hand-coding within tolerance of " << tolerance << "\n"; 452 | } 453 | 454 | for (int i = 0; i < nr_jacobian_warm_up; i++) { 455 | differentiator->jacobian(ta, q_init, q, jac, force_jacobian); 456 | } 457 | rms_verify = rms(jac, jac_reference); 458 | if (rms_verify > tolerance) { 459 | std::cout << " *** Jacobian RMS difference with hand-coded of " << rms_verify << " is greater than tolerance of " << tolerance << " ***\n"; 460 | verify_error = true; 461 | } 462 | else { 463 | std::cout << " Jacobian agrees with hand-coding within tolerance of " << tolerance << "\n"; 464 | } 465 | 466 | 467 | if (!verify_only) { 468 | differentiator->reset_timings(); 469 | for (int i = 0; i < nr; i++) { 470 | differentiator->adjoint(ta, q_init, q, q_AD, q_init_AD); 471 | } 472 | 473 | double relative_record_time = timer.timing(differentiator->base_timer_id()) 474 | / base_time; 475 | double relative_adjoint_time 476 | = timer.timing(differentiator->adjoint_compute_timer_id()) 477 | / base_time; 478 | double relative_adjoint_prep_time 479 | = timer.timing(differentiator->adjoint_prep_timer_id()) 480 | / base_time; 481 | 482 | std::cout << " Absolute time of adjoint: " 483 | << timer.timing(differentiator->base_timer_id()) 484 | + timer.timing(differentiator->adjoint_compute_timer_id()) 485 | + timer.timing(differentiator->adjoint_prep_timer_id()) 486 | << " s (" 487 | << timer.timing(differentiator->base_timer_id()) 488 | << " s + "; 489 | if (relative_adjoint_prep_time > 0.0) { 490 | std::cout << timer.timing(differentiator->adjoint_prep_timer_id()) 491 | << " s + "; 492 | } 493 | std::cout << timer.timing(differentiator->adjoint_compute_timer_id()) 494 | << " s)\n"; 495 | std::cout << " Relative time of adjoint: " 496 | << relative_record_time + relative_adjoint_prep_time 497 | + relative_adjoint_time 498 | << " (" << relative_record_time << " + "; 499 | if (relative_adjoint_prep_time > 0.0) { 500 | std::cout << relative_adjoint_prep_time << " + "; 501 | } 502 | std::cout << relative_adjoint_time << ")\n"; 503 | differentiator->reset_timings(); 504 | } 505 | 506 | for (int i = 0; i < nr_jacobian; i++) { 507 | differentiator->jacobian(ta, q_init, q, jac, force_jacobian); 508 | } 509 | 510 | if (print_jacobian) { 511 | double (&q_K)[NX][NX] 512 | = *reinterpret_cast(&jac[0]); 513 | std::cout << "jacobian_auto = [\n"; 514 | for (int i = 0; i < NX; i++) { 515 | std::cout << q_K[i][0]; 516 | for (int j = 1; j < NX; j++) { 517 | std::cout << ", " << q_K[i][j]; 518 | } 519 | std::cout << "\n"; 520 | } 521 | std::cout << "]\n"; 522 | } 523 | 524 | if (!verify_only) { 525 | double relative_record_time = (nr*timer.timing(differentiator->base_timer_id())) 526 | /(nr_jacobian*base_time); 527 | double relative_jacobian_time = (nr*timer.timing(differentiator->jacobian_timer_id())) 528 | /(nr_jacobian*base_time); 529 | double relative_adjoint_prep_time = (nr*timer.timing(differentiator->adjoint_prep_timer_id())) 530 | /(nr_jacobian*base_time); 531 | std::cout << " Absolute time of Jacobian: " 532 | << timer.timing(differentiator->base_timer_id()) 533 | + timer.timing(differentiator->adjoint_prep_timer_id()) 534 | + timer.timing(differentiator->jacobian_timer_id()) 535 | << " s (" 536 | << timer.timing(differentiator->base_timer_id()) 537 | << " s + "; 538 | if (relative_adjoint_prep_time > 0.0) { 539 | std::cout << timer.timing(differentiator->adjoint_prep_timer_id()) 540 | << " s + "; 541 | } 542 | std::cout << timer.timing(differentiator->jacobian_timer_id()) 543 | << " s)\n"; 544 | std::cout << " Relative time of Jacobian: " 545 | << relative_record_time + relative_adjoint_prep_time + relative_jacobian_time 546 | << " (" << relative_record_time << " + "; 547 | if (relative_adjoint_prep_time > 0.0) { 548 | std::cout << relative_adjoint_prep_time << " + "; 549 | } 550 | std::cout << relative_jacobian_time << ")\n"; 551 | } 552 | 553 | delete differentiator; 554 | } 555 | } 556 | } 557 | } 558 | if (verify_error) { 559 | std::cout << "\nEXITING WITH ERROR CODE 1: ONE OR MORE OF THE AUTOMATIC DIFFERENTIATION\n" 560 | << "TOOLS DID NOT REPRODUCE THE HAND-CODING RESULT\n"; 561 | return 1; 562 | } 563 | else { 564 | std::cout << "\nAll tests were passed within tolerance\n"; 565 | return 1; 566 | } 567 | } 568 | 569 | -------------------------------------------------------------------------------- /benchmark/differentiator.h: -------------------------------------------------------------------------------- 1 | /* differentiator.h 2 | 3 | Copyright (C) 2014 The University of Reading 4 | 5 | Copying and distribution of this file, with or without modification, 6 | are permitted in any medium without royalty provided the copyright 7 | notice and this notice are preserved. This file is offered as-is, 8 | without any warranty. 9 | */ 10 | 11 | #ifdef HAVE_CONFIG_H 12 | #include "config.h" 13 | #endif 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "Timer.h" 22 | 23 | #include "adept.h" 24 | 25 | #ifdef HAVE_ADOLC 26 | #include "adolc/adolc.h" 27 | #endif 28 | 29 | #ifdef HAVE_CPPAD 30 | #include "cppad/cppad.hpp" 31 | #endif 32 | 33 | #ifdef HAVE_SACADO 34 | #include "Sacado.hpp" 35 | #endif 36 | 37 | #include "advection_schemes.h" 38 | #include "advection_schemes_AD.h" 39 | #include "advection_schemes_K.h" 40 | 41 | 42 | enum TestAlgorithm { 43 | TEST_ALGORITHM_LAX_WENDROFF = 0, 44 | TEST_ALGORITHM_TOON = 1, 45 | N_TEST_ALGORITHMS 46 | }; 47 | 48 | const char* test_algorithm_long_string[] = {"Lax-Wendroff", "Toon et al."}; 49 | const char* test_algorithm_string[] = {"lw","toon"}; 50 | 51 | inline 52 | std::string 53 | test_algorithms() 54 | { 55 | std::string algs = test_algorithm_string[0]; 56 | for (int i = 1; i < N_TEST_ALGORITHMS; i++) { 57 | algs += ","; 58 | algs += test_algorithm_string[i]; 59 | } 60 | return algs; 61 | } 62 | 63 | 64 | class differentiator_exception : public std::exception { 65 | public: 66 | differentiator_exception(const char* message = "An error occurred in differentiator.h") 67 | { message_ = message; } 68 | virtual const char* what() const throw() 69 | { return message_; } 70 | protected: 71 | const char* message_; 72 | }; 73 | 74 | class Differentiator { 75 | public: 76 | Differentiator(Timer& timer) 77 | : timer_(timer) { 78 | initialize(2000, 0.125); 79 | } 80 | 81 | virtual ~Differentiator() { } 82 | 83 | void initialize(int nt, double c) { 84 | nt_ = nt; 85 | c_ = c; 86 | } 87 | 88 | template 89 | void func(TestAlgorithm test_algorithm, 90 | const std::vector& x, 91 | std::vector& y) { 92 | timer_.start(base_timer_id_); 93 | if (test_algorithm == TEST_ALGORITHM_LAX_WENDROFF) { 94 | lax_wendroff(nt_, c_, &x[0], &y[0]); 95 | } 96 | else if (test_algorithm == TEST_ALGORITHM_TOON) { 97 | toon(nt_, c_, &x[0], &y[0]); 98 | } 99 | timer_.stop(); 100 | } 101 | 102 | virtual bool adjoint(TestAlgorithm test_algorithm, 103 | const std::vector& x, 104 | std::vector& y, 105 | const std::vector& y_AD, 106 | std::vector& x_AD) { 107 | return false; 108 | } 109 | 110 | virtual bool jacobian(TestAlgorithm test_algorithm, 111 | const std::vector& x, 112 | std::vector& y, 113 | std::vector& jac, 114 | int force_jacobian = 0) { 115 | return false; 116 | } 117 | 118 | void reset_timings() { 119 | timer_.reset(base_timer_id_); 120 | timer_.reset(adjoint_prep_timer_id_); 121 | timer_.reset(adjoint_compute_timer_id_); 122 | timer_.reset(jacobian_timer_id_); 123 | } 124 | 125 | virtual std::string name() const = 0; //{ return "GENERIC"; } 126 | 127 | virtual void no_openmp() { } 128 | 129 | int base_timer_id() const { return base_timer_id_; } 130 | int adjoint_prep_timer_id() const { return adjoint_prep_timer_id_; } 131 | int adjoint_compute_timer_id() const { return adjoint_compute_timer_id_; } 132 | int jacobian_timer_id() const { return jacobian_timer_id_; } 133 | 134 | protected: 135 | void init_timer(const std::string name_) { 136 | base_timer_id_ = timer_.new_activity(name() + " | " + name_ + " | record"); 137 | adjoint_prep_timer_id_ = timer_.new_activity(name() + " | " + name_ + " | adjoint prep"); 138 | adjoint_compute_timer_id_ = timer_.new_activity(name() + " | " + name_ + " | adjoint compute"); 139 | jacobian_timer_id_ = timer_.new_activity(name() + " | " + name_ + " | Jacobian"); 140 | } 141 | 142 | protected: 143 | Timer& timer_; 144 | int nt_; // Number of timesteps to run 145 | double c_; // Courant number 146 | int base_timer_id_; 147 | int adjoint_prep_timer_id_; 148 | int adjoint_compute_timer_id_; 149 | int jacobian_timer_id_; 150 | }; 151 | 152 | // ================= HAND CODED =========================== 153 | #include "advection_schemes_AD.h" 154 | 155 | class HandCodedDifferentiator 156 | : public Differentiator { 157 | public: 158 | HandCodedDifferentiator(Timer& timer, const std::string& name_) 159 | : Differentiator(timer) { 160 | init_timer(name_); 161 | } 162 | 163 | virtual bool adjoint(TestAlgorithm test_algorithm, 164 | const std::vector& x, 165 | std::vector& y, 166 | const std::vector& y_AD, 167 | std::vector& x_AD) { 168 | if (test_algorithm == TEST_ALGORITHM_LAX_WENDROFF) { 169 | timer_.start(adjoint_compute_timer_id_); 170 | lax_wendroff_AD(nt_, c_, &x[0], &y[0], &y_AD[0], &x_AD[0]); 171 | timer_.stop(); 172 | } 173 | else if (test_algorithm == TEST_ALGORITHM_TOON) { 174 | timer_.start(adjoint_compute_timer_id_); 175 | toon_AD(nt_, c_, &x[0], &y[0], &y_AD[0], &x_AD[0]); 176 | timer_.stop(); 177 | } 178 | else { 179 | std::cerr << "Algorithm not found: " << test_algorithm << "\n"; 180 | return false; 181 | } 182 | return true; 183 | } 184 | 185 | virtual bool jacobian(TestAlgorithm test_algorithm, 186 | const std::vector& x, 187 | std::vector& y, 188 | std::vector& jac, 189 | int force_jacobian = 0) { 190 | jac.resize(NX*NX); 191 | if (test_algorithm == TEST_ALGORITHM_LAX_WENDROFF) { 192 | timer_.start(jacobian_timer_id_); 193 | lax_wendroff_K(nt_, c_, &x[0], &y[0], &jac[0]); 194 | timer_.stop(); 195 | } 196 | else if (test_algorithm == TEST_ALGORITHM_TOON) { 197 | timer_.start(jacobian_timer_id_); 198 | toon_K(nt_, c_, &x[0], &y[0], &jac[0]); 199 | timer_.stop(); 200 | } 201 | else { 202 | std::cerr << "Algorithm not found: " << test_algorithm << "\n"; 203 | return false; 204 | } 205 | return true; 206 | } 207 | 208 | virtual std::string name() const { return "Hand coded"; } 209 | }; 210 | 211 | 212 | 213 | // ================= ADEPT ================================ 214 | 215 | class AdeptDifferentiator 216 | : public Differentiator { 217 | public: 218 | AdeptDifferentiator(Timer& timer, const std::string& name_) 219 | : Differentiator(timer) { init_timer(name_); } 220 | 221 | virtual ~AdeptDifferentiator() { } 222 | 223 | virtual bool adjoint(TestAlgorithm test_algorithm, 224 | const std::vector& x, 225 | std::vector& y, 226 | const std::vector& y_AD, 227 | std::vector& x_AD) { 228 | if (x.size() != NX || y_AD.size() != NX) { 229 | throw differentiator_exception("One of input vectors not of size NX in call to AdeptDifferentiator::adjoint"); 230 | } 231 | y.resize(NX); 232 | x_AD.resize(NX); 233 | 234 | std::vector q_init(NX); 235 | std::vector q(NX); 236 | 237 | adept::set_values(&q_init[0], NX, &x[0]); 238 | 239 | stack_.new_recording(); 240 | func(test_algorithm, q_init, q); 241 | 242 | timer_.start(adjoint_compute_timer_id_); 243 | 244 | adept::set_gradients(&q[0], NX, &y_AD[0]); 245 | stack_.compute_adjoint(); 246 | adept::get_gradients(&q_init[0], NX, &x_AD[0]); 247 | 248 | timer_.stop(); 249 | 250 | return true; 251 | } 252 | 253 | 254 | virtual bool jacobian(TestAlgorithm test_algorithm, 255 | const std::vector& x, 256 | std::vector& y, 257 | std::vector& jac, 258 | int force_jacobian = 0) { 259 | if (x.size() != NX) { 260 | throw differentiator_exception("Input vector x not of size NX in call to AdeptDifferentiator::jacobian"); 261 | } 262 | y.resize(NX); 263 | jac.resize(NX*NX); 264 | 265 | std::vector q_init(NX); 266 | std::vector q(NX); 267 | 268 | adept::set_values(&q_init[0], NX, &x[0]); 269 | 270 | stack_.new_recording(); 271 | func(test_algorithm, q_init, q); 272 | 273 | stack_.independent(&q_init[0], NX); 274 | stack_.dependent(&q[0], NX); 275 | 276 | timer_.start(jacobian_timer_id_); 277 | if (force_jacobian > 0) { 278 | stack_.jacobian_forward(&jac[0]); 279 | } 280 | else if (force_jacobian < 0) { 281 | stack_.jacobian_reverse(&jac[0]); 282 | } 283 | else { 284 | stack_.jacobian(&jac[0]); 285 | } 286 | timer_.stop(); 287 | return true; 288 | } 289 | 290 | virtual std::string name() const { 291 | std::stringstream name_; 292 | name_ << "Adept"; 293 | int nthread = stack_.max_jacobian_threads(); 294 | if (nthread > 1) { 295 | name_ << " (Jacobian using up to " << nthread << " OpenMP threads)"; 296 | } 297 | else { 298 | name_ << " (single threaded)"; 299 | } 300 | return name_.str(); 301 | } 302 | 303 | virtual void no_openmp() { 304 | stack_.set_max_jacobian_threads(1); 305 | } 306 | 307 | private: 308 | adept::Stack stack_; 309 | }; 310 | 311 | 312 | 313 | #ifdef HAVE_ADOLC 314 | 315 | // ================= ADOLC ================================ 316 | 317 | class AdolcDifferentiator 318 | : public Differentiator { 319 | public: 320 | AdolcDifferentiator(Timer& timer, const std::string& name_) 321 | : Differentiator(timer), jac(0), I(0), result(0) { init_timer(name_); } 322 | 323 | virtual ~AdolcDifferentiator() { 324 | if (I) { 325 | myfreeI2(NX, I); 326 | } 327 | if (jac) { 328 | myfree2(jac); 329 | } 330 | if (result) { 331 | myfree1(result); 332 | } 333 | } 334 | 335 | virtual bool adjoint(TestAlgorithm test_algorithm, 336 | const std::vector& x, 337 | std::vector& y, 338 | const std::vector& y_AD, 339 | std::vector& x_AD) { 340 | if (x.size() != NX || y_AD.size() != NX) { 341 | throw differentiator_exception("One of input vectors not of size NX in call to AdolcDifferentiator::adjoint"); 342 | } 343 | y.resize(NX); 344 | x_AD.resize(NX); 345 | 346 | std::vector q_init(NX); 347 | std::vector q(NX); 348 | 349 | trace_on(1,1); 350 | 351 | for (int i = 0; i < NX; i++) { 352 | q_init[i] <<= x[i]; 353 | } 354 | 355 | func(test_algorithm, q_init, q); 356 | 357 | for (int i = 0; i < NX; i++) { 358 | q[i] >>= y[i]; 359 | } 360 | 361 | trace_off(); 362 | 363 | timer_.start(adjoint_compute_timer_id_); 364 | 365 | reverse(1, NX, NX, 0, const_cast(&y_AD[0]), &x_AD[0]); 366 | 367 | timer_.stop(); 368 | return true; 369 | } 370 | 371 | 372 | virtual bool jacobian(TestAlgorithm test_algorithm, 373 | const std::vector& x, 374 | std::vector& y, 375 | std::vector& jac_, 376 | int force_jacobian = 0) { 377 | if (x.size() != NX) { 378 | throw differentiator_exception("Input vector x not of size NX in call to AdolcDifferentiator::jacobian"); 379 | } 380 | y.resize(NX); 381 | jac_.resize(NX*NX); 382 | 383 | std::vector q_init(NX); 384 | std::vector q(NX); 385 | 386 | trace_on(1,1); 387 | 388 | for (int i = 0; i < NX; i++) { 389 | q_init[i] <<= x[i]; 390 | } 391 | 392 | func(test_algorithm, q_init, q); 393 | 394 | for (int i = 0; i < NX; i++) { 395 | q[i] >>= y[i]; 396 | } 397 | 398 | trace_off(); 399 | 400 | if (!jac) { 401 | jac = myalloc2(NX,NX); 402 | I = myallocI2(NX); 403 | result = myalloc1(NX); 404 | } 405 | 406 | timer_.start(jacobian_timer_id_); 407 | 408 | if (force_jacobian < 0) { 409 | int rc = zos_forward(1, NX, NX, 1, &x[0], result); 410 | if (rc < 0) { 411 | throw differentiator_exception("Error occurred ADOL-C's zos_forward()"); 412 | } 413 | MINDEC(rc,fov_reverse(1, NX, NX, NX, I, jac)); 414 | } 415 | else if (force_jacobian > 0) { 416 | int rc = fov_forward(1, NX, NX, NX, &x[0], I, result, jac); 417 | if (rc < 0) { 418 | throw differentiator_exception("Error occurred ADOL-C's fov_forward()"); 419 | } 420 | } 421 | else { 422 | ::jacobian(1, NX, NX, &x[0], jac); 423 | } 424 | 425 | timer_.stop(); 426 | 427 | for (int j=0, index=0; j < NX; j++) { 428 | for (int i=0; i < NX; i++, index++) { 429 | jac_[index] = jac[i][j]; 430 | } 431 | } 432 | return true; 433 | } 434 | 435 | virtual std::string name() const { return "ADOL-C"; } 436 | 437 | private: 438 | double** jac; 439 | double** I; 440 | double* result; 441 | }; 442 | 443 | #endif // HAVE_ADOLC 444 | 445 | 446 | #ifdef HAVE_CPPAD 447 | 448 | // ================= CPPAD ================================ 449 | 450 | class CppadDifferentiator 451 | : public Differentiator { 452 | public: 453 | typedef CppAD::AD adouble; 454 | 455 | CppadDifferentiator(Timer& timer, const std::string& name_) 456 | : Differentiator(timer) { 457 | init_timer(name_); 458 | CppAD::thread_alloc::hold_memory(true); 459 | } 460 | 461 | virtual ~CppadDifferentiator() { } 462 | 463 | virtual bool adjoint(TestAlgorithm test_algorithm, 464 | const std::vector& x, 465 | std::vector& y, 466 | const std::vector& y_AD, 467 | std::vector& x_AD) { 468 | if (x.size() != NX || y_AD.size() != NX) { 469 | throw differentiator_exception("One of input vectors not of size NX in call to CppadDifferentiator::adjoint"); 470 | } 471 | y.resize(NX); 472 | x_AD.resize(NX); 473 | 474 | std::vector q_init(NX); 475 | std::vector q(NX); 476 | 477 | for (int i = 0; i < NX; i++) { 478 | q_init[i] = x[i]; 479 | } 480 | 481 | CppAD::Independent(q_init); 482 | 483 | func(test_algorithm, q_init, q); 484 | 485 | for (int i = 0; i < NX; i++) { 486 | y[i] = CppAD::Value(q[i]); 487 | } 488 | 489 | timer_.start(adjoint_prep_timer_id_); 490 | CppAD::ADFun f(q_init, q); 491 | 492 | timer_.start(adjoint_compute_timer_id_); 493 | x_AD = f.Reverse(1, y_AD); 494 | timer_.stop(); 495 | 496 | return true; 497 | } 498 | 499 | virtual bool jacobian(TestAlgorithm test_algorithm, 500 | const std::vector& x, 501 | std::vector& y, 502 | std::vector& jac, 503 | int force_jacobian = 0) { 504 | if (x.size() != NX) { 505 | throw differentiator_exception("Input vector x not of size NX in call to CppadDifferentiator::jacobian"); 506 | } 507 | y.resize(NX); 508 | jac.resize(NX*NX); 509 | jac_transpose_.resize(NX*NX); 510 | 511 | std::vector q_init(NX); 512 | std::vector q(NX); 513 | 514 | for (int i = 0; i < NX; i++) { 515 | q_init[i] = x[i]; 516 | } 517 | 518 | CppAD::Independent(q_init); 519 | 520 | func(test_algorithm, q_init, q); 521 | 522 | for (int i = 0; i < NX; i++) { 523 | y[i] = CppAD::Value(q[i]); 524 | } 525 | 526 | timer_.start(adjoint_prep_timer_id_); 527 | CppAD::ADFun f(q_init, q); 528 | 529 | timer_.start(jacobian_timer_id_); 530 | 531 | if (force_jacobian < 0) { 532 | CppAD::JacobianRev(f, x, jac_transpose_); 533 | } 534 | else if (force_jacobian > 0) { 535 | CppAD::JacobianFor(f, x, jac_transpose_); 536 | } 537 | else { 538 | jac_transpose_ = f.Jacobian(x); 539 | } 540 | 541 | // Transpose Jacobian because CppAD uses the opposite convention to the other tools 542 | double (&jac_transpose2)[NX][NX] 543 | = *reinterpret_cast(&jac_transpose_[0]); 544 | for (int i = 0, index = 0; i < NX; i++) { 545 | for (int j = 0; j < NX; j++, index++) { 546 | jac[index] = jac_transpose2[j][i]; 547 | } 548 | } 549 | 550 | return true; 551 | } 552 | 553 | virtual std::string name() const { return "CppAD"; } 554 | 555 | private: 556 | std::vector jac_transpose_; 557 | }; 558 | 559 | #endif // HAVE_CPPAD 560 | 561 | 562 | #ifdef HAVE_SACADO 563 | 564 | // ================= SACADO ================================ 565 | 566 | template<> int Sacado::Rad::ADmemblock::n_blocks = 0; 567 | 568 | class SacadoDifferentiator 569 | : public Differentiator { 570 | public: 571 | typedef Sacado::Rad::ADvar adouble; 572 | typedef Sacado::ELRFad::DFad adouble_fad; 573 | 574 | SacadoDifferentiator(Timer& timer, const std::string& name_) 575 | : Differentiator(timer) { init_timer(name_); } 576 | 577 | virtual ~SacadoDifferentiator() { } 578 | 579 | virtual bool adjoint(TestAlgorithm test_algorithm, 580 | const std::vector& x, 581 | std::vector& y, 582 | const std::vector& y_AD, 583 | std::vector& x_AD) { 584 | if (x.size() != NX || y_AD.size() != NX) { 585 | throw differentiator_exception("One of input vectors not of size NX in call to SacadoDifferentiator::adjoint"); 586 | } 587 | y.resize(NX); 588 | x_AD.resize(NX); 589 | 590 | std::vector q_init(NX); 591 | std::vector q(NX); 592 | 593 | for (int i = 0; i < NX; i++) { 594 | q_init[i] = x[i]; 595 | } 596 | 597 | func(test_algorithm, q_init, q); 598 | 599 | for (int i = 0; i < NX; i++) { 600 | y[i] = q[i].val(); 601 | } 602 | 603 | timer_.start(base_timer_id_); 604 | adouble objective_func = 0.0; 605 | for (int i = 0; i < NX; i++) { 606 | objective_func += q[i] * y_AD[i]; 607 | } 608 | 609 | timer_.start(adjoint_compute_timer_id_); 610 | Sacado::Rad::ADvar::Gradcomp(); 611 | for (int i = 0; i < NX; i++) { 612 | x_AD[i] = q_init[i].adj(); 613 | } 614 | timer_.stop(); 615 | 616 | return true; 617 | } 618 | 619 | 620 | virtual bool jacobian(TestAlgorithm test_algorithm, 621 | const std::vector& x, 622 | std::vector& y, 623 | std::vector& jac, 624 | int force_jacobian = 0) { 625 | if (x.size() != NX) { 626 | throw differentiator_exception("Input vector x not of size NX in call to SacadoDifferentiator::jacobian"); 627 | } 628 | y.resize(NX); 629 | jac.resize(NX*NX); 630 | 631 | std::vector q_init(NX); 632 | std::vector q(NX); 633 | 634 | for (int i = 0; i < NX; i++) { 635 | q_init[i] = x[i]; 636 | q_init[i].resize(NX); 637 | q[i].resize(NX); 638 | q_init[i].fastAccessDx(i) = 1.0; 639 | } 640 | 641 | func(test_algorithm, q_init, q); 642 | 643 | for (int i = 0; i < NX; i++) { 644 | y[i] = q[i].val(); 645 | } 646 | 647 | int index = 0; 648 | for (int i = 0; i < NX; i++) { 649 | for (int k = 0; k < NX; k++, index++) { 650 | jac[index] = q[k].dx(i); 651 | } 652 | } 653 | return true; 654 | } 655 | 656 | virtual std::string name() const { return "Sacado (::Rad for adjoint, forward-mode only ::ELRFad for Jacobian)"; } 657 | }; 658 | 659 | #endif // HAVE_SACADO 660 | 661 | 662 | 663 | 664 | // The following enum is designed to be used in a "for" loop to loop 665 | // through the available automatic differentiaion tools 666 | enum AutoDiffTool { 667 | AUTODIFF_TOOL_ADEPT = 0 668 | #ifdef HAVE_ADOLC 669 | , AUTODIFF_TOOL_ADOLC 670 | #endif 671 | #ifdef HAVE_CPPAD 672 | , AUTODIFF_TOOL_CPPAD 673 | #endif 674 | #ifdef HAVE_SACADO 675 | , AUTODIFF_TOOL_SACADO 676 | #endif 677 | , N_AUTODIFF_TOOLS 678 | }; 679 | 680 | const char* autodiff_tool_string[] = { 681 | "adept" 682 | #ifdef HAVE_ADOLC 683 | , "adolc" 684 | #endif 685 | #ifdef HAVE_CPPAD 686 | , "cppad" 687 | #endif 688 | #ifdef HAVE_SACADO 689 | , "sacado" 690 | #endif 691 | }; 692 | 693 | const char* autodiff_tool_long_string[] = { 694 | "Adept" 695 | #ifdef HAVE_ADOLC 696 | , "ADOL-C" 697 | #endif 698 | #ifdef HAVE_CPPAD 699 | , "CppAD" 700 | #endif 701 | #ifdef HAVE_SACADO 702 | , "Sacado" 703 | #endif 704 | }; 705 | 706 | inline 707 | std::string 708 | autodiff_tools() 709 | { 710 | std::string tools = autodiff_tool_string[0]; 711 | for (int i = 1; i < N_AUTODIFF_TOOLS; i++) { 712 | tools += ","; 713 | tools += autodiff_tool_string[i]; 714 | } 715 | return tools; 716 | } 717 | 718 | 719 | // Return pointer to a virtual base object Differentiator 720 | inline 721 | Differentiator* 722 | new_differentiator(AutoDiffTool auto_diff_tool, Timer& timer, const std::string& name_) 723 | { 724 | if (auto_diff_tool == AUTODIFF_TOOL_ADEPT) { 725 | return new AdeptDifferentiator(timer, name_); 726 | } 727 | #ifdef HAVE_ADOLC 728 | else if (auto_diff_tool == AUTODIFF_TOOL_ADOLC) { 729 | return new AdolcDifferentiator(timer, name_); 730 | } 731 | #endif 732 | #ifdef HAVE_CPPAD 733 | else if (auto_diff_tool == AUTODIFF_TOOL_CPPAD) { 734 | return new CppadDifferentiator(timer, name_); 735 | } 736 | #endif 737 | #ifdef HAVE_SACADO 738 | else if (auto_diff_tool == AUTODIFF_TOOL_SACADO) { 739 | return new SacadoDifferentiator(timer, name_); 740 | } 741 | #endif 742 | else { 743 | return 0; 744 | } 745 | } 746 | -------------------------------------------------------------------------------- /benchmark/nx.h: -------------------------------------------------------------------------------- 1 | #ifndef NX 2 | #define NX 100 3 | #endif 4 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ([2.63]) 5 | AC_INIT([adept], [1.1], [r.j.hogan@reading.ac.uk]) 6 | 7 | AC_LANG([C++]) 8 | 9 | AC_CONFIG_SRCDIR([adept/adept.cpp]) 10 | AC_CONFIG_HEADERS([config.h]) 11 | 12 | AM_INIT_AUTOMAKE([-Wall -Wno-error]) 13 | AC_CONFIG_MACRO_DIR([m4]) 14 | 15 | # Checks for programs. 16 | AC_PROG_CXX 17 | AC_PROG_MAKE_SET 18 | m4_ifdef([AM_PROG_AR],[AM_PROG_AR]) 19 | AC_PROG_LIBTOOL 20 | 21 | # Checks for libraries. 22 | AC_CHECK_LIB([m],[cos]) 23 | AC_CHECK_LIB([gsl],[gsl_multimin_fdfminimizer_alloc]) 24 | AC_CHECK_LIB([adolc],[tapestats]) 25 | 26 | # Check for OpenMP 27 | AC_OPENMP 28 | AC_SUBST(AM_CXXFLAGS,"$OPENMP_CXXFLAGS") 29 | 30 | # Test program to see if Sacado is working 31 | ac_have_sacado=no 32 | save_LIBS=$LIBS 33 | LIBS="$LIBS -lsacado -lteuchos" 34 | AC_MSG_CHECKING([whether Sacado is installed]) 35 | AC_TRY_LINK([#include ], 36 | [Sacado::ELRFad::DFad v = 1.0; return 0;], 37 | [ac_have_sacado=yes 38 | AC_MSG_RESULT(yes) 39 | AC_DEFINE([HAVE_SACADO],1,[Is the Sacado library working?])], 40 | [LIBS=$save_LIBS 41 | AC_MSG_RESULT(no)]) 42 | 43 | # Checks for header files. 44 | AC_CHECK_HEADERS([sys/time.h]) 45 | AC_CHECK_HEADERS([cppad/cppad.hpp]) 46 | AC_CHECK_HEADERS([adolc/adolc.h]) 47 | 48 | if test "$ac_cv_header_cppad_cppad_hpp" = yes 49 | then 50 | AC_DEFINE([NDEBUG],1,[If CppAD is being used by the benchmarking program then it is much faster with debugging disabled]) 51 | fi 52 | 53 | # Checks for typedefs, structures, and compiler characteristics. 54 | AC_TYPE_SIZE_T 55 | 56 | # Checks for library functions. 57 | AC_CHECK_FUNCS([gettimeofday pow sqrt]) 58 | 59 | AC_CONFIG_FILES([Makefile makefile_include adept/Makefile include/Makefile benchmark/Makefile doc/Makefile]) 60 | 61 | AC_MSG_NOTICE([********************* Summary **************************************]) 62 | AC_MSG_NOTICE([Compiling with: $CXX $CPPFLAGS $CXXFLAGS $OPENMP_CXXFLAGS]) 63 | AC_MSG_NOTICE([Linker options: $LDFLAGS $LIBS $OPENMP_CXXFLAGS]) 64 | AC_MSG_NOTICE([Typing "make; make install" will install $includedir/adept.h]) 65 | AC_MSG_NOTICE([and the static and shared libraries as $libdir/libadept.*]) 66 | AC_MSG_NOTICE([********************* Example programs *****************************]) 67 | 68 | ac_warn_given=no 69 | if test "$ac_cv_lib_gsl_gsl_multimin_fdfminimizer_alloc" = no 70 | then 71 | AC_MSG_NOTICE([GNU Scientific Library (GSL) not found; Adept will compile all the]) 72 | AC_MSG_NOTICE([example programs except test/test_gsl_interface.]) 73 | ac_warn_given=yes 74 | else 75 | AC_MSG_NOTICE([GNU Scientific Library (GSL) found; Adept will compile all the]) 76 | AC_MSG_NOTICE([example programs.]) 77 | fi 78 | AC_SUBST([USE_GSL], ["$ac_cv_lib_gsl_gsl_multimin_fdfminimizer_alloc"]) 79 | 80 | 81 | AC_MSG_NOTICE([********************* Benchmark program ****************************]) 82 | AC_MSG_NOTICE([The benchmarking program, "benchmark/advection_benchmark", will be]) 83 | AC_MSG_NOTICE([compiled with support for these automatic differentiation libraries:]) 84 | AC_MSG_NOTICE([ Adept: yes]) 85 | 86 | if test "$ac_cv_lib_adolc_tapestats" = yes -a "$ac_cv_header_adolc_adolc_h" = yes 87 | then 88 | AC_MSG_NOTICE([ ADOLC: yes]) 89 | else 90 | AC_MSG_NOTICE([ ADOLC: no]) 91 | ac_warn_given=yes 92 | fi 93 | 94 | if test "$ac_cv_header_cppad_cppad_hpp" = yes 95 | then 96 | AC_MSG_NOTICE([ CppAD: yes]) 97 | else 98 | AC_MSG_NOTICE([ CppAD: no]) 99 | ac_warn_given=yes 100 | fi 101 | 102 | if test "$ac_have_sacado" = no 103 | then 104 | AC_MSG_NOTICE([ Sacado: no]) 105 | ac_warn_given=yes 106 | else 107 | AC_MSG_NOTICE([ Sacado: yes]) 108 | fi 109 | 110 | AC_MSG_NOTICE([********************* Top tips *************************************]) 111 | AC_MSG_NOTICE([To use a higher than default optimization level, call this script]) 112 | AC_MSG_NOTICE([with something like:]) 113 | AC_MSG_NOTICE([ ./configure "CXXFLAGS=-g -O3"]) 114 | if test "$ac_warn_given" = yes 115 | then 116 | AC_MSG_NOTICE([If you have some of the missing libraries, specify their location]) 117 | AC_MSG_NOTICE([by calling this script with something like:]) 118 | AC_MSG_NOTICE([ ./configure CPPFLAGS=-I/home/user/include LDFLAGS=-L/home/user/lib]) 119 | fi 120 | AC_MSG_NOTICE([********************************************************************]) 121 | 122 | AC_DEFINE_UNQUOTED([CXX],["$CXX"],[C++ compiler]) 123 | AC_DEFINE_UNQUOTED([CXXFLAGS],["$CXXFLAGS"],[Flags passed to C++ compiler]) 124 | 125 | AH_BOTTOM([/* Use ADOLC only if both the library and the header files are available */ 126 | #if defined( HAVE_LIBADOLC ) && defined( HAVE_ADOLC_ADOLC_H ) 127 | #define HAVE_ADOLC 1 128 | #endif]) 129 | AH_BOTTOM([/* Use CPPAD if the header files are available */ 130 | #if defined( HAVE_CPPAD_CPPAD_HPP ) 131 | #define HAVE_CPPAD 1 132 | #endif]) 133 | 134 | 135 | AC_OUTPUT 136 | -------------------------------------------------------------------------------- /doc/COPYING: -------------------------------------------------------------------------------- 1 | 2 | GNU Free Documentation License 3 | Version 1.3, 3 November 2008 4 | 5 | 6 | Copyright (C) 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. 7 | 8 | Everyone is permitted to copy and distribute verbatim copies 9 | of this license document, but changing it is not allowed. 10 | 11 | 0. PREAMBLE 12 | 13 | The purpose of this License is to make a manual, textbook, or other 14 | functional and useful document "free" in the sense of freedom: to 15 | assure everyone the effective freedom to copy and redistribute it, 16 | with or without modifying it, either commercially or noncommercially. 17 | Secondarily, this License preserves for the author and publisher a way 18 | to get credit for their work, while not being considered responsible 19 | for modifications made by others. 20 | 21 | This License is a kind of "copyleft", which means that derivative 22 | works of the document must themselves be free in the same sense. It 23 | complements the GNU General Public License, which is a copyleft 24 | license designed for free software. 25 | 26 | We have designed this License in order to use it for manuals for free 27 | software, because free software needs free documentation: a free 28 | program should come with manuals providing the same freedoms that the 29 | software does. But this License is not limited to software manuals; 30 | it can be used for any textual work, regardless of subject matter or 31 | whether it is published as a printed book. We recommend this License 32 | principally for works whose purpose is instruction or reference. 33 | 34 | 35 | 1. APPLICABILITY AND DEFINITIONS 36 | 37 | This License applies to any manual or other work, in any medium, that 38 | contains a notice placed by the copyright holder saying it can be 39 | distributed under the terms of this License. Such a notice grants a 40 | world-wide, royalty-free license, unlimited in duration, to use that 41 | work under the conditions stated herein. The "Document", below, 42 | refers to any such manual or work. Any member of the public is a 43 | licensee, and is addressed as "you". You accept the license if you 44 | copy, modify or distribute the work in a way requiring permission 45 | under copyright law. 46 | 47 | A "Modified Version" of the Document means any work containing the 48 | Document or a portion of it, either copied verbatim, or with 49 | modifications and/or translated into another language. 50 | 51 | A "Secondary Section" is a named appendix or a front-matter section of 52 | the Document that deals exclusively with the relationship of the 53 | publishers or authors of the Document to the Document's overall 54 | subject (or to related matters) and contains nothing that could fall 55 | directly within that overall subject. (Thus, if the Document is in 56 | part a textbook of mathematics, a Secondary Section may not explain 57 | any mathematics.) The relationship could be a matter of historical 58 | connection with the subject or with related matters, or of legal, 59 | commercial, philosophical, ethical or political position regarding 60 | them. 61 | 62 | The "Invariant Sections" are certain Secondary Sections whose titles 63 | are designated, as being those of Invariant Sections, in the notice 64 | that says that the Document is released under this License. If a 65 | section does not fit the above definition of Secondary then it is not 66 | allowed to be designated as Invariant. The Document may contain zero 67 | Invariant Sections. If the Document does not identify any Invariant 68 | Sections then there are none. 69 | 70 | The "Cover Texts" are certain short passages of text that are listed, 71 | as Front-Cover Texts or Back-Cover Texts, in the notice that says that 72 | the Document is released under this License. A Front-Cover Text may 73 | be at most 5 words, and a Back-Cover Text may be at most 25 words. 74 | 75 | A "Transparent" copy of the Document means a machine-readable copy, 76 | represented in a format whose specification is available to the 77 | general public, that is suitable for revising the document 78 | straightforwardly with generic text editors or (for images composed of 79 | pixels) generic paint programs or (for drawings) some widely available 80 | drawing editor, and that is suitable for input to text formatters or 81 | for automatic translation to a variety of formats suitable for input 82 | to text formatters. A copy made in an otherwise Transparent file 83 | format whose markup, or absence of markup, has been arranged to thwart 84 | or discourage subsequent modification by readers is not Transparent. 85 | An image format is not Transparent if used for any substantial amount 86 | of text. A copy that is not "Transparent" is called "Opaque". 87 | 88 | Examples of suitable formats for Transparent copies include plain 89 | ASCII without markup, Texinfo input format, LaTeX input format, SGML 90 | or XML using a publicly available DTD, and standard-conforming simple 91 | HTML, PostScript or PDF designed for human modification. Examples of 92 | transparent image formats include PNG, XCF and JPG. Opaque formats 93 | include proprietary formats that can be read and edited only by 94 | proprietary word processors, SGML or XML for which the DTD and/or 95 | processing tools are not generally available, and the 96 | machine-generated HTML, PostScript or PDF produced by some word 97 | processors for output purposes only. 98 | 99 | The "Title Page" means, for a printed book, the title page itself, 100 | plus such following pages as are needed to hold, legibly, the material 101 | this License requires to appear in the title page. For works in 102 | formats which do not have any title page as such, "Title Page" means 103 | the text near the most prominent appearance of the work's title, 104 | preceding the beginning of the body of the text. 105 | 106 | The "publisher" means any person or entity that distributes copies of 107 | the Document to the public. 108 | 109 | A section "Entitled XYZ" means a named subunit of the Document whose 110 | title either is precisely XYZ or contains XYZ in parentheses following 111 | text that translates XYZ in another language. (Here XYZ stands for a 112 | specific section name mentioned below, such as "Acknowledgements", 113 | "Dedications", "Endorsements", or "History".) To "Preserve the Title" 114 | of such a section when you modify the Document means that it remains a 115 | section "Entitled XYZ" according to this definition. 116 | 117 | The Document may include Warranty Disclaimers next to the notice which 118 | states that this License applies to the Document. These Warranty 119 | Disclaimers are considered to be included by reference in this 120 | License, but only as regards disclaiming warranties: any other 121 | implication that these Warranty Disclaimers may have is void and has 122 | no effect on the meaning of this License. 123 | 124 | 2. VERBATIM COPYING 125 | 126 | You may copy and distribute the Document in any medium, either 127 | commercially or noncommercially, provided that this License, the 128 | copyright notices, and the license notice saying this License applies 129 | to the Document are reproduced in all copies, and that you add no 130 | other conditions whatsoever to those of this License. You may not use 131 | technical measures to obstruct or control the reading or further 132 | copying of the copies you make or distribute. However, you may accept 133 | compensation in exchange for copies. If you distribute a large enough 134 | number of copies you must also follow the conditions in section 3. 135 | 136 | You may also lend copies, under the same conditions stated above, and 137 | you may publicly display copies. 138 | 139 | 140 | 3. COPYING IN QUANTITY 141 | 142 | If you publish printed copies (or copies in media that commonly have 143 | printed covers) of the Document, numbering more than 100, and the 144 | Document's license notice requires Cover Texts, you must enclose the 145 | copies in covers that carry, clearly and legibly, all these Cover 146 | Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on 147 | the back cover. Both covers must also clearly and legibly identify 148 | you as the publisher of these copies. The front cover must present 149 | the full title with all words of the title equally prominent and 150 | visible. You may add other material on the covers in addition. 151 | Copying with changes limited to the covers, as long as they preserve 152 | the title of the Document and satisfy these conditions, can be treated 153 | as verbatim copying in other respects. 154 | 155 | If the required texts for either cover are too voluminous to fit 156 | legibly, you should put the first ones listed (as many as fit 157 | reasonably) on the actual cover, and continue the rest onto adjacent 158 | pages. 159 | 160 | If you publish or distribute Opaque copies of the Document numbering 161 | more than 100, you must either include a machine-readable Transparent 162 | copy along with each Opaque copy, or state in or with each Opaque copy 163 | a computer-network location from which the general network-using 164 | public has access to download using public-standard network protocols 165 | a complete Transparent copy of the Document, free of added material. 166 | If you use the latter option, you must take reasonably prudent steps, 167 | when you begin distribution of Opaque copies in quantity, to ensure 168 | that this Transparent copy will remain thus accessible at the stated 169 | location until at least one year after the last time you distribute an 170 | Opaque copy (directly or through your agents or retailers) of that 171 | edition to the public. 172 | 173 | It is requested, but not required, that you contact the authors of the 174 | Document well before redistributing any large number of copies, to 175 | give them a chance to provide you with an updated version of the 176 | Document. 177 | 178 | 179 | 4. MODIFICATIONS 180 | 181 | You may copy and distribute a Modified Version of the Document under 182 | the conditions of sections 2 and 3 above, provided that you release 183 | the Modified Version under precisely this License, with the Modified 184 | Version filling the role of the Document, thus licensing distribution 185 | and modification of the Modified Version to whoever possesses a copy 186 | of it. In addition, you must do these things in the Modified Version: 187 | 188 | A. Use in the Title Page (and on the covers, if any) a title distinct 189 | from that of the Document, and from those of previous versions 190 | (which should, if there were any, be listed in the History section 191 | of the Document). You may use the same title as a previous version 192 | if the original publisher of that version gives permission. 193 | B. List on the Title Page, as authors, one or more persons or entities 194 | responsible for authorship of the modifications in the Modified 195 | Version, together with at least five of the principal authors of the 196 | Document (all of its principal authors, if it has fewer than five), 197 | unless they release you from this requirement. 198 | C. State on the Title page the name of the publisher of the 199 | Modified Version, as the publisher. 200 | D. Preserve all the copyright notices of the Document. 201 | E. Add an appropriate copyright notice for your modifications 202 | adjacent to the other copyright notices. 203 | F. Include, immediately after the copyright notices, a license notice 204 | giving the public permission to use the Modified Version under the 205 | terms of this License, in the form shown in the Addendum below. 206 | G. Preserve in that license notice the full lists of Invariant Sections 207 | and required Cover Texts given in the Document's license notice. 208 | H. Include an unaltered copy of this License. 209 | I. Preserve the section Entitled "History", Preserve its Title, and add 210 | to it an item stating at least the title, year, new authors, and 211 | publisher of the Modified Version as given on the Title Page. If 212 | there is no section Entitled "History" in the Document, create one 213 | stating the title, year, authors, and publisher of the Document as 214 | given on its Title Page, then add an item describing the Modified 215 | Version as stated in the previous sentence. 216 | J. Preserve the network location, if any, given in the Document for 217 | public access to a Transparent copy of the Document, and likewise 218 | the network locations given in the Document for previous versions 219 | it was based on. These may be placed in the "History" section. 220 | You may omit a network location for a work that was published at 221 | least four years before the Document itself, or if the original 222 | publisher of the version it refers to gives permission. 223 | K. For any section Entitled "Acknowledgements" or "Dedications", 224 | Preserve the Title of the section, and preserve in the section all 225 | the substance and tone of each of the contributor acknowledgements 226 | and/or dedications given therein. 227 | L. Preserve all the Invariant Sections of the Document, 228 | unaltered in their text and in their titles. Section numbers 229 | or the equivalent are not considered part of the section titles. 230 | M. Delete any section Entitled "Endorsements". Such a section 231 | may not be included in the Modified Version. 232 | N. Do not retitle any existing section to be Entitled "Endorsements" 233 | or to conflict in title with any Invariant Section. 234 | O. Preserve any Warranty Disclaimers. 235 | 236 | If the Modified Version includes new front-matter sections or 237 | appendices that qualify as Secondary Sections and contain no material 238 | copied from the Document, you may at your option designate some or all 239 | of these sections as invariant. To do this, add their titles to the 240 | list of Invariant Sections in the Modified Version's license notice. 241 | These titles must be distinct from any other section titles. 242 | 243 | You may add a section Entitled "Endorsements", provided it contains 244 | nothing but endorsements of your Modified Version by various 245 | parties--for example, statements of peer review or that the text has 246 | been approved by an organization as the authoritative definition of a 247 | standard. 248 | 249 | You may add a passage of up to five words as a Front-Cover Text, and a 250 | passage of up to 25 words as a Back-Cover Text, to the end of the list 251 | of Cover Texts in the Modified Version. Only one passage of 252 | Front-Cover Text and one of Back-Cover Text may be added by (or 253 | through arrangements made by) any one entity. If the Document already 254 | includes a cover text for the same cover, previously added by you or 255 | by arrangement made by the same entity you are acting on behalf of, 256 | you may not add another; but you may replace the old one, on explicit 257 | permission from the previous publisher that added the old one. 258 | 259 | The author(s) and publisher(s) of the Document do not by this License 260 | give permission to use their names for publicity for or to assert or 261 | imply endorsement of any Modified Version. 262 | 263 | 264 | 5. COMBINING DOCUMENTS 265 | 266 | You may combine the Document with other documents released under this 267 | License, under the terms defined in section 4 above for modified 268 | versions, provided that you include in the combination all of the 269 | Invariant Sections of all of the original documents, unmodified, and 270 | list them all as Invariant Sections of your combined work in its 271 | license notice, and that you preserve all their Warranty Disclaimers. 272 | 273 | The combined work need only contain one copy of this License, and 274 | multiple identical Invariant Sections may be replaced with a single 275 | copy. If there are multiple Invariant Sections with the same name but 276 | different contents, make the title of each such section unique by 277 | adding at the end of it, in parentheses, the name of the original 278 | author or publisher of that section if known, or else a unique number. 279 | Make the same adjustment to the section titles in the list of 280 | Invariant Sections in the license notice of the combined work. 281 | 282 | In the combination, you must combine any sections Entitled "History" 283 | in the various original documents, forming one section Entitled 284 | "History"; likewise combine any sections Entitled "Acknowledgements", 285 | and any sections Entitled "Dedications". You must delete all sections 286 | Entitled "Endorsements". 287 | 288 | 289 | 6. COLLECTIONS OF DOCUMENTS 290 | 291 | You may make a collection consisting of the Document and other 292 | documents released under this License, and replace the individual 293 | copies of this License in the various documents with a single copy 294 | that is included in the collection, provided that you follow the rules 295 | of this License for verbatim copying of each of the documents in all 296 | other respects. 297 | 298 | You may extract a single document from such a collection, and 299 | distribute it individually under this License, provided you insert a 300 | copy of this License into the extracted document, and follow this 301 | License in all other respects regarding verbatim copying of that 302 | document. 303 | 304 | 305 | 7. AGGREGATION WITH INDEPENDENT WORKS 306 | 307 | A compilation of the Document or its derivatives with other separate 308 | and independent documents or works, in or on a volume of a storage or 309 | distribution medium, is called an "aggregate" if the copyright 310 | resulting from the compilation is not used to limit the legal rights 311 | of the compilation's users beyond what the individual works permit. 312 | When the Document is included in an aggregate, this License does not 313 | apply to the other works in the aggregate which are not themselves 314 | derivative works of the Document. 315 | 316 | If the Cover Text requirement of section 3 is applicable to these 317 | copies of the Document, then if the Document is less than one half of 318 | the entire aggregate, the Document's Cover Texts may be placed on 319 | covers that bracket the Document within the aggregate, or the 320 | electronic equivalent of covers if the Document is in electronic form. 321 | Otherwise they must appear on printed covers that bracket the whole 322 | aggregate. 323 | 324 | 325 | 8. TRANSLATION 326 | 327 | Translation is considered a kind of modification, so you may 328 | distribute translations of the Document under the terms of section 4. 329 | Replacing Invariant Sections with translations requires special 330 | permission from their copyright holders, but you may include 331 | translations of some or all Invariant Sections in addition to the 332 | original versions of these Invariant Sections. You may include a 333 | translation of this License, and all the license notices in the 334 | Document, and any Warranty Disclaimers, provided that you also include 335 | the original English version of this License and the original versions 336 | of those notices and disclaimers. In case of a disagreement between 337 | the translation and the original version of this License or a notice 338 | or disclaimer, the original version will prevail. 339 | 340 | If a section in the Document is Entitled "Acknowledgements", 341 | "Dedications", or "History", the requirement (section 4) to Preserve 342 | its Title (section 1) will typically require changing the actual 343 | title. 344 | 345 | 346 | 9. TERMINATION 347 | 348 | You may not copy, modify, sublicense, or distribute the Document 349 | except as expressly provided under this License. Any attempt 350 | otherwise to copy, modify, sublicense, or distribute it is void, and 351 | will automatically terminate your rights under this License. 352 | 353 | However, if you cease all violation of this License, then your license 354 | from a particular copyright holder is reinstated (a) provisionally, 355 | unless and until the copyright holder explicitly and finally 356 | terminates your license, and (b) permanently, if the copyright holder 357 | fails to notify you of the violation by some reasonable means prior to 358 | 60 days after the cessation. 359 | 360 | Moreover, your license from a particular copyright holder is 361 | reinstated permanently if the copyright holder notifies you of the 362 | violation by some reasonable means, this is the first time you have 363 | received notice of violation of this License (for any work) from that 364 | copyright holder, and you cure the violation prior to 30 days after 365 | your receipt of the notice. 366 | 367 | Termination of your rights under this section does not terminate the 368 | licenses of parties who have received copies or rights from you under 369 | this License. If your rights have been terminated and not permanently 370 | reinstated, receipt of a copy of some or all of the same material does 371 | not give you any rights to use it. 372 | 373 | 374 | 10. FUTURE REVISIONS OF THIS LICENSE 375 | 376 | The Free Software Foundation may publish new, revised versions of the 377 | GNU Free Documentation License from time to time. Such new versions 378 | will be similar in spirit to the present version, but may differ in 379 | detail to address new problems or concerns. See 380 | http://www.gnu.org/copyleft/. 381 | 382 | Each version of the License is given a distinguishing version number. 383 | If the Document specifies that a particular numbered version of this 384 | License "or any later version" applies to it, you have the option of 385 | following the terms and conditions either of that specified version or 386 | of any later version that has been published (not as a draft) by the 387 | Free Software Foundation. If the Document does not specify a version 388 | number of this License, you may choose any version ever published (not 389 | as a draft) by the Free Software Foundation. If the Document 390 | specifies that a proxy can decide which future versions of this 391 | License can be used, that proxy's public statement of acceptance of a 392 | version permanently authorizes you to choose that version for the 393 | Document. 394 | 395 | 11. RELICENSING 396 | 397 | "Massive Multiauthor Collaboration Site" (or "MMC Site") means any 398 | World Wide Web server that publishes copyrightable works and also 399 | provides prominent facilities for anybody to edit those works. A 400 | public wiki that anybody can edit is an example of such a server. A 401 | "Massive Multiauthor Collaboration" (or "MMC") contained in the site 402 | means any set of copyrightable works thus published on the MMC site. 403 | 404 | "CC-BY-SA" means the Creative Commons Attribution-Share Alike 3.0 405 | license published by Creative Commons Corporation, a not-for-profit 406 | corporation with a principal place of business in San Francisco, 407 | California, as well as future copyleft versions of that license 408 | published by that same organization. 409 | 410 | "Incorporate" means to publish or republish a Document, in whole or in 411 | part, as part of another Document. 412 | 413 | An MMC is "eligible for relicensing" if it is licensed under this 414 | License, and if all works that were first published under this License 415 | somewhere other than this MMC, and subsequently incorporated in whole or 416 | in part into the MMC, (1) had no cover texts or invariant sections, and 417 | (2) were thus incorporated prior to November 1, 2008. 418 | 419 | The operator of an MMC Site may republish an MMC contained in the site 420 | under CC-BY-SA on the same site at any time before August 1, 2009, 421 | provided the MMC is eligible for relicensing. 422 | 423 | 424 | ADDENDUM: How to use this License for your documents 425 | 426 | To use this License in a document you have written, include a copy of 427 | the License in the document and put the following copyright and 428 | license notices just after the title page: 429 | 430 | Copyright (c) YEAR YOUR NAME. 431 | Permission is granted to copy, distribute and/or modify this document 432 | under the terms of the GNU Free Documentation License, Version 1.3 433 | or any later version published by the Free Software Foundation; 434 | with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. 435 | A copy of the license is included in the section entitled "GNU 436 | Free Documentation License". 437 | 438 | If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, 439 | replace the "with...Texts." line with this: 440 | 441 | with the Invariant Sections being LIST THEIR TITLES, with the 442 | Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. 443 | 444 | If you have Invariant Sections without Cover Texts, or some other 445 | combination of the three, merge those two alternatives to suit the 446 | situation. 447 | 448 | If your document contains nontrivial examples of program code, we 449 | recommend releasing these examples in parallel under your choice of 450 | free software license, such as the GNU General Public License, 451 | to permit their use in free software. 452 | -------------------------------------------------------------------------------- /doc/Makefile.am: -------------------------------------------------------------------------------- 1 | dist_pkgdata_DATA = adept_documentation.pdf 2 | EXTRA_DIST = adept_documentation.tex 3 | 4 | documentation: 5 | pdflatex adept_documentation.tex 6 | pdflatex adept_documentation.tex 7 | pdflatex adept_documentation.tex -------------------------------------------------------------------------------- /doc/README: -------------------------------------------------------------------------------- 1 | This directory contains the Adept User Guide, both the PDF and the 2 | LaTeX source file. 3 | 4 | Type "pdflatex adept_documentation.tex" three times to recreate the 5 | PDF file (or type "make documentation" in this directory). 6 | 7 | Permission is granted to copy, distribute and/or modify the Adept User 8 | Guide under the terms of the GNU Free Documentation License, Version 9 | 1.3 or any later version published by the Free Software 10 | Foundation. This license may be found at 11 | http://www.gnu.org/copyleft/fdl.html, and in this directory in the 12 | "COPYING" file. As an exception, no copyright is asserted for the code 13 | fragments in the document (indicated in the text with a light-grey 14 | background); these code fragments are in the Public Domain and may be 15 | copied, modified and distributed without restriction. 16 | -------------------------------------------------------------------------------- /doc/adept_documentation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjhogan/Adept/11cf0690f13247b60f041929f4be962afeaa1a13/doc/adept_documentation.pdf -------------------------------------------------------------------------------- /include/Makefile.am: -------------------------------------------------------------------------------- 1 | include_HEADERS = adept.h 2 | EXTRA_DIST = Timer.h create_adept_source_header adept_source.h 3 | 4 | adept_source.h: ../adept/*.cpp 5 | ./create_adept_source_header 6 | all-local: adept_source.h -------------------------------------------------------------------------------- /include/Timer.h: -------------------------------------------------------------------------------- 1 | /* Timer.h - Utility class for timing different parts of a program 2 | 3 | Copyright (C) 2012-2014 The University of Reading 4 | 5 | Copying and distribution of this file, with or without modification, 6 | are permitted in any medium without royalty provided the copyright 7 | notice and this notice are preserved. This file is offered as-is, 8 | without any warranty. 9 | */ 10 | 11 | #ifndef Timer_H 12 | #define Timer_H 1 13 | 14 | #ifdef _WIN32 15 | #include 16 | #include 17 | #else 18 | #include 19 | #endif 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | // The Timer class: all functions are inline 28 | class Timer { 29 | public: 30 | typedef int TimerInt; 31 | 32 | // Constructor can specify a number of unnamed activities 33 | Timer(TimerInt n_activities = 0) 34 | : current_activity_(-1), timer_on_(false), print_on_exit_(false) { 35 | #ifdef _WIN32 36 | win_last_time_.QuadPart = 0; 37 | #else 38 | last_time_.tv_sec = 0; 39 | last_time_.tv_usec = 0; 40 | #endif 41 | timings_.reserve(100); 42 | names_.reserve(100); 43 | for (TimerInt i = 0; i < n_activities; i++) { 44 | std::stringstream s; 45 | s << "Activity " << i; 46 | timings_.push_back(0.0); 47 | names_.push_back(s.str()); 48 | } 49 | } 50 | 51 | // When the timer is destructed (typically at program exit), print 52 | // out the times spent in each activity 53 | ~Timer() { 54 | if (print_on_exit_) { 55 | print(); 56 | } 57 | } 58 | 59 | // Print out the times spent in each activity 60 | void print() { 61 | double sum = 0.0; 62 | std::cerr << timings_.size() << " activities:\n"; 63 | for (TimerInt i = 0; i < timings_.size(); i++) { 64 | std::cerr.width(10); 65 | std::cerr << std::right << timings_[i] << " s: " << names_[i] << "\n"; 66 | sum += timings_[i]; 67 | } 68 | std::cerr.width(10); 69 | std::cerr << std::right << sum << " s: Total\n"; 70 | } 71 | 72 | // Register a new activity with the specified name, returning the 73 | // tag to be used to specify it in future, as a TimerInt 74 | TimerInt new_activity(const std::string& name) { 75 | TimerInt tag = timings_.size(); 76 | names_.push_back(name); 77 | timings_.push_back(0.0); 78 | return tag; 79 | } 80 | 81 | // Stop timing current activity 82 | void stop() { 83 | if (timer_on_) { 84 | timings_[current_activity_] += split_(); 85 | } 86 | timer_on_ = false; 87 | }; 88 | 89 | // Start timing specified activity 90 | void start(TimerInt activity) { 91 | if (timer_on_) { 92 | timings_[current_activity_] += split_(); 93 | } 94 | else { 95 | split_(); 96 | } 97 | 98 | if (activity >= 0 && activity < timings_.size()) { 99 | current_activity_ = activity; 100 | timer_on_ = true; 101 | } 102 | else { 103 | // Activity out of range - to keep this inline function fast we 104 | // don't throw an exception but just don't record the time for 105 | // this event 106 | timer_on_ = false; 107 | } 108 | }; 109 | 110 | // Set the timing for a specific activity back to zero 111 | void reset(TimerInt activity) { 112 | if (activity >= 0 && activity < timings_.size()) { 113 | timings_[activity] = 0.0; 114 | } 115 | } 116 | 117 | // Return the list of timings in seconds as a constant reference to 118 | // a vector of doubles 119 | const std::vector& timings() { return timings_; } 120 | 121 | // Return a single timing 122 | double timing(TimerInt activity) { 123 | if (activity >= 0 && activity < timings_.size()) { 124 | return timings_[activity]; 125 | } 126 | else { 127 | return 0.0; 128 | } 129 | } 130 | 131 | // Decide whether the contents of the timer class will be printed 132 | // when it is destructed 133 | void print_on_exit(bool b = true) { 134 | print_on_exit_ = b; 135 | } 136 | 137 | private: 138 | // Use Unix system call to get the time accurately 139 | double split_() { 140 | #ifdef _WIN32 141 | using namespace std; 142 | QueryPerformanceFrequency(&frequency); 143 | QueryPerformanceCounter(&win_time_); 144 | double dsec = (double) (win_time_.QuadPart - win_last_time_.QuadPart) 145 | / (double) frequency.QuadPart; 146 | win_last_time_ = win_time_; 147 | return dsec; 148 | #else 149 | struct timeval time; 150 | gettimeofday(&time, NULL); 151 | double dsec = time.tv_sec - last_time_.tv_sec 152 | + 0.000001 * (time.tv_usec - last_time_.tv_usec); 153 | last_time_ = time; 154 | return dsec; 155 | #endif 156 | } 157 | // Data 158 | std::vector timings_; 159 | std::vector names_; 160 | TimerInt current_activity_; 161 | #ifdef _WIN32 162 | LARGE_INTEGER frequency; // ticks per second 163 | LARGE_INTEGER win_time_, win_last_time_; // ticks 164 | #else 165 | timeval last_time_; 166 | #endif 167 | bool timer_on_; 168 | bool print_on_exit_; 169 | }; 170 | 171 | #endif 172 | -------------------------------------------------------------------------------- /include/create_adept_source_header: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This script creates a header file "adept_source.h" containing the 3 | # ../adept/*.cpp source files; why this is useful is explained below. 4 | 5 | ADEPT_SOURCE_HEADER=adept_source.h 6 | rm -f $ADEPT_SOURCE_HEADER 7 | 8 | echo "Creating $ADEPT_SOURCE_HEADER" 9 | 10 | echo "/* $ADEPT_SOURCE_HEADER - Source code for the Adept library 11 | 12 | Copyright (C) 2012-2015 The University of Reading 13 | 14 | Licensed under the Apache License, Version 2.0 (the \"License\"); you 15 | may not use this file except in compliance with the License. You 16 | may obtain a copy of the License at 17 | 18 | http://www.apache.org/licenses/LICENSE-2.0 19 | 20 | Unless required by applicable law or agreed to in writing, software 21 | distributed under the License is distributed on an \"AS IS\" BASIS, 22 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 23 | implied. See the License for the specific language governing 24 | permissions and limitations under the License. 25 | 26 | 27 | This file was created automatically by script $0 28 | on "$(date)" 29 | 30 | It contains a concatenation of the source files from the Adept 31 | library. The idea is that a program may #include this file in one of 32 | its source files (typically the one containing the main function), 33 | and then the Adept library will be built into the executable without 34 | the need to link to an external library. All other source files 35 | should just #include \"adept.h\". The ability to use Adept in this 36 | way makes it easier to distribute an Adept package that is usable on 37 | non-Unix platforms that are unable to use the configure script to 38 | build external libraries. 39 | 40 | The individual source files now follow. 41 | */ 42 | 43 | #ifndef ADEPT_SOURCE_H 44 | #define ADEPT_SOURCE_H 1 45 | " > $ADEPT_SOURCE_HEADER 46 | 47 | for FILE in ../adept/*.cpp 48 | do 49 | echo " Adding $FILE" 50 | echo " 51 | 52 | // ================================================================= 53 | // Contents of $(basename $FILE) 54 | // ================================================================= 55 | " >> $ADEPT_SOURCE_HEADER 56 | cat $FILE >> $ADEPT_SOURCE_HEADER 57 | done 58 | 59 | echo " 60 | 61 | #endif 62 | " >> $ADEPT_SOURCE_HEADER 63 | echo "Done" -------------------------------------------------------------------------------- /makefile_include.in: -------------------------------------------------------------------------------- 1 | # Template for configure to create makefile_include, which is included 2 | # by test/Makefile and benchmark/Makefile 3 | 4 | AR = @AR@ 5 | CC = @CC@ 6 | CFLAGS = @CFLAGS@ 7 | CPP = @CPP@ 8 | CPPFLAGS = @CPPFLAGS@ 9 | CXX = @CXX@ 10 | CXXCPP = @CXXCPP@ 11 | CXXFLAGS = @CXXFLAGS@ @OPENMP_CXXFLAGS@ 12 | DEFS = @DEFS@ 13 | LD = @LD@ 14 | LDFLAGS = @LDFLAGS@ @OPENMP_CXXFLAGS@ 15 | LIBOBJS = @LIBOBJS@ 16 | LIBS = @LIBS@ 17 | SHELL = @SHELL@ 18 | LIBTOOL = @LIBTOOL@ 19 | USE_GSL = @USE_GSL@ 20 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for example programs that demonstrate different features of 2 | # the Adept library 3 | # 4 | # Note that this Makefile is hand-coded rather than being generated by 5 | # automake 6 | # 7 | # The -DADEPT_RECORDING_PAUSABLE option enables the pause_recording 8 | # and continue_recording functionality and is used by test_adept, 9 | # although it will run correctly (but slightly more slowly) without 10 | # this flag 11 | 12 | # The configure script writes the following file, which contains 13 | # variables controlling the compilation 14 | include ../makefile_include 15 | 16 | ADEPT_FLAGS = -DADEPT_RECORDING_PAUSABLE 17 | 18 | # The objects to create 19 | OBJECTS = algorithm.o algorithm_noad.o test_checkpoint.o \ 20 | test_adept.o test_adept_with_and_without_ad.o \ 21 | test_radiances.o simulate_radiances.o test_thread_safe.o \ 22 | test_no_lib.o test_misc.o test_stack_nesting.o 23 | GSL_OBJECTS = test_gsl_interface.o state.o rosenbrock_banana_function.o 24 | 25 | GSL_LIBS = -lgsl -lgslcblas 26 | 27 | COMPILE_FLAGS = $(CXXFLAGS) $(CPPFLAGS) $(ADEPT_FLAGS) -I../include 28 | 29 | # Because we aren't going to install the test programs, and we want 30 | # them to work even if Adept is not installed, it is easiest to use 31 | # libtool to create statically-linked executables 32 | top_builddir = .. 33 | CXXLINK = $(LIBTOOL) --tag=CXX --mode=link $(CXX) $(CXXFLAGS) \ 34 | -static -no-install -L../adept/.libs $(LDFLAGS) -o $@ 35 | 36 | # Dependency on the presence of the Adept static library 37 | LIBADEPT = ../adept/.libs/libadept.a 38 | 39 | MYLIBS = -ladept $(LIBS) 40 | 41 | PROGRAMS = test_adept test_adept_with_and_without_ad test_radiances \ 42 | test_gsl_interface test_misc test_checkpoint test_thread_safe \ 43 | test_no_lib test_stack_nesting 44 | 45 | all: 46 | @echo "********************************************************" 47 | @echo "*** To compile test programs in test/ and benchmark/ ***" 48 | @echo "*** type \"make check\" ***" 49 | @echo "********************************************************" 50 | 51 | # Compile all four programs 52 | check: $(PROGRAMS) 53 | 54 | # Test program 1 55 | test_adept: algorithm.o test_adept.o $(LIBADEPT) 56 | $(CXXLINK) algorithm.o test_adept.o $(MYLIBS) 57 | 58 | # Test program 2 59 | test_adept_with_and_without_ad: algorithm.o algorithm_noad.o test_adept_with_and_without_ad.o $(LIBADEPT) 60 | $(CXXLINK) algorithm.o algorithm_noad.o test_adept_with_and_without_ad.o $(MYLIBS) 61 | 62 | # Test program 3 63 | test_radiances: simulate_radiances.o test_radiances.o $(LIBADEPT) 64 | $(CXXLINK) simulate_radiances.o test_radiances.o $(MYLIBS) 65 | 66 | ifeq "X$(USE_GSL)" "Xyes" 67 | # Test program 4 68 | test_gsl_interface: $(GSL_OBJECTS) $(LIBADEPT) 69 | $(CXXLINK) $(GSL_OBJECTS) $(GSL_LIBS) $(MYLIBS) 70 | else 71 | test_gsl_interface: 72 | @echo "The executable test_gsl_interface will not be created because GSL library was not found" 73 | endif 74 | 75 | # Test program 5 76 | test_misc: test_misc.o algorithm.o $(LIBADEPT) 77 | $(CXXLINK) test_misc.o algorithm.o $(MYLIBS) 78 | 79 | # Test program 6 80 | test_checkpoint: test_checkpoint.o $(LIBADEPT) 81 | $(CXXLINK) test_checkpoint.o $(MYLIBS) 82 | 83 | # Test program 7 84 | test_thread_safe: test_thread_safe.o $(LIBADEPT) 85 | $(CXXLINK) test_thread_safe.o $(MYLIBS) 86 | 87 | # Test program 8 (note that it is not linked against the Adept library 88 | test_no_lib: test_no_lib.o algorithm.o 89 | $(CXXLINK) test_no_lib.o algorithm.o 90 | 91 | # Test program 9 92 | test_stack_nesting: test_stack_nesting.o 93 | $(CXXLINK) test_stack_nesting.o $(MYLIBS) 94 | 95 | # The no-automatic-differentiation version of the algorithm: uses the 96 | # -DADEPT_NO_AUTOMATIC_DIFFERENTIATION to produce a version of the 97 | # algorithm that takes double rather than adouble arguments 98 | algorithm_noad.o: algorithm.cpp *.h ../include/adept.h 99 | $(CXX) $(COMPILE_FLAGS) $(INCLUDES) -c algorithm.cpp -DADEPT_NO_AUTOMATIC_DIFFERENTIATION -o $@ 100 | 101 | # All other object files created by compiling the corresponding source 102 | # file without this flag 103 | %.o: %.cpp *.h ../include/adept.h 104 | $(CXX) $(COMPILE_FLAGS) $(INCLUDES) -c $< 105 | 106 | # Remove all object files and executables 107 | clean: 108 | rm -f $(OBJECTS) $(GSL_OBJECTS) $(PROGRAMS) 109 | 110 | mostlyclean: clean 111 | 112 | # Null targets to satisfy autotools 113 | EMPTY_AUTOMAKE_TARGETS = distdir install install-data install-exec uninstall \ 114 | install-dvi install-html install-info install-ps install-pdf \ 115 | installdirs installcheck distclean maintainer-clean \ 116 | dvi pdf ps info html tags ctags 117 | .PHONY: $(EMPTY_AUTOMAKE_TARGETS) 118 | $(EMPTY_AUTOMAKE_TARGETS): 119 | -------------------------------------------------------------------------------- /test/README: -------------------------------------------------------------------------------- 1 | This directory contains examples to demonstrate various features of 2 | Adept. Type "make check" from the directory above to compile 3 | them. 4 | 5 | Note that unlike in the rest of this package, the Makefile in this 6 | directory was not generated by automake; it is well commented and so 7 | may assist in understanding how to build software that uses Adept. 8 | 9 | 10 | TEST 1: BASIC FEATURES 11 | 12 | Executable: test_adept 13 | 14 | Source files: test_adept.cpp, algorithm.cpp, algorithm.h 15 | 16 | Demonstrates: basic use of Adept, reverse-mode automatic 17 | differentiation, computing the Jacobian matrix, printing diagnostic 18 | information, verifying results by comparing to numerical calculations, 19 | pausing and continuing recordings 20 | 21 | Synopsis: This program demonstrates how to differentiate a simple 22 | function (in algorithm.cpp), comparing the results from automatic 23 | differentiation with numerical differentiation. The function used is 24 | the contrived example from the Adept paper. 25 | 26 | 27 | TEST 2: COMPILING SOURCE FILES TWICE, WITH AND WITHOUT AUTOMATIC 28 | DIFFERENTIATION 29 | 30 | Executable: test_adept_with_and_without_ad 31 | 32 | Source files: test_adept_with_and_without_ad.cpp, algorithm.cpp, 33 | algorithm.h, algorithm_with_and_without_ad.h 34 | 35 | Demonstrates: most of the same features as TEST_ADEPT, plus compiling 36 | a source file twice 37 | 38 | Synopsis: This program is the same as in Test 1, except that 39 | algorithm.cpp is compiled twice, once with automatic differentiation 40 | (producing the object file algorithm.o) and once without (producing 41 | the object file algorithm_noad.o). This is achieved in the Makefile 42 | using the -DADEPT_NO_AUTOMATIC_DIFFERENTIATION flag. This provides two 43 | overloaded versions of the "algorithm" function, one that takes active 44 | "adouble" arguments, and the other that takes inactive "double" 45 | arguments. The two versions are declared in the 46 | algorithm_with_and_without_ad.h header file. 47 | 48 | 49 | TEST 3: RADIANCE SIMULATION 50 | 51 | Executable: test_radiances 52 | 53 | Source files: test_radiances.cpp, simulate_radiances.cpp, 54 | simulate_radiances.h 55 | 56 | Demonstrates: activation and deactivation of an Adept stack, using 57 | more than one Adept stack in the same program (but not at the same 58 | time), how to interface Adept with software that computes its own 59 | Jacobian 60 | 61 | Synopsis: The "main" function is in test_radiances.cpp, and 62 | demonstrates how to interface Adept to an algorithm that does not have 63 | an Adept interface, but which provides its own Jacobian. The algorithm 64 | in this case is in simulate_radiances.cpp; while it does not have an 65 | Adept interface, it does use Adept internally to compute the Jacobian 66 | that it returns. It therefore needs to temporarily deactivate the 67 | calling function's Adept stack (where derivative information is 68 | stored) while using its own. This example is from the Adept 69 | documentation. 70 | 71 | 72 | TEST 4: GSL MINIMIZATION INTERFACE 73 | 74 | Executable: test_gsl_interface 75 | 76 | Command-line arguments: optionally, the executable name can be 77 | followed by an integer (which should be 2 or greater) expressing the 78 | number of dimensions of the minimization problem. The default is 2. 79 | 80 | Source files: test_gsl_interface.cpp, rosenbrock_banana_function.cpp, 81 | state.cpp, state.h 82 | 83 | Pre-requisites: the GNU Scientific Library should be installed; on an 84 | RPM-based system you want the "gsl" and "gsl-devel" packages. If this 85 | is not available at the time the configure script is run, this 86 | executable will not be built. 87 | 88 | Demonstrates: interface with the multi-dimensional minimization 89 | capability of the GNU Scientific Library, use of Adept to minimize a 90 | real function, an object-oriented way to store Adept data for a 91 | minimization problem 92 | 93 | Synopsis: The "main" function is in test_gsl_interface.cpp and is 94 | fairly self-explanatory. The state.cpp and state.h files show how 95 | Adept data can be stored and accessed in an object-oriented way. The 96 | function to be minimized is the N-dimensional Rosenbrock banana 97 | function, given in rosenbrock_banana_function.cpp. 98 | 99 | 100 | TEST 5: TRIVIAL EXAMPLE IN ADEPT PAPER 101 | 102 | Executable: test_misc 103 | 104 | Source files: test_misc.cpp, algorithm.cpp, algorithm.h 105 | 106 | Demonstrates: basic use of Adept, reverse-mode automatic 107 | differentiation 108 | 109 | Synopsis: This program is simply the trivial example in the Adept 110 | paper, using the same algorithm as in Test 1. 111 | 112 | 113 | TEST 6: CHECKPOINTING 114 | 115 | Executable: test_checkpointing 116 | 117 | Source files: test_checkpoint.cpp 118 | 119 | Demonstrates: checkpointing 120 | 121 | Synopsis: Large algorithms, particularly those that involve 122 | time-dependent simulations, can require a lot of memory when used with 123 | an automatic-differentiation tool. Even if enough memory is available, 124 | the speed may be sub-optimal. This program demonstrates the 125 | checkpointing technique, where a simulation using the "Toon" algorithm 126 | in the Adept paper is first run with 10,000 timesteps, and then in 100 127 | blocks of 100 timesteps (the checkpointed simulation), with the output 128 | stored after each block so that the reverse pass of the automatic 129 | differentiation needs 100 times less memory. The resulting gradients 130 | are output to verify that the two versions produce the results, and 131 | the timings of the two are presented as well. 132 | 133 | 134 | TEST 7: THREAD SAFETY 135 | 136 | Executable: test_thread_safe 137 | 138 | Source files: test_thread_safe.cpp 139 | 140 | Demonstrates: use of Adept in multi-threaded applications, thread 141 | safety, comparison of Jacobian matrices computed using the forward and 142 | reverse methods 143 | 144 | Synopsis: This program computes the 128-128 Jacobian matrix of an 145 | algorithm 16 times with different inputs. The Jacobian matrix is 146 | actually computed twice, once with 128 forward passes through the 147 | derivative statements and once with 128 reverse passes through the 148 | derivative statements, and a check is performed to see that the 149 | root-mean-squared difference is within some tolerance. 150 | The default behaviour (and if the "-parallel" command-line argument 151 | is provided) is to use OpenMP to run the 16 computations in parallel. 152 | In this instance the 128 passes required to compute the Jacobian 153 | matrices will be computed using just a single thread. If the "-serial" 154 | command-line argument is provided then the 16 computations are carried 155 | out in series. In this instance, the Adept library is able to run the 156 | Jacobian-matrix calculation in parallel (this behaviour is automatic 157 | if the program is compiled with the -fopenmp option). 158 | If the program is compiled with the ADEPT_STACK_THREAD_UNSAFE 159 | preprocessor variable defined, or on platforms that don't support 160 | thread-local variables (e.g. some Mac platforms), then the program 161 | should abort in the "-parallel" case ONLY. 162 | 163 | 164 | 165 | TEST 8: COMPILING WITHOUT EXTERNAL ADEPT LIBRARY 166 | 167 | Executable: test_no_lib 168 | 169 | Source files: test_no_lib.cpp algorithm.cpp algorithm.h 170 | 171 | Demonstrates: use of adept_source.h to create an executable without 172 | the need to the external Adept library 173 | 174 | Synopsis: This is basically the same as test_misc.cpp, but one of the 175 | source files includes adept_source.h (rather than adept.h), which 176 | contains the source code for the Adept library. This means that no 177 | linking to an external Adept library (via -ladept) is required. This 178 | capability makes it easier to distribute a package that can be used on 179 | the widest range of operating systems, particularly those like 180 | Microsoft Windows that cannot natively run the configure shell script. 181 | 182 | 183 | 184 | TEST 9: USING NESTED STACKS 185 | 186 | Executable: test_stack_nesting 187 | 188 | Source files: test_stack_nesting.cpp 189 | 190 | Demonstrates: use of nested stacks to accellerate Jacobian 191 | calculations in some situations. 192 | 193 | This test case illustrates how Jacobian calculations can be 194 | accelerated in certain situations when they are composed of "modules" 195 | that each involve a few numbers being calculated from many. In this 196 | situation we may avoid redundant computations by calculating a local 197 | Jacobian for each module and adding it to the stack. -------------------------------------------------------------------------------- /test/algorithm.cpp: -------------------------------------------------------------------------------- 1 | /* algorithm.cpp - A simple demonstration algorithm used in Tests 1 & 2 2 | 3 | Copyright (C) 2012-2014 The University of Reading 4 | 5 | Copying and distribution of this file, with or without modification, 6 | are permitted in any medium without royalty provided the copyright 7 | notice and this notice are preserved. This file is offered as-is, 8 | without any warranty. 9 | 10 | */ 11 | 12 | 13 | #include 14 | 15 | #include "algorithm.h" 16 | using adept::adouble; 17 | 18 | // A simple demonstration algorithm used in the Adept paper. Note that 19 | // this algorithm can be compiled with 20 | // -DADEPT_NO_AUTOMATIC_DIFFERENTIATION to create a version that takes 21 | // double arguments and returns a double result. 22 | adouble algorithm(const adouble x[2]) { 23 | adouble y = 4.0; 24 | adouble s = 2.0*x[0] + 3.0*x[1]*x[1]; 25 | double b=3.0; 26 | y = s + b; 27 | y *= sin(s); 28 | return y; 29 | } 30 | 31 | -------------------------------------------------------------------------------- /test/algorithm.h: -------------------------------------------------------------------------------- 1 | /* algorithm.h - Header file for the simple example algorithm function 2 | 3 | Copyright (C) 2012-2014 The University of Reading 4 | 5 | Copying and distribution of this file, with or without modification, 6 | are permitted in any medium without royalty provided the copyright 7 | notice and this notice are preserved. This file is offered as-is, 8 | without any warranty. 9 | */ 10 | 11 | #ifndef ALGORITHM_H 12 | #define ALGORITHM_H 1 13 | 14 | // This header file defining the interface of the simple demonstration 15 | // function "algorithm". This header file is included by both 16 | // algorithm.cpp, which defines the body of the function, and 17 | // test_adept.cpp, which calls algorithm. 18 | 19 | #include "adept.h" 20 | 21 | // Declare the function 22 | adept::adouble algorithm(const adept::adouble x[2]); 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /test/algorithm_with_and_without_ad.h: -------------------------------------------------------------------------------- 1 | /* algorithm_with_and_without_ad.h 2 | 3 | Copyright (C) 2012-2014 The University of Reading 4 | 5 | Copying and distribution of this file, with or without modification, 6 | are permitted in any medium without royalty provided the copyright 7 | notice and this notice are preserved. This file is offered as-is, 8 | without any warranty. 9 | */ 10 | 11 | // This header file defining the interface of the simple demonstration 12 | // function "algorithm", and is included by 13 | // test_adept_with_and_without_ad.cpp. It demonstrates the use of a 14 | // single source file that is compiled twice to produce two overloaded 15 | // versions of a function. The "original" version takes 16 | // double-precision arguments and returns a double-precision answer, 17 | // while the automatic differentiation version takes adouble arguments 18 | // and returns an adouble answer. The two versions are compiled from 19 | // the same source file algorithm.cpp by compiling it twice with and 20 | // without the compiler option -DAUTOMATIC_DIFFERENTIATION. 21 | 22 | 23 | #ifndef ALGORITHM_WITH_AND_WITHOUT_AD_H 24 | #define ALGORITHM_WITH_AND_WITHOUT_AD_H 1 25 | 26 | #include "adept.h" 27 | 28 | // Declare the original version of the function 29 | double algorithm(const double x[2]); 30 | 31 | #ifndef ADEPT_NO_AUTOMATIC_DIFFERENTIATION 32 | // Declare the automatic-differentiation version of the function 33 | adept::adouble algorithm(const adept::adouble x[2]); 34 | #endif 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /test/rosenbrock_banana_function.cpp: -------------------------------------------------------------------------------- 1 | /* rosenbrock_banana_function.cpp - N-dimensional Rosenbrock function 2 | 3 | Copyright (C) 2012-2014 The University of Reading 4 | 5 | Copying and distribution of this file, with or without modification, 6 | are permitted in any medium without royalty provided the copyright 7 | notice and this notice are preserved. This file is offered as-is, 8 | without any warranty. 9 | */ 10 | 11 | // This function is an N-dimensional extension of Rosenbrock's banana 12 | // function; it is actually the "2nd De Jong function" - see the 13 | // Wikipedia entry for Rosenbrock's function. 14 | 15 | #include "state.h" 16 | 17 | using adept::adouble; 18 | adouble State::calc_function_value(const adouble* x) { 19 | adouble sum = 0.0; 20 | for (unsigned int i = 0; i < nx()-1; i++) { 21 | adouble a = x[i+1]-x[i]*x[i]; 22 | sum += (1.0-x[i])*(1.0-x[i]) + 100.0*a*a; 23 | } 24 | return sum; 25 | } 26 | -------------------------------------------------------------------------------- /test/simulate_radiances.cpp: -------------------------------------------------------------------------------- 1 | /* simulate_radiances.cpp - provides a function taking inactive arguments that returns also Jacobian matrices 2 | 3 | Copyright (C) 2012-2014 The University of Reading 4 | 5 | Copying and distribution of this file, with or without modification, 6 | are permitted in any medium without royalty provided the copyright 7 | notice and this notice are preserved. This file is offered as-is, 8 | without any warranty. 9 | */ 10 | 11 | #include "adept.h" 12 | #include "simulate_radiances.h" 13 | 14 | using adept::adouble; 15 | 16 | // Simulate a single radiance (W sr-1 m-3) given the wavelength (m), 17 | // emissivity profile, surface temperature (K) and temperature profile 18 | // (K), where the profile data are located at n points with spacing 19 | // 1000 m. This function uses active arguments. It is accessible only 20 | // from within this file; the public interface is the 21 | // simulate_radiance function. 22 | static 23 | adouble 24 | simulate_radiance_private(int n, 25 | double wavelength, 26 | const double* emissivity, 27 | const adouble& surface_temperature, 28 | const adouble* temperature) 29 | { 30 | static const double BOLTZMANN_CONSTANT = 1.380648813e-23; 31 | static const double SPEED_OF_LIGHT = 299792458.0; 32 | 33 | int i; 34 | adouble bt = surface_temperature; // Brightness temperature in K 35 | // Loop up through the atmosphere working out the contribution from 36 | // each layer 37 | for (i = 0; i < n; i++) { 38 | bt = bt*(1.0-emissivity[i]) + emissivity[i]*temperature[i]; 39 | } 40 | // Convert from brightness temperature to radiance using 41 | // Rayleigh-Jeans approximation 42 | return 2.0*SPEED_OF_LIGHT*BOLTZMANN_CONSTANT*bt 43 | /(wavelength*wavelength*wavelength*wavelength); 44 | } 45 | 46 | // Simulate two radiances (W sr-1 m-3) given the surface temperature 47 | // (K) and temperature profile (K), where the profile data are located 48 | // at n points with spacing 1000 m. This function uses inactive 49 | // arguments. 50 | void 51 | simulate_radiances(int n, // Size of temperature array 52 | // Input variables: 53 | double surface_temperature, 54 | const double* temperature, 55 | // Output variables: 56 | double radiance[2], 57 | // Output Jacobians: 58 | double dradiance_dsurface_temperature[2], 59 | double* dradiance_dtemperature) 60 | { 61 | // First temporarily deactivate any existing Adept stack used by the 62 | // calling function 63 | adept::Stack* caller_stack = adept::active_stack(); 64 | if (caller_stack != 0) { 65 | caller_stack->deactivate(); 66 | } 67 | 68 | // Within the scope of these curly brackets, another Adept stack 69 | // will be used 70 | { 71 | // Ficticious oxygen channels around 60 GHz: wavelength in m 72 | static const double wavelength[2] = {0.006, 0.0061}; 73 | // Mass absorption coefficient of oxygen in m2 kg-1 74 | static const double mass_abs_coefft[2] = {3.0e-5, 3.0e-3}; 75 | // Layer thickness in m 76 | static const double dz = 1000.0; 77 | 78 | // Density of oxygen in kg m-3 79 | std::vector density_oxygen(n); 80 | // Emissivity at a particular microwave wavelength 81 | std::vector emissivity(n); 82 | 83 | // Start a new stack 84 | adept::Stack s; 85 | 86 | // Create local active variables: surface temperature, temperature 87 | // and radiance 88 | adouble st = surface_temperature; 89 | std::vector t(n); 90 | adouble r[2]; 91 | 92 | // Initialize the oxygen density and temperature 93 | for (int i = 0; i < n; i++) { 94 | double altitude = i*dz; 95 | // Oxygen density uses an assumed volume mixing ratio with air 96 | // of 21%, molecular mass of 16 (compared to 29 for air), a 97 | // surface air density of 1.2 kg m-3 and an atmospheric scale 98 | // height of 8000 m 99 | density_oxygen[i] = 1.2*0.21*(16.0/29.0)*exp(-altitude/8000.0); 100 | t[i] = temperature[i]; 101 | } 102 | 103 | // Start recording derivative information 104 | s.new_recording(); 105 | 106 | // Loop through the two channels 107 | for (int ichan = 0; ichan < 2; ichan++) { 108 | // Compute the emissivity profile 109 | for (int i = 0; i < n; i++) { 110 | emissivity[i] = 1.0-exp(-density_oxygen[i]*mass_abs_coefft[ichan]*dz); 111 | } 112 | // Simulate the radiance 113 | r[ichan] = simulate_radiance_private(n, wavelength[ichan], 114 | &emissivity[0], st, &t[0]); 115 | // Copy the adouble variable to the double variable 116 | radiance[ichan] = r[ichan].value(); 117 | } 118 | 119 | // Declare independent (x) and dependent (y) variables for 120 | // Jacobian matrix 121 | s.independent(st); 122 | s.independent(&t[0], n); 123 | s.dependent(r, 2); 124 | 125 | std::cout << s; 126 | 127 | // Compute Jacobian matrix 128 | std::vector jacobian((n+1)*2); 129 | s.jacobian(&jacobian[0]); 130 | 131 | // Copy elements of Jacobian matrix into the calling arrays 132 | for (int ichan = 0; ichan < 2; ichan++) { 133 | dradiance_dsurface_temperature[ichan] = jacobian[ichan]; 134 | for (int i = 0; i < n; i++) { 135 | dradiance_dtemperature[i*2+ichan] = jacobian[2+i*2+ichan]; 136 | } 137 | } 138 | 139 | // At the following curly bracket, the local Adept stack will be 140 | // destructed 141 | } 142 | 143 | // Reactivate the Adept stack of the calling function 144 | if (caller_stack != 0) { 145 | caller_stack->activate(); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /test/simulate_radiances.h: -------------------------------------------------------------------------------- 1 | /* simulate_radiances.h - a function taking inactive arguments that returns also Jacobian matrices 2 | 3 | Copyright (C) 2012-2014 The University of Reading 4 | 5 | Copying and distribution of this file, with or without modification, 6 | are permitted in any medium without royalty provided the copyright 7 | notice and this notice are preserved. This file is offered as-is, 8 | without any warranty. 9 | */ 10 | 11 | void simulate_radiances(int n, // Size of temperature array 12 | // Input variables: 13 | double surface_temperature, 14 | const double* temperature, 15 | // Output variables: 16 | double radiance[2], 17 | // Output Jacobians: 18 | double dradiance_dsurface_temperature[2], 19 | double* dradiance_dtemperature); 20 | -------------------------------------------------------------------------------- /test/state.cpp: -------------------------------------------------------------------------------- 1 | /* state.cpp - An object-oriented interface to an Adept-based minimizer 2 | 3 | Copyright (C) 2012-2014 The University of Reading 4 | 5 | Copying and distribution of this file, with or without modification, 6 | are permitted in any medium without royalty provided the copyright 7 | notice and this notice are preserved. This file is offered as-is, 8 | without any warranty. 9 | */ 10 | 11 | // Note that this implementation uses the GNU Scientific Library (GSL) 12 | // to provide the quasi-Newton minimization capability 13 | 14 | #include 15 | #include 16 | 17 | #include "state.h" 18 | 19 | // C functions needed by GSL 20 | 21 | // Return function value given a vector of state variables x 22 | extern "C" 23 | double my_function_value(const gsl_vector* x, void* params) { 24 | State* state = reinterpret_cast(params); 25 | return state->calc_function_value(x->data); 26 | } 27 | // Return gradient of function with respect to each state variable x 28 | extern "C" 29 | void my_function_gradient(const gsl_vector* x, void* params, gsl_vector* gradJ) { 30 | State* state = reinterpret_cast(params); 31 | state->calc_function_value_and_gradient(x->data, gradJ->data); 32 | } 33 | // Return both function and its gradient 34 | extern "C" 35 | void my_function_value_and_gradient(const gsl_vector* x, void* params, 36 | double* J, gsl_vector* gradJ) { 37 | State* state = reinterpret_cast(params); 38 | *J = state->calc_function_value_and_gradient(x->data, gradJ->data); 39 | } 40 | 41 | using adept::adouble; 42 | 43 | // "State" member function for returning the value of the function; it 44 | // does this by calling the underlying calc_function_value(const 45 | // adouble&) function, which is defined in 46 | // rosenbrock_banana_function.cpp. Since the gradient is not 47 | // required, the recording of automatic differentiation is "paused" 48 | // while this function is called. 49 | double State::calc_function_value(const double* x) { 50 | stack_.pause_recording(); 51 | for (unsigned int i = 0; i < nx(); ++i) active_x_[i] = x[i]; 52 | double result = value(calc_function_value(&active_x_[0])); 53 | stack_.continue_recording(); 54 | return result; 55 | } 56 | 57 | // Member function for returning both the value of the function and 58 | // its gradient - here Adept is used to compute the gradient 59 | double State::calc_function_value_and_gradient(const double* x, double* dJ_dx) { 60 | for (unsigned int i = 0; i < nx(); ++i) active_x_[i] = x[i]; 61 | stack_.new_recording(); 62 | adouble J = calc_function_value(&active_x_[0]); 63 | J.set_gradient(1.0); 64 | stack_.compute_adjoint(); 65 | adept::get_gradients(&active_x_[0], nx(), dJ_dx); 66 | return value(J); 67 | } 68 | 69 | // Minimize the function, returning true if minimization successful, 70 | // false otherwise 71 | bool State::minimize() { 72 | // Minimizer settings 73 | const double initial_step_size = 0.01; 74 | const double line_search_tolerance = 1.0e-4; 75 | const double converged_gradient_norm = 1.0e-3; 76 | // Use the "limited-memory BFGS" quasi-Newton minimizer 77 | const gsl_multimin_fdfminimizer_type* minimizer_type 78 | = gsl_multimin_fdfminimizer_vector_bfgs2; 79 | 80 | // Declare and populate structure containing function pointers 81 | gsl_multimin_function_fdf my_function; 82 | my_function.n = nx(); 83 | my_function.f = my_function_value; 84 | my_function.df = my_function_gradient; 85 | my_function.fdf = my_function_value_and_gradient; 86 | my_function.params = reinterpret_cast(this); 87 | 88 | // Set initial state variables using GSL's vector type: use -5.0 for 89 | // every value 90 | gsl_vector *x; 91 | x = gsl_vector_alloc(nx()); 92 | for (unsigned int i = 0; i < nx(); ++i) gsl_vector_set(x, i, -5.0); 93 | 94 | // Configure the minimizer, and call function once 95 | gsl_multimin_fdfminimizer* minimizer 96 | = gsl_multimin_fdfminimizer_alloc(minimizer_type, nx()); 97 | gsl_multimin_fdfminimizer_set(minimizer, &my_function, x, 98 | initial_step_size, line_search_tolerance); 99 | 100 | // Print out the result of the first function call with the initial 101 | // state 102 | std::cout << "Initial state: x = ["; 103 | for (unsigned int i = 0; i < nx(); i++) { 104 | std::cout << active_x_[i].value() << " "; 105 | } 106 | std::cout << "], cost_function = " << minimizer->f << "\n"; 107 | 108 | // Begin loop 109 | size_t iter = 0; 110 | int status; 111 | do { 112 | ++iter; 113 | // Perform one iteration 114 | status = gsl_multimin_fdfminimizer_iterate(minimizer); 115 | 116 | // Quit loop if iteration failed 117 | if (status != GSL_SUCCESS) break; 118 | 119 | // Test for convergence 120 | status = gsl_multimin_test_gradient(minimizer->gradient, 121 | converged_gradient_norm); 122 | 123 | // Print out limited number of state variables from this 124 | // iteration, and the corresponding cost function 125 | std::cout << "Iteration " << iter << ": x = ["; 126 | for (unsigned int i = 0; i < nx(); i++) { 127 | std::cout << active_x_[i].value() << " "; 128 | if (i >= 5) { 129 | std::cout << "..."; 130 | break; 131 | } 132 | } 133 | std::cout << "], cost_function = " << minimizer->f << "\n"; 134 | } 135 | while (status == GSL_CONTINUE && iter < 1000); 136 | 137 | // Free memory 138 | gsl_multimin_fdfminimizer_free(minimizer); 139 | gsl_vector_free(x); 140 | 141 | // Return true if successfully minimized function, false otherwise 142 | if (status == GSL_SUCCESS) { 143 | std::cout << "Minimum found after " << iter << " iterations\n"; 144 | return true; 145 | } 146 | else { 147 | std::cout << "Minimizer failed after " << iter << " iterations: " 148 | << gsl_strerror(status) << "\n"; 149 | return false; 150 | } 151 | } 152 | 153 | // Enquiry function to return the current value of the state 154 | // variables, called after minimize() has been run. 155 | void 156 | State::x(std::vector& x_out) const 157 | { 158 | x_out.resize(nx()); 159 | for (unsigned int i = 0; i < nx(); i++) { 160 | x_out[i] = active_x_[i].value(); 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /test/state.h: -------------------------------------------------------------------------------- 1 | /* state.h - An object-oriented interface to an Adept-based minimizer 2 | 3 | Copyright (C) 2012-2014 The University of Reading 4 | 5 | Copying and distribution of this file, with or without modification, 6 | are permitted in any medium without royalty provided the copyright 7 | notice and this notice are preserved. This file is offered as-is, 8 | without any warranty. 9 | */ 10 | 11 | #ifndef STATE_H 12 | #define STATE_H 1 13 | #include 14 | #include "adept.h" 15 | class State { 16 | public: 17 | // Construct a state with n state variables 18 | State(int n) { active_x_.resize(n); } 19 | // Minimize the function, returning true if minimization 20 | // successful, false otherwise 21 | bool minimize(); 22 | // Get copy of state variables after minimization 23 | void x(std::vector& x_out) const; 24 | // For input state variables x, compute the function J(x) and 25 | // return it 26 | double calc_function_value(const double* x); 27 | // For input state variables x, compute function and put its 28 | // gradient in dJ_dx 29 | double calc_function_value_and_gradient(const double* x, double* dJ_dx); 30 | // Return the size of the state vector 31 | unsigned int nx() const { return active_x_.size(); } 32 | protected: 33 | // Active version of the function: the algorithm is contained in 34 | // the definition of this function (in 35 | // rosenbrock_banana_function.cpp) 36 | adept::adouble calc_function_value(const adept::adouble* x); 37 | // DATA 38 | adept::Stack stack_; // Adept stack object 39 | std::vector active_x_; // Active state variables 40 | }; 41 | #endif 42 | -------------------------------------------------------------------------------- /test/test_adept.cpp: -------------------------------------------------------------------------------- 1 | /* test_adept.cpp - Demonstration of basic features of Adept 2 | 3 | Copyright (C) 2012-2014 The University of Reading 4 | 5 | Copying and distribution of this file, with or without modification, 6 | are permitted in any medium without royalty provided the copyright 7 | notice and this notice are preserved. This file is offered as-is, 8 | without any warranty. 9 | */ 10 | 11 | #include 12 | 13 | #include "adept.h" 14 | 15 | // Provide function prototype for "algorithm"; see algorithm.cpp for 16 | // the contents of the function 17 | #include "algorithm.h" 18 | 19 | int 20 | main(int argc, char** argv) 21 | { 22 | using adept::adouble; 23 | 24 | // Start an Adept stack before the first adouble object is 25 | // constructed 26 | adept::Stack s; 27 | 28 | adouble x[2]; // Our independent variables 29 | adouble y; // Our dependent variable 30 | 31 | // Set the values of x 32 | x[0] = 2.0; 33 | x[1] = 3.0; 34 | 35 | 36 | // PART 1: NUMERICAL ADJOINT 37 | std::cout << "*** Computing numerical adjoint ***\n\n"; 38 | 39 | // We will provide an estimate of the adjoints by perturbing the 40 | // inputs by a small amount 41 | 42 | adouble x_perturbed[2]; // Perturbed independent variables 43 | 44 | // This version of the code uses the same algorithm function that 45 | // takes adouble arguments for doing the numerical adjoint, even 46 | // though we are not doing automatic differentiation. To make it 47 | // faster, we can turn off the recording of derivative information 48 | // using the pause_recording function. This only works if all code 49 | // has been compiled with the -DADEPT_RECORDING_PAUSABLE flag; 50 | // otherwise it does nothing (so the program will still run 51 | // correctly, but will be less efficient). Note that another 52 | // approach if you want to call a function several times, sometimes 53 | // with automatic differentiation and sometimes without, is 54 | // demonstrated in 55 | // test_adept_with_without_automatic_differentiation.cpp. 56 | s.pause_recording(); 57 | 58 | // We will compare the Adept result to a numerically computed 59 | // adjoint, so define the perturbation size 60 | double dx = 1.0e-5; 61 | 62 | // Run the algorithm 63 | y = algorithm(x); 64 | 65 | // Now perturb x[0] and x[1] in turn and get a numerical estimate of 66 | // the gradient 67 | x_perturbed[0] = x[0]+dx; 68 | x_perturbed[1] = x[1]; 69 | double dy_dx0 = adept::value((algorithm(x_perturbed)-y)/dx); 70 | x_perturbed[0] = x[0]; 71 | x_perturbed[1] = x[1]+dx; 72 | double dy_dx1 = adept::value((algorithm(x_perturbed)-y)/dx); 73 | 74 | // Turn the recording of deriviative information back on 75 | s.continue_recording(); 76 | 77 | // Print information about the data held in the stack 78 | std::cout << "Stack status after numerical adjoint (if recording was successfully\n" 79 | << "paused then the number of operations should be zero):\n" 80 | << s; 81 | // Print memory information 82 | std::cout << "Memory usage: " << s.memory() << " bytes\n\n"; 83 | 84 | // PART 2: REVERSE-MODE AUTOMATIC DIFFERENTIATION 85 | 86 | // Now we use Adept to do the automatic differentiation 87 | std::cout << "*** Computing adjoint using automatic differentiation ***\n\n"; 88 | 89 | // Start a new recording of derivative statements; note that this 90 | // must be done after the independent variables x[0] and x[1] are 91 | // defined and after they have been given their initial values 92 | s.new_recording(); 93 | 94 | // Run the algorithm again 95 | y = algorithm(x); 96 | 97 | // Print information about the data held in the stack 98 | std::cout << "Stack status after algorithm run but adjoint not yet computed:\n" 99 | << s; 100 | // Print memory information 101 | std::cout << "Memory usage: " << s.memory() << " bytes\n\n"; 102 | 103 | // If we set the adjoint of the dependent variable to 1 then the 104 | // resulting adjoints of the independent variables after 105 | // reverse-mode automatic differentiation will be comparable to the 106 | // outputs of the numerical differentiation 107 | y.set_gradient(1.0); 108 | 109 | // Print out some diagnostic information 110 | std::cout << "List of derivative statements:\n"; 111 | s.print_statements(); 112 | std::cout << "\n"; 113 | 114 | std::cout << "Initial list of gradients:\n"; 115 | s.print_gradients(); 116 | std::cout << "\n"; 117 | 118 | // Run the adjoint algorithm (reverse-mode differentiation) 119 | s.reverse(); 120 | 121 | // Some more diagnostic information 122 | std::cout << "Final list of gradients:\n"; 123 | s.print_gradients(); 124 | std::cout << "\n"; 125 | 126 | // Extract the adjoints of the independent variables 127 | double x0_ad = 0, x1_ad = 0; 128 | x[0].get_gradient(x0_ad); 129 | x[1].get_gradient(x1_ad); 130 | 131 | 132 | // PART 3: JACOBIAN COMPUTATION 133 | 134 | // Here we use the same recording to compute the Jacobian matrix 135 | std::cout << "*** Computing Jacobian matrix ***\n\n"; 136 | 137 | s.independent(x, 2); // Declare independents 138 | s.dependent(y); // Declare dependents 139 | double jac[2]; // Where the Jacobian will be stored 140 | s.jacobian(jac); // Compute Jacobian 141 | 142 | 143 | // PART 4: PRINT OUT RESULTS 144 | 145 | // Print information about the data held in the stack 146 | std::cout << "Stack status after adjoint and Jacobian computed:\n" 147 | << s; 148 | // Print memory information 149 | std::cout << "Memory usage: " << s.memory() << " bytes\n\n"; 150 | 151 | std::cout << "Result of forward algorithm:\n"; 152 | std::cout << " y = " << y.value() << "\n"; 153 | 154 | std::cout << "Comparison of gradients:\n"; 155 | std::cout << " dy_dx0[numerical] = " << dy_dx0 << "\n"; 156 | std::cout << " dy_dx0[adjoint] = " << x0_ad << "\n"; 157 | std::cout << " dy_dx0[jacobian] = " << jac[0] << "\n"; 158 | std::cout << " dy_dx1[numerical] = " << dy_dx1 << "\n"; 159 | std::cout << " dy_dx1[adjoint] = " << x1_ad << "\n"; 160 | std::cout << " dy_dx1[jacobian] = " << jac[1] << "\n"; 161 | 162 | std::cout << "\nNote that the numerical gradients are less accurate since they use\n" 163 | << "a finite difference and are also succeptible to round-off error.\n"; 164 | 165 | return 0; 166 | 167 | } 168 | -------------------------------------------------------------------------------- /test/test_adept_with_and_without_ad.cpp: -------------------------------------------------------------------------------- 1 | /* test_adept_with_and_without_ad.cpp 2 | 3 | Copyright (C) 2012-2014 The University of Reading 4 | 5 | Copying and distribution of this file, with or without modification, 6 | are permitted in any medium without royalty provided the copyright 7 | notice and this notice are preserved. This file is offered as-is, 8 | without any warranty. 9 | */ 10 | 11 | // Demonstration of the use of Adept with code (in this case, 12 | // algorithm.cpp) that has been compiled twice, once with automatic 13 | // differentiation enabled (the default) and once with it disabled 14 | // (using -DADEPT_NO_AUTOMATIC_DIFFERENTIATION) to provide a faster 15 | // version of a function that works with double rather than adouble 16 | // objects. 17 | 18 | #include 19 | 20 | #include "adept.h" 21 | 22 | // Provide function prototypes for "algorithm"; see algorithm.cpp for 23 | // the contents of the function 24 | #include "algorithm_with_and_without_ad.h" 25 | 26 | // Simple demonstration of automatic differentiation using Adept 27 | int 28 | main(int argc, char** argv) 29 | { 30 | using adept::adouble; 31 | 32 | // Start an Adept stack before the first adouble object is 33 | // constructed 34 | adept::Stack s; 35 | 36 | adouble x[2]; // Our independent variables 37 | adouble y; // Our dependent variable 38 | 39 | // Set the values of x 40 | x[0] = 2.0; 41 | x[1] = 3.0; 42 | 43 | 44 | // PART 1: NUMERICAL ADJOINT 45 | std::cout << "*** Computing numerical adjoint ***\n\n"; 46 | 47 | // We will compare the Adept result to a numerically computed 48 | // adjoint, so define the perturbation size 49 | double dx = 1.0e-5; 50 | 51 | // Initialize a inactive version of x as double rather than adouble 52 | // variables 53 | double x_r[2]; 54 | x_r[0] = x[0].value(); 55 | x_r[1] = x[1].value(); 56 | 57 | // Run the original version of the algorithm that takes real 58 | // arguments; this was compiled from algorithm.cpp using the 59 | // -DADEPT_NO_AUTOMATIC_DIFFERENTIATION flag to produce the 60 | // algorithm_noad.o object file 61 | double y_real = algorithm(x_r); 62 | 63 | // Now perturb x[0] and x[1] in turn and get a numerical estimate of 64 | // the gradient 65 | x_r[0] = x[0].value()+dx; 66 | x_r[1] = x[1].value(); 67 | double dy_dx0 = (algorithm(x_r)-y_real)/dx; 68 | x_r[0] = x[0].value(); 69 | x_r[1] = x[1].value()+dx; 70 | double dy_dx1 = (algorithm(x_r)-y_real)/dx; 71 | 72 | // Print information about the data held in the stack 73 | std::cout << "Stack status after numerical adjoint (number of operations should be zero):\n" 74 | << s << "\n"; 75 | 76 | 77 | // PART 2: REVERSE-MODE AUTOMATIC DIFFERENTIATION 78 | std::cout << "*** Computing adjoint using automatic differentiation ***\n\n"; 79 | 80 | // Start a new recording of derivative statements (note that this 81 | // must be done after the independent variables x[0] and x[1] are 82 | // initialized 83 | s.new_recording(); 84 | 85 | // Now use Adept to do it - first run the algorithm overloaded for 86 | // adouble arguments 87 | y = algorithm(x); 88 | 89 | // Print information about the data held in the stack 90 | std::cout << "Stack status after algorithm run but adjoint not yet computed:\n" 91 | << s << "\n"; 92 | 93 | // If we set the adjoint of the dependent variable to 1 then the 94 | // resulting adjoints of the independent variables after 95 | // reverse-mode automatic differentiation will be comparable to the 96 | // outputs of the numerical differentiation 97 | y.set_gradient(1.0); 98 | 99 | // Print out some diagnostic information 100 | std::cout << "List of derivative statements:\n"; 101 | s.print_statements(); 102 | std::cout << "\n"; 103 | 104 | std::cout << "Initial list of gradients:\n"; 105 | s.print_gradients(); 106 | std::cout << "\n"; 107 | 108 | // Run the adjoint algorithm (reverse-mode differentiation) 109 | s.reverse(); 110 | 111 | std::cout << "Final list of gradients:\n"; 112 | s.print_gradients(); 113 | std::cout << "\n"; 114 | 115 | // Extract the adjoints of the independent variables 116 | double x0_ad = 0, x1_ad = 0; 117 | x[0].get_gradient(x0_ad); 118 | x[1].get_gradient(x1_ad); 119 | 120 | 121 | // PART 3: JACOBIAN COMPUTATION 122 | 123 | // Here we use the same recording to compute the Jacobian matrix 124 | std::cout << "*** Computing Jacobian matrix ***\n\n"; 125 | 126 | s.independent(x, 2); // Declare independents 127 | s.dependent(y); // Declare dependents 128 | double jac[2]; 129 | s.jacobian(jac); // Compute Jacobian 130 | 131 | 132 | // PART 4: PRINT OUT RESULT 133 | 134 | // Print information about the data held in the stack 135 | std::cout << "Stack status after adjoint and Jacobian computed:\n" 136 | << s << "\n"; 137 | 138 | // Print memory information 139 | std::cout << "Memory usage: " << s.memory() << " bytes\n\n"; 140 | 141 | std::cout << "Result of forward algorithm:\n"; 142 | std::cout << " y[from algorithm taking double arguments] = " << y_real << "\n"; 143 | std::cout << " y[from algorithm taking adouble arguments] = " << y.value() << "\n\n"; 144 | 145 | std::cout << "Comparison of gradients:\n"; 146 | std::cout << " dy_dx0[numerical] = " << dy_dx0 << "\n"; 147 | std::cout << " dy_dx0[adjoint] = " << x0_ad << "\n"; 148 | std::cout << " dy_dx0[jacobian] = " << jac[0] << "\n"; 149 | std::cout << " dy_dx1[numerical] = " << dy_dx1 << "\n"; 150 | std::cout << " dy_dx1[adjoint] = " << x1_ad << "\n"; 151 | std::cout << " dy_dx1[jacobian] = " << jac[1] << "\n"; 152 | 153 | std::cout << "\nNote that the numerical gradients are less accurate since they use\n" 154 | << "a finite difference and are also succeptible to round-off error.\n"; 155 | 156 | return 0; 157 | 158 | } 159 | -------------------------------------------------------------------------------- /test/test_checkpoint.cpp: -------------------------------------------------------------------------------- 1 | /* test_checkpoint.cpp - Test manual checkpointing of a simulation 2 | 3 | Copyright (C) 2012-2014 The University of Reading 4 | 5 | Copying and distribution of this file, with or without modification, 6 | are permitted in any medium without royalty provided the copyright 7 | notice and this notice are preserved. This file is offered as-is, 8 | without any warranty. 9 | */ 10 | 11 | #include 12 | #include 13 | 14 | #include "adept.h" 15 | // This header file is in the same directory as adept.h in the Adept 16 | // package 17 | #include "Timer.h" 18 | 19 | using adept::adouble; 20 | 21 | // Number of points in spatial grid of simulation 22 | #define NX 100 23 | 24 | // "Toon" advection scheme applied to linear advection in a 1D 25 | // periodic domain - see Adept paper for details 26 | static 27 | void 28 | toon(int nt, double c, const adouble q_init[NX], adouble q[NX]) { 29 | adouble flux[NX-1]; // Fluxes between boxes 30 | for (int i=0; i= 0; i--) { 202 | stack.new_recording(); 203 | toon(nt, dt, q_save[i], q); 204 | 205 | // This time we use the set of gradients output from the previous 206 | // simulation (which can be thought of as dJ/dq_save[i+1]) as 207 | // the input gradients for the next 208 | adept::set_gradients(q, NX, dJ_dq); 209 | 210 | // Perform adjoint calculation 211 | stack.reverse(); 212 | 213 | // Extract the next set of gradients (which can be thought of as 214 | // dJ/dq_save[i]) and place in dJ_dq ready for the next 215 | // iteration 216 | adept::get_gradients(q_save[i], NX, dJ_dq); 217 | } 218 | 219 | // Print out the gradients 220 | std::cout << "dJ_dq=["; 221 | for (int i = 0; i < NX; i++) { 222 | std::cout << " " << dJ_dq[i]; 223 | } 224 | std::cout << "]\n"; 225 | std::cout << stack; 226 | } 227 | timer.stop(); 228 | 229 | return 0; 230 | 231 | } 232 | -------------------------------------------------------------------------------- /test/test_gsl_interface.cpp: -------------------------------------------------------------------------------- 1 | /* test_gsl_interface.cpp - "main" function for Test 4 2 | 3 | Copyright (C) 2012-2014 The University of Reading 4 | 5 | Copying and distribution of this file, with or without modification, 6 | are permitted in any medium without royalty provided the copyright 7 | notice and this notice are preserved. This file is offered as-is, 8 | without any warranty. 9 | */ 10 | 11 | // This program minimizes the N-dimensional Rosenbrock banana 12 | // function, with the number of dimensions optionally provided on the 13 | // command line 14 | 15 | #include 16 | #include 17 | 18 | #include "state.h" 19 | 20 | int 21 | main(int argc, char** argv) 22 | { 23 | std::cout << "Testing Adept-GSL interface using N-dimensional Rosenbrock function\n"; 24 | std::cout << "Usage: " << argv[0] << " [number_of_dimensions]\n"; 25 | 26 | // Read number of dimensions from the command line (default 2) 27 | int nx = 2; 28 | if (argc > 1) { 29 | nx = atoi(argv[1]); 30 | } 31 | 32 | if (nx < 2) { 33 | std::cout << "Error: must have 2 or more dimensions, but " 34 | << nx << " requested\n"; 35 | return 1; 36 | } 37 | 38 | // Create minimization environment (see state.h) and then minimize 39 | // the function; note that initial values are set on construction. 40 | State state(nx); 41 | state.minimize(); 42 | 43 | // Print out the result 44 | std::vector x; 45 | state.x(x); 46 | std::cout << "Final state: x = ["; 47 | for (int i = 0; i < nx; i++) { 48 | std::cout << " " << x[i]; 49 | } 50 | std::cout << "]\n"; 51 | 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /test/test_misc.cpp: -------------------------------------------------------------------------------- 1 | /* test_misc.cpp 2 | 3 | Copyright (C) 2012-2014 The University of Reading 4 | 5 | Copying and distribution of this file, with or without modification, 6 | are permitted in any medium without royalty provided the copyright 7 | notice and this notice are preserved. This file is offered as-is, 8 | without any warranty. 9 | */ 10 | 11 | #include "adept.h" 12 | #include "algorithm.h" 13 | 14 | // A straight implementation of the trivial example in Hogan (2014) 15 | 16 | double algorithm_ad(const double x_val[2], // Input values 17 | double* Y_ad, // Input-output adjoint 18 | double x_ad[2]) { // Output adjoint 19 | using namespace adept; // Import Stack and adouble from adept 20 | Stack stack; // Where differential information is stored 21 | adouble x[2] = {x_val[0], x_val[1]}; // Initialize adouble inputs 22 | stack.new_recording(); // Start recording derivatives 23 | adouble Y = algorithm(x); // Version overloaded for adouble args 24 | Y.set_gradient(*Y_ad); // Load the input-output adjoint 25 | stack.reverse(); // Run the adjoint algorithm 26 | x_ad[0] = x[0].get_gradient(); // Extract the output adjoint for x[0] 27 | x_ad[1] = x[1].get_gradient(); // ...and x[1] 28 | *Y_ad = Y.get_gradient(); // Input-output adjoint has changed too 29 | return Y.value(); // Return result of simple computation 30 | } 31 | 32 | int main() 33 | { 34 | double x[2] = {2.0, 3.0}; 35 | double y_ad = 1.0; 36 | double x_ad[2]; 37 | double y = algorithm_ad(x, &y_ad, x_ad); 38 | std::cout << "x[0] = " << x[0] << "\n" 39 | << "x[1] = " << x[1] << "\n" 40 | << "y = " << y << "\n" 41 | << "y_ad = " << y_ad << "\n" 42 | << "x_ad[0]=" << x_ad[0] << "\n" 43 | << "x_ad[1]=" << x_ad[1] << "\n"; 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /test/test_no_lib.cpp: -------------------------------------------------------------------------------- 1 | /* test_no_lib.cpp 2 | 3 | Copyright (C) 2012-2014 The University of Reading 4 | 5 | Copying and distribution of this file, with or without modification, 6 | are permitted in any medium without royalty provided the copyright 7 | notice and this notice are preserved. This file is offered as-is, 8 | without any warranty. 9 | */ 10 | 11 | // This source file contains everything that would normally be 12 | // compiled into a static or dynamic library; this means that the 13 | // executable can be built without needing to link to the 14 | // library. This is useful for non-Unix platforms where the configure 15 | // script cannot be run. Note that only one source file should 16 | // #include "adept_source.h"; all the others should #include "adept.h" 17 | // as normal. 18 | #include "adept_source.h" 19 | 20 | #include "algorithm.h" 21 | 22 | // A straight implementation of the trivial example in Hogan (2014) 23 | 24 | double algorithm_ad(const double x_val[2], // Input values 25 | double* Y_ad, // Input-output adjoint 26 | double x_ad[2]) { // Output adjoint 27 | using namespace adept; // Import Stack and adouble from adept 28 | Stack stack; // Where differential information is stored 29 | adouble x[2] = {x_val[0], x_val[1]}; // Initialize adouble inputs 30 | stack.new_recording(); // Start recording derivatives 31 | adouble Y = algorithm(x); // Version overloaded for adouble args 32 | Y.set_gradient(*Y_ad); // Load the input-output adjoint 33 | stack.reverse(); // Run the adjoint algorithm 34 | x_ad[0] = x[0].get_gradient(); // Extract the output adjoint for x[0] 35 | x_ad[1] = x[1].get_gradient(); // ...and x[1] 36 | *Y_ad = Y.get_gradient(); // Input-output adjoint has changed too 37 | return Y.value(); // Return result of simple computation 38 | } 39 | 40 | int main() 41 | { 42 | double x[2] = {2.0, 3.0}; 43 | double y_ad = 1.0; 44 | double x_ad[2]; 45 | double y = algorithm_ad(x, &y_ad, x_ad); 46 | std::cout << "x[0] = " << x[0] << "\n" 47 | << "x[1] = " << x[1] << "\n" 48 | << "y = " << y << "\n" 49 | << "y_ad = " << y_ad << "\n" 50 | << "x_ad[0]=" << x_ad[0] << "\n" 51 | << "x_ad[1]=" << x_ad[1] << "\n"; 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /test/test_radiances.cpp: -------------------------------------------------------------------------------- 1 | /* test_radiances.cpp - "main" function for Test 3 2 | 3 | Copyright (C) 2012-2014 The University of Reading 4 | 5 | Copying and distribution of this file, with or without modification, 6 | are permitted in any medium without royalty provided the copyright 7 | notice and this notice are preserved. This file is offered as-is, 8 | without any warranty. 9 | */ 10 | 11 | #include "adept.h" 12 | #include "simulate_radiances.h" 13 | 14 | using adept::adouble; 15 | 16 | // This function provides an Adept interface to the simulate_radiances 17 | // function 18 | void simulate_radiances_wrapper(int n, 19 | const adouble& surface_temperature, 20 | const adouble* temperature, 21 | adouble radiance[2]) { 22 | // Create inactive (double) versions of the active (adouble) inputs 23 | double st = value(surface_temperature); 24 | std::vector t(n); 25 | for (int i = 0; i < n; ++i) t[i] = value(temperature[i]); 26 | 27 | // Declare variables to hold the inactive outputs and their Jacobians 28 | double r[2]; 29 | double dr_dst[2]; 30 | std::vector dr_dt(2*n); 31 | 32 | // Call the function with the non-Adept interface 33 | simulate_radiances(n, st, &t[0], &r[0], dr_dst, &dr_dt[0]); 34 | 35 | // Copy the results into the active variables, but use set_value in order 36 | // not to write any equivalent derivative statement to the Adept stack 37 | radiance[0].set_value(r[0]); 38 | radiance[1].set_value(r[1]); 39 | 40 | // Loop over the two radiances and add the derivative statements to 41 | // the Adept stack 42 | for (int i = 0; i < 2; ++i) { 43 | // Add the first term on the right-hand-side of Equation 1 in the text 44 | radiance[i].add_derivative_dependence(surface_temperature, dr_dst[i]); 45 | // Now append the second term on the right-hand-side of Equation 46 | // 1. The third argument "n" of the following function says that 47 | // there are n terms to be summed, and the fourth argument "2" 48 | // says to take only every second element of the Jacobian dr_dt, 49 | // since the derivatives with respect to the two radiances have 50 | // been interlaced. If the fourth argument is omitted then 51 | // relevant Jacobian elements will be assumed to be contiguous in 52 | // memory. 53 | radiance[i].append_derivative_dependence(temperature, &dr_dt[i], n, 2); 54 | } 55 | 56 | for (int i = 0; i < 2; ++i) { 57 | std::cout << "Channel " << i << "\n"; 58 | std::cout << "d[radiance]/d[surface_temperature] = " << dr_dst[i] << "\n"; 59 | std::cout << "d[radiance]/d[temperature] ="; 60 | for (int j = 0; j < n; ++j) { 61 | std::cout << " " << dr_dt[i+j*2]; 62 | } 63 | std::cout << "\n\n"; 64 | } 65 | 66 | } 67 | 68 | 69 | int 70 | main(int argc, char** argv) 71 | { 72 | // Temperature (K) at 1000-m intervals from the mid-latitude summer 73 | // standard atmosphere 74 | static const int N_POINTS = 25; 75 | static const double temperature_profile[N_POINTS+1] 76 | = {294.0, 290.0, 285.0, 279.0, 273.0, 267.0, 261.0, 255.0, 77 | 248.0, 242.0, 235.0, 229.0, 222.0, 216.0, 216.0, 216.0, 78 | 216.0, 216.0, 216.0, 217.0, 218.0, 219.0, 220.0, 222.0, 79 | 223.0, 224.0}; 80 | 81 | // Start the Adept stack 82 | adept::Stack s; 83 | 84 | // Copy the temperature profile information into active variables 85 | adouble surface_temperature = temperature_profile[0]; 86 | adouble temperature[N_POINTS]; 87 | for (int i = 0; i < N_POINTS; i++) { 88 | temperature[i] = temperature_profile[i+1]; 89 | } 90 | 91 | // The simulated radiances will be put here... 92 | adouble sim_radiance[2]; 93 | 94 | // ...and compared to the observed radiances here with their 1-sigma 95 | // error 96 | double obs_radiance[2] = {0.00189, 0.00140}; 97 | double radiance_error = 2.0e-5; 98 | 99 | // Start recording derivative information 100 | s.new_recording(); 101 | 102 | // Simulate the radiances for the input surface temperature and 103 | // atmospheric temperature 104 | simulate_radiances_wrapper(N_POINTS, surface_temperature, 105 | temperature, sim_radiance); 106 | 107 | std::cout << "Simulated radiances = " 108 | << sim_radiance[0].value() << " " 109 | << sim_radiance[1].value() << "\n"; 110 | 111 | // Compute a "cost function" (or "penalty function") expressing the 112 | // sum of the squared number of error standard deviations the 113 | // simulated radiances are from the observed radiances 114 | adouble cost_function = 0.0; 115 | for (int ichan = 0; ichan < 2; ichan++) { 116 | cost_function 117 | += (sim_radiance[ichan] - obs_radiance[ichan]) 118 | * (sim_radiance[ichan] - obs_radiance[ichan]) 119 | / (radiance_error*radiance_error); 120 | } 121 | 122 | std::cout << "Cost function = " << cost_function << "\n"; 123 | 124 | // We want the computed adjoints to be gradients of the cost 125 | // function with respect to the surface temperature or atmospheric 126 | // temperature 127 | cost_function.set_gradient(1.0); 128 | 129 | // Reverse-mode automatic differentiation 130 | s.reverse(); 131 | 132 | // Extract the gradients 133 | double dcost_dsurface_temperature = 0; 134 | double dcost_dtemperature[N_POINTS]; 135 | surface_temperature.get_gradient(dcost_dsurface_temperature); 136 | adept::get_gradients(temperature, N_POINTS, dcost_dtemperature); 137 | 138 | 139 | std::cout << "d[cost_function]/d[surface_temperature] = " 140 | << dcost_dsurface_temperature << "\n"; 141 | std::cout << "d[cost_function]/d[temperature] ="; 142 | for (int i = 0; i < N_POINTS; i++) { 143 | std::cout << " " << dcost_dtemperature[i]; 144 | } 145 | std::cout << "\n"; 146 | 147 | 148 | } 149 | -------------------------------------------------------------------------------- /test/test_stack_nesting.cpp: -------------------------------------------------------------------------------- 1 | /* test_stack_nesting - Acceleration of certain types of algorithm with nesting 2 | 3 | Copyright (C) 2016 European Centre for Medium Range Weather Forecasts 4 | 5 | Author: Robin Hogan 6 | 7 | Copying and distribution of this file, with or without modification, 8 | are permitted in any medium without royalty provided the copyright 9 | notice and this notice are preserved. This file is offered as-is, 10 | without any warranty. 11 | 12 | This test case illustrates how Jacobian calculations can be 13 | accelerated in certain situations when they are composed of 14 | "modules" that each involve a few numbers being calculated from 15 | many. In this situation we may avoid redundant computations by using 16 | a nested stack to calculate a local Jacobian for each module, and 17 | then adding it to the main stack. 18 | 19 | Thanks to Julian Kaupe for suggesting this pattern. 20 | 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #include "Timer.h" 27 | #include "adept.h" 28 | 29 | using adept::adouble; 30 | 31 | // Arbitrary function with one output 32 | static 33 | adouble 34 | many_in_one_out(const std::vector& x, const adouble& yinit) { 35 | adouble y = yinit; 36 | for (int i = 0; i < x.size(); i += 2) { 37 | adouble t = x[i]*x[i]; 38 | adouble e = exp(-x[i+1]); 39 | y = y*e + t*(1-e); 40 | } 41 | return y; 42 | } 43 | 44 | int 45 | main(int argc, char** argv) { 46 | 47 | static const int N = 1024; 48 | 49 | adept::Stack s(4*N*N); 50 | 51 | // Independent variables 52 | std::vector x(N), yinit(N); 53 | 54 | // Dependent variables 55 | std::vector y(N); 56 | 57 | // Initialize timer 58 | Timer timer; 59 | timer.print_on_exit(true); 60 | int unnested_fwd = timer.new_activity("Unnested forward pass"); 61 | int unnested_jac = timer.new_activity("Unnested Jacobian"); 62 | int nested_fwd = timer.new_activity( "Nested forward pass"); 63 | int nested_jac = timer.new_activity( "Nested Jacobian"); 64 | 65 | std::vector jac(N*N*2); 66 | 67 | std::cout << "*** UNNESTED ALGORITHM ***\n"; 68 | 69 | s.new_recording(); 70 | timer.start(unnested_fwd); 71 | for (int i = 0; i < N; ++i) { 72 | y[i] = many_in_one_out(x,yinit[i]); 73 | } 74 | 75 | timer.start(unnested_jac); 76 | s.clear_independents(); 77 | s.clear_dependents(); 78 | s.independent(x); 79 | s.independent(yinit); 80 | s.dependent(y); 81 | s.jacobian(&jac[0]); 82 | 83 | timer.stop(); 84 | 85 | std::cout << s; 86 | 87 | std::cout << "*** NESTED ALGORITHM ***\n"; 88 | 89 | double jac_nested[N+1]; 90 | 91 | s.new_recording(); 92 | timer.start(nested_fwd); 93 | for (int i = 0; i < N; ++i) { 94 | // Deactivate outer stack and start a nested one 95 | s.deactivate(); 96 | 97 | { 98 | adept::Stack s_nested(4*N); 99 | 100 | // We need local variables registered with the nested stack 101 | std::vector x_nested(N); 102 | adouble yinit_nested, y_nested; 103 | 104 | // Copy from the main variables - note that this puts references 105 | // to unregistered variables on the nested stack, but these are 106 | // deleted when we call new_recording 107 | for (int j = 0; j < N; ++j) { 108 | x_nested[j] = x[j]; 109 | } 110 | yinit_nested = y[i]; 111 | 112 | // Start with a fresh stack and only use local variables from 113 | // now on 114 | s_nested.new_recording(); 115 | y_nested = many_in_one_out(x_nested, yinit_nested); 116 | 117 | s_nested.clear_independents(); 118 | s_nested.clear_dependents(); 119 | s_nested.independent(x_nested); 120 | s_nested.independent(yinit_nested); 121 | s_nested.dependent(y_nested); 122 | s_nested.jacobian(jac_nested); 123 | 124 | // Nested stack goes out of scope here 125 | } 126 | // Reactivate outer stack 127 | s.activate(); 128 | 129 | // Copy nested Jacobian onto local stack - note that here we use 130 | // the original variables becase we know that x==x_nested and 131 | // yinit[i]==yinit_nested 132 | y[i].add_derivative_dependence(&x[0], jac_nested, N); 133 | y[i].append_derivative_dependence(yinit[i], jac_nested[N]); 134 | } 135 | 136 | timer.start(nested_jac); 137 | s.clear_independents(); 138 | s.clear_dependents(); 139 | s.independent(x); 140 | s.independent(yinit); 141 | s.dependent(y); 142 | s.jacobian(&jac[0]); 143 | 144 | timer.stop(); 145 | 146 | std::cout << s; 147 | 148 | return 0; 149 | 150 | 151 | } 152 | -------------------------------------------------------------------------------- /test/test_thread_safe.cpp: -------------------------------------------------------------------------------- 1 | /* test_thread_safe.cpp - Tests that Adept is thread-safe 2 | 3 | Copyright (C) 2012-2014 The University of Reading 4 | 5 | Copying and distribution of this file, with or without modification, 6 | are permitted in any medium without royalty provided the copyright 7 | notice and this notice are preserved. This file is offered as-is, 8 | without any warranty. 9 | 10 | This program tests the thread-safety of the Adept library: compile 11 | with and without ADEPT_STACK_THREAD_UNSAFE defined, and run with 12 | -serial and -parallel command-line arguments. It should crash only 13 | if ADEPT_STACK_THREAD_UNSAFE is defined AND -parallel is selected. 14 | */ 15 | 16 | #include 17 | #include 18 | 19 | #ifdef _OPENMP 20 | #include 21 | #endif 22 | 23 | // Test what happens if thread safety is disabled by uncommenting the 24 | // following 25 | //#define ADEPT_STACK_THREAD_UNSAFE 1 26 | #include "adept.h" 27 | 28 | using adept::adouble; 29 | 30 | // Number of points in spatial grid of simulation 31 | #define NX 128 32 | 33 | // "Toon" advection scheme applied to linear advection in a 1D 34 | // periodic domain - see Adept paper for details 35 | static 36 | void 37 | toon(int nt, double c, const adouble q_init[NX], adouble q[NX]) { 38 | adouble flux[NX-1]; // Fluxes between boxes 39 | for (int i=0; i 1.0e-5) { 109 | std::cout << "*** ERROR: Jacobian from forward and reverse computations disagree (RMSD = " 110 | << rmsd << ")\n"; 111 | error_occurred = true; 112 | } 113 | else { 114 | std::cout << "CORRECT BEHAVIOUR: Jacobians from forward and reverse computations agree within tolerance\n"; 115 | } 116 | 117 | if (i == 0) { 118 | // Print information about the data held in the stack 119 | std::cout << "Stack status for iteration 0:\n" 120 | << s; 121 | // Print memory information 122 | std::cout << "Memory usage: " << s.memory() << " bytes\n\n"; 123 | } 124 | 125 | std::cout << "\n"; 126 | } 127 | 128 | return error_occurred; 129 | } 130 | 131 | 132 | int 133 | main(int argc, char** argv) 134 | { 135 | using adept::adouble; 136 | 137 | bool error_occurred = false; 138 | 139 | const double pi = 4.0*atan(1.0); 140 | 141 | // Edit these variables to change properties of simulation 142 | const int nt = 2000; // Number of timesteps 143 | const double dt = 0.125; // Timestep (actually a Courant number) 144 | const int ncomputations = 16; 145 | 146 | // Initial values of field as a double array 147 | double q_init_save[NX]; 148 | 149 | bool is_parallel = true; 150 | 151 | if (argc > 1) { 152 | if (std::string("-serial") == argv[1]) { 153 | is_parallel = false; 154 | } 155 | else if (std::string("-parallel") == argv[1]) { 156 | is_parallel = true; 157 | } 158 | else { 159 | std::cout << "Usage: " << argv[0] << " [-serial|-parallel]\n"; 160 | return 1; 161 | } 162 | } 163 | 164 | 165 | std::cout << "Running " << argv[0] << "...\n"; 166 | 167 | #ifdef ADEPT_STACK_THREAD_UNSAFE 168 | std::cout << " Compiled to be THREAD UNSAFE\n"; 169 | #else 170 | std::cout << " Compiled to be THREAD SAFE\n"; 171 | #endif 172 | 173 | #ifdef _OPENMP 174 | std::cout << " " << omp_get_num_procs() << " processors available running maximum of " 175 | << omp_get_max_threads() << " threads\n"; 176 | if (is_parallel) { 177 | std::cout << " Performing " << ncomputations << " parallel computations,\n"; 178 | std::cout << " within which Jacobian (" << NX << "x" << NX << " matrix) calculations will be serial\n"; 179 | #ifdef ADEPT_STACK_THREAD_UNSAFE 180 | if (omp_get_max_threads() > 1) { 181 | std::cout << "*** You should expect this program to crash now!\n"; 182 | } 183 | #endif 184 | } 185 | else { 186 | std::cout << " Performing " << ncomputations << " serial computations,\n"; 187 | std::cout << " within which Jacobian (" << NX << "x" << NX << " matrix) calculations will be in parallel\n"; 188 | } 189 | #else 190 | std::cout << " Compiled with no OpenMP support\n"; 191 | #endif 192 | 193 | std::cout << "\n"; 194 | std::cout.flush(); 195 | 196 | 197 | // Initialize the field 198 | for (int i = 0; i < NX; i++) { 199 | q_init_save[i] = (0.5+0.5*sin((i*2.0*pi)/(NX-1.5)))+0.0001; 200 | } 201 | 202 | if (is_parallel) { 203 | #pragma omp parallel for 204 | for (int i = 0; i < ncomputations; i++) { 205 | if (compute(i, nt, dt, q_init_save)) { 206 | error_occurred = true; 207 | } 208 | } 209 | } 210 | else { 211 | for (int i = 0; i < ncomputations; i++) { 212 | if (compute(i, nt, dt, q_init_save)) { 213 | error_occurred = true; 214 | } 215 | } 216 | } 217 | 218 | if (error_occurred) { 219 | std::cout << "An error occurred\n"; 220 | } 221 | 222 | return error_occurred; 223 | 224 | } 225 | --------------------------------------------------------------------------------