Message Boards Message Boards

0
|
997 Views
|
5 Replies
|
6 Total Likes
View groups...
Share
Share this post:

How can I find all the functions in a notebook that are called

I have written a notebook. I have several functions that I wrote for testing purposes and debugging. However, I would now like to place all the functions that are called by my main function into a package. Many functions are not called and I wish not to include them in the package.
My idea is to copy the notebook (at least the functions in it) into a package file and remove from the package file all the unused functions).
My question is how can I get a list of all the uncalled functions so that I know which functions to remove from the package?
Of course, given the power of Mathematica, I suspect that there must be a better way and that I should be able to write a program that could:
1) Read a notebook.
2) Figure out the function call tree of a particular function (presumably the main function), and
3) Create a package with just the functions called by the main function by copying their definitions in the package file.
Does anyone have any suggestions/solutions? Also, is there a Mathematica function that can generate the function call tree of a given function?

POSTED BY: Henrick Jeanty
5 Replies

Maybe this will help:

Select[VertexList[depgraph], 
 Context @@ MakeExpression[#, StandardForm] === "Global`" &]

Your definitions are probably in the Global context. This should filter out calls to built-in functions which are in the System or some other context. If your definitions are in some other context, you have to modify "Global`". If you don't know what the context is, execute Context[main], where main is your function in question. It will tell you the context of main.

I should say that I wouldn't want to go down the road of parsing your notebook. I'm sure it can be done. I could probably figure it out. Given enough hours. If the above doesn't filter out enough, try quitting the kernel and then executing the definitions in your notebook. Then the above should make the job feasible, unless you've loaded up your init.m with loads of other definitions.

POSTED BY: Michael Rogers

Maybe ResourceFunction["SymbolDependencyGraph"] can help. Not sure how it handles recursion. If you have recursive calls, you can check.

POSTED BY: Michael Rogers

Do you know about AutoGeneratePackage? Either code below will save the cells marked InitializationCell (see menu Cell > Cell Properties > Initialization Cell, shortcut ctrl-8):

SetOptions[EvaluationNotebook[], AutoGeneratedPackage -> Automatic]
SetOptions[EvaluationNotebook[], AutoGeneratedPackage -> Manual]

See the documentation for the difference between Automatic and Manual. You could also look at the code for GeneralUtilities`PrintDefinitions (via GeneralUtilities`PrintDefinitions[GeneralUtilities`PrintDefinitions]), which prints code to a notebook. It may take some work to figure it out, since it does a lot of pretty-print formatting with hyperlinks. It's much more complicated than the basic task you want to do.

Here's a usage string generator similar to what you want:

ClearAll[fff];
fff[x_, y_ : 2] := x + y;
fff[x_, y_, z_] := x  z + y;

fff::usage = StringJoin@ Riffle[ToString /@ HoldForm @@@ DownValues[fff][[All, 1]], "\n"];
? fff

A more complicated example:

ClearAll[fn];
fn[e_, {x_, a_, b_}][x0_?NumericQ] := Block[{x = x0}, e];
fn[e_, {x_, a_, b_}]["Domain"] := {x, a, b};
fn[e_, {x_, a_, b_}]["Variable"] := x;
fn[e_, x_Symbol] := fn[e, {x, 0, 1}]; (* default domain *)
fn /: Plot[f_fn] := 
  With[{x = f["Variable"], domain = f["Domain"]}, Plot[f[x], domain]];

fn::usage = StringJoin@ Riffle[
   ToString /@ HoldForm @@@ Join[UpValues[fn], SubValues[fn], DownValues[fn]][[All, 1]], 
    "\n"];

One could also just write a utility function to use on functions under development:

usage[symb_] := HoldForm @@@ 
    Join[UpValues[symb], SubValues[symb], DownValues[symb]][[All, 1]] // 
   Column;
POSTED BY: Michael Rogers

Thank you Michael. I tried your suggestion and used it on a function I wrote. I obtained a fairly large graph with quite a few system functions like TpyeSystemSummaryPackagePrivate`deemph along with functions from my notebook. Is there a way I can get a graph of just the functions in my notebook? I guess I could select from the VertexList only those vertices whose name starts with a lowercase (since I name my functions with a name that starts with a lowercase), but I would like something more robust and that would only provide the names of functions defined in the notebook.

Regards, Henrick

POSTED BY: Henrick Jeanty

Hello Michael, Thank you very much for the information.This solves this issue for me. Given that I can obtain the function tree of a particular function, I wonder if there is a tool that would be able to then automatically write the usage header in the package and then copy the actual function code into the package. For instance, I have function called getFinancialData[...] I would like the usage section of the package to be getFinancialData::usage = "getFinancialData[symbol,{startDate,endDate,period:'Day'}]."; And then have the definition for getFinancial package copied from the notebook to the package file. This would allow someone to write code, test it, improve functions, etc,,, Then, when satisfied that you have a properly running main function, put all the finally used functions in a package while leaving behind all the early attempts or those functions that fell by the wayside.

POSTED BY: Henrick Jeanty
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract