4

我有一些应该是不可交换的符号,但我不想在构造方程时记住哪些表达式具有这种行为。

我曾想过使用 MakeExpression 作用于原始框,并在适​​当的时候自动将乘法提升为非交换乘法(例如,当某些符号是非交换对象时)。

我想知道是否有人对这种配置有任何经验。

这是我到目前为止所得到的:

(* Detect whether a set of row boxes represents a multiplication *)

Clear[isRowBoxMultiply];
isRowBoxMultiply[x_RowBox] := (Print["rowbox: ", x]; 
  Head[ToExpression[x]] === Times)
isRowBoxMultiply[x___] := (Print["non-rowbox: ", x]; False)

(* Hook into the expression maker, so that we can capture any \
expression of the form F[x___], to see how it is composed of boxes, \
and return true or false on that basis *)

MakeExpression[
  RowBox[List["F", "[", x___, "]"]], _] := (HoldComplete[
   isRowBoxMultiply[x]])

(* Test a number of expressions to see whether they are automatically \
detected as multiplies or not. *)
F[a]
F[a b]
F[a*b]
F[a - b]
F[3 x]
F[x^2]
F[e f*g ** h*i j]

Clear[MakeExpression]

这似乎可以正确识别作为乘法语句的表达式:

During evaluation of In[561]:= non-rowbox: a
Out[565]= False

During evaluation of In[561]:= rowbox: RowBox[{a,b}]
Out[566]= True

During evaluation of In[561]:= rowbox: RowBox[{a,*,b}]
Out[567]= True

During evaluation of In[561]:= rowbox: RowBox[{a,-,b}]
Out[568]= False

During evaluation of In[561]:= rowbox: RowBox[{3,x}]
Out[569]= True

During evaluation of In[561]:= non-rowbox: SuperscriptBox[x,2]
Out[570]= False

During evaluation of In[561]:= rowbox: RowBox[{e,f,*,RowBox[{g,**,h}],*,i,j}]
Out[571]= True

因此,看起来我可能能够有条件地重写底层表达式的框,这并不是没有问题的;但如何可靠地做到这一点?

以表达式为例RowBox[{"e","f","*",RowBox[{"g","**","h"}],"*","i","j"}],这将需要重写,因为RowBox[{"e","**","f","**",RowBox[{"g","**","h"}],"**","i","**","j"}]这似乎是与模式匹配器和规则集有关的非平凡操作。

我将不胜感激那些对我更有经验的人的任何建议。

我试图找到一种在不改变默认行为和乘法顺序的情况下做到这一点的方法。

谢谢!:)

4

4 回答 4

4

这不是对您的问题的最直接答案,但对于许多目的而言,与直接使用盒子一样低级工作可能是一种矫枉过正。这是一种替代方法:让 Mathematica 解析器解析您的代码,然后进行更改。这是一种可能性:

ClearAll[withNoncommutativeMultiply];
SetAttributes[withNoncommutativeMultiply, HoldAll];
withNoncommutativeMultiply[code_] :=
  Internal`InheritedBlock[{Times},
     Unprotect[Times];
     Times = NonCommutativeMultiply;
     Protect[Times];
     code];

这将Times动态替换为NonCommutativeMultiply,并避免您提到的复杂性。通过使用 ,我对本地执行的代码Internal`InheritedBlock进行了修改。TimeswithNoncommutativeMultiply

您现在可以使用以下命令自动应用此功能$Pre

$Pre  = withNoncommutativeMultiply;

现在,例如:

In[36]:= 
F[a]
F[a b]
F[a*b]
F[a-b]
F[3 x]
F[x^2]
F[e f*g**h*i j]

Out[36]= F[a]
Out[37]= F[a**b]
Out[38]= F[a**b]
Out[39]= F[a+(-1)**b]
Out[40]= F[3**x]
Out[41]= F[x^2]
Out[42]= F[e**f**g**h**i**j]

当然,$Pre以这种方式使用是不合适的,因为在所有代码中,乘法都将被非交换乘法所取代——我用它来举例说明。您可以对 , 进行更复杂的重新定义Times,以便这只适用于某些符号。

这是基于词汇而非动态作用域的更安全的替代方案:

ClearAll[withNoncommutativeMultiplyLex];
SetAttributes[withNoncommutativeMultiplyLex, HoldAll];
withNoncommutativeMultiplyLex[code_] :=
  With @@ Append[
      Hold[{Times = NonCommutativeMultiply}], 
      Unevaluated[code]]

您可以以相同的方式使用它,但只有那些Times显式存在于代码中的实例才会被替换。同样,这只是原理的说明,可以根据需要扩展或专门化它。可以使用具有相似语义的替换规则,而不是With在专门化/添加特殊情况的能力上相当有限。

于 2011-12-03T16:26:52.177 回答
1

