Module and function reference

Main module pyadi

The main module contains the most important function for users of PyADi: DiffFor(), which evaluates derivatives.

It also contains the runtime function decorators D() and Dc(), which are the main workhorse of PyADi. The module also contains the mechanism by which these decorators invoke the configured rule modules, which by default is just forwardad. When the rule modules at last ask the core to handle the function, source transformation is used to produce a differentiated function. The main module also contains the main AST visistor that performs the source code differentiation, while many tools related to that task are also in astvisitor.

class pyadi.pyadi.ASTVisitorFMAD[source]
__call__(tree)[source]

Process the tree. Calls dispatch, which will catch only FunctionDefs and enter ddispatch traversal when the function is designated as active. Calls methods self._XYZ for individual node XYZ handling, there is only _FunctionDef.

active_fields = []
active_methods = []
dadispatch(tree)[source]

traversal only for the LHS of assignments

ddispatch(tree)[source]

The main workhorse, the differentiation traversal Calls methods self._DXYZ for individual node XYZ handling

diffKeywords(keywords)[source]
diffStmtList(body)[source]
diffUnlessIsTupleDiff(t, src=None)[source]
getRoot(t)[source]
isLocal(t)[source]
isnodiffExpr(item)[source]
localvars = []
mkOpPartialC(op, r, dx, x, y)[source]
mkOpPartialL(op, r, dx, x, y)[source]
mkOpPartialL1(op, r, x, y)[source]
mkOpPartialR(op, r, dy, x, y)[source]
nodiffExpr = ['Raise', 'Assert']
nodiffFunctions = []
nonder_builtins = ['next']
nondercall_builtins = ['next']
tupleDiff = ['Call', 'List', 'ListComp', 'Dict', 'DictComp', 'DictComp', 'IfExp', 'GeneratorExp', 'Starred']
verbose = 0
pyadi.pyadi.D(function, **opts)

An alias for DiffFunction() so the generated code can be shorter.

pyadi.pyadi.Dc(tpl, **opts)

An alias for DiffFunctionObj() so the generated code can be shorter.

pyadi.pyadi.Diff(active='all', **opts)[source]
pyadi.pyadi.DiffFD(f, *args, active=[], seed=1, h=1e-08, f_kw={}, **opts)[source]

Evaluate derivatves using central finite differences.

The function f is called two times for each derivative direction provided by seed, to evaluate a central finite difference with step size h. The function f is called once more to compute the original result.

Parameters:
  • f (function) – Function to differentiate.

  • args (list) – Function arguments.

  • h (float) – Step size, default 1e-8

  • active (list or str) – Active arguments, like [0,1], [‘x’, ‘y’], or a comma-separated string like ‘x,y’. The empty list or string means all arguments. What actually happens is that a local function of only the active args, calling function, is generated by mkActArgFunction() and that is differentiated instead.

  • seed (1 or list) – Seed, derivative directions. When seed == 1, all derivative directions are computed. When seed is a list, then each entry must be a list or array of the same size as the total length of the active arguments. The function nvars() can compute that value.

  • f_kw (dict) – Further keyword arguments that will be passed to f as **f_kw.

  • opts (dict) – Options, not used.

Returns:

A tuple of the derivative and the function result. The derivative is a list with as many entries as there were seed directions.

Return type:

tuple

pyadi.pyadi.DiffFDNP(f, *args, active=[0], seed=1, h=1e-08, f_kw={}, **opts)[source]

An optimized version of DiffFD() with some restrictions:

  • there can be only one active argument, considering opts[‘active’].

  • the only active argument, the seeds, and the function result must all by numpy arrays.

Parameters:
  • f (function) – Function to differentiate.

  • args (list) – Function arguments.

  • h (float) – Step size.

  • active (list or str) – Active arguments, like [0,1], [‘x’, ‘y’], or a comma-separated string like ‘x,y’. What actually happens is that a local function of only the active args, calling function, is generated by mkActArgFunction() and that is differentiated instead.

  • seed (1 or list) – Seed, derivative directions. When seed == 1, all derivative directions are computed. When seed is a list, then each entry must be an array of the same size as the active argument.

  • f_kw (dict) – Further keyword arguments that will be passed to f as **f_kw.

  • opts (dict) – Options, of which this funciton uses:

Returns:

A tuple of the derivative and the function result. The derivative is a list with as many entries as there were seed directions.

Return type:

tuple

pyadi.pyadi.DiffFor(function, *args, seed=1, active=[], f_kw=None, timings=True, verbose=0, dump=0, dumpdir='dump', **opts)[source]

Differentiate function and compute first-order derivatives evaluated at *args and **f_kw, w.r.t. all floats in args, possibly restricted by àctive.

Differentiate function function(*args) with forward mode AD to produce adfun. This function is the main entry point to start the differentiation process. This function basically does the following:

  • Differentiate function with DiffFunction() alias D()

  • Create one set of derivative arguments dx = dzeros(args) using dzeros()

  • For each seeddir in seed, initialize dx with seeddir using fill() and call adfun with dx and args appropriately.

The result is a tuple of the list of the derivative results thus produced, and the function result.

