Installation

Import["https://raw.githubusercontent.com/FeynCalc/feyncalc/master/install.m"]

Stable version

InstallFeynCalc[]

Development version

(*InstallFeynCalc[InstallFeynCalcDevelopmentVersion->True]*)

Loading FeynCalc

Quit[]

<<FeynCalc`

Internal vs. External Representations

Internal representation

The internal representation (`FeynCalcIntenral` or `FCI`) is how FeynCalc internally "sees" the objects.  For example, a $4$-dimensional $4$-vector is represented by

Pair[LorentzIndex[μ],Momentum[p]]

Pair is one of the most basic FeynCalc objects. Depending on its arguments, it can represent a $4$-vector, a metric tensor

Pair[LorentzIndex[μ],LorentzIndex[ν]]

or a scalar product of two 4-vectors

Pair[Momentum[p],Momentum[q]]

Another essential object is `DiracGamma` that is used to represent Dirac matrices. An uncontracted Dirac matrix is

DiracGamma[LorentzIndex[μ]]

and for a Feynman slash we use

DiracGamma[Momentum[p]]

The Levi-Civita-Tensor is

Eps[LorentzIndex[μ],LorentzIndex[ν],LorentzIndex[ρ],LorentzIndex[σ]]

or, when contracted with $4$-momenta

Eps[Momentum[p1],Momentum[p2],Momentum[q1],Momentum[q2]]

This notation (momenta in the index slots) is also used in many other tools (e.g. FORM). The advantage is, that we do not need to canonicalize the indices of the Levi-Civita-Tensor, e.g. to ensure that

diff=Eps[LorentzIndex[μ],Momentum[p2],Momentum[q1],Momentum[q2]]Pair[LorentzIndex[μ],Momentum[p1]]-
Eps[LorentzIndex[ν],Momentum[p2],Momentum[q1],Momentum[q2]]Pair[LorentzIndex[ν],Momentum[p1]]

diff//Contract

is zero.

External representation

The internal representation is useful for the internal programming FeynCalc, but obviously too cumbersome for the user input. This is why FeynCalc also has an external representation (`FeynCalcExternal` or `FCE`), that is concise and convenient.

Let us start with the $4$-vector. In the FCE-notation it is just `FV` ("FourVector")

FV[p,μ]

It is not hard to guess that the scalar product is `SP`

SP[p,q]

while for the metric tensor we write `MT`

MT[μ,ν]

To input a Dirac matrix or a Feynman slash, use `GA` or `GS` respectively

GA[μ]

GS[p]

The Levi-Civita tensor is `LC`

LC[μ,ν,ρ,σ]

The fully contracted form is entered via

LC[][p1,p2,q1,q2]

It is also possible to enter a mixed form

LC[μ][p1,p2,q]

LC[μ,ν][p1,p2]

Switching between the representations

To convert between the two representations we use the functions `FCI` and `FCE`, which are shortcuts for `FeynCalcInternal` and `FeynCalcExternal`. One cannot distinguish between the notations using the typesetting, i.e. when we see a typeset object in the `TraditionalForm`, we cannot really tell if it is in the `FCI` or `FCE` notation.

ex1=FV[p,μ]
ex2=Pair[Momentum[p],LorentzIndex[μ]]

However, we can always use `StandardForm` to see the difference

ex1//StandardForm
ex2//StandardForm

Why it matters

All FeynCalc functions that are meant for users will automatically convert the user input in the `FCE` notation into the `FCI` notation. You do not have to do it by yourself.

On the other hand, virtually all FeynCalc functions produce their output in the `FCI` form. So when you have an expression that was obtained from FeynCalc and want to apply some replacement rules to it, we have to use the `FCI` form in the rule

ex=Pair[Momentum[p],Momentum[q]]

No surprise that following does not work

ex/.SP[p,q]->1

But if we wrap the r.h.s of the rule with `FCI`, then everything is fine

ex/.FCI[SP[p,q]]->1

Contractions

Simplifications of tensorial expressions

Now that we have some basic understanding of FeynCalc objects, let us do something with them. Contractions of Lorentz indices are one of the most essential operations in symbolic QFT calculations. In FeynCalc the corresponding function is called `Contract`

FV[p,μ]MT[μ,ν]
Contract[%]

FV[p,α]FV[q,α]
Contract[%]

Notice that when we enter noncommutative objects, such as Dirac matrices, we use `Dot` (`.`) and not `Times` (`*`)

FV[p,α]MT[β,γ]GA[α] . GA[β] . GA[γ]
Contract[%]

This is because `Times` is commutative, so writing something like

GA[δ] GA[β]GA[α]

will give you completely wrong results. It is also a very common beginner's mistake!

It might be surprising that FeynCalc does not seem to distinguish between upper and lower Lorentz indices.

In fact, FeynCalc tacitly assumes that all your expressions with Lorentz indices are manifestly Lorentz covariant and respect Einstein's summation. In particular, this implies that

In an equality, if a free Lorentz index appears upstairs on the right hand side, it must also appear upstairs
on the left hand side. Something like $p^{\mu} = c q_{\mu}$ would violate manifest Lorentz covariance. Hence,

FV[p,μ]==c FV[q,μ]

could equally stand for $p^{\mu} = c q^{\mu}$ or $p_{\mu} = c q_{\mu}$.

For the sake of definiteness, we impose that a free Lorentz should be always understood to be an upper index. This becomes important when dealing with nonrelativistic expressions involving Cartesian indices, where there's no manifest Lorentz covariance.

Since FeynCalc assumes that the expressions you enter are mathematically sensible, it will not check your input or complain, even if the expression you provided is obviously incorrect

MT[μ,ν]FV[p,μ]FV[q,μ]
Contract[%]

When it comes to products of Levi-Civita tensors (`Eps`), `Contract` will by default apply the product formula with the determinant of metric tensors

LC[μ,ν][p,q]LC[ρ,σ][r,s]FV[x,μ]
Contract[%]

This is, however, not always what we want and can be inhibited via the option `EpsContract`

LC[μ,ν][p,q]LC[ρ,σ][r,s]FV[x,μ]
Contract[%,EpsContract->False]

Options[Contract]

Kinematics

Manipulations of scalar products

FeynCalc allows you to specify the values of scalar products before doing the calculation.

SP[p,q]=s;

SP[p,q]

FV[q,μ]FV[q,ν](FV[p,μ]FV[p,ν]-MT[μ,ν]/SP[p,p])
%//Contract

To clear the previously set values, use

FCClearScalarProducts[]

SP[p,q]

FV[q,μ]FV[q,ν](FV[p,μ]FV[p,ν]-MT[μ,ν]/SP[p,p])
%//Contract

A good habit is to always apply `FCClearScalarProducts[]` before setting the values, like in

FCClearScalarProducts[];
SP[p1,p1]=m1^2;
SP[p2,p2]=m2^2;

Setting up the kinematics in advance improves performance of FeynCalc and leads to more compact results. The results with the fully arbitrary kinematics are the most complicated and the longest ones.

Expanding and undoing expansions

Manipulations

FeynCalc offers further useful functions for the manipulations of Lorentz tensors and Dirac matrices. To expand scalar products

ex1=SP[p+q+r,s+t]

or expressions like

ex2=FV[p+q+r,μ]

one can use

ExpandScalarProduct[ex1]

ExpandScalarProduct[ex2]

Notice that `ExpandScalarProduct` can also do expansions only for the given momentum, while
leaving the rest of the expression untouched, e.g.

x SP[p1+p2,q1+q2]+y SP[p3+p4,q3+q4]+z SP[p5+p6,q5+q6]
ExpandScalarProduct[%,Momentum->{p1}]

For the expansion of `Eps` tensors, we use

LC[][p1+p2,q,r,s]
EpsEvaluate[%]

`EpsEvaluate` also reorders the arguments of `Eps` according to its antisymmetric properties

LC[μ,σ,ρ,ν]
EpsEvaluate[%]

The inverse of `ExpandScalarProduct` is called `MomentumCombine`

3FV[p,μ]+4FV[q,μ]
MomentumCombine[%]

This also works for scalar products, but the results may not be always optimal

SP[p+q+t,r+s]
ExpandScalarProduct[%]
MomentumCombine[%]

SP[p+q+t,r+s]+SP[r,s]
ExpandScalarProduct[%]
MomentumCombine[%]

For Dirac matrices the corresponding functions are `DiracGammaExpand` and `DiracGammaCombine`

GA[μ] . GS[p+q] . GA[ν] . GS[r+s]
DiracGammaExpand[%]
DiracGammaCombine[%]

Notice the `DiracGammaExpand` does not expand the whole noncommutative product. If you need that, use `DotSimplify`

GA[μ] . GS[p+q] . GA[ν] . GS[r+s]
%//DiracGammaExpand//DotSimplify

Handling indices

Manipulations of tensorial quantities

When you square an expression with dummy indices, you must rename them first. People often do this by hand, e.g. as in

ex1=(FV[p,μ]+FV[q,μ])FV[r,μ]FV[r,ν]

ex1 (ex1/.μ->ρ)
Contract[%]

However, FeynCalc offers a function for that

FCRenameDummyIndices[ex1]

ex1 FCRenameDummyIndices[ex1]
Contract[%]

Wrong result!

ex1^2//Contract

Notice that `FCRenameDummyIndices` does not canonicalize the indices

FV[p,ν]FV[q,ν]-FV[p,μ]FV[q,μ]
FCRenameDummyIndices[%]

There is a function for that too

FV[p,ν]FV[q,ν]-FV[p,μ]FV[q,μ]
FCCanonicalizeDummyIndices[%]

Often we also need to uncontract already contracted indices. This is done by `Uncontract`. By default, it handles only contractions with Dirac matrices and Levi-Civita tensors

LC[][p,q,r,s]
Uncontract[%,p]
Uncontract[%%,p,q]

SP[p,q]
Uncontract[%,p]

To uncontract scalar products as well, use the option `Pair->All`

Uncontract[%,p,Pair->All]

Sometimes one might want to define custom symbolic tensors that are not specified in terms of the 4-vectors, metric tensors and Levi-Civitas. This is possible in FeynCalc, but the handling of such objects is not as good as that of the built-in quantities

DeclareFCTensor[myTensor];

myTensor[LorentzIndex[μ],LorentzIndex[ν]]FV[p,ν]FV[q,μ]
ex=Contract[%]

Uncontract[ex,p,q,Pair->All]

(myTensor[LorentzIndex[μ],LorentzIndex[ν]]MT[LorentzIndex[μ],LorentzIndex[ν]]+
myTensor[LorentzIndex[α],LorentzIndex[β]]MT[LorentzIndex[α],LorentzIndex[β]])
FCCanonicalizeDummyIndices[%,LorentzIndexNames->{i1,i2}]

To extract the list of free or dummy indices present in the expression, one can use `FCGetFreeIndices` and `FCGetDummyIndices` respectively

FCI[FV[p, μ] FV[q, ν]] 
FCGetFreeIndices[%, {LorentzIndex}]

FCI[FV[p, μ] FV[q, μ]] 
FCGetDummyIndices[%, {LorentzIndex}]

Dirac algebra

Simplifications of Dirac matrix chains

The two most relevant functions for the manipulations of Dirac matrices are `DiracSimplify` and `DiracTrace`.

The goal of `DiracSimplify` is to eliminate all pairs of Dirac matrices with the equal indices or contracted with the same $4$-vectors

GA[μ] . (GS[p]+m) . GA[μ]
DiracSimplify[%]

GA[μ] . (GS[p]+m1) . GA[ν] . (GS[p]+m2)
DiracSimplify[%]

`DiracTrace` is used for the evaluation of Dirac traces. The trace is not evaluated by default

DiracTrace[GA[μ,ν]]

To obtain the result we can either use the option `DiracTraceEvaluate`

DiracTrace[GA[μ,ν],DiracTraceEvaluate->True]

or use `DiracSimplify` instead.

DiracTrace[GA[μ,ν]]//DiracSimplify

By default FeynCalc refuses to compute a $D$-dimensional trace that contains $\gamma^5$

DiracTrace[GAD[α,β,μ,ν,ρ,σ,5]]//DiracSimplify

This is because by default FeynCalc is using anticommuting $\gamma^5$ in $D$-dimensions, a scheme known as Naive Dimensional Regularization (NDR)

DiracSimplify[GAD[μ] . GA[5] . GAD[ν]]

In general, a chiral trace is a very ambiguous object in NDR. The results depends on the position of $\gamma^5$ inside the trace, so that we chose not to produce results that might be potentially inconsistent. However, FeynCalc can also be told to use the Breitenlohner-Maison-t'Hooft-Veltman scheme (BMHV), which is an algebraically consistent scheme (but has other issues, e.g. it breaks Ward identities)

FCSetDiracGammaScheme["BMHV"];

Notice that now FeynCalc anticommutes $\gamma^5$ according to the BMHV algebra, which leads to the appearance of $D-4$-dimensional Dirac matrices

DiracSimplify[GAD[μ] . GA[5] . GAD[ν]]

Also Dirac traces are not an issue now

DiracTrace[GAD[α,β,μ,ν,ρ,σ] . GA[5]]//DiracSimplify

To compute chiral traces in the BMHV scheme, FeynCalc uses [West's formula](https://inspirehep.net/record/31057). Still, NDR is the default scheme in FeynCalc.

FCSetDiracGammaScheme["NDR"]

FCGetDiracGammaScheme[]

In tree-level calculation a useful operation is the so-called SPVAT-decomposition of Dirac chains.
This is done using `DiracReduce`

GA[μ,ν,ρ] . GS[p] . GA[α]
DiracReduce[%]

Gordon's identities are implemented via `GordonSimplify`

SpinorUBar[p1,m1] . GA[μ] . SpinorU[p2,m2]
GordonSimplify[%]
%//StandardForm

ubar.u

ubar.u, see the help page on `Spinor`

SpinorVBar[p1,m1] . GA[μ] . SpinorV[p2,m2]
GordonSimplify[%]
%//StandardForm

It is possible to reorder the free indices in a chain of Dirac matrices, which can sometimes help to simplify the expressions

GA[μ,ν,ρ,α,β]
DiracOrder[%,{β,ν,μ}]

However, since this procedure is computationally expensive, `DiracSimplify` will not apply it by default

DiracSimplify[GAD[μ, ν] + GAD[ν, μ]]

It can be activated via the option `DiracOrder`

DiracSimplify[GAD[μ, ν] + GAD[ν, μ], DiracOrder -> True]

Color algebra

Notation for colored objects

FeynCalc objects relevant for the color algebra are

SUNT[a]

SUNF[a,b,c]

SUND[a,b,c]

SUNDelta[a,b]

SUNFDelta[i,j]

SUNN

CA

CF

There are two main functions to deal with colored objects: `SUNSimplify` and `SUNTrace`. In general, `SUNSimplify` will also simplify color traces when possible

SUNT[a,a]
SUNSimplify[%]

SUNT[a,b,a,b]
SUNSimplify[%]

SUNT[b,d,a,b,d]
SUNSimplify[%]

SUNF[a, r, s] SUNF[b, r, s]
SUNSimplify[%]

SUNF[a, b, c]  SUNF[a, b, c]
SUNSimplify[%]

SUNF[a, b, c] SUND[d, b, c] 
SUNSimplify[%]

SUND[a, b, c] SUND[a, b, c] 
SUNSimplify[%]

The color factors $C_A$ and $C_F$ are reconstructed from $N_c$ using heuristics. The reconstruction can be disabled by setting the option `SUNNToCACF` to `False`

SUNSimplify[SUNT[b,d,a,b,d],SUNNToCACF->False]

The color traces are not evaluated by default. The evaluation can be forced either by applying `SUNSimplify` or setting the option `SUNTraceEvaluate` to `True`

SUNTrace[SUNT[a,b]]

SUNTrace[SUNT[a,b,b,a]]

SUNTrace[SUNT[a,b]]//SUNSimplify

SUNTrace[SUNT[a,b,b,a]]//SUNSimplify

SUNTrace[SUNT[a,b],SUNTraceEvaluate->True]

Use `SUNTF` to get color matrices with explicit fundamental indices

SUNTF[{a,b,c},i,j]SUNTrace[SUNT[b,a]]
%//SUNSimplify

SUNDelta[a, b] SUNTF[{a, b}, i, j] SUNTF[{c, d}, j, i]
SUNSimplify[%]

Color traces with more than 3 distinct matrices are not evaluated by default (assuming that no other simplifications are possible). The evaluation can be forced using the option `SUNTraceEvaluate` set to `True`

SUNTrace[SUNT[a,b,c,d]]//SUNSimplify

SUNTrace[SUNT[a,b,c,d]]//SUNSimplify[#,SUNTraceEvaluate->True]&

One can automatically rename dummy indices using the `SUNIndexNames` option

SUNTrace[SUNT[a,b,c,d]]//SUNSimplify[#,SUNTraceEvaluate->True,SUNIndexNames->{j}]&

Loops

Propagators

All propagators (and products thereof) appearing in loop diagrams and integrals are represented via `FeynAmpDenominator`

This container is capable of representing different propagator types, where the familiar quadratic propagators of the form $1/(q^2 - m^2 + i \eta)$ are described using `PropagatorDenominator`

FeynAmpDenominator[PropagatorDenominator[Momentum[q,D],m]]

Again, for the external input we always use a shortcut

FAD[{q,m}]

FAD[{q,m,2}]

FAD[{q,m0},{q+p1,m1},{q+p2,m1}]

This is not a propagator in FeynCalc

1/(SPD[q]-m^2)

There is also a more versatile symbol called `StandardFeynAmpDenominator` or `SFAD` that allows entering eikonal propagators as well

SFAD[{{p, 0}, m^2}]

SFAD[{{p, 0}, {-m^2, -1}}]

SFAD[{{0, p . q}, m^2}]

SFAD[{{0, p . q}, 0}]

SFAD[{{p, p . q}, m^2}]

The presence of `FeynAmpDenominator` in an expression does not automatically mean that it is a loop amplitude. `FeynAmpDenominator` can equally appear in tree level amplitudes, where it stands for the usual 4-dimensional propagator.

In FeynCalc there is no explicit way to distinguish between loop amplitudes and tree-level amplitudes. When you use functions that manipulate loop integrals, you need to tell them explicitly what is your loop momentum.

Manipulations of FeynAmpDenominators

There are several functions, that are useful both for tree- and loop-level amplitudes, depending on what we want to do

For example, one can split one `FeynAmpDenominator` into many

FAD[{k1-k2},{k1-p2,m},{k2+p2,m}]
FeynAmpDenominatorSplit[%]
%//FCE//StandardForm

or combine several into one

FeynAmpDenominatorCombine[FAD[k1-k2] FAD[{k1-p2,m}] FAD[{k2+p2,m}]]
%//FCE//StandardForm

At the tree-level we often do not need the `FeynAmpDenominators` but rather want to express everything in terms of explicit scalar products, in order to exploit kinematic simplifications. This is handled by `FeynAmpDenominatorExplicit`

FeynAmpDenominatorExplicit[FAD[{k2+p2,m},k1-k2,{k1-p2,m}]]
%//StandardForm

One-loop tensor reduction

1-loop tensor reduction using Passarino-Veltman method is handled by `TID`

FVD[q,μ]FVD[q,ν]FAD[{q,m}]
TID[%,q]

int=FVD[q,μ]SPD[q,p]FAD[{q,m0},{q+p,m1}]
TID[%,q]

int=SPD[q,p]FAD[{q,m0},{q+p,m1}]
TID[%,q]

By default, `TID` tries to reduce everything to scalar integrals with unit denominators.
However, if it encounters zero Gram determinants, it automatically switches to the coefficient functions

FCClearScalarProducts[]
SPD[p,p]=0;

int=FVD[q,μ]SPD[q,p]FAD[{q,m0},{q+p,m1}]

TID[int,q]

If we want the result to be express entirely in terms of Passarino-Veltman function, i. e. without `FAD`s, we can use `ToPaVe`

TID[int,q,ToPaVe->True]

`ToPaVe` is actually also a standalone function, so it can be used independently of `TID`

FCClearScalarProducts[]
FAD[q,{q+p1},{q+p2}]
ToPaVe[%,q]

Even if there are no Gram determinants, for some tensor integrals the full result in terms of scalar integrals is just too large

int=FVD[q,μ]FVD[q,ν]FAD[q,{q+p1},{q+p2}]
res=TID[int,q];

res//Short

Of course we collect with respect to `FAD` and isolate the prefactors, but the full result still remains messy

Collect2[res,FeynAmpDenominator,IsolateNames->KK]

In such cases, we can get a much more compact results , if we stick to coefficient functions and do not demand the full reduction to scalars. To do so, use the option `UsePaVeBasis`

res=TID[int,q,UsePaVeBasis->True]

The resulting coefficient functions can be further reduced with `PaVeReduce`

pvRes=PaVeReduce[res];

pvRes//Short

Multi-loop tensor reduction

In the case of multi-loop integrals (but also 1-loop integrals with linear propagators) one should use `FCMultiLoopTID`

FVD[q,μ]FVD[q,ν]SFAD[{q,m^2},{{0,2l . q}}]
FCMultiLoopTID[%,{q}]

Working with GLI and FCTopology symbols

Integral families are encoded in form of `FCTopology[id, {props}, {lmoms}, {extmoms}, kinematics, reserved]` symbols

topos={
FCTopology["topoBox1L",{FAD[{q,m0}],FAD[{q+p1,m1}],FAD[{q+p2,m2}],FAD[{q+p2,m3}]},
{q},{p1,p2,p3},{},{}],
FCTopology["topoTad2L",{FAD[{q1,m1}],FAD[{q2,m2}],FAD[{q1-q2,0}]},{q1,q2},{},{},{}]}

The loop integrals belonging to these topologies are written as `GLI[id, {powers}]` symbols

exp=a1 GLI["topoBox1L",{1,1,1,1}]+a2 GLI["topoTad2L",{1,2,2}]

Using `FCLoopFromGLI` we can convert `GLI`s into explicit propagator notation

FCLoopFromGLI[exp,topos]

Topology identification

The very first step is usually to identify the occurring topologies in the amplitude (without attempting to minimize their number)

Find topologies occurring in the 2-loop ghost self-energy amplitude

amp=Get[FileNameJoin[{$FeynCalcDirectory,"Documentation","Examples",
"Amplitudes","Gh-Gh-2L.m"}]];

res=FCLoopFindTopologies[amp,{q1,q2}];

res//Last

The amplitude is the written as a linear combination of special products, where numerators with explicit loop momenta are multiplied by denominators written as `GLI`s

res[[1]][[1;;5]]

Finding topology mappings

Here we have a set of 5 topologies

topos1={
FCTopology[fctopology1,{SFAD[{{p3,0},{0,1},1}],SFAD[{{p2,0},{0,1},1}],
SFAD[{{p1,0},{0,1},1}],SFAD[{{p2+p3,0},{0,1},1}],SFAD[{{p2-Q,0},{0,1},1}],
SFAD[{{p1-Q,0},{0,1},1}],SFAD[{{p2+p3-Q,0},{0,1},1}],SFAD[{{p1+p3-Q,0},{0,1},1}],
SFAD[{{p1+p2+p3-Q,0},{0,1},1}]},{p1,p2,p3},{Q},{},{}],
FCTopology[fctopology2,{SFAD[{{p3,0},{0,1},1}],
SFAD[{{p2,0},{0,1},1}],SFAD[{{p1,0},{0,1},1}],SFAD[{{p2+p3,0},{0,1},1}],
SFAD[{{p2-Q,0},{0,1},1}],SFAD[{{p1-Q,0},{0,1},1}],
SFAD[{{p2+p3-Q,0},{0,1},1}],SFAD[{{p1+p2-Q,0},{0,1},1}],
SFAD[{{p1+p2+p3-Q,0},{0,1},1}]},{p1,p2,p3},{Q},{},{}],
FCTopology[fctopology3,{SFAD[{{p3,0},{0,1},1}],
SFAD[{{p2,0},{0,1},1}],SFAD[{{p1,0},{0,1},1}],
SFAD[{{p2+p3,0},{0,1},1}],SFAD[{{p1+p3,0},{0,1},1}],
SFAD[{{p2-Q,0},{0,1},1}],SFAD[{{p2+p3-Q,0},{0,1},1}],
SFAD[{{p1+p3-Q,0},{0,1},1}],SFAD[{{p1+p2+p3-Q,0},{0,1},1}]},
{p1,p2,p3},{Q},{},{}],
FCTopology[fctopology4,{SFAD[{{p3,0},{0,1},1}],
SFAD[{{p2,0},{0,1},1}],SFAD[{{p1,0},{0,1},1}],
SFAD[{{p2+p3,0},{0,1},1}],SFAD[{{p1+p3,0},{0,1},1}],
SFAD[{{p2-Q,0},{0,1},1}],SFAD[{{p1-Q,0},{0,1},1}],
SFAD[{{p1+p3-Q,0},{0,1},1}],SFAD[{{p1+p2+p3-Q,0},{0,1},1}]},
{p1,p2,p3},{Q},{},{}],
FCTopology[fctopology5,{SFAD[{{p3,0},{0,1},1}],
SFAD[{{p2,0},{0,1},1}],SFAD[{{p1,0},{0,1},1}],
SFAD[{{p1+p3,0},{0,1},1}],SFAD[{{p2-Q,0},{0,1},1}],
SFAD[{{p1-Q,0},{0,1},1}],SFAD[{{p1+p3-Q,0},{0,1},1}],
SFAD[{{p1+p2-Q,0},{0,1},1}],SFAD[{{p1+p2+p3-Q,0},{0,1},1}]},
{p1,p2,p3},{Q},{},{}]};

where 3 of them can be mapped to the other 2

mappings1=FCLoopFindTopologyMappings[topos1];

mappings1[[1]]

And these are the final topologies

mappings1[[2]]

Tensor reductions with GLIs

Tensor reduction for topologies that have already been processed with `FCLoopFindTopologies` can be done using `FCLoopTensorReduce`

topo2=FCTopology[prop1l,{SFAD[{q,m^2},{q-p,m^2}]},{q},{p},{},{}]

amp2=gliProduct[GSD[q] . GAD[μ] . GSD[q], GLI[prop1l,{1,2}]]

amp2Red=FCLoopTensorReduce[amp2,{topo2},Head->gliProduct]

Applying topology mappings

This is a trial expression representing some loop amplitude that has already been processed using `FCFindTopologies`

ex=gliProduct[cc6*SPD[p1,p1],GLI[fctopology1,{1,1,2,1,1,1,1,1,1}]]+
gliProduct[cc2*SPD[p1,p2],GLI[fctopology2,{1,1,1,1,1,1,1,1,1}]]+
gliProduct[cc4*SPD[p1,p2],GLI[fctopology4,{1,1,1,1,1,1,1,1,1}]]+
gliProduct[cc1*SPD[p1,Q],GLI[fctopology1,{1,1,1,1,1,1,1,1,1}]]+
gliProduct[cc3*SPD[p2,p2],GLI[fctopology3,{1,1,1,1,1,1,1,1,1}]]+
gliProduct[cc5*SPD[p2,Q],GLI[fctopology5,{1,1,1,1,1,1,1,1,1}]]

These mapping rules describe how the 3 topologies "fctopology3", "fctopology4" and "fctopology5" are mapped to the topologies "fctopology1" and "fctopology2"

mappings={
{FCTopology[fctopology3,{SFAD[{{p3,0},{0,1},1}],SFAD[{{p2,0},{0,1},1}],
SFAD[{{p1,0},{0,1},1}],SFAD[{{p2+p3,0},{0,1},1}],SFAD[{{p1+p3,0},{0,1},1}],
SFAD[{{p2-Q,0},{0,1},1}],SFAD[{{p2+p3-Q,0},{0,1},1}],SFAD[{{p1+p3-Q,0},{0,1},1}],
SFAD[{{p1+p2+p3-Q,0},{0,1},1}]},{p1,p2,p3},{Q},{},{}],{p1->-p1-p3+Q,p2->
-p2-p3+Q,p3->p3},
GLI[fctopology3,{n1_,n7_,n8_,n5_,n6_,n4_,n2_,n3_,n9_}]:>
GLI[fctopology1,{n1,n2,n3,n4,n5,n6,n7,n8,n9}]},

{FCTopology[fctopology4,{SFAD[{{p3,0},{0,1},1}],SFAD[{{p2,0},{0,1},1}],SFAD[{{p1,0},
{0,1},1}],
SFAD[{{p2+p3,0},{0,1},1}],SFAD[{{p1+p3,0},{0,1},1}],SFAD[{{p2-Q,0},{0,1},1}],
SFAD[{{p1-Q,0},{0,1},1}],
SFAD[{{p1+p3-Q,0},{0,1},1}],SFAD[{{p1+p2+p3-Q,0},{0,1},1}]},{p1,p2,p3},{Q},{},{}],
{p1->-p2+Q,p2->-p1+Q,p3->-p3},
GLI[fctopology4,{n1_,n6_,n5_,n8_,n7_,n3_,n2_,n4_,n9_}]:>
GLI[fctopology1,{n1,n2,n3,n4,n5,n6,n7,n8,n9}]},

{FCTopology[fctopology5,{SFAD[{{p3,0},{0,1},1}],SFAD[{{p2,0},{0,1},1}],SFAD[{{p1,0},
{0,1},1}],
SFAD[{{p1+p3,0},{0,1},1}],SFAD[{{p2-Q,0},{0,1},1}],SFAD[{{p1-Q,0},{0,1},1}],
SFAD[{{p1+p3-Q,0},{0,1},1}],
SFAD[{{p1+p2-Q,0},{0,1},1}],SFAD[{{p1+p2+p3-Q,0},{0,1},1}]},{p1,p2,p3},{Q},{},
{}],{p1->p2,p2->p1,p3->p3},
GLI[fctopology5,{n1_,n3_,n2_,n4_,n6_,n5_,n7_,n8_,n9_}]:>
GLI[fctopology2,{n1,n2,n3,n4,n5,n6,n7,n8,n9}]}}

These are the two topologies onto which everything is mapped

finalTopos={
FCTopology[fctopology1,{SFAD[{{p3,0},{0,1},1}],SFAD[{{p2,0},{0,1},1}],
SFAD[{{p1,0},{0,1},1}],SFAD[{{p2+p3,0},{0,1},1}],SFAD[{{p2-Q,0},{0,1},1}],
SFAD[{{p1-Q,0},{0,1},1}],SFAD[{{p2+p3-Q,0},{0,1},1}],SFAD[{{p1+p3-Q,0},{0,1},1}],
SFAD[{{p1+p2+p3-Q,0},{0,1},1}]},{p1,p2,p3},{Q},{},{}],
FCTopology[fctopology2,{SFAD[{{p3,0},{0,1},1}],SFAD[{{p2,0},{0,1},1}],
SFAD[{{p1,0},{0,1},1}],SFAD[{{p2+p3,0},{0,1},1}],SFAD[{{p2-Q,0},{0,1},1}],
SFAD[{{p1-Q,0},{0,1},1}],SFAD[{{p2+p3-Q,0},{0,1},1}],SFAD[{{p1+p2-Q,0},{0,1},1}],
SFAD[{{p1+p2+p3-Q,0},{0,1},1}]},{p1,p2,p3},{Q},{},{}]}

`FCLoopApplyTopologyMappings`  applies the given mappings to the expression creating an output that is ready to be processed further

FCLoopApplyTopologyMappings[ex,{mappings,finalTopos},Head->gliProduct]

The resulting `GLI`s in the expression are loop integrals that can be IBP-reduced

Mappings between integrals

To find one-to-one mappings between loop integrals use `FCLoopFindIntegralMappings`

FCClearScalarProducts[]
ClearAll[topo1,topo2]

topos={FCTopology[topo1,{SFAD[{p1,m^2}],SFAD[{p2,m^2}]},{p1,p2},{},{},{}],
FCTopology[topo2,{SFAD[{p3,m^2}],SFAD[{p4,m^2}]},{p3,p4},{},{},{}]}

glis={GLI[topo1,{1,1}],GLI[topo1,{1,2}],GLI[topo1,{2,1}],
GLI[topo2,{1,1}],GLI[topo2,{2,2}]}

mappings=FCLoopFindIntegralMappings[glis,topos]