Tutorial - Creating SQs from Vanilla Python Functions
The first step in our application is to query our magnetometer to check if a car is near the sensor.
Let’s say the road is on a long highway where it is unexpected that the speed will change dramatically over 5 meters. We will model the inductance of our magnetometer with a negative cosine wave shifted vertically to avoid negative values. Our function for getting the magnetometer is shown below:
def sample_magnetometer(A, f, phi): from math import cos, pi return A - (A * cos(get_time() * 2 * f / pi + phi)))
Note that the
sample_magnetometer has imports within the function
body. These are necessary as SQs are not guaranteed to be on the same ensemble
as its calling SQ, so each SQ requires its own environment and modules to be
We won’t go into depth on
get_time(), but we’ll assume
be responsible for generating increasing times so
will produce different values over subsequent function calls.
As stated before,
sample_magnetometer has been provided by other
developers for general use. The function itself is purely written in Python
without any direct mention of TTPython constructs. The simplest way to
include this Python function into TTPython is using the
sample_magnetometer, as shown below.
@SQify def sample_magnetometer(A, f, phi): ...
@SQify takes a Python function and inserts it as a SQ into our dataflow
graph. The SQ defines the basic unit of computation in TTPython.
The graph execution of our program is transparent to he programmer; they
do not need to worry about converting data to tokens to communicate between SQ.
When the SQ has the tokens it needs to run, it will provide the values
in those tokens as arguments to the supplied function.
A common error is to overuse
@SQify over each separate function in an already
defined Python program. This is unnecessary as
@SQify treats the underlying
wrapped function as a black box. The contained function should not have any
mention of TTPython constructs. For example,
@SQify def sample_magnetometer(A, f, phi): from math import cos, pi return A - (A * cos(get_time() * 2 * f / pi + phi))) # correct def get_time(): ...
is correct, while
@SQify def sample_magnetometer(A, f, phi): from math import cos, pi return A - (A * cos(get_time() * 2 * f / pi + phi))) @SQify # incorrect, SQified functions should not call other SQified functions def get_time(): ...
incorrectly mixes the level of abstraction an SQ provides in TTPython.
@SQify limits the expressiveness of Python functions it decorates.
*args is ont allowed in function definitions as our graph requires a statically
known amount of inputs arguments.
**kwargs are allowed in function calls
if they are also defined within the function definition.
We can now write a basic “Hello World” program to call
once! We have informed TTPython how to include our sensing function as a SQ
into our graph. Now, we need to define the graph structure for our program.
To do so, we use another function decorator:
@SQify def sample_magnetometer(A, f, phi): from math import cos, pi return A - (A * cos(get_time() * 2 * f / pi + phi))) def get_time(): ... @GRAPHify def main(trigger): A = 1 f = 0.25 phi = 0 return sample_magnetometer(A, f, phi)
The function decorator takes the following function as the main program to run
in TTPython. The Python semantics in
@GRAPHify are actually quite different
from the regular sense. We’ll discuss the nuances and restrictiosn of
@GRAPHify later, but for now you can imagine that it behaves similarly as
another Python function would. One immediate difference is that because our
graphs require an input token to be called, there cannot be any parameterless
function definitions. Futhermore, any function called within
needs to have been decorated by
We need to show a few examples * basic function being SQified * importing a file/module with an SQify’d function in it * keyword argument (must match identically, and should not be a variable (esp. not an arc)) * TT-keyword arguments for parameterizing TTPython primitives. Example with TTExecuteOnFullToken; READ_TTCLOCK is a good example in Instructions.py