Although PyADi supports almost the full set of Python language features including keyword arguments, lambda functions, etc. the function given here must adhere to some restrictions:

  • function must be a regular Python function, defined with

    def, not a lambda expression.

  • This function only processes the positional arguments args and considers all keyword arguments as options to the process, additional keyword arguments can be passed using f_kw.

  • function can have parameter default values,

  • function can be a local function returned by whatever other function. This setup processs will not be differentiated.

  • function can also have a decorator, which will be differentiated.

It may in some cases be required, and it is no problem, to create additional toplevel functions that can be given to this function, for example to wrap a lambda expression.

It should not be required to build extra toplevel functions to inject global variables into the scope, since function can be a local function already. It will have access to the parent scopes as usual, but the values in it are treated as global values with zero derivative.

However, when a function returning a function is called within function, then this entire process, including possible calls to the result later, will be differentiated.

Parameters:
  • function (function) – Function to differentiate. Must be a regular function, defined with def, can be a local function.

  • args (list) – Function arguments. function will be differentiated with respect to all arguments or to those listed by active.

  • active (list or str) – Active arguments, like [0,1], [‘x’, ‘y’], or a comma-separated string like ‘x,y’. The empty list or string means all arguments. What actually happens is that a local function of only the active args, calling function, is generated by mkActArgFunction() and that is differentiated instead.

  • seed (1 or list) – Seed, derivative directions. When seed == 1, all derivative directions are computed. When seed is a list, then each entry must be a list or array of the same size as the total length of the active arguments. The function nvars() can compute that value.

  • f_kw (dict) – Further keyword arguments that will be passed to function as **f_kw. This wraps function with mkKwFunction().

  • opts (dict) – Further options opts including also verbose, dump and dumpdir are stored in a global variable transformOpts. These global options are added to the options of doDiffFunction() by each call to D() in the subsequent process.

Returns:

A tuple of the derivative and the function result. The derivative is a list with as many entries as there were seed directions.

Return type:

tuple

pyadi.pyadi.DiffFunction(function, **opts)[source]

Runtime decorator to handle function calls.

This function merely caches the calls to doDiffFunction(), which does the actual work when no entry is found for function.

Use clear() to clear this cache, which should be necessary only when the processing is redefined at runtime using initRules().

pyadi.pyadi.DiffFunctionObj(tpl, **opts)[source]

Runtime decorator to handle calls to local variables.

Calls to local variables like obj.meth are differentiated to an expression invoking this function as Dc((d_obj.meth, obj,meth)), that is, with a tuple of the “differentiated” function and the original function. Differentiated is in quotes because different cases can happen.

Let the tuple tpl be expanded to dfunc, func.

This function will usually call DiffFunction (aka. D) with func after handling the following cases:

  • When dfunc != func:

    1. A method is being called, dfunc and func are bound methods. Extract the two self pointers from both and substitute func with the actual class function T.meth, where T is the type. T is not necessarily the type of obj but may also be a parent class when an inherited method is being called using super().

      At runtime, inject the two self pointers to the front of the argument list.

    2. When func is not a function, then an object is being called, dfunc is the derivative object. Substitute func by T.__call__, where T is the type of obj.

      At runtime, inject the two self pointers (that is, dfunc and the original func) to the front of the argument list.

    3. Otherwise, a local function inner is being called, which will have been differentiated in source code already, the call to this decorator then being Dc(d_inner, inner). Hence, dfunc is already the differentiated function of func, it can be called directly. In this case D() is not called in the following.

  • When dfunc == func: A function alias has been called, that is, a global function was assigned to a local variable like myf = math.sin. The differentiated variable d_myf then has dzeros(math.sin), which is also math.sin. Do nothing.

. Finally call DiffFunction(func) and return that result, unless

the runtime arguments need patching, then return a local function doing that.

pyadi.pyadi.Dpy(func, active=[], **kw)[source]
class pyadi.pyadi.FillHelper(seed)[source]

A simple iterator used to source floats one by one from either a list or a numpy array, used by fill().

__init__(seed)[source]
__iter__()[source]
__next__()[source]

Return a single float from the data.

__repr__()[source]

Print the fill status like “FillHelper(i/n)”.

get(N)[source]

Batch-return N values to speed up filling arrays.

class pyadi.pyadi.GenIter(genobj)[source]
__init__(genobj)[source]
__iter__()[source]
__next__()[source]
next()[source]
class pyadi.pyadi.GenIter2(genobj)[source]
__init__(genobj)[source]
__iter__()[source]
__next__()[source]
exception pyadi.pyadi.NoRule[source]
pyadi.pyadi.addrulemodule(module, **kw)[source]
pyadi.pyadi.callHandle(name, *args, **kw)[source]
pyadi.pyadi.clear(search=None)[source]
pyadi.pyadi.clearrulemodules(name=None)[source]
pyadi.pyadi.createFullGradients(args)[source]
pyadi.pyadi.dargs(args, seed=1)[source]
pyadi.pyadi.diff2py(fname)[source]
pyadi.pyadi.diff2pys(intree, visitor, **kw)[source]
pyadi.pyadi.diff2pys2s(source, fname)[source]
pyadi.pyadi.differentiate(intree, activef=None, active=None, modules=None, filter=False, prefix=None, **kw)[source]
pyadi.pyadi.difffunction(func, active=[], **kw)[source]
pyadi.pyadi.doDiffFunction(function, **opts)[source]

