Function Repository Resource:

TraceCausalGraph

Source Notebook

Build a causal graph from an expression evaluation trace

Contributed by: Nik Murzin

ResourceFunction["TraceCausalGraph"][expr]

evaluate an expression and return a causal graph of its trace.

ResourceFunction["TraceCausalGraph"][expr,n]

trace only up-to n steps of evaluation.

ResourceFunction["TraceCausalGraph"][expr,n,patt]

prune trace by a specifying a pattern of expressions to include.

ResourceFunction["TraceCausalGraph"][expr,,prop]

returns the specified property prop.

Details and Options

Tracing functions with Flat, Orderless, OneIdentity attributes and other things that lead to non-standard evaluation (like Sequence) is not properly supported.
Supported properties for prop include:
"CausalGraph" (default)causal graph of the trace
"Path"path as an interspersed list of HoldComplete expressions and positions
"PathGraph"path as a PathGraph
"PathEventsGraph"intersperse a path graph with corresponding event vertices
"PathCausalGraph"add causal dependency edges to the "PathEventsGraph"
TraceCausalGraph takes the following options:
"IncludeInitialEvent"Falsewhether to include an additional event that produces original expression
"ShowIndices"Falseshow event indices
"ShowEventOrder"Falseshow evaluation order with a path between events
"ShowPositions"Falseshow event position with negative position indicating internal evaluations
"ShowExpressions"Trueshow complete or partial expressions
"PruneIdentities"Trueprune events that evaluate expression to itself
"PruneSideEvents"Falseprune expressions that do not correspond to any part of original expression
"PruneTerminatedEvaluation"Trueprune expression with TerminatedEvaluation
ResourceFunction["TraceCausalGraph"] also takes Graph options.

Examples

Basic Examples (5) 

Make a causal graph from a standard evaluation of an expression:

In[1]:=
ResourceFunction["TraceCausalGraph"][(1 + (2 + 3)) + (4*5)]
Out[1]=

Make a path consisting of intermediate expressions together with subexpression positions being evaluated:

In[2]:=
ResourceFunction["TraceCausalGraph"][(1 + (2 + 3)) + (4*5), "Path"]
Out[2]=

Make a path graph of expressions in a trace:

In[3]:=
ResourceFunction[
 "TraceCausalGraph"][(1 + (2 + 3)) + (4*5), "PathGraph"]
Out[3]=

Make a path with interspersed events between expressions:

In[4]:=
ResourceFunction[
 "TraceCausalGraph"][(1 + (2 + 3)) + (4*5), "PathEventsGraph"]
Out[4]=

Add dependency edges between events:

In[5]:=
ResourceFunction[
 "TraceCausalGraph"][(1 + (2 + 3)) + (4*5), "PathCausalGraph"]
Out[5]=

Scope (2) 

Trace a more complicated expression:

In[6]:=
ClearAll[fib]
fib[n_] := fib[n - 1] + fib[n - 2]
fib[0 | 1] = 1;

ResourceFunction["TraceCausalGraph"][fib[3]]
Out[7]=

Tracing internal functions would result in side-events (indicated by a dashed boundary):

In[8]:=
ResourceFunction["TraceCausalGraph"][FoldList[Plus, 0, {1, 2, 3}]]
Out[8]=
In[9]:=
ResourceFunction["TraceCausalGraph"][Table[i^2 + i, {i, 2}], GraphLayout -> {"LayeredDigraphEmbedding", "Orientation" -> Left}]
Out[9]=

Options (9) 

IncludeInitialEvent (1) 

Include an additional event that all events causally depend on:

In[10]:=
ResourceFunction["TraceCausalGraph"][2*3 + 4*5 + 6*7, "IncludeInitialEvent" -> True]
Out[10]=

ShowIndices (1) 

Show indices of events in evaluation order:

In[11]:=
ResourceFunction["TraceCausalGraph"][1 + (2 + (3 + 4)), "ShowIndices" -> True]
Out[11]=

ShowEventOrder (1) 

Indicate an actual order of events during evaluation:

