Redefine Noncommutative Multiplication in Mathemat

2019-04-27 04:28发布

问题:

Mathematicas NonCommutativeMultiply (**) does not simplify terms like

a**0=0**a=0  
a**1=1**a=a  

or

a**a=a^2.  

I would like to redefine ** to do this. I was using NCAlgebra to do this but I need ReplaceRepeated (//.) and NCAlgebra, as their documentation says, specifically breaks this functionality in mathematica.

Can some show me how to Clear the attributes of ** and redefine this multiplication do the same things it would normal do plus dealing with 1 and 0. I really do not need the multiplication to deal with a**a, but It would be nice if it is simple enough. The main thing I need ** to deal with 1 and 0.

回答1:

The below only works if you remove the Flat attribute of NonCommutativeMultiply (Which is something I did by mistake during testing... a rookie mistake!)

The simplest thing to do is

Unprotect[NonCommutativeMultiply];
NonCommutativeMultiply[a___, 1, b___] := a ** b
NonCommutativeMultiply[___, 0, ___] := 0
NonCommutativeMultiply[a_] := a
Protect[NonCommutativeMultiply];

The final expression is needed so that a**1 simplifies to a instead of NonCommutativeMultiply[a]. You might also need NonCommutativeMultiply[]:=1 so that expressions like 1**1 simplify properly (*). The only problem with all of this, is for large expressions, the pattern is checked against everything and this gets really slow.

The above two definitions for 0 and 1 can be combined and generalized to

NonCommutativeMultiply[a___, n_?NumericQ, b___] := n a ** b

which factors out any numerical terms inside the expression. But this slows down things even more in large expressions, since each term is checked to see if its numerical.

To simplify your a**a to a^2, you need something like

NonCommutativeMultiply[a___, b_, b_, c___] := a ** b^2 ** c

or more generally

NonCommutativeMultiply[a___, b_^n_., b_^m_., c___] := a ** b^(n + m) ** c

(*) Note that this is only because the default order that Mathematica puts its DownValues in is not necessarily the best in this case. Change the order so that NonCommutativeMultiply[a_] comes before a___ ** n_?NumericQ ** b___ then NonCommutativeMultiply[] won't be generated by the rules, and you won't need that last pattern (unless you produce NonCommutativeMultiply[] some other way).



回答2:

OK, writing rules that play nice with the attributes of NonCommutativeMultiply is sometimes a hassle. Here's an alternate method which introduces a helper NCM that does not have the rules and attributes of NonCommutativeMultiply associated with it.

The following code also incorporates the last couple of your questions. (1) (2)

Unprotect[NonCommutativeMultiply];
Clear[NonCommutativeMultiply]
(* Factor out numerics -- could generalize to some ScalarQ *)
nc:NonCommutativeMultiply[a__]/;MemberQ[{a},_?NumericQ]:=NCMFactorNumericQ[NCM[a]]/.NCM->NonCommutativeMultiply
(* Simplify Powers *)
b___**a_^n_.**a_^m_.**c___:=NCM[b,a^(n+m),c]/.NCM->NonCommutativeMultiply
(* Expand Brackets *)
nc:NonCommutativeMultiply[a___,b_Plus,c___]:=Distribute[NCM[a,b,c]]/.NCM->NonCommutativeMultiply
(* Sort Subscripts *)
c___**Subscript[a_, i_]**Subscript[b_, j_]**d___/;i>j:=c**Subscript[b, j]**Subscript[a, i]**d
Protect[NonCommutativeMultiply];

Unprotect[NCM];
Clear[NCM]
NCMFactorNumericQ[nc_NCM]:=With[{pos=Position[nc,_?NumericQ,1]},Times@@Extract[nc,pos]  Delete[nc,pos]]
NCM[a_]:=a
NCM[]:=1
Protect[NCM];

Note that NCMFactorNumericQ is fast because it works in a single pass, but the rule associated with it nc:NonCommutativeMultiply[a__]/;MemberQ[{a},_?NumericQ] is slow, because the Flat attribute means that it does a stupid number of checks using NumericQ. If you really want more speed and have large expressions, then you should just manually apply the Sort and Factor routines, so that Mathematica does less pattern checks.



回答3:

The trick with

Unprotect[NonCommutativeMultiply];
....
Protect[NonCommutativeMultiply];

is very good! I spent 10 hours trying to solve a problem with NonCommutativeMultiply (how to flatten expressions that involved both n.c. and normal multiplication like a**b**(c*d*(e**f)) but more complicated) but I didn't think of amending NonCommutativeMultiply itself. Thanks!