Frequently Asked Questions

How do I apply a transformation to a specific node or set of nodes?

Use the apply_to class method of the transformation. Each transformation class declares a fixed set of pattern variables (e.g., MapFusion exposes first_map_exit, array, and second_map_entry); pass the matched nodes as keyword arguments:

from dace.transformation.dataflow import MapFusion
MapFusion.apply_to(sdfg, first_map_exit=exit1, array=array_node,
                   second_map_entry=entry2)

For pattern-based application across the whole SDFG, use apply_transformations() and apply_transformations_repeated(). For whole-program optimizations, run a pass instead.

When should I use a symbol and when should I use a scalar?

See the discussion in Symbolic types vs. scalars for the general guidelines.

How do I perform dynamic memory allocation?

Array shapes in DaCe are always associated with symbolic expressions. When the size is known only at runtime, declare the array with a symbolic shape and assign the actual size to that symbol on a state’s inter-state edge before the array is used:

sdfg = dace.SDFG('dyn')
N = dace.symbol('N')
sdfg.add_array('A', (N,), dace.float32, transient=True)

init = sdfg.add_state('init')
body = sdfg.add_state('body')
sdfg.add_edge(init, body, dace.InterstateEdge(assignments={'N': 'compute_size()'}))

When the size depends on data within the SDFG, place the allocation inside a nested SDFG so that its symbol can be assigned from a scalar of the parent.