您的Mathematica工具包里有什么?[关闭]


152

我们都知道Mathematica很棒,但是它通常也缺少关键的功能。您与Mathematica一起使用哪种外部软件包/工具/资源?

我将编辑(并邀请其他人也这样做)此主要帖子,以包含侧重于科学研究中的一般适用性的资源,并且尽可能多的人会发现有用的资源。随意贡献任何东西,甚至是小的代码片段(就像我在下面的计时例程中所做的那样)。

同样,最欢迎使用Mathematica 7中未记载的有用功能以及您发现自己以外的东西,或者从某些纸张/站点中挖掘出来的东西。

请附上简短说明或评论,说明为何某物很棒或它提供了什么实用程序。如果您通过会员链接链接到Amazon上的图书,请提及该链接,例如,在链接后加上您的名字。


包装方式:

  1. LevelScheme是一个软件包,极大地扩展了Mathematica生成漂亮外观的能力。我将它用于其他任何事情,然后对帧/轴刻度进行了很多改进。它的最新版本称为SciDraw,并将于今年某个时候发布。
  2. 大卫·帕克Presentation Package(David Park's)(50美元-免费更新)
  3. 杰里米·迈克尔森(Jeremy Michelson)的grassmannOps软件包提供了使用格拉斯曼变量和具有非平凡换向关系的算符进行代数和微积分的资源。
  4. John Brown的GrassmannAlgebra书和与Grassmann和Clifford代数一起工作的书。
  5. RISC(符号计算研究所)提供了各种Mathematica(和其他语言)软件包供下载。特别是,在算法组合组的软件页面上,有用于自动定理证明的Theorema,以及用于符号求和,差分方程等的大量软件包。

工具:

  1. MASH是Daniel Reeves出色的Perl脚本,主要是为Mathematica v7提供脚本支持。(现在从Mathematica 8开始内置该-script选件。)
  2. alternate Mathematica shell具有GNU readline输入的An (使用python,仅* nix)
  3. ColourMaths包使您可以直观地选择表达式的各个部分并进行操作。http://www.dbaileyconsultancy.co.uk/colour_maths/colour_maths.html

资源:

  1. Wolfram自己的存储库MathSource在用于各种应用程序的狭窄笔记本中有很多有用的东西。还要查看其他部分,例如

  2. 数学维基教科书

图书:

  1. 数学编程:先进的引进列昂尼德希夫林(webpdf)是,如果你想做的任何事情不止一个必须阅读对于 Mathematica中循环。我们很高兴在Leonid这里回答自己的问题。
  2. James F. Feagin(亚马逊)的Mathematica量子方法
  3. 史蒂芬沃尔夫拉姆(亚马逊的Mathematica书web
  4. 绍姆的提纲亚马逊
  5. Stan Wagon(亚马逊)编写的Mathematica in Action -600页的简洁示例,直至Mathematica版本7。可视化技术特别好,您可以在作者的文章中看到其中的一些内容Demonstrations Page
  6. 理查德·盖洛德(Richard Gaylord pdf)撰写的Mathematica编程基础知识()-对您需要了解的有关Mathematica编程的大多数知识进行了简要的简要介绍。
  7. Sal Mangano撰写的Mathematica Cookbook,由O'Reilly发行,2010年832页。-以著名的O'Reilly Cookbook风格撰写:问题-解决方案。用于中间体。
  8. Mathematica的微分方程,第三版。2004年Elsevier阿姆斯特丹出版社,作者:玛莎·阿贝尔(Martha L. Abell),詹姆斯·布拉瑟尔顿(James P. Braselton)-893页对于初学者,可同时学习解DE和Mathematica。

未记录(或几乎未记录)的功能:

  1. 如何自定义Mathematica键盘快捷键。请参阅this question
  2. 如何检查Mathematica自身功能使用的模式和功能。看到this answer
  3. 如何在Mathematica中实现GraphPlot的大小一致?请参阅this question
  4. 如何使用Mathematica制作文档和演示文稿。请参阅this question

2
Mathematica 8具有更好的Shell脚本集成。wolfram.com/mathematica/new-in-8/mathematica-shell-scripts
Joshua Martell

2
+1,用于LevelScheme。有时有点慢。但是,它具有创建刻度线的明智方法,并且为图形Grid或类似图形创建有价值的期刊布局要容易得多。
rcollyer 2010年

2
正如Alexey在对此问题stackoverflow.com/questions/5152551/…的评论中所建议的那样,我在此处为Mathematica提议了标签重命名:meta.stackexchange.com/questions/81152/…。如果您同意,请查看并投票。我将其发布在这里,因为这个问题在这里的Mma社区中受到很多关注。
belisarius博士2011年

1
总体而言,出于所有常见原因,这个问题实际上应该是社区Wiki:它没有正确的答案,而且比其他任何东西都更重要。我向所有因这个问题而名声大振的人致歉。
rcollyer 2011年

2
这些问题的答案是建设性的,应重新讨论。
MR

Answers:


29

我已经提到过这个之前,但工具我觉得最有用的是应用程序ReapSow其模拟/扩展的行为GatherBy

SelectEquivalents[x_List,f_:Identity, g_:Identity, h_:(#2&)]:=
   Reap[Sow[g[#],{f[#]}]&/@x, _, h][[2]];

这使我可以按任何条件对列表进行分组,并在此过程中对其进行转换。它的工作方式是标准函数(f)标记列表中的每个项目,然后由提供的第二个函数(g)转换每个项目,而特定的输出由第三个函数(h)控制。该函数h接受两个参数:标签和具有该标签的已收集项目的列表。该项目会保留原来的顺序,所以如果你设置h = #1&那么你得到的无序Union,像在实例Reap。但是,它可以用于二次处理。

作为其实用程序的示例,我一直在与Wannier90一起工作,后者将空间相关的哈密顿量输出到文件中,其中每一行是矩阵中的不同元素,如下所示

rx ry rz i j Re[Hij] Im[Hij]

为了将该列表转换为一组矩阵,我收集了包含相同坐标的所有子列表,将元素信息转换为规则(即{i,j}-> Re [Hij] + I Im [Hij]),然后然后SparseArray使用一条班轮将收集到的规则变成全部:

SelectEquivalents[hamlst, 
      #[[;; 3]] &, 
      #[[{4, 5}]] -> (Complex @@ #[[6 ;;]]) &, 
      {#1, SparseArray[#2]} &]

老实说,这是我的瑞士军刀,它使复杂的事情变得非常简单。我的大多数其他工具在某种程度上都是特定于域的,因此我可能不会发布它们。但是,大多数(如果不是全部)参考SelectEquivalents

编辑:它不能完全模仿GatherBy,因为它不能尽可能简单地对表达式的多个级别进行分组GatherBy。但是,Map对于我的大多数需求来说,它都可以正常工作。

例子:@Yaroslav Bulatov要求一个独立的例子。这是我的研究中已大大简化的一项。假设我们在飞机上有一组点

In[1] := pts = {{-1, -1, 0}, {-1, 0, 0}, {-1, 1, 0}, {0, -1, 0}, {0, 0, 0}, 
 {0, 1, 0}, {1, -1, 0}, {1, 0, 0}, {1, 1, 0}}

并且我们希望通过一组对称操作来减少点数。(出于好奇,我们将生成每个点的小组。)对于本示例,让我们使用围绕z轴的四倍旋转轴

In[2] := rots = RotationTransform[#, {0, 0, 1}] & /@ (Pi/2 Range[0, 3]);

使用SelectEquivalents我们可以将在这些操作下产生相同图像集的点进行分组,即它们是等效的,使用以下命令

In[3] := SelectEquivalents[ pts, Union[Through[rots[#] ] ]& ] (*<-- Note Union*)
Out[3]:= {{{-1, -1, 0}, {-1, 1, 0}, {1, -1, 0}, {1, 1, 0}},
          {{-1, 0, 0}, {0, -1, 0}, {0, 1, 0}, {1, 0, 0}},
          {{0,0,0}}}

生成3个包含等效点的子列表。(请注意,Union这里绝对至关重要,因为它可以确保每个点都产生相同的图像。最初,我使用Sort,但是如果一个点位于对称轴上,则在围绕该轴旋转的情况下该点不变,从而为其自身提供了额外的图像因此,Union消除这些多余的图像。另外,GatherBy也将产生相同的结果。)在这种情况下,这些点已经处于我将要使用的形式,但是我只需要每个分组中的代表点,我想要一个计数等效点数 由于我不需要变换每个点,因此我使用Identity在第二位置起作用。对于第三个功能,我们需要小心。传递给它的第一个参数将是旋转下的点的图像,对于该点,该图像{0,0,0}是四个相同元素的列表,并且使用它会丢弃计数。但是,第二个参数只是具有该标签的所有元素的列表,因此它将仅包含{0,0,0}。在代码中

In[4] := SelectEquivalents[pts,  
             Union[Through[rots[#]]]&, #&, {#2[[1]], Length[#2]}& ]
Out[4]:= {{{-1, -1, 0}, 4}, {{-1, 0, 0}, 4}, {{0, 0, 0}, 1}}

注意,最后一步可以很容易地通过

In[5] := {#[[1]], Length[#]}& /@ Out[3]

但是,通过上面的这个例子和较不完整的示例,您很容易看到用最少的代码就能完成非常复杂的转换。


最初的Fortran77代码在1996年感恩节进行了重组,因此多年来一直被称为turkey.f ...:D非常漂亮的图形BTW。记得我Falicov的怪物……
belisarius博士10年

@belisarius,我没有阅读历史,这很有趣。我刚刚开始使用Wannier90,但这是我见过的一些组织最好且编写得井井有条的Fortran代码。让我几乎考虑使用Fortran...
rcollyer 2010年

我想知道您是否可以在操作中添加一个独立的SelectEquivalents示例
Yaroslav

@Yaroslav Bulatov,根据请求添加了一个示例。让我知道是否有帮助。如果没有,我们将看到可以做什么。
rcollyer

您会在此“问题”上打勾,以获得最有趣的代码段贡献。
Timo 2010年

57

Mathematica笔记本界面的优点之一是它可以评估任何语言的表达式,而不仅仅是Mathematica。作为一个简单的示例,请考虑创建一个新的Shell输入单元格类型,该类型将包含的表达式传递到操作系统Shell进行评估。

首先,定义一个函数,该函数将对文本命令的评估委托给外壳程序:

shellEvaluate[cmd_, _] := Import["!"~~cmd, "Text"]

第二个参数是必需的,并且由于以后将变得显而易见的原因而被忽略。接下来,我们要创建一种称为Shell的新样式:

  1. 打开一个新的笔记本。
  2. 选择菜单项“ 格式/编辑样式表...”。
  3. 在对话框中,在输入样式名称旁边键入Shell
  4. 选择新样式旁边的单元格括号。
  5. 选择菜单项“ 单元格/显示表达式”
  6. 使用下面给出的第6步文本覆盖单元格表达式。
  7. 再次选择菜单项“ 单元格/显示表达式”
  8. 关闭对话框。

使用以下单元格表达式作为“ 步骤6文本”

Cell[StyleData["Shell"],
 CellFrame->{{0, 0}, {0.5, 0.5}},
 CellMargins->{{66, 4}, {0, 8}},
 Evaluatable->True,
 StripStyleOnPaste->True,
 CellEvaluationFunction->shellEvaluate,
 CellFrameLabels->{{None, "Shell"}, {None, None}},
 Hyphenation->False,
 AutoQuoteCharacters->{},
 PasteAutoQuoteCharacters->{},
 LanguageCategory->"Formula",
 ScriptLevel->1,
 MenuSortingValue->1800,
 FontFamily->"Courier"]

此表达式的大部分直接从内置的程序样式复制而来。关键的变化是这些行:

 Evaluatable->True,
 CellEvaluationFunction->shellEvaluate,
 CellFrameLabels->{{None, "Shell"}, {None, None}},

Evaluatable启用单元格的SHIFT + ENTER功能。评估将调用CellEvaluationFunction传递的单元格内容和内容类型作为参数(shellEvaluate忽略后一个参数)。 CellFrameLabels只是让我们识别出此单元格不正常而已。

完成所有这些操作后,我们现在可以输入并评估shell表达式:

  1. 在上述步骤中创建的笔记本中,创建一个空单元格并选择单元格括号。
  2. 选择菜单项Format / Style / Shell
  3. 在单元格中输入有效的操作系统外壳程序命令(例如,在Unix上为“ ls”或在Windows上为“ dir”)。
  4. 按SHIFT + ENTER。

最好将此定义的样式保留在位于中心的样式表中。此外,评价函数喜欢shellEvaluate最好定义为使用存根DeclarePackageinit.m。这两项活动的详细信息都超出了此响应的范围。

使用此功能,可以创建包含任何感兴趣语法的输入表达式的笔记本。评估功能可以用纯Mathematica编写,也可以将评估的任何或所有部分委托给外部机构。要知道,有一些涉及细胞的评价,像其他的钩子CellEpilogCellPrologCellDynamicExpression

一种常见的模式包括将输入表达文本写入一个临时文件,以某种语言编译该文件,运行程序并捕获输出以最终显示在输出单元格中。在实现这种完整解决方案时(例如正确捕获错误消息),有很多细节需要解决,但是必须认识到这样一个事实,即不仅可以做这样的事情而且很实际。

就个人而言,正是这种功能使笔记本界面成为我编程领域的中心。

更新资料

以下帮助程序功能对于创建此类单元格非常有用:

evaluatableCell[label_String, evaluationFunction_] :=
  ( CellPrint[
      TextCell[
        ""
      , "Program"
      , Evaluatable -> True
      , CellEvaluationFunction -> (evaluationFunction[#]&)
      , CellFrameLabels -> {{None, label}, {None, None}}
      , CellGroupingRules -> "InputGrouping"
      ]
    ]
  ; SelectionMove[EvaluationNotebook[], All, EvaluationCell]
  ; NotebookDelete[]
  ; SelectionMove[EvaluationNotebook[], Next, CellContents]
  )

因此使用它:

shellCell[] := evaluatableCell["shell", Import["!"~~#, "Text"] &]

现在,如果shellCell[]进行了评估,则将删除输入单元格,并替换为一个新的输入单元格,该输入单元格将其内容评估为shell命令。


3
@WReach +100!我希望我早点知道!至少对我来说,这是非常有用的东西。感谢分享!
Leonid Shifrin

这看起来很漂亮! CellEvaluationFunction我认为也可以用于低级语法黑客。
威兹德先生2011年

@Leonid至少对于FrontEnd,CellEvaluationFunction您正在寻找的钩子吗?
威兹德先生2011年

2
另外:还有一个Cell与单元格评估有关的选项- Evaluator -> "EvaluatorName""EvaluatorName"可以通过Evaluation :: Kernel Configuration Options ...对话框来配置的含义。我仍然不知道是否可以通过编程方式对其进行共同配置...该技术允许Cell在一个笔记本中使用不同s中的不同MathKernels 。这些MathKernels可以来自安装的Mathematica的不同版本。
Alexey Popkov 2011年

1
@Szabolcs我对这项技术的所有使用都涉及到如上所述的stdin _ / _ stdout方法,或一个独立的远程请求,例如SQL查询或HTTP操作。您可以尝试建立一个Python REPL Web应用程序(像这样),并使用与它交互Import,或者启动外部Python过程,并通过其流(使用Java如通信的ProcessBuilder)。我确定有更好的Mathematica方法-听起来像是一个很好的SO问题:)
写出2011年

36

Todd Gayley(Wolfram Research)刚刚给我发送了一个不错的hack,它允许使用任意代码“包装”内置函数。我觉得我必须分享这个有用的工具。以下是托德对我的回答question

一段有趣的历史(?):Robby Villegas和我在1994年左右发明了一种“包装”内置函数的骇客风格,具有讽刺意味的是,该函数为Message出现在我为Mathematica Journal编写的名为ErrorHelp的程序包中那时。从那时起,它已经被许多人使用了很多次。这是内部人员的把戏,但我认为可以说这已经成为将自己的代码注入到内置函数的定义中的规范方法。它可以很好地完成工作。当然,您可以将$ inMsg变量放入所需的任何私有上下文中。

Unprotect[Message];

Message[args___] := Block[{$inMsg = True, result},
   "some code here";
   result = Message[args];
   "some code here";
   result] /; ! TrueQ[$inMsg]

Protect[Message];

@Alexey我很难理解这一点。您能解释一下这是如何工作的吗?某个地方不应该有Unprotect [Message]吗?并且此示例不包含无限递归吗?而且!TrueQ [$ inMsg]对在块作用域内定义的$ inMsg和在块外定义的$ inMsg有意义吗?
Sjoerd C. de Vries

9
@Sjoerd据我所知,Unprotect确实没有,只是被排除在外。Block(动态作用域)和的要点$inMsg就是要防止无限递归。因为$inMsg在外部未定义(这是一个重要的要求),所以首先TrueQ求值为False,然后我们进入函数的主体。但是,当我们体内有函数调用时,条件的计算结果为False(因为变量已由Block重新定义)。因此,用户定义的规则不匹配,而是使用内置规则。
Leonid Shifrin

1
@Leonid谢谢,我明白了。非常聪明!
Sjoerd C. de Vries

1
我刚刚发现,Wolfram Research的Robby Villegas在1999年开发者大会上讨论了这种技术。请参阅此处发布的“使用未评估的表达式”笔记本。在本笔记本中,Robby Villegas在“用于捕获对内置函数的调用的My Block技巧”小节中讨论了该技巧。
阿列克谢·波普科夫

1
@ Mr.Wizard这不是唯一的方法。很长时间以来,我使用的是一个版本DownValues,您可以在运行时重新定义它,您可以查看此帖子groups.google.com/group/comp.soft-sys.math.mathematica/…,例如(SetDelayed重新定义) 。但是我的方法不那么优雅,不那么健壮,更容易出错,并且使得从递归中实现的实现变得不那么琐碎。因此,在大多数情况下,@ Alexey描述的方法很容易取胜。
Leonid Shifrin

25

这不是完整的资源,因此我将其放在“答案”部分中,但是我发现它在解决速度问题时非常有用(不幸的是,这是Mathematica编程的主要内容)。

timeAvg[func_] := Module[
{x = 0, y = 0, timeLimit = 0.1, p, q, iterTimes = Power[10, Range[0, 10]]},
Catch[
 If[(x = First[Timing[(y++; Do[func, {#}]);]]) > timeLimit,
    Throw[{x, y}]
    ] & /@ iterTimes
 ] /. {p_, q_} :> p/iterTimes[[q]]
];
Attributes[timeAvg] = {HoldAll};

用法就很简单timeAvg@funcYouWantToTest

编辑:向导先生提供了一个更简单的版本,它消除了ThrowCatch并且解析起来稍微容易一些:

SetAttributes[timeAvg, HoldFirst]
timeAvg[func_] := Do[If[# > 0.3, Return[#/5^i]] & @@ 
                     Timing @ Do[func, {5^i}]
                     ,{i, 0, 15}]

编辑:这是acl的版本(从此处获取):

timeIt::usage = "timeIt[expr] gives the time taken to execute expr, \
  repeating as many times as necessary to achieve a total time of 1s";

SetAttributes[timeIt, HoldAll]
timeIt[expr_] := Module[{t = Timing[expr;][[1]], tries = 1},
  While[t < 1., tries *= 2; t = Timing[Do[expr, {tries}];][[1]];]; 
  t/tries]

再做一遍,然后……时间进入我自己的书包。tnx!
belisarius博士10年

1
这段代码的一个问题(也许,这是一个完美主义者的观点)是我们可以捕获到我们没有抛出的东西,并将其解释为错误的计时结果。双方CatchThrow应已使用唯一的例外标签。
Leonid Shifrin

2
蒂莫,我很高兴您喜欢我的演绎,足以包括在内。也感谢您给我信誉。我对您重新格式化我的代码的方式感到好奇。除了使自己易于阅读之外,我没有遵循自己代码中的任何特定准则。重新格式化后是否有一种思路?还是只是偏爱?由于Mathematica会重排输入内容的方式,因此不鼓励使用精确的代码格式,但是在此处发布代码使我开始考虑它。顺便说一句,我想你的意思是“ ThrowCatch”而不是“ Reap和” Sow
威兹德先生2011年

1
@ Simon,Wizard先生,我用这种方法来计时不同版本的小函数,这些小函数将被多次调用。不一定是循环结构,而是肯定在MMA优化的构造中。在这种情况下,定时执行循环是有意义的,其性能将接近实际应用。对于定时大型复杂函数(甚至可能是整个初始化单元),Simon的方法将给出更好的结果。总而言之,我对相对值更感兴趣,并且任何一种方法都应该在那起作用。
蒂莫,

3
现在RepeatedTiming要执行此操作。
masterxilo

20

Internal`InheritedBlock

我最近Internal`InheritedBlock从官方新闻组中的Daniel Lichtblau的消息中学到了这样有用的功能。

据我了解,Internal`InheritedBlock允许在Block范围内传递出站函数的副本:

In[1]:= Internal`InheritedBlock[{Message},
Print[Attributes[Message]];
Unprotect[Message];
Message[x___]:=Print[{{x},Stack[]}];
Sin[1,1]
]
Sin[1,1]
During evaluation of In[1]:= {HoldFirst,Protected}
During evaluation of In[1]:= {{Sin::argx,Sin,2},{Internal`InheritedBlock,CompoundExpression,Sin,Print,List}}
Out[1]= Sin[1,1]
During evaluation of In[1]:= Sin::argx: Sin called with 2 arguments; 1 argument is expected. >>
Out[2]= Sin[1,1]

我认为此功能对于需要临时修改内置功能的每个人都非常有用!

与块的比较

让我们定义一些功能:

a := Print[b]

现在,我们希望将此函数的副本传递到Block范围中。天真的审判并没有提供我们想要的东西:

In[2]:= Block[{a = a}, OwnValues[a]]

During evaluation of In[9]:= b

Out[2]= {HoldPattern[a] :> Null}

现在尝试在的第一个参数中使用延迟定义Block(这也是一个未记录的功能):

In[3]:= Block[{a := a}, OwnValues[a]]
Block[{a := a}, a]

Out[3]= {HoldPattern[a] :> a}

During evaluation of In[3]:= b

我们看到在这种情况下a可行,但是我们没有aBlock示波器内部获得原始副本。

现在让我们尝试Internal`InheritedBlock

In[5]:= Internal`InheritedBlock[{a}, OwnValues[a]]

Out[5]= {HoldPattern[a] :> Print[b]}

我们已经获得了作用域a内部的原始定义的副本,Block并且可以按照我们希望的方式对其进行修改,而不会影响的全局定义a


+1非常方便!工具包中还有一个工具,为您提供10点更近的“编辑”特权。
Mr.Wizard

对我而言,这似乎是早期或晚期或完全评估的一种变体。
user2432923

19

数学是一个尖锐的工具,但它可以减少你拥有多少有些类型化的行为雪崩神秘的诊断消息。解决此问题的一种方法是按照以下习惯用法定义函数:

ClearAll@zot
SetAttributes[zot, ...]
zot[a_] := ...
zot[b_ /; ...] := ...
zot[___] := (Message[zot::invalidArguments]; Abort[])

这是很多样板,我经常想跳过这些样板。尤其是在制作原型时,这在Mathematica中经常发生。因此,我使用了一个名为的宏define,该宏使我可以保持纪律,减少样板工作。

的基本用法define是这样的:

define[
  fact[0] = 1
; fact[n_ /; n > 0] := n * fact[n-1]
]

fact[5]

120

起初看起来并不多,但是有一些隐藏的好处。提供的第一个服务define是它自动应用于ClearAll所定义的符号。这样可以确保没有剩余的定义,这是在函数最初开发期间经常发生的情况。

第二项服务是被定义的功能自动“关闭”。我的意思是,如果函数使用与定义之一不匹配的参数列表调用,则该函数将发出消息并中止:

fact[-1]

define::badargs: There is no definition for 'fact' applicable to fact[-1].
$Aborted

这是的主要值define,它捕获了非常常见的错误类别。

另一个便利是在要定义的函数上指定属性的简洁方法。让我们做一个函数Listable

define[
  fact[0] = 1
; fact[n_ /; n > 0] := n * fact[n-1]
, Listable
]

fact[{3, 5, 8}]

{6, 120, 40320}

除了所有常规属性外,还define接受一个称为的附加属性Open。这样可以防止define将所有错误定义添加到函数中:

define[
  successor[x_ /; x > 0] := x + 1
, Open
]

successor /@ {1, "hi"}

{2, successor["hi"]}

可以为一个函数定义多个属性:

define[
  flatHold[x___] := Hold[x]
, {Flat, HoldAll}
]

flatHold[flatHold[1+1, flatHold[2+3]], 4+5]

Hold[1 + 1, 2 + 3, 4 + 5]

事不宜迟,这里是的定义define

ClearAll@define
SetAttributes[define, HoldAll]
define[body_, attribute_Symbol] := define[body, {attribute}]
define[body:(_Set|_SetDelayed), attributes_List:{}] := define[CompoundExpression[body], attributes]
define[body:CompoundExpression[((Set|SetDelayed)[name_Symbol[___], _])..], attributes_List:{}] :=
  ( ClearAll@name
  ; SetAttributes[name, DeleteCases[attributes, Open]]
  ; If[!MemberQ[attributes, Open]
    , def:name[___] := (Message[define::badargs, name, Defer@def]; Abort[])
    ]
  ; body
  ;
  )
def:define[___] := (Message[define::malformed, Defer@def]; Abort[])

define::badargs = "There is no definition for '``' applicable to ``.";
define::malformed = "Malformed definition: ``";

所展示的实现既不支持上值,也不支持curry,也不支持比简单函数定义更通用的模式。但是,它仍然有用。


2
+1-这是非常有用的东西。我一直在使用类似的工具。宏(以及自省和其他元编程技术)可能非常强大,但在Mathematica社区中似乎普遍未被重视,或者至少到目前为止,这是我的印象。
Leonid Shifrin

我刚刚定义了类似的内容。+1为CompoundExpression提供支持以执行多个定义,Abort [](似乎比更多消息更好)和Open(对于例如构造函数来说不错)。
masterxilo

16

在没有空白笔记本的情况下开始

让Mathematica从打开空白笔记本开始让我感到困扰。我可以使用脚本关闭此笔记本,但仍会短暂打开。我的技巧是创建一个Invisible.nb包含以下内容的文件:

Notebook[{},Visible->False]

并将其添加到我的Kernel\init.m

If[Length[Notebooks["Invisible*"]] > 0, 
  NotebookClose[Notebooks["Invisible*"][[1]]]
]

SetOptions[$FrontEnd,
  Options[$FrontEnd, NotebooksMenu] /. 
    HoldPattern["Invisible.nb" -> {__}] :> Sequence[]
]

我现在通过打开Mathematica Invisible.nb

也许有更好的方法,但这对我很有帮助。


定制FoldFoldList

Fold[f, x] 等于 Fold[f, First@x, Rest@x]

顺便说一句,我相信这可能会出现在Mathematica的未来版本中。

惊喜!尽管目前尚无记录,但已实现。 我获悉,它是在2011年由Oliver Ruebenkoenig实施的,显然在我发布此消息后不久。谢谢Oliver Ruebenkoenig!

Unprotect[Fold, FoldList]

Fold[f_, h_[a_, b__]] := Fold[f, Unevaluated @ a, h @ b]
FoldList[f_, h_[a_, b__]] := FoldList[f, Unevaluated @ a, h @ b]

(* Faysal's recommendation to modify SyntaxInformation *)
SyntaxInformation[Fold]     = {"ArgumentsPattern" -> {_, _, _.}};
SyntaxInformation[FoldList] = {"ArgumentsPattern" -> {_, _., {__}}};

Protect[Fold, FoldList]

更新以允许这样做:

SetAttributes[f, HoldAll]
Fold[f, Hold[1 + 1, 2/2, 3^3]]
f[f[1 + 1, 2/2], 3^3]

“动态分区”

有关此功能的新版本,请参见Mathematica.SE发布#7512

通常,我想根据长度顺序对列表进行分区。

伪代码示例:

partition[{1,2,3,4,5,6}, {2,3,1}]

输出: {{1,2}, {3,4,5}, {6}}

我想出了这个:

dynP[l_, p_] := 
 MapThread[l[[# ;; #2]] &, {{0} ~Join~ Most@# + 1, #} &@Accumulate@p]

然后我完成了此工作,包括参数测试:

dynamicPartition[l_List, p : {_Integer?NonNegative ..}] :=
  dynP[l, p] /; Length@l >= Tr@p

dynamicPartition[l_List, p : {_Integer?NonNegative ..}, All] :=
  dynP[l, p] ~Append~ Drop[l, Tr@p] /; Length@l >= Tr@p

dynamicPartition[l_List, p : {_Integer?NonNegative ..}, n__ | {n__}] :=
  dynP[l, p] ~Join~ Partition[l ~Drop~ Tr@p, n] /; Length@l >= Tr@p

第三个参数控制超出拆分规范的元素的处理方式。


Szabolcs的Mathematica技巧

我最常使用的一个是“粘贴表格数据面板”

CreatePalette@
 Column@{Button["TSV", 
    Module[{data, strip}, 
     data = NotebookGet[ClipboardNotebook[]][[1, 1, 1]];
     strip[s_String] := 
      StringReplace[s, RegularExpression["^\\s*(.*?)\\s*$"] -> "$1"];
     strip[e_] := e;
     If[Head[data] === String, 
      NotebookWrite[InputNotebook[], 
       ToBoxes@Map[strip, ImportString[data, "TSV"], {2}]]]]], 
   Button["CSV", 
    Module[{data, strip}, 
     data = NotebookGet[ClipboardNotebook[]][[1, 1, 1]];
     strip[s_String] := 
      StringReplace[s, RegularExpression["^\\s*(.*?)\\s*$"] -> "$1"];
     strip[e_] := e;
     If[Head[data] === String, 
      NotebookWrite[InputNotebook[], 
       ToBoxes@Map[strip, ImportString[data, "CSV"], {2}]]]]], 
   Button["Table", 
    Module[{data}, data = NotebookGet[ClipboardNotebook[]][[1, 1, 1]];
     If[Head[data] === String, 
      NotebookWrite[InputNotebook[], 
       ToBoxes@ImportString[data, "Table"]]]]]}

从内部修改外部数据 Compile

最近,Daniel Lichtblau展示了我从未见过的这种方法。在我看来,它极大地扩展了Compile

ll = {2., 3., 4.};
c = Compile[{{x}, {y}}, ll[[1]] = x; y];

c[4.5, 5.6]

ll

(* Out[1] = 5.6  *)

(* Out[2] = {4.5, 3., 4.}  *)

3
+1好收藏!关于内部的外部修改 Compile-我的整个帖子在这里:stackoverflow.com/questions/5246330/…,目的是在非平凡的情况下展示这种可能性(那里已经有一个简短,快速的解决问题的方法) 。IMO,这方面的最大胜利是能够模拟按引用传递并将大型编译功能分解为可管理和可重用的块的能力。
Leonid Shifrin

1
您还可以调整你的新定义的折叠并FoldList语法信息:SyntaxInformation [折纸] = {“ArgumentsPattern” - > {_, 。,_}}; 语法信息[FoldList] = {“ ArgumentsPattern”-> {_,_。,{_ }}};
faysou 2011年

14

一般的PDF / EMF导出问题和解决方案

1)这是完全没有预料到的,没有文档记录,但是Mathematica使用一组样式定义导出并保存PDF和EPS格式的图形,这些样式定义不同于在屏幕上显示笔记本的样式定义。默认情况下,笔记本电脑在“工作”风格的环境在屏幕上显示(这是默认值ScreenStyleEvironment全局$FrontEnd选项),但在打印"Printout"样式环境(这是默认值PrintingStyleEnvironment全局$FrontEnd选项)。当以栅格格式(例如GIF和PNG或EMF格式)导出图形时,Mathematica生成的图形看起来完全像在Notebook内部。看来"Working"在这种情况下,使用样式环境进行渲染。但是,当您导出/保存PDF或EPS格式的内容时,情况并非如此!在这种情况下"Printout",默认情况下使用的样式环境与“工作”样式环境有很大的不同。首先,"Printout"风格的环境设置Magnification到80% 。其次,对于不同样式的字体大小,它使用自己的值,与原始的屏幕显示形式相比,生成的PDF文件中的字体大小变化不一致。后者可以称为FontSize波动,这非常烦人。但是很高兴可以通过将PrintingStyleEnvironment全局$FrontEnd选项设置为“ Working”来避免这种情况:

SetOptions[$FrontEnd, PrintingStyleEnvironment -> "Working"]

2)导出为EMF格式的常见问题是,大多数程序(不仅是Mathematica)都会生成一个默认大小的文件,但是放大时却很难看。这是因为图元文件是按照屏幕分辨率保真度采样的。可以通过Magnify输入原始图形对象来增强生成的EMF文件的质量,以使原始图形采样的准确性变得更加精确。比较两个文件:

graphics1 = 
  First@ImportString[
    ExportString[Style["a", FontFamily -> "Times"], "PDF"], "PDF"];
graphics2 = Magnify[graphics1, 10];
Export["C:\\test1.emf", graphics1]
Export["C:\\test2.emf", graphics2]

如果将这些文件插入Microsoft Word并放大它们,您将看到第一个“ a”上有锯齿,而第二个则没有(用Mathematica 6 测试)。

Chris DegnenImageResolution提出了另一种解决方法(此选项至少从Mathematica 8 起生效):

Export["C:\\test1.emf", graphics1]
Export["C:\\test2.emf", graphics1, ImageResolution -> 300]

3)在Mathematica中,我们提供了三种将图形转换为图元文件的方法:通过Export"EMF"(强烈推荐的方式:以尽可能高的质量生成图元文件),通过Save selection As...菜单项(产生不太精确的图形,不推荐)和通过Edit ► Copy As ► Metafile菜单项(我强烈建议反对这条路线)。


13

根据普遍的需求,使用SO API生成前10名SO Answerers图(注释除外)的代码。

在此处输入图片说明

getRepChanges[userID_Integer] :=
 Module[{totalChanges},
  totalChanges = 
   "total" /. 
    Import["http://api.stackoverflow.com/1.1/users/" <> 
      ToString[userID] <> "/reputation?fromdate=0&pagesize=10&page=1",
      "JSON"];
  Join @@ Table[
    "rep_changes" /. 
     Import["http://api.stackoverflow.com/1.1/users/" <> 
       ToString[userID] <> 
       "/reputation?fromdate=0&pagesize=10&page=" <> ToString[page], 
      "JSON"],
    {page, 1, Ceiling[totalChanges/10]}
    ]
  ]

topAnswerers = ({"display_name", 
      "user_id"} /. #) & /@ ("user" /. ("top_users" /. 
      Import["http://api.stackoverflow.com/1.1/tags/mathematica/top-\
answerers/all-time", "JSON"]))

repChangesTopUsers =
  Monitor[Table[
    repChange = 
     ReleaseHold[(Hold[{DateList[
              "on_date" + AbsoluteTime["January 1, 1970"]], 
             "positive_rep" - "negative_rep"}] /. #) & /@ 
        getRepChanges[userID]] // Sort;
    accRepChange = {repChange[[All, 1]], 
       Accumulate[repChange[[All, 2]]]}\[Transpose],
    {userID, topAnswerers[[All, 2]]}
    ], userID];

pl = DateListLogPlot[
  Tooltip @@@ 
   Take[({repChangesTopUsers, topAnswerers[[All, 1]]}\[Transpose]), 
    10], Joined -> True, Mesh -> None, ImageSize -> 1000, 
  PlotRange -> {All, {10, All}}, 
  BaseStyle -> {FontFamily -> "Arial-Bold", FontSize -> 16}, 
  DateTicksFormat -> {"MonthNameShort", " ", "Year"}, 
  GridLines -> {True, None}, 
  FrameLabel -> (Style[#, FontSize -> 18] & /@ {"Date", "Reputation", 
      "Top-10 answerers", ""})]

1
布雷特(Brett)发布了一个问题,要求提供几乎完全相同的代码。也许在那里最合适,进行一两个调整以适合该问题。与这个问题相反,我实际上是值得代表的。
rcollyer 2011年

@rcollyer是正确的。这是“社区Wiki”
belisarius博士2011年

@belisarius我只是在布雷特问题的答案中复制了它……
Sjoerd C. de Vries

@Sjoerd您的图不会自动更新。
belisarius博士2011年

@belisarius实际上,我希望您能承担这个任务……;-)
Sjoerd C. de Vries

13

缓存表达式

我发现这些功能对于缓存任何表达式非常有帮助。这两个函数的有趣之处在于,与mathematica中众所周知的记忆(仅在函数定义为f的情况下才可以缓存结果)相比,保留的表达式本身用作哈希表/符号Cache或CacheIndex的键。 [x_]:= f [x] = ...因此,您可以缓存代码的任何部分,如果要多次调用一个函数但不必重新计算部分代码,则这很有用。

独立于其参数来缓存表达式。

SetAttributes[Cache, HoldFirst];
c:Cache[expr_] := c = expr;

Ex: Cache[Pause[5]; 6]
Cache[Pause[5]; 6]

表达式第二次返回6,而无需等待。

使用可以依赖于缓存表达式的参数的别名表达式缓存表达式。

SetAttributes[CacheIndex, HoldRest];
c:CacheIndex[index_,expr_] := c = expr;

Ex: CacheIndex[{"f",2},x=2;y=4;x+y]

如果expr需要花费一些时间进行计算,则求值{“ f”,2}的速度要快得多,例如检索缓存的结果。

对于这些功能的变化形式,以便具有本地化的高速缓存(即,高速缓存存储器会自动在Block构造外部释放),请参阅这篇文章,避免重复调用Interpolation

删除缓存的值

当您不知道函数的定义数时删除高速缓存的值。我认为定义的参数中有一个空格。

DeleteCachedValues[f_] := 
       DownValues[f] = Select[DownValues[f], !FreeQ[Hold@#,Pattern]&];

当您知道一个函数的定义数量时(快一点)删除高速缓存的值。

DeleteCachedValues[f_,nrules_] := 
       DownValues[f] = Extract[DownValues[f], List /@ Range[-nrules, -1]];

这利用了一个事实,即函数的定义位于其DownValues列表的末尾,而缓存的值位于其前。

使用符号存储数据和类似对象的功能

这里还有一些有趣的功能,可以使用像对象这样的符号。

众所周知,您可以将数据存储在符号中并使用DownValues快速访问它们

mysymbol["property"]=2;

您可以使用以下功能基于此站点上帖子中提交的权限来访问符号的键(或属性)列表:

SetAttributes[RemoveHead, {HoldAll}];
RemoveHead[h_[args___]] := {args};
NKeys[symbol_] := RemoveHead @@@ DownValues[symbol(*,Sort->False*)][[All,1]];
Keys[symbol_] := NKeys[symbol] /. {x_} :> x;

我经常使用此函数来显示符号的DownValues中包含的所有信息:

PrintSymbol[symbol_] :=
  Module[{symbolKeys},
    symbolKeys = Keys[symbol];
    TableForm@Transpose[{symbolKeys, symbol /@ symbolKeys}]
  ];

最后,这是一种创建符号的简单方法,该符号在面向对象的编程中的行为类似于对象(它只是重现了OOP的最基本行为,但我发现语法很优雅):

Options[NewObject]={y->2};
NewObject[OptionsPattern[]]:=
  Module[{newObject},
    newObject["y"]=OptionValue[y];

    function[newObject,x_] ^:= newObject["y"]+x;
    newObject /: newObject.function2[x_] := 2 newObject["y"]+x;

    newObject
  ];

属性作为DownValues存储,方法作为延迟Upvalue存储在返回的Module创建的符号中。我在Mathematica中的Tree数据结构中找到了function2的语法,该语法通常是函数的OO语法。

有关每个符号具有的现有值类型的列表,请参见http://reference.wolfram.com/mathematica/tutorial/PatternsAndTransformationRules.htmlhttp://www.verbeia.com/mathematica/tips/HTMLLinks/Tricks_Misc_4.html

例如试试这个

x = NewObject[y -> 3];
function[x, 4]
x.function2[5]

你可以走得更远,如果你想使用一个叫做可在这里InheritRules包效仿对象继承 http://library.wolfram.com/infocenter/MathSource/671/

您还可以将函数定义存储在newObject中,而不是在类型符号中,因此,如果NewObject返回type [newObject]而不是newObject,则可以在NewObject外部(而不是内部)定义function和function2,并且用法与之前相同。

function[type[object_], x_] ^:= object["y"] + x;
type /: type[object_].function2[x_] := 2 object["y"]+x;

使用UpValues [type]可以看到在type符号中定义了function和function2。

有关此最后一种语法的更多想法,请参见https://mathematica.stackexchange.com/a/999/66

SelectEquivalents的改进版本

@rcollyer:非常感谢您将SelectEquivalents引入了表面,这是一个了不起的功能。这是上面列出的SelectEquivalents的改进版本,具有更多的可能性和使用选项,因此更易于使用。

Options[SelectEquivalents] = 
   {
      TagElement->Identity,
      TransformElement->Identity,
      TransformResults->(#2&) (*#1=tag,#2 list of elements corresponding to tag*),
      MapLevel->1,
      TagPattern->_,
      FinalFunction->Identity
   };

SelectEquivalents[x_List,OptionsPattern[]] := 
   With[
      {
         tagElement=OptionValue@TagElement,
         transformElement=OptionValue@TransformElement,
         transformResults=OptionValue@TransformResults,
         mapLevel=OptionValue@MapLevel,
         tagPattern=OptionValue@TagPattern,
         finalFunction=OptionValue@FinalFunction
      }
      ,
      finalFunction[
         Reap[
            Map[
               Sow[
                  transformElement@#
                  ,
                  {tagElement@#}
               ]&
               , 
               x
               , 
               {mapLevel}
            ] 
            , 
            tagPattern
            , 
            transformResults
         ][[2]]
      ]
   ];

以下是如何使用此版本的示例:

正确使用Mathematica收集/收集

您将如何在Mathematica中执行数据透视表功能?

Mathematica快速2D分箱算法

内部`袋

Daniel Lichtblau在这里描述了一个有趣的内部数据结构,用于列表的增长。

在Mathematica中实现四叉树

调试功能

这两篇文章指出了调试有用的功能:

使用Mathematica编写小代码或大代码时如何调试?工作台?mma调试器?或者是其他东西?(展示下)

/programming/5459735/the-clearest-way-to-represent-mathematicas-evaluation-sequence/5527117#5527117(TraceView

这是另一个基于Reap和Sow的函数,用于从程序的不同部分提取表达式并将其存储在符号中。

SetAttributes[ReapTags,HoldFirst];
ReapTags[expr_]:=
   Module[{elements},
      Reap[expr,_,(elements[#1]=#2/.{x_}:>x)&];
      elements
   ];

这是一个例子

ftest[]:=((*some code*)Sow[1,"x"];(*some code*)Sow[2,"x"];(*some code*)Sow[3,"y"]);
s=ReapTags[ftest[]];
Keys[s]
s["x"]
PrintSymbol[s] (*Keys and PrintSymbol are defined above*)

其他资源

以下是用于学习目的的有趣链接列表:

Mathematica学习资源的集合

在这里更新:https : //mathematica.stackexchange.com/a/259/66


相关:“ 用内存构造函数的最佳方法 ”。WReach提供了一个简单函数的惊人示例,它不仅可以记住其值,还可以将它们写入文件,并在重新启动时向后读取。
Alexey Popkov 2011年

1
相关主题:“ Mathematica:如何清除符号的缓存,即取消设置无模式的DownValues ”。此问题说明如何使用标准f[x_] := f[x] = some code备忘来清除缓存。
西蒙(Simon)

7
+1有一个很好的符号方便,消除了在缓存函数中重复定义左侧的需求,例如:c:Cache[expr_] := c = expr
写到2011年

的不错变体SelectEquivalents。我认为,我将保留TagOnElement第二个参数Identity作为默认参数,因为它是其中使用最多的参数。我也不认为会包含在内FinalOp,因为它可以在中处理OpOnTaggedElems。我还会缩短选项名称,因为它们的长度使得输入时很尴尬。尝试TagFunctionTransformElementTransformResults,和TagPattern来代替。两者TagPatternMapLevel都是对功能的重要补充,并且总体而言是很好的重写。
rcollyer 2011年

感谢您的评论。我考虑了这一点,并提高了代码的可读性。我保留FinalFunction是因为它对Reap的结果进行运算,例如,如果要保留标记,则按标记对最终结果进行排序。
faysou 2011年

12

我的实用程序功能(我在MASH中内置了这些功能,在问题中提到):

pr = WriteString["stdout", ##]&;            (* More                           *)
prn = pr[##, "\n"]&;                        (*  convenient                    *)
perr = WriteString["stderr", ##]&;          (*   print                        *)
perrn = perr[##, "\n"]&;                    (*    statements.                 *)
re = RegularExpression;                     (* I wish mathematica             *)
eval = ToExpression[cat[##]]&;              (*  weren't so damn               *)
EOF = EndOfFile;                            (*   verbose!                     *)
read[] := InputString[""];                  (* Grab a line from stdin.        *)
doList[f_, test_] :=                        (* Accumulate list of what f[]    *)
  Most@NestWhileList[f[]&, f[], test];      (*  returns while test is true.   *)
readList[] := doList[read, #=!=EOF&];       (* Slurp list'o'lines from stdin. *)
cat = StringJoin@@(ToString/@{##})&;        (* Like sprintf/strout in C/C++.  *)
system = Run@cat@##&;                       (* System call.                   *)
backtick = Import[cat["!", ##], "Text"]&;   (* System call; returns stdout.   *)
slurp = Import[#, "Text"]&;                 (* Fetch contents of file as str. *)
                                            (* ABOVE: mma-scripting related.  *)
keys[f_, i_:1] :=                           (* BELOW: general utilities.      *)
  DownValues[f, Sort->False][[All,1,1,i]];  (* Keys of a hash/dictionary.     *)
SetAttributes[each, HoldAll];               (* each[pattern, list, body]      *)
each[pat_, lst_, bod_] := ReleaseHold[      (*  converts pattern to body for  *)
  Hold[Cases[Evaluate@lst, pat:>bod];]];    (*   each element of list.        *)
some[f_, l_List] := True ===                (* Whether f applied to some      *)
  Scan[If[f[#], Return[True]]&, l];         (*  element of list is True.      *)
every[f_, l_List] := Null ===               (* Similarly, And @@ f/@l         *)
  Scan[If[!f[#], Return[False]]&, l];       (*  (but with lazy evaluation).   *)

有关“每个”功能的信息,请参见stackoverflow.com/questions/160216/foreach-loop-in-mathematica
dreeves

11

我使用的一个技巧可以模拟大多数内置函数使用错误参数的方式(通过发送一条消息,然后返回未赋值的整个形式),Condition在定义中使用了一种奇怪的工作方式。如果foo仅应使用一个参数:

foo[x_] := x + 1;
expr : foo[___] /; (Message[foo::argx, foo, Length@Unevaluated[expr], 1]; 
                    False) := Null; (* never reached *)

如果您有更复杂的需求,可以很容易地将参数验证和消息生成作为独立的功能考虑在内。通过使用副作用,您Condition不仅可以生成消息,还可以做更多复杂的事情,但是我认为其中大多数都属于“卑鄙的黑客”类别,应尽可能避免使用。

另外,在“元编程”类别中,如果您有Mathematica包(.m)文件,则可以使用"HeldExpressions"元素来获取文件中所有用包裹的表达式HoldComplete。与使用基于文本的搜索相比,这使查找内容更加容易。不幸的是,没有一种简单的方法可以对笔记本执行相同的操作,但是您可以使用以下方法获取所有输入表达式:

inputExpressionsFromNotebookFile[nb_String] :=
 Cases[Get[nb],
  Cell[BoxData[boxes_], "Input", ___] :>
   MakeExpression[StripBoxes[boxes], StandardForm],
  Infinity]

最后,您可以使用Module模拟词汇闭包的事实来创建等效的引用类型。这是一个简单的堆栈(它使用变体来Condition作为错误处理的窍门,作为奖励):

ClearAll[MakeStack, StackInstance, EmptyQ, Pop, Push, Peek]
 With[{emptyStack = Unique["empty"]},
  Attributes[StackInstance] = HoldFirst;
  MakeStack[] :=
   Module[{backing = emptyStack},
    StackInstance[backing]];

  StackInstance::empty = "stack is empty";

  EmptyQ[StackInstance[backing_]] := (backing === emptyStack);

  HoldPattern[
    Pop[instance : StackInstance[backing_]]] /;
    ! EmptyQ[instance] || (Message[StackInstance::empty]; False) :=
   (backing = Last@backing; instance);

  HoldPattern[Push[instance : StackInstance[backing_], new_]] :=
   (backing = {new, backing}; instance);

  HoldPattern[Peek[instance : StackInstance[backing_]]] /;
    ! EmptyQ[instance] || (Message[StackInstance::empty]; False) :=
   First@backing]

现在,您可以以不必要的复杂方式以相反的顺序打印列表的元素!

With[{stack = MakeStack[], list},
 Do[Push[stack, elt], {elt, list}];

 While[!EmptyQ[stack],
  Print[Peek@stack];
  Pop@stack]]

1
HeldExpressions包中元素的+1 尚未意识到。我通常是作为字符串导入,然后ToExpressionHoldComplete最后一个arg一起使用。关于Condition消息的使用-自1994年以来,这一直是软件包编写的一种标准技术。关于通过Modulevars进行持久化-不久前,我在Mathgroup上发表了一篇很长的文章:groups.google.com/group/comp.soft- sys.math.mathematica /…(这是我在该线程的第三篇文章),内容大致相同,并链接到一些不平凡的用法示例。
Leonid Shifrin'2

@Leonid Shifrin:我Condition可能是从同事那里拿来作为绝杀的东西,但没有意识到这是一种标准技术。关于将Module符号用作引用类型的链接很有趣!
Pillsy'2

+1,我从没想过。我对这种语言了解得越多,它似乎越强大。
rcollyer 2011年

@Pillsy那样做堆栈的目的是什么?
威兹德先生2011年

@ Mr.Wizard:我只是选择了我可以想到的最简单的可变数据结构之一来说明该技术。
Pillsy 2011年

11

不带上下文的打印系统符号定义

contextFreeDefinition[]下面的函数将尝试在没有最常见上下文的情况下打印符号的定义。然后可以将该定义复制到Workbench并进行格式化以提高可读性(选择它,右键单击,Source-> Format)

Clear[commonestContexts, contextFreeDefinition]

commonestContexts[sym_Symbol, n_: 1] := Quiet[
  Commonest[
   Cases[Level[DownValues[sym], {-1}, HoldComplete], 
    s_Symbol /; FreeQ[$ContextPath, Context[s]] :> Context[s]], n],
  Commonest::dstlms]

contextFreeDefinition::contexts = "Not showing the following contexts: `1`";

contextFreeDefinition[sym_Symbol, contexts_List] := 
 (If[contexts =!= {}, Message[contextFreeDefinition::contexts, contexts]];
  Internal`InheritedBlock[{sym}, ClearAttributes[sym, ReadProtected];
   Block[{$ContextPath = Join[$ContextPath, contexts]}, 
    Print@InputForm[FullDefinition[sym]]]])

contextFreeDefinition[sym_Symbol, context_String] := 
 contextFreeDefinition[sym, {context}]

contextFreeDefinition[sym_Symbol] := 
 contextFreeDefinition[sym, commonestContexts[sym]]

withRules []

警告: 此功能不本地化变量以同样的方式WithModule做,那嵌套本地化结构不会按预期方式工作,其手段。 withRules[{a -> 1, b -> 2}, With[{a=3}, b_ :> b]] 替换aand b在嵌套With和中RuleWith而不会这样做。

这是With使用规则而不是=and 的变体:=

ClearAll[withRules]
SetAttributes[withRules, HoldAll]
withRules[rules_, expr_] :=
  Internal`InheritedBlock[
    {Rule, RuleDelayed},
    SetAttributes[{Rule, RuleDelayed}, HoldFirst];
    Unevaluated[expr] /. rules
  ]

在清理实验期间编写的代码并本地化变量时,我发现这很有用。有时候,我最终得到的参数列表形式为{par1 -> 1.1, par2 -> 2.2}。通过使用withRules参数值,可以轻松地将其插入先前使用全局变量编写的代码中。

用法就像With

withRules[
  {a -> 1, b -> 2},
  a+b
]

抗锯齿3D图形

即使图形硬件本身不支持抗锯齿3D图形,这也是一种非常简单的技术。

antialias[g_, n_: 3] := 
  ImageResize[Rasterize[g, "Image", ImageResolution -> n 72], Scaled[1/n]]

这是一个例子:

Mathematica图形 Mathematica图形

请注意,较大的值n或较大的图像往往会暴露图形驱动程序错误或引入伪影。


笔记本差异功能

<<AuthorTools`包中提供了笔记本差异功能,并且(未提供版本信息)(至少在版本8中)提供了笔记本差异功能NotebookTools`。这是一个GUI,用于区分当前打开的两个笔记本:

PaletteNotebook@DynamicModule[
  {nb1, nb2}, 
  Dynamic@Column[
    {PopupMenu[Dynamic[nb1], 
      Thread[Notebooks[] -> NotebookTools`NotebookName /@ Notebooks[]]], 
     PopupMenu[Dynamic[nb2], 
      Thread[Notebooks[] -> NotebookTools`NotebookName /@ Notebooks[]]], 
     Button["Show differences", 
      CreateDocument@NotebookTools`NotebookDiff[nb1, nb2]]}]
  ]

Mathematica图形


一切都会很好,但这并不能真正地对变量进行本地化,正如您可以看到的,a = 3; b = 4;可以在示例调用之前先分配say ,然后调用withRules。您可以使用以下方法保存它:SetAttributes[withRules, HoldAll];withRules[rules_, expr_] := Unevaluated[expr] /. Unevaluated[rules]。当时的语义差异With:1.现在评估规则的withRules范围2. 无法像使用内部作用域结构那样解决命名冲突With。最后一个非常严重-根据情况而定是好是坏。
Leonid Shifrin

@Leonid您完全正确,看来我从未学习过在发布之前正确检查代码的情况……当我使用它时,我几乎从不为变量赋值,但这是一个非常严重的问题,您是对的。您如何看待更正版本?(我真的不关心不处理嵌套Withs这个并不总是工作,内置的本地化构建或者,如:With[{a=1}, Block[{a=2}, a]]你是否认为有很好的理由嵌套的。Block不本地化那里,就像嵌套WithModule呢?)
扎博尔奇斯

@Leonid我不是简单地使用,Unevaluated[rules]因为我想x -> 1+1评估RHS。
Szabolcs

@Leonid您实际上是对的,嵌套的本地化问题可能非常严重。我认为嵌套Withs很容易发现和避免,但是模式不是:With[{a = 1}, a_ -> a]将内部局部化awithRules不会。您是否知道有什么方法可以访问Mathematica的内部本地化机制并创建Rule也可以本地化的新结构(类似于)?我可能稍后会删除此答案,因为它比用途更危险,但我想先使用它。
Szabolcs

我认为您的使用InheritedBlock非常酷,并且可以非常优雅地解决问题。至于作用域冲突,通常在“词法绑定时间”(即运行时之前)进行词法作用域的绑定,而动态作用域在运行时进行绑定,这可能可以解释这一点。您可以将它与的类似情况进行对比Module,后者可以进行有建设性的使用(请参见例如此处stackoverflow.com/questions/7394113/…)。问题是Block需要一些符号来...
Leonid Shifrin

9

递归纯函数(#0)似乎是该语言较暗的角落之一。这里有一些非常重要的用法示例,它们确实有用(不是没有它们就无法完成)。给定一系列指定为顶点对的边列表,以下是一个相当简洁且相当快速的函数,用于在图形中查找连接的组件:

ClearAll[setNew, componentsBFLS];
setNew[x_, x_] := Null;
setNew[lhs_, rhs_]:=lhs:=Function[Null, (#1 := #0[##]); #2, HoldFirst][lhs, rhs];

componentsBFLS[lst_List] := Module[{f}, setNew @@@ Map[f, lst, {2}];
   GatherBy[Tally[Flatten@lst][[All, 1]], f]];

这里发生的事情是,我们首先在每个顶点编号上映射一个虚拟符号,然后设置给定一对顶点{f[5],f[10]}(例如)然后f[5]求和的方式f[10]。递归纯函数用作路径压缩器(以建立备忘录的方式,使得只要f[1]=f[3],f[3]=f[4],f[4]=f[2], ...发现组件的新“根”,就可以修正备忘录的值,而不是像长链一样修正备忘录的值。这可以显着提高速度。因为我们使用赋值,所以我们需要将其设为HoldAll,这会使此构造更加晦涩且更具吸引力()。此功能是数学组在线和离线讨论的结果,该讨论由Fred Simons,Szabolcs Horvat,DrMajorBob和您的真正参与。例:

In[13]:= largeTest=RandomInteger[{1,80000},{40000,2}];

In[14]:= componentsBFLS[largeTest]//Short//Timing
Out[14]= {0.828,{{33686,62711,64315,11760,35384,45604,10212,52552,63986,  
     <<8>>,40962,7294,63002,38018,46533,26503,43515,73143,5932},<<10522>>}}

它当然比内置的要慢得多,但是对于代码的大小,IMO仍然相当快。

另一个示例:这是Select基于链表和递归纯函数的递归实现:

selLLNaive[x_List, test_] :=
  Flatten[If[TrueQ[test[#1]],
     {#1, If[#2 === {}, {}, #0 @@ #2]},
     If[#2 === {}, {}, #0 @@ #2]] & @@ Fold[{#2, #1} &, {}, Reverse[x]]];

例如,

In[5]:= Block[
         {$RecursionLimit= Infinity},
         selLLNaive[Range[3000],EvenQ]]//Short//Timing

Out[5]= {0.047,{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,
 <<1470>>,2972,2974,2976,2978,2980,2982,2984,2986,2988,2990,
  2992,2994,2996,2998,3000}}

但是,它不是正确的尾部递归,并且会炸毁堆栈(使内核崩溃)以获得更大的列表。这是尾递归版本:

selLLTailRec[x_List, test_] :=
Flatten[
 If[Last[#1] === {},
  If[TrueQ[test[First[#1]]],
   {#2, First[#1]}, #2],
  (* else *)
  #0[Last[#1],
   If[TrueQ[test[First[#1]]], {#2, First[#1]}, #2]
   ]] &[Fold[{#2, #1} &, {}, Reverse[x]], {}]];

例如,

In[6]:= Block[{$IterationLimit= Infinity},
       selLLTailRec[Range[500000],EvenQ]]//Short//Timing
Out[6]= {2.39,{2,4,6,8,10,12,14,16,18,20,22,
       <<249978>>,499980,499982,499984,499986,499988,499990,499992,
        499994,499996,499998,500000}} 

连接组件的功能仍然是我的最爱:-)
Szabolcs

@Szabolcs是的,这很酷。您和弗雷德(Fred)做了大部分工作,鲍比和我(IIRC)仅增加了一些改进。
Leonid Shifrin

8

这是Stan Wagon的书中的配方...当内置Plot由于缺乏精度而无法正常运行时使用

Options[PrecisePlot] = {PrecisionGoal -> 6};
PrecisePlot[f_, {x_, a_, b_}, opts___] := Module[{g, pg},
   pg = PrecisionGoal /. {opts} /. Options[PrecisePlot];
   SetAttributes[g, NumericFunction];
   g[z_?InexactNumberQ] := Evaluate[f /. x -> z];
   Plot[N[g[SetPrecision[y, \[Infinity]]], pg], {y, a, b},
    Evaluate[Sequence @@ FilterRules[{opts}, Options[Plot]]]]];

当我需要从Mathematica的贬值中获得“类似字典”的行为时,我经常使用Kristjan Kannike的以下技巧

index[downvalue_, 
   dict_] := (downvalue[[1]] /. HoldPattern[dict[x_]] -> x) // 
   ReleaseHold;
value[downvalue_] := downvalue[[-1]];
indices[dict_] := 
  Map[#[[1]] /. {HoldPattern[dict[x_]] -> x} &, DownValues[dict]] // 
   ReleaseHold;
values[dict_] := Map[#[[-1]] &, DownValues[dict]];
items[dict_] := Map[{index[#, dict], value[#]} &, DownValues[dict]];
indexQ[dict_, index_] := 
  If[MatchQ[dict[index], HoldPattern[dict[index]]], False, True];

(* Usage example: *)
(* Count number of times each subexpression occurs in an expression *)
expr = Cos[x + Cos[Cos[x] + Sin[x]]] + Cos[Cos[x] + Sin[x]]
Map[(counts[#] = If[indexQ[counts, #], counts[#] + 1, 1]; #) &, expr, Infinity];
items[counts]

当评估结果令人困惑时,有时有助于将评估步骤转储到文本文件中

SetAttributes[recordSteps, HoldAll];
recordSteps[expr_] :=
 Block[{$Output = List@OpenWrite["~/temp/msgStream.m"]}, 
  TracePrint[Unevaluated[expr], _?(FreeQ[#, Off] &), 
   TraceInternal -> True];
  Close /@ $Output;
  Thread[Union@
    Cases[ReadList["~/temp/msgStream.m", HoldComplete[Expression]], 
     symb_Symbol /; 
       AtomQ@Unevaluated@symb && 
        Context@Unevaluated@symb === "System`" :> 
      HoldComplete@symb, {0, Infinity}, Heads -> True], HoldComplete]
  ]

(* Usage example: *)
(* puts steps of evaluation of 1+2+Sin[5]) into ~/temp/msgStream.m *)
recordSteps[1+2+Sin[5]]

一个用法示例将是很棒的。有时间时尝试发布一个。
belisarius博士10年

你知道克里斯蒂安吗?我曾经在赫尔辛基和他一起工作过。好人,小世界。
蒂莫(Timo)

不,在网上找到了他的代码。实际上,试图向他发送电子邮件以修复代码中的一个小错误,但是他网页上的电子邮件不再起作用
Yaroslav Bulatov 2010年

8

可以通过使用未公开的命令行选项-batchinput和,-batchoutput以批处理模式运行MathKernel :

math -batchinput -batchoutput < input.m > outputfile.txt

(其中input.m以换行符结尾的批处理输入文件outputfile.txt是将输出重定向到的文件)。

Mathematica v。> = 6中,MathKernel具有未记录的命令行选项:

-noicon

它控制MathKernel在任务栏上是否具有可见图标(至少在Windows下)。

FrontEnd(至少从v.5起)具有未记录的命令行选项

-b

这将禁用启动屏幕并允许更快地运行Mathematica FrontEnd

和选项

-directlaunch

会禁用启动最新安装的Mathematica版本而不是启动与系统注册表中与.nb文件关联的版本的机制。

另一种方法可能

而不是在安装目录中启动Mathematica.exe二进制文件,而是在SystemFiles \ FrontEnd \ Binaries \ Windows中启动Mathematica.exe二进制文件。前者是一个简单的启动程序,它会尽最大努力将打开笔记本的请求重定向到运行用户界面的副本。后者是用户界面二进制文件本身。

将最后一个命令行选项与设置全局FrontEnd选项结合使用非常方便,该选项VersionedPreferences->True 可禁用已安装的不同Mathematica版本之间的首选项共享

SetOptions[$FrontEnd, VersionedPreferences -> True]

(以上内容应在安装的最新Mathematica版本中进行评估。)

Mathematica 8中,这是在“首选项”对话框中“系统”窗格中的“创建和维护特定于版本的前端首选项”设置下进行控制的

通过使用未记录的密钥-h(Windows的代码),可能会获得FrontEnd的命令行选项的不完整列表:

SetDirectory[$InstallationDirectory <> 
   "\\SystemFiles\\FrontEnd\\Binaries\\Windows\\"];
Import["!Mathematica -h", "Text"]

给出:

Usage:  Mathematica [options] [files]
Valid options:
    -h (--help):  prints help message
    -cleanStart (--cleanStart):  removes existing preferences upon startup
    -clean (--clean):  removes existing preferences upon startup
    -nogui (--nogui):  starts in a mode which is initially hidden
    -server (--server):  starts in a mode which disables user interaction
    -activate (--activate):  makes application frontmost upon startup
    -topDirectory (--topDirectory):  specifies the directory to search for resources and initialization files
    -preferencesDirectory (--preferencesDirectory):  specifies the directory to search for user AddOns and preference files
    -password (--password):  specifies the password contents
    -pwfile (--pwfile):  specifies the path for the password file
    -pwpath (--pwpath):  specifies the directory to search for the password file
    -b (--b):  launches without the splash screen
    -min (--min):  launches as minimized

其他选项包括:

-directLaunch:  force this FE to start
-32:  force the 32-bit FE to start
-matchingkernel:  sets the frontend to use the kernel of matching bitness
-Embedding:  specifies that this instance is being used to host content out of process

MathKernel和FrontEnd是否还有其他可能有用的命令行选项?如果您知道,请分享。

相关问题


“匹配的咬感?” 那是什么意思?
威兹德先生2011年

@ Mr.Wizard也许该选项仅在64位系统与该选项结合使用时才有意义,-32并且意味着FrontEnd使用的MathKernel的位数将与操作系统的位数(64位)匹配。似乎在其他情况下,此选项不会更改任何内容。
阿列克谢·波普科夫

7

我最喜欢的技巧是小的代码生成宏,使您可以用一个短命令替换一堆标准样板命令。或者,您可以创建用于打开/创建笔记本的命令。

这是我在Mathematica日常工作流程中使用了一段时间的内容。我发现自己做了很多事情:

  1. 使笔记本具有私有上下文,加载我需要的包,使其自动保存。
  2. 在使用此笔记本一段时间后,我想在一个单独的笔记本中进行一些草稿计算,该笔记本具有自己的私有上下文,同时可以访问我在“主”笔记本中一直使用的定义。因为我设置了私有上下文,所以这需要手动调整$ ContextPath

一遍又一遍地手动完成所有操作很痛苦,所以让我们自动化吧!首先,一些实用程序代码:

(* Credit goes to Sasha for SelfDestruct[] *)
SetAttributes[SelfDestruct, HoldAllComplete];
SelfDestruct[e_] := (If[$FrontEnd =!= $Failed,
   SelectionMove[EvaluationNotebook[], All, EvaluationCell]; 
   NotebookDelete[]]; e)

writeAndEval[nb_,boxExpr_]:=(
    NotebookWrite[nb,  CellGroupData[{Cell[BoxData[boxExpr],"Input"]}]];
    SelectionMove[nb, Previous, Cell]; 
    SelectionMove[nb, Next, Cell];
    SelectionEvaluate[nb];
)

ExposeContexts::badargs = 
  "Exposed contexts should be given as a list of strings.";
ExposeContexts[list___] := 
 Module[{ctList}, ctList = Flatten@List@list; 
  If[! MemberQ[ctList, Except[_String]],AppendTo[$ContextPath, #] & /@ ctList, 
   Message[ExposeContexts::badargs]];
  $ContextPath = DeleteDuplicates[$ContextPath];
  $ContextPath]

    Autosave[x:(True|False)] := SetOptions[EvaluationNotebook[],NotebookAutoSave->x];

现在,让我们创建一个宏,该宏将在笔记本中放置以下单元格:

SetOptions[EvaluationNotebook[], CellContext -> Notebook]
Needs["LVAutils`"]
Autosave[True]

这是宏:

MyPrivatize[exposedCtxts : ({__String} | Null) : Null]:=
  SelfDestruct@Module[{contBox,lvaBox,expCtxtBox,assembledStatements,strList},
    contBox = MakeBoxes[SetOptions[EvaluationNotebook[], CellContext -> Notebook]];
    lvaBox = MakeBoxes[Needs["LVAutils`"]];

    assembledStatements = {lvaBox,MakeBoxes[Autosave[True]],"(*********)"};
    assembledStatements = Riffle[assembledStatements,"\[IndentingNewLine]"]//RowBox;
    writeAndEval[InputNotebook[],contBox];
    writeAndEval[InputNotebook[],assembledStatements];
    If[exposedCtxts =!= Null,
       strList = Riffle[("\"" <> # <> "\"") & /@ exposedCtxts, ","];
       expCtxtBox = RowBox[{"ExposeContexts", "[", RowBox[{"{", RowBox[strList], "}"}], "]"}];
       writeAndEval[InputNotebook[],expCtxtBox];
      ]
 ]

现在,当我键入MyPrivatize[]is 时,将创建私有上下文并加载我的标准包。现在,让我们创建一个命令,该命令将使用其自己的私有上下文打开一个新的暂存笔记本(以便您可以大肆放弃,而不会搞砸定义),但是可以访问您当前的上下文。

SpawnScratch[] := SelfDestruct@Module[{nb,boxExpr,strList},
    strList = Riffle[("\"" <> # <> "\"") & /@ $ContextPath, ","];
    boxExpr = RowBox[{"MyPrivatize", "[",
        RowBox[{"{", RowBox[strList], "}"}], "]"}];
    nb = CreateDocument[];
    writeAndEval[nb,boxExpr];
]

SelfDestruct这样做的好处是,由于运行命令时,它不会在当前笔记本中留下任何痕迹-很好,因为否则会造成混乱。

要获得更多的样式点,您可以使用来为这些宏创建关键字触发器InputAutoReplacements,但是我将其作为练习留给读者。


7

PutAppend具有PageWidth-> Infinity

Mathematica中,使用PutAppend命令是维护具有中间计算结果的运行日志文件的最直接方法。但是,PageWith->78在将表达式导出到文件时,它默认使用设置,因此不能保证每个中间输出在日志中仅占一行。

PutAppend本身没有任何选项,但是跟踪其评估结果表明,它基于OpenAppend具有该PageWith选项的函数,并允许通过以下SetOptions命令更改其默认值:

In[2]:= Trace[x>>>"log.txt",TraceInternal->True]
Out[2]= {x>>>log.txt,{OpenAppend[log.txt,CharacterEncoding->PrintableASCII],OutputStream[log.txt,15]},Null}

因此,我们可以PutAppend通过设置每次仅追加一行:

SetOptions[OpenAppend, PageWidth -> Infinity]

更新

版本10中引入了一个错误(版本11.3中已修复):SetOptions不再影响OpenWriteand 的行为OpenAppend

一种解决方法是PutAppend使用显式PageWidth -> Infinity选项实现您自己的版本:

Clear[myPutAppend]
myPutAppend[expr_, pathtofile_String] :=
 (Write[#, expr]; Close[#];) &[OpenAppend[pathtofile, PageWidth -> Infinity]]

请注意,我们也可以WriteString答案所示通过via来实现,但是在这种情况下,有必要将表达式预先转换为相应的InputFormvia ToString[expr, InputForm]


6

我只是在浏览其中的一个程序包以包含在其中,并发现了一些我定义的消息,它们使工作感到惊奇: Debug::<some name>。默认情况下,它们是关闭的,因此不会产生太多开销。但是,我可以随便乱扔我的代码,如果需要弄清楚代码的行为方式,可以将它们打开。


从“帮助”>“ 2.0版”(1991年发布)开始,Debug已被Trace取代。
belisarius博士10年

1
@belisarius,您错过了重点。它既Debug不是Trace功能,也不是功能。这是我创建的一组消息,可以随意添加/禁用代码。它们以单词开头,Debug就像usagemsg以函数名称开头一样。它提供与cout在c ++代码中放置一堆语句相同的功能。
rcollyer 2010年

1
噢抱歉。我感到困惑,因为我从未从幼儿园毕业,因为他没有学习“资本是国家的”:D
belisarius博士10年

6

使我对内置作用域构造感到困扰的一件事是,它们立即评估所有局部变量定义,因此您不能编写例如

With[{a = 5, b = 2 * a},
    ...
]

所以不久前,我想出了一个名为WithNest的宏,您可以使用它来进行此操作。我发现它很方便,因为它使您可以将变量绑定保持在本地,而不必执行类似的操作

Module[{a = 5,b},
    b = 2 * a;
    ...
]

最后,我能找到的最佳方法是使用特殊符号,使其更容易在绑定列表上进行递归,然后将定义放入其自己的包中,以使该符号隐藏。也许有人对这个问题有更简单的解决方案?

如果您想尝试一下,请将以下内容放入名为的文件中Scoping.m

BeginPackage["Scoping`"];

WithNest::usage=
"WithNest[{var1=val1,var2=val2,...},body] works just like With, except that
values are evaluated in order and later values have access to earlier ones.
For example, val2 can use var1 in its definition.";

Begin["`Private`"];

(* Set up a custom symbol that works just like Hold. *)
SetAttributes[WithNestHold,HoldAll];

(* The user-facing call.  Give a list of bindings and a body that's not
our custom symbol, and we start a recursive call by using the custom
symbol. *)
WithNest[bindings_List,body:Except[_WithNestHold]]:=
WithNest[bindings,WithNestHold[body]];

(* Base case of recursive definition *)
WithNest[{},WithNestHold[body_]]:=body;

WithNest[{bindings___,a_},WithNestHold[body_]]:=
WithNest[
{bindings},
WithNestHold[With[List@a,body]]];

SyntaxInformation[WithNest]={"ArgumentsPattern"->{{__},_}};
SetAttributes[WithNest,{HoldAll,Protected}];

End[];

EndPackage[];

剑锋发布一个版本的这一点,并在MathGroup引用您的问题: stackoverflow.com/questions/4190845/custom-notation-question/...
Mr.Wizard

感谢您指出了这一点!自从我看了这些东西已经有一段时间了,看到所有其他方法很有趣。
DGrady

5

这是由Alberto Di Lullo(他似乎没有出现在Stack Overflow上)写的。

CopyToClipboard,对于Mathematica 7(内置在Mathematica 8中)

CopyToClipboard[expr_] := 
  Module[{nb}, 
   nb = CreateDocument[Null, Visible -> False, WindowSelected -> True];
   NotebookWrite[nb, Cell[OutputFormData@expr], All];
   FrontEndExecute[FrontEndToken[nb, "Copy"]];
   NotebookClose@nb];

原始帖子:http : //forums.wolfram.com/mathgroup/archive/2010/Jun/msg00148.html

我发现此例程对于以普通的十进制格式将较大的实数复制到剪贴板很有用。例如CopyToClipboard["123456789.12345"]

Cell[OutputFormData@expr] 整齐地删除引号。


5

此代码创建一个调色板,将选择内容作为图像上传到Stack Exchange。在Windows上,提供了一个额外的按钮,可以更忠实地呈现所选内容。

将代码复制到笔记本单元格中并进行评估。然后从输出中弹出调色板,并使用安装Palettes -> Install Palette...

如果您有任何问题,请在此处发表评论。在此处下载笔记本版本。


Begin["SOUploader`"];

Global`palette = PaletteNotebook@DynamicModule[{},

   Column[{
     Button["Upload to SE",
      With[{img = rasterizeSelection1[]},
       If[img === $Failed, Beep[], uploadWithPreview[img]]],
      Appearance -> "Palette"],

     If[$OperatingSystem === "Windows",

      Button["Upload to SE (pp)",
       With[{img = rasterizeSelection2[]},
        If[img === $Failed, Beep[], uploadWithPreview[img]]],
       Appearance -> "Palette"],

      Unevaluated@Sequence[]
      ]
     }],

   (* Init start *)
   Initialization :>
    (

     stackImage::httperr = "Server returned respose code: `1`";
     stackImage::err = "Server returner error: `1`";

     stackImage[g_] :=
      Module[
       {getVal, url, client, method, data, partSource, part, entity,
        code, response, error, result},

       getVal[res_, key_String] :=
        With[{k = "var " <> key <> " = "},
         StringTrim[

          First@StringCases[
            First@Select[res, StringMatchQ[#, k ~~ ___] &],
            k ~~ v___ ~~ ";" :> v],
          "'"]
         ];

       data = ExportString[g, "PNG"];

       JLink`JavaBlock[
        url = "http://stackoverflow.com/upload/image";
        client =
         JLink`JavaNew["org.apache.commons.httpclient.HttpClient"];
        method =
         JLink`JavaNew[
          "org.apache.commons.httpclient.methods.PostMethod", url];
        partSource =
         JLink`JavaNew[
          "org.apache.commons.httpclient.methods.multipart.\
ByteArrayPartSource", "mmagraphics.png",
          JLink`MakeJavaObject[data]@toCharArray[]];
        part =
         JLink`JavaNew[
          "org.apache.commons.httpclient.methods.multipart.FilePart",
          "name", partSource];
        part@setContentType["image/png"];
        entity =
         JLink`JavaNew[
          "org.apache.commons.httpclient.methods.multipart.\
MultipartRequestEntity", {part}, method@getParams[]];
        method@setRequestEntity[entity];
        code = client@executeMethod[method];
        response = method@getResponseBodyAsString[];
        ];

       If[code =!= 200, Message[stackImage::httperr, code];
        Return[$Failed]];
       response = StringTrim /@ StringSplit[response, "\n"];

       error = getVal[response, "error"];
       result = getVal[response, "result"];
       If[StringMatchQ[result, "http*"],
        result,
        Message[stackImage::err, error]; $Failed]
       ];

     stackMarkdown[g_] :=
      "![Mathematica graphics](" <> stackImage[g] <> ")";

     stackCopyMarkdown[g_] := Module[{nb, markdown},
       markdown = Check[stackMarkdown[g], $Failed];
       If[markdown =!= $Failed,
        nb = NotebookCreate[Visible -> False];
        NotebookWrite[nb, Cell[markdown, "Text"]];
        SelectionMove[nb, All, Notebook];
        FrontEndTokenExecute[nb, "Copy"];
        NotebookClose[nb];
        ]
       ];

     (* Returns available vertical screen space,
     taking into account screen elements like the taskbar and menu *)


     screenHeight[] := -Subtract @@
        Part[ScreenRectangle /. Options[$FrontEnd, ScreenRectangle],
         2];

     uploadWithPreview[img_Image] :=
      CreateDialog[
       Column[{
         Style["Upload image to the Stack Exchange network?", Bold],
         Pane[

          Image[img, Magnification -> 1], {Automatic,
           Min[screenHeight[] - 140, 1 + ImageDimensions[img][[2]]]},
          Scrollbars -> Automatic, AppearanceElements -> {},
          ImageMargins -> 0
          ],
         Item[
          ChoiceButtons[{"Upload and copy MarkDown"}, \
{stackCopyMarkdown[img]; DialogReturn[]}], Alignment -> Right]
         }],
       WindowTitle -> "Upload image to Stack Exchange?"
       ];

     (* Multiplatform, fixed-width version.
        The default max width is 650 to fit Stack Exchange *)
     rasterizeSelection1[maxWidth_: 650] :=
      Module[{target, selection, image},
       selection = NotebookRead[SelectedNotebook[]];
       If[MemberQ[Hold[{}, $Failed, NotebookRead[$Failed]], selection],

        $Failed, (* There was nothing selected *)

        target =
         CreateDocument[{}, WindowSelected -> False, Visible -> False,
           WindowSize -> maxWidth];
        NotebookWrite[target, selection];
        image = Rasterize[target, "Image"];
        NotebookClose[target];
        image
        ]
       ];

     (* Windows-only pixel perfect version *)
     rasterizeSelection2[] :=
      If[
       MemberQ[Hold[{}, $Failed, NotebookRead[$Failed]],
        NotebookRead[SelectedNotebook[]]],

       $Failed, (* There was nothing selected *)

       Module[{tag},
        FrontEndExecute[
         FrontEndToken[FrontEnd`SelectedNotebook[], "CopySpecial",
          "MGF"]];
        Catch[
         NotebookGet@ClipboardNotebook[] /.
          r_RasterBox :>
           Block[{},
            Throw[Image[First[r], "Byte", ColorSpace -> "RGB"], tag] /;
              True];
         $Failed,
         tag
         ]
        ]
       ];
     )
   (* Init end *)
   ]

End[];

4

我敢肯定,很多人都遇到了运行某些东西的情况,意识到它不仅卡住了程序,而且在最近10分钟内没有保存!

编辑

经历了一段时间后,有一天我发现可以Mathematica代码中创建自动保存。我认为过去使用这种自动保存功能对我有很大帮助,我一直觉得这种可能性本身并不是很多人意识到他们可以做到的。

我使用的原始代码在底部。多亏了这些评论,我发现它是有问题的,并且最好以另一种方式使用它来做ScheduledTask(这仅在Mathematica 8中有效)。

代码此中可以找到这个答案Sjoerd C. de Vries (因为我不知道它是否可以把它复制到这里,我只把它当作一个链接。)


以下解决方案使用Dynamic。它将每60秒保存一次笔记本,但是显然只有在其单元格可见的情况下才可以保存笔记本。我仅出于完成原因而将其留在这里。(以及Mathematica 6和7的用户)

/编辑

为了解决这个问题,我在笔记本的开头使用了以下代码:

Dynamic[Refresh[NotebookSave[]; DateString[], UpdateInterval -> 60]]

这将每60秒节省您的工作。
我喜欢NotebookAutoSave[]之所以是因为它在处理输入之前会保存,并且因为某些文件的文本多于输入。

我最初在这里找到它:http : //en.wikipedia.org/wiki/Talk : Mathematica#Criticisms

请注意,一旦运行此行,即使关闭并重新打开文件(只要启用了动态更新),也会进行保存。

另外,由于Mathematica中没有撤消操作,因此请注意不要删除所有内容,因为保存将使其不可逆(作为预防措施,我从每个已完成的笔记本中删除此代码)


您还可以使用其他名称(例如,将当前时间和日期附加到文件名的末尾)保存在特定目录(例如“备份”)中。这就像版本控制的原始形式。
ACL

您可以执行类似的操作NotebookSave[SelectedNotebook[], "work-" <> IntegerString[i] <> ".nb"]; i++,但是我认为对当前笔记本名称的任何引用都将是递归的。
tsvikas 2011年

2
我认为Dynamic对象仅在可见时才会刷新,因此,例如将Dynamic对象滚动到可见区域之外,我不确定该方法是否会起作用。再说一次,我没有尝试过。无论如何,我只是提供了一个建议。
ACL

1
您可以使用进行测试Dynamic[Refresh[i++, UpdateInterval -> 1, TrackedSymbols -> {}]]。滚动视线中的递增数字,等待一分钟,然后向后滚动,以查看该数字并未递增60。关于UpdateInterval:通常在可能的情况下使用,但是如果您的代码包含更改的变量,则此更改将在刷新之前触发新的刷新。间隔结束。不使用TrackedSymbols
Sjoerd C. de Vries

1
@ j0ker5试试我上面的代码,您会发现UpdateInterval并不总是强制将更新间隔为指定的间隔。此代码还显示,仅当Dynamic包含的单元格在前端可见时Dynamic才起作用。它真的在看不见的那一刻就停止了。人们真的不应该相信此代码来保存他们的文件,因为事实并非如此。它的危险
Sjoerd C. de Vries


3

我发现在开发软件包时将此键盘快捷方式添加到我的SystemFiles/FrontEnd/TextResources/Windows/KeyEventTranslations.tr文件中非常有用。

(* Evaluate Initialization Cells: Real useful for reloading library changes. *)

Item[KeyEvent["i", Modifiers -> {Control, Command}],
    FrontEndExecute[
        FrontEndToken[
            SelectedNotebook[],
            "EvaluateInitialization"]]],

每个下一个 Packagename.m我做一个PackagenameTest.nb笔记本进行测试,并将测试笔记本的前两个单元格设置为初始化单元格。在第一个单元格中

Needs["PackageManipulations`"]

加载非常有用 由Leonid编写 PackageManipulations库。第二个单元格包含

PackageRemove["Packagename`Private`"]
PackageRemove["Packagename`"]
PackageReload["Packagename`"]

所有这些都可以实际加载软件包。请注意,前两行仅Remove所有符号,因为我希望保持上下文尽可能整洁。

这样,编写和测试程序包的工作流程就变成了这样。

  1. 将更改保存到 Packagename.m
  2. 转到PackagenameTest.nbCTRL + ALT + i

这将导致初始化单元重新加载程序包,从而使测试变得非常简单。


1

以下函数format[expr_]可用于缩进/格式化mathematica跨越页面的未格式化表达式

indent[str_String, ob_String, cb_String, delim_String] := 
  Module[{ind, indent, f, tab}, ind = 0; tab = "    ";
   indent[i_, tab_, nl_] := nl <> Nest[tab <> ToString[#] &, "", i];
   f[c_] := (indent[ind, "", " "] <> c <> indent[++ind, tab, "\n"]) /;StringMatchQ[ob, ___ ~~ c ~~ ___];
   f[c_] := (indent[--ind, "", " "] <> c <> indent[ind, tab, "\n"]) /;StringMatchQ[cb, ___ ~~ c ~~ ___];
   f[c_] := (c <> indent[ind, tab, "\n"]) /;StringMatchQ[delim, ___ ~~ c ~~ ___];
   f[c_] := c;
   f /@ Characters@str // StringJoin];
format[expr_] := indent[expr // InputForm // ToString, "[({", "])}", ";"];

(*    
format[Hold@Module[{ind, indent, f, tab}, ind = 0; tab = "    ";
 indent[i_, tab_, nl_] := nl <> Nest[tab <> ToString[#] &, "", i];
 f[c_] := (indent[ind, "", " "] <> c <> indent[++ind, tab, "\n"]) /;StringMatchQ[ob, ___ ~~ c ~~ ___];
 f[c_] := (indent[--ind, "", " "] <> c <> indent[ind, tab, "\n"]) /;StringMatchQ[cb, ___ ~~ c ~~ ___];
 f[c_] := (c <> indent[ind, tab, "\n"]) /;StringMatchQ[delim, ___ ~~ c ~~ ___];
 f[c_] := c;
 f /@ Characters@str // StringJoin]]
*)

参考:https : //codegolf.stackexchange.com/questions/3088/indent-a-string-using-given-parentheses


您在实践中将其用于什么?将输出应用于代码或数据(列表)时,其输出有点“有趣”,以至于无法读取format@RandomInteger[10,{3,3}]pastebin.com/nUT54Emq 既然您已经具备了基础知识,并且对此感兴趣,可以将代码改进为产生有用的可读格式?然后,下一步是制作一个粘贴按钮,该按钮将使用缩进的Mathematica代码创建输入单元(最好保留注释!)。另请参见我的相关问题
Szabolcs
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.