Times and NonCommutativeMultiply, automatically passing the difference

I have some characters that should be non-commutative, but I do not want to remember which expressions have this behavior when constructing equations.

I had to use MakeExpression to work with raw boxes and automatically increase multiplication by non-commutative multiplication when necessary (for example, when some of the characters are non-commutative objects).

I was wondering if anyone had any experience with this configuration.

Here is what I have 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[ab] F[a*b] F[a - b] F[3 x] F[x^2] F[ef*g ** h*ij] Clear[MakeExpression] 

This seems to correctly identify expressions that are multiplication operators:

 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 seems that this is not one of the questions that I could conditionally rewrite the boxes of the main expression; but how to do it reliably?

Take the expression RowBox[{"e","f","*",RowBox[{"g","**","h"}],"*","i","j"}] , this will need to be rewritten as RowBox[{"e","**","f","**",RowBox[{"g","**","h"}],"**","i","**","j"}] , which seems to be a non-zero operation associated with pattern matching and a set of rules.

I would be grateful for any suggestions from more experienced with me.

I am trying to find a way to do this without changing the default behavior and multiplication order.

Thanks!:)

Joe

+4
source share
4 answers

This is not the most direct answer to your question, but for many purposes working both low-level and directly with boxes, it may be redundant. Here's an alternative: let the Mathematica parser parse your code and modify it. Here is the opportunity:

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

This dynamically replaces Times with NonCommutativeMultiply and avoids the subtleties described. Using Internal`InheritedBlock , I make changes to the Times local code that runs inside withNoncommutativeMultiply .

Now you can automate the use of this function with $Pre :

 $Pre = withNoncommutativeMultiply; 

Now for example:

 In[36]:= F[a] F[ab] F[a*b] F[ab] F[3 x] F[x^2] F[ef*g**h*ij] 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] 

Of course, using $Pre this way is hardly suitable, since noncommutative multiplication will be replaced in all your code multiplication - I used this as an illustration. You can do a more complicated redefinition of Times , so this will only work for certain characters.

The following is a safer alternative based on lexical rather than dynamic reach:

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

you can use this in the same way, but only instances of Times that are explicitly present in the code will be replaced. Again, this is just an illustration of the principles, it can be expanded or specialized as necessary. Instead of With , which is quite limited in its ability to specialize / add special cases, you can use replacement rules that have similar semantics.

+4
source

If I understand correctly, you want to enter ab and a * b and MMA automatically understand that Times is a truly non-commutative operator (which has its own - separate switching rules). Well, my suggestion is that you are using the Notation package. It is very powerful and (relatively) easy to use (especially for the sophisticated user, as you seem to be). It can be used programmatically and it can reinterpret predefined characters such as Times. Basically, it can intercept Times and change it to MyTimes. Then you write code for MyTimes that determines, for example, which characters do not commute, and then the output can be formatted again just like that or whatever. Input and output processing - 2 lines of code. This is it! You should carefully read the documentation and do some experimentation if you want no more or less "standard hacking" of I / O jobs. Your case seems pretty standard to me (again: if I understand well what you want to achieve), and you should find it useful to read the "advanced" pages of the Notation package. To give you an idea of ​​how powerful and flexible a package is, I use it to record the I / O formatting of a significant Category Theory package, where non-commutative operations abound. But wait! I do not just define ONE non-commutative operation, I define an unlimited number of non-commutative operations. Another thing I did was rethink Power when arguments are categories, without overloading Power. This allows me to relate to functorial categories using standard mathematical notation. Now my “endless” operations and “Super Power” have the same appearance as standard MMA characters, including copy-paste functionality.

+1
source

Thus, this does not directly answer the question, but it provides the kind of implementation I was thinking about.

So, after doing a little research and accepting some of @LeonidShifrin's suggestions, I managed to implement most of what I was thinking. The idea is that you can define patterns that should be considered non-commuting values ​​using commutingQ[form] := False . Then any multiplicative expression (practically any expression) can be wrapped with withCommutativeSensitivity[expr] , and the expression will be processed to divide the values ​​into Times[] and NonCommutativeMultiply[] subexpressions, if necessary,

 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, you can use $Pre = withCommutativeSensitivity to make this behavior the default (come to Wolfram! Make it the default already;)). However, it would be nice to have this more fundamental behavior. I really would like to create a module and Needs[NonCommutativeQuantities] at the beginning of any notebook that he needs and not have all the features that $ Pre break uses for me (doesn't track its usage?).

Intuitively, I feel that there should be a natural way to attach this functionality to Mathematica at the level of syntax analysis and connect it using MakeExpression[] . Can i move here? I would appreciate any thoughts on whether I am pursuing a dead end. (I had several experiments in this direction, but I always fall into the recursive definition that I can’t figure out how to break it).

Any thoughts will be gladly accepted, 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]] 
+1
source

This answer does not affect your question, but rather a problem that forces you to ask this question. Mathematica is pretty useless when working with non-commuting objects, but since such objects abound, for example, in particle physics, there are several useful packages to solve this problem.

Check out the grassmanOps package . They have a way to define characters as commuting or anti-commuting and overload the standard NonCommutativeMultiply for processing, i.e. Transmit commuting characters. They also define several other operators, such as Derivative, to handle anti-commutation characters. It probably adapts easily to use arbitrary switching rules, and it should at least give you an indication of what needs to be changed if you want to collapse your own.

0
source

Source: https://habr.com/ru/post/1384455/


All Articles