你的 Mathematica 工具包里有什么?

我们都知道 Mathematica 很棒,但是它也常常缺乏关键的功能。Mathematica 使用什么样的外部包/工具/资源?

我将编辑(并邀请其他人也这样做)这个主要职位,包括资源,这是关于科学研究的普遍适用性和尽可能多的人会发现有用的。请随意贡献任何东西,甚至是小代码片段(就像我在下面为计时例程所做的那样)。

另外,Mathematica 7中没有文档记录的、有用的特性,或者从一些文章/网站中挖掘出来的特性,都是非常受欢迎的。

请包括一个简短的描述或评论,为什么一些是伟大的或它提供了什么实用性。如果你链接到亚马逊的书籍与联盟链接请提到它,例如,把你的名字后面的链接。


包装:

  1. LevelScheme 是一个软件包,极大地扩展了 Mathematica 生成漂亮情节的能力。我使用它,如果没有其他任何东西,然后为了更多,更好的控制框架/轴刻度。它的最新版本叫做 SciDraw,将在今年的某个时候发布。
  2. 大卫 · 帕克的 Presentation Package(50美元-更新免费)
  3. Jeremy Michelson 的 grassmannOps包提供了使用 Grassmann 变量和具有非平凡对易关系的运算符进行代数和微积分的资源。
  4. 约翰布朗的 GrassmannAlgebra工作与格拉斯曼和 Clifford 代数包和书。
  5. RISC (符号计算研究所) 有各种 Mathematica (和其他语言)软件包可供下载。特别是定理机器证明的 定理,以及在 组合算法组的软件页面的符号求和、差分方程等的众多软件包。

工具:

  1. MASH 是 Daniel Reeves 优秀的 Perl脚本,实际上为 Mathematica v7提供了脚本支持。(现在在 Mathematica 8中内置了 -script选项。)
  2. 带有 GNU readline 输入的 alternate Mathematica shell(仅使用 python,* nix)
  3. 使用 ColourMaths 包,您可以直观地选择表达式的某些部分并对其进行操作

资源:

  1. Wolfram 自己的存储库 MathSource为各种应用程序提供了许多有用的(如果是狭义的)笔记本电脑。还可以查看其他部分,如

  2. Mathematica Wikibook.

书评:

  1. Mathematica 编程: Leonid Shifrin 的高级介绍(webpdf)是一本必读的书,如果你想在 Mathematica 做任何超过 为了循环的事情。我们有幸请到 Leonid本人在这里回答问题。
  2. James F. Feagin 的 Mathematica 量子方法(亚马逊)
  3. 作者: Stephen Wolfram (亚马逊)(web)
  4. 萧万长的大纲 (亚马逊)
  5. Mathematica in Action 作者: Stan Wagon (亚马逊)-600页简洁的例子,直到 Mathematica 第7版。可视化技术特别好,你可以在作者的 Demonstrations Page中看到其中的一些。
  6. 作者: Richard Gaylord (pdf)-关于 Mathematica 编程你需要知道的大部分内容的简明介绍。
  7. Sal Mangano 编写的 Mathematica 食谱由 O’Reilly 出版社出版2010年832页。- 用著名的 O’Reilly 食谱风格写的: 问题-解决方案。给中间人用的。
  8. 微分方程与 Mathematica,第3版。爱思唯尔2004年阿姆斯特丹 作者: Martha L. Abell,James P. Braselton-893页对于初学者,同时学习 DEs 和 Mathematica。

未记录(或几乎没有记录)的特征:

  1. 如何自定义 Mathematica 键盘快捷键。参见 this question
  2. 如何检查 Mathematica 自己的函数使用的模式和函数。参见 this answer
  3. 如何在 Mathematica 实现图形大小的一致性。
  4. 如何使用 Mathematica 生成文档和演示文稿。参见 this question
32423 次浏览

这不是一个完整的资源,所以我把它放在这里的答案部分,但我发现它非常有用,当计算速度问题(不幸的是,这是一个很大的 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

编辑: Wizard 先生提供了一个更简单的版本,去掉了 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]

这是 Stan Wagon 书中的配方... 当内置情节由于缺乏精确性而行为不稳定时使用它

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]]

请记住,Mathematica Book 也可以在 http://reference.wolfram.com/legacy/v5_2/上在线获得——尽管它已经被 http://reference.wolfram.com上的当前文档所取代

我刚刚浏览了我的一个包,发现了一些我定义的消息: Debug::<some name>。默认情况下,它们是关闭的,所以不会产生太多的开销。但是,我可以把它们扔在我的代码中,如果我需要弄清楚一点代码是如何工作的,我可以打开它们。

