kpeeters / cadabra2

A field-theory motivated approach to computer algebra.
https://cadabra.science/
GNU General Public License v3.0
215 stars 37 forks source link

Hoping to implement transposition #183

Open cbehan opened 4 years ago

cbehan commented 4 years ago

The only note about transpose in Cadabra appears to be the statement that one can define it as a custom operator using IndexInherit. This no longer seems like enough now that combine() can generate a transpose from normal data.

So far I have two ideas for how Cadabra could return "A^T". The first would be a tree with "A" underneath "\transpose" where "\transpose" is a new string node along the lines of "\sum" and "\prod". The second would some symbol defined at property assignment time. I.e. if the user plans on using combine() heavily, she should start with something like

    A::Matrix(transpose=At).

Assuming that one of these ideas is to your liking, I think the next step would be an algorithm called remove_transpose(). This algorithm would first find the matrices that are (anti)-symmetric and remove transpose trivially. Then it would find everything that looks like

    (A^T)_{a b}

and change it to

    (A)_{b a}.

Finally, indexbrackets with many matrices would only be altered if they contain a pure transpose like

    (A^T B^T)_{a b}.

Acting on

    (A^T B)_{a b}

would just be trading one transpose for another. Please let me know if any parts of the proposal are unclear!

kpeeters commented 4 years ago

It is not so much 'what is to my liking' but more 'what works for you'. Having said that, I think there is something to be said for a \transpose{...} operator, or if we want to be able to change later on which indices it acts, a TransposeOp property which you can attach to \transpose' or anything else to your liking. We have the latter forTrace`, so perhaps that makes sense.

It is probably a good idea to first draft the tests which you want this to pass, as a sort of implicit form of documentation, so you can see whether it catches all your use-cases.

Other than that, thanks a lot for contributing!

cbehan commented 4 years ago

Coming back to this bug, I think we should use it to reach a consensus about the (now closed) pull request 189. My main motivation is that the index set name must be explicitly specified to handle tensor product representations. I know it isn't supported yet, but one could imagine making T_{\mu \nu m n} symmetric with respect to the Greek indices and antisymmetric with respect to the Latin indices. There is no way for Cadabra to figure this out later if unqualified Symmetric and AntiSymmetric properties are assigned to T.

Epsilon, on the other hand, is defined to be antisymmetric in all its indices. Therefore \epsilon{#}::EpsilonTensor is perfectly sensible. I would like to make this work again but I can think of at least two approaches.

  1. We could decide to always read index types for epsilon at algorithm run time and avoid setting the "index_set_name" that it inherits from AntiSymmetric.
  2. We could echo what we do with Traceless and treat the empty string as matching everything. This would make \epsilon_{m n} \epsilon_{\mu \nu} joinable for epsilons that are declared using "#".
kpeeters commented 4 years ago

If you want T_{\mu \nu m n} to be symmetric in the greek indices and anti-symmetric in the latin ones, you can do

T_{\mu\nu m n}::TableauSymmetry(shape={2}, indices={0,1}, shape={1,1}, indices={2,3});

I admit that most users struggle with this, and would rather say

{\mu,\nu}::Indices(greek);
{m,n}::Indices(latin);
T_{\mu\nu m n}::Symmetric(greek);
T_{\mu\nu m n}::AntiSymmetric(latin);

In my original setup (Anti)Symmetric was only meant to do 'simple' cases, but I see the point of being able to do what you suggest (this has actually been requested more than once).

I think your option '2' makes a lot of sense, but I would probably still let epsilon_to_delta check that the indices which are on the two epsilons either have no Indices property, or have the same Indices property. That's the general logic I follow elsewhere in the pattern matcher too.

And in the end, for the canonicaliser the only thing that is necessary is that everything derived from TableauSymmetry implements get_tab. If AntiSymmetric achieves that by looking up index names, that's fine.

cbehan commented 4 years ago

Thanks! I didn't realize that TableauSymmetry was already this flexible. However, am I correct that it cannot make a tensor symmetric and traceless because it (currently) functions as an SU(N) tableau? If so, it sounds like I need to expand the existing "index_setname" into a list so that calls like `T{\mu \nu m n}::Traceless(greek, latin)` are allowed.

kpeeters commented 4 years ago

That's right; TableauSymmetry just implements standard symmetrisation over rows & anti-symmetrisation over columns, it does not do trace subtraction (so strictly speaking this does not put the tensors in an irrep). If you want a traceless condition you need to add that separately.

So yes, we need Traceless to accept multiple arguments. We should probably also have some mechanism to automatically merge

T_{\mu \nu m n}::Traceless(greek);
T_{\mu \nu m n}::Traceless(latin);

into something that is effectively

T_{\mu \nu m n}::Traceless(greek, latin)

Because if you do those first two lines in the current setup, the 2nd line will overwrite the 1st, effectively leading to something that is only traceless in the latin indices. Let me think a bit about that part though, I need to refresh my memory about the internals.