# Define commutator of operators, to do computations

I'm actually new to Mathematica I have been using sympy and sometimes cadabra to do calculations for a while though, I was wondering if there is an easy way to compute arbitrary expressions simplified by commutators, by defining commutations

For example, let's say I have

And I wanted to get

How would I get a simplified answer using the fact that

Here's how it would be done in Cadabra for reference https://stackoverflow.com/questions/62254012/sympy-how-to-get-simplified-commutators-using-the-second-quantization-module

Can this be done simply in Mathematica? Sorry if it's a silly question could not find any info about it

• Maybe you need SNEG. Nov 25 '20 at 16:39
• Might want to check this MathOverflow thread. And there should be a few also on MSE that are relevant. Nov 25 '20 at 17:26

As already discussed in the comments under OPs question: computations of this kind can be facilitated by some packages. Regarding the specific problem posed by OP a minimal semi-automatic solution would be

(* Check if a symbol is non-commutative under NCM: defaults False *)
ClearAll[NCQ]
NCQ[a__]:=NCQ@List[a];
NCQ[a_List]:=NCQ[#]&/@a
NCQ[Subscript[a_,i_]]:=NCQ[a]
NCQ[a_]:=False;

(* Non-commutative multiply *)
ClearAll[NCM];
NCM[]:=1;
NCM[a_]:=a
NCM[x___,NCM[y1_,y2__],z___]:=NCM[x,y1,y2,z]
NCM[x___,f_[y1_,y2___],z___]/;MemberQ[{Plus,List,Equal,Rule,RuleDelayed},f]:=f@@Map[NCM[x,#,z]&,{y1,y2}]
NCM[x___,Times[y1_,y2__],z___]:=NCM[x,y1,y2,z]
NCM[x__/;MemberQ[NCQ[x],False](*contains commuting factors*)]:=Module[{s,nc},
s=1;
nc=If[NCQ[#],#,s=Times[s,#];Nothing]&/@{x};
Return[Times[s,NCM@@nc]]
]
NCM/:MakeBoxes[NCM[a_,b__],StandardForm]/;BoxFormUseIcons:=ToBoxes@Row[{a,b},"**"]

(* Dagger symbol *)
ClearAll[dagger];
dagger/:MakeBoxes[dagger[a_],StandardForm]/;BoxFormUseIcons:=ToBoxes@Superscript[a,"\[Dagger]"]
dagger/:NCQ[dagger[a_]]:=NCQ[a]

(* Commutator symbol *)
ClearAll[NCC];
NCQ[NCC[a_,b_]]:=True;
NCC[a_,a_]:=0
NCC/:MakeBoxes[NCC[a_,b_],StandardForm]/;BoxFormUseIcons:=ToBoxes@Row[{"[",a,",",b,"]"}]


followed by the explicit computation based by "normal" ordering non-commutative products (the method order) of as assuming $$\omega_1$$, $$\omega_2$$, $$g$$ and $$\bar{g}$$ are commutative constants:

(* Establish a as a non-commuting symbol in NCM *)
NCQ[a]=True;

(* Setup normal-ordered commutators *)
NCC[Subscript[a, k_],dagger[Subscript[a, l_]]]:=KroneckerDelta[k,l]
NCC[dagger[Subscript[a, l_]],Subscript[a, k_]]:=-NCC[Subscript[a, k],dagger[Subscript[a, l]]]
NCC[Subscript[a, k_],Subscript[a, l_]]:=-NCC[Subscript[a, l],Subscript[a, k]]/;(!OrderedQ[{k,l}])
NCC[dagger[Subscript[a, k_]],dagger[Subscript[a, l_]]]:=-NCC[dagger[Subscript[a, l]],dagger[Subscript[a, k]]]/;(!OrderedQ[{k,l}])

(* Implement a "normal order" for products of a_i and dagger[a_i]*)
ClearAll[order];
order[exp_]:=Fold[ReplaceRepeated,exp,{
HoldPattern[NCM[x___,dagger[Subscript[a, k_]],Subscript[a, l_],y___]]:>NCM[x,Subscript[a, l],dagger[Subscript[a, k]],y]+NCM[x,NCC[dagger[Subscript[a, k]],Subscript[a, l]],y],
HoldPattern[NCM[x___,Subscript[a, k_],Subscript[a, l_],y___]]:>NCM[x,Subscript[a, l],Subscript[a, k],y]+NCM[x,NCC[Subscript[a, k],Subscript[a, l]],y]/;(!OrderedQ[{k,l}]),
HoldPattern[NCM[x___,dagger[Subscript[a, k_]],dagger[Subscript[a, l_]],y___]]:>NCM[x,dagger[Subscript[a, l]],dagger[Subscript[a, k]],y]+NCM[x,NCC[dagger[Subscript[a, k]],dagger[Subscript[a, l]]],y]/;(!OrderedQ[{k,l}])
}];

(** Computation **)
Subscript[\[Omega],1]* NCM[Subscript[a,1],dagger[Subscript[a,1]]]+Subscript[\[Omega],2]*NCM[Subscript[a,2],dagger[Subscript[a,2]]]+g*NCM[dagger[Subscript[a,1]],Subscript[a,2]]+gb*NCM[dagger[Subscript[a,1]],Subscript[a,2]]
NCM[%,Subscript[a, 1]]-NCM[Subscript[a, 1],%]
%//order//Expand//Simplify
%/.HoldPattern[NCC[Subscript[a, k_],Subscript[a, l_]]]:>0


which I simplified further in the last step assuming $$[a_i,a_j]=0$$, which if I recall Second quantization correctly should be the case. I have neither checked the code thoroughly nor did I do the computation by hand carefully, so I can not really guarantee it to be correct but it seems plausible to me apart from the strange definition of the last two terms in $$H$$ (I would have expected by looking at for something like $$a_2^\dagger a_1$$ in the last term instead of being identical to the second to last apart from the prefactor).

This code works by first implementing the rudimentary method NCM for non-commutative products with the auxiliary function NCQ checking symbols for potentially non-commutative character. dagger and NCC are symbols for Hermitian conjugate (just a wrapper here) and symbolic commutators respectively. To perform the actual computation $$[H,a_1]$$ I implemented the explicit commutators for $$a_i$$ and $$a_i^\dagger$$ and established a "normal ordering" with the rules in order. order commutes all daggers to the right and then orders all daggered and non-daggered appearances of $$a$$ according to Mathematicas canonical ordering.

This code is meant to given an impression on how one could implement such computations in an in principle straight-forward manner: which means that the code is probably terribly inefficient BUT most likely faster than a human. Implementing $$[a_i,a_j]=0$$ together with the other commutators would reduce the intermediate terms significantly.

• This is pretty much was I was looking for , It is quite the work to have this simple calculations in mathematica, I'll give it a try but most likely I'll end up still using cadabra, Thanks for the answer it was pretty detailed and understandable Nov 26 '20 at 4:26
• @GerardoSuarez The problem is that Mathematica has (at least to my knowledge) no inbuilt functionalities for symbolic computations involving non-commutative products. Implementing such methods is quite tricky if one wants a flexible solution on the one hand and a potent one on the other. I had most of the code for this answer NCM and NCQ` lying around since I have been working on large symbolic expressions involving non-commutative products.
– N0va
Nov 26 '20 at 5:10
• Yes, I get it, in this case I think the open source route seems way more user friendly to me, It will probably be a pain to implement things like partial traces in mathematica, but I will have to take a look and try for myself Nov 26 '20 at 5:20