我的实用程序函数(我在 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).   *)

我以前提到过 这个,但是我发现最有用的工具是 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]

但是,通过这个示例和上面不太完整的示例,很容易看到用最少的代码就可以实现非常复杂的转换。

Mathematica 是一个尖锐的工具,但它可以削减你与其有点 不同类型的行为雪崩的神秘 诊断信息。处理这个问题的一种方法是按照这个习语定义函数:

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的主要值,它捕获一类非常常见的错误。

另一个方便的方法是用简洁的方式指定正在定义的函数的属性:

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: ``";

所展示的实现既不支持向上值也不支持局部套用,也不支持比简单函数定义更通用的模式。然而,它仍然有用。

递归纯函数(#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}}

我使用的一个技巧允许您模拟大多数内置函数处理错误参数的方式(通过发送消息,然后返回未计算的整个表单) ,它利用了在定义中使用 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]]

Todd Gayley (沃尔夫勒姆研究公司)刚刚发给我一个不错的代码,允许用任意代码“包装”内置函数。我觉得我必须分享这个有用的工具。以下是托德在我的 question上的回答。

一个有趣的(?)历史: 这种“包装”的黑客风格 内置函数是由 Robby Villegas 和我在1994年左右发明的, 具有讽刺意味的是,在一个名为 ErrorHelp 的包中,有一个 Message 函数 我当时为《数学杂志》写的文章。它已经被使用了 很多次,很多人,从那以后。这是一个有点内部人士的 但我认为公平地说,它已经成为规范 将您自己的代码注入到内置的 函数。它可以很好地完成工作。当然,你可以把 $inMsg 变量转换为任意您希望的私有上下文。

Unprotect[Message];


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


Protect[Message];

开始时不要打开一个空白的笔记本

让 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[]
]

我现在通过打开 abc0来启动 Mathematica

也许有更好的办法,但这对我很有用。


定制 FoldFoldList

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

顺便说一句,我相信这可能会在未来版本的 Mathematica 中找到它的方法。

惊喜吧!这已经实现了,尽管目前还没有文档记录。我被告知,它是由 Oliver Ruebenkoenig 在2011年实施的,显然是在我发表这篇文章后不久。谢谢你 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 邮编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

第三个参数控制对拆分规范之外的元素的处理。


Szabocs 的 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.}  *)

Mathematica 笔记本界面的一个好处是,它可以用 任何语言计算表达式,而不仅仅是 Mathematica。作为一个简单的例子,考虑创建一个新的 壳牌输入单元格类型,将包含的表达式传递给壳层进行计算。

首先,定义一个函数,该函数将文本命令的求值委托给外部 shell:

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

第二个论点是必要的,并且被忽略了,其中的原因稍后将会显现出来。接下来,我们要创建一个名为 壳牌的新样式:

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

使用以下单元格表达式作为 第六步文字:

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. 选择菜单项 格式/样式/外壳
  3. 在单元格中键入一个有效的壳层命令(例如 Unix 中的“ ls”或 Windows 中的“ dir”)。
  4. 按 Shift + Enter。

最好将此定义的样式保存在位于中心位置的样式表中。此外,像 shellEvaluate这样的评估函数最好定义为使用 init.m中的 声明包裹的存根。这两个活动的细节都超出了本响应的范围。

有了这个功能,就可以创建包含任何感兴趣语法的输入表达式的笔记本。评估功能可以用纯 Mathematica 编写,也可以将评估的任何或所有部分委托给外部机构。请注意,还有其他与细胞评估相关的钩子,如 CellEpilogCellPrologCellDynamicExpression

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

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

更新

下面的 helper 函数对于创建这样的单元格很有用:

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 命令的形式计算其内容。

Internal`InheritedBlock

我最近从官方新闻组的 这是丹尼尔 · 利希特布劳的信息中了解到 Internal`InheritedBlock这样有用的功能的存在。

据我所知,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工作,但我们没有得到原来的 a的副本内的 Block范围。

