sympy/sympy — pull request #1644 by pernici (2012-11-11 17:22:45+00:00)
Title: Canonical tensors using Butler-Portugal algorithm

Canonicalize a tensor choosing as the representative
the least tensor equivalent to it in lexicographic order,
using the Butler-Portugal algorithm

For example consider the following product of Riemann tensors

`R^d1_d2^b_d0 * R^{d0 a}_d1^d2`

Order the indices putting first the free indices, then the dummy indices,
putting the contravariant index before the covariant one (here indicated
with a minus sign)
`ordering = `[a, b, d0,-d0, d1,-d2,d2]`

Find the permutation corresponding to it, adding two indices for the sign
of the tensor

```
>>> from sympy.combinatorics import Permutation
>>> from sympy.combinatorics.tensor_can import riemann_bsgs, canonicalize, get_symmetric_group_sgs
>>> baser, gensr = riemann_bsgs
>>> g = Permutation([4,7,1,3,2,0,5,6,8,9])
>>> canonicalize(g, range(2,8), 0, (baser, gensr, 2, 0))
[0, 2, 4, 6, 1, 3, 5, 7, 9, 8]
```

which corresponds to `-R^{a d0 d1 d2}* R^b_{d0 d1 d2}`

As another example, let A be a symmetric commuting tensor
`R^{d6 d5}_d2^d1 * R^{d4 d0 d2 d3} * A_{d6 d0} A_{d3 d1} * A_{d4 d5}`

`ordering = [d0,-d0,d1,-d1,d2,-d2,d3,-d3,d4,-d4,d5,-d5,d6,-d6]`

```
>>> base2, gens2 = get_symmetric_group_sgs(2)
>>> g = Permutation([12,10,5,2,8,0,4,6,13,1,7,3,9,11,14,15])
>>> canonicalize(g, range(14), 0, ((baser,gensr,2,0)), (base2,gens2,3,0))
[0, 2, 4, 6, 1, 8, 10, 12, 3, 9, 5, 11, 7, 13, 15, 14]
```
so that the canonical form is

`-R^{d0 d1 d2 d3} * R_d0^{d4,d5,d6} * A_{d1 d4} * A_{d2 d5} * A_{d3 d6}`