Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Watch function calls and variable values?

Tags:

python

trace

How can I watch which functions get called and all variable values in a Python script?

I have just discovered the uncertainties package for Python, and I want to actually figure out how it works so I can explain it to my boss.

Basically, I can't see how the uncertainties are actually calculated. This is probably because I don't know how Python works yet.

For starters, how can I see how c is calculated?

import uncertainties
from uncertainties import ufloat

a = ufloat(1,3)
b = ufloat(2,4)

c = a + b  # How does this work??

print c
like image 425
masher Avatar asked Aug 16 '13 00:08

masher


2 Answers

Ignoring the specific case of the uncertainties module, Python provides the sys.settrace function, which can be used to implement things like the Smiliey application tracer

For example, from the docs:

In one terminal window, run the monitor command:

$ smiley monitor

In a second terminal window, use smiley to run an application. This example uses test.py from the test_app directory in the smiley source tree.

$ smiley run ./test.py
args: ['./test.py']
input = 10
Leaving c() [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Leaving b()
Leaving a()

The monitor session will show the execution path and local variables for the app.

Starting new run: ./test.py
test.py:   1: import test_funcs
test.py:   1: import test_funcs
test_funcs.py:   1: import sys
test_funcs.py:   1: import sys
test_funcs.py:   3: def gen(m):
test_funcs.py:   8: def c(input):
like image 175
dbr Avatar answered Oct 02 '22 15:10

dbr


If you want to see how things are calculated, pdb is indeed one solution.

However, with a debugger like pdb, it is hard to get a high-level overview of what is going on. This is why reading the code is also useful. For example, if you want to know what a+b does, you can check if type(a).__add__ exists, because if it does, it handles the addition. This is the case with the uncertainties package.

That said, __add__ is indeed implemented in uncertainties through a general mechanism instead of being specifically coded for, so I can tell you the idea behind its implementation, since this is what you seem to be ultimately looking for.

In your example, a and b are Variable objects:

>>> from uncertainties import ufloat                                            
>>> a = ufloat(1, 3)
>>> b = ufloat(2, 4)
>>> type(a)
<class 'uncertainties.Variable'>

Then c = a + b is actually a linear function of a and b, represented by its derivatives with respect to a and b:

>>> c = a + b
>>> type(c)
<class 'uncertainties.AffineScalarFunc'>
>>> c.derivatives
{1.0+/-3.0: 1.0, 2.0+/-4.0: 1.0}

If you know the derivatives of a function with respect to its variables, you can easily get an approximation of its standard deviation from the standard deviations of its variables.

Thus, the main ideas behind the implementation of the uncertainties package is that values are either:

  • random variables like x = 3.14±0.0.1 and y = 0±0.01 (Variable objects), described by their standard deviation,
  • or linear approximations of functions (AffineScalarFunc objects: "affine" because they are linear, "scalar" because their values are real, and "func" because they are functions).

To take a more complicated example, z = 2*x+sin(y) is approximated in (x, y) = (3.14, 0) as 2*x + y. In the implementation, since the approximation is linear, only the derivatives with respect to the variables are stored:

>>> x = ufloat(3.14, 0.01)
>>> y = ufloat(0, 0.01)
>>> from uncertainties.umath import sin
>>> z = 2*x + sin(y)
>>> type(z)
<class 'uncertainties.AffineScalarFunc'>
>>> z.derivatives
{3.14+/-0.01: 2.0, 0.0+/-0.01: 1.0}

The main work done by the uncertainties package is thus to calculate the derivatives of any function involving variables. This is done by the efficient method of automatic differentiation. Concretely, when you do something like a+b, Python automatically calls the Variable.__add__() method, which creates a new linear function by calculating the derivatives of a+b with respect to its variables (the derivatives are both one, because the derivative of a with respect to a is one, and the same for b). More generally, one adds functions, not pure variables: the derivatives of f(a,b) + g(a,b) with respect to a and b is calculated with the chain rule. This is how automatic differentiation works, and this is what is implemented in the uncertainties package. The key function here is uncertainties.wrap(). It is the largest and most complicated function of the whole package, but the code is largely commented, and details on the method are available.

Derivatives then give you the standard deviation of the final function as a function of the standard deviations of the variables (the code of AffineScalarFunc.std_dev() is very simple: the more difficult task is to automatically calculate derivatives).

like image 31
Eric O Lebigot Avatar answered Oct 02 '22 15:10

Eric O Lebigot