Python Guide & Performance Benchmark - XAD Automatic Differentiation (original) (raw)
The following example for first-order adjoint mode illustrates how to use it:
[](#%5F%5Fcodelineno-0-1)import xad.adj_1st as xadj [](#%5F%5Fcodelineno-0-2) [](#%5F%5Fcodelineno-0-3) [](#%5F%5Fcodelineno-0-4)# set independent variables [](#%5F%5Fcodelineno-0-5)x0_ad = xadj.Real(1.0) [](#%5F%5Fcodelineno-0-6)x1_ad = xadj.Real(1.5) [](#%5F%5Fcodelineno-0-7)x2_ad = xadj.Real(1.3) [](#%5F%5Fcodelineno-0-8)x3_ad = xadj.Real(1.2) [](#%5F%5Fcodelineno-0-9) [](#%5F%5Fcodelineno-0-10)with xadj.Tape() as tape: [](#%5F%5Fcodelineno-0-11) # and register them [](#%5F%5Fcodelineno-0-12) tape.registerInput(x0_ad) [](#%5F%5Fcodelineno-0-13) tape.registerInput(x1_ad) [](#%5F%5Fcodelineno-0-14) tape.registerInput(x2_ad) [](#%5F%5Fcodelineno-0-15) tape.registerInput(x3_ad) [](#%5F%5Fcodelineno-0-16) [](#%5F%5Fcodelineno-0-17) # start recording derivatives [](#%5F%5Fcodelineno-0-18) tape.newRecording() [](#%5F%5Fcodelineno-0-19) [](#%5F%5Fcodelineno-0-20) # calculate the output [](#%5F%5Fcodelineno-0-21) y = x0_ad + x1_ad - x2_ad * x3_ad [](#%5F%5Fcodelineno-0-22) [](#%5F%5Fcodelineno-0-23) # register and seed adjoint of output [](#%5F%5Fcodelineno-0-24) tape.registerOutput(y) [](#%5F%5Fcodelineno-0-25) y.derivative = 1.0 [](#%5F%5Fcodelineno-0-26) [](#%5F%5Fcodelineno-0-27) # compute all other adjoints [](#%5F%5Fcodelineno-0-28) tape.computeAdjoints() [](#%5F%5Fcodelineno-0-29) [](#%5F%5Fcodelineno-0-30) # output results [](#%5F%5Fcodelineno-0-31) print(f"y = {y}") [](#%5F%5Fcodelineno-0-32) print(f"first order derivatives:\n") [](#%5F%5Fcodelineno-0-33) print(f"dy/dx0 = {x0_ad.derivative}") [](#%5F%5Fcodelineno-0-34) print(f"dy/dx1 = {x1_ad.derivative}") [](#%5F%5Fcodelineno-0-35) print(f"dy/dx2 = {x2_ad.derivative}") [](#%5F%5Fcodelineno-0-36) print(f"dy/dx3 = {x3_ad.derivative}")
The Python bindings follow largely the same syntax and workflow as in C++.
Modules and Naming
| Module | Description | Contents |
|---|---|---|
| xad | The main module, which contain global functions and subpackages | value, derivative |
| xad.exceptions | Contains all exceptions, with the same names as described in Exceptions | e.g. NoTapeException |
| xad.math | Mirrors Python's math module, with functions for XAD's active types. | e.g. sin, exp |
| xad.fwd_1st | Active type for first-order forward mode | Real |
| xad.adj_1st | Active type for first-order adjoint mode as well as the corresponding tape type | Real, Tape |
Notes
- First order forward mode (module
xad.fwd_1st) and first order adjoint mode are supported (modulexad.adj_1st) - The active type is called
Realin all modes - In adjoint mode, a newly constructed
Tapeobject is not automatically activated on construction. It can be activated usingtape.activate()later, but we recommend using awithblock as illustrated in the example above. - The math functions in
xad.mathhave been designed as a drop-in replacement for the standard Pythonmathmodule. They not only support calls with XAD's active type, but also with regularfloatvariables. - Checkpointing and external function features are not yet supported in Python.
- The
x.getDerivative()andx.setDerivative()methods of active types are also available as the Python propertyx.derivativewith both set and get functionality. - The
x.getValue()method of active types is also available as the read-only propertyx.value - Use
y.setDerivative(1.0)or the property settery.derivative = 1.0to seed and access derivatives. - Complex numbers are not yet supported in the Python bindings.