Using MakeRule to replace Contractions

Skip to first unread message

Edu Serna

Jan 29, 2011, 6:24:47 AM1/29/11
to xAct Tensor Computer Algebra
Hi I use xAct to calculate scattering amplitudes and as such need to
make replacements of contractions of tensors e.g.

rule= MakeRule[{p[a] p[-a], }, MetricOn -> All, ContractMetrics ->

I have been experiencing issues with this feature and have
experimented extensively with it so that I could one day ask for help
properly here.

The main problem seem to be that xAct will only do this replacement if
the two tensors that are contracted are contiguous i.e.
p[a] q[c] p[-a] often wont get replaced straight away and I need to do
several rounds of Expand and Simplification. To help this process and
for clarity I often replace the inner products by parameters
(mandelstam variables for those who know about them).

However I was wondering if there might be a better way, I have two
ideas but no idea how to implement them:

1. Inserting some kind of wildcard in the definition: MakeRule[{p[a]
WILDCARD p[-a], }, MetricOn -> All, ContractMetrics -> True];
2. Running a routine that can permute the order in which
Simplification considers expressions. I believe this can be done as
Mathematica has ways of selecting terms of an expression, but have no
idea of how to do it efficiently (perhaps with a random number

Any ideas or is there already an implemented way to do this?


Jan 29, 2011, 1:10:41 PM1/29/11
to xAct Tensor Computer Algebra
Thanks for reporting this. Without a particular example I don´t really
know what might be the problem you find.

MakeRule is just a constructor of standard Mathematica rules, designed
to simplify or automate some simple and frequent cases of tensorial
rules. But often MakeRule is not flexible enough to implement what you
want, and then you have to write the rules yourself, using the full
power of the pattern matching capabilities of Mathematica. I believe
Mathematica's language allows you to implement any rule you might
want, but certainly not MakeRule.

In your case, the possible reorderings of your momenta are controlled
by the attributes Flat and Orderless of Times, and hence it should be
automatic. If it doesn't work for you, it might be because something
else in the rule is interfering with that, but I don't know what it
might be. As I said, the best thing would be to show an example.

As for the wildcar, I guess you mean a pattern like rest_. (note the
dot), or if you want a pattern for momenta, something like mom_?
xTensorQ[ind_] , which accepts any tensor with only one index. You can
also add tests in the index to select indices of various types.


Edu Serna

Feb 5, 2011, 4:19:43 PM2/5/11
to xAct Tensor Computer Algebra
Thanks so much for the reply, I admit I am not fully familiar with the
Mathematica syntax due to lack of time.

So for instance an example of this problem is when I have contractions
in the denominator with the scalar head.

Something like this will do the trick:

Expand[Simplification[ContractMetric[dg1, \[Eta]] //. onshell] //.
onshell //. mand] //. onshell //. mand // Simplification

But soething like this: Simplification[
Expand[ContractMetric[dg1, \[Eta]]] //. onshell //. mand]

will leave the contractions in the denominator unreplaced.

onshell and mand are lists of rules compiled with FoldedRule.

On a different note, what exactly is SeparateMetric? Is it the
opposite of ContractMetric? I don't understand its syntax and I get
funny indices with numbers when I try it.

Thanks again

Leo Stein

Feb 5, 2011, 5:08:21 PM2/5/11
to Edu Serna, xAct Tensor Computer Algebra
Dealing with scalar contractions in the denominator is tricky. The problem is that Mathematica doesn't know that it can't take something like
  (p[a] p[-a])^-1,
and rewrite it as
  p[a]^-1 p[-a]^-1,
which makes no sense. This is probably why your rule is not always working as expected. The expressions it's try to work on sometimes look like
  Times[ ..., Power[ p[a], -1], Power[ p[-a], -1], ...],
or along those lines. This does not match the pattern that MakeRule spits out by default.

Using Scalar can help, writing expression instead as
  Times ..., Power[ Scalar[ Times[ p[a], p[-a] ] ], -1 ], ...],
and now there is something that matches the pattern returned by MakeRule. ToCanonical tries to add Scalar heads sometimes (I'm not sure when), but I think it doesn't group things in denominators properly for some reason. Try adding Scalar as early as possible when writing your expressions with contractions in the denominator, e.g.
  Scalar[ p[a] p[-a] ]^-1,
which will be successfully transformed by the rule you get out of MakeRule.



Feb 6, 2011, 12:29:15 PM2/6/11
to xAct Tensor Computer Algebra

First a general comment. In this expression:

> Expand[Simplification[ContractMetric[dg1, \[Eta]] //. onshell] //.
>       onshell //. mand] //. onshell //. mand // Simplification

you use a combination of Expand and Simplification. Note that
Simplification is just Simplify[ ToCanonical[ ... ] ] and therefore
you are spending time in using Simplify and then undoing its action
with Expand. The recommendation is to use ToCanonical at intermediate
steps (which returns expressions expanded), when you think it is
needed, and only at the end use Simplification (or just Simplify if
the expression is already canonicalized).

> But soething like this: Simplification[
>  Expand[ContractMetric[dg1, \[Eta]]] //. onshell //. mand]
> will leave the contractions in the denominator unreplaced.

As Leo points out, the idea of contraction in the denominator is based
on the assumption that you deal with a scalar. Most functions in
xTensor will not stop to check that, but sometimes ToCanonical
discovers, as part of its standard computation, that this is the case.
Then ToCanonical wraps the expression with Scalar, to help all other
commands knowing this fact. If you work with tensor products in the
denominator, you certainly need to use Scalar. See the functions
PutScalar, BreakScalar, NoScalar. If such denominators are very
frequent, consider the possibility of declaring them, say:

DefTensor[ pp[], M ]
p/: p[a_] p[-a_] := pp[]

xTensor will be faster manipulating pp[] than manipulating
Scalar[ p[a] p[-a] ].

> On a different note, what exactly is SeparateMetric? Is it the
> opposite of ContractMetric?

Essentially yes. The idea of SeparateMetric is the following. We
absorb metric contractions by raising and lowering indices without
changing the stem of the tensor, say g[a,b] T[-b] is written as T[a].
This is simple and useful, but hides the presence of the metric, and
that is potentially dangerous in some computations. What
SeparateMetric does is extracting metric factors from a given tensor
until all its slots have indices are in the positions in which the
tensor was defined. That is, it makes explicit the presence of the
metric field. If you define DefTensor[ T[a,-b], M ] then
SeparateMetric[][ T[a, b] ] will extract a metric factor from the
second slot of T, but not from the first one, etc. ContractMetric
would absorb it again, and in this sense they are inverses. The only
difference is that SeparateMetric takes into account the original
configuration (stored in SlotsOfTensor[ T ]), but ContractMetric
absorbs all metric factors.

> I don't understand its syntax and I get funny indices with numbers when I try it.

SeparateMetric has additional arguments for further flexibility. The
general syntax is SeparateMetric[ metric, basis ][ expr, index ], with
defaults for all arguments except expr. The metric argument specifies
which metrics you want to separate (by default all first-metrics). The
basis argument specifies the type of index used for the new
contraction (by default an abstract index, with formal basis AIndex).
The index argument specifies which indices you want to separate, that
is, the indices already present in the original expression, not the
index added for the new contraction (the default is all indices that
can be separated). The reason why this function has a double pair of
brackets is because I use it frequently with mapping constructs, like
Map[ SeparateMetric[metric], expr , {level}] or
MapAt[ SeparateMetric[metric], expr, position ]. Just that.

Numbered indices, like f1 or f32, are generated when xTensor runs out
of user-defined indices. xTensor takes the last index you declared
with the manifold or vbundle and starts adding numbers sequentially.
If you have a look at IndicesOfVBundle[vbundle] you will see that it
contains two lists: the indices you declared and the indices added by
this mechanism. Note that these are all proper abstract indices,
perfectly usable. They are not dollar-indices (like f$1 or f$32),
which are internal dummies, not to be used directly by users.
ScreenDollarIndices replaces the dollar-dummies with normal indices,
and the latter could be numbered. If you don´t like these, declare
many indices at the beginning.


Edu Serna

Feb 6, 2011, 4:10:24 PM2/6/11
to xAct Tensor Computer Algebra
Thanks so much to both of you.

For the record I have wrapped the contraction in the denominator when
defining dg1.

Thanks for the comments on efficiency and for the explanation I will
make due note of them.

I have a suggestion to make regarding the documentation: Add what you
just told me about SeparateMetric next to the section on
ContractMetric (it can be very useful for producing Feynman Rules) and
state clearly that Expand is needed to replace contractions.

I can do these additions myself and then send them to you if its most

I will keep looking in my notebooks for examples of dodgy


Edu Serna

Feb 28, 2011, 12:04:36 PM2/28/11
to xAct Tensor Computer Algebra
Ok I have another example of something that seems to be a minor bug
but which can be very annoying

defining the usual manifold

onshellk =
MakeRule[{k[a] k[-a], 0}, MetricOn -> All, ContractMetrics -> True];


k[a] k[-a] // ToCanonical //. onshellk

just returns k[-a] k[a]

whereas this returns 0 as expected

ToCanonical[k[a] k[-a]] //. onshellk

Leo Stein

Feb 28, 2011, 1:43:46 PM2/28/11
to Edu Serna, xAct Tensor Computer Algebra
This is not an xAct problem. Rather, this has to do with the precedence of different infix operators in Mathematica.
The //. operator (aka ReplaceRepeated) binds more tightly than the // operator (aka Postfix function notation). That means something like
    k[a] k[-a] // ToCanonical //. onshellk
is parsed as
    k[a] k[-a] // (ToCanonical //. onshellk)
which is not what you intended. Rather, you must tell Mathematica to apply // first, either 
    (k[a] k[-a] // ToCanonical) //. onshellk
    ToCanonical[ k[a] k[-a] ] //. onshellk

Hope this helps!

Eduardo Serna

Feb 28, 2011, 1:52:51 PM2/28/11
to Leo Stein, xAct Tensor Computer Algebra
Thanks so much, 

k[a] k[-a] // (ToCanonical //. onshellk) so what does this mean? a replacement being done on ToCAnonical with no argument?


Leo Stein

Feb 28, 2011, 1:59:23 PM2/28/11
to Eduardo Serna, xAct Tensor Computer Algebra
That's right. ToCanonical is just a symbol (with some patterns that match for it). You can do ReplaceAll or ReplaceRepeated on anything you want, including "function names" (which are really just symbols). The return value of ( ToCanonical //. onshellk ) will just be ToCanonical, since the replacement has nothing to replace. Then ToCanonical will be applied to the expression to the left.


Eduardo Serna

Mar 1, 2011, 5:05:03 AM3/1/11
to Leo Stein, xAct Tensor Computer Algebra
Ok thanks so much this is reassuring
Reply all
Reply to author
0 new messages