如果我理解正确,您想输入 ab 和 a*b 并让 MMA 自动理解 Times 实际上是一个非交换运算符(它有自己的 -separate - 交换规则)。好吧,我的建议是你使用 Notation 包。它非常强大并且(相对)易于使用(尤其是对于像您这样的老练用户)。它可以以编程方式使用,并且可以重新解释预定义的符号,例如 Times。基本上它可以拦截Times并将其更改为MyTimes。然后,您为 MyTimes 编写代码,例如决定哪些符号是非通勤的,然后输出可以重新格式化为时间或您希望的任何其他格式。输入和输出处理是两行代码。而已!您必须仔细阅读文档并进行一些实验,如果您想要的不是或多或少对输入输出作业的“标准黑客”。在我看来,您的案例非常标准(再次:如果我很好地理解您想要实现的目标),您应该会发现阅读 Notation 包的“高级”页面很有用。为了让您了解这个包的强大和灵活程度,我使用它来编写一个相当大的范畴论包的输入输出格式,其中非交换操作比比皆是。可是等等!我不只是定义一个非交换操作,我定义了无限数量的非交换操作。我做的另一件事是在论点是类别时重新解释 Power,而不会重载 Power。这使我可以使用标准数学符号来处理函数类别。现在我的“无限”操作和“超能力”

于 2011-12-04T17:10:02.330 回答
1

所以,这并没有直接回答这个问题,但它确实提供了我正在考虑的那种实现。

因此,经过一番调查并采纳了@LeonidShifrin 的一些建议,我已经设法实现了我的大部分想法。这个想法是可以定义应该被认为是非通勤量的模式,使用commutingQ[form] := False. 然后可以包装任何乘法表达式(实际上是任何表达式),withCommutativeSensitivity[expr]并且表达式将被操作以将数量分成适当Times[]NonCommutativeMultiply[]子表达式,

In[1]:= commutingQ[b] ^:= False;
In[2]:= withCommutativeSensitivity[ a (a + b + 4) b (3 + a) b ]
Out[1]:= a (3 + a) (a + b + 4) ** b ** b

当然,可以使用$Pre = withCommutativeSensitivity让这种行为成为默认行为(来吧 Wolfram!让它成为默认值;))。但是,最好让它具有更基本的行为。我真的很想Needs[NonCommutativeQuantities]在任何需要它的笔记本的开头制作一个模块,并且没有使用 $Pre break 的所有设施(不跟踪使用它吗?)。

直觉上,我觉得必须有一种自然的方式在盒子解析级别将此功能连接到 Mathematica 中,并使用MakeExpression[]. 我在这里扩展了吗?我会很感激任何关于我是否在追逐死胡同的想法。(我在这个方向上进行了一些实验,但总是陷入我无法解决的递归定义中)。

乔,任何想法都会很高兴地接受。

代码

Unprotect[NonCommutativeMultiply];
ClearAll[NonCommutativeMultiply]
NonCommutativeMultiply[a_] := a
Protect[NonCommutativeMultiply];

ClearAll[commutingQ]
commutingQ::usage = "commutingQ[\!\(\*
    StyleBox[\"expr\", \"InlineFormula\",\nFontSlant->\"Italic\"]\)] \
    returns True if expr doesn't contain any constituent parts that fail \
    the commutingQ test. By default all objects return True to \
    commutingQ.";
commutingQ[x_] :=  If[Length[x] == 0, True, And @@ (commutingQ /@ List @@ x)]

ClearAll[times2, withCommutativeSensitivity] 
SetAttributes[times2, {Flat, OneIdentity, HoldAll}]
SetAttributes[withCommutativeSensitivity, HoldAll];

gatherByCriteria[list_List, crit_] := 
 With[{gathered = 
    Gather[{#, crit[#1]} & /@ list, #1[[2]] == #2[[2]] &]},
        (Identity @@ Union[#[[2]]] -> #[[1]] &)[Transpose[#]] & /@ gathered]

times2[x__] := Module[{a, b, y = List[x]}, 
    Times @@ (gatherByCriteria[y, commutingQ] //.
      {True -> Times, False -> NonCommutativeMultiply, 
       HoldPattern[a_ -> b_] :> a @@ b})]

withCommutativeSensitivity[code_] := With @@ Append[
    Hold[{Times = times2, NonCommutativeMultiply = times2}], 
    Unevaluated[code]]
于 2011-12-12T19:09:12.660 回答
0

该答案并未解决您的问题,而是解决了导致您提出该问题的问题。Mathematica 在处理非通勤对象时非常无用,但由于此类对象在粒子物理学中比比皆是,因此有一些有用的软件包可以处理这种情况。

查看grassmanOps包。他们有一种方法可以将符号定义为通勤或反通勤,并重载标准 NonCommutativeMultiply 来处理(即通过)通勤符号。他们还定义了其他几个运算符,例如 Derivative,来处理反通勤符号。它可能很容易适应任意的交换规则,如果你想自己动手,它至少应该让你知道需要改变什么。

于 2011-12-03T20:48:33.307 回答