如何通过命令行评估笔记本电脑?

19

如何在命令行中(即在以命令行模式运行内核时)评估Mathematica笔记本?假设我们正在远程机器上工作。我知道可以将笔记本转换为m文件,并对其进行评估,但我想知道是否可以直接使用笔记本进行评估。


目前我所拥有的是:

首先,在远程Linux机器上需要启动一个无头X服务器,这样前端就可以在那里运行(并打开笔记本)。如果您是在本地机器上工作,则跳过此步骤。

Xvfb :1 &
export DISPLAY=:1

接着我启动了Mathematica的内核 (math),并进行了以下操作。

使用 UsingFrontEnd 很有必要,因为打开笔记本需要前端。test.nb 只包含一个输入单元格,其中包含 a=1

In[1]:= nb=UsingFrontEnd@NotebookOpen["test.nb"]

Out[1]= -NotebookObject-

在尝试评估笔记本后,显然我会得到一个对话框,我需要使用Return[]返回。 我不确定为什么输入行再次从1开始计数(前端启动了一个新内核?)请注意,a没有获得值。

In[2]:= UsingFrontEnd@NotebookEvaluate[nb]

 In[1]:= a

 Out[1]= a

 In[2]:= Return[]

Out[2]= a

在对话框返回后,a仍然没有值。

In[3]:= a

Out[3]= a

看起来我们在以类似的方式工作,同样懒惰! - acl
1
+1 我也很想知道!我想在我们的HPC上远程评估我的笔记本。 - Eli Lansey
2个回答

11

这是对你问题的部分回答。以下代码打开一个笔记本,为其分配一个“测试”内核,在该内核中评估笔记本,等待评估完成并保存已评估的笔记本。但它不会导致在本地命令行内核中定义a

这将等待笔记本中的内核评估完成:

NotebookPauseForEvaluation[nb_] := Module[{},
 While[ NotebookEvaluatingQ[nb], Pause[.25] ] ]

这将检查笔记本中是否仍有任何单元格正在评估:

NotebookEvaluatingQ[nb_]:=Module[{},
 SelectionMove[nb,All,Notebook];
 Or@@Map["Evaluating"/.#&,Developer`CellInformation[nb]]
]

当您试图重新定义内核(例如"Test")时,这只是一条诊断消息:

AddTestEvaluator::exists = "Evaluator `1` is already defined, but has a definition that is `2` and not the expected `3`.";

这是添加一个像"Test"的评估器到前端的代码:

AddTestEvaluator[evaluator_String] := Module[
 {evaluatornames, testevaluator},
 evaluatornames = EvaluatorNames /. Options[$FrontEnd, EvaluatorNames];
 testevaluator = evaluator -> {"AutoStartOnLaunch" -> False};
 Which[
  MemberQ[evaluatornames, evaluator -> {"AutoStartOnLaunch" -> False}],
  Null,
  MemberQ[evaluatornames, evaluator -> _],
  Message[AddTestEvaluator::exists,
  evaluator,
  evaluator /. (EvaluatorNames /. Options[$FrontEnd, EvaluatorNames]),
  {"AutoStartOnLaunch" -> False}
 ],
 True,
 AppendTo[evaluatornames, testevaluator];
 SetOptions[$FrontEnd, EvaluatorNames -> evaluatornames]
 ]
]

最终,以下是使用“Test”内核评估笔记本并保存评估内核的代码:

 UsingFrontEnd[     
  AddTestEvaluator["Test"];
  nb = NotebookOpen["test.nb"];
  SetOptions[nb,Evaluator->"Test"];
  SelectionMove[nb,All,Notebook];
  SelectionEvaluate[nb];
  NotebookPauseForEvaluation[nb];
  NotebookSave[nb]
 ]

我仍在寻找解决方案,以解决您的整个问题(即在本地命令行内核中定义a)。


1
这已经非常有用了!您是否知道在内核之间传输与符号相关的定义的简单方法?这正是在并行计算期间发生的情况以及DistributeDefinitions所做的事情。因此,我猜想这已经实现了。但是执行此操作的功能是否对用户可访问? - Szabolcs

10

这是在Windows上使用Arnoud的好作品,只需添加普通的MathLink(非常慢...):

link = LinkCreate["8000", LinkProtocol -> "TCPIP"];
UsingFrontEnd[
NotebookPauseForEvaluation[nb_] := Module[{},
 While[ NotebookEvaluatingQ[nb], Pause[.25] ] ];
NotebookEvaluatingQ[nb_]:=Module[{},
 SelectionMove[nb,All,Notebook];
 Or@@Map["Evaluating"/.#&,Developer`CellInformation[nb]]
];
nb = NotebookOpen["G:\\mma\\test.nb"];
SelectionMove[nb, Before, Notebook];
NotebookWrite[nb, Cell["Link = LinkConnect[\"8000\", LinkProtocol -> \"TCPIP\"]", "Input"]];
SelectionMove[nb, After, Notebook];
NotebookWrite[nb, Cell["LinkWrite[Link, a]", "Input"]];
SelectionMove[nb, All, Notebook];
SelectionEvaluate[nb];
a = LinkRead[link];
Print["a = ",a];
]

谢谢!我们这里真的需要 LinkProtocol -> "TCPIP" 吗?还是可以使用更高效的默认值?(我认为默认情况下它使用内存映射文件进行进程间通信) - Szabolcs
可能是这样。至少我无法通过LinkProtocol -> "SharedMemory"使它工作。 - Rolf Mertig
顺便问一下:你真的需要这个吗?使用DumpSave或类似的方法保存结果不是更容易吗? - Rolf Mertig
也许他在笔记本电脑上开发代码,并希望在远程机器上运行它。这就是我所做的,我发现这些答案非常有用(而且在我的情况下,使用笔记本电脑而不是m文件,可以混合代码和排版讨论)。 - acl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接