Produce differentiated functions.

This function is called to produce a derivative function for function, that is, a function that is called with tuples (dx, x) for each original argument x in the original code, and that returns a tuple (dr, r) where r is the function result and dr is the derivative.

This function will call processRules(), which calls the installed rule modules.

The default rule module forwardad will for example catch calls to print(), which is a builtin function, and call mkRule() with D_builtins_print() to produce a suitable result, namely, it will print the differentiated arguments in an additional line to the original print, which in the case of a formatted f-string would be the same f-string, but with differentiated expressions..

When no rule module catchs the call and returns a suitable function, finally the source differentiation doSourceDiff() is invoked. It will produce a suitable result by retrieving the AST of function using getast() and differentiating that.

A few special cases need to by handled as follows:

  • When function is a type, then a constructor is being called.

    • set _C = function

    • When _C.__init__ is not builtin, set function = _C.__init__, that is the constructor class method.

  • When function has a closure and the last closure entry fdec is a function this might be a call to a decorated function, that is, the result of deco(fdec), which is a local function that captured fdec. So when fdec has a decorator list (getting the ast of fdec), this might be the right thing. TODO: We should check if this is really the right function. However, substitute function by fdec. This will thus in the following get the AST of fdec, which is something like:

    @mydeco2(1.23)
    def gdeco2(l):
        return gl_sum(l)
    

    This gets differentiated to an expression decorating the regular D(fdec) with the differentiated decorator expression:

    @(lambda f: D(mydeco2)((0, 1.23))[0](f, gdeco2)[0])
    def d_gdeco2(d_l, l):
        return D(gl_sum)((d_l, l))
    

    Which when loaded produces the differentiated inner function that the differentiated decorator, that D(mydeco2) returns, creates when called with d_gdeco2 alias f, and gdeco2. Thus, whatever happens in these decorators and the inner functions that they produce is getting differentiated regulary.

    The differentiated decorator expression is one of the few cases where we have to throw away the second part of the tuples that differentiated functions produce, because we only need the differentiated result, and even twice in this case.

Then the differentiated function adfun is produced by calling processRules(). This function returns however a local function def theADFun(*args, **kw): that does the following:

  • first flatten the argument list args of N tuples to a list of 2*N, alternating derivative and regular arguments. This is because the source differentiation differentiates def f(x, y): to def d_f(d_x, x, d_y, y):. Hence, the builtin rules will also be called with the flattened list of arguments. This step also forces the evaluation of potentially lazy zip and other iterators that the arguments may be.

  • when _C is not None, a type, that is, a constructor has been called. Initialize two objects d_o and o with initType(). Prepend (d_o, o) to the list of arguments. This requires that _C.__init__ accepts being called with no arguments. Both objects will then be reinitialized again with the provided arguments to the constructor when the differentiated __init__ method adres is invoked in the next step. TODO: check if we can somehow produce unitialized objects, that is, do what Python does before it calls __init__?

  • Another corner case is when function is not a function but a bound method. This can only happen with global objects being called, like the method get of os.environ. Then the self pointer o is extracted and a copy d_o to be dzeros()-ed must be created somehow on the fly. Prepend (d_o, o) to the list of arguments.

  • Finally call adres = adfun(*args, **kw)

  • when adres is None, which often happens with methods, return (None, None), unless _C is not None, then a constructor has been called, return (d_o, o).

  • when adres is an object of the builtin type generator, function was a generator function and adfun is too, with differentiated yield statements that produce tuples. Create two coupled iterators d_it = GenIter (adres) and it = GenIter2 (d_it) that in tandem iterate adres, one returning r[0] and the other r[1] of the tuples r produced, and return (d_it, it).

  • otherwise, return adres, which is a tuple.

pyadi.pyadi.doSourceDiff(function, opts)[source]
pyadi.pyadi.dumpFile(fname)[source]
pyadi.pyadi.execompile(source, fglobals={}, flocals={}, imports=['math', 'sys', 'os', {'pyadi': 'D'}], vars=['x'], fname='', **kw)[source]
pyadi.pyadi.fid(func, active)[source]
pyadi.pyadi.fill(arg, seed)[source]

Fill arg with values from seed.

Fill arguments arg with values from seed. Lists, tuples, dicts and objects are deep-copied and each generic value, as per astunparse.astnode.isgeneric() is filled with one value from seed using FillHelper. numpy arrays are batch-filled in-place using FillHelper.get(), so dzeros() should be used before if it is desired that arrays are cloned and the original arrays not modified

Parameters:
  • arg (list of objects) – Function arguments.

  • seed (list of floats or a numpy array) – Values to fill into arg during deep-copy.

Returns:

A deep copy of arg filled with seed.

Return type:

arg

pyadi.pyadi.getHandle(alias)[source]

Return handle to a rule module.

