Times 和 NonCommutativeMultiply,自动处理差值

发布于 2024-12-19 03:19:13 字数 1829 浏览 1 评论 0原文

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

我曾想过使用 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"}] 这对于模式匹配器和规则集来说似乎是一个不平凡的操作。

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

我试图找到一种方法来做到这一点而不改变默认行为和乘法顺序。

谢谢! :)

I've got some symbols which should are non-commutative, but I don't want to have to remember which expressions have this behaviour whilst constructing equations.

I've had the thought to use MakeExpression to act on the raw boxes, and automatically uplift multiply to non-commutative multiply when appropriate (for instance when some of the symbols are non-commutative objects).

I was wondering whether anyone had any experience with this kind of configuration.

Here's what I've got so far:

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

This appears to correctly identify expressions that are multiplication statements:

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

So, it looks like it's not out of the questions that I might be able to conditionally rewrite the boxes of the underlying expression; but how to do this reliably?

Take the expression RowBox[{"e","f","*",RowBox[{"g","**","h"}],"*","i","j"}], this would need to be rewritten as RowBox[{"e","**","f","**",RowBox[{"g","**","h"}],"**","i","**","j"}] which seems like a non trivial operation to do with the pattern matcher and a rule set.

I'd be grateful for any suggestions from those more experienced with me.

I'm trying to find a way of doing this without altering the default behaviour and ordering of multiply.

Thanks! :)

Joe

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

谁的新欢旧爱 2024-12-26 03:19:13

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

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

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

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

This is not a most direct answer to your question, but for many purposes working as low-level as directly with the boxes might be an overkill. Here is an alternative: let the Mathematica parser parse your code, and make a change then. Here is a possibility:

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

This replaces Times dynamically with NonCommutativeMultiply, and avoids the intricacies you mentioned. By using Internal`InheritedBlock, I make modifications to Times local to the code executed inside withNoncommutativeMultiply.

You now can automate the application of this function with $Pre:

$Pre  = withNoncommutativeMultiply;

Now, for example:

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]

Surely, using $Pre in such manner is hardly appropriate, since in all your code multiplication will be replaced with noncommutative multiplication - I used this as an illustration. You could make a more complicated redefinition of Times, so that this would only work for certain symbols.

Here is a safer alternative based on lexical, rather than dynamic, scoping:

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

you can use this in the same way, but only those instances of Times which are explicitly present in the code would be replaced. Again, this is just an illustration of the principles, one can extend or specialize this as needed. Instead of With, which is rather limited in its ability to specialize / add special cases, one can use replacement rules which have similar semantics.

巷子口的你 2024-12-26 03:19:13

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

If I understand correctly, you want to input
a b and a*b
and have MMA understand automatically that Times is really a non commutative operator (which has its own -separate - commutation rules).
Well, my suggestion is that you use the Notation package.
It is very powerful and (relatively) easy to use (especially for a sophisticated user like you seem to be).
It can be used programmatically and it can reinterpret predefined symbols like Times.
Basically it can intercept Times and change it to MyTimes. You then write code for MyTimes deciding for example which symbols are non commuting and then the output can be pretty formatted again as times or whatever else you wish.
The input and output processing are 2 lines of code. That’s it!
You have to read the documentation carefully and do some experimentation, if what you want is not more or less “standard hacking” of the input-output jobs.
Your case seems to me pretty much standard (again: If I understood well what you want to achieve) and you should find useful to read the “advanced” pages of the Notation package.
To give you an idea of how powerful and flexible the package is, I am using it to write the input-output formatting of a sizable package of Category Theory where noncommutative operations abound. But wait! I am not just defining ONE noncommutative operation, I am defining an unlimited number of noncommutative operations.
Another thing I did was to reinterpret Power when the arguments are categories, without overloading Power. This allows me to treat functorial categories using standard mathematics notation.
Now my “infinite” operations and "super Power" have the same look and feel of standard MMA symbols, including copy-paste functionality.

会傲 2024-12-26 03:19:13

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

因此,经过一些调查并采纳@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 的设施都在我身上(不追踪使用它吗?)。

凭直觉,我觉得必须有一种自然的方法可以在框解析级别将此功能挂接到 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]]

So, this doesn't directly answer the question, but it's does provide the sort of implementation that I was thinking about.

So, after a bit of investigation and taking on board some of @LeonidShifrin's suggestions, I've managed to implement most of what I was thinking of. The idea is that it's possible to define patterns that should be considered to be non-commuting quantities, using commutingQ[form] := False. Then any multiplicative expression (actually any expression) can be wrapped with withCommutativeSensitivity[expr] and the expression will be manipulated to separate the quantities into Times[] and NonCommutativeMultiply[] sub-expressions as appropriate,

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

Of course it's possible to use $Pre = withCommutativeSensitivity to have this behaviour become default (come on Wolfram! Make it default already ;) ). It would, however, be nice to have it a more fundamental behaviour though. I'd really like to make a module and Needs[NonCommutativeQuantities] at the beginning of any note book that is needs it, and not have all the facilities that use $Pre break on me (doesn't tracing use it?).

Intuitively I feel that there must be a natural way to hook this functionality into Mathematica on at the level of box parsing and wire it up using MakeExpression[]. Am I over extending here? I'd appreciate any thoughts as to whether I'm chasing up a blind alley. (I've had a few experiments in this direction, but always get caught in a recursive definition that I can't work out how to break).

Any thoughts would be gladly received,
Joe.

Code

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]]
锦欢 2024-12-26 03:19:13

这个答案并没有解决您的问题,而是解决了导致您提出该问题的问题。 Mathematica 在处理非通勤对象时非常无用,但由于此类对象在粒子物理学等领域大量存在,因此有一些有用的包来处理这种情况。

查看 grassmanOps 包。他们有一种方法将符号定义为通勤或反通勤,并重载标准 NonCommutativeMultiply 来处理(即通过)通勤符号。他们还定义了其他几个运算符(例如导数)来处理反交换符号。它可能很容易适应任意的换向规则,并且它至少应该让您了解如果您想推出自己的规则,则需要更改哪些内容。

This answer does not address your question but rather the problem that leads you to ask that question. Mathematica is pretty useless when dealing with non-commuting objects but since such objects abound in, e.g., particle physics, there are some usefull packages around to deal with the situation.

Look at the grassmanOps package. They have a method to define symbols as either commuting or anti-commuting and overload the standard NonCommutativeMultiply to handle, i.e. pass through, commuting symbols. They also define several other operators, such as Derivative, to handle anti-commuting symbols. It is probably easily adapted to cover arbitrary commutation rules and it should at the very least give you an insigt into what things need to be changed if you want to roll your own.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文