Mathematica:覆盖`Plus`的`Listable`属性

时间:2011-01-06 05:53:39

标签: wolfram-mathematica

我想定义一个符号pt来保持一个点(并最终缓存一些与该点相关的数据):

pt::"usage" = "pt[{x,y}] represents a point at {x,y}";

我希望能够以尽可能多的方式使用这些pt个对象,特别是,我希望能够写出

{a0,a1}+pt[{b0,b1}]

并让它返回pt[{a0+b0,a1+b1}]而不是{a0+pt[{b0,b1}],a1+pt[{b0,b1}]}。 我最初的想法是使用:

pt /: Plus[pt[p0_], p1 : {_, _}] = pt[p0 + p1];

但这不起作用(因为PlusListable?)。有没有办法在不取消保护Plus

的情况下执行此操作

更新 正如Leonid所指出的,如果没有全局或本地黑客Plus,这是不可能的,因为Listable属性在任何*值之前被考虑。这实际上在evaluation tutorial中非常精确地描述。

2 个答案:

答案 0 :(得分:6)

Mathematica的评估员似乎不够灵活,不能轻易做到这一点。用于pt的UpValues确实在DownValues for Plus之前应用,但是由于可列表性而导致列表上的线程甚至在此之前发生。在这种特殊情况下,以下内容可能对您有用:

eval = Function[code,Block[{Plus = Plus, attr = DeleteCases[Attributes[Plus], Listable]},
SetAttributes[Plus, attr]; code], HoldAll]

要使用它,请将其包裹在您希望应用pt规则的代码段中,例如:

eval[{a0, a1} + pt[{b0, b1}]]

你可以使用$ Pre作为$Pre = eval来避免每次输入eval,尽管通常我不推荐这样做。 Blocking Plus是一种暂时禁用其部分或全部属性的更软方式。优点w.r.t.清除和设置不带阻塞的属性是指即使抛出异常或计算中止,也无法最终处于永久禁用Listable属性的全局状态。

由于Listable属性直接影响评估而不是模式匹配(后者当然可能间接影响,如果某些模式必须匹配Plus线程列表的结果),在大多数情况下这应该是正常的。理论上,在某些情况下,它可能仍然会导致一些不必要的影响,特别是在涉及模式匹配的情况下。但在实践中,它可能已经足够好了。更简洁但更复杂的解决方案是根据您的需求创建定制评估器。

答案 1 :(得分:1)

以下内容有点浪费,但确实有效:我们的目的只是观察Listable Plus属性将pt放入所有元素的情况。列表(即原始点) - 然后将其拉出。首先,定义一个添加pt对象的函数:

SetAttributes[ptPlus, {Orderless}]
ptPlus[pt[pa : {_, _}], pt[pb : {_, _}], r___] := 
  ptPlus[pt[pa + pb], r];
ptPlus[p_pt] := p; 

然后我们确保涉及Plus的任何pt都映射到ptPlus(与pt关联的规则)。

Plus[h___, a_pt, t___] ^:= ptPlus[h, a, t];

以上规则意味着:{x0,y0}+pt[{x1,y1}]将从{x0+pt[{x1,y1}],y0+pt[{x1,y1}]}扩展为{ptPlus[x0,pt[{x1,y1}]],ptPlus[y0,pt[{x1,y1}]]}。现在我们只是制定一个规则将其转换为pt[{x0,y0}]+pt[{x1,y1}](注意检查pt s相等的延迟条件):

{ptPlus[x__], ptPlus[y__]} ^:= Module[{
    ptCases = Cases[{{x}, {y}}, _pt, {2}]},
  ptCases[[1]] + pt[Plus @@@ DeleteCases[{{x}, {y}}, _pt, {2}]] 
    /; Equal @@ ptCases]

更不透明但更谨慎的版本,更容易推广到更高的尺寸:

ptPlus /: p : {_ptPlus, _ptPlus} := Module[{ptCases, rest,
   lp = ReleaseHold@Apply[List, Hold[p], {2}]},
  ptCases = Cases[lp, _pt, {2}];
  rest = Plus @@@ DeleteCases[lp, _pt, {2}];
  ptCases[[1]] + pt[rest] /; And[Equal @@ ptCases, VectorQ@rest]]

{a+pt[{0,0}],a+pt[{0,b}]} /. {a -> pt[{0,0}]}评估为pt[{0,0}] c==0{pt[{0,0}],pt[{0,c}]}时,这整个方法当然会导致可怕的微妙错误。

HTH - 对那个人说自己......