I've been trying this for a few days now, but I just can't seem to find an efficient (speed-wise) functional way to code the following task.
Context:
I would like to construct an expressions that is the result of sorting a product of non-commuting objects (they can be expressions, but we'll use only Symbol
s for clarity):
input = str[j,i,h,g,f,e,d,c,b,a]
If these objects were commuting, then Sort
will do the job. But I would like to write a (non-commutative sort) NCSort
that will also include the appropriate commutators comm[x,y]
for every required pairwise interchange. Here is the code that recursively performs this task:
NCSort[expr_str] := ReplaceRepeated[expr,
str[left___, a_, b_, right___] /; ! OrderedQ[{a, b}] :>
str[left, b, a, right] + comm[a, b] str[left, right]]
It takes 1 sec on my computer to give the result for NCSort[str[j,i,h,g,f,e,d,c,b,a]]
. Furthermore, I would like the answer expanded out. Calling Expand
on the output takes another 4 seconds.
Problem:
To speed things up, it is useful to know that the algebra problem can be turned into an expression-construction problem. The final result can be written in closed from (Wick's theorem),
$$ \begin{eqnarray}\text{str}(a,b,c,d,\ldots) &=& \text{sorted}(a,b,c,d,\ldots)\\ && + \hspace{-5mm}\sum_{\substack{\text{all req'd}\\\text{single comm's}}} \hspace{-5mm} \text{comm}(a,b)\text{sorted}(c,d,\ldots) + \ldots \\ && + \hspace{-5mm}\sum_{\substack{\text{all req'd}\\\text{double comm's}}} \hspace{-5mm} \text{comm}(a,b)\text{comm}(c,d)\text{sorted}(\ldots) + \ldots \\ &&\ldots \end{eqnarray}$$
I need help in directly constructing the entire expression in the RHS. Once again for clarification, this is not an algebra problem. This is an expression-construction problem. The end result should be identical to the output of NCSort[str[j,i,h,g,f,e,d,c,b,a]]//Expand
given above.
What I have so far
Instead of using Sum
I'm thinking it would be faster to write this functionally. I have pieces that would potentially be useful, but I can't quite put it all together, and that is where I need help.
This will select all possible subsets containing elements of the input string that would be involved in comm
:
elementsInvolvedInCommutator[input_str, n_?EvenQ] := Subsets[List @@ input, {n}]
If n
is 4 or greater, then they need to be partitioned into pairs (inspired by this answer). This involves recursion, so the spirit of the solution is lost here. I need help:
allPairwisePartitions[l : {_, _}] := {{l}}
allPairwisePartitions[list_] :=
Join @@ Function[x,
Apply[{x, ##} &,
allPairwisePartitions[
DeleteCases[list, Alternatives @@ x]], {1}]] /@
Subsets[list, {2}, Length[list] - 1]
If I put the above two together, I can get all the pairwise commutators involved in a given sum. For example, the following gives a list of all potential double commutators (third line in the equation above):
Join @@ (allPairwisePartitions /@ elementsInvolvedInCommutator[input, 4])
I'm having trouble proceeding from here. I am unable to remove the commutators that are not needed, i.e. those that are already in order, and I need help writing allPairwisePartitions
non-recursively.
NCSort[input]//Expand
given above which is basically the RHS of Wick's theorem. Note however, only the contractions required to sort the input appear and not all of them. $\endgroup$