Supported subset of Python¶
The supported subset of Python covers functions,
inner functions, and lambda
functions, which can have parameters, parameters with
default values, a positional wildcard or a keyword wildcard parameter
(cf. function definition
) and
which can be called with any combination of positional
arguments, keyword arguments, and starred expressions
as Python allows.
The compound statements
for
,
while
,
if
,
try
, and
with
are supported, as of
course are also
function definitions
.
Import statements
are
somewhat easier to handle as they are not generally processed, except
the from module import name
statements. These are are currently
processed once when a module is first loaded by pyadi
,
unconditionally, meaning using from module import name
within
another statement (like if
or try
) may or not work, because
pyadi
makes no attempt to find out what actually happened
when the module was loaded by Python and whether or not the import was
effective. Plain import
statements need not to be processed
because pyadi
finds the module from the function that is
being differentiated.
The data types Dictionary displays, tuple()
, and dict()
are
supported as literals well as they are in the form of list
comprehensions
and
dict comprehensions
,
also known as generator expressions.
Object oriented programming with classes is supported, including inheritance, method calling, bound methods, and the super() function. Object methods including the constructor are differentiated. Objects can also define a hidden __call__ method, which is also differentiated when the object is called.
Iterators including user-defined iterators are supported but they (i.e. the hidden methods __iter__ and __next__) are not differentiated. However, a “derivative” iterator object will automatically be created for each iterator object that the code uses, and its constructor and other methods being called regularly will be differentiated, so as long as the iterations just shuffe data around, the derivative should also be correct.
Generator functions and the yield statment are also supported. Here, the generator function and the yielded expressions are differentiated entirely.
Formatted strings are differentiated, and the rule for
print()
prints the differentiated arguments, so the
differentiated programs will print lines with the values of
differentiated expressions, in addition to the original line.
Several of the most important functions are already supported, be it
because they are available in source of because they have been added
to the list of builtin rules in forwardad
. The latter must
happen for any function that cannot or shall not be differentiated in
source. It is a work in progress to cover more and more builtin
functions. When a function is not covered by a rule and the source
code cannot be obtained, DiffFor()
will raise
NoSource
. Users can use setrule()
to dynamically
add rules at runtime to avoid this scenario. This can also be used to
install custom derivatives for any function.
Limitations¶
There are several known limitations:
Multiple decorators are untested
Coroutines,
async
andawait
are not supportedIterator functions
__next__
and__iter__
are not differentiated so they work correcty when data is copied, but not when float computations are performed inside. Generators usingyield
should be used in this case, for exampleLambda functions cannot by passed to
DiffFor()
directly, they must be wrapped in a regular functionList multiplication with
*
is not supported, a list comprehension with generator expression should be used instead. List addition with+
is supported.There is no activity analysis
There is no vector mode, or derivative class as in ADiMat
There is no reverse mode