现在让我们试试 Internal`InheritedBlock:

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


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

我们已经得到了 Block范围内的 a的原始定义的副本,我们可以按照我们想要的方式修改它,而不会影响 a的全局定义!

关于内置作用域构造,困扰我的一个问题是它们一次计算所有的局部变量定义,因此您不能编写这样的例子

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[];

根据流行的需求,使用 空气污染指数生成前10个 SO 应答图(除了 注释)的代码。

enter image description here

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", ""})]

可以通过使用未记录的 命令行选项 ABC0和 -batchoutput以批处理模式运行 MathKernel:

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

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

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

-noicon

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

FrontEnd (至少从5节开始)有一个未记录的命令行选项

-b

禁用启动画面并允许更快地运行 Mathematica FrontEnd

和选择

-directlaunch

而不是在系统注册表中启动与.nb 文件相关联的版本。

另一种方法可能是 :

而不是启动 中的 Mathematica.exe 二进制文件 安装目录,启动 Mathematica.exe 二进制文件 SystemFiles FrontEnd 二进制文件窗口。 前者是一个简单的发射器 尽最大努力 重新定向开放请求 笔记本的副本 用户界面。后者是 用户界面二进制本身。

将最后一个命令行选项与设置全局 FrontEnd 选项 VersionedPreferences->True 禁止在安装的不同 < em > Mathematica 版本之间共享首选项组合起来很方便:

SetOptions[$FrontEnd, VersionedPreferences -> True]

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

Mathematica8 这是在首选项对话框控制,在系统面板,在设置“创建和维护版本特定的前端首选项”下

可以通过使用未记录的键 -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 是否还有其他潜在有用的命令行选项? 如果您知道,请与我们分享。

相关问题。

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

以下是我在日常 Mathematica 工作流程中使用了一段时间的内容。我发现自己经常做以下几件事:

  1. 使笔记本有一个私人上下文,加载包(s)我需要,使它自动保存。
  2. 在使用这个笔记本一段时间后,我想在一个单独的笔记本中做一些草稿计算,它有自己的私有上下文,同时可以访问我在“ main”笔记本中使用的定义。因为我设置了私有上下文,所以需要手动调整 $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[]是创建私有上下文和加载我的标准包。现在,让我们创建一个命令,它将打开一个带有自己私有上下文的新的草稿笔记本(这样您就可以随心所欲地修改它,而不会有搞砸定义的风险) ,但是可以访问您当前的上下文。

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

由于 SelfDestruct的缘故,这个命令在运行时不会在当前的笔记本中留下任何痕迹——这很好,因为否则它只会创建混乱。

对于额外的样式点,您可以使用 InputAutoReplacements为这些宏创建关键字触发器,但是我将留给读者作为练习。

一般 PDF/EMF 出口问题及解决方案

1)这是完全出乎意料和没有文件的,但 Mathematica导出和保存 PDF 和 EPS 格式的图形使用一套风格定义,不同于用来显示屏幕上的笔记本电脑。默认情况下,笔记本显示在屏幕上的“工作”样式环境(这是 ScreenStyleEvironment全局 $FrontEnd选项的默认值) ,但是打印在 "Printout"样式环境(这是 PrintingStyleEnvironment全局 $FrontEnd选项的默认值)。当一个以栅格格式(如 GIF 和 PNG)或 EMF 格式导出图形时,Mathematica生成的图形看起来与笔记本电脑内部的图形一模一样。在这种情况下,似乎使用了 "Working"样式环境来呈现。但是,当您导出/保存 PDF 或 EPS 格式的任何内容时,情况并非如此!在这种情况下,$FrontEnd1与“工作”风格的环境有很大的不同。首先,$FrontEnd2。其次,它对不同样式的字体大小使用自己的值,这导致生成的 PDF 文件中的字体大小变化与原始屏幕上的表示相比不一致。后者可以被称为 $FrontEnd3,这是非常恼人的。 但令人高兴的是,这是可以避免的 通过设置 ABC0全球 $FrontEnd选项为“工作”:

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”上有锯齿,而第二个没有(使用 Mathematica6进行测试)。

Chris Degnen提出了另一种通过 ImageResolution的方法(这种方法至少从 Mathematica8开始有效) :

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

3)在 Mathematica中,我们有三种方法将图形转换成图元文件: 通过 Export"EMF"(强烈推荐的方法: 生成尽可能高质量的图元文件) ,通过 Save selection As...菜单项(产生的精确数字要小得多,不推荐)和通过 Edit ► Copy As ► Metafile菜单项(我强烈建议不要走这条路)。

缓存表达式

我发现这些函数对缓存任何表达式都非常有用。这两个函数的有趣之处在于,持有的表达式本身被用作哈希表/符号缓存或缓存索引的键,相比之下,著名的数学制表法只能在函数定义为 f [ 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 结构之外)请参阅本文后面的 避免重复调用插值

删除缓存值

在不知道函数的定义数时删除缓存值。我认为定义在它们的论点中某处是空白的。

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

在知道函数的定义数量时删除缓存的值(速度稍微快一些)。

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

这使用了这样一个事实,即函数的定义位于 DownValue 列表的末尾,而缓存的值位于。

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

这里还有一些有趣的函数来使用象对象这样的符号。

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

mysymbol["property"]=2;

你可以使用这些函数来访问符号的键(或属性)列表,这些函数基于 treeves 在本网站上发表的文章:

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

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

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

Finally here is a simple way to create a symbol that behaves like an object in object oriented programming (it just reproduces the most basic behaviour of OOP but I find the syntax elegant) :

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
];

属性在返回的 Module 创建的符号中作为 DownValue 存储,而方法作为延迟 Upvalue 存储。我找到了 function 2的语法,它是 Mathematica 的树木资料结构中函数的通常 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]

如果您想使用这里提供的一个名为 Heritage itRules 的包来模拟对象继承,则可以进一步深入 Http://library.wolfram.com/infocenter/mathsource/671/

您还可以将函数定义不存储在 newObject 中,而是存储在类型符号中,因此如果 NewObject 返回的是 type [ newObject ]而不是 newObject,那么您可以像下面这样定义 function 和 function 2 在 NewObject 之外(而不是在其中) ,并且具有与之前相同的用法。

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

使用 UpValue [ type ]查看在类型符号中定义的函数和 function 2。

这里将进一步介绍关于最后一种语法的想法 https://mathematica.stackexchange.com/a/999/66

选择等价物的改进版本

@ rcolyer: 非常感谢将 SelectEquvalents 带到表面,这是一个令人惊奇的功能。 下面是上面列出的 SelectEquvalents 的改进版本,它具有更多的可能性和使用选项,这使它更容易使用。

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 快速二维分组算法

内袋

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

在 Mathematica 实现四叉树

调试功能

这两篇文章指出了用于调试的有用函数:

如何在使用 Mathematica、 workbench、 mma 调试器或其他工具编写小代码或大代码时进行调试? (ShowIt)

Https://stackoverflow.com/questions/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

PutAppend with 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不再影响 OpenWriteOpenAppend的行为。

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

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

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

我相信很多人都遇到过这样的情况: 他们运行某些程序,意识到它不仅困住了程序,而且还困住了 已经十分钟没存钱了!

剪辑

经过一段时间的这种痛苦,我有一天发现,可以创建自动保存从内部的 Mathematica代码。我认为使用这样的自动保存在过去帮助了我很多,我总是觉得 可能性本身是没有很多人意识到他们可以做的事情。

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

这方面的代码可以在 Sjoerd C. de Vries这个答案中找到 (因为我不确定是否可以把它复制到这里,所以我只把它作为一个链接留在这里。)


下面的解决方案是使用 Dynamic。这将节省笔记本每60秒,但显然 除非它的细胞是可见的。我把它留在这里只是为了完成任务。(适用于 Mathematica6及7的使用者)

编辑

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

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

这将每60秒节省您的工作。
NotebookAutoSave[]相比,我更喜欢它,因为它在处理输入之前保存,而且因为有些文件比输入更多的是文本。

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

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

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

这篇文章是由 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]巧妙地删除了报价。

函数 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

我发现在开发将这个快捷键添加到我的 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笔记本,测试笔记本的前2个单元格被设置为初始化单元格。在我放进去的第一个牢房里

Needs["PackageManipulations`"]

