Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

Sometimes one may want to execute a notebook via the command line (for example to run it remotely).

As far as I know it's not possible to run notebooks directly, but .m files can be executed, typically with code like

math -noprompt -run "<<file.m"

So one needs to convert .nb to .m. One way to do this is to save the .nb as a Mathematica package and then to convert all cells to initialization cells.

However, this conversion handles some of the typography (e.g. subscripts) improperly.

Is there a less error-prone way to do this?


Edit:

Examples for things that don't convert:

Subscript part notation (Ctrl+_+[[part]])

The corresponding FullForm is Part[list,n], the converted expression is Subscript[list, [[n]]].

share|improve this question
1  
Care to share some of the problematic cases? –  Yves Klett Aug 12 '13 at 16:29
    
Could you paste the FullForm of the expression that does not convert and that of the (improper) result? –  Yves Klett Aug 12 '13 at 16:58
2  
I understand the charm in using fancy subscripts to write your programs, but it's good practice to avoid heavy typesetting in code, especially in code that is to be run from the command line. Almost always, the workarounds are localized and probably not worth it. Well, that's just how I see it... fancy typesetting is best reserved for textual data. YMMV –  rm -rf Aug 12 '13 at 17:21
    
Which Mathematica version? For 9.0.1 I see no problems really. But of course, you should not write longer programs in the FrontEnd anyway. E.g. you have multiple undo in Eclipse with the Workbench plugin. –  Rolf Mertig Aug 12 '13 at 18:14
    
@Rolf Mertig: I'm on 8.0. –  Emerson Aug 13 '13 at 11:28

2 Answers 2

I often had to run slow code on a cluster in a command line. Of course, you always want to write your code and debug in the FrontEnd if at all possible so it is important to support both methods of opening the file.

My solution was to have my code as a .m file and then dump the output to a binary mathematica file to read later (in the frontend if I was running on a commandline).

The simplest way to do this is to do all of the calculations you need and then dump the global variables. For example,

DumpGlobals[save$name_, sub$directory_: "", postfix_ : ""] := Module[{notebookDirectoryExists,outputDirectory},
    notebookDirectoryExists = Check[NotebookDirectory[],0];
    outputDirectory = If[notebookDirectoryExists == 0, Directory[], notebookDirectoryExists];
    If[Not[DirectoryQ[outputDirectory <> sub$directory]],CreateDirectory[outputDirectory <> sub$directory],0];
    SetDirectory[outputDirectory <> sub$directory];
		CaptionPrint["Saving Output to " <> outputDirectory <> sub$directory <>"/"<> save$name <> postfix <>".mx"];
		DumpSave[save$name <> postfix <>".mx", "Global`"];
    SetDirectory[outputDirectory];
];  

The creation of the output sub$directory is not strictly necessary but made my life easier for automically copying output from the cluster. The trick here is that getting the directory you are running in for the .m file depends on whether you opened it in the FrontEnd or if you are running it on a commandline (i.e. NotebookDirectory[] doesn't always work).

With this output, you can open it up in either an interactive notebook or another .m file by using the << myfile.mx

As for losing the formatting of subscripted variables when using the .m file, they are more trouble than they are worth. If all you want to do is display code with subscripts and copy them to latex) then check out: Displaying index as subscript on output: e.g. C[i] -> C_i with Notation[...] or Interpretation[..]?

share|improve this answer

As far as I know it's not possible to run notebooks directly

It is possible, and there is no need to convert .nb to .m if you want to execute it without FrontEnd.

Notebooks are nothing but Mathematica expressions, so it is not difficult to sketch a script that would evaluate all Input cells in that expression, add new cells with the newly calculated output, and rewrite the target .nb file.

The script suggested here erases all existing Output cells in the notebook. Make backups, or modify the script in case you keep separate Output cells in your notebook.

The script probably preserves the basic notebook structure, but I'm not aware of complete .nb specifications. Notebook backups are recommended.

Suppose, your target notebook file is test.nb in $UserBaseDirectory.

The content of script file test.nb.mmaNotebookEvaluator:

Begin["EvalContext`"]

nbFileName = FileNameJoin[{$UserBaseDirectory, "test.nb"}];

outputCellPattern = Cell[_, "Output", ___];

cellEval[Cell[b_BoxData, "Input", rest___]] :=
 Cell[
  CellGroupData[{
    Cell[b, "Input", rest],
    Cell[BoxData@ToBoxes@(ToExpression @@ b), "Output"]},
   Open]]

cellEval[x : (_CellGroupData | _Cell | _Notebook)] := cellEval /@ x

cellEval[l_List] := cellEval /@ Cases[l, Except@outputCellPattern, {1}]

cellEval[smthElse_] := smthElse

evaluateNotebook = Export[#, cellEval@Get@#] &;

End[]

EvalContext`evaluateNotebook@EvalContext`nbFileName

Then, math -script test.nb.mmaNotebookEvaluator updates your notebook file via command line. It is very basic, evaluating only Input cells, erasing all Output cells, and placing Null as output for expressions with “;” at the end.

cellEval maps itself inside CellGroupData, Cell, Notebook -headed expressions. In case Cell contains BoxData, and is of Input type, cellEval transforms it ToExpression, and the original Cell is replaced with “Input & Output” group of Cells.

I'm not sure if creating a separate context in the script is necessary.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.