Return the second item of the result of a rule module’s decorator function, or None. This second item is meant to be a function that can manipulate or read the local scope of the decorator, for an example see the tracing rule module trace.

The result returned becomes invalid whenever initRules() is called again.

Parameters:

alias (str) – The module name or alias used with initRules().

Returns:

The second item that the rule module’s decorator returned, usally a second inner function.

Return type:

object, usually function or None

pyadi.pyadi.getRuleModules(index)[source]
pyadi.pyadi.getsig(f)[source]
pyadi.pyadi.initRules(rules='ad=pyadi.forwardad', **opts)[source]

Initialize the rule processing mechanism for processRules() that performs the mapping of functions to differentiated functions.

The decorator() of a rule module may return two function handles instead of one. In this case the second one can be retrieved using getHandle(), possibly to manipulate the scope of the returned differentiated functions at runtime, as demonstrated by the decorator() of the rule module trace.

When the same module shall be used several times in the chain, an alias can be defined, for example:

pyadi.initRules(
  rules='pyadi.trace,pyadi.forwardad,tr2=pyadi.trace',
  tracecalls=True, verbose=True, verboseargs=True)

Then, getHandle('tr2') retrieves the handle to the second instance of the decorator that the trace module installed, and getHandle('pyadi.trace') gets that of the first, while getHandle('pyadi.forwardad') is None because it does not provide a handler function.

Parameters:
  • rules (str) – Comma-separated list of python modules to use as rule modules. Entries can use ‘alias=module’ to define a name alias.

  • opts (dict) – Passed to decorator() of all the rule modules upon initialization.

pyadi.pyadi.initType(function, *args, **kw)[source]

Create pair of objects d_o, and o by calling the constructor function twice, and then zero all floats in d_o with dzeros().

pyadi.pyadi.isdiff(tree)[source]
pyadi.pyadi.mkClosDict(function)[source]

Return dictionary of closure variables of function.

pyadi.pyadi.mkConstr(function)[source]
pyadi.pyadi.nodiff(tree)[source]
pyadi.pyadi.nvars(args)[source]

Compute recursively the total number of values in the list args.

pyadi.pyadi.parinds(f, x)[source]
pyadi.pyadi.processRules(function, opts, *args, **kw)[source]
pyadi.pyadi.setprefix(diff, tmp, common='')[source]
pyadi.pyadi.varspec(x)[source]
pyadi.pyadi.varv(args)[source]

Runtime rule modules

The rule modules are initialized by initRules(), which takes a list of python module names and imports them. PyADi provides some builtin rule modules which are documented in this section.

Any python module may be used as a rule module, as long as it contains a function decorator().

The rules modules come in two categories: Modules that do the actual thing, of which there are forwardad and dummyad, and modules which do nothing, inserting themselves into the chain without changing anything to the arguments and results. They may choose to intercept all the function calls, but then again they do not change the result and call the given function. The No-Op modules are trace and timing,

Module forwardad

The default rule module for PyADi.

It resolves functions for which it has a handler registered to a corresponding function compatible with our AD process, that is, function that takes the flattened list of 2*N arguments and the differentiated keywords dictionary and returns a tuple of the derivative and the function result.

When some function is not handled by this module, then source transformation will be invoked. This in turn fails with the exception NoSource when the source can not be obtained. Then a handler must be added to this module in order to make the process work.

Defining handlers, how they are resolved and their semantics is entirely local to this module.

Handlers for any Python function function can be set, retrieved, and deleted with setrule(), getrule(), and delrule(), respectively.

Note the mode parameter of these functions, which can be ‘D’, ‘Dkw’ or ‘E’. This controls how the generic calling pattern is mapped to the rules:

“D”) mkRule() is used to build the AD function, and the

rule must have the signature rule(r, *args, **kw), or compatible. The wrapper calls the original function first as r = function(*args[1::2], **kw) and then calls the rule passing the result r as the first parameter. The rule must return just the derivative d_r, the wrapper returns (d_r, r).

“Dkw”) similar to “D”, mkRule2() is used to build the AD

function, which additionally unpacks the keywords into the derivative keywords and the original keywords with unjnd() into d_kw, kw. The rule must have the signature rule(r, d_kw, *args, **kw). The wrapper in addition to the function result passes the derivative keywords as the second parameter d_kw while kw will only receive the original keyword params.

“E”) No wrapper is produced, the rule will be called directly, which

accordingy must return a tuple.

Note that the rule modes have the precedence ‘D’, ‘Dkw’, and ‘E’. So if you wanted to replace an existing rule with mode ‘D’ with a new rule with mode ‘E’, make sure to delrule() the handler with mode ‘D’ first, or else your new rule would be shadowed by the still extant rule with mode ‘D’.

Mode “D” is useful in that vast majority of cases. For example, the handler for sin() is:

def D_math_sin(r, dx, x):
    return dx * cos(x)

The handler for print() calls print again, this time with all the differentiated arguments:

def D_builtins_print(r, *args):
    print('D ', *args[0::2])
    return 0

The function result that is provided by the wrapper can be put to good use in several functions, for example the exponentials like exp() and sqrt(), but also numpy.linalg.inv():