In[12]:=
ResourceFunction["TraceCausalGraph"][(1 + 2) + (3 + 4)^5, "ShowEventOrder" -> True]
Out[12]=

ShowPositions (2) 

Show positions of subexpressions being evaluated:

In[13]:=
ResourceFunction["TraceCausalGraph"][1 + (2 + (3 + 4)), "ShowPositions" -> True]
Out[13]=

With side-events having decreasing negative part numbers:

In[14]:=
ResourceFunction["TraceCausalGraph"][Nest[f, 1, 3], "ShowPositions" -> True]
Out[14]=

ShowExpressions (1) 

Instead of the whole expression show only subexpressions under evaluation:

In[15]:=
ResourceFunction["TraceCausalGraph"][1 + (2 + (3 + 4))]
Out[15]=
In[16]:=
ResourceFunction["TraceCausalGraph"][1 + (2 + (3 + 4)), "ShowExpressions" -> False]
Out[16]=

PruneIdentities (1) 

Trivial identity events are pruned by default:

In[17]:=
ResourceFunction["TraceCausalGraph"][1 + (2 + 3)]
Out[17]=
In[18]:=
ResourceFunction["TraceCausalGraph"][1 + (2 + 3), "PruneIdentities" -> False]
Out[18]=

PruneSideEvents (1) 

Prune side-events from a trace PathGraph and corresponding events:

In[19]:=
f[n_ /; n > 1] := f[n - 1]
In[20]:=
ResourceFunction["TraceCausalGraph"][f[3], "PruneSideEvents" -> False]
Out[20]=
In[21]:=
ResourceFunction["TraceCausalGraph"][f[3], "PathGraph", "PruneSideEvents" -> True]
Out[21]=
In[22]:=
ResourceFunction["TraceCausalGraph"][f[3], "PruneSideEvents" -> True]
Out[22]=

PruneTerminatedEvaluation (1) 

Terminating after non-terminal amount of steps results in TerminatedEvaluation inside of the last event, which is pruned by default:

In[23]:=
GraphicsRow[
 Table[ResourceFunction["TraceCausalGraph"][(1 + 2)^3, n, "PruneTerminatedEvaluation" -> False, PlotLabel -> Row[{n, If[n == 1, "step", "steps"]}, " "], GraphLayout -> "SpiralEmbedding"], {n, 4, 12, 2}], Frame -> All]
Out[23]=

Possible Issues (1) 

Non-standard evaluation, like flattening of Flat subexpressions results in incorrect reconstruction of intermediate expressions:

In[24]:=
ClearAll[f]
SetAttributes[f, Flat]
f[x, a] := f[a, x]
ResourceFunction["TraceCausalGraph"][f[x, a, a], "PathGraph"]
Out[25]=

Neat Examples (3) 

Trace a Fibonacci function with memoization:

In[26]:=
ClearAll[f]
f[0] = f[1] = 1; f[n_] := f[n] = f[n - 1] + f[n - 2]
In[27]:=
ResourceFunction["TraceCausalGraph"][f[8], "CausalGraphStructure", GraphLayout -> "LayeredDigraphEmbedding"]
Out[27]=

Make a causal graph of a nested recursive function:

In[28]:=
Clear[f]
f[n_] := f[n - f[n - 3]] + f[n - 2]
f[n_ /; n < 1] = 1;
In[29]:=
ResourceFunction["TraceCausalGraph"][f[5], "CausalGraphStructure"]
Out[29]=
In[30]:=
ResourceFunction["TraceCausalGraph"][f[5], "CausalGraphStructure", GraphLayout -> "LayeredDigraphEmbedding", AspectRatio -> 2]
Out[30]=

Divide-and-conquer factorial:

In[31]:=
f[l_List] := Times @@ f /@ TakeDrop[l, Quotient[Length[l], 2]]
f[{x_}] := x
In[32]:=
ResourceFunction["TraceCausalGraph"][
 f[Range[10]], "CausalGraphStructure"]
Out[32]=

Requirements

Wolfram Language 13.0 (December 2021) or above

Version History

  • 1.0.0 – 04 October 2023

Related Resources

License Information