Times和NonCommutativeMultiply,自动处理差异

时间:2011-12-03 09:35:53

标签: wolfram-mathematica mathematica-frontend

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

我已经考虑过使用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 个答案:

答案 0 :(得分:4)

这不是对你的问题的最直接的答案,但是对于许多目的而言,与盒子一起作为低级别工作可能是一种过度杀伤力。这是另一种选择:让Mathematica解析器解析您的代码,然后进行更改。这是一种可能性:

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

这会动态替换Times NonCommutativeMultiply,并避免您提到的错综复杂。使用Internal`InheritedBlock,我对Times内执行的代码的本地withNoncommutativeMultiply进行了修改。

您现在可以使用$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,而{{1}}在专门化/添加特殊情况的能力方面相当有限。

答案 1 :(得分:1)

如果我理解正确,你想输入 a b和a * b 让MMA自动了解Times是一个非交换运算符(它有自己的 - 单独的 - 换向规则)。 好吧,我的建议是你使用Notation包。 它非常强大且(相对)易于使用(特别是对于像您这样的复杂用户而言)。 它可以以编程方式使用,它可以重新解释像Times这样的预定义符号。 基本上它可以拦截时间并将其更改为MyTimes。然后,您为MyTimes编写代码,例如决定哪些符号不通勤,然后输出可以再次格式化为时间或其他任何您想要的。 输入和输出处理是2行代码。而已! 你必须仔细阅读文档并做一些实验,如果你想要的不是或多或少“输入 - 输出工作的标准黑客”。 你的情况在我看来非常标准(再次:如果我很清楚你想要实现的目标),你应该会发现阅读Notation包的“高级”页面很有用。 为了让你了解这个包是多么强大和灵活,我用它来编写一个相当大的类别理论包的输入输出格式,其中非交换操作比比皆是。可是等等!我不只是定义一个非交换操作,我定义了无限数量的非交换操作。 我做的另一件事是当参数是类别时重新解释Power,而不会使Power过载。这允许我使用标准数学符号来处理函数类别。 现在,我的“无限”操作和“超级大国”具有与标准MMA符号相同的外观和感觉,包括复制粘贴功能。

答案 2 :(得分: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]]

答案 3 :(得分:0)

这个答案并不能解决您的问题,而是导致您提出问题的问题。 Mathematica在处理非通勤对象时毫无用处,但由于这些对象比比皆是,例如粒子物理学,因此有一些有用的包来处理这种情况。

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