def D_math_exp(r, dx, x):
    return r * dx

def D_math_sqrt(r, dx, x):
    return 0.5 * dx / r

def D_numpy_linalg_inv(r, dx, x):
    return r @ -dx @ r

Common trivial cases are type conversions, which should be applied to the derivative arguments too:

def D_builtins_list(r, dx, x):
    return list(dx)

def D_builtins_tuple(r, dx, x):
    return tuple(dx)

def D_builtins_float(r, dx, x):
    return float(dx)

def D_builtins_complex(r, dx, x, dy, y):
    return complex(dx, dy)

Another generic case is when data is shuffled around in whatever way, then apply the same shuffling to the derivatives:

def D_builtins_ndarray_reshape(r, *args, **kw):
    # args[0]: the derivative array
    # args[1]: the original array
    # args[3::2]: the remainder of the original arguments, i.e. the sizes
    return args[0].reshape(*args[3::2])

def D_numpy_hstack(r, dx, x):
    return np.hstack(dx)

def D_numpy_diag(r, dx, x):
    return np.diag(dx)

def D_numpy_real(r, dx, x):
    return np.real(dx)

def D_numpy_imag(r, dx, x):
    return np.imag(dx)

Another trivial case, but which can be a pitfall, is where values are created that do not depend on the inputs, in which case it is paramount that the derivative values are always zero:

def D_builtins_int(r, dx, x):
    return 0

def D_builtins_len(r, dx, x):
    return 0

def D_builtins_Random_random(r):
    return 0

When a sequence is created, we must provide a sequence of zeros:

def D_builtins_range(r, *args):
    return [0]*len(r)

def D_builtins_enumerate(r, dx, x):
    return zip([0]*len(x), dx)

And likewise for arrays:

def D_numpy_zeros(r, *args):
    return np.zeros(r.shape, dtype=r.dtype)

D_numpy_eye = D_numpy_ones = D_numpy_random_rand = D_numpy_zeros

The intention of the mode “Dkw” is to save the call to unjnd() when it is not needed. The flipside is that rules must announce when they do want the split keyword arguments, but so far these are quite a small number, for example, dict() itself:

def Dkw_builtins_dict(r, d_kw, *args, **kw):
    return dict(**d_kw)

Another example is numpy.sum(), which on past occasions has it made pretty clear that it does not want to be bothered with a keyword d_axis or any other keyword starting with d_ for that matter, so we give it what it needs but not what is does not want:

def Dkw_numpy_sum(r, d_kw, dx, x, **kw):
    return np.sum(dx, **kw)
