This tool converts stan model file (left) into variable dependencies as graph structure, and visualize the graph (right).
Put your stan files in code/, and git clone this repo such that your working directory contains both code/ and Profile_Stan/.
mkdir outputs
mkdir outputs/probgraph
and run
python model_parser_wrapper.py
To visualize the graph, run
python to_graphviz.py ../outputs/probgraph/[the graph to visualize].probgraph
and paste the results to http://www.webgraphviz.com.
parse_model.py stores probability graph ending with .probgraph. It streams graph into a json file. The data structure is:
- {node: [([parents], dependency_type)]} where
- dependency_type:
- indexing,
- simple/complex computation,
- discrete/continuous distribution
- variables are dependent on the index variables
- real beta[3]; there are 3 betas here, create "3" as a "variable"; only keep the largest integer
- ignore the arithmetic operations within []
- examples: eps[2:nyear] = eps2[1:nyear - 1], or N_est[t + 1] = N_est[t] * lambda[t];
- a[b[i],c[i]], generate i->b, i->c, b->a, c->a (ignore i->a)
- verified 14 models out of 69 models in BPA
- does not work for one statement with {} in one line
- does not support /* or */ appearing after statements
- simply deal with functions{} (e.g. Ch.07/cjs_add.stan) by adding a connection between returned value and arguments
- the dependency belongs to complex
- (a more sophisticated way to solve this is to build a graph for each functions, and map variables accordingly whenever the function is called)
- works for 69 model files in BPA, verified 17 files
- variables assigned within if statement, are dependent on the variables in if conditions. Dependency type is basic.
- variables declared within for loops, are dependent on the loop indices; the dependency is indexing
- we add indexing dependency for one variable at a time. For example (['a', 'b'], 'indexing') should be converted to (['a'], 'indexing'), (['b'], 'indexing')
- does not work for for statement without {} followed by more than one statement, example: 28 for (n in 1:nmax) 29 if (n < nmin) 30 lp_parts[n] <- log(1.0 / nmax) + negative_infinity(); // Zero probability 31 else 32 lp_parts[n] <- log(1.0 / nmax) + binomial_log(k, n, theta);
- does not work for if/for statements, whoes { is in a new line
- when calling increment_log_prob(), construct a 'target' variable to hold the value
- does not work if for/if statement put condition and statement together..
Emma Wang Originally on Feb 24th, 2017, Updated on March 21th, 2017.