加载由 Leonid 编写的非常有用的 包装操作

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

所有这些都做实际的包重新加载。注意前两行只有 Remove的所有符号,因为我希望保持上下文尽可能干净。

然后用于编写和测试包的工作流就变成了这样的东西。

  1. 保存对 Packagename.m的更改。
  2. 转到 PackagenameTest.nb然后做 CTRL + ALT + i

这会导致初始化单元格重新加载包,这使得测试非常简单。

不预先设置上下文的打印系统符号定义

下面的 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]]

与规则[]

注意: 这个函数不像 WithModule那样对变量进行本地化,这意味着嵌套的本地化构造不会像预期的那样工作。withRules[{a -> 1, b -> 2}, With[{a=3}, b_ :> b]] 威尔在嵌套的 WithRule中取代 ab,而 With不这样做。

这是 With的一个变体,它使用规则而不是 =:=:

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 graphicsMathematica graphics

注意,对于 n或大图像大小的大值倾向于暴露图形驱动程序错误或引入人工制品。


笔记本的不同功能

笔记本 diff 功能在 <<AuthorTools`包中可用,并且(至少在版本8中)在未记录的 NotebookTools`上下文中可用。这是一个小图形用户界面,区别于目前打开的两款笔记本电脑:

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 graphics

此代码生成一个调色板,该调色板将所选内容作为图像上传到 StackExchange。在 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[];