pyadi.forwardad.D_builtins_RandomState_rand(r, *args)
pyadi.forwardad.D_builtins_Random_random(r)[source]
pyadi.forwardad.D_builtins_abs(r, dx, x)[source]
pyadi.forwardad.D_builtins_complex(r, dx, x, dy, y)[source]
pyadi.forwardad.D_builtins_dict_get(r, dx, x, dk, k, dd, d)[source]
pyadi.forwardad.D_builtins_dict_items(r, dx, x)[source]
pyadi.forwardad.D_builtins_dict_keys(r, dx, x)[source]
pyadi.forwardad.D_builtins_dict_values(r, dx, x)[source]
pyadi.forwardad.D_builtins_enumerate(r, dx, x)[source]
pyadi.forwardad.D_builtins_float(r, dx, x)[source]
pyadi.forwardad.D_builtins_getattr(r, *args)[source]
pyadi.forwardad.D_builtins_int(r, dx, x)[source]
pyadi.forwardad.D_builtins_len(r, dx, x)[source]
pyadi.forwardad.D_builtins_list(r, dx, x)[source]
pyadi.forwardad.D_builtins_max(r, dx, x, dy, y)[source]
pyadi.forwardad.D_builtins_min(r, dx, x, dy, y)[source]
pyadi.forwardad.D_builtins_print(r, *args)[source]
pyadi.forwardad.D_builtins_range(r, *args)[source]
pyadi.forwardad.D_builtins_sum(r, dx, x)[source]
pyadi.forwardad.D_builtins_tuple(r, dx, x)[source]
pyadi.forwardad.D_builtins_zip(r, *args)[source]
pyadi.forwardad.D_math_acos(r, dx, x)[source]
pyadi.forwardad.D_math_asin(r, dx, x)[source]
pyadi.forwardad.D_math_atan(r, dx, x)[source]
pyadi.forwardad.D_math_cos(r, dx, x)[source]
pyadi.forwardad.D_math_exp(r, dx, x)[source]
pyadi.forwardad.D_math_log(r, dx, x)[source]
pyadi.forwardad.D_math_sin(r, dx, x)[source]
pyadi.forwardad.D_math_sqrt(r, dx, x)[source]
pyadi.forwardad.D_math_tan(r, dx, x)[source]
pyadi.forwardad.D_numpy_array(r, dx, x)[source]
pyadi.forwardad.D_numpy_cos(r, dx, x)[source]
pyadi.forwardad.D_numpy_diag(r, dx, x)[source]
pyadi.forwardad.D_numpy_exp(r, dx, x)[source]
pyadi.forwardad.D_numpy_eye(r, *args)
pyadi.forwardad.D_numpy_hstack(r, dx, x)[source]
pyadi.forwardad.D_numpy_imag(r, dx, x)[source]
pyadi.forwardad.D_numpy_linalg_inv(r, dx, x)[source]
pyadi.forwardad.D_numpy_linalg_norm(r, dx, x, d_ord=0, ord=None)[source]
pyadi.forwardad.D_numpy_log(r, dx, x)[source]
pyadi.forwardad.D_numpy_matmul(r, dx, x, dy, y)[source]
pyadi.forwardad.D_numpy_ones(r, *args)
pyadi.forwardad.D_numpy_random_rand(r, *args)
pyadi.forwardad.D_numpy_real(r, dx, x)[source]
pyadi.forwardad.D_numpy_savetxt(r, *args)[source]
pyadi.forwardad.D_numpy_sin(r, dx, x)[source]
pyadi.forwardad.D_numpy_sqrt(r, dx, x)[source]
pyadi.forwardad.D_numpy_tan(r, dx, x)[source]
pyadi.forwardad.D_numpy_zeros(r, *args)[source]
pyadi.forwardad.D_pyadi_runtime_binop_add(r, dx, x, dy, y)[source]
pyadi.forwardad.D_pyadi_runtime_binop_c_mult(r, dx, x, dy, y)[source]
pyadi.forwardad.D_pyadi_runtime_binop_d_mult(r, dx, x, dy, y)[source]
pyadi.forwardad.D_pyadi_runtime_binop_div(r, dx, x, dy, y)[source]
pyadi.forwardad.D_pyadi_runtime_binop_floordiv(r, dx, x, dy, y)[source]
pyadi.forwardad.D_pyadi_runtime_binop_matmult(r, dx, x, dy, y)[source]
pyadi.forwardad.D_pyadi_runtime_binop_mod(r, dx, x, dy, y)[source]
pyadi.forwardad.D_pyadi_runtime_binop_mult(r, dx, x, dy, y)[source]
pyadi.forwardad.D_pyadi_runtime_binop_pow(r, dx, x, dy, y)[source]
pyadi.forwardad.D_pyadi_runtime_binop_sub(r, dx, x, dy, y)[source]
pyadi.forwardad.D_pyadi_runtime_unaryop_uadd(r, dx, x)[source]
pyadi.forwardad.D_pyadi_runtime_unaryop_usub(r, dx, x)[source]
pyadi.forwardad.Dkw_builtins_dict(r, d_kw, *args, **kw)[source]
pyadi.forwardad.Dkw_numpy_sum(r, d_kw, dx, x, **kw)[source]
pyadi.forwardad.E_builtins_ndarray_copy(*args, **kw)[source]
pyadi.forwardad.E_builtins_ndarray_reshape(*args, **kw)[source]
pyadi.forwardad.E_builtins_object___init__(*args, **kw)[source]
pyadi.forwardad.E_builtins_super(*args)[source]
pyadi.forwardad.E_builtins_super___init__(*args, **kw)[source]
pyadi.forwardad.decorator(**opts)[source]
pyadi.forwardad.delrule(func, mode='D')[source]

Delete the runtime handler for func with mode. See setrule() for details.

Returns:

The currently installed handler.

Return type:

function

pyadi.forwardad.getrule(func, mode='D')[source]

Return the runtime handler adfunc for func with mode. See setrule() for details.

Returns:

The currently installed handler.

Return type:

function

pyadi.forwardad.getrules()[source]
pyadi.forwardad.initType(function, *args, **kw)[source]
pyadi.forwardad.mkRule(f, rule)[source]
pyadi.forwardad.mkRule2(f, rule)[source]
pyadi.forwardad.mkRule3(f, rule)[source]
pyadi.forwardad.setrule(func, adfunc, mode='D')[source]

Install a runtime handler adfunc for func with mode.

This is a function that gets called with the current original and derivative parameters in the form adfunc(*args, **kw), where args is a list of 2*N arguments, derivative and original arguments interleaved.

Depending on mode the adfunc will be handled differently, in the first two cases a wrapper function is produced:

  • When mode='D', the handler will be called as adfunc(r, *args, **kw), where r is the function result, and has to return just the derivative d_r.

  • When mode='Dkw', the handler will be called as adfunc(r, d_kw, *args, **kw), where in addition d_kw, kw is the result of unjnd().

  • When mode='E', then the handler will be called directly as adfunc(*args, **kw), and has to return a tuple.

Module dummyad

This rule module is an attempt to provide a set of rules that makes the differentiated code run, with no regard for the derivative result.

pyadi.dummyad.decorator(**opts)[source]
pyadi.dummyad.mkCall(f)[source]
pyadi.dummyad.mkCall2(f)[source]

Module trace

This rule module adds a call to any function call that monitors for certain tasks, like printing the function name and possibly arguments, and for other tasks such as even interrupting the program.

exception pyadi.trace.Stop[source]
pyadi.trace.decorator(tracecalls=False, verbose=False, verboseargs=False, **opts)[source]

