I'm trying to write a dot product that can handle fermionic variables, i.e., let $a,b$ be fermionic variables, $a\, b=-b\, a$.
There is already a package that can handle fermionic+bosonic variables, grassmann.m, which you can find here
http://people.brandeis.edu/~headrick/Mathematica/grassmann.m
But this package is very slow and for long expressions it stops working (add 12 fermionic variables and it will stop working properly).
What I have written is the following:
ClearAll[dot, fermion, boson, grading]
dot[a___, b_Plus, c___] := dot[a, #, c] & /@ b
dot[a___, b_ d___, c___] := dot[a, b, d, c]
grading[_] := 0;
fermion[a__] := (grading[#] = 1) & /@ {a};
boson[a__] := (grading[#] = 2) & /@ {a};
dot[a___, dot[b___], c___] := dot[a, b, c]
dot[b___, a_, c___, a_, d___] /; OddQ[grading[a]] := 0;
dot[a___, b_ /; grading[b] == 0, c___] := b dot[a, c]
dot[a___, b_, c_, d___] /; (! OrderedQ[{b, c}]) :=
dot[a, c, b, d] (-1)^(grading[b]*grading[c])
Explaining a little bit: I have different gradings: for fermion (1), boson (2) and functions (0). I also want to impose dot to have the attribute Flat, but if I try to add
SetAttributes[dot, Flat]
I end up with an infinite loop when sorting (Question 1: why?, I don't get it. It starts setting the head of any element inside dot a head dot!)
The first two lines are obvious: I want dot to be distributive with respect to Plus, and I found out this to be the simplest way; the second one might be unnecessary, and/or replaced by
dot[a___,b_*c___,d___]/;grading[b]==0:=b dot[a,c,d]
But I haven't tried this option and so far it's working, so I don't dare to change the code! Line 8 plus line 3 do the trick.
Line 7 is a known identity.
Finally, in line 8 I try to sort the list inside dot. This is the hard part. If I impose Flat as an attribute of dot, I end up with an infinite loop (Question 1.) I haven't tried further (I made it finally work two hours ago), but I'm wondering (Question 2) if there is a more efficient way to sort the elements. With grassmann.m sometimes my laptop takes several minutes (15 - 20) to compute something. I don't want that to happen here.
If you look up the package grassmann.m, you will see that most of my code comes from there, except from this last line (and the distributive property.) Also, since grassmann.m already uses NonCummutativeMultiple, which has the Flat attribute, it sometimes conflicts with certain pattern matching replacements, that's why I tried to define my own variables.
As I mentioned, if you have too many fermionic variables, like 12 (6 Weyls in four dimensions), grassmann.m stops assigning grading to some of them, thus, not doing what I want it to do. (Question 3: how can I avoid such problem?, it is related to the memory leak pointed out in one of "Jeremy's additions"?)
Finally, sometimes I will need to generalize the grading in order to add a "form" grading, so this little code should be a good start.
I've looked at other questions, like
Boson commutation relations
Sorting function for non commuting bosons
But I don't understand the answers, and even less how to apply them to my problem. But maybe they are relevant.