Module timing

This rule module adds a call to any function call that monitors certain function calls. When a matching function is caught its call and its descendants for a configurable height are timed with Timer.

pyadi.timing.decorator(catch=[], height=1, **opts)[source]

This function produces a decorator inner() that always install another layer of function calls around the result (a function) it receives from inner layers.

In addtion to the parameters, there are two closure variables, stack and found. The function timing() that the decorator produces maintains the current stack height in stack. When the function name matches an entry in catch, height is set to stack.

When found + height > stack, then the call to the function produced by the preceding layer is sent through a timing with Timer.

AST utility modules

Module astvisitor

class pyadi.astvisitor.ASTCanonicalizer[source]
__call__(tree)[source]

Call self as a function.

__init__()[source]
dispatch(tree)[source]
edispatch(tree, val=None)[source]
processStmts(stmts)[source]
class pyadi.astvisitor.ASTLocalAction[source]
After(t)[source]
Before(t)[source]
Begin(t)[source]
End(t)[source]
__call__(tree)[source]

Call self as a function.

__init__()[source]
dispatch(tree)[source]
class pyadi.astvisitor.ASTPatchSuper[source]
Before(tree)[source]
Begin(tree)[source]
class pyadi.astvisitor.ASTReolvetmpvars[source]
Before(tree)[source]
Begin(tree)[source]
class pyadi.astvisitor.ASTReplaceOps(**kw)[source]
After(tree)[source]
Before(tree)[source]
Begin(tree)[source]
__init__(**kw)[source]
class pyadi.astvisitor.ASTReplaceOpsInvert(**kw)[source]
After(tree)[source]
Before(tree)[source]
Begin(tree)[source]
__init__(**kw)[source]
class pyadi.astvisitor.ASTVisitor[source]
__call__(tree)[source]

Call self as a function.

__init__()[source]
dispatch(tree)[source]
class pyadi.astvisitor.ASTVisitorDict[source]
After(tree)[source]
Before(tree)[source]
Begin(tree)[source]
End(tree)[source]
class pyadi.astvisitor.ASTVisitorFilterFunctions(names)[source]
After(tree)[source]
Before(tree)[source]
Begin(tree)[source]
End(tree)[source]
__init__(names)[source]
class pyadi.astvisitor.ASTVisitorID[source]
dispatch(tree)[source]
class pyadi.astvisitor.ASTVisitorImports[source]
Before(tree)[source]
Begin(tree)[source]
End(tree)[source]
class pyadi.astvisitor.ASTVisitorLastFunction[source]
Before(tree)[source]
Begin(tree)[source]
End(tree)[source]
class pyadi.astvisitor.ASTVisitorLastFunctionSig[source]
Before(tree)[source]
Begin(tree)[source]
End(tree)[source]
class pyadi.astvisitor.ASTVisitorLocals[source]
Before(tree)[source]
Begin(tree)[source]
End(tree)[source]
classmethod getRoot(t)[source]
classmethod getVars(t)[source]
exception pyadi.astvisitor.NoSource[source]
exception pyadi.astvisitor.NotFound[source]
class pyadi.astvisitor.TmpVar(kind='t')[source]
__init__(kind='t')[source]
pyadi.astvisitor.canonicalize(tree, **kw)[source]
pyadi.astvisitor.fddname(func)[source]
pyadi.astvisitor.fdname(func)[source]
pyadi.astvisitor.filterFunctions(intree, names)[source]
pyadi.astvisitor.filterLastFunction(intree)[source]
pyadi.astvisitor.fname(func)[source]
pyadi.astvisitor.fqname(func)[source]
pyadi.astvisitor.getast(func, **kw)[source]
pyadi.astvisitor.getmoddict(mod, **opts)[source]

Return dictionary with ASTs of module classes and functions. Resolve from imports with resolveImports().

pyadi.astvisitor.getmodule(func)[source]
pyadi.astvisitor.infoSignature(intree)[source]
pyadi.astvisitor.isbuiltin(func)[source]
pyadi.astvisitor.iscall(cn)[source]
pyadi.astvisitor.iscanon(cn)[source]
pyadi.astvisitor.isop(cn)[source]
pyadi.astvisitor.mkOprevName(dict)[source]
pyadi.astvisitor.mkTmp(kind='t')[source]
pyadi.astvisitor.mkTmpName(kind='t')[source]
pyadi.astvisitor.mkUnOprevName(dict)[source]
pyadi.astvisitor.normalize(tree, **kw)[source]
pyadi.astvisitor.op_revname(op)
pyadi.astvisitor.op_revname_unary(op)
pyadi.astvisitor.op_unrevname(op)
pyadi.astvisitor.py(func, info=False)[source]
pyadi.astvisitor.py2py(fname)[source]
pyadi.astvisitor.py2pys(jdict, visitor)[source]
pyadi.astvisitor.py2pys_check(jdict, visitor)[source]
pyadi.astvisitor.resolveImports(mod, modfile, moddict, imports, modules, **opts)[source]
pyadi.astvisitor.resolvetmpvars(tree, **kw)[source]
pyadi.astvisitor.rid(func)[source]
pyadi.astvisitor.roundtrip2JID(fname)[source]
pyadi.astvisitor.roundtrip2JIDs(source, fname)[source]
pyadi.astvisitor.run()[source]
pyadi.astvisitor.setprefix(t)[source]
pyadi.astvisitor.testdir()[source]
pyadi.astvisitor.unnormalize(tree, **kw)[source]

Module nodes

class pyadi.nodes.Assign(l, r)[source]
__init__(l, r)[source]
class pyadi.nodes.Attribute(v, attr)[source]
__init__(v, attr)[source]
class pyadi.nodes.AugAssign(op, target=None, value=None)[source]
__init__(op, target=None, value=None)[source]
class pyadi.nodes.BinOp(op, left=None, right=None)[source]
__init__(op, left=None, right=None)[source]
class pyadi.nodes.Call(func, args=[], kw=[])[source]
__init__(func, args=[], kw=[])[source]
class pyadi.nodes.FunctionDef(name, args, l)[source]
__init__(name, args, l)[source]
class pyadi.nodes.Keyword(arg, value)[source]
__init__(arg, value)[source]
class pyadi.nodes.Lambda(args, l)[source]
__init__(args, l)[source]
class pyadi.nodes.List(elts)[source]
__init__(elts)[source]
class pyadi.nodes.Module(body)[source]
__init__(body)[source]
class pyadi.nodes.Return(val)[source]
__init__(val)[source]
class pyadi.nodes.Slice(l, u=None, s=None)[source]
__init__(l, u=None, s=None)[source]
class pyadi.nodes.Starred(value)[source]
__init__(value)[source]
class pyadi.nodes.Subscript(v, ind)[source]
__init__(v, ind)[source]
class pyadi.nodes.Tuple(elts)[source]
__init__(elts)[source]
class pyadi.nodes.UnaryOp(op, value=None)[source]
__init__(op, value=None)[source]
class pyadi.nodes.arg(arg)[source]
__init__(arg)[source]
class pyadi.nodes.arguments(args)[source]
__init__(args)[source]
class pyadi.nodes.keyword(arg, value)[source]
__init__(arg, value)[source]

Other utility modules

Module runtime

class pyadi.runtime.DWith(*args, **kw)[source]
__init__(*args, **kw)[source]
pyadi.runtime.augassign_add(x, y)[source]
pyadi.runtime.augassign_div(x, y)[source]
pyadi.runtime.augassign_mod(x, y)[source]
pyadi.runtime.augassign_mult(x, y)[source]
pyadi.runtime.augassign_sub(x, y)[source]
pyadi.runtime.augassign_truediv(x, y)[source]
pyadi.runtime.binop_add(x, y)[source]
pyadi.runtime.binop_c_mult(x, y)[source]
pyadi.runtime.binop_d_mult(x, y)[source]
pyadi.runtime.binop_div(x, y)[source]
pyadi.runtime.binop_floordiv(x, y)[source]
pyadi.runtime.binop_matmult(x, y)[source]
pyadi.runtime.binop_mod(x, y)[source]
pyadi.runtime.binop_mult(x, y)[source]
pyadi.runtime.binop_pow(x, y)[source]
pyadi.runtime.binop_sub(x, y)[source]
pyadi.runtime.dzeros(args, lev=0)[source]
pyadi.runtime.joind(ddl, dl)[source]
class pyadi.runtime.lzip(*args)[source]
__init__(*args)[source]
pyadi.runtime.unaryop_uadd(x)[source]
pyadi.runtime.unaryop_usub(x)[source]
pyadi.runtime.unjnd(d)[source]
pyadi.runtime.unzd(d)[source]

Module dtargets

pyadi.dtargets.mkActArgFunction(f, args, inds)[source]

Create an inner function of only the arguments given by inds, filling in the remaining ones statically in each call.

Return the inner function and the remaining arguments.

This function is differentiated automatically by DiffFor() and DiffFD() when active arguments were specified.

Parameters:

function (function) – A function of args, for which an inner function is created of only [args[i] for i in inds]

Returns:

A tuple of the inner function and the remaining arguments.

Return type:

function, list

pyadi.dtargets.mkKwFunction(f, f_kw)[source]

Create an inner function that adds **f_kw to the call to f.

This function is differentiated automatically by DiffFor() when the option f_kw is used.

Parameters:
  • function (function) – A function of args, for which an inner function is created of only [args[i] for i in inds]

  • kw (dict) – Dictionary of keyword parameters to be added to the call.

Returns:

A tuple of the inner function and the remaining arguments.

Return type:

function

Module timer

class pyadi.timer.Timer(func, kind, verbose=0, **kw)[source]
__init__(func, kind, verbose=0, **kw)[source]
__str__()[source]

Return str(self).

fmt(t)[source]
getev(func, kind)[source]
millis()[source]
pref = ['m', 'µ', 'n', 'p']
register()[source]

Module cmdline

pyadi.cmdline.pycanon()[source]
pyadi.cmdline.pydiff()[source]
pyadi.cmdline.run(parsefun, prog, description='What the program does')[source]